OSDN Git Service

ptex.pdf
authormaqiyuan <maqiyuan@users.sourceforge.jp>
Wed, 11 Jun 2014 14:03:58 +0000 (22:03 +0800)
committermaqiyuan <maqiyuan@users.sourceforge.jp>
Wed, 11 Jun 2014 14:03:58 +0000 (22:03 +0800)
doc/ptex.pdf [new file with mode: 0644]
doc/ptex.tex [new file with mode: 0644]
doc/ptex.web [new file with mode: 0644]

diff --git a/doc/ptex.pdf b/doc/ptex.pdf
new file mode 100644 (file)
index 0000000..6ddeaf7
Binary files /dev/null and b/doc/ptex.pdf differ
diff --git a/doc/ptex.tex b/doc/ptex.tex
new file mode 100644 (file)
index 0000000..4d35987
--- /dev/null
@@ -0,0 +1,43203 @@
+\input webmac
+% This program is copyright (C) 1982 by D. E. Knuth; all rights are reserved.
+% Copying of this file is authorized only if (1) you are D. E. Knuth, or if
+% (2) you make absolutely no changes to your copy. (The WEB system provides
+% for alterations via an auxiliary file; the master file should stay intact.)
+% See Appendix H of the WEB manual for hints on how to install this program.
+% And see Appendix A of the TRIP manual for details about how to validate it.
+
+% TeX is a trademark of the American Mathematical Society.
+% METAFONT is a trademark of Addison-Wesley Publishing Company.
+
+% Version 0 was released in September 1982 after it passed a variety of tests.
+% Version 1 was released in November 1983 after thorough testing.
+% Version 1.1 fixed ``disappearing font identifiers'' et alia (July 1984).
+% Version 1.2 allowed `0' in response to an error, et alia (October 1984).
+% Version 1.3 made memory allocation more flexible and local (November 1984).
+% Version 1.4 fixed accents right after line breaks, et alia (April 1985).
+% Version 1.5 fixed \the\toks after other expansion in \edefs (August 1985).
+% Version 2.0 (almost identical to 1.5) corresponds to "Volume B" (April 1986).
+% Version 2.1 corrected anomalies in discretionary breaks (January 1987).
+% Version 2.2 corrected "(Please type...)" with null \endlinechar (April 1987).
+% Version 2.3 avoided incomplete page in premature termination (August 1987).
+% Version 2.4 fixed \noaligned rules in indented displays (August 1987).
+% Version 2.5 saved cur_order when expanding tokens (September 1987).
+% Version 2.6 added 10sp slop when shipping leaders (November 1987).
+% Version 2.7 improved rounding of negative-width characters (November 1987).
+% Version 2.8 fixed weird bug if no \patterns are used (December 1987).
+% Version 2.9 made \csname\endcsname's "relax" local (December 1987).
+% Version 2.91 fixed \outer\def\a0{}\a\a bug (April 1988).
+% Version 2.92 fixed \patterns, also file names with complex macros (May 1988).
+% Version 2.93 fixed negative halving in allocator when mem_min<0 (June 1988).
+% Version 2.94 kept open_log_file from calling fatal_error (November 1988).
+% Version 2.95 solved that problem a better way (December 1988).
+% Version 2.96 corrected bug in "Infinite shrinkage" recovery (January 1989).
+% Version 2.97 corrected blunder in creating 2.95 (February 1989).
+% Version 2.98 omitted save_for_after at outer level (March 1989).
+% Version 2.99 caught $$\begingroup\halign..$$ (June 1989).
+% Version 2.991 caught .5\ifdim.6... (June 1989).
+% Version 2.992 introduced major changes for 8-bit extensions (September 1989).
+% Version 2.993 fixed a save_stack synchronization bug et alia (December 1989).
+% Version 3.0 fixed unusual displays; was more \output robust (March 1990).
+% Version 3.1 fixed nullfont, disabled \write{\the\prevgraf} (September 1990).
+% Version 3.14 fixed unprintable font names and corrected typos (March 1991).
+% Version 3.141 more of same; reconstituted ligatures better (March 1992).
+% Version 3.1415 preserved nonexplicit kerns, tidied up (February 1993).
+% Version 3.14159 allowed fontmemsize to change; bulletproofing (March 1995).
+% Version 3.141592 fixed \xleaders, glueset, weird alignments (December 2002).
+% Version 3.1415926 was a general cleanup with minor fixes (February 2008).
+
+% A reward of $327.68 will be paid to the first finder of any remaining bug.
+
+% Although considerable effort has been expended to make the TeX program
+% correct and reliable, no warranty is implied; the author disclaims any
+% obligation or liability for damages, including but not limited to
+% special, indirect, or consequential damages arising out of or in
+% connection with the use or performance of this software. This work has
+% been a ``labor of love'' and the author hopes that users enjoy it.
+
+% Here is TeX material that gets inserted after \input webmac
+\def\hang{\hangindent 3em\noindent\ignorespaces}
+\def\hangg#1 {\hang\hbox{#1 }}
+\def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps for names like SAIL
+\def\PASCAL{Pascal}
+\def\ph{\hbox{Pascal-H}}
+\def\pct!{{\char`\%}} % percent sign in ordinary text
+\font\logo=logo10 % font used for the METAFONT logo
+\def\MF{{\logo META}\-{\logo FONT}}
+\def\<#1>{$\langle#1\rangle$}
+\def\section{\mathhexbox278}
+
+\def\(#1){} % this is used to make section names sort themselves better
+\def\9#1{} % this is used for sort keys in the index via @:sort key}{entry@>
+
+\outer\def\N#1. \[#2]#3.{\MN#1.\vfil\eject % begin starred section
+  \def\rhead{PART #2:\uppercase{#3}} % define running headline
+  \message{*\modno} % progress report
+  \edef\next{\write\cont{\Z{\?#2]#3}{\modno}{\the\pageno}}}\next
+  \ifon\startsection{\bf\ignorespaces#3.\quad}\ignorespaces}
+\let\?=\relax % we want to be able to \write a \?
+
+\def\title{\TeX82}
+\def\topofcontents{\hsize 5.5in
+  \vglue 0pt plus 1fil minus 1.5in
+  \def\?##1]{\hbox{Changes to \hbox to 1em{\hfil##1}.\ }}
+  }
+\let\maybe=\iftrue
+\def\botofcontents{\vskip 0pt plus 1fil minus 1.5in}
+\pageno=3
+\def\glob{13} % this should be the section number of "<Global...>"
+\def\gglob{20, 26} % this should be the next two sections of "<Global...>"
+
+
+\N1.  \[1] Introduction.
+This is \TeX, a document compiler intended to produce typesetting of high
+quality.
+The \PASCAL\ program that follows is the definition of \TeX82, a standard
+version of \TeX\ that is designed to be highly portable so that identical
+output
+will be obtainable on a great variety of computers.
+
+The main purpose of the following program is to explain the algorithms of \TeX\
+as clearly as possible. As a result, the program will not necessarily be very
+efficient when a particular \PASCAL\ compiler has translated it into a
+particular machine language. However, the program has been written so that it
+can be tuned to run efficiently in a wide variety of operating environments
+by making comparatively few changes. Such flexibility is possible because
+the documentation that follows is written in the \.{WEB} language, which is
+at a higher level than \PASCAL; the preprocessing step that converts \.{WEB}
+to \PASCAL\ is able to introduce most of the necessary refinements.
+Semi-automatic translation to other languages is also feasible, because the
+program below does not make extensive use of features that are peculiar to
+\PASCAL.
+
+A large piece of software like \TeX\ has inherent complexity that cannot
+be reduced below a certain level of difficulty, although each individual
+part is fairly simple by itself. The \.{WEB} language is intended to make
+the algorithms as readable as possible, by reflecting the way the
+individual program pieces fit together and by providing the
+cross-references that connect different parts. Detailed comments about
+what is going on, and about why things were done in certain ways, have
+been liberally sprinkled throughout the program.  These comments explain
+features of the implementation, but they rarely attempt to explain the
+\TeX\ language itself, since the reader is supposed to be familiar with
+{\sl The \TeX book}.
+
+\fi
+
+\M2. The present implementation has a long ancestry, beginning in the summer
+of~1977, when Michael~F. Plass and Frank~M. Liang designed and coded
+a prototype
+based on some specifications that the author had made in May of that year.
+This original proto\TeX\ included macro definitions and elementary
+manipulations on boxes and glue, but it did not have line-breaking,
+page-breaking, mathematical formulas, alignment routines, error recovery,
+or the present semantic nest; furthermore,
+it used character lists instead of token lists, so that a control sequence
+like \.{\\halign} was represented by a list of seven characters. A
+complete version of \TeX\ was designed and coded by the author in late
+1977 and early 1978; that program, like its prototype, was written in the
+{\mc SAIL} language, for which an excellent debugging system was
+available. Preliminary plans to convert the {\mc SAIL} code into a form
+somewhat like the present ``web'' were developed by Luis Trabb~Pardo and
+the author at the beginning of 1979, and a complete implementation was
+created by Ignacio~A. Zabala in 1979 and 1980. The \TeX82 program, which
+was written by the author during the latter part of 1981 and the early
+part of 1982, also incorporates ideas from the 1979 implementation of
+\TeX\ in {\mc MESA} that was written by Leonidas Guibas, Robert Sedgewick,
+and Douglas Wyatt at the Xerox Palo Alto Research Center.  Several hundred
+refinements were introduced into \TeX82 based on the experiences gained with
+the original implementations, so that essentially every part of the system
+has been substantially improved. After the appearance of ``Version 0'' in
+September 1982, this program benefited greatly from the comments of
+many other people, notably David~R. Fuchs and Howard~W. Trickey.
+A final revision in September 1989 extended the input character set to
+eight-bit codes and introduced the ability to hyphenate words from
+different languages, based on some ideas of Michael~J. Ferguson.
+
+No doubt there still is plenty of room for improvement, but the author
+is firmly committed to keeping \TeX82 ``frozen'' from now on; stability
+and reliability are to be its main virtues.
+
+On the other hand, the \.{WEB} description can be extended without changing
+the core of \TeX82 itself, and the program has been designed so that such
+extensions are not extremely difficult to make.
+The \\{banner} string defined here should be changed whenever \TeX\
+undergoes any modifications, so that it will be clear which version of
+\TeX\ might be the guilty party when a problem arises.
+
+If this program is changed, the resulting system should not be called
+`\TeX'; the official name `\TeX' by itself is reserved
+for software systems that are fully compatible with each other.
+A special test suite called the ``\.{TRIP} test'' is available for
+helping to determine whether a particular implementation deserves to be
+known as `\TeX' [cf.~Stanford Computer Science report CS1027,
+November 1984].
+
+ML\TeX{} will add new primitives changing the behaviour of \TeX.  The
+\\{banner} string has to be changed.  We do not change the \\{banner}
+string, but will output an additional line to make clear that this is
+a modified \TeX{} version.
+
+
+\Y\P\D \37$\\{TeX\_banner\_k}\S\.{\'This\ is\ TeXk,\ Version\ 3.1415926\'}$%
+\C{printed when \TeX\ starts}\par
+\P\D \37$\\{TeX\_banner}\S\.{\'This\ is\ TeX,\ Version\ 3.1415926\'}$\C{printed
+when \TeX\ starts}\Y\par
+\P\D \37$\\{pTeX\_version\_string}\S\.{\'-p3.5\'}$\C{current p\TeX\ version}\Y%
+\par
+\P\D \37$\\{pTeX\_banner}\S\.{\'This\ is\ pTeX,\ Version\ 3.14159265\'},\39%
+\\{pTeX\_version\_string}$\par
+\P\D \37$\\{pTeX\_banner\_k}\S\\{pTeX\_banner}$\C{printed when p\TeX\ starts}\Y%
+\par
+\P\D \37$\\{banner}\S\\{pTeX\_banner}$\par
+\P\D \37$\\{banner\_k}\S\\{pTeX\_banner\_k}$\par
+\fi
+
+\M3. Different \PASCAL s have slightly different conventions, and the present
+program expresses \TeX\ in terms of the \PASCAL\ that was
+available to the author in 1982. Constructions that apply to
+this particular compiler, which we shall call \ph, should help the
+reader see how to make an appropriate interface for other systems
+if necessary. (\ph\ is Charles Hedrick's modification of a compiler
+for the DECsystem-10 that was originally developed at the University of
+Hamburg; cf.\ {\sl SOFTWARE---Practice \AM\ Experience \bf6} (1976),
+29--42. The \TeX\ program below is intended to be adaptable, without
+extensive changes, to most other versions of \PASCAL, so it does not fully
+use the admirable features of \ph. Indeed, a conscious effort has been
+made here to avoid using several idiosyncratic features of standard
+\PASCAL\ itself, so that most of the code can be translated mechanically
+into other high-level languages. For example, the `\&{with}' and `\\{new}'
+features are not used, nor are pointer types, set types, or enumerated
+scalar types; there are no `\&{var}' parameters, except in the case of files;
+there are no tag fields on variant records; there are no assignments
+$\\{real}\K\\{integer}$; no procedures are declared local to other procedures.)
+
+The portions of this program that involve system-dependent code, where
+changes might be necessary because of differences between \PASCAL\ compilers
+and/or differences between
+operating systems, can be identified by looking at the sections whose
+numbers are listed under `system dependencies' in the index. Furthermore,
+the index entries for `dirty \PASCAL' list all places where the restrictions
+of \PASCAL\ have not been followed perfectly, for one reason or another.
+
+Incidentally, \PASCAL's standard \\{round} function can be problematical,
+because it disagrees with the IEEE floating-point standard.
+Many implementors have
+therefore chosen to substitute their own home-grown rounding procedure.
+
+\fi
+
+\M4. The program begins with a normal \PASCAL\ program heading, whose
+components will be filled in later, using the conventions of \.{WEB}.
+For example, the portion of the program called `\X\glob:Global
+variables\X' below will be replaced by a sequence of variable declarations
+that starts in $\section\glob$ of this documentation. In this way, we are able
+to define each individual global variable when we are prepared to
+understand what it means; we do not have to define all of the globals at
+once.  Cross references in $\section\glob$, where it says ``See also
+sections \gglob, \dots,'' also make it possible to look at the set of
+all global variables, if desired.  Similar remarks apply to the other
+portions of the program heading.
+
+
+\Y\P\D \37$\\{mtype}\S\|t\J\|y\J\|p\J\|e$\C{this is a \.{WEB} coding trick:}\par
+\P\F \37$\\{mtype}\S\\{type}$\C{`\&{mtype}' will be equivalent to `\&{type}'}%
+\par
+\P\F \37$\\{type}\S\\{true}$\C{but `\\{type}' will not be treated as a reserved
+word}\par
+\Y\P\hbox{\4}\X9:Compiler directives\X\6
+\4\&{program}\1\  \37\\{TEX};\C{all file names are defined dynamically}\6
+\4\&{const} \37\X11:Constants in the outer block\X\6
+\4\&{mtype} \37\X18:Types in the outer block\X\6
+\4\&{var} \37\X13:Global variables\X\7
+\4\&{procedure}\1\  \37\\{initialize};\C{this procedure gets things started
+properly}\6
+\4\&{var} \37\X19:Local variables for initialization\X\2\6
+\&{begin} \37\X8:Initialize whatever \TeX\ might access\X\6
+\&{end};\7
+\hbox{\4}\X58:Basic printing procedures\X\6
+\hbox{\4}\X79:Error handling procedures\X\par
+\fi
+
+\M5. The overall \TeX\ program begins with the heading just shown, after which
+comes a bunch of procedure declarations and function declarations.
+Finally we will get to the main program, which begins with the
+comment `\\{start\_here}'. If you want to skip down to the
+main program now, you can look up `\\{start\_here}' in the index.
+But the author suggests that the best way to understand this program
+is to follow pretty much the order of \TeX's components as they appear in the
+\.{WEB} description you are now reading, since the present ordering is
+intended to combine the advantages of the ``bottom up'' and ``top down''
+approaches to the problem of understanding a somewhat complicated system.
+
+\fi
+
+\M6. For Web2c, labels are not declared in the main program, but
+we still have to declare the symbolic names.
+
+\Y\P\D \37$\\{start\_of\_TEX}=1$\C{go here when \TeX's variables are
+initialized}\par
+\P\D \37$\\{final\_end}=9999$\C{this label marks the ending of the program}\par
+\fi
+
+\M7. Some of the code below is intended to be used only when diagnosing the
+strange behavior that sometimes occurs when \TeX\ is being installed or
+when system wizards are fooling around with \TeX\ without quite knowing
+what they are doing. Such code will not normally be compiled; it is
+delimited by the codewords `$ \&{debug} \ldots  \&{gubed} $', with apologies
+to people who wish to preserve the purity of English.
+
+Similarly, there is some conditional code delimited by
+`$ \&{stat} \ldots  \&{tats} $' that is intended for use when statistics are to
+be
+kept about \TeX's memory usage.  The  \&{stat}  $\ldots$   \&{tats}  code also
+implements diagnostic information for \.{\\tracingparagraphs} and
+\.{\\tracingpages}.
+
+\Y\P\D \37$\\{debug}\S\\{ifdef}(\.{\'TEXMF\_DEBUG\'})$\par
+\P\D \37$\\{gubed}\S\\{endif}(\.{\'TEXMF\_DEBUG\'})$\par
+\P\F \37$\\{debug}\S\\{begin}$\par
+\P\F \37$\\{gubed}\S\\{end}$\Y\par
+\P\D \37$\\{stat}\S\\{ifdef}(\.{\'STAT\'})$\par
+\P\D \37$\\{tats}\S\\{endif}(\.{\'STAT\'})$\par
+\P\F \37$\\{stat}\S\\{begin}$\par
+\P\F \37$\\{tats}\S\\{end}$\par
+\fi
+
+\M8. This program has two important variations: (1) There is a long and slow
+version called \.{INITEX}, which does the extra calculations needed to
+initialize \TeX's internal tables; and (2)~there is a shorter and faster
+production version, which cuts the initialization to a bare minimum.
+Parts of the program that are needed in (1) but not in (2) are delimited by
+the codewords `$ \&{init} \ldots  \&{tini} $' for declarations and by the
+codewords
+`$ \&{Init} \ldots  \&{Tini} $' for executable code.  This distinction is
+helpful for
+implementations where a run-time switch differentiates between the two
+versions of the program.
+
+\Y\P\D \37$\\{init}\S\\{ifdef}(\.{\'INITEX\'})$\par
+\P\D \37$\\{tini}\S\\{endif}(\.{\'INITEX\'})$\par
+\P\D $\\{Init}\S$ \6
+\&{init}   \6
+\&{if} $\\{ini\_version}$ \1\&{then} \6
+\&{begin} \37\par
+\P\D \37$\\{Tini}\S$ \6
+\&{end} ;\ \&{tini} \par
+\P\F \37$\\{Init}\S\\{begin}$\par
+\P\F \37$\\{Tini}\S\\{end}$\par
+\P\F \37$\\{init}\S\\{begin}$\par
+\P\F \37$\\{tini}\S\\{end}$\par
+\Y\P$\4\X8:Initialize whatever \TeX\ might access\X\S$\6
+\X21:Set initial values of key variables\X\6
+\&{Init} \37\X170:Initialize table entries (done by \.{INITEX} only)\X\ %
+\&{Tini}\par
+\U4.\fi
+
+\M9. If the first character of a \PASCAL\ comment is a dollar sign,
+\ph\ treats the comment as a list of ``compiler directives'' that will
+affect the translation of this program into machine language.  The
+directives shown below specify full checking and inclusion of the \PASCAL\
+debugger when \TeX\ is being debugged, but they cause range checking and other
+redundant code to be eliminated when the production system is being generated.
+Arithmetic overflow will be detected in all cases.
+
+\Y\P$\4\X9:Compiler directives\X\S$\6
+$\B\J\$\|C-,\39\|A+,\39\|D-\T$\C{no range check, catch arithmetic overflow, no
+debug overhead}\6
+\&{debug} \37$\B\J\$\|C+,\39\|D+\T$\ \&{gubed}\C{but turn everything on when
+debugging}\par
+\U4.\fi
+
+\M10. This \TeX\ implementation conforms to the rules of the {\sl Pascal User
+Manual} published by Jensen and Wirth in 1975, except where system-dependent
+code is necessary to make a useful system program, and except in another
+respect where such conformity would unnecessarily obscure the meaning
+and clutter up the code: We assume that   \&{case}  statements may include a
+default case that applies if no matching label is found. Thus, we shall use
+constructions like
+$$\vbox{\halign{\ignorespaces#\hfil\cr
+ \&{case} $\|x$ \&{of}\cr
+1: $\langle\,$code for $x=1\,\rangle$;\cr
+3: $\langle\,$code for $x=3\,\rangle$;\cr
+ \&{othercases}  $\langle\,$code for $\|x\I1$ and $\|x\I3$$\,\rangle$\cr
+  \&{endcases} \cr}}$$
+since most \PASCAL\ compilers have plugged this hole in the language by
+incorporating some sort of default mechanism. For example, the \ph\
+compiler allows `\\{others}:' as a default label, and other \PASCAL s allow
+syntaxes like `\&{else}' or `\&{otherwise}' or `\\{otherwise}:', etc. The
+definitions of  \&{othercases}  and   \&{endcases}  should be changed to agree
+with
+local conventions.  Note that no semicolon appears before   \&{endcases}  in
+this program, so the definition of   \&{endcases}  should include a semicolon
+if the compiler wants one. (Of course, if no default mechanism is
+available, the   \&{case}  statements of \TeX\ will have to be laboriously
+extended by listing all remaining cases. People who are stuck with such
+\PASCAL s have, in fact, done this, successfully but not happily!)
+
+\Y\P\D \37$\\{othercases}\S\\{others}$: \37\C{default for cases not listed
+explicitly}\par
+\P\D \37$\\{endcases}\S$\ \&{end} \C{follows the default case in an extended   %
+\&{case}  statement}\par
+\P\F \37$\\{othercases}\S\\{else}$\par
+\P\F \37$\\{endcases}\S\\{end}$\par
+\fi
+
+\M11. The following parameters can be changed at compile time to extend or
+reduce \TeX's capacity. They may have different values in \.{INITEX} and
+in production versions of \TeX.
+
+\Y\P\D \37$\\{file\_name\_size}\S\\{maxint}$\par
+\P\D \37$\\{ssup\_error\_line}=255$\par
+\P\D \37$\\{ssup\_max\_strings}\S2097151$\C{Larger values than 65536 cause the
+arrays to consume much more memory.}\par
+\P\D \37$\\{ssup\_trie\_opcode}\S65535$\par
+\P\D \37$\\{ssup\_trie\_size}\S\H{3FFFFF}$\par
+\P\D \37$\\{ssup\_hyph\_size}\S65535$\C{Changing this requires changing
+(un)dumping!}\par
+\P\D \37$\\{iinf\_hyphen\_size}\S610$\C{Must be not less than \\{hyph\_prime}!}%
+\par
+\P\D \37$\\{max\_font\_max}=9000$\C{maximum number of internal fonts; this can
+be                       increased, but $\\{hash\_size}+\\{max\_font\_max}$
+                  should not exceed 29000.}\par
+\P\D \37$\\{font\_base}=0$\C{smallest internal font number; must be
+    $\G\\{min\_quarterword}$; do not change this without
+modifying the dynamic definition of the font arrays.}\par
+\Y\P$\4\X11:Constants in the outer block\X\S$\6
+$\\{hash\_offset}=514$;\C{smallest index in hash array, i.e., \\{hash\_base} }\6
+\C{Use $\\{hash\_offset}=0$ for compilers which cannot decrement pointers.}\6
+$\\{trie\_op\_size}=35111$;\C{space for ``opcodes'' in the hyphenation
+patterns;   best if relatively prime to 313, 361, and 1009.}\6
+$\\{neg\_trie\_op\_size}=-35111$;\C{for lower \\{trie\_op\_hash} array bound;
+must be equal to $-\\{trie\_op\_size}$.}\6
+$\\{min\_trie\_op}=0$;\C{first possible trie op code for any language}\6
+$\\{max\_trie\_op}=\\{ssup\_trie\_opcode}$;\C{largest possible trie opcode for
+any language}\6
+$\\{pool\_name}=\\{TEXMF\_POOL\_NAME}$;\C{this is configurable, for the sake of
+ML-\TeX}\6
+\C{string of length \\{file\_name\_size}; tells where the string pool appears}\6
+$\\{engine\_name}=\\{TEXMF\_ENGINE\_NAME}$;\C{the name of this engine}\7
+$\\{inf\_mem\_bot}=0$;\5
+$\\{sup\_mem\_bot}=1$;\5
+$\\{inf\_main\_memory}=3000$;\5
+$\\{sup\_main\_memory}=256000000$;\5
+$\\{inf\_trie\_size}=8000$;\5
+$\\{sup\_trie\_size}=\\{ssup\_trie\_size}$;\5
+$\\{inf\_max\_strings}=3000$;\5
+$\\{sup\_max\_strings}=\\{ssup\_max\_strings}$;\5
+$\\{inf\_strings\_free}=100$;\5
+$\\{sup\_strings\_free}=\\{sup\_max\_strings}$;\5
+$\\{inf\_buf\_size}=500$;\5
+$\\{sup\_buf\_size}=30000000$;\5
+$\\{inf\_nest\_size}=40$;\5
+$\\{sup\_nest\_size}=4000$;\5
+$\\{inf\_max\_in\_open}=6$;\5
+$\\{sup\_max\_in\_open}=127$;\5
+$\\{inf\_param\_size}=60$;\5
+$\\{sup\_param\_size}=32767$;\5
+$\\{inf\_save\_size}=600$;\5
+$\\{sup\_save\_size}=80000$;\5
+$\\{inf\_stack\_size}=200$;\5
+$\\{sup\_stack\_size}=30000$;\5
+$\\{inf\_dvi\_buf\_size}=800$;\5
+$\\{sup\_dvi\_buf\_size}=65536$;\5
+$\\{inf\_font\_mem\_size}=20000$;\5
+$\\{sup\_font\_mem\_size}=147483647$;\C{\\{integer}-limited, so 2 could be
+prepended?}\6
+$\\{sup\_font\_max}=\\{max\_font\_max}$;\5
+$\\{inf\_font\_max}=50$;\C{could be smaller, but why?}\6
+$\\{inf\_pool\_size}=32000$;\5
+$\\{sup\_pool\_size}=40000000$;\5
+$\\{inf\_pool\_free}=1000$;\5
+$\\{sup\_pool\_free}=\\{sup\_pool\_size}$;\5
+$\\{inf\_string\_vacancies}=8000$;\5
+$\\{sup\_string\_vacancies}=\\{sup\_pool\_size}-23000$;\5
+$\\{sup\_hash\_extra}=\\{sup\_max\_strings}$;\5
+$\\{inf\_hash\_extra}=0$;\5
+$\\{sup\_hyph\_size}=\\{ssup\_hyph\_size}$;\5
+$\\{inf\_hyph\_size}=\\{iinf\_hyphen\_size}$;\C{Must be not less than \\{hyph%
+\_prime}!}\6
+$\\{inf\_expand\_depth}=10$;\5
+$\\{sup\_expand\_depth}=10000000$;\par
+\U4.\fi
+
+\M12. Like the preceding parameters, the following quantities can be changed
+at compile time to extend or reduce \TeX's capacity. But if they are changed,
+it is necessary to rerun the initialization program \.{INITEX}
+to generate new tables for the production \TeX\ program.
+One can't simply make helter-skelter changes to the following constants,
+since certain rather complex initialization
+numbers are computed from them. They are defined here using
+\.{WEB} macros, instead of being put into \PASCAL's  \&{const}  list, in order
+to
+emphasize this distinction.
+
+\Y\P\D \37$\\{hash\_size}=15000$\C{maximum number of control sequences; it
+should be at most   about $(\\{mem\_max}-\\{mem\_min})/10$; see also \\{font%
+\_max}}\par
+\P\D \37$\\{hash\_prime}=8501$\C{a prime number equal to about 85\pct! of %
+\\{hash\_size}}\par
+\P\D \37$\\{hyph\_prime}=607$\C{another prime for hashing \.{\\hyphenation}
+exceptions;                 if you change this, you should also change \\{iinf%
+\_hyphen\_size}.}\par
+\fi
+
+\M13. In case somebody has inadvertently made bad settings of the
+``constants,''
+\TeX\ checks them using a global variable called \\{bad}.
+
+This is the first of many sections of \TeX\ where global variables are
+defined.
+
+\Y\P$\4\X13:Global variables\X\S$\6
+\4\\{bad}: \37\\{integer};\C{is some ``constant'' wrong?}\par
+\As20, 26, 31, 33, 40, 51, 55, 74, 77, 80, 97, 105, 116, 117, 118, 119, 125,
+171, 179, 187, 219, 252, 259, 262, 277, 292, 303, 307, 310, 311, 314, 315, 316,
+339, 354, 369, 375, 393, 398, 399, 421, 449, 458, 491, 500, 504, 523, 524, 531,
+538, 543, 550, 560, 561, 566, 603, 606, 616, 627, 657, 658, 672, 695, 730, 735,
+775, 781, 825, 832, 834, 836, 839, 844, 850, 858, 883, 903, 911, 916, 918, 932,
+937, 954, 958, 961, 982, 991, 993, 1000, 1043, 1086, 1279, 1294, 1312, 1318,
+1344, 1355, 1358, 1392, 1394, 1396, 1404, 1405, 1410, 1430, 1446\ETs1449.
+\U4.\fi
+
+\M14. Later on we will say `\ignorespaces \&{if} $\\{mem\_max}\G\\{max%
+\_halfword}$ \&{then} $\\{bad}\K14$',
+or something similar. (We can't do that until \\{max\_halfword} has been
+defined.)
+
+\Y\P$\4\X14:Check the ``constant'' values for consistency\X\S$\6
+$\\{bad}\K0$;\6
+\&{if} $(\\{half\_error\_line}<30)\V(\\{half\_error\_line}>\\{error\_line}-15)$
+\1\&{then}\5
+$\\{bad}\K1$;\2\6
+\&{if} $\\{max\_print\_line}<60$ \1\&{then}\5
+$\\{bad}\K2$;\2\6
+\&{if} $\\{dvi\_buf\_size}\mathbin{\&{mod}}8\I0$ \1\&{then}\5
+$\\{bad}\K3$;\2\6
+\&{if} $\\{mem\_bot}+1100>\\{mem\_top}$ \1\&{then}\5
+$\\{bad}\K4$;\2\6
+\&{if} $\\{hash\_prime}>\\{hash\_size}$ \1\&{then}\5
+$\\{bad}\K5$;\2\6
+\&{if} $\\{max\_in\_open}\G128$ \1\&{then}\5
+$\\{bad}\K6$;\2\6
+\&{if} $\\{mem\_top}<256+11$ \1\&{then}\5
+$\\{bad}\K7$;\C{we will want $\\{null\_list}>255$}\2\par
+\As112, 296, 533\ETs1262.
+\U1345.\fi
+
+\M15. Labels are given symbolic names by the following definitions, so that
+occasional \&{goto}  statements will be meaningful. We insert the label
+`\\{exit}' just before the `\ignorespaces  \&{end} \unskip' of a procedure in
+which we have used the `\&{return}' statement defined below; the label
+`\\{restart}' is occasionally used at the very beginning of a procedure; and
+the label `\\{reswitch}' is occasionally used just prior to a   \&{case}
+statement in which some cases change the conditions and we wish to branch
+to the newly applicable case.  Loops that are set up with the  \~ \&{loop}
+construction defined below are commonly exited by going to `\\{done}' or to
+`\\{found}' or to `\\{not\_found}', and they are sometimes repeated by going to
+`\\{continue}'.  If two or more parts of a subroutine start differently but
+end up the same, the shared code may be gathered together at
+`\\{common\_ending}'.
+
+Incidentally, this program never declares a label that isn't actually used,
+because some fussy \PASCAL\ compilers will complain about redundant labels.
+
+\Y\P\D \37$\\{exit}=10$\C{go here to leave a procedure}\par
+\P\D \37$\\{restart}=20$\C{go here to start a procedure again}\par
+\P\D \37$\\{reswitch}=21$\C{go here to start a case statement again}\par
+\P\D \37$\\{continue}=22$\C{go here to resume a loop}\par
+\P\D \37$\\{done}=30$\C{go here to exit a loop}\par
+\P\D \37$\\{done1}=31$\C{like \\{done}, when there is more than one loop}\par
+\P\D \37$\\{done2}=32$\C{for exiting the second loop in a long block}\par
+\P\D \37$\\{done3}=33$\C{for exiting the third loop in a very long block}\par
+\P\D \37$\\{done4}=34$\C{for exiting the fourth loop in an extremely long
+block}\par
+\P\D \37$\\{done5}=35$\C{for exiting the fifth loop in an immense block}\par
+\P\D \37$\\{done6}=36$\C{for exiting the sixth loop in a block}\par
+\P\D \37$\\{found}=40$\C{go here when you've found it}\par
+\P\D \37$\\{found1}=41$\C{like \\{found}, when there's more than one per
+routine}\par
+\P\D \37$\\{found2}=42$\C{like \\{found}, when there's more than two per
+routine}\par
+\P\D \37$\\{not\_found}=45$\C{go here when you've found nothing}\par
+\P\D \37$\\{common\_ending}=50$\C{go here when you want to merge with another
+branch}\par
+\fi
+
+\M16. Here are some macros for common programming idioms.
+
+\Y\P\D \37$\\{negate}(\#)\S\#\K-\#$\C{change the sign of a variable}\par
+\P\D \37$\\{loop}\S$\ \&{while} $\\{true}$ \1\&{do}\ \C{repeat over and over
+until a \&{goto}  happens}\par
+\P\F \37$\\{loop}\S\\{xclause}$\C{\.{WEB}'s  \~ \&{xclause} acts like `%
+\ignorespaces \&{while} $\\{true}$ \&{do}\unskip'}\par
+\P\D \37$\\{do\_nothing}\S$\C{empty statement}\par
+\P\D \37$\\{return}\S$\1\5
+\&{goto} \37\\{exit}\C{terminate a procedure call}\2\par
+\P\F \37$\\{return}\S\\{nil}$\par
+\P\D \37$\\{empty}=0$\C{symbolic name for a null constant}\par
+\fi
+
+\N17.  \[2] The character set.
+In order to make \TeX\ readily portable to a wide variety of
+computers, all of its input text is converted to an internal eight-bit
+code that includes standard ASCII, the ``American Standard Code for
+Information Interchange.''  This conversion is done immediately when each
+character is read in. Conversely, characters are converted from ASCII to
+the user's external representation just before they are output to a
+text file.
+
+Such an internal code is relevant to users of \TeX\ primarily because it
+governs the positions of characters in the fonts. For example, the
+character `\.A' has ASCII code $65=\O{101}$, and when \TeX\ typesets
+this letter it specifies character number 65 in the current font.
+If that font actually has `\.A' in a different position, \TeX\ doesn't
+know what the real position is; the program that does the actual printing from
+\TeX's device-independent files is responsible for converting from ASCII to
+a particular font encoding.
+
+\TeX's internal code also defines the value of constants
+that begin with a reverse apostrophe; and it provides an index to the
+\.{\\catcode}, \.{\\mathcode}, \.{\\uccode}, \.{\\lccode}, and \.{\\delcode}
+tables.
+
+\fi
+
+\M18. Characters of text that have been converted to \TeX's internal form
+are said to be of type \\{ASCII\_code}, which is a subrange of the integers.
+
+\Y\P$\4\X18:Types in the outer block\X\S$\6
+$\\{ASCII\_code}=0\to255$;\C{eight-bit numbers}\6
+$\\{KANJI\_code}=0\to65535$;\C{sixteen-bit numbers}\par
+\As25, 39, 102, 110, 114, 156, 218, 275, 306, 559, 605, 931\ETs936.
+\U4.\fi
+
+\M19. The original \PASCAL\ compiler was designed in the late 60s, when six-bit
+character sets were common, so it did not make provision for lowercase
+letters. Nowadays, of course, we need to deal with both capital and small
+letters in a convenient way, especially in a program for typesetting;
+so the present specification of \TeX\ has been written under the assumption
+that the \PASCAL\ compiler and run-time system permit the use of text files
+with more than 64 distinguishable characters. More precisely, we assume that
+the character set contains at least the letters and symbols associated
+with ASCII codes \O{40} through \O{176}; all of these characters are now
+available on most computer terminals.
+
+Since we are dealing with more characters than were present in the first
+\PASCAL\ compilers, we have to decide what to call the associated data
+type. Some \PASCAL s use the original name \\{char} for the
+characters in text files, even though there now are more than 64 such
+characters, while other \PASCAL s consider \\{char} to be a 64-element
+subrange of a larger data type that has some other name.
+
+In order to accommodate this difference, we shall use the name \\{text\_char}
+to stand for the data type of the characters that are converted to and
+from \\{ASCII\_code} when they are input and output. We shall also assume
+that \\{text\_char} consists of the elements $\\{chr}(\\{first\_text\_char})$
+through
+$\\{chr}(\\{last\_text\_char})$, inclusive. The following definitions should be
+adjusted if necessary.
+
+\Y\P\D \37$\\{text\_char}\S\\{ASCII\_code}$\C{the data type of characters in
+text files}\par
+\P\D \37$\\{first\_text\_char}=0$\C{ordinal number of the smallest element of %
+\\{text\_char}}\par
+\P\D \37$\\{last\_text\_char}=255$\C{ordinal number of the largest element of %
+\\{text\_char}}\par
+\Y\P$\4\X19:Local variables for initialization\X\S$\6
+\4\|i: \37\\{integer};\par
+\As169\ET938.
+\U4.\fi
+
+\M20. The \TeX\ processor converts between ASCII code and
+the user's external character set by means of arrays \\{xord} and \\{xchr}
+that are analogous to \PASCAL's \\{ord} and \\{chr} functions.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{xord}: \37\&{array} $[\\{text\_char}]$ \1\&{of}\5
+\\{ASCII\_code};\C{specifies conversion of input characters}\2\6
+\4\\{xchr}: \37\&{array} $[\\{ASCII\_code}]$ \1\&{of}\5
+\\{text\_char};\C{ specifies conversion of output characters }\2\6
+\4\\{xprn}: \37\&{array} $[\\{ASCII\_code}]$ \1\&{of}\5
+\\{ASCII\_code};\C{ non zero iff character is printable }\2\par
+\fi
+
+\M21. Since we are assuming that our \PASCAL\ system is able to read and
+write the visible characters of standard ASCII (although not
+necessarily using the ASCII codes to represent them), the following
+assignment statements initialize the standard part of the \\{xchr} array
+properly, without needing any system-dependent changes. On the other
+hand, it is possible to implement \TeX\ with less complete character
+sets, and in such cases it will be necessary to change something here.
+
+\Y\P$\4\X21:Set initial values of key variables\X\S$\6
+$\\{xchr}[\O{40}]\K\.{\'\ \'}$;\5
+$\\{xchr}[\O{41}]\K\.{\'!\'}$;\5
+$\\{xchr}[\O{42}]\K\.{\'"\'}$;\5
+$\\{xchr}[\O{43}]\K\.{\'\#\'}$;\5
+$\\{xchr}[\O{44}]\K\.{\'\$\'}$;\5
+$\\{xchr}[\O{45}]\K\.{\'\%\'}$;\5
+$\\{xchr}[\O{46}]\K\.{\'\&\'}$;\5
+$\\{xchr}[\O{47}]\K\.{\'\'}\.{\'\'}$;\6
+$\\{xchr}[\O{50}]\K\.{\'(\'}$;\5
+$\\{xchr}[\O{51}]\K\.{\')\'}$;\5
+$\\{xchr}[\O{52}]\K\.{\'*\'}$;\5
+$\\{xchr}[\O{53}]\K\.{\'+\'}$;\5
+$\\{xchr}[\O{54}]\K\.{\',\'}$;\5
+$\\{xchr}[\O{55}]\K\.{\'-\'}$;\5
+$\\{xchr}[\O{56}]\K\.{\'.\'}$;\5
+$\\{xchr}[\O{57}]\K\.{\'/\'}$;\6
+$\\{xchr}[\O{60}]\K\.{\'0\'}$;\5
+$\\{xchr}[\O{61}]\K\.{\'1\'}$;\5
+$\\{xchr}[\O{62}]\K\.{\'2\'}$;\5
+$\\{xchr}[\O{63}]\K\.{\'3\'}$;\5
+$\\{xchr}[\O{64}]\K\.{\'4\'}$;\5
+$\\{xchr}[\O{65}]\K\.{\'5\'}$;\5
+$\\{xchr}[\O{66}]\K\.{\'6\'}$;\5
+$\\{xchr}[\O{67}]\K\.{\'7\'}$;\6
+$\\{xchr}[\O{70}]\K\.{\'8\'}$;\5
+$\\{xchr}[\O{71}]\K\.{\'9\'}$;\5
+$\\{xchr}[\O{72}]\K\.{\':\'}$;\5
+$\\{xchr}[\O{73}]\K\.{\';\'}$;\5
+$\\{xchr}[\O{74}]\K\.{\'<\'}$;\5
+$\\{xchr}[\O{75}]\K\.{\'=\'}$;\5
+$\\{xchr}[\O{76}]\K\.{\'>\'}$;\5
+$\\{xchr}[\O{77}]\K\.{\'?\'}$;\6
+$\\{xchr}[\O{100}]\K\.{\'@\'}$;\5
+$\\{xchr}[\O{101}]\K\.{\'A\'}$;\5
+$\\{xchr}[\O{102}]\K\.{\'B\'}$;\5
+$\\{xchr}[\O{103}]\K\.{\'C\'}$;\5
+$\\{xchr}[\O{104}]\K\.{\'D\'}$;\5
+$\\{xchr}[\O{105}]\K\.{\'E\'}$;\5
+$\\{xchr}[\O{106}]\K\.{\'F\'}$;\5
+$\\{xchr}[\O{107}]\K\.{\'G\'}$;\6
+$\\{xchr}[\O{110}]\K\.{\'H\'}$;\5
+$\\{xchr}[\O{111}]\K\.{\'I\'}$;\5
+$\\{xchr}[\O{112}]\K\.{\'J\'}$;\5
+$\\{xchr}[\O{113}]\K\.{\'K\'}$;\5
+$\\{xchr}[\O{114}]\K\.{\'L\'}$;\5
+$\\{xchr}[\O{115}]\K\.{\'M\'}$;\5
+$\\{xchr}[\O{116}]\K\.{\'N\'}$;\5
+$\\{xchr}[\O{117}]\K\.{\'O\'}$;\6
+$\\{xchr}[\O{120}]\K\.{\'P\'}$;\5
+$\\{xchr}[\O{121}]\K\.{\'Q\'}$;\5
+$\\{xchr}[\O{122}]\K\.{\'R\'}$;\5
+$\\{xchr}[\O{123}]\K\.{\'S\'}$;\5
+$\\{xchr}[\O{124}]\K\.{\'T\'}$;\5
+$\\{xchr}[\O{125}]\K\.{\'U\'}$;\5
+$\\{xchr}[\O{126}]\K\.{\'V\'}$;\5
+$\\{xchr}[\O{127}]\K\.{\'W\'}$;\6
+$\\{xchr}[\O{130}]\K\.{\'X\'}$;\5
+$\\{xchr}[\O{131}]\K\.{\'Y\'}$;\5
+$\\{xchr}[\O{132}]\K\.{\'Z\'}$;\5
+$\\{xchr}[\O{133}]\K\.{\'[\'}$;\5
+$\\{xchr}[\O{134}]\K\.{\'\\\'}$;\5
+$\\{xchr}[\O{135}]\K\.{\']\'}$;\5
+$\\{xchr}[\O{136}]\K\.{\'\^\'}$;\5
+$\\{xchr}[\O{137}]\K\.{\'\_\'}$;\6
+$\\{xchr}[\O{140}]\K\.{\'\`\'}$;\5
+$\\{xchr}[\O{141}]\K\.{\'a\'}$;\5
+$\\{xchr}[\O{142}]\K\.{\'b\'}$;\5
+$\\{xchr}[\O{143}]\K\.{\'c\'}$;\5
+$\\{xchr}[\O{144}]\K\.{\'d\'}$;\5
+$\\{xchr}[\O{145}]\K\.{\'e\'}$;\5
+$\\{xchr}[\O{146}]\K\.{\'f\'}$;\5
+$\\{xchr}[\O{147}]\K\.{\'g\'}$;\6
+$\\{xchr}[\O{150}]\K\.{\'h\'}$;\5
+$\\{xchr}[\O{151}]\K\.{\'i\'}$;\5
+$\\{xchr}[\O{152}]\K\.{\'j\'}$;\5
+$\\{xchr}[\O{153}]\K\.{\'k\'}$;\5
+$\\{xchr}[\O{154}]\K\.{\'l\'}$;\5
+$\\{xchr}[\O{155}]\K\.{\'m\'}$;\5
+$\\{xchr}[\O{156}]\K\.{\'n\'}$;\5
+$\\{xchr}[\O{157}]\K\.{\'o\'}$;\6
+$\\{xchr}[\O{160}]\K\.{\'p\'}$;\5
+$\\{xchr}[\O{161}]\K\.{\'q\'}$;\5
+$\\{xchr}[\O{162}]\K\.{\'r\'}$;\5
+$\\{xchr}[\O{163}]\K\.{\'s\'}$;\5
+$\\{xchr}[\O{164}]\K\.{\'t\'}$;\5
+$\\{xchr}[\O{165}]\K\.{\'u\'}$;\5
+$\\{xchr}[\O{166}]\K\.{\'v\'}$;\5
+$\\{xchr}[\O{167}]\K\.{\'w\'}$;\6
+$\\{xchr}[\O{170}]\K\.{\'x\'}$;\5
+$\\{xchr}[\O{171}]\K\.{\'y\'}$;\5
+$\\{xchr}[\O{172}]\K\.{\'z\'}$;\5
+$\\{xchr}[\O{173}]\K\.{\'\{\'}$;\5
+$\\{xchr}[\O{174}]\K\.{\'|\'}$;\5
+$\\{xchr}[\O{175}]\K\.{\'\}\'}$;\5
+$\\{xchr}[\O{176}]\K\.{\'\~\'}$;\par
+\As23, 24, 75, 78, 81, 98, 172, 221, 260, 263, 278, 293, 355, 376, 394, 450,
+492, 501, 562, 567, 604, 607, 617, 659, 673, 696, 782, 939, 1001, 1044, 1280,
+1295, 1313, 1356, 1393, 1397, 1406, 1431\ETs1447.
+\U8.\fi
+
+\M22. Some of the ASCII codes without visible characters have been given
+symbolic
+names in this program because they are used with a special meaning.
+
+\Y\P\D \37$\\{null\_code}=\O{0}$\C{ASCII code that might disappear}\par
+\P\D \37$\\{carriage\_return}=\O{15}$\C{ASCII code used at end of line}\par
+\P\D \37$\\{invalid\_code}=\O{177}$\C{ASCII code that many systems prohibit in
+text files}\par
+\fi
+
+\M23. The ASCII code is ``standard'' only to a certain extent, since many
+computer installations have found it advantageous to have ready access
+to more than 94 printing characters. Appendix~C of {\sl The \TeX book\/}
+gives a complete specification of the intended correspondence between
+characters and \TeX's internal representation.
+
+If \TeX\ is being used
+on a garden-variety \PASCAL\ for which only standard ASCII
+codes will appear in the input and output files, it doesn't really matter
+what codes are specified in $\\{xchr}[0\to\O{37}]$, but the safest policy is to
+blank everything out by using the code shown below.
+
+However, other settings of \\{xchr} will make \TeX\ more friendly on
+computers that have an extended character set, so that users can type things
+like `\.^^Z' instead of `\.{\\ne}'. People with extended character sets can
+assign codes arbitrarily, giving an \\{xchr} equivalent to whatever
+characters the users of \TeX\ are allowed to have in their input files.
+It is best to make the codes correspond to the intended interpretations as
+shown in Appendix~C whenever possible; but this is not necessary. For
+example, in countries with an alphabet of more than 26 letters, it is
+usually best to map the additional letters into codes less than~\O{40}.
+To get the most ``permissive'' character set, change \.{\'\ \'} on the
+right of these assignment statements to $\\{chr}(\|i)$.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+\C{Initialize \\{xchr} to the identity mapping.}\6
+\&{for} $\|i\K0\mathrel{\&{to}}\O{37}$ \1\&{do}\5
+$\\{xchr}[\|i]\K\|i$;\2\6
+\&{for} $\|i\K\O{177}\mathrel{\&{to}}\O{377}$ \1\&{do}\5
+$\\{xchr}[\|i]\K\|i$;\2\par
+\fi
+
+\M24. The following system-independent code makes the \\{xord} array contain a
+suitable inverse to the information in \\{xchr}. Note that if $\\{xchr}[\|i]=%
+\\{xchr}[\|j]$
+where $\|i<\|j<\O{177}$, the value of $\\{xord}[\\{xchr}[\|i]]$ will turn out
+to be
+\|j or more; hence, standard ASCII code numbers will be used instead of
+codes below \O{40} in case there is a coincidence.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+\&{for} $\|i\K\\{first\_text\_char}\mathrel{\&{to}}\\{last\_text\_char}$ \1%
+\&{do}\5
+$\\{xord}[\\{chr}(\|i)]\K\\{invalid\_code}$;\2\6
+\&{for} $\|i\K\O{200}\mathrel{\&{to}}\O{377}$ \1\&{do}\5
+$\\{xord}[\\{xchr}[\|i]]\K\|i$;\2\6
+\&{for} $\|i\K0\mathrel{\&{to}}\O{176}$ \1\&{do}\5
+$\\{xord}[\\{xchr}[\|i]]\K\|i$;\C{Set \\{xprn} for printable ASCII, unless %
+\\{eight\_bit\_p} is set.}\2\6
+\&{for} $\|i\K0\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{xprn}[\|i]\K(\\{eight\_bit\_p}\V((\|i\G\.{"\ "})\W(\|i\L\.{"\~"})))$;\C{The
+idea for this dynamic translation comes from the patch by  Libor Skarvada %
+\.{<libor@informatics.muni.cz>}  and Petr Sojka %
+\.{<sojka@informatics.muni.cz>}. I didn't use any of the  actual code, though,
+preferring a more general approach.}\6
+\C{This updates the \\{xchr}, \\{xord}, and \\{xprn} arrays from the provided  %
+\\{translate\_filename}.  See the function definition in \.{texmfmp.c} for
+more comments.}\2\6
+\&{if} $\\{translate\_filename}$ \1\&{then}\5
+\\{read\_tcx\_file};\2\par
+\fi
+
+\N25.  \[3] Input and output.
+The bane of portability is the fact that different operating systems treat
+input and output quite differently, perhaps because computer scientists
+have not given sufficient attention to this problem. People have felt somehow
+that input and output are not part of ``real'' programming. Well, it is true
+that some kinds of programming are more fun than others. With existing
+input/output conventions being so diverse and so messy, the only sources of
+joy in such parts of the code are the rare occasions when one can find a
+way to make the program a little less bad than it might have been. We have
+two choices, either to attack I/O now and get it over with, or to postpone
+I/O until near the end. Neither prospect is very attractive, so let's
+get it over with.
+
+The basic operations we need to do are (1)~inputting and outputting of
+text, to or from a file or the user's terminal; (2)~inputting and
+outputting of eight-bit bytes, to or from a file; (3)~instructing the
+operating system to initiate (``open'') or to terminate (``close'') input or
+output from a specified file; (4)~testing whether the end of an input
+file has been reached.
+
+\TeX\ needs to deal with two kinds of files.
+We shall use the term \\{alpha\_file} for a file that contains textual data,
+and the term \\{byte\_file} for a file that contains eight-bit binary
+information.
+These two types turn out to be the same on many computers, but
+sometimes there is a significant distinction, so we shall be careful to
+distinguish between them. Standard protocols for transferring
+such files from computer to computer, via high-speed networks, are
+now becoming available to more and more communities of users.
+
+The program actually makes use also of a third kind of file, called a
+\\{word\_file}, when dumping and reloading base information for its own
+initialization.  We shall define a word file later; but it will be possible
+for us to specify simple operations on word files before they are defined.
+
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{eight\_bits}=0\to255$;\C{unsigned one-byte quantity}\6
+$\\{sixteen\_bits}=0\to65535$;\C{unsigned two-bytes quantity}\6
+$\\{alpha\_file}=$\1\5
+\&{packed} \37\&{file} \1\&{of}\5
+\\{text\_char};\C{files that contain textual data}\2\2\6
+$\\{byte\_file}=$\1\5
+\&{packed} \37\&{file} \1\&{of}\5
+\\{eight\_bits};\C{files that contain binary data}\2\2\par
+\fi
+
+\M26. Most of what we need to do with respect to input and output can be
+handled
+by the I/O facilities that are standard in \PASCAL, i.e., the routines
+called \\{get}, \\{put}, \\{eof}, and so on. But
+standard \PASCAL\ does not allow file variables to be associated with file
+names that are determined at run time, so it cannot be used to implement
+\TeX; some sort of extension to \PASCAL's ordinary \\{reset} and \\{rewrite}
+is crucial for our purposes. We shall assume that \\{name\_of\_file} is a
+variable
+of an appropriate type such that the \PASCAL\ run-time system being used to
+implement \TeX\ can open a file whose external name is specified by
+\\{name\_of\_file}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{name\_of\_file}: \37$\^\\{text\_char}$;\6
+\4\\{name\_length}: \37$0\to\\{file\_name\_size}$;\6
+\C{this many characters are actually   relevant in \\{name\_of\_file} (the rest
+are blank)}\par
+\fi
+
+\M27. All of the file opening functions are defined in C.
+
+\fi
+
+\M28. Kanji code handling.
+
+\fi
+
+\M29. And all the file closing routines as well.
+
+\fi
+
+\M30. Binary input and output are done with \PASCAL's ordinary \\{get} and %
+\\{put}
+procedures, so we don't have to make any other special arrangements for
+binary~I/O. Text output is also easy to do with standard \PASCAL\ routines.
+The treatment of text input is more difficult, however, because
+of the necessary translation to \\{ASCII\_code} values.
+\TeX's conventions should be efficient, and they should
+blend nicely with the user's operating environment.
+
+\fi
+
+\M31. Input from text files is read one line at a time, using a routine called
+\\{input\_ln}. This function is defined in terms of global variables called
+\\{buffer}, \\{first}, and \\{last} that will be described in detail later; for
+now, it suffices for us to know that \\{buffer} is an array of \\{ASCII\_code}
+values, and that \\{first} and \\{last} are indices into this array
+representing the beginning and ending of a line of text.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{buffer}: \37$\^\\{ASCII\_code}$;\C{lines of characters being read}\6
+\4\\{first}: \37$0\to\\{buf\_size}$;\C{the first unused position in \\{buffer}}%
+\6
+\4\\{last}: \37$0\to\\{buf\_size}$;\C{end of the line just input to \\{buffer}}%
+\6
+\4\\{max\_buf\_stack}: \37$0\to\\{buf\_size}$;\C{largest index used in %
+\\{buffer}}\par
+\fi
+
+\M32. The \\{input\_ln} function brings the next line of input from the
+specified
+file into available positions of the buffer array and returns the value
+\\{true}, unless the file has already been entirely read, in which case it
+returns \\{false} and sets $\\{last}\K\\{first}$.  In general, the \\{ASCII%
+\_code}
+numbers that represent the next line of the file are input into
+$\\{buffer}[\\{first}]$, $\\{buffer}[\\{first}+1]$, \dots, $\\{buffer}[%
+\\{last}-1]$; and the
+global variable \\{last} is set equal to \\{first} plus the length of the
+line. Trailing blanks are removed from the line; thus, either $\\{last}=%
+\\{first}$
+(in which case the line was entirely blank) or $\\{buffer}[\\{last}-1]\I\.{"\
+"}$.
+
+An overflow error is given, however, if the normal actions of \\{input\_ln}
+would make $\\{last}\G\\{buf\_size}$; this is done so that other parts of \TeX\
+can safely look at the contents of $\\{buffer}[\\{last}+1]$ without
+overstepping
+the bounds of the \\{buffer} array. Upon entry to \\{input\_ln}, the condition
+$\\{first}<\\{buf\_size}$ will always hold, so that there is always room for an
+``empty'' line.
+
+The variable \\{max\_buf\_stack}, which is used to keep track of how large
+the \\{buf\_size} parameter must be to accommodate the present job, is
+also kept up to date by \\{input\_ln}.
+
+If the \\{bypass\_eoln} parameter is \\{true}, \\{input\_ln} will do a \\{get}
+before looking at the first character of the line; this skips over
+an \\{eoln} that was in $\|f\^$. The procedure does not do a \\{get} when it
+reaches the end of the line; therefore it can be used to acquire input
+from the user's terminal as well as from ordinary text files.
+
+Standard \PASCAL\ says that a file should have \\{eoln} immediately
+before \\{eof}, but \TeX\ needs only a weaker restriction: If \\{eof}
+occurs in the middle of a line, the system function \\{eoln} should return
+a \\{true} result (even though $\|f\^$ will be undefined).
+
+Since the inner loop of \\{input\_ln} is part of \TeX's ``inner loop''---each
+character of input comes in at this place---it is wise to reduce system
+overhead by making use of special routines that read in an entire array
+of characters at once, if such routines are available. The following
+code uses standard \PASCAL\ to illustrate what needs to be done, but
+finer tuning is often possible at well-developed \PASCAL\ sites.
+
+We define \\{input\_ln} in C, for efficiency. Nevertheless we quote the module
+`Report overflow of the input buffer, and abort' here in order to make
+\.{WEAVE} happy, since part of that module is needed by e-TeX.
+
+\Y\P$\B\X36:Report overflow of the input buffer, and abort\X\T$\par
+\fi
+
+\M33. The user's terminal acts essentially like other files of text, except
+that it is used both for input and for output. When the terminal is
+considered an input file, the file variable is called \\{term\_in}, and when it
+is considered an output file the file variable is \\{term\_out}.
+
+\Y\P\D \37$\\{term\_in}\S\\{stdin}$\C{the terminal as an input file}\par
+\P\D \37$\\{term\_out}\S\\{stdout}$\C{the terminal as an output file}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\&{init} \37\\{ini\_version}: \37\\{boolean};\C{are we \.{INITEX}?}\6
+\4\\{dump\_option}: \37\\{boolean};\C{was the dump name option used?}\6
+\4\\{dump\_line}: \37\\{boolean};\C{was a \.{\%\AM format} line seen?}\6
+\&{tini}\7
+\4\\{bound\_default}: \37\\{integer};\C{temporary for setup}\6
+\4\\{bound\_name}: \37\\{const\_cstring};\C{temporary for setup}\7
+\4\\{mem\_bot}: \37\\{integer};\C{smallest index in the \\{mem} array dumped by
+\.{INITEX};   must not be less than \\{mem\_min}}\6
+\4\\{main\_memory}: \37\\{integer};\C{total memory words allocated in initex}\6
+\4\\{extra\_mem\_bot}: \37\\{integer};\C{$\\{mem\_min}\K\\{mem\_bot}-\\{extra%
+\_mem\_bot}$ except in \.{INITEX}}\6
+\4\\{mem\_min}: \37\\{integer};\C{smallest index in \TeX's internal \\{mem}
+array;   must be \\{min\_halfword} or more;   must be equal to \\{mem\_bot} in %
+\.{INITEX}, otherwise $\L\\{mem\_bot}$}\6
+\4\\{mem\_top}: \37\\{integer};\C{largest index in the \\{mem} array dumped by %
+\.{INITEX};   must be substantially larger than \\{mem\_bot},   equal to \\{mem%
+\_max} in \.{INITEX}, else not greater than \\{mem\_max}}\6
+\4\\{extra\_mem\_top}: \37\\{integer};\C{$\\{mem\_max}\K\\{mem\_top}+\\{extra%
+\_mem\_top}$ except in \.{INITEX}}\6
+\4\\{mem\_max}: \37\\{integer};\C{greatest index in \TeX's internal \\{mem}
+array;   must be strictly less than \\{max\_halfword};   must be equal to %
+\\{mem\_top} in \.{INITEX}, otherwise $\G\\{mem\_top}$}\6
+\4\\{error\_line}: \37\\{integer};\C{width of context lines on terminal error
+messages}\6
+\4\\{half\_error\_line}: \37\\{integer};\C{width of first lines of contexts in
+terminal   error messages; should be between 30 and $\\{error\_line}-15$}\6
+\4\\{max\_print\_line}: \37\\{integer};\C{width of longest text lines output;
+should be at least 60}\6
+\4\\{max\_strings}: \37\\{integer};\C{maximum number of strings; must not
+exceed \\{max\_halfword}}\6
+\4\\{strings\_free}: \37\\{integer};\C{strings available after format loaded}\6
+\4\\{string\_vacancies}: \37\\{integer};\C{the minimum number of characters
+that should be   available for the user's control sequences and font names,
+after \TeX's own error messages are stored}\6
+\4\\{pool\_size}: \37\\{integer};\C{maximum number of characters in strings,
+including all   error messages and help texts, and the names of all fonts and
+control sequences; must exceed \\{string\_vacancies} by the total   length of %
+\TeX's own strings, which is currently about 23000}\6
+\4\\{pool\_free}: \37\\{integer};\C{pool space free after format loaded}\6
+\4\\{font\_mem\_size}: \37\\{integer};\C{number of words of \\{font\_info} for
+all fonts}\6
+\4\\{font\_max}: \37\\{integer};\C{maximum internal font number; ok to exceed %
+\\{max\_quarterword}   and must be at most \\{font\_base}+\\{max\_font\_max}}\6
+\4\\{font\_k}: \37\\{integer};\C{loop variable for initialization}\6
+\4\\{hyph\_size}: \37\\{integer};\C{maximun number of hyphen exceptions}\6
+\4\\{trie\_size}: \37\\{integer};\C{space for hyphenation patterns; should be
+larger for   \.{INITEX} than it is in production versions of \TeX.  50000 is
+needed for English, German, and Portuguese.}\6
+\4\\{buf\_size}: \37\\{integer};\C{maximum number of characters simultaneously
+present in   current lines of open files and in control sequences between   \.{%
+\\csname} and \.{\\endcsname}; must not exceed \\{max\_halfword}}\6
+\4\\{stack\_size}: \37\\{integer};\C{maximum number of simultaneous input
+sources}\6
+\4\\{max\_in\_open}: \37\\{integer};\C{maximum number of input files and error
+insertions that   can be going on simultaneously}\6
+\4\\{param\_size}: \37\\{integer};\C{maximum number of simultaneous macro
+parameters}\6
+\4\\{nest\_size}: \37\\{integer};\C{maximum number of semantic levels
+simultaneously active}\6
+\4\\{save\_size}: \37\\{integer};\C{space for saving values outside of current
+group; must be   at most \\{max\_halfword}}\6
+\4\\{dvi\_buf\_size}: \37\\{integer};\C{size of the output buffer; must be a
+multiple of 8}\6
+\4\\{expand\_depth}: \37\\{integer};\C{limits recursive calls to the \\{expand}
+procedure}\6
+\4\\{parse\_first\_line\_p}: \37\\{cinttype};\C{parse the first line for
+options}\6
+\4\\{file\_line\_error\_style\_p}: \37\\{cinttype};\C{format messages as
+file:line:error}\6
+\4\\{eight\_bit\_p}: \37\\{cinttype};\C{make all characters printable by
+default}\6
+\4\\{halt\_on\_error\_p}: \37\\{cinttype};\C{stop at first error}\6
+\4\\{quoted\_filename}: \37\\{boolean};\C{current filename is quoted}\6
+\C{Variables for source specials}\6
+\4\\{src\_specials\_p}: \37\\{boolean};\C{Whether \\{src\_specials} are enabled
+at all}\6
+\4\\{insert\_src\_special\_auto}: \37\\{boolean};\6
+\4\\{insert\_src\_special\_every\_par}: \37\\{boolean};\6
+\4\\{insert\_src\_special\_every\_parend}: \37\\{boolean};\6
+\4\\{insert\_src\_special\_every\_cr}: \37\\{boolean};\6
+\4\\{insert\_src\_special\_every\_math}: \37\\{boolean};\6
+\4\\{insert\_src\_special\_every\_hbox}: \37\\{boolean};\6
+\4\\{insert\_src\_special\_every\_vbox}: \37\\{boolean};\6
+\4\\{insert\_src\_special\_every\_display}: \37\\{boolean};\par
+\fi
+
+\M34. Here is how to open the terminal files.  \\{t\_open\_out} does nothing.
+\\{t\_open\_in}, on the other hand, does the work of ``rescanning,'' or getting
+any command line arguments the user has provided.  It's defined in C.
+
+\Y\P\D \37$\\{t\_open\_out}\S$\C{output already open for text output}\par
+\fi
+
+\M35. Sometimes it is necessary to synchronize the input/output mixture that
+happens on the user's terminal, and three system-dependent
+procedures are used for this
+purpose. The first of these, \\{update\_terminal}, is called when we want
+to make sure that everything we have output to the terminal so far has
+actually left the computer's internal buffers and been sent.
+The second, \\{clear\_terminal}, is called when we wish to cancel any
+input that the user may have typed ahead (since we are about to
+issue an unexpected error message). The third, \\{wake\_up\_terminal},
+is supposed to revive the terminal if the user has disabled it by
+some instruction to the operating system.  The following macros show how
+these operations can be specified with {\mc UNIX}.  \\{update\_terminal}
+does an \\{fflush}. \\{clear\_terminal} is redefined
+to do nothing, since the user should control the terminal.
+
+\Y\P\D \37$\\{update\_terminal}\S\\{fflush}(\\{term\_out})$\par
+\P\D \37$\\{clear\_terminal}\S\\{do\_nothing}$\par
+\P\D \37$\\{wake\_up\_terminal}\S\\{do\_nothing}$\C{cancel the user's
+cancellation of output}\par
+\fi
+
+\M36. We need a special routine to read the first line of \TeX\ input from
+the user's terminal. This line is different because it is read before we
+have opened the transcript file; there is sort of a ``chicken and
+egg'' problem here. If the user types `\.{\\input paper}' on the first
+line, or if some macro invoked by that line does such an \.{\\input},
+the transcript file will be named `\.{paper.log}'; but if no \.{\\input}
+commands are performed during the first line of terminal input, the transcript
+file will acquire its default name `\.{texput.log}'. (The transcript file
+will not contain error messages generated by the first line before the
+first \.{\\input} command.)
+
+The first line is even more special if we are lucky enough to have an operating
+system that treats \TeX\ differently from a run-of-the-mill \PASCAL\ object
+program. It's nice to let the user start running a \TeX\ job by typing
+a command line like `\.{tex paper}'; in such a case, \TeX\ will operate
+as if the first line of input were `\.{paper}', i.e., the first line will
+consist of the remainder of the command line, after the part that invoked
+\TeX.
+
+The first line is special also because it may be read before \TeX\ has
+input a format file. In such cases, normal error messages cannot yet
+be given. The following code uses concepts that will be explained later.
+(If the \PASCAL\ compiler does not support non-local \&{goto} \unskip, the
+statement `\&{goto} \\{final\_end}' should be replaced by something that
+quietly terminates the program.)
+
+Routine is implemented in C; part of module is, however, needed for e-TeX.
+
+\Y\P$\4\X36:Report overflow of the input buffer, and abort\X\S$\6
+\&{begin} \37$\\{cur\_input}.\\{loc\_field}\K\\{first}$;\5
+$\\{cur\_input}.\\{limit\_field}\K\\{last}-1$;\5
+$\\{overflow}(\.{"buffer\ size"},\39\\{buf\_size})$;\6
+\&{end}\par
+\U32.\fi
+
+\M37. Different systems have different ways to get started. But regardless of
+what conventions are adopted, the routine that initializes the terminal
+should satisfy the following specifications:
+
+\yskip\textindent{1)}It should open file \\{term\_in} for input from the
+terminal. (The file \\{term\_out} will already be open for output to the
+terminal.)
+
+\textindent{2)}If the user has given a command line, this line should be
+considered the first line of terminal input. Otherwise the
+user should be prompted with `\.{**}', and the first line of input
+should be whatever is typed in response.
+
+\textindent{3)}The first line of input, which might or might not be a
+command line, should appear in locations \\{first} to $\\{last}-1$ of the
+\\{buffer} array.
+
+\textindent{4)}The global variable \\{loc} should be set so that the
+character to be read next by \TeX\ is in $\\{buffer}[\\{loc}]$. This
+character should not be blank, and we should have $\\{loc}<\\{last}$.
+
+\yskip\noindent(It may be necessary to prompt the user several times
+before a non-blank line comes in. The prompt is `\.{**}' instead of the
+later `\.*' because the meaning is slightly different: `\.{\\input}' need
+not be typed immediately after~`\.{**}'.)
+
+\Y\P\D \37$\\{loc}\S\\{cur\_input}.\\{loc\_field}$\C{location of first unread
+character in \\{buffer}}\par
+\fi
+
+\M38. The following program does the required initialization.
+Iff anything has been specified on the command line, then \\{t\_open\_in}
+will return with $\\{last}>\\{first}$.
+
+\Y\P\4\&{function}\1\  \37\\{init\_terminal}: \37\\{boolean};\C{gets the
+terminal input started}\6
+\4\&{label} \37\\{exit};\2\6
+\&{begin} \37\\{t\_open\_in};\6
+\&{if} $\\{last}>\\{first}$ \1\&{then}\6
+\&{begin} \37$\\{loc}\K\\{first}$;\6
+\&{while} $(\\{loc}<\\{last})\W(\\{buffer}[\\{loc}]=\.{\'\ \'})$ \1\&{do}\5
+$\\{incr}(\\{loc})$;\2\6
+\&{if} $\\{loc}<\\{last}$ \1\&{then}\6
+\&{begin} \37$\\{init\_terminal}\K\\{true}$;\5
+\&{goto} \37\\{exit};\6
+\&{end};\2\6
+\&{end};\2\6
+\~ \1\&{loop}\ \&{begin} \37\\{wake\_up\_terminal};\5
+$\\{write}(\\{term\_out},\39\.{\'**\'})$;\5
+\\{update\_terminal};\6
+\&{if} $\R\\{input\_ln}(\\{term\_in},\39\\{true})$ \1\&{then}\C{this shouldn't
+happen}\6
+\&{begin} \37$\\{write\_ln}(\\{term\_out})$;\5
+$\\{write\_ln}(\\{term\_out},\39\.{\'!\ End\ of\ file\ on\ the\ terminal...\
+why?\'})$;\5
+$\\{init\_terminal}\K\\{false}$;\5
+\&{return};\6
+\&{end};\2\6
+$\\{loc}\K\\{first}$;\6
+\&{while} $(\\{loc}<\\{last})\W(\\{buffer}[\\{loc}]=\.{"\ "})$ \1\&{do}\5
+$\\{incr}(\\{loc})$;\2\6
+\&{if} $\\{loc}<\\{last}$ \1\&{then}\6
+\&{begin} \37$\\{init\_terminal}\K\\{true}$;\5
+\&{return};\C{return unless the line was all blank}\6
+\&{end};\2\6
+$\\{write\_ln}(\\{term\_out},\39\.{\'Please\ type\ the\ name\ of\ your\ input\
+file.\'})$;\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\N39.  \[4] String handling.
+Control sequence names and diagnostic messages are variable-length strings
+of eight-bit characters. Since \PASCAL\ does not have a well-developed string
+mechanism, \TeX\ does all of its string processing by homegrown methods.
+
+Elaborate facilities for dynamic strings are not needed, so all of the
+necessary operations can be handled with a simple data structure.
+The array \\{str\_pool} contains all of the (eight-bit) ASCII codes in all
+of the strings, and the array \\{str\_start} contains indices of the starting
+points of each string. Strings are referred to by integer numbers, so that
+string number \|s comprises the characters $\\{str\_pool}[\|j]$ for
+$\\{str\_start}[\|s]\L\|j<\\{str\_start}[\|s+1]$. Additional integer variables
+\\{pool\_ptr} and \\{str\_ptr} indicate the number of entries used so far
+in \\{str\_pool} and \\{str\_start}, respectively; locations
+$\\{str\_pool}[\\{pool\_ptr}]$ and $\\{str\_start}[\\{str\_ptr}]$ are
+ready for the next string to be allocated.
+
+String numbers 0 to 255 are reserved for strings that correspond to single
+ASCII characters. This is in accordance with the conventions of \.{WEB},
+which converts single-character strings into the ASCII code number of the
+single character involved, while it converts other strings into integers
+and builds a string pool file. Thus, when the string constant \.{"."} appears
+in the program below, \.{WEB} converts it into the integer 46, which is the
+ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"}
+into some integer greater than~255. String number 46 will presumably be the
+single character `\..'; but some ASCII codes have no standard visible
+representation, and \TeX\ sometimes needs to be able to print an arbitrary
+ASCII character, so the first 256 strings are used to specify exactly what
+should be printed for each of the 256 possibilities.
+
+Elements of the \\{str\_pool} array must be ASCII codes that can actually
+be printed; i.e., they must have an \\{xchr} equivalent in the local
+character set. (This restriction applies only to preloaded strings,
+not to those generated dynamically by the user.)
+
+Some \PASCAL\ compilers won't pack integers into a single byte unless the
+integers lie in the range $-128\to127$. To accommodate such systems
+we access the string pool only via macros that can easily be redefined.
+
+\Y\P\D \37$\\{si}(\#)\S\#$\C{convert from \\{ASCII\_code} to \\{packed\_ASCII%
+\_code}}\par
+\P\D \37$\\{so}(\#)\S\#$\C{convert from \\{packed\_ASCII\_code} to \\{ASCII%
+\_code}}\par
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{pool\_pointer}=\\{integer}$;\C{for variables that point into \\{str\_pool}}%
+\6
+$\\{str\_number}=0\to\\{ssup\_max\_strings}$;\C{for variables that point into %
+\\{str\_start}}\6
+$\\{packed\_ASCII\_code}=0\to255$;\C{elements of \\{str\_pool} array}\par
+\fi
+
+\M40. \P$\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{str\_pool}: \37$\^\\{packed\_ASCII\_code}$;\C{the characters}\6
+\4\\{str\_start}: \37$\^\\{pool\_pointer}$;\C{the starting pointers}\6
+\4\\{pool\_ptr}: \37\\{pool\_pointer};\C{first unused position in \\{str%
+\_pool}}\6
+\4\\{str\_ptr}: \37\\{str\_number};\C{number of the current string being
+created}\6
+\4\\{init\_pool\_ptr}: \37\\{pool\_pointer};\C{the starting value of \\{pool%
+\_ptr}}\6
+\4\\{init\_str\_ptr}: \37\\{str\_number};\C{the starting value of \\{str\_ptr}}%
+\par
+\fi
+
+\M41. Several of the elementary string operations are performed using \.{WEB}
+macros instead of \PASCAL\ procedures, because many of the
+operations are done quite frequently and we want to avoid the
+overhead of procedure calls. For example, here is
+a simple macro that computes the length of a string.
+
+\Y\P\D \37$\\{length}(\#)\S(\\{str\_start}[\#+1]-\\{str\_start}[\#])$\C{the
+number of characters   in string number \#}\par
+\fi
+
+\M42. The length of the current string is called \\{cur\_length}:
+
+\Y\P\D \37$\\{cur\_length}\S(\\{pool\_ptr}-\\{str\_start}[\\{str\_ptr}])$\par
+\fi
+
+\M43. Strings are created by appending character codes to \\{str\_pool}.
+The \\{append\_char} macro, defined here, does not check to see if the
+value of \\{pool\_ptr} has gotten too high; this test is supposed to be
+made before \\{append\_char} is used. There is also a \\{flush\_char}
+macro, which erases the last character appended.
+
+To test if there is room to append \|l more characters to \\{str\_pool},
+we shall write $\\{str\_room}(\|l)$, which aborts \TeX\ and gives an
+apologetic error message if there isn't enough room.
+
+\Y\P\D \37$\\{append\_char}(\#)\S$\C{put \\{ASCII\_code} \# at the end of %
+\\{str\_pool}}\6
+\&{begin} \37$\\{str\_pool}[\\{pool\_ptr}]\K\\{si}(\#)$;\5
+$\\{incr}(\\{pool\_ptr})$;\6
+\&{end}\par
+\P\D \37$\\{flush\_char}\S\\{decr}(\\{pool\_ptr})$\C{forget the last character
+in the pool}\par
+\P\D \37$\\{str\_room}(\#)\S$\C{make sure that the pool hasn't overflowed}\6
+\&{begin} \37\&{if} $\\{pool\_ptr}+\#>\\{pool\_size}$ \1\&{then}\5
+$\\{overflow}(\.{"pool\ size"},\39\\{pool\_size}-\\{init\_pool\_ptr})$;\2\6
+\&{end}\par
+\fi
+
+\M44. Once a sequence of characters has been appended to \\{str\_pool}, it
+officially becomes a string when the function \\{make\_string} is called.
+This function returns the identification number of the new string as its
+value.
+
+\Y\P\4\&{function}\1\  \37\\{make\_string}: \37\\{str\_number};\C{current
+string enters the pool}\2\6
+\&{begin} \37\&{if} $\\{str\_ptr}=\\{max\_strings}$ \1\&{then}\5
+$\\{overflow}(\.{"number\ of\ strings"},\39\\{max\_strings}-\\{init\_str%
+\_ptr})$;\2\6
+$\\{incr}(\\{str\_ptr})$;\5
+$\\{str\_start}[\\{str\_ptr}]\K\\{pool\_ptr}$;\5
+$\\{make\_string}\K\\{str\_ptr}-1$;\6
+\&{end};\par
+\fi
+
+\M45. To destroy the most recently made string, we say \\{flush\_string}.
+
+\Y\P\D \37$\\{flush\_string}\S$\1\6
+\&{begin} \37$\\{decr}(\\{str\_ptr})$;\5
+$\\{pool\_ptr}\K\\{str\_start}[\\{str\_ptr}]$;\6
+\&{end}\2\par
+\fi
+
+\M46. The following subroutine compares string \|s with another string of the
+same length that appears in \\{buffer} starting at position \|k;
+the result is \\{true} if and only if the strings are equal.
+Empirical tests indicate that \\{str\_eq\_buf} is used in such a way that
+it tends to return \\{true} about 80 percent of the time.
+
+\Y\P\4\&{function}\1\  \37$\\{str\_eq\_buf}(\|s:\\{str\_number};\,\35\|k:%
+\\{integer})$: \37\\{boolean};\C{test equality of strings}\6
+\4\&{label} \37\\{not\_found};\C{loop exit}\6
+\4\&{var} \37\|j: \37\\{pool\_pointer};\C{running index}\6
+\\{result}: \37\\{boolean};\C{result of comparison}\2\6
+\&{begin} \37$\|j\K\\{str\_start}[\|s]$;\6
+\&{while} $\|j<\\{str\_start}[\|s+1]$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{so}(\\{str\_pool}[\|j])\I\\{buffer}[\|k]$ \1\&{then}\6
+\&{begin} \37$\\{result}\K\\{false}$;\5
+\&{goto} \37\\{not\_found};\6
+\&{end};\2\6
+$\\{incr}(\|j)$;\5
+$\\{incr}(\|k)$;\6
+\&{end};\2\6
+$\\{result}\K\\{true}$;\6
+\4\\{not\_found}: \37$\\{str\_eq\_buf}\K\\{result}$;\6
+\&{end};\par
+\fi
+
+\M47. Here is a similar routine, but it compares two strings in the string
+pool,
+and it does not assume that they have the same length.
+
+\Y\P\4\&{function}\1\  \37$\\{str\_eq\_str}(\|s,\39\|t:\\{str\_number})$: \37%
+\\{boolean};\C{test equality of strings}\6
+\4\&{label} \37\\{not\_found};\C{loop exit}\6
+\4\&{var} \37$\|j,\39\|k$: \37\\{pool\_pointer};\C{running indices}\6
+\\{result}: \37\\{boolean};\C{result of comparison}\2\6
+\&{begin} \37$\\{result}\K\\{false}$;\6
+\&{if} $\\{length}(\|s)\I\\{length}(\|t)$ \1\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+$\|j\K\\{str\_start}[\|s]$;\5
+$\|k\K\\{str\_start}[\|t]$;\6
+\&{while} $\|j<\\{str\_start}[\|s+1]$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{str\_pool}[\|j]\I\\{str\_pool}[\|k]$ \1\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+$\\{incr}(\|j)$;\5
+$\\{incr}(\|k)$;\6
+\&{end};\2\6
+$\\{result}\K\\{true}$;\6
+\4\\{not\_found}: \37$\\{str\_eq\_str}\K\\{result}$;\6
+\&{end};\par
+\fi
+
+\M48. The initial values of \\{str\_pool}, \\{str\_start}, \\{pool\_ptr},
+and \\{str\_ptr} are computed by the \.{INITEX} program, based in part
+on the information that \.{WEB} has output while processing \TeX.
+
+\Y\P\hbox{\4}\X1402:Declare additional routines for string recycling\X\6
+\&{init} \37\&{function}\1\  \37\\{get\_strings\_started}: \37\\{boolean};%
+\C{initializes the string pool,   but returns \\{false} if something goes
+wrong}\6
+\4\&{label} \37$\\{done},\39\\{exit}$;\6
+\4\&{var} \37$\|k,\39\|l$: \37\\{KANJI\_code};\C{small indices or counters}\6
+$\|m,\39\|n$: \37\\{text\_char};\C{characters input from \\{pool\_file}}\6
+\|g: \37\\{str\_number};\C{garbage}\6
+\|a: \37\\{integer};\C{accumulator for check sum}\6
+\|c: \37\\{boolean};\C{check sum has been checked}\2\6
+\&{begin} \37$\\{pool\_ptr}\K0$;\5
+$\\{str\_ptr}\K0$;\5
+$\\{str\_start}[0]\K0$;\5
+\X49:Make the first 256 strings\X;\6
+\X52:Read the other strings from the \.{TEX.POOL} file and return \\{true}, or
+give an error message and return \\{false}\X;\6
+\4\\{exit}: \37\&{end};\6
+\&{tini}\par
+\fi
+
+\M49. \P\D \37$\\{app\_lc\_hex}(\#)\S\|l\K\#$;\6
+\&{if} $\|l<10$ \1\&{then}\5
+$\\{append\_char}(\|l+\.{"0"})$\ \&{else} $\\{append\_char}(\|l-10+\.{"a"})$\2%
+\par
+\Y\P$\4\X49:Make the first 256 strings\X\S$\6
+\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\6
+\&{begin} \37\&{if} $(\X50:Character \|k cannot be printed\X)$ \1\&{then}\6
+\&{begin} \37$\\{append\_char}(\.{"\^"})$;\5
+$\\{append\_char}(\.{"\^"})$;\6
+\&{if} $\|k<\O{100}$ \1\&{then}\5
+$\\{append\_char}(\|k+\O{100})$\6
+\4\&{else} \&{if} $\|k<\O{200}$ \1\&{then}\5
+$\\{append\_char}(\|k-\O{100})$\6
+\4\&{else} \&{begin} \37$\\{app\_lc\_hex}(\|k\mathbin{\&{div}}16)$;\5
+$\\{app\_lc\_hex}(\|k\mathbin{\&{mod}}16)$;\6
+\&{end};\2\2\6
+\&{end}\6
+\4\&{else} $\\{append\_char}(\|k)$;\2\6
+$\|g\K\\{make\_string}$;\6
+\&{end}\2\par
+\U48.\fi
+
+\M50. The first 128 strings will contain 95 standard ASCII characters, and the
+other 33 characters will be printed in three-symbol form like `\.{\^\^A}'
+unless a system-dependent change is made here. Installations that have
+an extended character set, where for example $\\{xchr}[\O{32}]=\hbox{\.{\'^^Z%
+\'}}$,
+would like string \O{32} to be printed as the single character \O{32}
+instead of the
+three characters \O{136}, \O{136}, \O{132} (\.{\^\^Z}). On the other hand,
+even people with an extended character set will want to represent string
+\O{15} by \.{\^\^M}, since \O{15} is \\{carriage\_return}; the idea is to
+produce visible strings instead of tabs or line-feeds or carriage-returns
+or bell-rings or characters that are treated anomalously in text files.
+
+Unprintable characters of codes 128--255 are, similarly, rendered
+\.{\^\^80}--\.{\^\^ff}.
+
+The boolean expression defined here should be \\{true} unless \TeX\
+internal code number~\|k corresponds to a non-troublesome visible
+symbol in the local character set.  An appropriate formula for the
+extended character set recommended in {\sl The \TeX book\/} would, for
+example, be `$\|k\in[0,\O{10}\to\O{12},\O{14},\O{15},\O{33},\O{177}\to%
+\O{377}]$'.
+If character \|k cannot be printed, and $\|k<\O{200}$, then character $\|k+%
+\O{100}$ or
+$\|k-\O{100}$ must be printable; moreover, ASCII codes $[\O{41}\to\O{46},\O{60}%
+\to\O{71},\O{136},\O{141}\to\O{146},\O{160}\to\O{171}]$ must be printable.
+Thus, at least 81 printable characters are needed.
+
+\Y\P$\4\X50:Character \|k cannot be printed\X\S$\6
+$\R(\\{ismultiprn}(\|k)\V\\{xprn}[\|k])$\par
+\U49.\fi
+
+\M51. When the \.{WEB} system program called \.{TANGLE} processes the %
+\.{TEX.WEB}
+description that you are now reading, it outputs the \PASCAL\ program
+\.{TEX.PAS} and also a string pool file called \.{TEX.POOL}. The \.{INITEX}
+program reads the latter file, where each string appears as a two-digit decimal
+length followed by the string itself, and the information is recorded in
+\TeX's string memory.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\&{init} \37\\{pool\_file}: \37\\{alpha\_file};\C{the string-pool file output
+by \.{TANGLE}}\6
+\&{tini}\par
+\fi
+
+\M52. \P\D \37$\\{bad\_pool}(\#)\S$\1\6
+\&{begin} \37\\{wake\_up\_terminal};\5
+$\\{write\_ln}(\\{term\_out},\39\#)$;\5
+$\\{a\_close}(\\{pool\_file})$;\5
+$\\{get\_strings\_started}\K\\{false}$;\5
+\&{return};\6
+\&{end}\2\par
+\Y\P$\4\X52:Read the other strings from the \.{TEX.POOL} file and return %
+\\{true}, or give an error message and return \\{false}\X\S$\6
+$\\{name\_length}\K\\{strlen}(\\{pool\_name})$;\5
+$\\{name\_of\_file}\K\\{xmalloc\_array}(\\{ASCII\_code},\39\\{name%
+\_length}+1)$;\5
+$\\{strcpy}(\\{stringcast}(\\{name\_of\_file}+1),\39\\{pool\_name})$;\C{copy
+the string}\6
+\&{if} $\\{a\_open\_in}(\\{pool\_file},\39\\{kpse\_texpool\_format})$ \1%
+\&{then}\6
+\&{begin} \37$\|c\K\\{false}$;\6
+\1\&{repeat} \37\X53:Read one string, but return \\{false} if the string memory
+space is getting too tight for comfort\X;\6
+\4\&{until}\5
+\|c;\2\6
+$\\{a\_close}(\\{pool\_file})$;\5
+$\\{get\_strings\_started}\K\\{true}$;\6
+\&{end}\6
+\4\&{else} $\\{bad\_pool}(\.{\'!\ I\ can\'}\.{\'t\ read\ \'},\39\\{pool\_name},%
+\39\.{\';\ bad\ path?\'})$\2\par
+\U48.\fi
+
+\M53. \P$\X53:Read one string, but return \\{false} if the string memory space
+is getting too tight for comfort\X\S$\6
+\&{begin} \37\&{if} $\\{eof}(\\{pool\_file})$ \1\&{then}\5
+$\\{bad\_pool}(\.{\'!\ \'},\39\\{pool\_name},\39\.{\'\ has\ no\ check\ sum.%
+\'})$;\2\6
+$\\{read}(\\{pool\_file},\39\|m)$;\5
+$\\{read}(\\{pool\_file},\39\|n)$;\C{read two digits of string length}\6
+\&{if} $\|m=\.{\'*\'}$ \1\&{then}\5
+\X54:Check the pool check sum\X\6
+\4\&{else} \&{begin} \37\&{if} $(\\{xord}[\|m]<\.{"0"})\V(\\{xord}[\|m]>%
+\.{"9"})\V\30(\\{xord}[\|n]<\.{"0"})\V(\\{xord}[\|n]>\.{"9"})$ \1\&{then}\5
+$\\{bad\_pool}(\.{\'!\ \'},\39\\{pool\_name},\39\.{\'\ line\ doesn\'}\.{\'t\
+begin\ with\ two\ digits.\'})$;\2\6
+$\|l\K\\{xord}[\|m]\ast10+\\{xord}[\|n]-\.{"0"}\ast11$;\C{compute the length}\6
+\&{if} $\\{pool\_ptr}+\|l+\\{string\_vacancies}>\\{pool\_size}$ \1\&{then}\5
+$\\{bad\_pool}(\.{\'!\ You\ have\ to\ increase\ POOLSIZE.\'})$;\2\6
+\&{for} $\|k\K1\mathrel{\&{to}}\|l$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{eoln}(\\{pool\_file})$ \1\&{then}\5
+$\|m\K\.{\'\ \'}$\ \&{else} $\\{read}(\\{pool\_file},\39\|m)$;\2\6
+$\\{append\_char}(\\{xord}[\|m])$;\6
+\&{end};\2\6
+$\\{read\_ln}(\\{pool\_file})$;\5
+$\|g\K\\{make\_string}$;\6
+\&{end};\2\6
+\&{end}\par
+\U52.\fi
+
+\M54. The \.{WEB} operation \.{@\$} denotes the value that should be at the
+end of this \.{TEX.POOL} file; any other value means that the wrong pool
+file has been loaded.
+
+\Y\P$\4\X54:Check the pool check sum\X\S$\6
+\&{begin} \37$\|a\K0$;\5
+$\|k\K1$;\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $(\\{xord}[\|n]<\.{"0"})\V(\\{xord}[\|n]>%
+\.{"9"})$ \1\&{then}\5
+$\\{bad\_pool}(\.{\'!\ \'},\39\\{pool\_name},\39\.{\'\ check\ sum\ doesn\'}\.{%
+\'t\ have\ nine\ digits.\'})$;\2\6
+$\|a\K10\ast\|a+\\{xord}[\|n]-\.{"0"}$;\6
+\&{if} $\|k=9$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\\{incr}(\|k)$;\5
+$\\{read}(\\{pool\_file},\39\|n)$;\6
+\&{end};\2\6
+\4\\{done}: \37\&{if} $\|a\I\)$ \1\&{then}\5
+$\\{bad\_pool}(\.{\'!\ \'},\39\\{pool\_name},\39\.{\'\ doesn\'}\.{\'t\ match;\
+tangle\ me\ again\ (or\ fix\ the\ path).\'})$;\2\6
+$\|c\K\\{true}$;\6
+\&{end}\par
+\U53.\fi
+
+\N55.  \[5] On-line and off-line printing.
+Messages that are sent to a user's terminal and to the transcript-log file
+are produced by several `\\{print}' procedures. These procedures will
+direct their output to a variety of places, based on the setting of
+the global variable \\{selector}, which has the following possible
+values:
+
+\yskip
+\hang \\{term\_and\_log}, the normal setting, prints on the terminal and on the
+transcript file.
+
+\hang \\{log\_only}, prints only on the transcript file.
+
+\hang \\{term\_only}, prints only on the terminal.
+
+\hang \\{no\_print}, doesn't print at all. This is used only in rare cases
+before the transcript file is open.
+
+\hang \\{pseudo}, puts output into a cyclic buffer that is used
+by the \\{show\_context} routine; when we get to that routine we shall discuss
+the reasoning behind this curious mode.
+
+\hang \\{new\_string}, appends the output to the current string in the
+string pool.
+
+\hang 0 to 15, prints on one of the sixteen files for \.{\\write} output.
+
+\yskip
+\noindent The symbolic names `\\{term\_and\_log}', etc., have been assigned
+numeric codes that satisfy the convenient relations $\\{no\_print}+1=\\{term%
+\_only}$,
+$\\{no\_print}+2=\\{log\_only}$, $\\{term\_only}+2=\\{log\_only}+1=\\{term\_and%
+\_log}$.
+
+Three additional global variables, \\{tally} and \\{term\_offset} and
+\\{file\_offset}, record the number of characters that have been printed
+since they were most recently cleared to zero. We use \\{tally} to record
+the length of (possibly very long) stretches of printing; \\{term\_offset}
+and \\{file\_offset}, on the other hand, keep track of how many characters
+have appeared so far on the current line that has been output to the
+terminal or to the transcript file, respectively.
+
+\Y\P\D \37$\\{no\_print}=16$\C{\\{selector} setting that makes data disappear}%
+\par
+\P\D \37$\\{term\_only}=17$\C{printing is destined for the terminal only}\par
+\P\D \37$\\{log\_only}=18$\C{printing is destined for the transcript file only}%
+\par
+\P\D \37$\\{term\_and\_log}=19$\C{normal \\{selector} setting}\par
+\P\D \37$\\{pseudo}=20$\C{special \\{selector} setting for \\{show\_context}}%
+\par
+\P\D \37$\\{new\_string}=21$\C{printing is deflected to the string pool}\par
+\P\D \37$\\{max\_selector}=21$\C{highest selector setting}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{log\_file}: \37\\{alpha\_file};\C{transcript of \TeX\ session}\6
+\4\\{selector}: \37$0\to\\{max\_selector}$;\C{where to print a message}\6
+\4\\{dig}: \37\&{array} $[0\to22]$ \1\&{of}\5
+$0\to15$;\C{digits in a number being output}\2\6
+\4\\{tally}: \37\\{integer};\C{the number of characters recently printed}\6
+\4\\{term\_offset}: \37$0\to\\{max\_print\_line}$;\C{the number of characters
+on the current terminal line}\6
+\4\\{file\_offset}: \37$0\to\\{max\_print\_line}$;\C{the number of characters
+on the current file line}\6
+\4\\{trick\_buf}: \37\&{array} $[0\to\\{ssup\_error\_line}]$ \1\&{of}\5
+\\{ASCII\_code};\C{circular buffer for   pseudoprinting}\2\6
+\4\\{trick\_buf2}: \37\&{array} $[0\to\\{ssup\_error\_line}]$ \1\&{of}\5
+$0\to2$;\C{pTeX: buffer for KANJI}\2\6
+\4\\{kcode\_pos}: \37$0\to2$;\C{pTeX: denotes whether first byte or second byte
+of KANJI}\6
+\4\\{prev\_char}: \37\\{ASCII\_code};\6
+\4\\{trick\_count}: \37\\{integer};\C{threshold for pseudoprinting, explained
+later}\6
+\4\\{first\_count}: \37\\{integer};\C{another variable for pseudoprinting}\par
+\fi
+
+\M56. \P$\X56:Initialize the output routines\X\S$\6
+$\\{selector}\K\\{term\_only}$;\5
+$\\{tally}\K0$;\5
+$\\{term\_offset}\K0$;\5
+$\\{file\_offset}\K0$;\5
+$\\{kcode\_pos}\K0$;\par
+\As62, 539\ETs544.
+\U1345.\fi
+
+\M57. Macro abbreviations for output to the terminal and to the log file are
+defined here for convenience. Some systems need special conventions
+for terminal output, and it is possible to adhere to those conventions
+by changing \\{wterm}, \\{wterm\_ln}, and \\{wterm\_cr} in this section.
+
+\Y\P\D \37$\\{wterm}(\#)\S\\{write}(\\{term\_out},\39\#)$\par
+\P\D \37$\\{wterm\_ln}(\#)\S\\{write\_ln}(\\{term\_out},\39\#)$\par
+\P\D \37$\\{wterm\_cr}\S\\{write\_ln}(\\{term\_out})$\par
+\P\D \37$\\{wlog}(\#)\S\\{write}(\\{log\_file},\39\#)$\par
+\P\D \37$\\{wlog\_ln}(\#)\S\\{write\_ln}(\\{log\_file},\39\#)$\par
+\P\D \37$\\{wlog\_cr}\S\\{write\_ln}(\\{log\_file})$\par
+\fi
+
+\M58. To end a line of text output, we call \\{print\_ln}.
+
+\Y\P$\4\X58:Basic printing procedures\X\S$\6
+\4\&{procedure}\1\  \37\\{print\_ln};\C{prints an end-of-line}\2\6
+\&{begin} \37\&{case} $\\{selector}$ \1\&{of}\6
+\4\\{term\_and\_log}: \37\&{begin} \37\&{if} $\\{kcode\_pos}=1$ \1\&{then}\6
+\&{begin} \37$\\{wterm}(\.{\'\ \'})$;\5
+$\\{wlog}(\.{\'\ \'})$;\6
+\&{end};\2\6
+\\{wterm\_cr};\5
+\\{wlog\_cr};\5
+$\\{term\_offset}\K0$;\5
+$\\{file\_offset}\K0$;\6
+\&{end};\6
+\4\\{log\_only}: \37\&{begin} \37\&{if} $\\{kcode\_pos}=1$ \1\&{then}\5
+$\\{wlog}(\.{\'\ \'})$;\2\6
+\\{wlog\_cr};\5
+$\\{file\_offset}\K0$;\6
+\&{end};\6
+\4\\{term\_only}: \37\&{begin} \37\&{if} $\\{kcode\_pos}=1$ \1\&{then}\5
+$\\{wterm}(\.{\'\ \'})$;\2\6
+\\{wterm\_cr};\5
+$\\{term\_offset}\K0$;\6
+\&{end};\6
+\4$\\{no\_print},\39\\{pseudo},\39\\{new\_string}$: \37\\{do\_nothing};\6
+\4\&{othercases} \37$\\{write\_ln}(\\{write\_file}[\\{selector}])$\2\6
+\&{endcases};\6
+$\\{kcode\_pos}\K0$;\6
+\&{end};\C{\\{tally} is not affected}\par
+\As59, 60, 61, 63, 64, 65, 66, 268, 269, 529, 710, 1368, 1395, 1398, 1467%
+\ETs1473.
+\U4.\fi
+
+\M59. The \\{print\_char} procedure sends one character to the desired
+destination,
+using the \\{xchr} array to map it into an external character compatible with
+\\{input\_ln}. All printing comes through \\{print\_ln} or \\{print\_char}.
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_char}(\|s:\\{ASCII\_code})$;\C{prints a
+single character}\6
+\4\&{label} \37\\{exit};\C{label is not used but nonetheless kept (for other
+changes?)}\2\6
+\&{begin} \37\&{if} $\X250:Character \|s is the current new-line character\X$ %
+\1\&{then}\6
+\&{if} $\\{selector}<\\{pseudo}$ \1\&{then}\6
+\&{begin} \37\\{print\_ln};\5
+\&{return};\6
+\&{end};\2\2\6
+\&{if} $\\{kcode\_pos}=1$ \1\&{then}\5
+$\\{kcode\_pos}\K2$\6
+\4\&{else} \&{if} $\\{iskanji1}(\\{xchr}[\|s])$ \1\&{then}\6
+\&{begin} \37$\\{kcode\_pos}\K1$;\6
+\&{if} $(\\{selector}=\\{term\_and\_log})\V(\\{selector}=\\{log\_only})$ \1%
+\&{then}\6
+\&{if} $\\{file\_offset}\G\\{max\_print\_line}-1$ \1\&{then}\6
+\&{begin} \37\\{wlog\_cr};\5
+$\\{file\_offset}\K0$;\6
+\&{end};\2\2\6
+\&{if} $(\\{selector}=\\{term\_and\_log})\V(\\{selector}=\\{term\_only})$ \1%
+\&{then}\6
+\&{if} $\\{term\_offset}\G\\{max\_print\_line}-1$ \1\&{then}\6
+\&{begin} \37\\{wterm\_cr};\5
+$\\{term\_offset}\K0$;\6
+\&{end};\2\2\6
+\&{end}\6
+\4\&{else} $\\{kcode\_pos}\K0$;\2\2\6
+\&{case} $\\{selector}$ \1\&{of}\6
+\4\\{term\_and\_log}: \37\&{begin} \37$\\{wterm}(\\{xchr}[\|s])$;\5
+$\\{incr}(\\{term\_offset})$;\6
+\&{if} $\\{term\_offset}=\\{max\_print\_line}$ \1\&{then}\6
+\&{begin} \37\\{wterm\_cr};\5
+$\\{term\_offset}\K0$;\6
+\&{end};\2\6
+$\\{wlog}(\\{xchr}[\|s])$;\5
+$\\{incr}(\\{file\_offset})$;\6
+\&{if} $\\{file\_offset}=\\{max\_print\_line}$ \1\&{then}\6
+\&{begin} \37\\{wlog\_cr};\5
+$\\{file\_offset}\K0$;\6
+\&{end};\2\6
+\&{end};\6
+\4\\{log\_only}: \37\&{begin} \37$\\{wlog}(\\{xchr}[\|s])$;\5
+$\\{incr}(\\{file\_offset})$;\6
+\&{if} $\\{file\_offset}=\\{max\_print\_line}$ \1\&{then}\5
+\\{print\_ln};\2\6
+\&{end};\6
+\4\\{term\_only}: \37\&{begin} \37$\\{wterm}(\\{xchr}[\|s])$;\5
+$\\{incr}(\\{term\_offset})$;\6
+\&{if} $\\{term\_offset}=\\{max\_print\_line}$ \1\&{then}\5
+\\{print\_ln};\2\6
+\&{end};\6
+\4\\{no\_print}: \37\\{do\_nothing};\6
+\4\\{pseudo}: \37\&{if} $\\{tally}<\\{trick\_count}$ \1\&{then}\6
+\&{begin} \37$\\{trick\_buf}[\\{tally}\mathbin{\&{mod}}\\{error\_line}]\K\|s$;\5
+$\\{trick\_buf2}[\\{tally}\mathbin{\&{mod}}\\{error\_line}]\K\\{kcode\_pos}$;\6
+\&{end};\2\6
+\4\\{new\_string}: \37\&{begin} \37\&{if} $\\{pool\_ptr}<\\{pool\_size}$ \1%
+\&{then}\5
+$\\{append\_char}(\|s)$;\2\6
+\&{end};\C{we drop characters if the string space is full}\6
+\4\&{othercases} \37$\\{write}(\\{write\_file}[\\{selector}],\39\\{xchr}[\|s])$%
+\2\6
+\&{endcases};\6
+$\\{incr}(\\{tally})$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M60. An entire string is output by calling \\{print}. Note that if we are
+outputting
+the single standard ASCII character \.c, we could call $\\{print}(\.{"c"})$,
+since
+$\.{"c"}=99$ is the number of a single-character string, as explained above.
+But
+$\\{print\_char}(\.{"c"})$ is quicker, so \TeX\ goes directly to the \\{print%
+\_char}
+routine when it knows that this is safe. (The present implementation
+assumes that it is always safe to print a visible ASCII character.)
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print}(\|s:\\{integer})$;\C{prints string \|s}\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|j: \37\\{pool\_pointer};\C{current character code position}\6
+\\{nl}: \37\\{integer};\C{new-line character to restore}\2\6
+\&{begin} \37\&{if} $\|s\G\\{str\_ptr}$ \1\&{then}\5
+$\|s\K\.{"???"}$\C{this can't happen}\6
+\4\&{else} \&{if} $\|s<256$ \1\&{then}\6
+\&{if} $\|s<0$ \1\&{then}\5
+$\|s\K\.{"???"}$\C{can't happen}\6
+\4\&{else} \&{begin} \37\&{if} $\\{selector}>\\{pseudo}$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\|s)$;\5
+\&{return};\C{internal strings are not expanded}\6
+\&{end};\2\6
+\&{if} $(\X250:Character \|s is the current new-line character\X)$ \1\&{then}\6
+\&{if} $\\{selector}<\\{pseudo}$ \1\&{then}\6
+\&{begin} \37\\{print\_ln};\5
+\&{return};\6
+\&{end};\2\2\6
+$\\{nl}\K\\{new\_line\_char}$;\5
+$\\{new\_line\_char}\K-1$;\C{temporarily disable new-line character}\6
+$\|j\K\\{str\_start}[\|s]$;\6
+\&{while} $\|j<\\{str\_start}[\|s+1]$ \1\&{do}\6
+\&{begin} \37$\\{print\_char}(\\{so}(\\{str\_pool}[\|j]))$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+$\\{new\_line\_char}\K\\{nl}$;\5
+\&{return};\6
+\&{end};\2\2\2\6
+$\|j\K\\{str\_start}[\|s]$;\6
+\&{while} $\|j<\\{str\_start}[\|s+1]$ \1\&{do}\6
+\&{begin} \37$\\{print\_char}(\\{so}(\\{str\_pool}[\|j]))$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M61. Control sequence names, file names, and strings constructed with
+\.{\\string} might contain \\{ASCII\_code} values that can't
+be printed using \\{print\_char}. Therefore we use \\{slow\_print} for them:
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{slow\_print}(\|s:\\{integer})$;\C{prints string \|s}%
+\6
+\4\&{var} \37\|j: \37\\{pool\_pointer};\C{current character code position}\2\6
+\&{begin} \37\&{if} $(\|s\G\\{str\_ptr})\V(\|s<256)$ \1\&{then}\5
+$\\{print}(\|s)$\6
+\4\&{else} \&{begin} \37$\|j\K\\{str\_start}[\|s]$;\6
+\&{while} $\|j<\\{str\_start}[\|s+1]$ \1\&{do}\6
+\&{begin} \37$\\{print}(\\{so}(\\{str\_pool}[\|j]))$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M62. Here is the very first thing that \TeX\ prints: a headline that
+identifies
+the version number and format package. The \\{term\_offset} variable is
+temporarily
+incorrect, but the discrepancy is not serious since we assume that the banner
+and format identifier together will occupy at most \\{max\_print\_line}
+character positions.
+
+\Y\P$\4\X56:Initialize the output routines\X\mathrel{+}\S$\6
+\&{if} $\\{src\_specials\_p}\V\\{file\_line\_error\_style\_p}\V\\{parse\_first%
+\_line\_p}$ \1\&{then}\5
+$\\{wterm}(\\{banner\_k})$\6
+\4\&{else} $\\{wterm}(\\{banner})$;\2\6
+$\\{wterm}(\.{\'\ (\'})$;\5
+$\\{wterm}(\\{conststringcast}(\\{get\_enc\_string}))$;\5
+$\\{wterm}(\.{\')\'})$;\5
+$\\{wterm}(\\{version\_string})$;\6
+\&{if} $\\{format\_ident}>0$ \1\&{then}\5
+$\\{slow\_print}(\\{format\_ident})$;\2\6
+\\{print\_ln};\6
+\&{if} $\\{shellenabledp}$ \1\&{then}\6
+\&{begin} \37$\\{wterm}(\.{\'\ \'})$;\6
+\&{if} $\\{restrictedshell}$ \1\&{then}\6
+\&{begin} \37$\\{wterm}(\.{\'restricted\ \'})$;\6
+\&{end};\2\6
+$\\{wterm\_ln}(\.{\'\\write18\ enabled.\'})$;\6
+\&{end};\2\6
+\&{if} $\\{src\_specials\_p}$ \1\&{then}\6
+\&{begin} \37$\\{wterm\_ln}(\.{\'\ Source\ specials\ enabled.\'})$\6
+\&{end};\2\6
+\&{if} $\\{translate\_filename}$ \1\&{then}\6
+\&{begin} \37$\\{wterm}(\.{\'\ (\'})$;\5
+$\\{fputs}(\\{translate\_filename},\39\\{stdout})$;\5
+$\\{wterm\_ln}(\.{\')\'})$;\6
+\&{end};\2\6
+\\{update\_terminal};\par
+\fi
+
+\M63. The procedure \\{print\_nl} is like \\{print}, but it makes sure that the
+string appears at the beginning of a new line.
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_nl}(\|s:\\{str\_number})$;\C{prints string %
+\|s at beginning of line}\2\6
+\&{begin} \37\&{if} $((\\{term\_offset}>0)\W(\\{odd}(\\{selector})))\V\30((%
+\\{file\_offset}>0)\W(\\{selector}\G\\{log\_only}))$ \1\&{then}\5
+\\{print\_ln};\2\6
+$\\{print}(\|s)$;\6
+\&{end};\par
+\fi
+
+\M64. The procedure \\{print\_esc} prints a string that is preceded by
+the user's escape character (which is usually a backslash).
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_esc}(\|s:\\{str\_number})$;\C{prints escape
+character, then \|s}\6
+\4\&{var} \37\|c: \37\\{integer};\C{the escape character code}\2\6
+\&{begin} \37\X249:Set variable \|c to the current escape character\X;\6
+\&{if} $\|c\G0$ \1\&{then}\6
+\&{if} $\|c<256$ \1\&{then}\5
+$\\{print}(\|c)$;\2\2\6
+$\\{slow\_print}(\|s)$;\6
+\&{end};\par
+\fi
+
+\M65. An array of digits in the range $0\to15$ is printed by \\{print\_the%
+\_digs}.
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_the\_digs}(\|k:\\{eight\_bits})$;\C{prints $%
+\\{dig}[\|k-1]$$\,\ldots\,$$\\{dig}[0]$}\2\6
+\&{begin} \37\&{while} $\|k>0$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\|k)$;\6
+\&{if} $\\{dig}[\|k]<10$ \1\&{then}\5
+$\\{print\_char}(\.{"0"}+\\{dig}[\|k])$\6
+\4\&{else} $\\{print\_char}(\.{"A"}-10+\\{dig}[\|k])$;\2\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M66. The following procedure, which prints out the decimal representation of a
+given integer \|n, has been written carefully so that it works properly
+if $\|n=0$ or if $(-\|n)$ would cause overflow. It does not apply $\mathbin{%
+\&{mod}}$ or $\mathbin{\&{div}}$
+to negative arguments, since such operations are not implemented consistently
+by all \PASCAL\ compilers.
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_int}(\|n:\\{integer})$;\C{prints an integer
+in decimal form}\6
+\4\&{var} \37\|k: \37$0\to23$;\C{index to current digit; we assume that $%
+\|n<10^{23}$}\6
+\|m: \37\\{integer};\C{used to negate \|n in possibly dangerous cases}\2\6
+\&{begin} \37$\|k\K0$;\6
+\&{if} $\|n<0$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{"-"})$;\6
+\&{if} $\|n>-100000000$ \1\&{then}\5
+$\\{negate}(\|n)$\6
+\4\&{else} \&{begin} \37$\|m\K-1-\|n$;\5
+$\|n\K\|m\mathbin{\&{div}}10$;\5
+$\|m\K(\|m\mathbin{\&{mod}}10)+1$;\5
+$\|k\K1$;\6
+\&{if} $\|m<10$ \1\&{then}\5
+$\\{dig}[0]\K\|m$\6
+\4\&{else} \&{begin} \37$\\{dig}[0]\K0$;\5
+$\\{incr}(\|n)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\2\6
+\1\&{repeat} \37$\\{dig}[\|k]\K\|n\mathbin{\&{mod}}10$;\5
+$\|n\K\|n\mathbin{\&{div}}10$;\5
+$\\{incr}(\|k)$;\6
+\4\&{until}\5
+$\|n=0$;\2\6
+$\\{print\_the\_digs}(\|k)$;\6
+\&{end};\par
+\fi
+
+\M67. Here is a trivial procedure to print two digits; it is usually called
+with
+a parameter in the range $0\L\|n\L99$.
+
+\Y\P\4\&{procedure}\1\  \37$\\{print\_two}(\|n:\\{integer})$;\C{prints two
+least significant digits}\2\6
+\&{begin} \37$\|n\K\\{abs}(\|n)\mathbin{\&{mod}}100$;\5
+$\\{print\_char}(\.{"0"}+(\|n\mathbin{\&{div}}10))$;\5
+$\\{print\_char}(\.{"0"}+(\|n\mathbin{\&{mod}}10))$;\6
+\&{end};\par
+\fi
+
+\M68. Hexadecimal printing of nonnegative integers is accomplished by \\{print%
+\_hex}.
+
+\Y\P\4\&{procedure}\1\  \37$\\{print\_hex}(\|n:\\{integer})$;\C{prints a
+positive integer in hexadecimal form}\6
+\4\&{var} \37\|k: \37$0\to22$;\C{index to current digit; we assume that $0\L
+n<16^{22}$}\2\6
+\&{begin} \37$\|k\K0$;\5
+$\\{print\_char}(\.{""}\.{""})$;\6
+\1\&{repeat} \37$\\{dig}[\|k]\K\|n\mathbin{\&{mod}}16$;\5
+$\|n\K\|n\mathbin{\&{div}}16$;\5
+$\\{incr}(\|k)$;\6
+\4\&{until}\5
+$\|n=0$;\2\6
+$\\{print\_the\_digs}(\|k)$;\6
+\&{end};\par
+\fi
+
+\M69. Old versions of \TeX\ needed a procedure called \\{print\_ASCII} whose
+function
+is now subsumed by \\{print}. We retain the old name here as a possible aid to
+future software arch\ae ologists.
+
+\Y\P\D \37$\\{print\_ASCII}\S\\{print}$\par
+\fi
+
+\M70. Roman numerals are produced by the \\{print\_roman\_int} routine.
+Readers
+who like puzzles might enjoy trying to figure out how this tricky code
+works; therefore no explanation will be given. Notice that 1990 yields
+\.{mcmxc}, not \.{mxm}.
+
+\Y\P\4\&{procedure}\1\  \37$\\{print\_roman\_int}(\|n:\\{integer})$;\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37$\|j,\39\|k$: \37\\{pool\_pointer};\C{mysterious indices into %
+\\{str\_pool}}\6
+$\|u,\39\|v$: \37\\{nonnegative\_integer};\C{mysterious numbers}\2\6
+\&{begin} \37$\|j\K\\{str\_start}[\.{"m2d5c2l5x2v5i"}]$;\5
+$\|v\K1000$;\6
+\~ \1\&{loop}\ \&{begin} \37\&{while} $\|n\G\|v$ \1\&{do}\6
+\&{begin} \37$\\{print\_char}(\\{so}(\\{str\_pool}[\|j]))$;\5
+$\|n\K\|n-\|v$;\6
+\&{end};\2\6
+\&{if} $\|n\L0$ \1\&{then}\5
+\&{return};\C{nonpositive input produces no output}\2\6
+$\|k\K\|j+2$;\5
+$\|u\K\|v\mathbin{\&{div}}(\\{so}(\\{str\_pool}[\|k-1])-\.{"0"})$;\6
+\&{if} $\\{str\_pool}[\|k-1]=\\{si}(\.{"2"})$ \1\&{then}\6
+\&{begin} \37$\|k\K\|k+2$;\5
+$\|u\K\|u\mathbin{\&{div}}(\\{so}(\\{str\_pool}[\|k-1])-\.{"0"})$;\6
+\&{end};\2\6
+\&{if} $\|n+\|u\G\|v$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\\{so}(\\{str\_pool}[\|k]))$;\5
+$\|n\K\|n+\|u$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|j\K\|j+2$;\5
+$\|v\K\|v\mathbin{\&{div}}(\\{so}(\\{str\_pool}[\|j-1])-\.{"0"})$;\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M71. The \\{print} subroutine will not print a string that is still being
+created. The following procedure will.
+
+\Y\P\4\&{procedure}\1\  \37\\{print\_current\_string};\C{prints a yet-unmade
+string}\6
+\4\&{var} \37\|j: \37\\{pool\_pointer};\C{points to current character code}\2\6
+\&{begin} \37$\|j\K\\{str\_start}[\\{str\_ptr}]$;\6
+\&{while} $\|j<\\{pool\_ptr}$ \1\&{do}\6
+\&{begin} \37$\\{print\_char}(\\{so}(\\{str\_pool}[\|j]))$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M72. Here is a procedure that asks the user to type a line of input,
+assuming that the \\{selector} setting is either \\{term\_only} or \\{term\_and%
+\_log}.
+The input is placed into locations \\{first} through $\\{last}-1$ of the
+\\{buffer} array, and echoed on the transcript file if appropriate.
+
+This procedure is never called when $\\{interaction}<\\{scroll\_mode}$.
+
+\Y\P\D \37$\\{prompt\_input}(\#)\S$\1\6
+\&{begin} \37\\{wake\_up\_terminal};\5
+$\\{print}(\#)$;\5
+\\{term\_input};\6
+\&{end}\C{prints a string and gets a line of input}\2\par
+\Y\P\4\&{procedure}\1\  \37\\{term\_input};\C{gets a line from the terminal}\6
+\4\&{var} \37\|k: \37$0\to\\{buf\_size}$;\C{index into \\{buffer}}\2\6
+\&{begin} \37\\{update\_terminal};\C{now the user sees the prompt for sure}\6
+\&{if} $\R\\{input\_ln}(\\{term\_in},\39\\{true})$ \1\&{then}\5
+$\\{fatal\_error}(\.{"End\ of\ file\ on\ the\ terminal!"})$;\2\6
+$\\{term\_offset}\K0$;\C{the user's line ended with \<\rm return>}\6
+$\\{decr}(\\{selector})$;\C{prepare to echo the input}\6
+\&{if} $\\{last}\I\\{first}$ \1\&{then}\6
+\&{for} $\|k\K\\{first}\mathrel{\&{to}}\\{last}-1$ \1\&{do}\5
+$\\{print}(\\{buffer}[\|k])$;\2\2\6
+\\{print\_ln};\5
+$\\{incr}(\\{selector})$;\C{restore previous status}\6
+\&{end};\par
+\fi
+
+\N73.  \[6] Reporting errors.
+When something anomalous is detected, \TeX\ typically does something like this:
+$$\vbox{\halign{#\hfil\cr
+$\\{print\_err}(\.{"Something\ anomalous\ has\ been\ detected"})$;\cr
+$\\{help3}(\.{"This\ is\ the\ first\ line\ of\ my\ offer\ to\ help."})$\cr
+$(\.{"This\ is\ the\ second\ line.\ I\'m\ trying\ to"})$\cr
+$(\.{"explain\ the\ best\ way\ for\ you\ to\ proceed."})$;\cr
+\\{error};\cr}}$$
+A two-line help message would be given using \\{help2}, etc.; these informal
+helps should use simple vocabulary that complements the words used in the
+official error message that was printed. (Outside the U.S.A., the help
+messages should preferably be translated into the local vernacular. Each
+line of help is at most 60 characters long, in the present implementation,
+so that \\{max\_print\_line} will not be exceeded.)
+
+The \\{print\_err} procedure supplies a `\.!' before the official message,
+and makes sure that the terminal is awake if a stop is going to occur.
+The \\{error} procedure supplies a `\..' after the official message, then it
+shows the location of the error; and if $\\{interaction}=\\{error\_stop%
+\_mode}$,
+it also enters into a dialog with the user, during which time the help
+message may be printed.
+
+\fi
+
+\M74. The global variable \\{interaction} has four settings, representing
+increasing
+amounts of user interaction:
+
+\Y\P\D \37$\\{batch\_mode}=0$\C{omits all stops and omits terminal output}\par
+\P\D \37$\\{nonstop\_mode}=1$\C{omits all stops}\par
+\P\D \37$\\{scroll\_mode}=2$\C{omits error stops}\par
+\P\D \37$\\{error\_stop\_mode}=3$\C{stops at every opportunity to interact}\par
+\P\D \37$\\{unspecified\_mode}=4$\C{extra value for command-line switch}\par
+\P\D \37$\\{print\_err}(\#)\S$\1\6
+\&{begin} \37\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5
+\\{wake\_up\_terminal};\2\6
+\&{if} $\\{file\_line\_error\_style\_p}$ \1\&{then}\5
+\\{print\_file\_line}\6
+\4\&{else} $\\{print\_nl}(\.{"!\ "})$;\2\6
+$\\{print}(\#)$;\6
+\&{end}\2\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{interaction}: \37$\\{batch\_mode}\to\\{error\_stop\_mode}$;\C{current
+level of interaction}\6
+\4\\{interaction\_option}: \37$\\{batch\_mode}\to\\{unspecified\_mode}$;\C{set
+from command line}\par
+\fi
+
+\M75. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+\&{if} $\\{interaction\_option}=\\{unspecified\_mode}$ \1\&{then}\5
+$\\{interaction}\K\\{error\_stop\_mode}$\6
+\4\&{else} $\\{interaction}\K\\{interaction\_option}$;\2\par
+\fi
+
+\M76. \TeX\ is careful not to call \\{error} when the print \\{selector}
+setting
+might be unusual. The only possible values of \\{selector} at the time of
+error messages are
+
+\yskip\hang\\{no\_print} (when $\\{interaction}=\\{batch\_mode}$
+and \\{log\_file} not yet open);
+
+\hang\\{term\_only} (when $\\{interaction}>\\{batch\_mode}$ and \\{log\_file}
+not yet open);
+
+\hang\\{log\_only} (when $\\{interaction}=\\{batch\_mode}$ and \\{log\_file} is
+open);
+
+\hang\\{term\_and\_log} (when $\\{interaction}>\\{batch\_mode}$ and \\{log%
+\_file} is open).
+
+\Y\P$\4\X76:Initialize the print \\{selector} based on \\{interaction}\X\S$\6
+\&{if} $\\{interaction}=\\{batch\_mode}$ \1\&{then}\5
+$\\{selector}\K\\{no\_print}$\ \&{else} $\\{selector}\K\\{term\_only}$\2\par
+\Us1278\ET1350.\fi
+
+\M77. A global variable \\{deletions\_allowed} is set \\{false} if the \\{get%
+\_next}
+routine is active when \\{error} is called; this ensures that \\{get\_next}
+and related routines like \\{get\_token} will never be called recursively.
+A similar interlock is provided by \\{set\_box\_allowed}.
+
+The global variable \\{history} records the worst level of error that
+has been detected. It has four possible values: \\{spotless}, \\{warning%
+\_issued},
+\\{error\_message\_issued}, and \\{fatal\_error\_stop}.
+
+Another global variable, \\{error\_count}, is increased by one when an
+\\{error} occurs without an interactive dialog, and it is reset to zero at
+the end of every paragraph.  If \\{error\_count} reaches 100, \TeX\ decides
+that there is no point in continuing further.
+
+\Y\P\D \37$\\{spotless}=0$\C{\\{history} value when nothing has been amiss yet}%
+\par
+\P\D \37$\\{warning\_issued}=1$\C{\\{history} value when \\{begin\_diagnostic}
+has been called}\par
+\P\D \37$\\{error\_message\_issued}=2$\C{\\{history} value when \\{error} has
+been called}\par
+\P\D \37$\\{fatal\_error\_stop}=3$\C{\\{history} value when termination was
+premature}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{deletions\_allowed}: \37\\{boolean};\C{is it safe for \\{error} to call %
+\\{get\_token}?}\6
+\4\\{set\_box\_allowed}: \37\\{boolean};\C{is it safe to do a \.{\\setbox}
+assignment?}\6
+\4\\{history}: \37$\\{spotless}\to\\{fatal\_error\_stop}$;\C{has the source
+input been clean so far?}\6
+\4\\{error\_count}: \37$-1\to100$;\C{the number of scrolled errors since the
+last paragraph ended}\par
+\fi
+
+\M78. The value of \\{history} is initially \\{fatal\_error\_stop}, but it will
+be changed to \\{spotless} if \TeX\ survives the initialization process.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{deletions\_allowed}\K\\{true}$;\5
+$\\{set\_box\_allowed}\K\\{true}$;\5
+$\\{error\_count}\K0$;\C{\\{history} is initialized elsewhere}\par
+\fi
+
+\M79. Since errors can be detected almost anywhere in \TeX, we want to declare
+the
+error procedures near the beginning of the program. But the error procedures
+in turn use some other procedures, which need to be declared \\{forward}
+before we get to \\{error} itself.
+
+It is possible for \\{error} to be called recursively if some error arises
+when \\{get\_token} is being used to delete a token, and/or if some fatal error
+occurs while \TeX\ is trying to fix a non-fatal one. But such recursion
+is never more than two levels deep.
+
+\Y\P$\4\X79:Error handling procedures\X\S$\6
+\4\&{procedure}\1\  \37\\{normalize\_selector};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{get\_token};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{term\_input};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{show\_context};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{begin\_file\_reading};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{open\_log\_file};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{close\_files\_and\_terminate};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{clear\_for\_error\_prompt};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{give\_err\_help};\5
+\\{forward};\5
+\hbox{\2}\6
+\hbox{\4\hskip-\fontdimen2\font}\ \&{debug} \37\ \&{procedure}\1\  \37\\{debug%
+\_help};\5
+\\{forward};\ \&{gubed} \par
+\As82, 83, 94, 95\ETs96.
+\U4.\fi
+
+\M80. Individual lines of help are recorded in the array \\{help\_line}, which
+contains entries in positions $0\to(\\{help\_ptr}-1)$. They should be printed
+in reverse order, i.e., with $\\{help\_line}[0]$ appearing last.
+
+\Y\P\D \37$\\{hlp1}(\#)\S\\{help\_line}[0]\K\#$;\ \&{end} \par
+\P\D \37$\\{hlp2}(\#)\S\\{help\_line}[1]\K\#$;\5
+\\{hlp1}\par
+\P\D \37$\\{hlp3}(\#)\S\\{help\_line}[2]\K\#$;\5
+\\{hlp2}\par
+\P\D \37$\\{hlp4}(\#)\S\\{help\_line}[3]\K\#$;\5
+\\{hlp3}\par
+\P\D \37$\\{hlp5}(\#)\S\\{help\_line}[4]\K\#$;\5
+\\{hlp4}\par
+\P\D \37$\\{hlp6}(\#)\S\\{help\_line}[5]\K\#$;\5
+\\{hlp5}\par
+\P\D \37$\\{help0}\S\\{help\_ptr}\K0$\C{sometimes there might be no help}\par
+\P\D \37$\\{help1}\S$\ \&{begin} \37$\\{help\_ptr}\K1$;\5
+\\{hlp1}\C{use this with one help line}\par
+\P\D \37$\\{help2}\S$\ \&{begin} \37$\\{help\_ptr}\K2$;\5
+\\{hlp2}\C{use this with two help lines}\par
+\P\D \37$\\{help3}\S$\ \&{begin} \37$\\{help\_ptr}\K3$;\5
+\\{hlp3}\C{use this with three help lines}\par
+\P\D \37$\\{help4}\S$\ \&{begin} \37$\\{help\_ptr}\K4$;\5
+\\{hlp4}\C{use this with four help lines}\par
+\P\D \37$\\{help5}\S$\ \&{begin} \37$\\{help\_ptr}\K5$;\5
+\\{hlp5}\C{use this with five help lines}\par
+\P\D \37$\\{help6}\S$\ \&{begin} \37$\\{help\_ptr}\K6$;\5
+\\{hlp6}\C{use this with six help lines}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{help\_line}: \37\&{array} $[0\to5]$ \1\&{of}\5
+\\{str\_number};\C{helps for the next \\{error}}\2\6
+\4\\{help\_ptr}: \37$0\to6$;\C{the number of help lines present}\6
+\4\\{use\_err\_help}: \37\\{boolean};\C{should the \\{err\_help} list be
+shown?}\par
+\fi
+
+\M81. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{help\_ptr}\K0$;\5
+$\\{use\_err\_help}\K\\{false}$;\par
+\fi
+
+\M82. The \\{jump\_out} procedure just cuts across all active procedure levels
+and
+goes to \\{end\_of\_TEX}. This is the only nontrivial \&{goto}  statement in
+the
+whole program. It is used when there is no recovery from a particular error.
+
+Some \PASCAL\ compilers do not implement non-local \&{goto}  statements.
+In such cases the body of \\{jump\_out} should simply be
+`\\{close\_files\_and\_terminate};\thinspace' followed by a call on some system
+procedure that quietly terminates the program.
+
+\Y\P\D \37$\\{do\_final\_end}\S$\1\6
+\&{begin} \37\\{update\_terminal};\5
+$\\{ready\_already}\K0$;\6
+\&{if} $(\\{history}\I\\{spotless})\W(\\{history}\I\\{warning\_issued})$ \1%
+\&{then}\5
+$\\{uexit}(1)$\6
+\4\&{else} $\\{uexit}(0)$;\2\6
+\&{end}\2\par
+\Y\P$\4\X79:Error handling procedures\X\mathrel{+}\S$\6
+\\{noreturn} \6
+\4\&{procedure}\1\  \37\\{jump\_out};\2\6
+\&{begin} \37\\{close\_files\_and\_terminate};\5
+\\{do\_final\_end};\6
+\&{end};\par
+\fi
+
+\M83. Here now is the general \\{error} routine.
+
+\Y\P$\4\X79:Error handling procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{error};\C{completes the job of error reporting}\6
+\4\&{label} \37$\\{continue},\39\\{exit}$;\6
+\4\&{var} \37\|c: \37\\{ASCII\_code};\C{what the user types}\6
+$\\{s1},\39\\{s2},\39\\{s3},\39\\{s4}$: \37\\{integer};\C{used to save global
+variables when deleting tokens}\2\6
+\&{begin} \37\&{if} $\\{history}<\\{error\_message\_issued}$ \1\&{then}\5
+$\\{history}\K\\{error\_message\_issued}$;\2\6
+$\\{print\_char}(\.{"."})$;\5
+\\{show\_context};\6
+\&{if} $(\\{halt\_on\_error\_p})$ \1\&{then}\6
+\&{begin} \37$\\{history}\K\\{fatal\_error\_stop}$;\5
+\\{jump\_out};\6
+\&{end};\2\6
+\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5
+\X84:Get user's advice and \&{return}\X;\2\6
+$\\{incr}(\\{error\_count})$;\6
+\&{if} $\\{error\_count}=100$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"(That\ makes\ 100\ errors;\ please\ try\
+again.)"})$;\5
+$\\{history}\K\\{fatal\_error\_stop}$;\5
+\\{jump\_out};\6
+\&{end};\2\6
+\X91:Put help message on the transcript file\X;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M84. \P$\X84:Get user's advice and \&{return}\X\S$\6
+\~ \1\&{loop}\ \&{begin} \37\\{continue}: \37\\{clear\_for\_error\_prompt};\5
+$\\{prompt\_input}(\.{"?\ "})$;\6
+\&{if} $\\{last}=\\{first}$ \1\&{then}\5
+\&{return};\2\6
+$\|c\K\\{buffer}[\\{first}]$;\6
+\&{if} $\|c\G\.{"a"}$ \1\&{then}\5
+$\|c\K\|c+\.{"A"}-\.{"a"}$;\C{convert to uppercase}\2\6
+\X85:Interpret code \|c and \&{return} if done\X;\6
+\&{end}\2\par
+\U83.\fi
+
+\M85. It is desirable to provide an `\.E' option here that gives the user
+an easy way to return from \TeX\ to the system editor, with the offending
+line ready to be edited.
+We do this by calling the external procedure \\{call\_edit} with a pointer to
+the filename, its length, and the line number.
+However, here we just set up the variables that will be used as arguments,
+since we don't want to do the switch-to-editor until after TeX has closed
+its files.
+
+There is a secret `\.D' option available when the debugging routines haven't
+been commented~out.
+\Y\P\D \37$\\{edit\_file}\S\\{input\_stack}[\\{base\_ptr}]$\par
+\Y\P$\4\X85:Interpret code \|c and \&{return} if done\X\S$\6
+\&{case} $\|c$ \1\&{of}\6
+\4$\.{"0"},\39\.{"1"},\39\.{"2"},\39\.{"3"},\39\.{"4"},\39\.{"5"},\39\.{"6"},%
+\39\.{"7"},\39\.{"8"},\39\.{"9"}$: \37\&{if} $\\{deletions\_allowed}$ \1%
+\&{then}\5
+\X89:Delete \(c)$\|c-\.{"0"}$ tokens and \&{goto} \\{continue}\X;\2\6
+\hbox{\4\4}\ \&{debug} \37\.{"D"}: \37\&{begin} \37\\{debug\_help};\5
+\&{goto} \37\\{continue};\ \&{end};\ \&{gubed}\6
+\4\.{"E"}: \37\&{if} $\\{base\_ptr}>0$ \1\&{then}\6
+\&{begin} \37$\\{edit\_name\_start}\K\\{str\_start}[\\{edit\_file}.\\{name%
+\_field}]$;\5
+$\\{edit\_name\_length}\K\\{str\_start}[\\{edit\_file}.\\{name\_field}+1]-%
+\\{str\_start}[\\{edit\_file}.\\{name\_field}]$;\5
+$\\{edit\_line}\K\\{line}$;\5
+\\{jump\_out};\6
+\&{end};\2\6
+\4\.{"H"}: \37\X90:Print the help information and \&{goto} \\{continue}\X;\6
+\4\.{"I"}: \37\X88:Introduce new material from the terminal and \&{return}\X;\6
+\4$\.{"Q"},\39\.{"R"},\39\.{"S"}$: \37\X87:Change the interaction level and %
+\&{return}\X;\6
+\4\.{"X"}: \37\&{begin} \37$\\{interaction}\K\\{scroll\_mode}$;\5
+\\{jump\_out};\6
+\&{end};\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\6
+\X86:Print the menu of available options\X\par
+\U84.\fi
+
+\M86. \P$\X86:Print the menu of available options\X\S$\6
+\&{begin} \37$\\{print}(\.{"Type\ <return>\ to\ proceed,\ S\ to\ scroll\ future%
+\ error\ messages,"})$;\6
+$\\{print\_nl}(\.{"R\ to\ run\ without\ stopping,\ Q\ to\ run\ quietly,"})$;\6
+$\\{print\_nl}(\.{"I\ to\ insert\ something,\ "})$;\6
+\&{if} $\\{base\_ptr}>0$ \1\&{then}\5
+$\\{print}(\.{"E\ to\ edit\ your\ file,"})$;\2\6
+\&{if} $\\{deletions\_allowed}$ \1\&{then}\5
+$\\{print\_nl}(\.{"1\ or\ ...\ or\ 9\ to\ ignore\ the\ next\ 1\ to\ 9\ tokens\
+of\ input,"})$;\2\6
+$\\{print\_nl}(\.{"H\ for\ help,\ X\ to\ quit."})$;\6
+\&{end}\par
+\U85.\fi
+
+\M87. Here the author of \TeX\ apologizes for making use of the numerical
+relation between \.{"Q"}, \.{"R"}, \.{"S"}, and the desired interaction
+settings
+\\{batch\_mode}, \\{nonstop\_mode}, \\{scroll\_mode}.
+
+\Y\P$\4\X87:Change the interaction level and \&{return}\X\S$\6
+\&{begin} \37$\\{error\_count}\K0$;\5
+$\\{interaction}\K\\{batch\_mode}+\|c-\.{"Q"}$;\5
+$\\{print}(\.{"OK,\ entering\ "})$;\6
+\&{case} $\|c$ \1\&{of}\6
+\4\.{"Q"}: \37\&{begin} \37$\\{print\_esc}(\.{"batchmode"})$;\5
+$\\{decr}(\\{selector})$;\6
+\&{end};\6
+\4\.{"R"}: \37$\\{print\_esc}(\.{"nonstopmode"})$;\6
+\4\.{"S"}: \37$\\{print\_esc}(\.{"scrollmode"})$;\2\6
+\&{end};\C{there are no other cases}\6
+$\\{print}(\.{"..."})$;\5
+\\{print\_ln};\5
+\\{update\_terminal};\5
+\&{return};\6
+\&{end}\par
+\U85.\fi
+
+\M88. When the following code is executed, $\\{buffer}[(\\{first}+1)\to(%
+\\{last}-1)]$ may
+contain the material inserted by the user; otherwise another prompt will
+be given. In order to understand this part of the program fully, you need
+to be familiar with \TeX's input stacks.
+
+\Y\P$\4\X88:Introduce new material from the terminal and \&{return}\X\S$\6
+\&{begin} \37\\{begin\_file\_reading};\C{enter a new syntactic level for
+terminal input}\6
+\C{now $\\{state}=\\{mid\_line}$, so an initial blank space will count as a
+blank}\6
+\&{if} $\\{last}>\\{first}+1$ \1\&{then}\6
+\&{begin} \37$\\{loc}\K\\{first}+1$;\5
+$\\{buffer}[\\{first}]\K\.{"\ "}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{prompt\_input}(\.{"insert>"})$;\5
+$\\{loc}\K\\{first}$;\6
+\&{end};\2\6
+$\\{first}\K\\{last}$;\5
+$\\{cur\_input}.\\{limit\_field}\K\\{last}-1$;\C{no \\{end\_line\_char} ends
+this line}\6
+\&{return};\6
+\&{end}\par
+\U85.\fi
+
+\M89. We allow deletion of up to 99 tokens at a time.
+
+\Y\P$\4\X89:Delete \(c)$\|c-\.{"0"}$ tokens and \&{goto} \\{continue}\X\S$\6
+\&{begin} \37$\\{s1}\K\\{cur\_tok}$;\5
+$\\{s2}\K\\{cur\_cmd}$;\5
+$\\{s3}\K\\{cur\_chr}$;\5
+$\\{s4}\K\\{align\_state}$;\5
+$\\{align\_state}\K1000000$;\5
+$\\{OK\_to\_interrupt}\K\\{false}$;\6
+\&{if} $(\\{last}>\\{first}+1)\W(\\{buffer}[\\{first}+1]\G\.{"0"})\W(%
+\\{buffer}[\\{first}+1]\L\.{"9"})$ \1\&{then}\5
+$\|c\K\|c\ast10+\\{buffer}[\\{first}+1]-\.{"0"}\ast11$\6
+\4\&{else} $\|c\K\|c-\.{"0"}$;\2\6
+\&{while} $\|c>0$ \1\&{do}\6
+\&{begin} \37\\{get\_token};\C{one-level recursive call of \\{error} is
+possible}\6
+$\\{decr}(\|c)$;\6
+\&{end};\2\6
+$\\{cur\_tok}\K\\{s1}$;\5
+$\\{cur\_cmd}\K\\{s2}$;\5
+$\\{cur\_chr}\K\\{s3}$;\5
+$\\{align\_state}\K\\{s4}$;\5
+$\\{OK\_to\_interrupt}\K\\{true}$;\5
+$\\{help2}(\.{"I\ have\ just\ deleted\ some\ text,\ as\ you\ asked."})$\6
+$(\.{"You\ can\ now\ delete\ more,\ or\ insert,\ or\ whatever."})$;\5
+\\{show\_context};\5
+\&{goto} \37\\{continue};\6
+\&{end}\par
+\U85.\fi
+
+\M90. \P$\X90:Print the help information and \&{goto} \\{continue}\X\S$\6
+\&{begin} \37\&{if} $\\{use\_err\_help}$ \1\&{then}\6
+\&{begin} \37\\{give\_err\_help};\5
+$\\{use\_err\_help}\K\\{false}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{help\_ptr}=0$ \1\&{then}\5
+$\\{help2}(\.{"Sorry,\ I\ don\'t\ know\ how\ to\ help\ in\ this\ situation."})$%
+\2\6
+$\hbox{\kern1em}(\.{"Maybe\ you\ should\ try\ asking\ a\ human?"})$;\6
+\1\&{repeat} \37$\\{decr}(\\{help\_ptr})$;\5
+$\\{print}(\\{help\_line}[\\{help\_ptr}])$;\5
+\\{print\_ln};\6
+\4\&{until}\5
+$\\{help\_ptr}=0$;\2\6
+\&{end};\2\6
+$\\{help4}(\.{"Sorry,\ I\ already\ gave\ what\ help\ I\ could..."})$\6
+$(\.{"Maybe\ you\ should\ try\ asking\ a\ human?"})$\6
+$(\.{"An\ error\ might\ have\ occurred\ before\ I\ noticed\ any\ problems."})$\6
+$(\.{"\`\`If\ all\ else\ fails,\ read\ the\ instructions.\'\'"})$;\6
+\&{goto} \37\\{continue};\6
+\&{end}\par
+\U85.\fi
+
+\M91. \P$\X91:Put help message on the transcript file\X\S$\6
+\&{if} $\\{interaction}>\\{batch\_mode}$ \1\&{then}\5
+$\\{decr}(\\{selector})$;\C{avoid terminal output}\2\6
+\&{if} $\\{use\_err\_help}$ \1\&{then}\6
+\&{begin} \37\\{print\_ln};\5
+\\{give\_err\_help};\6
+\&{end}\6
+\4\&{else} \&{while} $\\{help\_ptr}>0$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\\{help\_ptr})$;\5
+$\\{print\_nl}(\\{help\_line}[\\{help\_ptr}])$;\6
+\&{end};\2\2\6
+\\{print\_ln};\6
+\&{if} $\\{interaction}>\\{batch\_mode}$ \1\&{then}\5
+$\\{incr}(\\{selector})$;\C{re-enable terminal output}\2\6
+\\{print\_ln}\par
+\U83.\fi
+
+\M92. A dozen or so error messages end with a parenthesized integer, so we
+save a teeny bit of program space by declaring the following procedure:
+
+\Y\P\4\&{procedure}\1\  \37$\\{int\_error}(\|n:\\{integer})$;\2\6
+\&{begin} \37$\\{print}(\.{"\ ("})$;\5
+$\\{print\_int}(\|n)$;\5
+$\\{print\_char}(\.{")"})$;\5
+\\{error};\6
+\&{end};\par
+\fi
+
+\M93. In anomalous cases, the print selector might be in an unknown state;
+the following subroutine is called to fix things just enough to keep
+running a bit longer.
+
+\Y\P\4\&{procedure}\1\  \37\\{normalize\_selector};\2\6
+\&{begin} \37\&{if} $\\{log\_opened}$ \1\&{then}\5
+$\\{selector}\K\\{term\_and\_log}$\6
+\4\&{else} $\\{selector}\K\\{term\_only}$;\2\6
+\&{if} $\\{job\_name}=0$ \1\&{then}\5
+\\{open\_log\_file};\2\6
+\&{if} $\\{interaction}=\\{batch\_mode}$ \1\&{then}\5
+$\\{decr}(\\{selector})$;\2\6
+\&{end};\par
+\fi
+
+\M94. The following procedure prints \TeX's last words before dying.
+
+\Y\P\D \37$\\{succumb}\S$\1\6
+\&{begin} \37\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5
+$\\{interaction}\K\\{scroll\_mode}$;\C{no more interaction}\2\6
+\&{if} $\\{log\_opened}$ \1\&{then}\5
+\\{error};\2\6
+\&{debug} \37\&{if} $\\{interaction}>\\{batch\_mode}$ \1\&{then}\5
+\\{debug\_help};\ \2\6
+\&{gubed}\6
+$\\{history}\K\\{fatal\_error\_stop}$;\5
+\\{jump\_out};\C{irrecoverable error}\6
+\&{end}\2\par
+\Y\P$\4\X79:Error handling procedures\X\mathrel{+}\S$\6
+\\{noreturn} \6
+\4\&{procedure}\1\  \37$\\{fatal\_error}(\|s:\\{str\_number})$;\C{prints \|s,
+and that's it}\2\6
+\&{begin} \37\\{normalize\_selector};\6
+$\\{print\_err}(\.{"Emergency\ stop"})$;\5
+$\\{help1}(\|s)$;\5
+\\{succumb};\6
+\&{end};\par
+\fi
+
+\M95. Here is the most dreaded error message.
+
+\Y\P$\4\X79:Error handling procedures\X\mathrel{+}\S$\6
+\\{noreturn} \6
+\4\&{procedure}\1\  \37$\\{overflow}(\|s:\\{str\_number};\,\35\|n:%
+\\{integer})$;\C{stop due to finiteness}\2\6
+\&{begin} \37\\{normalize\_selector};\5
+$\\{print\_err}(\.{"TeX\ capacity\ exceeded,\ sorry\ ["})$;\5
+$\\{print}(\|s)$;\5
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_int}(\|n)$;\5
+$\\{print\_char}(\.{"]"})$;\5
+$\\{help2}(\.{"If\ you\ really\ absolutely\ need\ more\ capacity,"})$\6
+$(\.{"you\ can\ ask\ a\ wizard\ to\ enlarge\ me."})$;\5
+\\{succumb};\6
+\&{end};\par
+\fi
+
+\M96. The program might sometime run completely amok, at which point there is
+no choice but to stop. If no previous error has been detected, that's bad
+news; a message is printed that is really intended for the \TeX\
+maintenance person instead of the user (unless the user has been
+particularly diabolical).  The index entries for `this can't happen' may
+help to pinpoint the problem.
+
+\Y\P$\4\X79:Error handling procedures\X\mathrel{+}\S$\6
+\\{noreturn} \6
+\4\&{procedure}\1\  \37$\\{confusion}(\|s:\\{str\_number})$;\C{consistency
+check violated; \|s tells where}\2\6
+\&{begin} \37\\{normalize\_selector};\6
+\&{if} $\\{history}<\\{error\_message\_issued}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"This\ can\'t\ happen\ ("})$;\5
+$\\{print}(\|s)$;\5
+$\\{print\_char}(\.{")"})$;\5
+$\\{help1}(\.{"I\'m\ broken.\ Please\ show\ this\ to\ someone\ who\ can\ fix\
+can\ fix"})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"I\ can\'t\ go\ on\ meeting\ you\
+like\ this"})$;\5
+$\\{help2}(\.{"One\ of\ your\ faux\ pas\ seems\ to\ have\ wounded\ me\
+deeply..."})$\6
+$(\.{"in\ fact,\ I\'m\ barely\ conscious.\ Please\ fix\ it\ and\ try\
+again."})$;\6
+\&{end};\2\6
+\\{succumb};\6
+\&{end};\par
+\fi
+
+\M97. Users occasionally want to interrupt \TeX\ while it's running.
+If the \PASCAL\ runtime system allows this, one can implement
+a routine that sets the global variable \\{interrupt} to some nonzero value
+when such an interrupt is signalled. Otherwise there is probably at least
+a way to make \\{interrupt} nonzero using the \PASCAL\ debugger.
+
+\Y\P\D \37$\\{check\_interrupt}\S$\1\6
+\&{begin} \37\&{if} $\\{interrupt}\I0$ \1\&{then}\5
+\\{pause\_for\_instructions};\2\6
+\&{end}\2\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{interrupt}: \37\\{integer};\C{should \TeX\ pause for instructions?}\6
+\4\\{OK\_to\_interrupt}: \37\\{boolean};\C{should interrupts be observed?}\par
+\fi
+
+\M98. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{interrupt}\K0$;\5
+$\\{OK\_to\_interrupt}\K\\{true}$;\par
+\fi
+
+\M99. When an interrupt has been detected, the program goes into its
+highest interaction level and lets the user have nearly the full flexibility of
+the \\{error} routine.  \TeX\ checks for interrupts only at times when it is
+safe to do this.
+
+\Y\P\4\&{procedure}\1\  \37\\{pause\_for\_instructions};\2\6
+\&{begin} \37\&{if} $\\{OK\_to\_interrupt}$ \1\&{then}\6
+\&{begin} \37$\\{interaction}\K\\{error\_stop\_mode}$;\6
+\&{if} $(\\{selector}=\\{log\_only})\V(\\{selector}=\\{no\_print})$ \1\&{then}\5
+$\\{incr}(\\{selector})$;\2\6
+$\\{print\_err}(\.{"Interruption"})$;\5
+$\\{help3}(\.{"You\ rang?"})$\6
+$(\.{"Try\ to\ insert\ some\ instructions\ for\ me\ (e.g.,\`I\\showlists%
+\'),"})$\6
+$(\.{"unless\ you\ just\ want\ to\ quit\ by\ typing\ \`X\'."})$;\5
+$\\{deletions\_allowed}\K\\{false}$;\5
+\\{error};\5
+$\\{deletions\_allowed}\K\\{true}$;\5
+$\\{interrupt}\K0$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\N100.  \[7] Arithmetic with scaled dimensions.
+The principal computations performed by \TeX\ are done entirely in terms of
+integers less than $2^{31}$ in magnitude; and divisions are done only when both
+dividend and divisor are nonnegative. Thus, the arithmetic specified in this
+program can be carried out in exactly the same way on a wide variety of
+computers, including some small ones. Why? Because the arithmetic
+calculations need to be spelled out precisely in order to guarantee that
+\TeX\ will produce identical output on different machines. If some
+quantities were rounded differently in different implementations, we would
+find that line breaks and even page breaks might occur in different places.
+Hence the arithmetic of \TeX\ has been designed with care, and systems that
+claim to be implementations of \TeX82 should follow precisely the
+calculations as they appear in the present program.
+
+(Actually there are three places where \TeX\ uses $\mathbin{\&{div}}$ with a
+possibly negative
+numerator. These are harmless; see $\mathbin{\&{div}}$ in the index. Also if
+the user
+sets the \.{\\time} or the \.{\\year} to a negative value, some diagnostic
+information will involve negative-numerator division. The same remarks
+apply for $\mathbin{\&{mod}}$ as well as for $\mathbin{\&{div}}$.)
+
+\fi
+
+\M101. Here is a routine that calculates half of an integer, using an
+unambiguous convention with respect to signed odd numbers.
+
+\Y\P\4\&{function}\1\  \37$\\{half}(\|x:\\{integer})$: \37\\{integer};\2\6
+\&{begin} \37\&{if} $\\{odd}(\|x)$ \1\&{then}\5
+$\\{half}\K(\|x+1)\mathbin{\&{div}}2$\6
+\4\&{else} $\\{half}\K\|x\mathbin{\&{div}}2$;\2\6
+\&{end};\par
+\fi
+
+\M102. Fixed-point arithmetic is done on {\sl scaled integers\/} that are
+multiples
+of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit
+positions from the right end of a binary computer word.
+
+\Y\P\D \37$\\{unity}\S\O{200000}$\C{$2^{16}$, represents 1.00000}\par
+\P\D \37$\\{two}\S\O{400000}$\C{$2^{17}$, represents 2.00000}\par
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{scaled}=\\{integer}$;\C{this type is used for scaled integers}\6
+$\\{nonnegative\_integer}=0\to\O{17777777777}$;\C{$0\L x<2^{31}$}\6
+$\\{small\_number}=0\to63$;\C{this type is self-explanatory}\par
+\fi
+
+\M103. The following function is used to create a scaled integer from a given
+decimal
+fraction $(.d_0d_1\ldots d_{k-1})$, where $0\L\|k\L17$. The digit $d_i$ is
+given in $\\{dig}[\|i]$, and the calculation produces a correctly rounded
+result.
+
+\Y\P\4\&{function}\1\  \37$\\{round\_decimals}(\|k:\\{small\_number})$: \37%
+\\{scaled};\C{converts a decimal fraction}\6
+\4\&{var} \37\|a: \37\\{integer};\C{the accumulator}\2\6
+\&{begin} \37$\|a\K0$;\6
+\&{while} $\|k>0$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\|k)$;\5
+$\|a\K(\|a+\\{dig}[\|k]\ast\\{two})\mathbin{\&{div}}10$;\6
+\&{end};\2\6
+$\\{round\_decimals}\K(\|a+1)\mathbin{\&{div}}2$;\6
+\&{end};\par
+\fi
+
+\M104. Conversely, here is a procedure analogous to \\{print\_int}. If the
+output
+of this procedure is subsequently read by \TeX\ and converted by the
+\\{round\_decimals} routine above, it turns out that the original value will
+be reproduced exactly; the ``simplest'' such decimal number is output,
+but there is always at least one digit following the decimal point.
+
+The invariant relation in the \&{repeat} loop is that a sequence of
+decimal digits yet to be printed will yield the original number if and only if
+they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$.
+We can stop if and only if $f=0$ satisfies this condition; the loop will
+terminate before $s$ can possibly become zero.
+
+\Y\P\4\&{procedure}\1\  \37$\\{print\_scaled}(\|s:\\{scaled})$;\C{prints scaled
+real, rounded to five   digits}\6
+\4\&{var} \37\\{delta}: \37\\{scaled};\C{amount of allowable inaccuracy}\2\6
+\&{begin} \37\&{if} $\|s<0$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{"-"})$;\5
+$\\{negate}(\|s)$;\C{print the sign, if negative}\6
+\&{end};\2\6
+$\\{print\_int}(\|s\mathbin{\&{div}}\\{unity})$;\C{print the integer part}\6
+$\\{print\_char}(\.{"."})$;\5
+$\|s\K10\ast(\|s\mathbin{\&{mod}}\\{unity})+5$;\5
+$\\{delta}\K10$;\6
+\1\&{repeat} \37\&{if} $\\{delta}>\\{unity}$ \1\&{then}\5
+$\|s\K\|s+\O{100000}-50000$;\C{round the last digit}\2\6
+$\\{print\_char}(\.{"0"}+(\|s\mathbin{\&{div}}\\{unity}))$;\5
+$\|s\K10\ast(\|s\mathbin{\&{mod}}\\{unity})$;\5
+$\\{delta}\K\\{delta}\ast10$;\6
+\4\&{until}\5
+$\|s\L\\{delta}$;\2\6
+\&{end};\par
+\fi
+
+\M105. Physical sizes that a \TeX\ user specifies for portions of documents are
+represented internally as scaled points. Thus, if we define an `sp' (scaled
+point) as a unit equal to $2^{-16}$ printer's points, every dimension
+inside of \TeX\ is an integer number of sp. There are exactly
+4,736,286.72 sp per inch.  Users are not allowed to specify dimensions
+larger than $2^{30}-1$ sp, which is a distance of about 18.892 feet (5.7583
+meters); two such quantities can be added without overflow on a 32-bit
+computer.
+
+The present implementation of \TeX\ does not check for overflow when
+dimensions are added or subtracted. This could be done by inserting a
+few dozen tests of the form `\ignorespaces \&{if} $\|x\G\O{10000000000}$ %
+\&{then} \hbox{\\{report\_overflow}}', but the chance of overflow is so remote
+that
+such tests do not seem worthwhile.
+
+\TeX\ needs to do only a few arithmetic operations on scaled quantities,
+other than addition and subtraction, and the following subroutines do most of
+the work. A single computation might use several subroutine calls, and it is
+desirable to avoid producing multiple error messages in case of arithmetic
+overflow; so the routines set the global variable \\{arith\_error} to \\{true}
+instead of reporting errors directly to the user. Another global variable,
+\\{remainder}, holds the remainder after a division.
+
+\Y\P\D \37$\\{remainder}\S\\{tex\_remainder}$\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{arith\_error}: \37\\{boolean};\C{has arithmetic overflow occurred
+recently?}\6
+\4\\{remainder}: \37\\{scaled};\C{amount subtracted to get an exact division}%
+\par
+\fi
+
+\M106. The first arithmetical subroutine we need computes $nx+y$, where \|x
+and~\|y are \\{scaled} and \|n is an integer. We will also use it to
+multiply integers.
+
+\Y\P\D \37$\\{nx\_plus\_y}(\#)\S\\{mult\_and\_add}(\#,\39\O{7777777777})$\par
+\P\D \37$\\{mult\_integers}(\#)\S\\{mult\_and\_add}(\#,\390,\39%
+\O{17777777777})$\par
+\Y\P\4\&{function}\1\  \37$\\{mult\_and\_add}(\|n:\\{integer};\,\35\|x,\39\|y,%
+\39\\{max\_answer}:\\{scaled})$: \37\\{scaled};\2\6
+\&{begin} \37\&{if} $\|n<0$ \1\&{then}\6
+\&{begin} \37$\\{negate}(\|x)$;\5
+$\\{negate}(\|n)$;\6
+\&{end};\2\6
+\&{if} $\|n=0$ \1\&{then}\5
+$\\{mult\_and\_add}\K\|y$\6
+\4\&{else} \&{if} $((\|x\L(\\{max\_answer}-\|y)\mathbin{\&{div}}\|n)\W(-\|x\L(%
+\\{max\_answer}+\|y)\mathbin{\&{div}}\|n))$ \1\&{then}\5
+$\\{mult\_and\_add}\K\|n\ast\|x+\|y$\6
+\4\&{else} \&{begin} \37$\\{arith\_error}\K\\{true}$;\5
+$\\{mult\_and\_add}\K0$;\6
+\&{end};\2\2\6
+\&{end};\par
+\fi
+
+\M107. We also need to divide scaled dimensions by integers.
+
+\Y\P\4\&{function}\1\  \37$\\{x\_over\_n}(\|x:\\{scaled};\,\35\|n:%
+\\{integer})$: \37\\{scaled};\6
+\4\&{var} \37\\{negative}: \37\\{boolean};\C{should \\{remainder} be negated?}%
+\2\6
+\&{begin} \37$\\{negative}\K\\{false}$;\6
+\&{if} $\|n=0$ \1\&{then}\6
+\&{begin} \37$\\{arith\_error}\K\\{true}$;\5
+$\\{x\_over\_n}\K0$;\5
+$\\{remainder}\K\|x$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\|n<0$ \1\&{then}\6
+\&{begin} \37$\\{negate}(\|x)$;\5
+$\\{negate}(\|n)$;\5
+$\\{negative}\K\\{true}$;\6
+\&{end};\2\6
+\&{if} $\|x\G0$ \1\&{then}\6
+\&{begin} \37$\\{x\_over\_n}\K\|x\mathbin{\&{div}}\|n$;\5
+$\\{remainder}\K\|x\mathbin{\&{mod}}\|n$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{x\_over\_n}\K-((-\|x)\mathbin{\&{div}}\|n)$;\5
+$\\{remainder}\K-((-\|x)\mathbin{\&{mod}}\|n)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{negative}$ \1\&{then}\5
+$\\{negate}(\\{remainder})$;\2\6
+\&{end};\par
+\fi
+
+\M108. Then comes the multiplication of a scaled number by a fraction $\|n/%
+\|d$,
+where \|n and \|d are nonnegative integers $\L\hbox{$2^{16}$}$ and \|d is
+positive. It would be too dangerous to multiply by~\|n and then divide
+by~\|d, in separate operations, since overflow might well occur; and it
+would be too inaccurate to divide by \|d and then multiply by \|n. Hence
+this subroutine simulates 1.5-precision arithmetic.
+
+\Y\P\4\&{function}\1\  \37$\\{xn\_over\_d}(\|x:\\{scaled};\,\35\|n,\39\|d:%
+\\{integer})$: \37\\{scaled};\6
+\4\&{var} \37\\{positive}: \37\\{boolean};\C{was $\|x\G0$?}\6
+$\|t,\39\|u,\39\|v$: \37\\{nonnegative\_integer};\C{intermediate quantities}\2\6
+\&{begin} \37\&{if} $\|x\G0$ \1\&{then}\5
+$\\{positive}\K\\{true}$\6
+\4\&{else} \&{begin} \37$\\{negate}(\|x)$;\5
+$\\{positive}\K\\{false}$;\6
+\&{end};\2\6
+$\|t\K(\|x\mathbin{\&{mod}}\O{100000})\ast\|n$;\5
+$\|u\K(\|x\mathbin{\&{div}}\O{100000})\ast\|n+(\|t\mathbin{\&{div}}%
+\O{100000})$;\5
+$\|v\K(\|u\mathbin{\&{mod}}\|d)\ast\O{100000}+(\|t\mathbin{\&{mod}}%
+\O{100000})$;\6
+\&{if} $\|u\mathbin{\&{div}}\|d\G\O{100000}$ \1\&{then}\5
+$\\{arith\_error}\K\\{true}$\6
+\4\&{else} $\|u\K\O{100000}\ast(\|u\mathbin{\&{div}}\|d)+(\|v\mathbin{\&{div}}%
+\|d)$;\2\6
+\&{if} $\\{positive}$ \1\&{then}\6
+\&{begin} \37$\\{xn\_over\_d}\K\|u$;\5
+$\\{remainder}\K\|v\mathbin{\&{mod}}\|d$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{xn\_over\_d}\K-\|u$;\5
+$\\{remainder}\K-(\|v\mathbin{\&{mod}}\|d)$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M109. The next subroutine is used to compute the ``badness'' of glue, when a
+total~\|t is supposed to be made from amounts that sum to~\|s.  According
+to {\sl The \TeX book}, the badness of this situation is $100(t/s)^3$;
+however, badness is simply a heuristic, so we need not squeeze out the
+last drop of accuracy when computing it. All we really want is an
+approximation that has similar properties.
+
+The actual method used to compute the badness is easier to read from the
+program than to describe in words. It produces an integer value that is a
+reasonably close approximation to $100(t/s)^3$, and all implementations
+of \TeX\ should use precisely this method. Any badness of $2^{13}$ or more is
+treated as infinitely bad, and represented by 10000.
+
+It is not difficult to prove that $$\hbox{$\\{badness}(\|t+1,\|s)\G\\{badness}(%
+\|t,\|s)\G\\{badness}(\|t,\|s+1)$}.$$ The badness function defined here is
+capable of
+computing at most 1095 distinct values, but that is plenty.
+
+\Y\P\D \37$\\{inf\_bad}=10000$\C{infinitely bad value}\par
+\Y\P\4\&{function}\1\  \37$\\{badness}(\|t,\39\|s:\\{scaled})$: \37%
+\\{halfword};\C{compute badness, given $\|t\G0$}\6
+\4\&{var} \37\|r: \37\\{integer};\C{approximation to $\alpha t/s$, where $%
+\alpha^3\approx   100\cdot2^{18}$}\2\6
+\&{begin} \37\&{if} $\|t=0$ \1\&{then}\5
+$\\{badness}\K0$\6
+\4\&{else} \&{if} $\|s\L0$ \1\&{then}\5
+$\\{badness}\K\\{inf\_bad}$\6
+\4\&{else} \&{begin} \37\&{if} $\|t\L7230584$ \1\&{then}\5
+$\|r\K(\|t\ast297)\mathbin{\&{div}}\|s$\C{$297^3=99.94\times2^{18}$}\6
+\4\&{else} \&{if} $\|s\G1663497$ \1\&{then}\5
+$\|r\K\|t\mathbin{\&{div}}(\|s\mathbin{\&{div}}297)$\6
+\4\&{else} $\|r\K\|t$;\2\2\6
+\&{if} $\|r>1290$ \1\&{then}\5
+$\\{badness}\K\\{inf\_bad}$\C{$1290^3<2^{31}<1291^3$}\6
+\4\&{else} $\\{badness}\K(\|r\ast\|r\ast\|r+\O{400000})\mathbin{\&{div}}%
+\O{1000000}$;\2\6
+\&{end};\C{that was $r^3/2^{18}$, rounded to the nearest integer}\2\2\6
+\&{end};\par
+\fi
+
+\M110. When \TeX\ ``packages'' a list into a box, it needs to calculate the
+proportionality ratio by which the glue inside the box should stretch
+or shrink. This calculation does not affect \TeX's decision making,
+so the precise details of rounding, etc., in the glue calculation are not
+of critical importance for the consistency of results on different computers.
+
+We shall use the type \\{glue\_ratio} for such proportionality ratios.
+A glue ratio should take the same amount of memory as an
+\\{integer} (usually 32 bits) if it is to blend smoothly with \TeX's
+other data structures. Thus \\{glue\_ratio} should be equivalent to
+\\{short\_real} in some implementations of \PASCAL. Alternatively,
+it is possible to deal with glue ratios using nothing but fixed-point
+arithmetic; see {\sl TUGboat \bf3},1 (March 1982), 10--27. (But the
+routines cited there must be modified to allow negative glue ratios.)
+
+\Y\P\D \37$\\{set\_glue\_ratio\_zero}(\#)\S\#\K0.0$\C{store the representation
+of zero ratio}\par
+\P\D \37$\\{set\_glue\_ratio\_one}(\#)\S\#\K1.0$\C{store the representation of
+unit ratio}\par
+\P\D \37$\\{float}(\#)\S\#$\C{convert from \\{glue\_ratio} to type \\{real}}\par
+\P\D \37$\\{unfloat}(\#)\S\#$\C{convert from \\{real} to type \\{glue\_ratio}}%
+\par
+\P\D \37$\\{float\_constant}(\#)\S\#.0$\C{convert \\{integer} constant to %
+\\{real}}\par
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\par
+\fi
+
+\N111.  \[8] Packed data.
+In order to make efficient use of storage space, \TeX\ bases its major data
+structures on a \\{memory\_word}, which contains either a (signed) integer,
+possibly scaled, or a (signed) \\{glue\_ratio}, or a small number of
+fields that are one half or one quarter of the size used for storing
+integers.
+
+If \|x is a variable of type \\{memory\_word}, it contains up to four
+fields that can be referred to as follows:
+$$\vbox{\halign{\hfil#&#\hfil&#\hfil\cr
+\|x&.\\{int}&(an \\{integer})\cr
+\|x&.\\{sc}\qquad&(a \\{scaled} integer)\cr
+\|x&.\\{gr}&(a \\{glue\_ratio})\cr
+\|x.\\{hh}.\\{lh}, \|x.\\{hh}&.\\{rh}&(two halfword fields)\cr
+\|x.\\{hh}.\\{b0}, \|x.\\{hh}.\\{b1}, \|x.\\{hh}&.\\{rh}&(two quarterword
+fields, one halfword
+field)\cr
+\|x.\\{qqqq}.\\{b0}, \|x.\\{qqqq}.\\{b1}, \|x.\\{qqqq}&.\\{b2}, \|x.\\{qqqq}.%
+\\{b3}\hskip-100pt
+&\qquad\qquad\qquad(four quarterword fields)\cr}}$$
+This is somewhat cumbersome to write, and not very readable either, but
+macros will be used to make the notation shorter and more transparent.
+The \PASCAL\ code below gives a formal definition of \\{memory\_word} and
+its subsidiary types, using packed variant records. \TeX\ makes no
+assumptions about the relative positions of the fields within a word.
+
+Since we are assuming 32-bit integers, a halfword must contain at least
+16 bits, and a quarterword must contain at least 8 bits.
+But it doesn't hurt to have more bits; for example, with enough 36-bit
+words you might be able to have \\{mem\_max} as large as 262142, which is
+eight times as much memory as anybody had during the first four years of
+\TeX's existence.
+
+N.B.: Valuable memory space will be dreadfully wasted unless \TeX\ is compiled
+by a \PASCAL\ that packs all of the \\{memory\_word} variants into
+the space of a single integer. This means, for example, that \\{glue\_ratio}
+words should be \\{short\_real} instead of \\{real} on some computers. Some
+\PASCAL\ compilers will pack an integer whose subrange is `$0\to255$' into
+an eight-bit field, but others insist on allocating space for an additional
+sign bit; on such systems you can get 256 values into a quarterword only
+if the subrange is `$-128\to127$'.
+
+The present implementation tries to accommodate as many variations as possible,
+so it makes few assumptions. If integers having the subrange
+`$\\{min\_quarterword}\to\\{max\_quarterword}$' can be packed into a
+quarterword,
+and if integers having the subrange `$\\{min\_halfword}\to\\{max\_halfword}$'
+can be packed into a halfword, everything should work satisfactorily.
+
+It is usually most efficient to have $\\{min\_quarterword}=\\{min%
+\_halfword}=0$,
+so one should try to achieve this unless it causes a severe problem.
+The values defined here are recommended for most 32-bit computers.
+
+\Y\P\D \37$\\{min\_quarterword}=0$\C{smallest allowable value in a %
+\\{quarterword}}\par
+\P\D \37$\\{max\_quarterword}=255$\C{largest allowable value in a %
+\\{quarterword}}\par
+\P\D \37$\\{min\_halfword}\S-\H{FFFFFFF}$\C{smallest allowable value in a %
+\\{halfword}}\par
+\P\D \37$\\{max\_halfword}\S\H{FFFFFFF}$\C{largest allowable value in a %
+\\{halfword}}\par
+\fi
+
+\M112. Here are the inequalities that the quarterword and halfword values
+must satisfy (or rather, the inequalities that they mustn't satisfy):
+
+\Y\P$\4\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6
+\&{init} \37\&{if} $(\\{mem\_min}\I\\{mem\_bot})\V(\\{mem\_max}\I\\{mem\_top})$
+\1\&{then}\5
+$\\{bad}\K10$;\ \2\6
+\&{tini}\6
+\&{if} $(\\{mem\_min}>\\{mem\_bot})\V(\\{mem\_max}<\\{mem\_top})$ \1\&{then}\5
+$\\{bad}\K10$;\2\6
+\&{if} $(\\{min\_quarterword}>0)\V(\\{max\_quarterword}<127)$ \1\&{then}\5
+$\\{bad}\K11$;\2\6
+\&{if} $(\\{min\_halfword}>0)\V(\\{max\_halfword}<32767)$ \1\&{then}\5
+$\\{bad}\K12$;\2\6
+\&{if} $(\\{min\_quarterword}<\\{min\_halfword})\V\30(\\{max\_quarterword}>%
+\\{max\_halfword})$ \1\&{then}\5
+$\\{bad}\K13$;\2\6
+\&{if} $(\\{mem\_bot}-\\{sup\_main\_memory}<\\{min\_halfword})\V\30(\\{mem%
+\_top}+\\{sup\_main\_memory}\G\\{max\_halfword})\V\30(\\{hi}(0)\I0)$ \1\&{then}%
+\5
+$\\{bad}\K14$;\2\6
+\&{if} $(\\{max\_font\_max}<\\{min\_halfword})\V(\\{max\_font\_max}>\\{max%
+\_halfword})$ \1\&{then}\5
+$\\{bad}\K15$;\2\6
+\&{if} $\\{font\_max}>\\{font\_base}+\\{max\_font\_max}$ \1\&{then}\5
+$\\{bad}\K16$;\2\6
+\&{if} $(\\{save\_size}>\\{max\_halfword})\V(\\{max\_strings}>\\{max%
+\_halfword})$ \1\&{then}\5
+$\\{bad}\K17$;\2\6
+\&{if} $\\{buf\_size}>\\{max\_halfword}$ \1\&{then}\5
+$\\{bad}\K18$;\2\6
+\&{if} $\\{max\_quarterword}-\\{min\_quarterword}<255$ \1\&{then}\5
+$\\{bad}\K19$;\2\par
+\fi
+
+\M113. The operation of adding or subtracting \\{min\_quarterword} occurs quite
+frequently in \TeX, so it is convenient to abbreviate this operation
+by using the macros \\{qi} and \\{qo} for input and output to and from
+quarterword format.
+
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `$\|x+0$' and `$\|x-0$', if these
+macros are simplified in the obvious way when $\\{min\_quarterword}=0$.
+So they have been simplified here in the obvious way.
+
+The \.{WEB} source for \TeX\ defines $\\{hi}(\#)\S\#+\\{min\_halfword}$ which
+can be
+simplified when $\\{min\_halfword}=0$.  The Web2C implemetation of \TeX\ can
+use
+$\\{hi}(\#)\S\#$ together with $\\{min\_halfword}<0$ as long as \\{max%
+\_halfword} is
+sufficiently large and this is required for p\TeX.
+
+\Y\P\D \37$\\{qi}(\#)\S\#$\C{to put an \\{eight\_bits} item into a quarterword}%
+\par
+\P\D \37$\\{qo}(\#)\S\#$\C{to take an \\{eight\_bits} item from a quarterword}%
+\par
+\P\D \37$\\{hi}(\#)\S\#$\C{to put a sixteen-bit item into a halfword}\par
+\P\D \37$\\{ho}(\#)\S\#$\C{to take a sixteen-bit item from a halfword}\par
+\P\D \37$\\{KANJI}(\#)\S\#$\C{pTeX: to output a KANJI code}\par
+\P\D \37$\\{tokanji}(\#)\S\#$\C{pTeX: to take a KANJI code from a halfword}\par
+\P\D \37$\\{tonum}(\#)\S\#$\C{pTeX: to put a KANJI code into a halfword}\par
+\fi
+
+\M114. The reader should study the following definitions closely:
+
+\Y\P\D \37$\\{sc}\S\\{int}$\C{\\{scaled} data is equivalent to \\{integer}}\par
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{quarterword}=\\{min\_quarterword}\to\\{max\_quarterword}$;\5
+$\\{halfword}=\\{min\_halfword}\to\\{max\_halfword}$;\5
+$\\{two\_choices}=1\to2$;\C{used when there are two variants in a record}\6
+$\\{four\_choices}=1\to4$;\C{used when there are four variants in a record}\6
+$\={\#include\ "texmfmem.h";}\\{word\_file}=$\1\5
+\&{file} \1\&{of}\5
+\\{memory\_word};\2\2\par
+\fi
+
+\M115. When debugging, we may want to print a \\{memory\_word} without knowing
+what type it is; so we print it in all modes.
+
+\Y\P\&{debug} \37\&{procedure}\1\  \37$\\{print\_word}(\|w:\\{memory\_word})$;%
+\C{prints \|w in all ways}\2\6
+\&{begin} \37$\\{print\_int}(\|w.\\{int})$;\5
+$\\{print\_char}(\.{"\ "})$;\6
+$\\{print\_scaled}(\|w.\\{sc})$;\5
+$\\{print\_char}(\.{"\ "})$;\6
+$\\{print\_scaled}(\\{round}(\\{unity}\ast\\{float}(\|w.\\{gr})))$;\5
+\\{print\_ln};\6
+$\\{print\_int}(\|w.\\{hh}.\\{lh})$;\5
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_int}(\|w.\\{hh}.\\{b0})$;\5
+$\\{print\_char}(\.{":"})$;\5
+$\\{print\_int}(\|w.\\{hh}.\\{b1})$;\5
+$\\{print\_char}(\.{";"})$;\5
+$\\{print\_int}(\|w.\\{hh}.\\{rh})$;\5
+$\\{print\_char}(\.{"\ "})$;\6
+$\\{print\_int}(\|w.\\{qqqq}.\\{b0})$;\5
+$\\{print\_char}(\.{":"})$;\5
+$\\{print\_int}(\|w.\\{qqqq}.\\{b1})$;\5
+$\\{print\_char}(\.{":"})$;\5
+$\\{print\_int}(\|w.\\{qqqq}.\\{b2})$;\5
+$\\{print\_char}(\.{":"})$;\5
+$\\{print\_int}(\|w.\\{qqqq}.\\{b3})$;\6
+\&{end};\6
+\&{gubed}\par
+\fi
+
+\N116.  \[9] Dynamic memory allocation.
+The \TeX\ system does nearly all of its own memory allocation, so that it
+can readily be transported into environments that do not have automatic
+facilities for strings, garbage collection, etc., and so that it can be in
+control of what error messages the user receives. The dynamic storage
+requirements of \TeX\ are handled by providing a large array \\{mem} in
+which consecutive blocks of words are used as nodes by the \TeX\ routines.
+
+Pointer variables are indices into this array, or into another array
+called \\{eqtb} that will be explained later. A pointer variable might
+also be a special flag that lies outside the bounds of \\{mem}, so we
+allow pointers to assume any \\{halfword} value. The minimum halfword
+value represents a null pointer. \TeX\ does not assume that $\\{mem}[\\{null}]$
+exists.
+
+\Y\P\D \37$\\{pointer}\S\\{halfword}$\C{a flag or a location in \\{mem} or %
+\\{eqtb}}\par
+\P\D \37$\\{null}\S\\{min\_halfword}$\C{the null pointer}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{temp\_ptr}: \37\\{pointer};\C{a pointer variable for occasional emergency
+use}\par
+\fi
+
+\M117. The \\{mem} array is divided into two regions that are allocated
+separately,
+but the dividing line between these two regions is not fixed; they grow
+together until finding their ``natural'' size in a particular job.
+Locations less than or equal to \\{lo\_mem\_max} are used for storing
+variable-length records consisting of two or more words each. This region
+is maintained using an algorithm similar to the one described in exercise
+2.5--19 of {\sl The Art of Computer Programming}. However, no size field
+appears in the allocated nodes; the program is responsible for knowing the
+relevant size when a node is freed. Locations greater than or equal to
+\\{hi\_mem\_min} are used for storing one-word records; a conventional
+\.{AVAIL} stack is used for allocation in this region.
+
+Locations of \\{mem} between \\{mem\_bot} and \\{mem\_top} may be dumped as
+part
+of preloaded format files, by the \.{INITEX} preprocessor.
+Production versions of \TeX\ may extend the memory at both ends in order to
+provide more space; locations between \\{mem\_min} and \\{mem\_bot} are always
+used for variable-size nodes, and locations between \\{mem\_top} and \\{mem%
+\_max}
+are always used for single-word nodes.
+
+The key pointers that govern \\{mem} allocation have a prescribed order:
+$$\advance\thickmuskip-2mu
+\hbox{$\\{null}\L\\{mem\_min}\L\\{mem\_bot}<\\{lo\_mem\_max}<\\{hi\_mem\_min}<%
+\\{mem\_top}\L\\{mem\_end}\L\\{mem\_max}$.}$$
+
+Empirical tests show that the present implementation of \TeX\ tends to
+spend about 9\pct! of its running time allocating nodes, and about 6\pct!
+deallocating them after their use.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{yzmem}: \37$\^\\{memory\_word}$;\C{the big dynamic storage area}\6
+\4\\{zmem}: \37$\^\\{memory\_word}$;\C{the big dynamic storage area}\6
+\4\\{lo\_mem\_max}: \37\\{pointer};\C{the largest location of variable-size
+memory in use}\6
+\4\\{hi\_mem\_min}: \37\\{pointer};\C{the smallest location of one-word memory
+in use}\par
+\fi
+
+\M118. In order to study the memory requirements of particular applications, it
+is possible to prepare a version of \TeX\ that keeps track of current and
+maximum memory usage. When code between the delimiters  \&{stat}  $\ldots$
+  \&{tats}  is not ``commented out,'' \TeX\ will run a bit slower but it will
+report these statistics when \\{tracing\_stats} is sufficiently large.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4$\\{var\_used},\39\\{dyn\_used}$: \37\\{integer};\C{how much memory is in
+use}\par
+\fi
+
+\M119. Let's consider the one-word memory region first, since it's the
+simplest. The pointer variable \\{mem\_end} holds the highest-numbered location
+of \\{mem} that has ever been used. The free locations of \\{mem} that
+occur between \\{hi\_mem\_min} and \\{mem\_end}, inclusive, are of type
+\\{two\_halves}, and we write $\\{info}(\|p)$ and $\\{link}(\|p)$ for the %
+\\{lh}
+and \\{rh} fields of $\\{mem}[\|p]$ when it is of this type. The single-word
+free locations form a linked list
+$$\\{avail},\;\hbox{$\\{link}(\\{avail})$},\;\hbox{$\\{link}(\\{link}(%
+\\{avail}))$},\;\ldots$$
+terminated by \\{null}.
+
+\Y\P\D \37$\\{link}(\#)\S\\{mem}[\#].\\{hh}.\\{rh}$\C{the \\{link} field of a
+memory word}\par
+\P\D \37$\\{info}(\#)\S\\{mem}[\#].\\{hh}.\\{lh}$\C{the \\{info} field of a
+memory word}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{avail}: \37\\{pointer};\C{head of the list of available one-word nodes}\6
+\4\\{mem\_end}: \37\\{pointer};\C{the last one-word node used in \\{mem}}\par
+\fi
+
+\M120. If memory is exhausted, it might mean that the user has forgotten
+a right brace. We will define some procedures later that try to help
+pinpoint the trouble.
+
+\Y\P\X298:Declare the procedure called \\{show\_token\_list}\X\6
+\X312:Declare the procedure called \\{runaway}\X\par
+\fi
+
+\M121. The function \\{get\_avail} returns a pointer to a new one-word node
+whose
+\\{link} field is null. However, \TeX\ will halt if there is no more room left.
+
+If the available-space list is empty, i.e., if $\\{avail}=\\{null}$,
+we try first to increase \\{mem\_end}. If that cannot be done, i.e., if
+$\\{mem\_end}=\\{mem\_max}$, we try to decrease \\{hi\_mem\_min}. If that
+cannot be
+done, i.e., if $\\{hi\_mem\_min}=\\{lo\_mem\_max}+1$, we have to quit.
+
+\Y\P\4\&{function}\1\  \37\\{get\_avail}: \37\\{pointer};\C{single-word node
+allocation}\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node being got}\2\6
+\&{begin} \37$\|p\K\\{avail}$;\C{get top location in the \\{avail} stack}\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\5
+$\\{avail}\K\\{link}(\\{avail})$\C{and pop it off}\6
+\4\&{else} \&{if} $\\{mem\_end}<\\{mem\_max}$ \1\&{then}\C{or go into virgin
+territory}\6
+\&{begin} \37$\\{incr}(\\{mem\_end})$;\5
+$\|p\K\\{mem\_end}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{decr}(\\{hi\_mem\_min})$;\5
+$\|p\K\\{hi\_mem\_min}$;\6
+\&{if} $\\{hi\_mem\_min}\L\\{lo\_mem\_max}$ \1\&{then}\6
+\&{begin} \37\\{runaway};\C{if memory is exhausted, display possible runaway
+text}\6
+$\\{overflow}(\.{"main\ memory\ size"},\39\\{mem\_max}+1-\\{mem\_min})$;%
+\C{quit; all one-word nodes are busy}\6
+\&{end};\2\6
+\&{end};\2\2\6
+$\\{link}(\|p)\K\\{null}$;\C{provide an oft-desired initialization of the new
+node}\6
+\&{stat} \37$\\{incr}(\\{dyn\_used})$;\ \&{tats}\C{maintain statistics}\6
+$\\{get\_avail}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M122. Conversely, a one-word node is recycled by calling \\{free\_avail}.
+This routine is part of \TeX's ``inner loop,'' so we want it to be fast.
+
+\Y\P\D \37$\\{free\_avail}(\#)\S$\C{single-word node liberation}\6
+\&{begin} \37$\\{link}(\#)\K\\{avail}$;\5
+$\\{avail}\K\#$;\6
+\&{stat} \37$\\{decr}(\\{dyn\_used})$;\ \&{tats}\6
+\&{end}\par
+\fi
+
+\M123. There's also a \\{fast\_get\_avail} routine, which saves the
+procedure-call
+overhead at the expense of extra programming. This routine is used in
+the places that would otherwise account for the most calls of \\{get\_avail}.
+
+\Y\P\D \37$\\{fast\_get\_avail}(\#)\S\hbox{}$\6
+\&{begin} \37$\#\K\\{avail}$;\C{avoid \\{get\_avail} if possible, to save time}%
+\6
+\&{if} $\#=\\{null}$ \1\&{then}\5
+$\#\K\\{get\_avail}$\6
+\4\&{else} \&{begin} \37$\\{avail}\K\\{link}(\#)$;\5
+$\\{link}(\#)\K\\{null}$;\6
+\&{stat} \37$\\{incr}(\\{dyn\_used})$;\ \&{tats}\6
+\&{end};\2\6
+\&{end}\par
+\fi
+
+\M124. The procedure $\\{flush\_list}(\|p)$ frees an entire linked list of
+one-word nodes that starts at position \|p.
+
+\Y\P\4\&{procedure}\1\  \37$\\{flush\_list}(\|p:\\{pointer})$;\C{makes list of
+single-word nodes   available}\6
+\4\&{var} \37$\|q,\39\|r$: \37\\{pointer};\C{list traversers}\2\6
+\&{begin} \37\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\|r\K\|p$;\6
+\1\&{repeat} \37$\|q\K\|r$;\5
+$\|r\K\\{link}(\|r)$;\6
+\&{stat} \37$\\{decr}(\\{dyn\_used})$;\ \&{tats}\6
+\4\&{until}\5
+$\|r=\\{null}$;\C{now \|q is the last node on the list}\2\6
+$\\{link}(\|q)\K\\{avail}$;\5
+$\\{avail}\K\|p$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M125. The available-space list that keeps track of the variable-size portion
+of \\{mem} is a nonempty, doubly-linked circular list of empty nodes,
+pointed to by the roving pointer \\{rover}.
+
+Each empty node has size 2 or more; the first word contains the special
+value \\{max\_halfword} in its \\{link} field and the size in its \\{info}
+field;
+the second word contains the two pointers for double linking.
+
+Each nonempty node also has size 2 or more. Its first word is of type
+\\{two\_halves}\kern-1pt, and its \\{link} field is never equal to \\{max%
+\_halfword}.
+Otherwise there is complete flexibility with respect to the contents
+of its other fields and its other words.
+
+(We require $\\{mem\_max}<\\{max\_halfword}$ because terrible things can happen
+when \\{max\_halfword} appears in the \\{link} field of a nonempty node.)
+
+\Y\P\D \37$\\{empty\_flag}\S\\{max\_halfword}$\C{the \\{link} of an empty
+variable-size node}\par
+\P\D \37$\\{is\_empty}(\#)\S(\\{link}(\#)=\\{empty\_flag})$\C{tests for empty
+node}\par
+\P\D \37$\\{node\_size}\S\\{info}$\C{the size field in empty variable-size
+nodes}\par
+\P\D \37$\\{llink}(\#)\S\\{info}(\#+1)$\C{left link in doubly-linked list of
+empty nodes}\par
+\P\D \37$\\{rlink}(\#)\S\\{link}(\#+1)$\C{right link in doubly-linked list of
+empty nodes}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{rover}: \37\\{pointer};\C{points to some node in the list of empties}\par
+\fi
+
+\M126. A call to \\{get\_node} with argument \|s returns a pointer to a new
+node
+of size~\|s, which must be 2~or more. The \\{link} field of the first word
+of this new node is set to null. An overflow stop occurs if no suitable
+space exists.
+
+If \\{get\_node} is called with $s=2^{30}$, it simply merges adjacent free
+areas and returns the value \\{max\_halfword}.
+
+\Y\P\4\&{function}\1\  \37$\\{get\_node}(\|s:\\{integer})$: \37\\{pointer};%
+\C{variable-size node allocation}\6
+\4\&{label} \37$\\{found},\39\\{exit},\39\\{restart}$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the node currently under inspection}\6
+\|q: \37\\{pointer};\C{the node physically after node \|p}\6
+\|r: \37\\{integer};\C{the newly allocated node, or a candidate for this honor}%
+\6
+\|t: \37\\{integer};\C{temporary register}\2\6
+\&{begin} \37\\{restart}: \37$\|p\K\\{rover}$;\C{start at some free node in the
+ring}\6
+\1\&{repeat} \37\X128:Try to allocate within node \|p and its physical
+successors, and \&{goto} \\{found} if allocation was possible\X;\6
+$\|p\K\\{rlink}(\|p)$;\C{move to the next node in the ring}\6
+\4\&{until}\5
+$\|p=\\{rover}$;\C{repeat until the whole list has been traversed}\2\6
+\&{if} $\|s=\O{10000000000}$ \1\&{then}\6
+\&{begin} \37$\\{get\_node}\K\\{max\_halfword}$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $\\{lo\_mem\_max}+2<\\{hi\_mem\_min}$ \1\&{then}\6
+\&{if} $\\{lo\_mem\_max}+2\L\\{mem\_bot}+\\{max\_halfword}$ \1\&{then}\5
+\X127:Grow more variable-size memory and \&{goto} \\{restart}\X;\2\2\6
+$\\{overflow}(\.{"main\ memory\ size"},\39\\{mem\_max}+1-\\{mem\_min})$;%
+\C{sorry, nothing satisfactory is left}\6
+\4\\{found}: \37$\\{link}(\|r)\K\\{null}$;\C{this node is now nonempty}\6
+\&{stat} \37$\\{var\_used}\K\\{var\_used}+\|s$;\C{maintain usage statistics}\6
+\&{tats}\6
+$\\{get\_node}\K\|r$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M127. The lower part of \\{mem} grows by 1000 words at a time, unless
+we are very close to going under. When it grows, we simply link
+a new node into the available-space list. This method of controlled
+growth helps to keep the \\{mem} usage consecutive when \TeX\ is
+implemented on ``virtual memory'' systems.
+
+\Y\P$\4\X127:Grow more variable-size memory and \&{goto} \\{restart}\X\S$\6
+\&{begin} \37\&{if} $\\{hi\_mem\_min}-\\{lo\_mem\_max}\G1998$ \1\&{then}\5
+$\|t\K\\{lo\_mem\_max}+1000$\6
+\4\&{else} $\|t\K\\{lo\_mem\_max}+1+(\\{hi\_mem\_min}-\\{lo\_mem\_max})%
+\mathbin{\&{div}}2$;\C{$\\{lo\_mem\_max}+2\L\|t<\\{hi\_mem\_min}$}\2\6
+$\|p\K\\{llink}(\\{rover})$;\5
+$\|q\K\\{lo\_mem\_max}$;\5
+$\\{rlink}(\|p)\K\|q$;\5
+$\\{llink}(\\{rover})\K\|q$;\6
+\&{if} $\|t>\\{mem\_bot}+\\{max\_halfword}$ \1\&{then}\5
+$\|t\K\\{mem\_bot}+\\{max\_halfword}$;\2\6
+$\\{rlink}(\|q)\K\\{rover}$;\5
+$\\{llink}(\|q)\K\|p$;\5
+$\\{link}(\|q)\K\\{empty\_flag}$;\5
+$\\{node\_size}(\|q)\K\|t-\\{lo\_mem\_max}$;\6
+$\\{lo\_mem\_max}\K\|t$;\5
+$\\{link}(\\{lo\_mem\_max})\K\\{null}$;\5
+$\\{info}(\\{lo\_mem\_max})\K\\{null}$;\5
+$\\{rover}\K\|q$;\5
+\&{goto} \37\\{restart};\6
+\&{end}\par
+\U126.\fi
+
+\M128. Empirical tests show that the routine in this section performs a
+node-merging operation about 0.75 times per allocation, on the average,
+after which it finds that $\|r>\|p+1$ about 95\pct! of the time.
+
+\Y\P$\4\X128:Try to allocate within node \|p and its physical successors, and %
+\&{goto} \\{found} if allocation was possible\X\S$\6
+$\|q\K\|p+\\{node\_size}(\|p)$;\C{find the physical successor}\6
+\&{while} $\\{is\_empty}(\|q)$ \1\&{do}\C{merge node \|p with node \|q}\6
+\&{begin} \37$\|t\K\\{rlink}(\|q)$;\6
+\&{if} $\|q=\\{rover}$ \1\&{then}\5
+$\\{rover}\K\|t$;\2\6
+$\\{llink}(\|t)\K\\{llink}(\|q)$;\5
+$\\{rlink}(\\{llink}(\|q))\K\|t$;\6
+$\|q\K\|q+\\{node\_size}(\|q)$;\6
+\&{end};\2\6
+$\|r\K\|q-\|s$;\6
+\&{if} $\|r>\\{intcast}(\|p+1)$ \1\&{then}\5
+\X129:Allocate from the top of node \|p and \&{goto} \\{found}\X;\2\6
+\&{if} $\|r=\|p$ \1\&{then}\6
+\&{if} $\\{rlink}(\|p)\I\|p$ \1\&{then}\5
+\X130:Allocate entire node \|p and \&{goto} \\{found}\X;\2\2\6
+$\\{node\_size}(\|p)\K\|q-\|p$\C{reset the size in case it grew}\par
+\U126.\fi
+
+\M129. \P$\X129:Allocate from the top of node \|p and \&{goto} \\{found}\X\S$\6
+\&{begin} \37$\\{node\_size}(\|p)\K\|r-\|p$;\C{store the remaining size}\6
+$\\{rover}\K\|p$;\C{start searching here next time}\6
+\&{goto} \37\\{found};\6
+\&{end}\par
+\U128.\fi
+
+\M130. Here we delete node \|p from the ring, and let \\{rover} rove around.
+
+\Y\P$\4\X130:Allocate entire node \|p and \&{goto} \\{found}\X\S$\6
+\&{begin} \37$\\{rover}\K\\{rlink}(\|p)$;\5
+$\|t\K\\{llink}(\|p)$;\5
+$\\{llink}(\\{rover})\K\|t$;\5
+$\\{rlink}(\|t)\K\\{rover}$;\5
+\&{goto} \37\\{found};\6
+\&{end}\par
+\U128.\fi
+
+\M131. Conversely, when some variable-size node \|p of size \|s is no longer
+needed,
+the operation $\\{free\_node}(\|p,\|s)$ will make its words available, by
+inserting
+\|p as a new empty node just before where \\{rover} now points.
+
+\Y\P\4\&{procedure}\1\  \37$\\{free\_node}(\|p:\\{pointer};\,\35\|s:%
+\\{halfword})$;\C{variable-size node   liberation}\6
+\4\&{var} \37\|q: \37\\{pointer};\C{$\\{llink}(\\{rover})$}\2\6
+\&{begin} \37$\\{node\_size}(\|p)\K\|s$;\5
+$\\{link}(\|p)\K\\{empty\_flag}$;\5
+$\|q\K\\{llink}(\\{rover})$;\5
+$\\{llink}(\|p)\K\|q$;\5
+$\\{rlink}(\|p)\K\\{rover}$;\C{set both links}\6
+$\\{llink}(\\{rover})\K\|p$;\5
+$\\{rlink}(\|q)\K\|p$;\C{insert \|p into the ring}\6
+\&{stat} \37$\\{var\_used}\K\\{var\_used}-\|s$;\ \&{tats}\C{maintain
+statistics}\6
+\&{end};\par
+\fi
+
+\M132. Just before \.{INITEX} writes out the memory, it sorts the doubly linked
+available space list. The list is probably very short at such times, so a
+simple insertion sort is used. The smallest available location will be
+pointed to by \\{rover}, the next-smallest by $\\{rlink}(\\{rover})$, etc.
+
+\Y\P\&{init} \37\&{procedure}\1\  \37\\{sort\_avail};\C{sorts the available
+variable-size nodes   by location}\6
+\4\&{var} \37$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{indices into \\{mem}}\6
+\\{old\_rover}: \37\\{pointer};\C{initial \\{rover} setting}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\O{10000000000})$;\C{merge adjacent free
+areas}\6
+$\|p\K\\{rlink}(\\{rover})$;\5
+$\\{rlink}(\\{rover})\K\\{max\_halfword}$;\5
+$\\{old\_rover}\K\\{rover}$;\6
+\&{while} $\|p\I\\{old\_rover}$ \1\&{do}\5
+\X133:Sort \(p)\|p into the list starting at \\{rover} and advance \|p to $%
+\\{rlink}(\|p)$\X;\2\6
+$\|p\K\\{rover}$;\6
+\&{while} $\\{rlink}(\|p)\I\\{max\_halfword}$ \1\&{do}\6
+\&{begin} \37$\\{llink}(\\{rlink}(\|p))\K\|p$;\5
+$\|p\K\\{rlink}(\|p)$;\6
+\&{end};\2\6
+$\\{rlink}(\|p)\K\\{rover}$;\5
+$\\{llink}(\\{rover})\K\|p$;\6
+\&{end};\6
+\&{tini}\par
+\fi
+
+\M133. The following  \&{while}  loop is guaranteed to
+terminate, since the list that starts at
+\\{rover} ends with \\{max\_halfword} during the sorting procedure.
+
+\Y\P$\4\X133:Sort \(p)\|p into the list starting at \\{rover} and advance \|p
+to $\\{rlink}(\|p)$\X\S$\6
+\&{if} $\|p<\\{rover}$ \1\&{then}\6
+\&{begin} \37$\|q\K\|p$;\5
+$\|p\K\\{rlink}(\|q)$;\5
+$\\{rlink}(\|q)\K\\{rover}$;\5
+$\\{rover}\K\|q$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|q\K\\{rover}$;\6
+\&{while} $\\{rlink}(\|q)<\|p$ \1\&{do}\5
+$\|q\K\\{rlink}(\|q)$;\2\6
+$\|r\K\\{rlink}(\|p)$;\5
+$\\{rlink}(\|p)\K\\{rlink}(\|q)$;\5
+$\\{rlink}(\|q)\K\|p$;\5
+$\|p\K\|r$;\6
+\&{end}\2\par
+\U132.\fi
+
+\N134.  \[10] Data structures for boxes and their friends.
+From the computer's standpoint, \TeX's chief mission is to create
+horizontal and vertical lists. We shall now investigate how the elements
+of these lists are represented internally as nodes in the dynamic memory.
+
+A horizontal or vertical list is linked together by \\{link} fields in
+the first word of each node. Individual nodes represent boxes, glue,
+penalties, or special things like discretionary hyphens; because of this
+variety, some nodes are longer than others, and we must distinguish different
+kinds of nodes. We do this by putting a `\\{type}' field in the first word,
+together with the link and an optional `\\{subtype}'.
+
+\Y\P\D \37$\\{type}(\#)\S\\{mem}[\#].\\{hh}.\\{b0}$\C{identifies what kind of
+node this is}\par
+\P\D \37$\\{subtype}(\#)\S\\{mem}[\#].\\{hh}.\\{b1}$\C{secondary identification
+in some cases}\par
+\fi
+
+\M135. A \\{char\_node}, which represents a single character, is the most
+important
+kind of node because it accounts for the vast majority of all boxes.
+Special precautions are therefore taken to ensure that a \\{char\_node} does
+not take up much memory space. Every such node is one word long, and in fact
+it is identifiable by this property, since other kinds of nodes have at least
+two words, and they appear in \\{mem} locations less than \\{hi\_mem\_min}.
+This makes it possible to omit the \\{type} field in a \\{char\_node}, leaving
+us room for two bytes that identify a \\{font} and a \\{character} within
+that font.
+
+Note that the format of a \\{char\_node} allows for up to 256 different
+fonts and up to 256 characters per font; but most implementations will
+probably limit the total number of fonts to fewer than 75 per job,
+and most fonts will stick to characters whose codes are
+less than 128 (since higher codes
+are more difficult to access on most keyboards).
+
+Extensions of \TeX\ intended for oriental languages will need even more
+than $256\times256$ possible characters, when we consider different sizes
+and styles of type.  It is suggested that Chinese and Japanese fonts be
+handled by representing such characters in two consecutive \\{char\_node}
+entries: The first of these has $\\{font}=\\{font\_base}$, and its \\{link}
+points
+to the second;
+the second identifies the font and the character dimensions.
+The saving feature about oriental characters is that most of them have
+the same box dimensions. The \\{character} field of the first \\{char\_node}
+is a ``\\{charext}'' that distinguishes between graphic symbols whose
+dimensions are identical for typesetting purposes. (See the \MF\ manual.)
+Such an extension of \TeX\ would not be difficult; further details are
+left to the reader.
+
+In order to make sure that the \\{character} code fits in a quarterword,
+\TeX\ adds the quantity \\{min\_quarterword} to the actual code.
+
+Character nodes appear only in horizontal lists, never in vertical lists.
+
+\Y\P\D \37$\\{is\_char\_node}(\#)\S(\#\G\\{hi\_mem\_min})$\C{does the argument
+point to a \\{char\_node}?}\par
+\P\D \37$\\{font}\S\\{type}$\C{the font code in a \\{char\_node}}\par
+\P\D \37$\\{character}\S\\{subtype}$\C{the character code in a \\{char\_node}}%
+\par
+\fi
+
+\M136. An \\{hlist\_node} stands for a box that was made from a horizontal
+list.
+Each \\{hlist\_node} is seven words long, and contains the following fields
+(in addition to the mandatory \\{type} and \\{link}, which we shall not
+mention explicitly when discussing the other node types): The \\{height} and
+\\{width} and \\{depth} are scaled integers denoting the dimensions of the
+box.  There is also a \\{shift\_amount} field, a scaled integer indicating
+how much this box should be lowered (if it appears in a horizontal list),
+or how much it should be moved to the right (if it appears in a vertical
+list). There is a \\{list\_ptr} field, which points to the beginning of the
+list from which this box was fabricated; if \\{list\_ptr} is \\{null}, the box
+is empty. Finally, there are three fields that represent the setting of
+the glue:  $\\{glue\_set}(\|p)$ is a word of type \\{glue\_ratio} that
+represents
+the proportionality constant for glue setting; $\\{glue\_sign}(\|p)$ is
+\\{stretching} or \\{shrinking} or \\{normal} depending on whether or not the
+glue should stretch or shrink or remain rigid; and $\\{glue\_order}(\|p)$
+specifies the order of infinity to which glue setting applies (\\{normal},
+\\{fil}, \\{fill}, or \\{filll}). The \\{subtype} field is not used in \TeX.
+In p\TeX\ the \\{subtype} field records the box direction \\{box\_dir}.
+
+\Y\P\D \37$\\{hlist\_node}=0$\C{\\{type} of hlist nodes}\par
+\P\D \37$\\{box\_node\_size}=8$\C{number of words to allocate for a box node}\Y%
+\par
+\P\D \37$\\{box\_dir}(\#)\S(\\{qo}(\\{subtype}(\#)))$\C{direction of a box}\par
+\P\D \37$\\{set\_box\_dir}(\#)\S\\{subtype}(\#)\K\\{set\_box\_dir\_end}$\par
+\P\D \37$\\{set\_box\_dir\_end}(\#)\S\\{qi}(\#)$\Y\par
+\P\D \37$\\{dir\_default}=0$\C{direction of the box, default Left to Right}\par
+\P\D \37$\\{dir\_dtou}=1$\C{direction of the box, Bottom to Top}\par
+\P\D \37$\\{dir\_tate}=3$\C{direction of the box, Top to Bottom}\par
+\P\D \37$\\{dir\_yoko}=4$\C{direction of the box, equal default}\par
+\P\D \37$\\{any\_dir}\S\\{dir\_yoko},\39\\{dir\_tate},\39\\{dir\_dtou}$\Y\par
+\P\D \37$\\{width\_offset}=1$\C{position of \\{width} field in a box node}\par
+\P\D \37$\\{depth\_offset}=2$\C{position of \\{depth} field in a box node}\par
+\P\D \37$\\{height\_offset}=3$\C{position of \\{height} field in a box node}\par
+\P\D \37$\\{width}(\#)\S\\{mem}[\#+\\{width\_offset}].\\{sc}$\C{width of the
+box, in sp}\par
+\P\D \37$\\{depth}(\#)\S\\{mem}[\#+\\{depth\_offset}].\\{sc}$\C{depth of the
+box, in sp}\par
+\P\D \37$\\{height}(\#)\S\\{mem}[\#+\\{height\_offset}].\\{sc}$\C{height of the
+box, in sp}\par
+\P\D \37$\\{shift\_amount}(\#)\S\\{mem}[\#+4].\\{sc}$\C{repositioning distance,
+in sp}\par
+\P\D \37$\\{list\_offset}=5$\C{position of \\{list\_ptr} field in a box node}%
+\par
+\P\D \37$\\{list\_ptr}(\#)\S\\{link}(\#+\\{list\_offset})$\C{beginning of the
+list inside the box}\par
+\P\D \37$\\{glue\_order}(\#)\S\\{subtype}(\#+\\{list\_offset})$\C{applicable
+order of infinity}\par
+\P\D \37$\\{glue\_sign}(\#)\S\\{type}(\#+\\{list\_offset})$\C{stretching or
+shrinking}\par
+\P\D \37$\\{normal}=0$\C{the most common case when several cases are named}\par
+\P\D \37$\\{stretching}=1$\C{glue setting applies to the stretch components}\par
+\P\D \37$\\{shrinking}=2$\C{glue setting applies to the shrink components}\par
+\P\D \37$\\{glue\_offset}=6$\C{position of \\{glue\_set} in a box node}\par
+\P\D \37$\\{glue\_set}(\#)\S\\{mem}[\#+\\{glue\_offset}].\\{gr}$\C{a word of
+type \\{glue\_ratio} for glue setting}\par
+\P\D \37$\\{space\_offset}=7$\C{position of \\{glue\_set} in a box node}\par
+\P\D \37$\\{space\_ptr}(\#)\S\\{link}(\#+\\{space\_offset})$\par
+\P\D \37$\\{xspace\_ptr}(\#)\S\\{info}(\#+\\{space\_offset})$\par
+\fi
+
+\M137. The \\{new\_null\_box} function returns a pointer to an \\{hlist\_node}
+in
+which all subfields have the values corresponding to `\.{\\hbox\{\}}'.
+The \\{subtype} field is set to \\{min\_quarterword}, since that's the desired
+\\{span\_count} value if this \\{hlist\_node} is changed to an \\{unset\_node}.
+
+\Y\P\4\&{function}\1\  \37\\{new\_null\_box}: \37\\{pointer};\C{creates a new
+box node}\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{box\_node\_size})$;\5
+$\\{type}(\|p)\K\\{hlist\_node}$;\5
+$\\{subtype}(\|p)\K\\{min\_quarterword}$;\5
+$\\{width}(\|p)\K0$;\5
+$\\{depth}(\|p)\K0$;\5
+$\\{height}(\|p)\K0$;\5
+$\\{shift\_amount}(\|p)\K0$;\5
+$\\{list\_ptr}(\|p)\K\\{null}$;\5
+$\\{glue\_sign}(\|p)\K\\{normal}$;\5
+$\\{glue\_order}(\|p)\K\\{normal}$;\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|p))$;\5
+$\\{space\_ptr}(\|p)\K\\{zero\_glue}$;\5
+$\\{xspace\_ptr}(\|p)\K\\{zero\_glue}$;\5
+$\\{add\_glue\_ref}(\\{zero\_glue})$;\5
+$\\{add\_glue\_ref}(\\{zero\_glue})$;\5
+$\\{new\_null\_box}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M138. A \\{vlist\_node} is like an \\{hlist\_node} in all respects except that
+it
+contains a vertical list.
+
+\Y\P\D \37$\\{vlist\_node}=1$\C{\\{type} of vlist nodes}\par
+\fi
+
+\M139. A \\{dir\_node} stands for direction change.
+
+\Y\P\D \37$\\{dir\_node}=2$\C{\\{type} of dir nodes}\par
+\Y\P\4\&{function}\1\  \37$\\{new\_dir\_node}(\|b:\\{pointer};\,\35\\{dir}:%
+\\{eight\_bits})$: \37\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37\&{if} $\\{type}(\|b)>\\{vlist\_node}$ \1\&{then}\5
+$\\{confusion}(\.{"new\_dir\_node:not\ box"})$;\2\6
+$\|p\K\\{new\_null\_box}$;\5
+$\\{type}(\|p)\K\\{dir\_node}$;\5
+$\\{set\_box\_dir}(\|p)(\\{dir})$;\6
+\&{case} $\\{box\_dir}(\|b)$ \1\&{of}\6
+\4\\{dir\_yoko}: \37\X140:Yoko to other direction\X;\6
+\4\\{dir\_tate}: \37\X141:Tate to other direction\X;\6
+\4\\{dir\_dtou}: \37\X142:DtoU to other direction\X;\6
+\4\&{othercases} \37$\\{confusion}(\.{"new\_dir\_node:illegal\ dir"})$;\2\6
+\&{endcases};\5
+$\\{link}(\|b)\K\\{null}$;\5
+$\\{list\_ptr}(\|p)\K\|b$;\5
+$\\{new\_dir\_node}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M140. \P$\X140:Yoko to other direction\X\S$\6
+\&{case} $\\{dir}$ \1\&{of}\6
+\4\\{dir\_tate}: \37\&{begin} \37$\\{width}(\|p)\K\\{height}(\|b)+\\{depth}(%
+\|b)$;\5
+$\\{depth}(\|p)\K\\{width}(\|b)/2$;\5
+$\\{height}(\|p)\K\\{width}(\|b)-\\{depth}(\|p)$;\6
+\&{end};\6
+\4\\{dir\_dtou}: \37\&{begin} \37$\\{width}(\|p)\K\\{height}(\|b)+\\{depth}(%
+\|b)$;\5
+$\\{depth}(\|p)\K0$;\5
+$\\{height}(\|p)\K\\{width}(\|b)$;\6
+\&{end};\6
+\4\&{othercases} \37$\\{confusion}(\.{"new\_dir\_node:y->?"})$;\2\6
+\&{endcases}\par
+\U139.\fi
+
+\M141. \P$\X141:Tate to other direction\X\S$\6
+\&{case} $\\{dir}$ \1\&{of}\6
+\4\\{dir\_yoko}: \37\&{begin} \37$\\{width}(\|p)\K\\{height}(\|b)+\\{depth}(%
+\|b)$;\5
+$\\{depth}(\|p)\K0$;\5
+$\\{height}(\|p)\K\\{width}(\|b)$;\6
+\&{end};\6
+\4\\{dir\_dtou}: \37\&{begin} \37$\\{width}(\|p)\K\\{width}(\|b)$;\5
+$\\{depth}(\|p)\K\\{height}(\|b)$;\5
+$\\{height}(\|p)\K\\{depth}(\|b)$;\6
+\&{end};\6
+\4\&{othercases} \37$\\{confusion}(\.{"new\_dir\_node:t->?"})$;\2\6
+\&{endcases}\par
+\U139.\fi
+
+\M142. \P$\X142:DtoU to other direction\X\S$\6
+\&{case} $\\{dir}$ \1\&{of}\6
+\4\\{dir\_yoko}: \37\&{begin} \37$\\{width}(\|p)\K\\{height}(\|b)+\\{depth}(%
+\|b)$;\5
+$\\{depth}(\|p)\K0$;\5
+$\\{height}(\|p)\K\\{width}(\|b)$;\6
+\&{end};\6
+\4\\{dir\_tate}: \37\&{begin} \37$\\{width}(\|p)\K\\{width}(\|b)$;\5
+$\\{depth}(\|p)\K\\{height}(\|b)$;\5
+$\\{height}(\|p)\K\\{depth}(\|b)$;\6
+\&{end};\6
+\4\&{othercases} \37$\\{confusion}(\.{"new\_dir\_node:d->?"})$;\2\6
+\&{endcases}\par
+\U139.\fi
+
+\M143. A \\{rule\_node} stands for a solid black rectangle; it has \\{width},
+\\{depth}, and \\{height} fields just as in an \\{hlist\_node}. However, if
+any of these dimensions is $-2^{30}$, the actual value will be determined
+by running the rule up to the boundary of the innermost enclosing box.
+This is called a ``running dimension.'' The \\{width} is never running in
+an hlist; the \\{height} and \\{depth} are never running in a~vlist.
+
+\Y\P\D \37$\\{rule\_node}=3$\C{\\{type} of rule nodes}\par
+\P\D \37$\\{rule\_node\_size}=4$\C{number of words to allocate for a rule node}%
+\par
+\P\D \37$\\{null\_flag}\S-\O{10000000000}$\C{$-2^{30}$, signifies a missing
+item}\par
+\P\D \37$\\{is\_running}(\#)\S(\#=\\{null\_flag})$\C{tests for a running
+dimension}\par
+\fi
+
+\M144. A new rule node is delivered by the \\{new\_rule} function. It
+makes all the dimensions ``running,'' so you have to change the
+ones that are not allowed to run.
+
+\Y\P\4\&{function}\1\  \37\\{new\_rule}: \37\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{rule\_node\_size})$;\5
+$\\{type}(\|p)\K\\{rule\_node}$;\5
+$\\{subtype}(\|p)\K0$;\C{the \\{subtype} is not used}\6
+$\\{width}(\|p)\K\\{null\_flag}$;\5
+$\\{depth}(\|p)\K\\{null\_flag}$;\5
+$\\{height}(\|p)\K\\{null\_flag}$;\5
+$\\{new\_rule}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M145. Insertions are represented by \\{ins\_node} records, where the %
+\\{subtype}
+indicates the corresponding box number. For example, `\.{\\insert 250}'
+leads to an \\{ins\_node} whose \\{subtype} is $250+\\{min\_quarterword}$.
+The \\{height} field of an \\{ins\_node} is slightly misnamed; it actually
+holds
+the natural height plus depth of the vertical list being inserted.
+The \\{depth} field holds the \\{split\_max\_depth} to be used in case this
+insertion is split, and the \\{split\_top\_ptr} points to the corresponding
+\\{split\_top\_skip}. The \\{float\_cost} field holds the \\{floating\_penalty}
+that
+will be used if this insertion floats to a subsequent page after a
+split insertion of the same class.  There is one more field, the
+\\{ins\_ptr}, which points to the beginning of the vlist for the insertion.
+
+\Y\P\D \37$\\{ins\_node}=4$\C{\\{type} of insertion nodes}\par
+\P\D \37$\\{ins\_node\_size}=6$\C{number of words to allocate for an insertion}%
+\par
+\P\D \37$\\{float\_cost}(\#)\S\\{mem}[\#+1].\\{int}$\C{the \\{floating%
+\_penalty} to be used}\par
+\P\D \37$\\{ins\_ptr}(\#)\S\\{info}(\#+4)$\C{the vertical list to be inserted}%
+\par
+\P\D \37$\\{split\_top\_ptr}(\#)\S\\{link}(\#+4)$\C{the \\{split\_top\_skip} to
+be used}\par
+\P\D \37$\\{ins\_dir}(\#)\S\\{subtype}(\#+5)$\C{direction of \\{ins\_node}}\par
+\fi
+
+\M146. A \\{disp\_node} has a \\{disp\_dimen} field that points to the
+displacement
+distance of the baselineshift between Latin characters and Kanji chatacters.
+
+\Y\P\D \37$\\{disp\_node}=5$\C{\\{type} of a displace node}\par
+\P\D \37$\\{disp\_dimen}(\#)\S\\{mem}[\#+1].\\{sc}$\par
+\fi
+
+\M147. A \\{mark\_node} has a \\{mark\_ptr} field that points to the reference
+count
+of a token list that contains the user's \.{\\mark} text.
+This field occupies a full word instead of a halfword, because
+there's nothing to put in the other halfword; it is easier in \PASCAL\ to
+use the full word than to risk leaving garbage in the unused half.
+
+\Y\P\D \37$\\{mark\_node}=6$\C{\\{type} of a mark node}\par
+\P\D \37$\\{small\_node\_size}=2$\C{number of words to allocate for most node
+types}\par
+\P\D \37$\\{mark\_ptr}(\#)\S\\{mem}[\#+1].\\{int}$\C{head of the token list for
+a mark}\par
+\fi
+
+\M148. An \\{adjust\_node}, which occurs only in horizontal lists,
+specifies material that will be moved out into the surrounding
+vertical list; i.e., it is used to implement \TeX's `\.{\\vadjust}'
+operation.  The \\{adjust\_ptr} field points to the vlist containing this
+material.
+
+\Y\P\D \37$\\{adjust\_node}=7$\C{\\{type} of an adjust node}\par
+\P\D \37$\\{adjust\_ptr}\S\\{mark\_ptr}$\C{vertical list to be moved out of
+horizontal list}\par
+\fi
+
+\M149. A \\{ligature\_node}, which occurs only in horizontal lists, specifies
+a character that was fabricated from the interaction of two or more
+actual characters.  The second word of the node, which is called the
+\\{lig\_char} word, contains \\{font} and \\{character} fields just as in a
+\\{char\_node}. The characters that generated the ligature have not been
+forgotten, since they are needed for diagnostic messages and for
+hyphenation; the \\{lig\_ptr} field points to a linked list of character
+nodes for all original characters that have been deleted. (This list
+might be empty if the characters that generated the ligature were
+retained in other nodes.)
+
+The \\{subtype} field is 0, plus 2 and/or 1 if the original source of the
+ligature included implicit left and/or right boundaries.
+
+\Y\P\D \37$\\{ligature\_node}=8$\C{\\{type} of a ligature node}\par
+\P\D \37$\\{lig\_char}(\#)\S\#+1$\C{the word where the ligature is to be found}%
+\par
+\P\D \37$\\{lig\_ptr}(\#)\S\\{link}(\\{lig\_char}(\#))$\C{the list of
+characters}\par
+\fi
+
+\M150. The \\{new\_ligature} function creates a ligature node having given
+contents of the \\{font}, \\{character}, and \\{lig\_ptr} fields. We also have
+a \\{new\_lig\_item} function, which returns a two-word node having a given
+\\{character} field. Such nodes are used for temporary processing as ligatures
+are being created.
+
+\Y\P\4\&{function}\1\  \37$\\{new\_ligature}(\|f:\\{internal\_font\_number};\,%
+\35\|c:\\{quarterword};\,\35\|q:\\{pointer})$: \37\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|p)\K\\{ligature\_node}$;\5
+$\\{font}(\\{lig\_char}(\|p))\K\|f$;\5
+$\\{character}(\\{lig\_char}(\|p))\K\|c$;\5
+$\\{lig\_ptr}(\|p)\K\|q$;\5
+$\\{subtype}(\|p)\K0$;\5
+$\\{new\_ligature}\K\|p$;\6
+\&{end};\7
+\4\&{function}\1\  \37$\\{new\_lig\_item}(\|c:\\{quarterword})$: \37%
+\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{character}(\|p)\K\|c$;\5
+$\\{lig\_ptr}(\|p)\K\\{null}$;\5
+$\\{new\_lig\_item}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M151. A \\{disc\_node}, which occurs only in horizontal lists, specifies a
+``dis\-cretion\-ary'' line break. If such a break occurs at node \|p, the text
+that starts at $\\{pre\_break}(\|p)$ will precede the break, the text that
+starts at
+$\\{post\_break}(\|p)$ will follow the break, and text that appears in the next
+$\\{replace\_count}(\|p)$ nodes will be ignored. For example, an ordinary
+discretionary hyphen, indicated by `\.{\\-}', yields a \\{disc\_node} with
+\\{pre\_break} pointing to a \\{char\_node} containing a hyphen, $\\{post%
+\_break}=\\{null}$,
+and $\\{replace\_count}=0$. All three of the discretionary texts must be
+lists that consist entirely of character, kern, box, rule, and ligature nodes.
+
+If $\\{pre\_break}(\|p)=\\{null}$, the \\{ex\_hyphen\_penalty} will be charged
+for this
+break.  Otherwise the \\{hyphen\_penalty} will be charged.  The texts will
+actually be substituted into the list by the line-breaking algorithm if it
+decides to make the break, and the discretionary node will disappear at
+that time; thus, the output routine sees only discretionaries that were
+not chosen.
+
+\Y\P\D \37$\\{disc\_node}=9$\C{\\{type} of a discretionary node}\par
+\P\D \37$\\{replace\_count}\S\\{subtype}$\C{how many subsequent nodes to
+replace}\par
+\P\D \37$\\{pre\_break}\S\\{llink}$\C{text that precedes a discretionary break}%
+\par
+\P\D \37$\\{post\_break}\S\\{rlink}$\C{text that follows a discretionary break}%
+\par
+\Y\P\4\&{function}\1\  \37\\{new\_disc}: \37\\{pointer};\C{creates an empty %
+\\{disc\_node}}\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|p)\K\\{disc\_node}$;\5
+$\\{replace\_count}(\|p)\K0$;\5
+$\\{pre\_break}(\|p)\K\\{null}$;\5
+$\\{post\_break}(\|p)\K\\{null}$;\5
+$\\{new\_disc}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M152. A \\{whatsit\_node} is a wild card reserved for extensions to \TeX. The
+\\{subtype} field in its first word says what `\\{whatsit}' it is, and
+implicitly determines the node size (which must be 2 or more) and the
+format of the remaining words. When a \\{whatsit\_node} is encountered
+in a list, special actions are invoked; knowledgeable people who are
+careful not to mess up the rest of \TeX\ are able to make \TeX\ do new
+things by adding code at the end of the program. For example, there
+might be a `\TeX nicolor' extension to specify different colors of ink,
+and the whatsit node might contain the desired parameters.
+
+The present implementation of \TeX\ treats the features associated with
+`\.{\\write}' and `\.{\\special}' as if they were extensions, in order to
+illustrate how such routines might be coded. We shall defer further
+discussion of extensions until the end of this program.
+
+\Y\P\D \37$\\{whatsit\_node}=10$\C{\\{type} of special extension nodes}\par
+\fi
+
+\M153. A \\{math\_node}, which occurs only in horizontal lists, appears before
+and
+after mathematical formulas. The \\{subtype} field is \\{before} before the
+formula and \\{after} after it. There is a \\{width} field, which represents
+the amount of surrounding space inserted by \.{\\mathsurround}.
+
+\Y\P\D \37$\\{math\_node}=11$\C{\\{type} of a math node}\par
+\P\D \37$\\{before}=0$\C{\\{subtype} for math node that introduces a formula}%
+\par
+\P\D \37$\\{after}=1$\C{\\{subtype} for math node that winds up a formula}\par
+\Y\P\4\&{function}\1\  \37$\\{new\_math}(\|w:\\{scaled};\,\35\|s:\\{small%
+\_number})$: \37\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|p)\K\\{math\_node}$;\5
+$\\{subtype}(\|p)\K\|s$;\5
+$\\{width}(\|p)\K\|w$;\5
+$\\{new\_math}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M154. \TeX\ makes use of the fact that \\{hlist\_node}, \\{vlist\_node},
+\\{rule\_node}, \\{ins\_node}, \\{mark\_node}, \\{adjust\_node}, \\{ligature%
+\_node},
+\\{disc\_node}, \\{whatsit\_node}, and \\{math\_node} are at the low end of the
+type codes, by permitting a break at glue in a list if and only if the
+\\{type} of the previous node is less than \\{math\_node}. Furthermore, a
+node is discarded after a break if its type is \\{math\_node} or~more.
+
+\Y\P\D \37$\\{precedes\_break}(\#)\S(\\{type}(\#)<\\{math\_node})$\par
+\P\D \37$\\{non\_discardable}(\#)\S(\\{type}(\#)<\\{math\_node})$\par
+\fi
+
+\M155. A \\{glue\_node} represents glue in a list. However, it is really only
+a pointer to a separate glue specification, since \TeX\ makes use of the
+fact that many essentially identical nodes of glue are usually present.
+If \|p points to a \\{glue\_node}, $\\{glue\_ptr}(\|p)$ points to
+another packet of words that specify the stretch and shrink components, etc.
+
+Glue nodes also serve to represent leaders; the \\{subtype} is used to
+distinguish between ordinary glue (which is called \\{normal}) and the three
+kinds of leaders (which are called \\{a\_leaders}, \\{c\_leaders}, and \\{x%
+\_leaders}).
+The \\{leader\_ptr} field points to a rule node or to a box node containing the
+leaders; it is set to \\{null} in ordinary glue nodes.
+
+Many kinds of glue are computed from \TeX's ``skip'' parameters, and
+it is helpful to know which parameter has led to a particular glue node.
+Therefore the \\{subtype} is set to indicate the source of glue, whenever
+it originated as a parameter. We will be defining symbolic names for the
+parameter numbers later (e.g., $\\{line\_skip\_code}=0$, $\\{baseline\_skip%
+\_code}=1$,
+etc.); it suffices for now to say that the \\{subtype} of parametric glue
+will be the same as the parameter number, plus~one.
+
+In math formulas there are two more possibilities for the \\{subtype} in a
+glue node: \\{mu\_glue} denotes an \.{\\mskip} (where the units are scaled %
+\.{mu}
+instead of scaled \.{pt}); and \\{cond\_math\_glue} denotes the `\.{%
+\\nonscript}'
+feature that cancels the glue node immediately following if it appears
+in a subscript.
+
+\Y\P\D \37$\\{glue\_node}=12$\C{\\{type} of node that points to a glue
+specification}\par
+\P\D \37$\\{cond\_math\_glue}=98$\C{special \\{subtype} to suppress glue in the
+next node}\par
+\P\D \37$\\{mu\_glue}=99$\C{\\{subtype} for math glue}\par
+\P\D \37$\\{a\_leaders}=100$\C{\\{subtype} for aligned leaders}\par
+\P\D \37$\\{c\_leaders}=101$\C{\\{subtype} for centered leaders}\par
+\P\D \37$\\{x\_leaders}=102$\C{\\{subtype} for expanded leaders}\par
+\P\D \37$\\{glue\_ptr}\S\\{llink}$\C{pointer to a glue specification}\par
+\P\D \37$\\{leader\_ptr}\S\\{rlink}$\C{pointer to box or rule node for leaders}%
+\par
+\fi
+
+\M156. A glue specification has a halfword reference count in its first word,
+representing \\{null} plus the number of glue nodes that point to it (less
+one).
+Note that the reference count appears in the same position as
+the \\{link} field in list nodes; this is the field that is initialized
+to \\{null} when a node is allocated, and it is also the field that is flagged
+by \\{empty\_flag} in empty nodes.
+
+Glue specifications also contain three \\{scaled} fields, for the \\{width},
+\\{stretch}, and \\{shrink} dimensions. Finally, there are two one-byte
+fields called \\{stretch\_order} and \\{shrink\_order}; these contain the
+orders of infinity (\\{normal}, \\{fil}, \\{fill}, or \\{filll})
+corresponding to the stretch and shrink values.
+
+\Y\P\D \37$\\{glue\_spec\_size}=4$\C{number of words to allocate for a glue
+specification}\par
+\P\D \37$\\{glue\_ref\_count}(\#)\S\\{link}(\#)$\C{reference count of a glue
+specification}\par
+\P\D \37$\\{stretch}(\#)\S\\{mem}[\#+2].\\{sc}$\C{the stretchability of this
+glob of glue}\par
+\P\D \37$\\{shrink}(\#)\S\\{mem}[\#+3].\\{sc}$\C{the shrinkability of this glob
+of glue}\par
+\P\D \37$\\{stretch\_order}\S\\{type}$\C{order of infinity for stretching}\par
+\P\D \37$\\{shrink\_order}\S\\{subtype}$\C{order of infinity for shrinking}\par
+\P\D \37$\\{fil}=1$\C{first-order infinity}\par
+\P\D \37$\\{fill}=2$\C{second-order infinity}\par
+\P\D \37$\\{filll}=3$\C{third-order infinity}\par
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{glue\_ord}=\\{normal}\to\\{filll}$;\C{infinity to the 0, 1, 2, or 3 power}%
+\par
+\fi
+
+\M157. Here is a function that returns a pointer to a copy of a glue spec.
+The reference count in the copy is \\{null}, because there is assumed
+to be exactly one reference to the new specification.
+
+\Y\P\4\&{function}\1\  \37$\\{new\_spec}(\|p:\\{pointer})$: \37\\{pointer};%
+\C{duplicates a glue specification}\6
+\4\&{var} \37\|q: \37\\{pointer};\C{the new spec}\2\6
+\&{begin} \37$\|q\K\\{get\_node}(\\{glue\_spec\_size})$;\6
+$\\{mem}[\|q]\K\\{mem}[\|p]$;\5
+$\\{glue\_ref\_count}(\|q)\K\\{null}$;\6
+$\\{width}(\|q)\K\\{width}(\|p)$;\5
+$\\{stretch}(\|q)\K\\{stretch}(\|p)$;\5
+$\\{shrink}(\|q)\K\\{shrink}(\|p)$;\5
+$\\{new\_spec}\K\|q$;\6
+\&{end};\par
+\fi
+
+\M158. And here's a function that creates a glue node for a given parameter
+identified by its code number; for example,
+$\\{new\_param\_glue}(\\{line\_skip\_code})$ returns a pointer to a glue node
+for the
+current \.{\\lineskip}.
+
+\Y\P\4\&{function}\1\  \37$\\{new\_param\_glue}(\|n:\\{small\_number})$: \37%
+\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\6
+\|q: \37\\{pointer};\C{the glue specification}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|p)\K\\{glue\_node}$;\5
+$\\{subtype}(\|p)\K\|n+1$;\5
+$\\{leader\_ptr}(\|p)\K\\{null}$;\6
+$\|q\K\X230:Current \\{mem} equivalent of glue parameter number \|n\X\hbox{}$;\5
+$\\{glue\_ptr}(\|p)\K\|q$;\5
+$\\{incr}(\\{glue\_ref\_count}(\|q))$;\5
+$\\{new\_param\_glue}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M159. Glue nodes that are more or less anonymous are created by \\{new\_glue},
+whose argument points to a glue specification.
+
+\Y\P\4\&{function}\1\  \37$\\{new\_glue}(\|q:\\{pointer})$: \37\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|p)\K\\{glue\_node}$;\5
+$\\{subtype}(\|p)\K\\{normal}$;\5
+$\\{leader\_ptr}(\|p)\K\\{null}$;\5
+$\\{glue\_ptr}(\|p)\K\|q$;\5
+$\\{incr}(\\{glue\_ref\_count}(\|q))$;\5
+$\\{new\_glue}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M160. Still another subroutine is needed: This one is sort of a combination
+of \\{new\_param\_glue} and \\{new\_glue}. It creates a glue node for one of
+the current glue parameters, but it makes a fresh copy of the glue
+specification, since that specification will probably be subject to change,
+while the parameter will stay put. The global variable \\{temp\_ptr} is
+set to the address of the new spec.
+
+\Y\P\4\&{function}\1\  \37$\\{new\_skip\_param}(\|n:\\{small\_number})$: \37%
+\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\\{temp\_ptr}\K\\{new\_spec}(\X230:Current \\{mem} equivalent of
+glue parameter number \|n\X)$;\5
+$\|p\K\\{new\_glue}(\\{temp\_ptr})$;\5
+$\\{glue\_ref\_count}(\\{temp\_ptr})\K\\{null}$;\5
+$\\{subtype}(\|p)\K\|n+1$;\5
+$\\{new\_skip\_param}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M161. A \\{kern\_node} has a \\{width} field to specify a (normally negative)
+amount of spacing. This spacing correction appears in horizontal lists
+between letters like A and V when the font designer said that it looks
+better to move them closer together or further apart. A kern node can
+also appear in a vertical list, when its `\\{width}' denotes additional
+spacing in the vertical direction. The \\{subtype} is either \\{normal} (for
+kerns inserted from font information or math mode calculations) or \\{explicit}
+(for kerns inserted from \.{\\kern} and \.{\\/} commands) or \\{acc\_kern}
+(for kerns inserted from non-math accents) or \\{mu\_glue} (for kerns
+inserted from \.{\\mkern} specifications in math formulas).
+
+\Y\P\D \37$\\{kern\_node}=13$\C{\\{type} of a kern node}\par
+\P\D \37$\\{explicit}=1$\C{\\{subtype} of kern nodes from \.{\\kern}}\par
+\P\D \37$\\{acc\_kern}=2$\C{\\{subtype} of kern nodes from accents}\par
+\P\D \37$\\{ita\_kern}=3$\C{\\{subtype} of kern nodes from \.{\\/}}\par
+\fi
+
+\M162. The \\{new\_kern} function creates a kern node having a given width.
+
+\Y\P\4\&{function}\1\  \37$\\{new\_kern}(\|w:\\{scaled})$: \37\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|p)\K\\{kern\_node}$;\5
+$\\{subtype}(\|p)\K\\{normal}$;\5
+$\\{width}(\|p)\K\|w$;\5
+$\\{new\_kern}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M163. A \\{penalty\_node} specifies the penalty associated with line or page
+breaking, in its \\{penalty} field. This field is a fullword integer, but
+the full range of integer values is not used: Any penalty $\G10000$ is
+treated as infinity, and no break will be allowed for such high values.
+Similarly, any penalty $\L-10000$ is treated as negative infinity, and a
+break will be forced.
+
+\Y\P\D \37$\\{penalty\_node}=14$\C{\\{type} of a penalty node}\par
+\P\D \37$\\{widow\_pena}=1$\C{\\{subtype} of penalty nodes from \.{%
+\\jchrwidowpenalty}}\par
+\P\D \37$\\{kinsoku\_pena}=2$\C{\\{subtype} of penalty nodes from kinsoku}\par
+\P\D \37$\\{inf\_penalty}=\\{inf\_bad}$\C{``infinite'' penalty value}\par
+\P\D \37$\\{eject\_penalty}=-\\{inf\_penalty}$\C{``negatively infinite''
+penalty value}\par
+\P\D \37$\\{penalty}(\#)\S\\{mem}[\#+1].\\{int}$\C{the added cost of breaking a
+list here}\par
+\fi
+
+\M164. Anyone who has been reading the last few sections of the program will
+be able to guess what comes next.
+
+\Y\P\4\&{function}\1\  \37$\\{new\_penalty}(\|m:\\{integer})$: \37\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|p)\K\\{penalty\_node}$;\5
+$\\{subtype}(\|p)\K0$;\C{the \\{subtype} is not used}\6
+$\\{penalty}(\|p)\K\|m$;\5
+$\\{new\_penalty}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M165. You might think that we have introduced enough node types by now. Well,
+almost, but there is one more: An \\{unset\_node} has nearly the same format
+as an \\{hlist\_node} or \\{vlist\_node}; it is used for entries in \.{%
+\\halign}
+or \.{\\valign} that are not yet in their final form, since the box
+dimensions are their ``natural'' sizes before any glue adjustment has been
+made. The \\{glue\_set} word is not present; instead, we have a \\{glue%
+\_stretch}
+field, which contains the total stretch of order \\{glue\_order} that is
+present in the hlist or vlist being boxed.
+Similarly, the \\{shift\_amount} field is replaced by a \\{glue\_shrink} field,
+containing the total shrink of order \\{glue\_sign} that is present.
+The \\{subtype} field is called \\{span\_count}; an unset box typically
+contains the data for $\\{qo}(\\{span\_count})+1$ columns.
+Unset nodes will be changed to box nodes when alignment is completed.
+
+\Y\P\D \37$\\{unset\_node}=15$\C{\\{type} for an unset node}\par
+\P\D \37$\\{glue\_stretch}(\#)\S\\{mem}[\#+\\{glue\_offset}].\\{sc}$\C{total
+stretch in an unset node}\par
+\P\D \37$\\{glue\_shrink}\S\\{shift\_amount}$\C{total shrink in an unset node}%
+\par
+\P\D \37$\\{span\_count}\S\\{subtype}$\C{indicates the number of spanned
+columns}\par
+\fi
+
+\M166. In fact, there are still more types coming. When we get to math formula
+processing we will see that a \\{style\_node} has $\\{type}=16$; and a number
+of larger type codes will also be defined, for use in math mode only.
+
+\fi
+
+\M167. Warning: If any changes are made to these data structure layouts, such
+as
+changing any of the node sizes or even reordering the words of nodes,
+the \\{copy\_node\_list} procedure and the memory initialization code
+below may have to be changed. Such potentially dangerous parts of the
+program are listed in the index under `data structure assumptions'.
+However, other references to the nodes are made symbolically in terms of
+the \.{WEB} macro definitions above, so that format changes will leave
+\TeX's other algorithms intact.
+
+\fi
+
+\N168.  \[11] Memory layout.
+Some areas of \\{mem} are dedicated to fixed usage, since static allocation is
+more efficient than dynamic allocation when we can get away with it. For
+example, locations \\{mem\_bot} to $\\{mem\_bot}+3$ are always used to store
+the
+specification for glue that is `\.{0pt plus 0pt minus 0pt}'. The
+following macro definitions accomplish the static allocation by giving
+symbolic names to the fixed positions. Static variable-size nodes appear
+in locations \\{mem\_bot} through \\{lo\_mem\_stat\_max}, and static
+single-word nodes
+appear in locations \\{hi\_mem\_stat\_min} through \\{mem\_top}, inclusive. It
+is
+harmless to let \\{lig\_trick} and \\{garbage} share the same location of %
+\\{mem}.
+
+\Y\P\D \37$\\{zero\_glue}\S\\{mem\_bot}$\C{specification for \.{0pt plus 0pt
+minus 0pt}}\par
+\P\D \37$\\{fil\_glue}\S\\{zero\_glue}+\\{glue\_spec\_size}$\C{\.{0pt plus 1fil
+minus 0pt}}\par
+\P\D \37$\\{fill\_glue}\S\\{fil\_glue}+\\{glue\_spec\_size}$\C{\.{0pt plus
+1fill minus 0pt}}\par
+\P\D \37$\\{ss\_glue}\S\\{fill\_glue}+\\{glue\_spec\_size}$\C{\.{0pt plus 1fil
+minus 1fil}}\par
+\P\D \37$\\{fil\_neg\_glue}\S\\{ss\_glue}+\\{glue\_spec\_size}$\C{\.{0pt plus
+-1fil minus 0pt}}\par
+\P\D \37$\\{lo\_mem\_stat\_max}\S\\{fil\_neg\_glue}+\\{glue\_spec\_size}-1$%
+\C{largest statically   allocated word in the variable-size \\{mem}}\Y\par
+\P\D \37$\\{page\_ins\_head}\S\\{mem\_top}$\C{list of insertion data for
+current page}\par
+\P\D \37$\\{contrib\_head}\S\\{mem\_top}-1$\C{vlist of items not yet on current
+page}\par
+\P\D \37$\\{page\_head}\S\\{mem\_top}-2$\C{vlist for current page}\par
+\P\D \37$\\{temp\_head}\S\\{mem\_top}-3$\C{head of a temporary list of some
+kind}\par
+\P\D \37$\\{hold\_head}\S\\{mem\_top}-4$\C{head of a temporary list of another
+kind}\par
+\P\D \37$\\{adjust\_head}\S\\{mem\_top}-5$\C{head of adjustment list returned
+by \\{hpack}}\par
+\P\D \37$\\{active}\S\\{mem\_top}-7$\C{head of active list in \\{line\_break},
+needs two words}\par
+\P\D \37$\\{align\_head}\S\\{mem\_top}-8$\C{head of preamble list for
+alignments}\par
+\P\D \37$\\{end\_span}\S\\{mem\_top}-9$\C{tail of spanned-width lists}\par
+\P\D \37$\\{omit\_template}\S\\{mem\_top}-10$\C{a constant token list}\par
+\P\D \37$\\{null\_list}\S\\{mem\_top}-11$\C{permanently empty list}\par
+\P\D \37$\\{lig\_trick}\S\\{mem\_top}-12$\C{a ligature masquerading as a %
+\\{char\_node}}\par
+\P\D \37$\\{garbage}\S\\{mem\_top}-12$\C{used for scrap information}\par
+\P\D \37$\\{backup\_head}\S\\{mem\_top}-13$\C{head of token list built by %
+\\{scan\_keyword}}\par
+\P\D \37$\\{hi\_mem\_stat\_min}\S\\{mem\_top}-13$\C{smallest statically
+allocated word in   the one-word \\{mem}}\par
+\P\D \37$\\{hi\_mem\_stat\_usage}=14$\C{the number of one-word nodes always
+present}\par
+\fi
+
+\M169. The following code gets \\{mem} off to a good start, when \TeX\ is
+initializing itself the slow~way.
+
+\Y\P$\4\X19:Local variables for initialization\X\mathrel{+}\S$\6
+\4\|k: \37\\{integer};\C{index into \\{mem}, \\{eqtb}, etc.}\par
+\fi
+
+\M170. \P$\X170:Initialize table entries (done by \.{INITEX} only)\X\S$\6
+\&{for} $\|k\K\\{mem\_bot}+1\mathrel{\&{to}}\\{lo\_mem\_stat\_max}$ \1\&{do}\5
+$\\{mem}[\|k].\\{sc}\K0$;\C{all glue dimensions are zeroed}\2\6
+$\|k\K\\{mem\_bot}$;\ \&{while} $\|k\L\\{lo\_mem\_stat\_max}$ \1\&{do}\C{set
+first words of glue specifications}\6
+\&{begin} \37$\\{glue\_ref\_count}(\|k)\K\\{null}+1$;\5
+$\\{stretch\_order}(\|k)\K\\{normal}$;\5
+$\\{shrink\_order}(\|k)\K\\{normal}$;\5
+$\|k\K\|k+\\{glue\_spec\_size}$;\6
+\&{end};\2\6
+$\\{stretch}(\\{fil\_glue})\K\\{unity}$;\5
+$\\{stretch\_order}(\\{fil\_glue})\K\\{fil}$;\6
+$\\{stretch}(\\{fill\_glue})\K\\{unity}$;\5
+$\\{stretch\_order}(\\{fill\_glue})\K\\{fill}$;\6
+$\\{stretch}(\\{ss\_glue})\K\\{unity}$;\5
+$\\{stretch\_order}(\\{ss\_glue})\K\\{fil}$;\6
+$\\{shrink}(\\{ss\_glue})\K\\{unity}$;\5
+$\\{shrink\_order}(\\{ss\_glue})\K\\{fil}$;\6
+$\\{stretch}(\\{fil\_neg\_glue})\K-\\{unity}$;\5
+$\\{stretch\_order}(\\{fil\_neg\_glue})\K\\{fil}$;\6
+$\\{rover}\K\\{lo\_mem\_stat\_max}+1$;\5
+$\\{link}(\\{rover})\K\\{empty\_flag}$;\C{now initialize the dynamic memory}\6
+$\\{node\_size}(\\{rover})\K1000$;\C{which is a 1000-word available node}\6
+$\\{llink}(\\{rover})\K\\{rover}$;\5
+$\\{rlink}(\\{rover})\K\\{rover}$;\6
+$\\{lo\_mem\_max}\K\\{rover}+1000$;\5
+$\\{link}(\\{lo\_mem\_max})\K\\{null}$;\5
+$\\{info}(\\{lo\_mem\_max})\K\\{null}$;\6
+\&{for} $\|k\K\\{hi\_mem\_stat\_min}\mathrel{\&{to}}\\{mem\_top}$ \1\&{do}\5
+$\\{mem}[\|k]\K\\{mem}[\\{lo\_mem\_max}]$;\C{clear list heads}\2\6
+\X801:Initialize the special list heads and constant nodes\X;\6
+$\\{avail}\K\\{null}$;\5
+$\\{mem\_end}\K\\{mem\_top}$;\5
+$\\{hi\_mem\_min}\K\\{hi\_mem\_stat\_min}$;\C{initialize the one-word memory}\6
+$\\{var\_used}\K\\{lo\_mem\_stat\_max}+1-\\{mem\_bot}$;\5
+$\\{dyn\_used}\K\\{hi\_mem\_stat\_usage}$;\C{initialize statistics}\par
+\As228, 234, 238, 246, 256, 264, 563, 957, 962, 1228, 1314\ETs1382.
+\U8.\fi
+
+\M171. If \TeX\ is extended improperly, the \\{mem} array might get screwed up.
+For example, some pointers might be wrong, or some ``dead'' nodes might not
+have been freed when the last reference to them disappeared. Procedures
+\\{check\_mem} and \\{search\_mem} are available to help diagnose such
+problems. These procedures make use of two arrays called \\{free} and
+\\{was\_free} that are present only if \TeX's debugging routines have
+been included. (You may want to decrease the size of \\{mem} while you
+are debugging.)
+
+\Y\P\D \37$\\{free}\S\\{free\_arr}$\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\C{The debug memory arrays have not been mallocated yet.}\6
+\&{debug} \37\\{free}: \37\&{packed} \37\&{array} $[0\to9]$ \1\&{of}\5
+\\{boolean};\C{free cells}\2\6
+\4\hbox{\hskip10pt}\\{was\_free}: \37\&{packed} \37\&{array} $[0\to9]$ \1\&{of}%
+\5
+\\{boolean};\C{previously free cells}\2\6
+\4$\hbox{\hskip10pt}\\{was\_mem\_end},\39\\{was\_lo\_max},\39\\{was\_hi\_min}$:
+\37\\{pointer};\C{previous \\{mem\_end}, \\{lo\_mem\_max}, and \\{hi\_mem%
+\_min}}\6
+\4\hbox{\hskip10pt}\\{panicking}: \37\\{boolean};\C{do we want to check memory
+constantly?}\6
+\&{gubed}\par
+\fi
+
+\M172. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+\&{debug} \37$\\{was\_mem\_end}\K\\{mem\_min}$;\C{indicate that everything was
+previously free}\6
+$\\{was\_lo\_max}\K\\{mem\_min}$;\5
+$\\{was\_hi\_min}\K\\{mem\_max}$;\5
+$\\{panicking}\K\\{false}$;\6
+\&{gubed}\par
+\fi
+
+\M173. Procedure \\{check\_mem} makes sure that the available space lists of
+\\{mem} are well formed, and it optionally prints out all locations
+that are reserved now but were free the last time this procedure was called.
+
+\Y\P\&{debug} \37\&{procedure}\1\  \37$\\{check\_mem}(\\{print\_locs}:%
+\\{boolean})$;\6
+\4\&{label} \37$\\{done1},\39\\{done2}$;\C{loop exits}\6
+\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{current locations of interest in %
+\\{mem}}\6
+\\{clobbered}: \37\\{boolean};\C{is something amiss?}\2\6
+\&{begin} \37\&{for} $\|p\K\\{mem\_min}\mathrel{\&{to}}\\{lo\_mem\_max}$ \1%
+\&{do}\5
+$\\{free}[\|p]\K\\{false}$;\C{you can probably   do this faster}\2\6
+\&{for} $\|p\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\5
+$\\{free}[\|p]\K\\{false}$;\C{ditto}\2\6
+\X174:Check single-word \\{avail} list\X;\6
+\X175:Check variable-size \\{avail} list\X;\6
+\X176:Check flags of unavailable nodes\X;\6
+\&{if} $\\{print\_locs}$ \1\&{then}\5
+\X177:Print newly busy locations\X;\2\6
+\&{for} $\|p\K\\{mem\_min}\mathrel{\&{to}}\\{lo\_mem\_max}$ \1\&{do}\5
+$\\{was\_free}[\|p]\K\\{free}[\|p]$;\2\6
+\&{for} $\|p\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\5
+$\\{was\_free}[\|p]\K\\{free}[\|p]$;\C{$\\{was\_free}\K\\{free}$ might be
+faster}\2\6
+$\\{was\_mem\_end}\K\\{mem\_end}$;\5
+$\\{was\_lo\_max}\K\\{lo\_mem\_max}$;\5
+$\\{was\_hi\_min}\K\\{hi\_mem\_min}$;\6
+\&{end};\6
+\&{gubed}\par
+\fi
+
+\M174. \P$\X174:Check single-word \\{avail} list\X\S$\6
+$\|p\K\\{avail}$;\5
+$\|q\K\\{null}$;\5
+$\\{clobbered}\K\\{false}$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $(\|p>\\{mem\_end})\V(\|p<\\{hi\_mem\_min})$ \1\&{then}\5
+$\\{clobbered}\K\\{true}$\6
+\4\&{else} \&{if} $\\{free}[\|p]$ \1\&{then}\5
+$\\{clobbered}\K\\{true}$;\2\2\6
+\&{if} $\\{clobbered}$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"AVAIL\ list\ clobbered\ at\ "})$;\5
+$\\{print\_int}(\|q)$;\5
+\&{goto} \37\\{done1};\6
+\&{end};\2\6
+$\\{free}[\|p]\K\\{true}$;\5
+$\|q\K\|p$;\5
+$\|p\K\\{link}(\|q)$;\6
+\&{end};\2\6
+\4\\{done1}: \37\par
+\U173.\fi
+
+\M175. \P$\X175:Check variable-size \\{avail} list\X\S$\6
+$\|p\K\\{rover}$;\5
+$\|q\K\\{null}$;\5
+$\\{clobbered}\K\\{false}$;\6
+\1\&{repeat} \37\&{if} $(\|p\G\\{lo\_mem\_max})\V(\|p<\\{mem\_min})$ \1\&{then}%
+\5
+$\\{clobbered}\K\\{true}$\6
+\4\&{else} \&{if} $(\\{rlink}(\|p)\G\\{lo\_mem\_max})\V(\\{rlink}(\|p)<\\{mem%
+\_min})$ \1\&{then}\5
+$\\{clobbered}\K\\{true}$\6
+\4\&{else} \&{if} $\R(\\{is\_empty}(\|p))\V(\\{node\_size}(\|p)<2)\V\30(\|p+%
+\\{node\_size}(\|p)>\\{lo\_mem\_max})\V\30(\\{llink}(\\{rlink}(\|p))\I\|p)$ \1%
+\&{then}\5
+$\\{clobbered}\K\\{true}$;\2\2\2\6
+\&{if} $\\{clobbered}$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"Double-AVAIL\ list\ clobbered\ at\ "})$;\5
+$\\{print\_int}(\|q)$;\5
+\&{goto} \37\\{done2};\6
+\&{end};\2\6
+\&{for} $\|q\K\|p\mathrel{\&{to}}\|p+\\{node\_size}(\|p)-1$ \1\&{do}\C{mark all
+locations free}\6
+\&{begin} \37\&{if} $\\{free}[\|q]$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"Doubly\ free\ location\ at\ "})$;\5
+$\\{print\_int}(\|q)$;\5
+\&{goto} \37\\{done2};\6
+\&{end};\2\6
+$\\{free}[\|q]\K\\{true}$;\6
+\&{end};\2\6
+$\|q\K\|p$;\5
+$\|p\K\\{rlink}(\|p)$;\6
+\4\&{until}\5
+$\|p=\\{rover}$;\2\6
+\4\\{done2}: \37\par
+\U173.\fi
+
+\M176. \P$\X176:Check flags of unavailable nodes\X\S$\6
+$\|p\K\\{mem\_min}$;\6
+\&{while} $\|p\L\\{lo\_mem\_max}$ \1\&{do}\C{node \|p should not be empty}\6
+\&{begin} \37\&{if} $\\{is\_empty}(\|p)$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"Bad\ flag\ at\ "})$;\5
+$\\{print\_int}(\|p)$;\6
+\&{end};\2\6
+\&{while} $(\|p\L\\{lo\_mem\_max})\W\R\\{free}[\|p]$ \1\&{do}\5
+$\\{incr}(\|p)$;\2\6
+\&{while} $(\|p\L\\{lo\_mem\_max})\W\\{free}[\|p]$ \1\&{do}\5
+$\\{incr}(\|p)$;\2\6
+\&{end}\2\par
+\U173.\fi
+
+\M177. \P$\X177:Print newly busy locations\X\S$\6
+\&{begin} \37$\\{print\_nl}(\.{"New\ busy\ locs:"})$;\6
+\&{for} $\|p\K\\{mem\_min}\mathrel{\&{to}}\\{lo\_mem\_max}$ \1\&{do}\6
+\&{if} $\R\\{free}[\|p]\W((\|p>\\{was\_lo\_max})\V\\{was\_free}[\|p])$ \1%
+\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{"\ "})$;\5
+$\\{print\_int}(\|p)$;\6
+\&{end};\2\2\6
+\&{for} $\|p\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\6
+\&{if} $\R\\{free}[\|p]\W((\|p<\\{was\_hi\_min})\V(\|p>\\{was\_mem\_end})\V%
+\\{was\_free}[\|p])$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{"\ "})$;\5
+$\\{print\_int}(\|p)$;\6
+\&{end};\2\2\6
+\&{end}\par
+\U173.\fi
+
+\M178. The \\{search\_mem} procedure attempts to answer the question ``Who
+points
+to node~\|p?'' In doing so, it fetches \\{link} and \\{info} fields of \\{mem}
+that might not be of type \\{two\_halves}. Strictly speaking, this is
+undefined in \PASCAL, and it can lead to ``false drops'' (words that seem to
+point to \|p purely by coincidence). But for debugging purposes, we want
+to rule out the places that do {\sl not\/} point to \|p, so a few false
+drops are tolerable.
+
+\Y\P\&{debug} \37\&{procedure}\1\  \37$\\{search\_mem}(\|p:\\{pointer})$;%
+\C{look for pointers to \|p}\6
+\4\&{var} \37\|q: \37\\{integer};\C{current position being searched}\2\6
+\&{begin} \37\&{for} $\|q\K\\{mem\_min}\mathrel{\&{to}}\\{lo\_mem\_max}$ \1%
+\&{do}\6
+\&{begin} \37\&{if} $\\{link}(\|q)=\|p$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"LINK("})$;\5
+$\\{print\_int}(\|q)$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\6
+\&{if} $\\{info}(\|q)=\|p$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"INFO("})$;\5
+$\\{print\_int}(\|q)$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{for} $\|q\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{link}(\|q)=\|p$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"LINK("})$;\5
+$\\{print\_int}(\|q)$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\6
+\&{if} $\\{info}(\|q)=\|p$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"INFO("})$;\5
+$\\{print\_int}(\|q)$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\6
+\&{end};\2\6
+\X261:Search \\{eqtb} for equivalents equal to \|p\X;\6
+\X291:Search \\{save\_stack} for equivalents that point to \|p\X;\6
+\X944:Search \\{hyph\_list} for pointers to \|p\X;\6
+\&{end};\6
+\&{gubed}\par
+\fi
+
+\N179.  \[12] Displaying boxes.
+We can reinforce our knowledge of the data structures just introduced
+by considering two procedures that display a list in symbolic form.
+The first of these, called \\{short\_display}, is used in ``overfull box''
+messages to give the top-level description of a list. The other one,
+called \\{show\_node\_list}, prints a detailed description of exactly what
+is in the data structure.
+
+The philosophy of \\{short\_display} is to ignore the fine points about exactly
+what is inside boxes, except that ligatures and discretionary breaks are
+expanded. As a result, \\{short\_display} is a recursive procedure, but the
+recursion is never more than one level deep.
+
+A global variable \\{font\_in\_short\_display} keeps track of the font code
+that
+is assumed to be present when \\{short\_display} begins; deviations from this
+font will be printed.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{font\_in\_short\_display}: \37\\{integer};\C{an internal font number}\par
+\fi
+
+\M180. Boxes, rules, inserts, whatsits, marks, and things in general that are
+sort of ``complicated'' are indicated only by printing `\.{[]}'.
+
+\Y\P\4\&{procedure}\1\  \37$\\{short\_display}(\|p:\\{integer})$;\C{prints
+highlights of list \|p}\6
+\4\&{var} \37\|n: \37\\{integer};\C{for replacement counts}\2\6
+\&{begin} \37\&{while} $\|p>\\{mem\_min}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{begin} \37\&{if} $\|p\L\\{mem\_end}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{font}(\|p)\I\\{font\_in\_short\_display}$ \1\&{then}\6
+\&{begin} \37\&{if} $(\\{font}(\|p)>\\{font\_max})$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\6
+\4\&{else} \X273:Print the font identifier for $\\{font}(\|p)$\X;\2\6
+$\\{print\_char}(\.{"\ "})$;\5
+$\\{font\_in\_short\_display}\K\\{font}(\|p)$;\6
+\&{end};\2\6
+\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{link}(\|p)$;\5
+$\\{print\_kanji}(\\{info}(\|p))$;\6
+\&{end}\6
+\4\&{else} $\\{print\_ASCII}(\\{qo}(\\{character}(\|p)))$;\2\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \X181:Print a short indication of the contents of node \|p\X;\2\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M181. \P$\X181:Print a short indication of the contents of node \|p\X\S$\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{ins\_node},\39%
+\\{whatsit\_node},\39\\{mark\_node},\39\\{adjust\_node},\39\\{unset\_node}$: %
+\37$\\{print}(\.{"[]"})$;\6
+\4\\{rule\_node}: \37$\\{print\_char}(\.{"|"})$;\6
+\4\\{glue\_node}: \37\&{if} $\\{glue\_ptr}(\|p)\I\\{zero\_glue}$ \1\&{then}\5
+$\\{print\_char}(\.{"\ "})$;\2\6
+\4\\{math\_node}: \37$\\{print\_char}(\.{"\$"})$;\6
+\4\\{ligature\_node}: \37$\\{short\_display}(\\{lig\_ptr}(\|p))$;\6
+\4\\{disc\_node}: \37\&{begin} \37$\\{short\_display}(\\{pre\_break}(\|p))$;\5
+$\\{short\_display}(\\{post\_break}(\|p))$;\6
+$\|n\K\\{replace\_count}(\|p)$;\6
+\&{while} $\|n>0$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{link}(\|p)\I\\{null}$ \1\&{then}\5
+$\|p\K\\{link}(\|p)$;\2\6
+$\\{decr}(\|n)$;\6
+\&{end};\2\6
+\&{end};\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases}\par
+\U180.\fi
+
+\M182. The \\{show\_node\_list} routine requires some auxiliary subroutines:
+one to
+print a font-and-character combination, one to print a token list without
+its reference count, and one to print a rule dimension.
+
+\Y\P\4\&{procedure}\1\  \37$\\{print\_font\_and\_char}(\|p:\\{integer})$;%
+\C{prints \\{char\_node} data}\2\6
+\&{begin} \37\&{if} $\|p>\\{mem\_end}$ \1\&{then}\5
+$\\{print\_esc}(\.{"CLOBBERED."})$\6
+\4\&{else} \&{begin} \37\&{if} $(\\{font}(\|p)>\\{font\_max})$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\6
+\4\&{else} \X273:Print the font identifier for $\\{font}(\|p)$\X;\2\6
+$\\{print\_char}(\.{"\ "})$;\6
+\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{link}(\|p)$;\5
+$\\{print\_kanji}(\\{info}(\|p))$;\6
+\&{end}\6
+\4\&{else} $\\{print\_ASCII}(\\{qo}(\\{character}(\|p)))$;\2\6
+\&{end};\2\6
+\&{end};\7
+\4\&{procedure}\1\  \37$\\{print\_mark}(\|p:\\{integer})$;\C{prints token list
+data in braces}\2\6
+\&{begin} \37$\\{print\_char}(\.{"\{"})$;\6
+\&{if} $(\|p<\\{hi\_mem\_min})\V(\|p>\\{mem\_end})$ \1\&{then}\5
+$\\{print\_esc}(\.{"CLOBBERED."})$\6
+\4\&{else} $\\{show\_token\_list}(\\{link}(\|p),\39\\{null},\39\\{max\_print%
+\_line}-10)$;\2\6
+$\\{print\_char}(\.{"\}"})$;\6
+\&{end};\7
+\4\&{procedure}\1\  \37$\\{print\_rule\_dimen}(\|d:\\{scaled})$;\C{prints
+dimension in rule node}\2\6
+\&{begin} \37\&{if} $\\{is\_running}(\|d)$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\6
+\4\&{else} $\\{print\_scaled}(\|d)$;\2\6
+\&{end};\par
+\fi
+
+\M183. Then there is a subroutine that prints glue stretch and shrink, possibly
+followed by the name of finite units:
+
+\Y\P\4\&{procedure}\1\  \37$\\{print\_glue}(\|d:\\{scaled};\,\35\\{order}:%
+\\{integer};\,\35\|s:\\{str\_number})$;\C{prints a glue component}\2\6
+\&{begin} \37$\\{print\_scaled}(\|d)$;\6
+\&{if} $(\\{order}<\\{normal})\V(\\{order}>\\{filll})$ \1\&{then}\5
+$\\{print}(\.{"foul"})$\6
+\4\&{else} \&{if} $\\{order}>\\{normal}$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"fil"})$;\6
+\&{while} $\\{order}>\\{fil}$ \1\&{do}\6
+\&{begin} \37$\\{print\_char}(\.{"l"})$;\5
+$\\{decr}(\\{order})$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|s\I0$ \1\&{then}\5
+$\\{print}(\|s)$;\2\2\2\6
+\&{end};\par
+\fi
+
+\M184. The next subroutine prints a whole glue specification.
+
+\Y\P\4\&{procedure}\1\  \37$\\{print\_spec}(\|p:\\{integer};\,\35\|s:\\{str%
+\_number})$;\C{prints a glue specification}\2\6
+\&{begin} \37\&{if} $(\|p<\\{mem\_min})\V(\|p\G\\{lo\_mem\_max})$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\6
+\4\&{else} \&{begin} \37$\\{print\_scaled}(\\{width}(\|p))$;\6
+\&{if} $\|s\I0$ \1\&{then}\5
+$\\{print}(\|s)$;\2\6
+\&{if} $\\{stretch}(\|p)\I0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ plus\ "})$;\5
+$\\{print\_glue}(\\{stretch}(\|p),\39\\{stretch\_order}(\|p),\39\|s)$;\6
+\&{end};\2\6
+\&{if} $\\{shrink}(\|p)\I0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ minus\ "})$;\5
+$\\{print\_glue}(\\{shrink}(\|p),\39\\{shrink\_order}(\|p),\39\|s)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M185. We also need to declare some procedures that appear later in this
+documentation.
+
+\Y\P\X702:Declare procedures needed for displaying the elements of mlists\X\6
+\X231:Declare the procedure called \\{print\_skip\_param}\X\par
+\fi
+
+\M186. Since boxes can be inside of boxes, \\{show\_node\_list} is inherently
+recursive,
+up to a given maximum number of levels.  The history of nesting is indicated
+by the current string, which will be printed at the beginning of each line;
+the length of this string, namely \\{cur\_length}, is the depth of nesting.
+
+Recursive calls on \\{show\_node\_list} therefore use the following pattern:
+
+\Y\P\D \37$\\{node\_list\_display}(\#)\S$\1\6
+\&{begin} \37$\\{append\_char}(\.{"."})$;\5
+$\\{show\_node\_list}(\#)$;\5
+\\{flush\_char};\6
+\&{end}\C{\\{str\_room} need not be checked; see \\{show\_box} below}\2\par
+\fi
+
+\M187. A global variable called \\{depth\_threshold} is used to record the
+maximum
+depth of nesting for which \\{show\_node\_list} will show information.  If we
+have $\\{depth\_threshold}=0$, for example, only the top level information will
+be given and no sublists will be traversed. Another global variable, called
+\\{breadth\_max}, tells the maximum number of items to show at each level;
+\\{breadth\_max} had better be positive, or you won't see anything.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{depth\_threshold}: \37\\{integer};\C{maximum nesting depth in box
+displays}\6
+\4\\{breadth\_max}: \37\\{integer};\C{maximum number of items shown at the same
+list level}\par
+\fi
+
+\M188. Now we are ready for \\{show\_node\_list} itself. This procedure has
+been
+written to be ``extra robust'' in the sense that it should not crash or get
+into a loop even if the data structures have been messed up by bugs in
+the rest of the program. You can safely call its parent routine
+$\\{show\_box}(\|p)$ for arbitrary values of \|p when you are debugging \TeX.
+However, in the presence of bad data, the procedure may
+fetch a \\{memory\_word} whose variant is different from the way it was stored;
+for example, it might try to read $\\{mem}[\|p].\\{hh}$ when $\\{mem}[\|p]$
+contains a scaled integer, if \|p is a pointer that has been
+clobbered or chosen at random.
+
+\Y\P\4\&{procedure}\1\  \37$\\{show\_node\_list}(\|p:\\{integer})$;\C{prints a
+node list symbolically}\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|n: \37\\{integer};\C{the number of items already printed at this
+level}\6
+\|g: \37\\{real};\C{a glue ratio, as a floating point number}\2\6
+\&{begin} \37\&{if} $\\{cur\_length}>\\{depth\_threshold}$ \1\&{then}\6
+\&{begin} \37\&{if} $\|p>\\{null}$ \1\&{then}\5
+$\\{print}(\.{"\ []"})$;\C{indicate that there's been some truncation}\2\6
+\&{return};\6
+\&{end};\2\6
+$\|n\K0$;\6
+\&{while} $\|p>\\{mem\_min}$ \1\&{do}\6
+\&{begin} \37\\{print\_ln};\5
+\\{print\_current\_string};\C{display the nesting history}\6
+\&{if} $\|p>\\{mem\_end}$ \1\&{then}\C{pointer out of range}\6
+\&{begin} \37$\\{print}(\.{"Bad\ link,\ display\ aborted."})$;\5
+\&{return};\6
+\&{end};\2\6
+$\\{incr}(\|n)$;\6
+\&{if} $\|n>\\{breadth\_max}$ \1\&{then}\C{time to stop}\6
+\&{begin} \37$\\{print}(\.{"etc."})$;\5
+\&{return};\6
+\&{end};\2\6
+\X189:Display node \|p\X;\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M189. \P$\X189:Display node \|p\X\S$\6
+\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{begin} \37$\\{print\_font\_and\_char}(\|p)$;\6
+\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}\5
+$\|p\K\\{link}(\|p)$\2\6
+\&{end}\6
+\4\&{else} \&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{unset\_node}$: \37%
+\X190:Display box \|p\X;\6
+\4\\{rule\_node}: \37\X193:Display rule \|p\X;\6
+\4\\{ins\_node}: \37\X194:Display insertion \|p\X;\6
+\4\\{whatsit\_node}: \37\X1369:Display the whatsit node \|p\X;\6
+\4\\{disp\_node}: \37\&{begin} \37$\\{print\_esc}(\.{"displace\ "})$;\5
+$\\{print\_scaled}(\\{disp\_dimen}(\|p))$;\6
+\&{end};\6
+\4\\{glue\_node}: \37\X195:Display glue \|p\X;\6
+\4\\{kern\_node}: \37\X197:Display kern \|p\X;\6
+\4\\{math\_node}: \37\X198:Display math node \|p\X;\6
+\4\\{ligature\_node}: \37\X199:Display ligature \|p\X;\6
+\4\\{penalty\_node}: \37\X200:Display penalty \|p\X;\6
+\4\\{disc\_node}: \37\X201:Display discretionary \|p\X;\6
+\4\\{mark\_node}: \37\X202:Display mark \|p\X;\6
+\4\\{adjust\_node}: \37\X203:Display adjustment \|p\X;\6
+\hbox{\4}\X701:Cases of \\{show\_node\_list} that arise in mlists only\X\6
+\4\&{othercases} \37$\\{print}(\.{"Unknown\ node\ type!"})$\2\6
+\&{endcases}\2\par
+\U188.\fi
+
+\M190. \P$\X190:Display box \|p\X\S$\6
+\&{begin} \37\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4\\{hlist\_node}: \37$\\{print\_esc}(\.{"h"})$;\6
+\4\\{vlist\_node}: \37$\\{print\_esc}(\.{"v"})$;\6
+\4\\{dir\_node}: \37$\\{print\_esc}(\.{"dir"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"unset"})$\2\6
+\&{endcases}\6
+;\5
+$\\{print}(\.{"box("})$;\5
+$\\{print\_scaled}(\\{height}(\|p))$;\5
+$\\{print\_char}(\.{"+"})$;\5
+$\\{print\_scaled}(\\{depth}(\|p))$;\5
+$\\{print}(\.{")x"})$;\5
+$\\{print\_scaled}(\\{width}(\|p))$;\6
+\&{if} $\\{type}(\|p)=\\{unset\_node}$ \1\&{then}\5
+\X191:Display special fields of the unset node \|p\X\6
+\4\&{else} \&{begin} \37\X192:Display the value of $\\{glue\_set}(\|p)$\X;\6
+\&{if} $\\{shift\_amount}(\|p)\I0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{",\ shifted\ "})$;\5
+$\\{print\_scaled}(\\{shift\_amount}(\|p))$;\6
+\&{end};\2\6
+\&{if} $\\{box\_dir}(\|p)\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{",\ "})$;\5
+$\\{print\_direction}(\\{box\_dir}(\|p))$;\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{node\_list\_display}(\\{list\_ptr}(\|p))$;\C{recursive call}\6
+\&{end}\par
+\U189.\fi
+
+\M191. \P$\X191:Display special fields of the unset node \|p\X\S$\6
+\&{begin} \37\&{if} $\\{span\_count}(\|p)\I\\{min\_quarterword}$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ ("})$;\5
+$\\{print\_int}(\\{qo}(\\{span\_count}(\|p))+1)$;\5
+$\\{print}(\.{"\ columns)"})$;\6
+\&{end};\2\6
+\&{if} $\\{glue\_stretch}(\|p)\I0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{",\ stretch\ "})$;\5
+$\\{print\_glue}(\\{glue\_stretch}(\|p),\39\\{glue\_order}(\|p),\390)$;\6
+\&{end};\2\6
+\&{if} $\\{glue\_shrink}(\|p)\I0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{",\ shrink\ "})$;\5
+$\\{print\_glue}(\\{glue\_shrink}(\|p),\39\\{glue\_sign}(\|p),\390)$;\6
+\&{end};\2\6
+\&{end}\par
+\U190.\fi
+
+\M192. The code will have to change in this place if \\{glue\_ratio} is
+a structured type instead of an ordinary \\{real}. Note that this routine
+should avoid arithmetic errors even if the \\{glue\_set} field holds an
+arbitrary random value. The following code assumes that a properly
+formed nonzero \\{real} number has absolute value $2^{20}$ or more when
+it is regarded as an integer; this precaution was adequate to prevent
+floating point underflow on the author's computer.
+
+\Y\P$\4\X192:Display the value of $\\{glue\_set}(\|p)$\X\S$\6
+$\|g\K\\{float}(\\{glue\_set}(\|p))$;\6
+\&{if} $(\|g\I\\{float\_constant}(0))\W(\\{glue\_sign}(\|p)\I\\{normal})$ \1%
+\&{then}\6
+\&{begin} \37$\\{print}(\.{",\ glue\ set\ "})$;\6
+\&{if} $\\{glue\_sign}(\|p)=\\{shrinking}$ \1\&{then}\5
+$\\{print}(\.{"-\ "})$;\C{ The Unix \\{pc} folks removed this restriction with
+a remark that     invalid bit patterns were vanishingly improbable, so we
+follow     their example without really understanding it.    \&{if} $\\{abs}(%
+\\{mem}[\|p+\\{glue\_offset}].\\{int})<\O{4000000}$ \&{then} $\\{print}(\.{%
+\'?.?\'})$ \&{else}  }\2\6
+\&{if} $\\{fabs}(\|g)>\\{float\_constant}(20000)$ \1\&{then}\6
+\&{begin} \37\&{if} $\|g>\\{float\_constant}(0)$ \1\&{then}\5
+$\\{print\_char}(\.{">"})$\6
+\4\&{else} $\\{print}(\.{"<\ -"})$;\2\6
+$\\{print\_glue}(20000\ast\\{unity},\39\\{glue\_order}(\|p),\390)$;\6
+\&{end}\6
+\4\&{else} $\\{print\_glue}(\\{round}(\\{unity}\ast\|g),\39\\{glue\_order}(%
+\|p),\390)$;\2\6
+\&{end}\2\par
+\U190.\fi
+
+\M193. \P$\X193:Display rule \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{"rule("})$;\5
+$\\{print\_rule\_dimen}(\\{height}(\|p))$;\5
+$\\{print\_char}(\.{"+"})$;\5
+$\\{print\_rule\_dimen}(\\{depth}(\|p))$;\5
+$\\{print}(\.{")x"})$;\5
+$\\{print\_rule\_dimen}(\\{width}(\|p))$;\6
+\&{end}\par
+\U189.\fi
+
+\M194. \P$\X194:Display insertion \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{"insert"})$;\5
+$\\{print\_int}(\\{qo}(\\{subtype}(\|p)))$;\5
+$\\{print\_dir}(\\{ins\_dir}(\|p))$;\5
+$\\{print}(\.{",\ natural\ size\ "})$;\5
+$\\{print\_scaled}(\\{height}(\|p))$;\5
+$\\{print}(\.{";\ split("})$;\5
+$\\{print\_spec}(\\{split\_top\_ptr}(\|p),\390)$;\5
+$\\{print\_char}(\.{","})$;\5
+$\\{print\_scaled}(\\{depth}(\|p))$;\5
+$\\{print}(\.{");\ float\ cost\ "})$;\5
+$\\{print\_int}(\\{float\_cost}(\|p))$;\5
+$\\{node\_list\_display}(\\{ins\_ptr}(\|p))$;\C{recursive call}\6
+\&{end}\par
+\U189.\fi
+
+\M195. \P$\X195:Display glue \|p\X\S$\6
+\&{if} $\\{subtype}(\|p)\G\\{a\_leaders}$ \1\&{then}\5
+\X196:Display leaders \|p\X\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"glue"})$;\6
+\&{if} $\\{subtype}(\|p)\I\\{normal}$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{"("})$;\6
+\&{if} $\\{subtype}(\|p)<\\{cond\_math\_glue}$ \1\&{then}\5
+$\\{print\_skip\_param}(\\{subtype}(\|p)-1)$\6
+\4\&{else} \&{if} $\\{subtype}(\|p)=\\{cond\_math\_glue}$ \1\&{then}\5
+$\\{print\_esc}(\.{"nonscript"})$\6
+\4\&{else} $\\{print\_esc}(\.{"mskip"})$;\2\2\6
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\6
+\&{if} $\\{subtype}(\|p)\I\\{cond\_math\_glue}$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{"\ "})$;\6
+\&{if} $\\{subtype}(\|p)<\\{cond\_math\_glue}$ \1\&{then}\5
+$\\{print\_spec}(\\{glue\_ptr}(\|p),\390)$\6
+\4\&{else} $\\{print\_spec}(\\{glue\_ptr}(\|p),\39\.{"mu"})$;\2\6
+\&{end};\2\6
+\&{end}\2\par
+\U189.\fi
+
+\M196. \P$\X196:Display leaders \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{""})$;\6
+\&{if} $\\{subtype}(\|p)=\\{c\_leaders}$ \1\&{then}\5
+$\\{print\_char}(\.{"c"})$\6
+\4\&{else} \&{if} $\\{subtype}(\|p)=\\{x\_leaders}$ \1\&{then}\5
+$\\{print\_char}(\.{"x"})$;\2\2\6
+$\\{print}(\.{"leaders\ "})$;\5
+$\\{print\_spec}(\\{glue\_ptr}(\|p),\390)$;\5
+$\\{node\_list\_display}(\\{leader\_ptr}(\|p))$;\C{recursive call}\6
+\&{end}\par
+\U195.\fi
+
+\M197. An ``explicit'' kern value is indicated implicitly by an explicit space.
+
+\Y\P$\4\X197:Display kern \|p\X\S$\6
+\&{if} $\\{subtype}(\|p)\I\\{mu\_glue}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"kern"})$;\6
+\&{if} $\\{subtype}(\|p)\I\\{normal}$ \1\&{then}\5
+$\\{print\_char}(\.{"\ "})$;\2\6
+$\\{print\_scaled}(\\{width}(\|p))$;\6
+\&{if} $\\{subtype}(\|p)=\\{acc\_kern}$ \1\&{then}\5
+$\\{print}(\.{"\ (for\ accent)"})$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"mkern"})$;\5
+$\\{print\_scaled}(\\{width}(\|p))$;\5
+$\\{print}(\.{"mu"})$;\6
+\&{end}\2\par
+\U189.\fi
+
+\M198. \P$\X198:Display math node \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{"math"})$;\6
+\&{if} $\\{subtype}(\|p)=\\{before}$ \1\&{then}\5
+$\\{print}(\.{"on"})$\6
+\4\&{else} $\\{print}(\.{"off"})$;\2\6
+\&{if} $\\{width}(\|p)\I0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{",\ surrounded\ "})$;\5
+$\\{print\_scaled}(\\{width}(\|p))$;\6
+\&{end};\2\6
+\&{end}\par
+\U189.\fi
+
+\M199. \P$\X199:Display ligature \|p\X\S$\6
+\&{begin} \37$\\{print\_font\_and\_char}(\\{lig\_char}(\|p))$;\5
+$\\{print}(\.{"\ (ligature\ "})$;\6
+\&{if} $\\{subtype}(\|p)>1$ \1\&{then}\5
+$\\{print\_char}(\.{"|"})$;\2\6
+$\\{font\_in\_short\_display}\K\\{font}(\\{lig\_char}(\|p))$;\5
+$\\{short\_display}(\\{lig\_ptr}(\|p))$;\6
+\&{if} $\\{odd}(\\{subtype}(\|p))$ \1\&{then}\5
+$\\{print\_char}(\.{"|"})$;\2\6
+$\\{print\_char}(\.{")"})$;\6
+\&{end}\par
+\U189.\fi
+
+\M200. \P$\X200:Display penalty \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{"penalty\ "})$;\5
+$\\{print\_int}(\\{penalty}(\|p))$;\6
+\&{if} $\\{subtype}(\|p)=\\{widow\_pena}$ \1\&{then}\5
+$\\{print}(\.{"(for\ \\jchrwidowpenalty)"})$\6
+\4\&{else} \&{if} $\\{subtype}(\|p)=\\{kinsoku\_pena}$ \1\&{then}\5
+$\\{print}(\.{"(for\ kinsoku)"})$;\2\2\6
+\&{end}\par
+\U189.\fi
+
+\M201. The \\{post\_break} list of a discretionary node is indicated by a
+prefixed
+`\.{\char'174}' instead of the `\..' before the \\{pre\_break} list.
+
+\Y\P$\4\X201:Display discretionary \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{"discretionary"})$;\6
+\&{if} $\\{replace\_count}(\|p)>0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ replacing\ "})$;\5
+$\\{print\_int}(\\{replace\_count}(\|p))$;\6
+\&{end};\2\6
+$\\{node\_list\_display}(\\{pre\_break}(\|p))$;\C{recursive call}\6
+$\\{append\_char}(\.{"|"})$;\5
+$\\{show\_node\_list}(\\{post\_break}(\|p))$;\5
+\\{flush\_char};\C{recursive call}\6
+\&{end}\par
+\U189.\fi
+
+\M202. \P$\X202:Display mark \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{"mark"})$;\5
+$\\{print\_mark}(\\{mark\_ptr}(\|p))$;\6
+\&{end}\par
+\U189.\fi
+
+\M203. \P$\X203:Display adjustment \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{"vadjust"})$;\5
+$\\{node\_list\_display}(\\{adjust\_ptr}(\|p))$;\C{recursive call}\6
+\&{end}\par
+\U189.\fi
+
+\M204. The recursive machinery is started by calling \\{show\_box}.
+
+\Y\P\4\&{procedure}\1\  \37$\\{show\_box}(\|p:\\{pointer})$;\2\6
+\&{begin} \37\X242:Assign the values $\\{depth\_threshold}\K\\{show\_box%
+\_depth}$ and $\\{breadth\_max}\K\\{show\_box\_breadth}$\X;\6
+\&{if} $\\{breadth\_max}\L0$ \1\&{then}\5
+$\\{breadth\_max}\K5$;\2\6
+\&{if} $\\{pool\_ptr}+\\{depth\_threshold}\G\\{pool\_size}$ \1\&{then}\5
+$\\{depth\_threshold}\K\\{pool\_size}-\\{pool\_ptr}-1$;\C{now there's enough
+room for prefix string}\2\6
+$\\{show\_node\_list}(\|p)$;\C{the show starts at \|p}\6
+\\{print\_ln};\6
+\&{end};\par
+\fi
+
+\N205.  \[13] Destroying boxes.
+When we are done with a node list, we are obliged to return it to free
+storage, including all of its sublists. The recursive procedure
+\\{flush\_node\_list} does this for us.
+
+\fi
+
+\M206. First, however, we shall consider two non-recursive procedures that do
+simpler tasks. The first of these, \\{delete\_token\_ref}, is called when
+a pointer to a token list's reference count is being removed. This means
+that the token list should disappear if the reference count was \\{null},
+otherwise the count should be decreased by one.
+
+\Y\P\D \37$\\{token\_ref\_count}(\#)\S\\{info}(\#)$\C{reference count preceding
+a token list}\par
+\Y\P\4\&{procedure}\1\  \37$\\{delete\_token\_ref}(\|p:\\{pointer})$;\C{\|p
+points to the reference count   of a token list that is losing one reference}\2%
+\6
+\&{begin} \37\&{if} $\\{token\_ref\_count}(\|p)=\\{null}$ \1\&{then}\5
+$\\{flush\_list}(\|p)$\6
+\4\&{else} $\\{decr}(\\{token\_ref\_count}(\|p))$;\2\6
+\&{end};\par
+\fi
+
+\M207. Similarly, \\{delete\_glue\_ref} is called when a pointer to a glue
+specification is being withdrawn.
+\Y\P\D \37$\\{fast\_delete\_glue\_ref}(\#)\S\hbox{}$\6
+\&{begin} \37\&{if} $\\{glue\_ref\_count}(\#)=\\{null}$ \1\&{then}\5
+$\\{free\_node}(\#,\39\\{glue\_spec\_size})$\6
+\4\&{else} $\\{decr}(\\{glue\_ref\_count}(\#))$;\2\6
+\&{end}\par
+\Y\P\4\&{procedure}\1\  \37$\\{delete\_glue\_ref}(\|p:\\{pointer})$;\C{\|p
+points to a glue specification}\6
+$\\{fast\_delete\_glue\_ref}(\|p)$;\par
+\fi
+
+\M208. Now we are ready to delete any node list, recursively.
+In practice, the nodes deleted are usually charnodes (about 2/3 of the time),
+and they are glue nodes in about half of the remaining cases.
+
+\Y\P\4\&{procedure}\1\  \37$\\{flush\_node\_list}(\|p:\\{pointer})$;\C{erase
+list of nodes starting at \|p}\6
+\4\&{label} \37\\{done};\C{go here when node \|p has been freed}\6
+\4\&{var} \37\|q: \37\\{pointer};\C{successor to node \|p}\2\6
+\&{begin} \37\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\|q\K\\{link}(\|p)$;\6
+\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\5
+$\\{free\_avail}(\|p)$\6
+\4\&{else} \&{begin} \37\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{unset\_node}$: \37%
+\&{begin} \37$\\{flush\_node\_list}(\\{list\_ptr}(\|p))$;\5
+$\\{fast\_delete\_glue\_ref}(\\{space\_ptr}(\|p))$;\5
+$\\{fast\_delete\_glue\_ref}(\\{xspace\_ptr}(\|p))$;\5
+$\\{free\_node}(\|p,\39\\{box\_node\_size})$;\5
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4\\{rule\_node}: \37\&{begin} \37$\\{free\_node}(\|p,\39\\{rule\_node%
+\_size})$;\5
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4\\{ins\_node}: \37\&{begin} \37$\\{flush\_node\_list}(\\{ins\_ptr}(\|p))$;\5
+$\\{delete\_glue\_ref}(\\{split\_top\_ptr}(\|p))$;\5
+$\\{free\_node}(\|p,\39\\{ins\_node\_size})$;\5
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4\\{whatsit\_node}: \37\X1371:Wipe out the whatsit node \|p and \&{goto} %
+\\{done}\X;\6
+\4\\{glue\_node}: \37\&{begin} \37$\\{fast\_delete\_glue\_ref}(\\{glue\_ptr}(%
+\|p))$;\6
+\&{if} $\\{leader\_ptr}(\|p)\I\\{null}$ \1\&{then}\5
+$\\{flush\_node\_list}(\\{leader\_ptr}(\|p))$;\2\6
+\&{end};\6
+\4$\\{disp\_node},\39\\{kern\_node},\39\\{math\_node},\39\\{penalty\_node}$: %
+\37\\{do\_nothing};\6
+\4\\{ligature\_node}: \37$\\{flush\_node\_list}(\\{lig\_ptr}(\|p))$;\6
+\4\\{mark\_node}: \37$\\{delete\_token\_ref}(\\{mark\_ptr}(\|p))$;\6
+\4\\{disc\_node}: \37\&{begin} \37$\\{flush\_node\_list}(\\{pre\_break}(\|p))$;%
+\5
+$\\{flush\_node\_list}(\\{post\_break}(\|p))$;\6
+\&{end};\6
+\4\\{adjust\_node}: \37$\\{flush\_node\_list}(\\{adjust\_ptr}(\|p))$;\6
+\hbox{\4}\X709:Cases of \\{flush\_node\_list} that arise in mlists only\X\6
+\4\&{othercases} \37$\\{confusion}(\.{"flushing"})$\2\6
+\&{endcases};\6
+$\\{free\_node}(\|p,\39\\{small\_node\_size})$;\6
+\4\\{done}: \37\&{end};\2\6
+$\|p\K\|q$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\N209.  \[14] Copying boxes.
+Another recursive operation that acts on boxes is sometimes needed: The
+procedure \\{copy\_node\_list} returns a pointer to another node list that has
+the same structure and meaning as the original. Note that since glue
+specifications and token lists have reference counts, we need not make
+copies of them. Reference counts can never get too large to fit in a
+halfword, since each pointer to a node is in a different memory address,
+and the total number of memory addresses fits in a halfword.
+
+(Well, there actually are also references from outside \\{mem}; if the
+\\{save\_stack} is made arbitrarily large, it would theoretically be possible
+to break \TeX\ by overflowing a reference count. But who would want to do
+that?)
+
+\Y\P\D \37$\\{add\_token\_ref}(\#)\S\\{incr}(\\{token\_ref\_count}(\#))$\C{new
+reference to a token list}\par
+\P\D \37$\\{add\_glue\_ref}(\#)\S\\{incr}(\\{glue\_ref\_count}(\#))$\C{new
+reference to a glue spec}\par
+\fi
+
+\M210. The copying procedure copies words en masse without bothering
+to look at their individual fields. If the node format changes---for
+example, if the size is altered, or if some link field is moved to another
+relative position---then this code may need to be changed too.
+
+\Y\P\4\&{function}\1\  \37$\\{copy\_node\_list}(\|p:\\{pointer})$: \37%
+\\{pointer};\C{makes a duplicate of the   node list that starts at \|p and
+returns a pointer to the new list}\6
+\4\&{var} \37\|h: \37\\{pointer};\C{temporary head of copied list}\6
+\|q: \37\\{pointer};\C{previous position in new list}\6
+\|r: \37\\{pointer};\C{current node being fabricated for new list}\6
+\\{words}: \37$0\to5$;\C{number of words remaining to be copied}\2\6
+\&{begin} \37$\|h\K\\{get\_avail}$;\5
+$\|q\K\|h$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\X211:Make a copy of node \|p in node \|r\X;\6
+$\\{link}(\|q)\K\|r$;\5
+$\|q\K\|r$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+$\\{link}(\|q)\K\\{null}$;\5
+$\|q\K\\{link}(\|h)$;\5
+$\\{free\_avail}(\|h)$;\5
+$\\{copy\_node\_list}\K\|q$;\6
+\&{end};\par
+\fi
+
+\M211. \P$\X211:Make a copy of node \|p in node \|r\X\S$\6
+$\\{words}\K1$;\C{this setting occurs in more branches than any other}\6
+\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\5
+$\|r\K\\{get\_avail}$\6
+\4\&{else} \X212:Case statement to copy different types and set \\{words} to
+the number of initial words not yet copied\X;\2\6
+\&{while} $\\{words}>0$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\\{words})$;\5
+$\\{mem}[\|r+\\{words}]\K\\{mem}[\|p+\\{words}]$;\6
+\&{end}\2\par
+\U210.\fi
+
+\M212. \P$\X212:Case statement to copy different types and set \\{words} to the
+number of initial words not yet copied\X\S$\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{dir\_node},\39\\{hlist\_node},\39\\{vlist\_node},\39\\{unset\_node}$: \37%
+\&{begin} \37$\|r\K\\{get\_node}(\\{box\_node\_size})$;\5
+$\\{mem}[\|r+7]\K\\{mem}[\|p+7]$;\5
+$\\{mem}[\|r+6]\K\\{mem}[\|p+6]$;\5
+$\\{mem}[\|r+5]\K\\{mem}[\|p+5]$;\C{copy the last three words}\6
+$\\{add\_glue\_ref}(\\{space\_ptr}(\|r))$;\5
+$\\{add\_glue\_ref}(\\{xspace\_ptr}(\|r))$;\5
+$\\{list\_ptr}(\|r)\K\\{copy\_node\_list}(\\{list\_ptr}(\|p))$;\C{this affects
+$\\{mem}[\|r+5]$}\6
+$\\{words}\K5$;\6
+\&{end};\6
+\4\\{rule\_node}: \37\&{begin} \37$\|r\K\\{get\_node}(\\{rule\_node\_size})$;\5
+$\\{words}\K\\{rule\_node\_size}$;\6
+\&{end};\6
+\4\\{ins\_node}: \37\&{begin} \37$\|r\K\\{get\_node}(\\{ins\_node\_size})$;\5
+$\\{mem}[\|r+5]\K\\{mem}[\|p+5]$;\5
+$\\{mem}[\|r+4]\K\\{mem}[\|p+4]$;\5
+$\\{add\_glue\_ref}(\\{split\_top\_ptr}(\|p))$;\5
+$\\{ins\_ptr}(\|r)\K\\{copy\_node\_list}(\\{ins\_ptr}(\|p))$;\C{this affects $%
+\\{mem}[\|r+4]$}\6
+$\\{words}\K\\{ins\_node\_size}-2$;\6
+\&{end};\6
+\4\\{whatsit\_node}: \37\X1370:Make a partial copy of the whatsit node \|p and
+make \|r point to it; set \\{words} to the number of initial words not yet
+copied\X;\6
+\4\\{glue\_node}: \37\&{begin} \37$\|r\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{add\_glue\_ref}(\\{glue\_ptr}(\|p))$;\5
+$\\{glue\_ptr}(\|r)\K\\{glue\_ptr}(\|p)$;\5
+$\\{leader\_ptr}(\|r)\K\\{copy\_node\_list}(\\{leader\_ptr}(\|p))$;\6
+\&{end};\6
+\4$\\{disp\_node},\39\\{kern\_node},\39\\{math\_node},\39\\{penalty\_node}$: %
+\37\&{begin} \37$\|r\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{words}\K\\{small\_node\_size}$;\6
+\&{end};\6
+\4\\{ligature\_node}: \37\&{begin} \37$\|r\K\\{get\_node}(\\{small\_node%
+\_size})$;\5
+$\\{mem}[\\{lig\_char}(\|r)]\K\\{mem}[\\{lig\_char}(\|p)]$;\C{copy \\{font} and
+\\{character}}\6
+$\\{lig\_ptr}(\|r)\K\\{copy\_node\_list}(\\{lig\_ptr}(\|p))$;\6
+\&{end};\6
+\4\\{disc\_node}: \37\&{begin} \37$\|r\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{pre\_break}(\|r)\K\\{copy\_node\_list}(\\{pre\_break}(\|p))$;\5
+$\\{post\_break}(\|r)\K\\{copy\_node\_list}(\\{post\_break}(\|p))$;\6
+\&{end};\6
+\4\\{mark\_node}: \37\&{begin} \37$\|r\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{add\_token\_ref}(\\{mark\_ptr}(\|p))$;\5
+$\\{words}\K\\{small\_node\_size}$;\6
+\&{end};\6
+\4\\{adjust\_node}: \37\&{begin} \37$\|r\K\\{get\_node}(\\{small\_node%
+\_size})$;\5
+$\\{adjust\_ptr}(\|r)\K\\{copy\_node\_list}(\\{adjust\_ptr}(\|p))$;\6
+\&{end};\C{$\\{words}=1=\\{small\_node\_size}-1$}\6
+\4\&{othercases} \37$\\{confusion}(\.{"copying"})$\2\6
+\&{endcases}\par
+\U211.\fi
+
+\N213.  \[15] The command codes.
+Before we can go any further, we need to define symbolic names for the internal
+code numbers that represent the various commands obeyed by \TeX. These codes
+are somewhat arbitrary, but not completely so. For example, the command
+codes for character types are fixed by the language, since a user says,
+e.g., `\.{\\catcode \`\\\${} = 3}' to make \.{\char'44} a math delimiter,
+and the command code \\{math\_shift} is equal to~3. Some other codes have
+been made adjacent so that   \&{case}  statements in the program need not
+consider
+cases that are widely spaced, or so that   \&{case}  statements can be replaced
+by   \&{if}  statements.
+
+At any rate, here is the list, for future reference. First come the
+``catcode'' commands, several of which share their numeric codes with
+ordinary commands when the catcode cannot emerge from \TeX's scanning routine.
+
+\Y\P\D \37$\\{escape}=0$\C{escape delimiter (called \.\\ in {\sl The \TeX book%
+\/})}\par
+\P\D \37$\\{relax}=0$\C{do nothing ( \.{\\relax} )}\par
+\P\D \37$\\{left\_brace}=1$\C{beginning of a group ( \.\{ )}\par
+\P\D \37$\\{right\_brace}=2$\C{ending of a group ( \.\} )}\par
+\P\D \37$\\{math\_shift}=3$\C{mathematics shift character ( \.\$ )}\par
+\P\D \37$\\{tab\_mark}=4$\C{alignment delimiter ( \.\&, \.{\\span} )}\par
+\P\D \37$\\{car\_ret}=5$\C{end of line ( \\{carriage\_return}, \.{\\cr}, \.{%
+\\crcr} )}\par
+\P\D \37$\\{out\_param}=5$\C{output a macro parameter}\par
+\P\D \37$\\{mac\_param}=6$\C{macro parameter symbol ( \.\# )}\par
+\P\D \37$\\{sup\_mark}=7$\C{superscript ( \.{\char'136} )}\par
+\P\D \37$\\{sub\_mark}=8$\C{subscript ( \.{\char'137} )}\par
+\P\D \37$\\{ignore}=9$\C{characters to ignore ( \.{\^\^@} )}\par
+\P\D \37$\\{endv}=9$\C{end of \<v_j> list in alignment template}\par
+\P\D \37$\\{spacer}=10$\C{characters equivalent to blank space ( \.{\ } )}\par
+\P\D \37$\\{letter}=11$\C{characters regarded as letters ( \.{A..Z}, \.{a..z}
+)}\par
+\P\D \37$\\{other\_char}=12$\C{none of the special character types}\par
+\P\D \37$\\{active\_char}=13$\C{characters that invoke macros ( \.{\char`\~} )}%
+\par
+\P\D \37$\\{par\_end}=13$\C{end of paragraph ( \.{\\par} )}\par
+\P\D \37$\\{match}=13$\C{match a macro parameter}\par
+\P\D \37$\\{comment}=14$\C{characters that introduce comments ( \.\% )}\par
+\P\D \37$\\{end\_match}=14$\C{end of parameters to macro}\par
+\P\D \37$\\{stop}=14$\C{end of job ( \.{\\end}, \.{\\dump} )}\par
+\P\D \37$\\{invalid\_char}=15$\C{characters that shouldn't appear ( \.{\^\^?}
+)}\par
+\P\D \37$\\{delim\_num}=15$\C{specify delimiter numerically ( \.{\\delimiter}
+)}\par
+\P\D \37$\\{kanji}=16$\C{kanji}\par
+\P\D \37$\\{kana}=17$\C{hiragana, katakana, alphabet}\par
+\P\D \37$\\{other\_kchar}=18$\C{kanji codes}\par
+\P\D \37$\\{max\_char\_code}=18$\C{largest catcode for individual characters}%
+\par
+\fi
+
+\M214. Next are the ordinary run-of-the-mill command codes.  Codes that are
+\\{min\_internal} or more represent internal quantities that might be
+expanded by `\.{\\the}'.
+
+\Y\P\D \37$\\{char\_num}=\\{max\_char\_code}+1$\C{character specified
+numerically ( \.{\\char} )}\par
+\P\D \37$\\{math\_char\_num}=\\{char\_num}+1$\C{explicit math code ( \.{%
+\\mathchar} )}\par
+\P\D \37$\\{mark}=\\{math\_char\_num}+1$\C{mark definition ( \.{\\mark} )}\par
+\P\D \37$\\{xray}=\\{mark}+1$\C{peek inside of \TeX\ ( \.{\\show}, \.{%
+\\showbox}, etc.~)}\par
+\P\D \37$\\{make\_box}=\\{xray}+1$\C{make a box ( \.{\\box}, \.{\\copy}, \.{%
+\\hbox}, etc.~)}\par
+\P\D \37$\\{hmove}=\\{make\_box}+1$\C{horizontal motion ( \.{\\moveleft}, \.{%
+\\moveright} )}\par
+\P\D \37$\\{vmove}=\\{hmove}+1$\C{vertical motion ( \.{\\raise}, \.{\\lower} )}%
+\par
+\P\D \37$\\{un\_hbox}=\\{vmove}+1$\C{unglue a box ( \.{\\unhbox}, \.{\\unhcopy}
+)}\par
+\P\D \37$\\{un\_vbox}=\\{un\_hbox}+1$\C{unglue a box ( \.{\\unvbox}, \.{%
+\\unvcopy} )}\par
+\P\D \37$\\{remove\_item}=\\{un\_vbox}+1$\C{nullify last item ( \.{%
+\\unpenalty},   \.{\\unkern}, \.{\\unskip} )}\par
+\P\D \37$\\{hskip}=\\{remove\_item}+1$\C{horizontal glue ( \.{\\hskip}, \.{%
+\\hfil}, etc.~)}\par
+\P\D \37$\\{vskip}=\\{hskip}+1$\C{vertical glue ( \.{\\vskip}, \.{\\vfil},
+etc.~)}\par
+\P\D \37$\\{mskip}=\\{vskip}+1$\C{math glue ( \.{\\mskip} )}\par
+\P\D \37$\\{kern}=\\{mskip}+1$\C{fixed space ( \.{\\kern})}\par
+\P\D \37$\\{mkern}=\\{kern}+1$\C{math kern ( \.{\\mkern} )}\par
+\P\D \37$\\{leader\_ship}=\\{mkern}+1$\C{use a box ( \.{\\shipout}, \.{%
+\\leaders}, etc.~)}\par
+\P\D \37$\\{halign}=\\{leader\_ship}+1$\C{horizontal table alignment ( \.{%
+\\halign} )}\par
+\P\D \37$\\{valign}=\\{halign}+1$\C{vertical table alignment ( \.{\\valign} )}%
+\par
+\P\D \37$\\{no\_align}=\\{valign}+1$\C{temporary escape from alignment ( \.{%
+\\noalign} )}\par
+\P\D \37$\\{vrule}=\\{no\_align}+1$\C{vertical rule ( \.{\\vrule} )}\par
+\P\D \37$\\{hrule}=\\{vrule}+1$\C{horizontal rule ( \.{\\hrule} )}\par
+\P\D \37$\\{insert}=\\{hrule}+1$\C{vlist inserted in box ( \.{\\insert} )}\par
+\P\D \37$\\{vadjust}=\\{insert}+1$\C{vlist inserted in enclosing paragraph ( %
+\.{\\vadjust} )}\par
+\P\D \37$\\{ignore\_spaces}=\\{vadjust}+1$\C{gobble \\{spacer} tokens ( \.{%
+\\ignorespaces} )}\par
+\P\D \37$\\{after\_assignment}=\\{ignore\_spaces}+1$\C{save till assignment is
+done ( \.{\\afterassignment} )}\par
+\P\D \37$\\{after\_group}=\\{after\_assignment}+1$\C{save till group is done ( %
+\.{\\aftergroup} )}\par
+\P\D \37$\\{break\_penalty}=\\{after\_group}+1$\C{additional badness ( \.{%
+\\penalty} )}\par
+\P\D \37$\\{start\_par}=\\{break\_penalty}+1$\C{begin paragraph ( \.{\\indent},
+\.{\\noindent} )}\par
+\P\D \37$\\{ital\_corr}=\\{start\_par}+1$\C{italic correction ( \.{\\/} )}\par
+\P\D \37$\\{accent}=\\{ital\_corr}+1$\C{attach accent in text ( \.{\\accent} )}%
+\par
+\P\D \37$\\{math\_accent}=\\{accent}+1$\C{attach accent in math ( \.{%
+\\mathaccent} )}\par
+\P\D \37$\\{discretionary}=\\{math\_accent}+1$\C{discretionary texts ( \.{\\-},
+\.{\\discretionary} )}\par
+\P\D \37$\\{eq\_no}=\\{discretionary}+1$\C{equation number ( \.{\\eqno}, \.{%
+\\leqno} )}\par
+\P\D \37$\\{left\_right}=\\{eq\_no}+1$\C{variable delimiter ( \.{\\left}, \.{%
+\\right} )}\par
+\P\D \37$\\{math\_comp}=\\{left\_right}+1$\C{component of formula ( \.{%
+\\mathbin}, etc.~)}\par
+\P\D \37$\\{limit\_switch}=\\{math\_comp}+1$\C{diddle limit conventions ( \.{%
+\\displaylimits}, etc.~)}\par
+\P\D \37$\\{above}=\\{limit\_switch}+1$\C{generalized fraction ( \.{\\above}, %
+\.{\\atop}, etc.~)}\par
+\P\D \37$\\{math\_style}=\\{above}+1$\C{style specification ( \.{%
+\\displaystyle}, etc.~)}\par
+\P\D \37$\\{math\_choice}=\\{math\_style}+1$\C{choice specification ( \.{%
+\\mathchoice} )}\par
+\P\D \37$\\{non\_script}=\\{math\_choice}+1$\C{conditional math glue ( \.{%
+\\nonscript} )}\par
+\P\D \37$\\{vcenter}=\\{non\_script}+1$\C{vertically center a vbox ( \.{%
+\\vcenter} )}\par
+\P\D \37$\\{case\_shift}=\\{vcenter}+1$\C{force specific case ( \.{%
+\\lowercase}, \.{\\uppercase}~)}\par
+\P\D \37$\\{message}=\\{case\_shift}+1$\C{send to user ( \.{\\message}, \.{%
+\\errmessage} )}\par
+\P\D \37$\\{extension}=\\{message}+1$\C{extensions to \TeX\ ( \.{\\write}, \.{%
+\\special}, etc.~)}\par
+\P\D \37$\\{in\_stream}=\\{extension}+1$\C{files for reading ( \.{\\openin}, %
+\.{\\closein} )}\par
+\P\D \37$\\{begin\_group}=\\{in\_stream}+1$\C{begin local grouping ( \.{%
+\\begingroup} )}\par
+\P\D \37$\\{end\_group}=\\{begin\_group}+1$\C{end local grouping ( \.{%
+\\endgroup} )}\par
+\P\D \37$\\{omit}=\\{end\_group}+1$\C{omit alignment template ( \.{\\omit} )}%
+\par
+\P\D \37$\\{ex\_space}=\\{omit}+1$\C{explicit space ( \.{\\\ } )}\par
+\P\D \37$\\{no\_boundary}=\\{ex\_space}+1$\C{suppress boundary ligatures ( \.{%
+\\noboundary} )}\par
+\P\D \37$\\{radical}=\\{no\_boundary}+1$\C{square root and similar signs ( \.{%
+\\radical} )}\par
+\P\D \37$\\{end\_cs\_name}=\\{radical}+1$\C{end control sequence ( \.{%
+\\endcsname} )}\par
+\P\D \37$\\{min\_internal}=\\{end\_cs\_name}+1$\C{the smallest code that can
+follow \.{\\the}}\par
+\P\D \37$\\{char\_given}=\\{min\_internal}$\C{character code defined by \.{%
+\\chardef}}\par
+\P\D \37$\\{math\_given}=\\{char\_given}+1$\C{math code defined by \.{%
+\\mathchardef}}\par
+\P\D \37$\\{last\_item}=\\{math\_given}+1$\C{most recent item ( \.{%
+\\lastpenalty},   \.{\\lastkern}, \.{\\lastskip} )}\par
+\P\D \37$\\{inhibit\_glue}=\\{last\_item}+1$\C{inhibit adjust glue ( \.{%
+\\inhibitglue} )}\par
+\P\D \37$\\{chg\_dir}=\\{inhibit\_glue}+1$\C{change dir mode by \.{\\tate}, \.{%
+\\yoko}}\par
+\P\D \37$\\{max\_non\_prefixed\_command}=\\{chg\_dir}$\C{largest command code
+that can't be \.{\\global}}\par
+\fi
+
+\M215. The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are \\{max\_internal} or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+\Y\P\D \37$\\{toks\_register}=\\{max\_non\_prefixed\_command}+1$\C{token list
+register ( \.{\\toks} )}\par
+\P\D \37$\\{assign\_toks}=\\{toks\_register}+1$\C{special token list ( \.{%
+\\output}, \.{\\everypar}, etc.~)}\par
+\P\D \37$\\{assign\_int}=\\{assign\_toks}+1$\C{user-defined integer ( \.{%
+\\tolerance}, \.{\\day}, etc.~)}\par
+\P\D \37$\\{assign\_dimen}=\\{assign\_int}+1$\C{user-defined length ( \.{%
+\\hsize}, etc.~)}\par
+\P\D \37$\\{assign\_glue}=\\{assign\_dimen}+1$\C{user-defined glue ( \.{%
+\\baselineskip}, etc.~)}\par
+\P\D \37$\\{assign\_mu\_glue}=\\{assign\_glue}+1$\C{user-defined muglue ( \.{%
+\\thinmuskip}, etc.~)}\par
+\P\D \37$\\{assign\_font\_dimen}=\\{assign\_mu\_glue}+1$\C{user-defined font
+dimension ( \.{\\fontdimen} )}\par
+\P\D \37$\\{assign\_font\_int}=\\{assign\_font\_dimen}+1$\C{user-defined font
+integer ( \.{\\hyphenchar}, \.{\\skewchar} )}\par
+\P\D \37$\\{assign\_kinsoku}=\\{assign\_font\_int}+1$\C{user-defined kinsoku
+character ( \.{\\prebreakpenalty},    \.{\\postbreakpenalty} )}\par
+\P\D \37$\\{assign\_inhibit\_xsp\_code}=\\{assign\_kinsoku}+1$\C{user-defined
+inhibit xsp character ( \.{\\inhibitxspcode} )}\par
+\P\D \37$\\{set\_kansuji\_char}=\\{assign\_inhibit\_xsp\_code}+1$%
+\C{user-defined kansuji character ( \.{\\kansujichar} )}\par
+\P\D \37$\\{set\_aux}=\\{set\_kansuji\_char}+1$\C{specify state info ( \.{%
+\\spacefactor}, \.{\\prevdepth} )}\par
+\P\D \37$\\{set\_prev\_graf}=\\{set\_aux}+1$\C{specify state info ( \.{%
+\\prevgraf} )}\par
+\P\D \37$\\{set\_page\_dimen}=\\{set\_prev\_graf}+1$\C{specify state info ( \.{%
+\\pagegoal}, etc.~)}\par
+\P\D \37$\\{set\_page\_int}=\\{set\_page\_dimen}+1$\C{specify state info ( \.{%
+\\deadcycles},   \.{\\insertpenalties} )}\par
+\P\D \37$\\{set\_box\_dimen}=\\{set\_page\_int}+1$\C{change dimension of box ( %
+\.{\\wd}, \.{\\ht}, \.{\\dp} )}\par
+\P\D \37$\\{set\_shape}=\\{set\_box\_dimen}+1$\C{specify fancy paragraph shape
+( \.{\\parshape} )}\par
+\P\D \37$\\{def\_code}=\\{set\_shape}+1$\C{define a character code ( \.{%
+\\catcode}, etc.~)}\par
+\P\D \37$\\{def\_family}=\\{def\_code}+1$\C{declare math fonts ( \.{%
+\\textfont}, etc.~)}\par
+\P\D \37$\\{set\_font}=\\{def\_family}+1$\C{set current font ( font identifiers
+)}\par
+\P\D \37$\\{def\_font}=\\{set\_font}+1$\C{define a font file ( \.{\\font} )}\par
+\P\D \37$\\{def\_jfont}=\\{def\_font}+1$\C{define a font file ( \.{\\jfont} )}%
+\par
+\P\D \37$\\{def\_tfont}=\\{def\_jfont}+1$\C{define a font file ( \.{\\tfont} )}%
+\par
+\P\D \37$\\{register}=\\{def\_tfont}+1$\C{internal register ( \.{\\count}, \.{%
+\\dimen}, etc.~)}\par
+\P\D \37$\\{max\_internal}=\\{register}$\C{the largest code that can follow \.{%
+\\the}}\par
+\P\D \37$\\{advance}=\\{max\_internal}+1$\C{advance a register or parameter ( %
+\.{\\advance} )}\par
+\P\D \37$\\{multiply}=\\{advance}+1$\C{multiply a register or parameter ( \.{%
+\\multiply} )}\par
+\P\D \37$\\{divide}=\\{multiply}+1$\C{divide a register or parameter ( \.{%
+\\divide} )}\par
+\P\D \37$\\{prefix}=\\{divide}+1$\C{qualify a definition ( \.{\\global}, \.{%
+\\long}, \.{\\outer} )}\par
+\P\D \37$\\{let}=\\{prefix}+1$\C{assign a command code ( \.{\\let}, \.{%
+\\futurelet} )}\par
+\P\D \37$\\{shorthand\_def}=\\{let}+1$\C{code definition ( \.{\\chardef}, \.{%
+\\countdef}, etc.~)}\6
+\C{or \.{\\charsubdef}}\par
+\P\D \37$\\{read\_to\_cs}=\\{shorthand\_def}+1$\C{read into a control sequence
+( \.{\\read} )}\par
+\P\D \37$\\{def}=\\{read\_to\_cs}+1$\C{macro definition ( \.{\\def}, \.{%
+\\gdef}, \.{\\xdef}, \.{\\edef} )}\par
+\P\D \37$\\{set\_box}=\\{def}+1$\C{set a box ( \.{\\setbox} )}\par
+\P\D \37$\\{hyph\_data}=\\{set\_box}+1$\C{hyphenation data ( \.{\\hyphenation},
+\.{\\patterns} )}\par
+\P\D \37$\\{set\_interaction}=\\{hyph\_data}+1$\C{define level of interaction (
+\.{\\batchmode}, etc.~)}\par
+\P\D \37$\\{set\_auto\_spacing}=\\{set\_interaction}+1$\C{set auto spaceing
+mode   ( \.{\\autospacing}, \.{\\noautospacing}, ( \.{\\autoxspacing}, \.{%
+\\noautoxspacing} )}\par
+\P\D \37$\\{max\_command}=\\{set\_auto\_spacing}$\C{the largest command code
+seen at \\{big\_switch}}\par
+\fi
+
+\M216. The remaining command codes are extra special, since they cannot get
+through
+\TeX's scanner to the main control routine. They have been given values higher
+than \\{max\_command} so that their special nature is easily discernible.
+The ``expandable'' commands come first.
+
+\Y\P\D \37$\\{undefined\_cs}=\\{max\_command}+1$\C{initial state of most \\{eq%
+\_type} fields}\par
+\P\D \37$\\{expand\_after}=\\{max\_command}+2$\C{special expansion ( \.{%
+\\expandafter} )}\par
+\P\D \37$\\{no\_expand}=\\{max\_command}+3$\C{special nonexpansion ( \.{%
+\\noexpand} )}\par
+\P\D \37$\\{input}=\\{max\_command}+4$\C{input a source file ( \.{\\input}, \.{%
+\\endinput} )}\par
+\P\D \37$\\{if\_test}=\\{max\_command}+5$\C{conditional text ( \.{\\if}, \.{%
+\\ifcase}, etc.~)}\par
+\P\D \37$\\{fi\_or\_else}=\\{max\_command}+6$\C{delimiters for conditionals ( %
+\.{\\else}, etc.~)}\par
+\P\D \37$\\{cs\_name}=\\{max\_command}+7$\C{make a control sequence from tokens
+( \.{\\csname} )}\par
+\P\D \37$\\{convert}=\\{max\_command}+8$\C{convert to text ( \.{\\number}, \.{%
+\\string}, etc.~)}\par
+\P\D \37$\\{the}=\\{max\_command}+9$\C{expand an internal quantity ( \.{\\the}
+)}\par
+\P\D \37$\\{top\_bot\_mark}=\\{max\_command}+10$\C{inserted mark ( \.{%
+\\topmark}, etc.~)}\par
+\P\D \37$\\{call}=\\{max\_command}+11$\C{non-long, non-outer control sequence}%
+\par
+\P\D \37$\\{long\_call}=\\{max\_command}+12$\C{long, non-outer control
+sequence}\par
+\P\D \37$\\{outer\_call}=\\{max\_command}+13$\C{non-long, outer control
+sequence}\par
+\P\D \37$\\{long\_outer\_call}=\\{max\_command}+14$\C{long, outer control
+sequence}\par
+\P\D \37$\\{end\_template}=\\{max\_command}+15$\C{end of an alignment template}%
+\par
+\P\D \37$\\{dont\_expand}=\\{max\_command}+16$\C{the following token was marked
+by \.{\\noexpand}}\par
+\P\D \37$\\{glue\_ref}=\\{max\_command}+17$\C{the equivalent points to a glue
+specification}\par
+\P\D \37$\\{shape\_ref}=\\{max\_command}+18$\C{the equivalent points to a
+parshape specification}\par
+\P\D \37$\\{box\_ref}=\\{max\_command}+19$\C{the equivalent points to a box
+node, or is \\{null}}\par
+\P\D \37$\\{data}=\\{max\_command}+20$\C{the equivalent is simply a halfword
+number}\par
+\fi
+
+\N217.  \[16] The semantic nest.
+\TeX\ is typically in the midst of building many lists at once. For example,
+when a math formula is being processed, \TeX\ is in math mode and
+working on an mlist; this formula has temporarily interrupted \TeX\ from
+being in horizontal mode and building the hlist of a paragraph; and this
+paragraph has temporarily interrupted \TeX\ from being in vertical mode
+and building the vlist for the next page of a document. Similarly, when a
+\.{\\vbox} occurs inside of an \.{\\hbox}, \TeX\ is temporarily
+interrupted from working in restricted horizontal mode, and it enters
+internal vertical mode.  The ``semantic nest'' is a stack that
+keeps track of what lists and modes are currently suspended.
+
+At each level of processing we are in one of six modes:
+
+\yskip\hang\\{vmode} stands for vertical mode (the page builder);
+
+\hang\\{hmode} stands for horizontal mode (the paragraph builder);
+
+\hang\\{mmode} stands for displayed formula mode;
+
+\hang$-\\{vmode}$ stands for internal vertical mode (e.g., in a \.{\\vbox});
+
+\hang$-\\{hmode}$ stands for restricted horizontal mode (e.g., in an \.{%
+\\hbox});
+
+\hang$-\\{mmode}$ stands for math formula mode (not displayed).
+
+\yskip\noindent The mode is temporarily set to zero while processing \.{%
+\\write}
+texts in the \\{ship\_out} routine.
+
+Numeric values are assigned to \\{vmode}, \\{hmode}, and \\{mmode} so that
+\TeX's ``big semantic switch'' can select the appropriate thing to
+do by computing the value $\\{abs}(\\{mode})+\\{cur\_cmd}$, where \\{mode} is
+the current
+mode and \\{cur\_cmd} is the current command code.
+
+\Y\P\D \37$\\{vmode}=1$\C{vertical mode}\par
+\P\D \37$\\{hmode}=\\{vmode}+\\{max\_command}+1$\C{horizontal mode}\par
+\P\D \37$\\{mmode}=\\{hmode}+\\{max\_command}+1$\C{math mode}\par
+\Y\P\4\&{procedure}\1\  \37$\\{print\_mode}(\|m:\\{integer})$;\C{prints the
+mode represented by \|m}\2\6
+\&{begin} \37\&{if} $\|m>0$ \1\&{then}\6
+\&{case} $\|m\mathbin{\&{div}}(\\{max\_command}+1)$ \1\&{of}\6
+\40: \37$\\{print}(\.{"vertical\ mode"})$;\6
+\41: \37$\\{print}(\.{"horizontal\ mode"})$;\6
+\42: \37$\\{print}(\.{"display\ math\ mode"})$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|m=0$ \1\&{then}\5
+$\\{print}(\.{"no\ mode"})$\6
+\4\&{else} \&{case} $(-\|m)\mathbin{\&{div}}(\\{max\_command}+1)$ \1\&{of}\6
+\40: \37$\\{print}(\.{"internal\ vertical\ mode"})$;\6
+\41: \37$\\{print}(\.{"restricted\ horizontal\ mode"})$;\6
+\42: \37$\\{print}(\.{"math\ mode"})$;\2\6
+\&{end};\2\2\6
+\&{end};\6
+\4\&{procedure}\1\  \37$\\{print\_in\_mode}(\|m:\\{integer})$;\C{prints the
+mode represented by \|m}\2\6
+\&{begin} \37\&{if} $\|m>0$ \1\&{then}\6
+\&{case} $\|m\mathbin{\&{div}}(\\{max\_command}+1)$ \1\&{of}\6
+\40: \37$\\{print}(\.{"\'\ in\ vertical\ mode"})$;\6
+\41: \37$\\{print}(\.{"\'\ in\ horizontal\ mode"})$;\6
+\42: \37$\\{print}(\.{"\'\ in\ display\ math\ mode"})$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|m=0$ \1\&{then}\5
+$\\{print}(\.{"\'\ in\ no\ mode"})$\6
+\4\&{else} \&{case} $(-\|m)\mathbin{\&{div}}(\\{max\_command}+1)$ \1\&{of}\6
+\40: \37$\\{print}(\.{"\'\ in\ internal\ vertical\ mode"})$;\6
+\41: \37$\\{print}(\.{"\'\ in\ restricted\ horizontal\ mode"})$;\6
+\42: \37$\\{print}(\.{"\'\ in\ math\ mode"})$;\2\6
+\&{end};\2\2\6
+\&{end};\par
+\fi
+
+\M218. The state of affairs at any semantic level can be represented by
+five values:
+
+\yskip\hang\\{mode} is the number representing the semantic mode, as
+just explained.
+
+\yskip\hang\\{head} is a \\{pointer} to a list head for the list being built;
+$\\{link}(\\{head})$ therefore points to the first element of the list, or
+to \\{null} if the list is empty.
+
+\yskip\hang\\{tail} is a \\{pointer} to the final node of the list being
+built; thus, $\\{tail}=\\{head}$ if and only if the list is empty.
+
+\yskip\hang\\{prev\_graf} is the number of lines of the current paragraph that
+have already been put into the present vertical list.
+
+\yskip\hang\\{aux} is an auxiliary \\{memory\_word} that gives further
+information
+that is needed to characterize the situation.
+
+\yskip\noindent
+In vertical mode, \\{aux} is also known as \\{prev\_depth}; it is the scaled
+value representing the depth of the previous box, for use in baseline
+calculations, or it is $\L-1000$pt if the next box on the vertical list is to
+be exempt from baseline calculations.  In horizontal mode, \\{aux} is also
+known as \\{space\_factor} and \\{clang}; it holds the current space factor
+used in
+spacing calculations, and the current language used for hyphenation.
+(The value of \\{clang} is undefined in restricted horizontal mode.)
+In math mode, \\{aux} is also known as \\{incompleat\_noad}; if
+not \\{null}, it points to a record that represents the numerator of a
+generalized fraction for which the denominator is currently being formed
+in the current list.
+
+There is also a sixth quantity, \\{mode\_line}, which correlates
+the semantic nest with the user's input; \\{mode\_line} contains the source
+line number at which the current level of nesting was entered. The negative
+of this line number is the \\{mode\_line} at the level of the
+user's output routine.
+
+In horizontal mode, the \\{prev\_graf} field is used for initial language data.
+
+The semantic nest is an array called \\{nest} that holds the \\{mode}, %
+\\{head},
+\\{tail}, \\{prev\_graf}, \\{aux}, and \\{mode\_line} values for all semantic
+levels
+below the currently active one. Information about the currently active
+level is kept in the global quantities \\{mode}, \\{head}, \\{tail}, \\{prev%
+\_graf},
+\\{aux}, and \\{mode\_line}, which live in a \PASCAL\ record that is ready to
+be pushed onto \\{nest} if necessary.
+
+\Y\P\D \37$\\{ignore\_depth}\S-65536000$\C{\\{prev\_depth} value that is
+ignored}\par
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{list\_state\_record}=$\1\5
+\1\&{record} \37\\{mode\_field}: \37$-\\{mmode}\to\\{mmode}$;\ $\\{dir\_field},%
+\39\\{adj\_dir\_field}$: \37$-\\{dir\_yoko}\to\\{dir\_yoko}$;\6
+\4\\{pdisp\_field}: \37\\{scaled};\6
+\4$\\{head\_field},\39\\{tail\_field},\39\\{pnode\_field},\39\\{last\_jchr%
+\_field}$: \37\\{pointer};\6
+\4$\\{pg\_field},\39\\{ml\_field}$: \37\\{integer};\ \\{aux\_field}: \37%
+\\{memory\_word};\2\6
+\&{end};\2\par
+\fi
+
+\M219. \P\D \37$\\{mode}\S\\{cur\_list}.\\{mode\_field}$\C{current mode}\par
+\P\D \37$\\{direction}\S\\{cur\_list}.\\{dir\_field}$\C{current direction}\par
+\P\D \37$\\{adjust\_dir}\S\\{cur\_list}.\\{adj\_dir\_field}$\C{current adjust
+direction}\par
+\P\D \37$\\{head}\S\\{cur\_list}.\\{head\_field}$\C{header node of current
+list}\par
+\P\D \37$\\{tail}\S\\{cur\_list}.\\{tail\_field}$\C{final node on current list}%
+\par
+\P\D \37$\\{prev\_node}\S\\{cur\_list}.\\{pnode\_field}$\C{previous to last %
+\\{disp\_node}}\par
+\P\D \37$\\{prev\_disp}\S\\{cur\_list}.\\{pdisp\_field}$\C{displacemant at %
+\\{prev\_node}}\par
+\P\D \37$\\{last\_jchr}\S\\{cur\_list}.\\{last\_jchr\_field}$\C{final jchar
+node on current list}\par
+\P\D \37$\\{prev\_graf}\S\\{cur\_list}.\\{pg\_field}$\C{number of paragraph
+lines accumulated}\par
+\P\D \37$\\{aux}\S\\{cur\_list}.\\{aux\_field}$\C{auxiliary data about the
+current list}\par
+\P\D \37$\\{prev\_depth}\S\\{aux}.\\{sc}$\C{the name of \\{aux} in vertical
+mode}\par
+\P\D \37$\\{space\_factor}\S\\{aux}.\\{hh}.\\{lh}$\C{part of \\{aux} in
+horizontal mode}\par
+\P\D \37$\\{clang}\S\\{aux}.\\{hh}.\\{rh}$\C{the other part of \\{aux} in
+horizontal mode}\par
+\P\D \37$\\{incompleat\_noad}\S\\{aux}.\\{int}$\C{the name of \\{aux} in math
+mode}\par
+\P\D \37$\\{mode\_line}\S\\{cur\_list}.\\{ml\_field}$\C{source file line number
+at beginning of list}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{nest}: \37$\^\\{list\_state\_record}$;\6
+\4\\{nest\_ptr}: \37$0\to\\{nest\_size}$;\C{first unused location of \\{nest}}\6
+\4\\{max\_nest\_stack}: \37$0\to\\{nest\_size}$;\C{maximum of \\{nest\_ptr}
+when pushing}\6
+\4\\{cur\_list}: \37\\{list\_state\_record};\C{the ``top'' semantic state}\6
+\4\\{shown\_mode}: \37$-\\{mmode}\to\\{mmode}$;\C{most recent mode shown by \.{%
+\\tracingcommands}}\par
+\fi
+
+\M220. Here is a common way to make the current list grow:
+
+\Y\P\D \37$\\{tail\_append}(\#)\S$\1\6
+\&{begin} \37$\\{link}(\\{tail})\K\#$;\5
+$\\{tail}\K\\{link}(\\{tail})$;\6
+\&{end}\2\par
+\P\D \37$\\{prev\_append}(\#)\S$\1\6
+\&{begin} \37$\\{link}(\\{prev\_node})\K\#$;\5
+$\\{link}(\\{link}(\\{prev\_node}))\K\\{tail}$;\5
+$\\{prev\_node}\K\\{link}(\\{prev\_node})$;\6
+\&{end}\2\par
+\fi
+
+\M221. We will see later that the vertical list at the bottom semantic level is
+split
+into two parts; the ``current page'' runs from \\{page\_head} to \\{page%
+\_tail},
+and the ``contribution list'' runs from \\{contrib\_head} to \\{tail} of
+semantic level zero. The idea is that contributions are first formed in
+vertical mode, then ``contributed'' to the current page (during which time
+the page-breaking decisions are made). For now, we don't need to know
+any more details about the page-building process.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{nest\_ptr}\K0$;\5
+$\\{max\_nest\_stack}\K0$;\5
+$\\{mode}\K\\{vmode}$;\5
+$\\{head}\K\\{contrib\_head}$;\5
+$\\{tail}\K\\{contrib\_head}$;\5
+$\\{prev\_node}\K\\{tail}$;\5
+$\\{direction}\K\\{dir\_yoko}$;\5
+$\\{adjust\_dir}\K\\{direction}$;\5
+$\\{prev\_disp}\K0$;\5
+$\\{last\_jchr}\K\\{null}$;\5
+$\\{prev\_depth}\K\\{ignore\_depth}$;\5
+$\\{mode\_line}\K0$;\5
+$\\{prev\_graf}\K0$;\5
+$\\{shown\_mode}\K0$;\6
+\C{The following piece of code is a copy of module 991:}\6
+$\\{page\_contents}\K\\{empty}$;\5
+$\\{page\_tail}\K\\{page\_head}$;\C{$\\{link}(\\{page\_head})\K\\{null}$;}\6
+$\\{last\_glue}\K\\{max\_halfword}$;\5
+$\\{last\_penalty}\K0$;\5
+$\\{last\_kern}\K0$;\5
+$\\{page\_depth}\K0$;\5
+$\\{page\_max\_depth}\K0$;\par
+\fi
+
+\M222. When \TeX's work on one level is interrupted, the state is saved by
+calling \\{push\_nest}. This routine changes \\{head} and \\{tail} so that
+a new (empty) list is begun; it does not change \\{mode} or \\{aux}.
+
+\Y\P\4\&{procedure}\1\  \37\\{push\_nest};\C{enter a new semantic level, save
+the old}\2\6
+\&{begin} \37\&{if} $\\{nest\_ptr}>\\{max\_nest\_stack}$ \1\&{then}\6
+\&{begin} \37$\\{max\_nest\_stack}\K\\{nest\_ptr}$;\6
+\&{if} $\\{nest\_ptr}=\\{nest\_size}$ \1\&{then}\5
+$\\{overflow}(\.{"semantic\ nest\ size"},\39\\{nest\_size})$;\2\6
+\&{end};\2\6
+$\\{nest}[\\{nest\_ptr}]\K\\{cur\_list}$;\C{stack the record}\6
+$\\{incr}(\\{nest\_ptr})$;\5
+$\\{head}\K\\{new\_null\_box}$;\5
+$\\{tail}\K\\{head}$;\5
+$\\{prev\_node}\K\\{tail}$;\5
+$\\{prev\_graf}\K0$;\5
+$\\{prev\_disp}\K0$;\5
+$\\{last\_jchr}\K\\{null}$;\5
+$\\{mode\_line}\K\\{line}$;\6
+\&{end};\par
+\fi
+
+\M223. Conversely, when \TeX\ is finished on the current level, the former
+state is restored by calling \\{pop\_nest}. This routine will never be
+called at the lowest semantic level, nor will it be called unless \\{head}
+is a node that should be returned to free memory.
+
+\Y\P\4\&{procedure}\1\  \37\\{pop\_nest};\C{leave a semantic level, re-enter
+the old}\2\6
+\&{begin} \37$\\{fast\_delete\_glue\_ref}(\\{space\_ptr}(\\{head}))$;\5
+$\\{fast\_delete\_glue\_ref}(\\{xspace\_ptr}(\\{head}))$;\5
+$\\{free\_node}(\\{head},\39\\{box\_node\_size})$;\5
+$\\{decr}(\\{nest\_ptr})$;\5
+$\\{cur\_list}\K\\{nest}[\\{nest\_ptr}]$;\6
+\&{end};\par
+\fi
+
+\M224. Here is a procedure that displays what \TeX\ is working on, at all
+levels.
+
+\Y\P\4\&{procedure}\1\  \37\\{print\_totals};\5
+\\{forward}; \hbox{\2} \6
+\4\&{procedure}\1\  \37\\{show\_activities};\6
+\4\&{var} \37\|p: \37$0\to\\{nest\_size}$;\C{index into \\{nest}}\6
+\|m: \37$-\\{mmode}\to\\{mmode}$;\C{mode}\6
+\|a: \37\\{memory\_word};\C{auxiliary}\6
+$\|q,\39\|r$: \37\\{pointer};\C{for showing the current page}\6
+\|t: \37\\{integer};\C{ditto}\2\6
+\&{begin} \37$\\{nest}[\\{nest\_ptr}]\K\\{cur\_list}$;\C{put the top level into
+the array}\6
+$\\{print\_nl}(\.{""})$;\5
+\\{print\_ln};\6
+\&{for} $\|p\K\\{nest\_ptr}\mathrel{\&{downto}}0$ \1\&{do}\6
+\&{begin} \37$\|m\K\\{nest}[\|p].\\{mode\_field}$;\5
+$\|a\K\\{nest}[\|p].\\{aux\_field}$;\5
+$\\{print\_nl}(\.{"\#\#\#\ "})$;\5
+$\\{print\_direction}(\\{nest}[\|p].\\{dir\_field})$;\5
+$\\{print}(\.{",\ "})$;\5
+$\\{print\_mode}(\|m)$;\5
+$\\{print}(\.{"\ entered\ at\ line\ "})$;\5
+$\\{print\_int}(\\{abs}(\\{nest}[\|p].\\{ml\_field}))$;\6
+\&{if} $\|m=\\{hmode}$ \1\&{then}\6
+\&{if} $\\{nest}[\|p].\\{pg\_field}\I\O{40600000}$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ (language"})$;\5
+$\\{print\_int}(\\{nest}[\|p].\\{pg\_field}\mathbin{\&{mod}}\O{200000})$;\5
+$\\{print}(\.{":hyphenmin"})$;\5
+$\\{print\_int}(\\{nest}[\|p].\\{pg\_field}\mathbin{\&{div}}\O{20000000})$;\5
+$\\{print\_char}(\.{","})$;\5
+$\\{print\_int}((\\{nest}[\|p].\\{pg\_field}\mathbin{\&{div}}\O{200000})%
+\mathbin{\&{mod}}\O{100})$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\2\6
+\&{if} $\\{nest}[\|p].\\{ml\_field}<0$ \1\&{then}\5
+$\\{print}(\.{"\ (\\output\ routine)"})$;\2\6
+\&{if} $\|p=0$ \1\&{then}\6
+\&{begin} \37\X997:Show the status of the current page\X;\6
+\&{if} $\\{link}(\\{contrib\_head})\I\\{null}$ \1\&{then}\5
+$\\{print\_nl}(\.{"\#\#\#\ recent\ contributions:"})$;\2\6
+\&{end};\2\6
+$\\{show\_box}(\\{link}(\\{nest}[\|p].\\{head\_field}))$;\5
+\X225:Show the auxiliary field, \|a\X;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M225. \P$\X225:Show the auxiliary field, \|a\X\S$\6
+\&{case} $\\{abs}(\|m)\mathbin{\&{div}}(\\{max\_command}+1)$ \1\&{of}\6
+\40: \37\&{begin} \37$\\{print\_nl}(\.{"prevdepth\ "})$;\6
+\&{if} $\|a.\\{sc}\L\\{ignore\_depth}$ \1\&{then}\5
+$\\{print}(\.{"ignored"})$\6
+\4\&{else} $\\{print\_scaled}(\|a.\\{sc})$;\2\6
+\&{if} $\\{nest}[\|p].\\{pg\_field}\I0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{",\ prevgraf\ "})$;\5
+$\\{print\_int}(\\{nest}[\|p].\\{pg\_field})$;\6
+\&{if} $\\{nest}[\|p].\\{pg\_field}\I1$ \1\&{then}\5
+$\\{print}(\.{"\ lines"})$\6
+\4\&{else} $\\{print}(\.{"\ line"})$;\2\6
+\&{end};\2\6
+\&{end};\6
+\41: \37\&{begin} \37$\\{print\_nl}(\.{"spacefactor\ "})$;\5
+$\\{print\_int}(\|a.\\{hh}.\\{lh})$;\6
+\&{if} $\|m>0$ \1\&{then}\ \&{if} $\|a.\\{hh}.\\{rh}>0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{",\ current\ language\ "})$;\5
+$\\{print\_int}(\|a.\\{hh}.\\{rh})$;\ \&{end};\2\2\6
+\&{end};\6
+\42: \37\&{if} $\|a.\\{int}\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"this\ will\ be\ denominator\ of:"})$;\5
+$\\{show\_box}(\|a.\\{int})$;\ \&{end};\2\2\6
+\&{end}\C{there are no other cases}\par
+\U224.\fi
+
+\N226.  \[17] The table of equivalents.
+Now that we have studied the data structures for \TeX's semantic routines,
+we ought to consider the data structures used by its syntactic routines. In
+other words, our next concern will be
+the tables that \TeX\ looks at when it is scanning
+what the user has written.
+
+The biggest and most important such table is called \\{eqtb}. It holds the
+current ``equivalents'' of things; i.e., it explains what things mean
+or what their current values are, for all quantities that are subject to
+the nesting structure provided by \TeX's grouping mechanism. There are six
+parts to \\{eqtb}:
+
+\yskip\hangg 1) $\\{eqtb}[\\{active\_base}\to(\\{hash\_base}-1)]$ holds the
+current
+equivalents of single-character control sequences.
+
+\yskip\hangg 2) $\\{eqtb}[\\{hash\_base}\to(\\{glue\_base}-1)]$ holds the
+current
+equivalents of multiletter control sequences.
+
+\yskip\hangg 3) $\\{eqtb}[\\{glue\_base}\to(\\{local\_base}-1)]$ holds the
+current
+equivalents of glue parameters like the current baselineskip.
+
+\yskip\hangg 4) $\\{eqtb}[\\{local\_base}\to(\\{int\_base}-1)]$ holds the
+current
+equivalents of local halfword quantities like the current box registers,
+the current ``catcodes,'' the current font, and a pointer to the current
+paragraph shape.
+Additionally region~4 contains the table with ML\TeX's character
+substitution definitions.
+
+\yskip\hangg 5) $\\{eqtb}[\\{int\_base}\to(\\{dimen\_base}-1)]$ holds the
+current
+equivalents of fullword integer parameters like the current hyphenation
+penalty.
+
+\yskip\hangg 6) $\\{eqtb}[\\{dimen\_base}\to\\{eqtb\_size}]$ holds the current
+equivalents
+of fullword dimension parameters like the current hsize or amount of
+hanging indentation.
+
+\yskip\noindent Note that, for example, the current amount of
+baselineskip glue is determined by the setting of a particular location
+in region~3 of \\{eqtb}, while the current meaning of the control sequence
+`\.{\\baselineskip}' (which might have been changed by \.{\\def} or
+\.{\\let}) appears in region~2.
+
+\fi
+
+\M227. Each entry in \\{eqtb} is a \\{memory\_word}. Most of these words are of
+type
+\\{two\_halves}, and subdivided into three fields:
+
+\yskip\hangg 1) The \\{eq\_level} (a quarterword) is the level of grouping at
+which this equivalent was defined. If the level is \\{level\_zero}, the
+equivalent has never been defined; \\{level\_one} refers to the outer level
+(outside of all groups), and this level is also used for global
+definitions that never go away. Higher levels are for equivalents that
+will disappear at the end of their group.
+
+\yskip\hangg 2) The \\{eq\_type} (another quarterword) specifies what kind of
+entry this is. There are many types, since each \TeX\ primitive like
+\.{\\hbox}, \.{\\def}, etc., has its own special code. The list of
+command codes above includes all possible settings of the \\{eq\_type} field.
+
+\yskip\hangg 3) The \\{equiv} (a halfword) is the current equivalent value.
+This may be a font number, a pointer into \\{mem}, or a variety of other
+things.
+
+\Y\P\D \37$\\{eq\_level\_field}(\#)\S\#.\\{hh}.\\{b1}$\par
+\P\D \37$\\{eq\_type\_field}(\#)\S\#.\\{hh}.\\{b0}$\par
+\P\D \37$\\{equiv\_field}(\#)\S\#.\\{hh}.\\{rh}$\par
+\P\D \37$\\{eq\_level}(\#)\S\\{eq\_level\_field}(\\{eqtb}[\#])$\C{level of
+definition}\par
+\P\D \37$\\{eq\_type}(\#)\S\\{eq\_type\_field}(\\{eqtb}[\#])$\C{command code
+for equivalent}\par
+\P\D \37$\\{equiv}(\#)\S\\{equiv\_field}(\\{eqtb}[\#])$\C{equivalent value}\par
+\P\D \37$\\{level\_zero}=\\{min\_quarterword}$\C{level for undefined
+quantities}\par
+\P\D \37$\\{level\_one}=\\{level\_zero}+1$\C{outermost level for defined
+quantities}\par
+\fi
+
+\M228. Many locations in \\{eqtb} have symbolic names. The purpose of the next
+paragraphs is to define these names, and to set up the initial values of the
+equivalents.
+
+In the first region we have 256 equivalents for ``active characters'' that
+act as control sequences, followed by 256 equivalents for single-character
+control sequences.
+
+Then comes region~2, which corresponds to the hash table that we will
+define later.  The maximum address in this region is used for a dummy
+control sequence that is perpetually undefined. There also are several
+locations for control sequences that are perpetually defined
+(since they are used in error recovery).
+
+\Y\P\D \37$\\{active\_base}=1$\C{beginning of region 1, for active character
+equivalents}\par
+\P\D \37$\\{single\_base}=\\{active\_base}+256$\C{equivalents of one-character
+control sequences}\par
+\P\D \37$\\{null\_cs}=\\{single\_base}+256$\C{equivalent of \.{\\csname%
+\\endcsname}}\par
+\P\D \37$\\{hash\_base}=\\{null\_cs}+1$\C{beginning of region 2, for the hash
+table}\par
+\P\D \37$\\{frozen\_control\_sequence}=\\{hash\_base}+\\{hash\_size}$\C{for
+error recovery}\par
+\P\D \37$\\{frozen\_protection}=\\{frozen\_control\_sequence}$\C{inaccessible
+but definable}\par
+\P\D \37$\\{frozen\_cr}=\\{frozen\_control\_sequence}+1$\C{permanent `\.{%
+\\cr}'}\par
+\P\D \37$\\{frozen\_end\_group}=\\{frozen\_control\_sequence}+2$\C{permanent `%
+\.{\\endgroup}'}\par
+\P\D \37$\\{frozen\_right}=\\{frozen\_control\_sequence}+3$\C{permanent `\.{%
+\\right}'}\par
+\P\D \37$\\{frozen\_fi}=\\{frozen\_control\_sequence}+4$\C{permanent `\.{%
+\\fi}'}\par
+\P\D \37$\\{frozen\_end\_template}=\\{frozen\_control\_sequence}+5$\C{permanent
+`\.{\\endtemplate}'}\par
+\P\D \37$\\{frozen\_endv}=\\{frozen\_control\_sequence}+6$\C{second permanent `%
+\.{\\endtemplate}'}\par
+\P\D \37$\\{frozen\_relax}=\\{frozen\_control\_sequence}+7$\C{permanent `\.{%
+\\relax}'}\par
+\P\D \37$\\{end\_write}=\\{frozen\_control\_sequence}+8$\C{permanent `\.{%
+\\endwrite}'}\par
+\P\D \37$\\{frozen\_dont\_expand}=\\{frozen\_control\_sequence}+9$\C{permanent
+`\.{\\notexpanded:}'}\par
+\P\D \37$\\{frozen\_special}=\\{frozen\_control\_sequence}+10$\C{permanent `\.{%
+\\special}'}\par
+\P\D \37$\\{frozen\_null\_font}=\\{frozen\_control\_sequence}+11$\C{permanent `%
+\.{\\nullfont}'}\par
+\P\D \37$\\{font\_id\_base}=\\{frozen\_null\_font}-\\{font\_base}$\C{begins
+table of 257 permanent font identifiers}\par
+\P\D \37$\\{undefined\_control\_sequence}=\\{frozen\_null\_font}+\\{max\_font%
+\_max}+1$\C{dummy location}\par
+\P\D \37$\\{glue\_base}=\\{undefined\_control\_sequence}+1$\C{beginning of
+region 3}\par
+\Y\P$\4\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}\S$%
+\6
+$\\{eq\_type}(\\{undefined\_control\_sequence})\K\\{undefined\_cs}$;\5
+$\\{equiv}(\\{undefined\_control\_sequence})\K\\{null}$;\5
+$\\{eq\_level}(\\{undefined\_control\_sequence})\K\\{level\_zero}$;\6
+\&{for} $\|k\K\\{active\_base}\mathrel{\&{to}}\\{eqtb\_top}$ \1\&{do}\5
+$\\{eqtb}[\|k]\K\\{eqtb}[\\{undefined\_control\_sequence}]$;\2\par
+\fi
+
+\M229. Here is a routine that displays the current meaning of an \\{eqtb} entry
+in region 1 or~2. (Similar routines for the other regions will appear
+below.)
+
+\Y\P$\4\X229:Show equivalent \|n, in region 1 or 2\X\S$\6
+\&{begin} \37$\\{sprint\_cs}(\|n)$;\5
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_cmd\_chr}(\\{eq\_type}(\|n),\39\\{equiv}(\|n))$;\6
+\&{if} $\\{eq\_type}(\|n)\G\\{call}$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{":"})$;\5
+$\\{show\_token\_list}(\\{link}(\\{equiv}(\|n)),\39\\{null},\3932)$;\6
+\&{end};\2\6
+\&{end}\par
+\U258.\fi
+
+\M230. Region 3 of \\{eqtb} contains the 256 \.{\\skip} registers, as well as
+the
+glue parameters defined here. It is important that the ``muskip''
+parameters have larger numbers than the others.
+
+\Y\P\D \37$\\{line\_skip\_code}=0$\C{interline glue if \\{baseline\_skip} is
+infeasible}\par
+\P\D \37$\\{baseline\_skip\_code}=1$\C{desired glue between baselines}\par
+\P\D \37$\\{par\_skip\_code}=2$\C{extra glue just above a paragraph}\par
+\P\D \37$\\{above\_display\_skip\_code}=3$\C{extra glue just above displayed
+math}\par
+\P\D \37$\\{below\_display\_skip\_code}=4$\C{extra glue just below displayed
+math}\par
+\P\D \37$\\{above\_display\_short\_skip\_code}=5$\C{glue above displayed math
+following short lines}\par
+\P\D \37$\\{below\_display\_short\_skip\_code}=6$\C{glue below displayed math
+following short lines}\par
+\P\D \37$\\{left\_skip\_code}=7$\C{glue at left of justified lines}\par
+\P\D \37$\\{right\_skip\_code}=8$\C{glue at right of justified lines}\par
+\P\D \37$\\{top\_skip\_code}=9$\C{glue at top of main pages}\par
+\P\D \37$\\{split\_top\_skip\_code}=10$\C{glue at top of split pages}\par
+\P\D \37$\\{tab\_skip\_code}=11$\C{glue between aligned entries}\par
+\P\D \37$\\{space\_skip\_code}=12$\C{glue between words (if not \\{zero%
+\_glue})}\par
+\P\D \37$\\{xspace\_skip\_code}=13$\C{glue after sentences (if not \\{zero%
+\_glue})}\par
+\P\D \37$\\{par\_fill\_skip\_code}=14$\C{glue on last line of paragraph}\par
+\P\D \37$\\{kanji\_skip\_code}=15$\C{between kanji-kanji space}\par
+\P\D \37$\\{xkanji\_skip\_code}=16$\C{between latin-kanji or kanji-latin space}%
+\par
+\P\D \37$\\{thin\_mu\_skip\_code}=17$\C{thin space in math formula}\par
+\P\D \37$\\{med\_mu\_skip\_code}=18$\C{medium space in math formula}\par
+\P\D \37$\\{thick\_mu\_skip\_code}=19$\C{thick space in math formula}\par
+\P\D \37$\\{jfm\_skip}=20$\C{space refer from JFM}\par
+\P\D \37$\\{glue\_pars}=21$\C{total number of glue parameters}\par
+\P\D \37$\\{skip\_base}=\\{glue\_base}+\\{glue\_pars}$\C{table of 256 ``skip''
+registers}\par
+\P\D \37$\\{mu\_skip\_base}=\\{skip\_base}+256$\C{table of 256 ``muskip''
+registers}\par
+\P\D \37$\\{local\_base}=\\{mu\_skip\_base}+256$\C{beginning of region 4}\Y\par
+\P\D \37$\\{skip}(\#)\S\\{equiv}(\\{skip\_base}+\#)$\C{\\{mem} location of glue
+specification}\par
+\P\D \37$\\{mu\_skip}(\#)\S\\{equiv}(\\{mu\_skip\_base}+\#)$\C{\\{mem} location
+of math glue spec}\par
+\P\D \37$\\{glue\_par}(\#)\S\\{equiv}(\\{glue\_base}+\#)$\C{\\{mem} location of
+glue specification}\par
+\P\D \37$\\{line\_skip}\S\\{glue\_par}(\\{line\_skip\_code})$\par
+\P\D \37$\\{baseline\_skip}\S\\{glue\_par}(\\{baseline\_skip\_code})$\par
+\P\D \37$\\{par\_skip}\S\\{glue\_par}(\\{par\_skip\_code})$\par
+\P\D \37$\\{above\_display\_skip}\S\\{glue\_par}(\\{above\_display\_skip%
+\_code})$\par
+\P\D \37$\\{below\_display\_skip}\S\\{glue\_par}(\\{below\_display\_skip%
+\_code})$\par
+\P\D \37$\\{above\_display\_short\_skip}\S\\{glue\_par}(\\{above\_display%
+\_short\_skip\_code})$\par
+\P\D \37$\\{below\_display\_short\_skip}\S\\{glue\_par}(\\{below\_display%
+\_short\_skip\_code})$\par
+\P\D \37$\\{left\_skip}\S\\{glue\_par}(\\{left\_skip\_code})$\par
+\P\D \37$\\{right\_skip}\S\\{glue\_par}(\\{right\_skip\_code})$\par
+\P\D \37$\\{top\_skip}\S\\{glue\_par}(\\{top\_skip\_code})$\par
+\P\D \37$\\{split\_top\_skip}\S\\{glue\_par}(\\{split\_top\_skip\_code})$\par
+\P\D \37$\\{tab\_skip}\S\\{glue\_par}(\\{tab\_skip\_code})$\par
+\P\D \37$\\{space\_skip}\S\\{glue\_par}(\\{space\_skip\_code})$\par
+\P\D \37$\\{xspace\_skip}\S\\{glue\_par}(\\{xspace\_skip\_code})$\par
+\P\D \37$\\{par\_fill\_skip}\S\\{glue\_par}(\\{par\_fill\_skip\_code})$\par
+\P\D \37$\\{thin\_mu\_skip}\S\\{glue\_par}(\\{thin\_mu\_skip\_code})$\par
+\P\D \37$\\{med\_mu\_skip}\S\\{glue\_par}(\\{med\_mu\_skip\_code})$\par
+\P\D \37$\\{thick\_mu\_skip}\S\\{glue\_par}(\\{thick\_mu\_skip\_code})$\par
+\P\D \37$\\{kanji\_skip}\S\\{glue\_par}(\\{kanji\_skip\_code})$\par
+\P\D \37$\\{xkanji\_skip}\S\\{glue\_par}(\\{xkanji\_skip\_code})$\par
+\Y\P$\4\X230:Current \\{mem} equivalent of glue parameter number \|n\X\S$\6
+$\\{glue\_par}(\|n)$\par
+\Us158\ET160.\fi
+
+\M231. Sometimes we need to convert \TeX's internal code numbers into symbolic
+form. The \\{print\_skip\_param} routine gives the symbolic name of a glue
+parameter.
+
+\Y\P$\4\X231:Declare the procedure called \\{print\_skip\_param}\X\S$\6
+\4\&{procedure}\1\  \37$\\{print\_skip\_param}(\|n:\\{integer})$;\2\6
+\&{begin} \37\&{case} $\|n$ \1\&{of}\6
+\4\\{line\_skip\_code}: \37$\\{print\_esc}(\.{"lineskip"})$;\6
+\4\\{baseline\_skip\_code}: \37$\\{print\_esc}(\.{"baselineskip"})$;\6
+\4\\{par\_skip\_code}: \37$\\{print\_esc}(\.{"parskip"})$;\6
+\4\\{above\_display\_skip\_code}: \37$\\{print\_esc}(\.{"abovedisplayskip"})$;\6
+\4\\{below\_display\_skip\_code}: \37$\\{print\_esc}(\.{"belowdisplayskip"})$;\6
+\4\\{above\_display\_short\_skip\_code}: \37$\\{print\_esc}(%
+\.{"abovedisplayshortskip"})$;\6
+\4\\{below\_display\_short\_skip\_code}: \37$\\{print\_esc}(%
+\.{"belowdisplayshortskip"})$;\6
+\4\\{left\_skip\_code}: \37$\\{print\_esc}(\.{"leftskip"})$;\6
+\4\\{right\_skip\_code}: \37$\\{print\_esc}(\.{"rightskip"})$;\6
+\4\\{top\_skip\_code}: \37$\\{print\_esc}(\.{"topskip"})$;\6
+\4\\{split\_top\_skip\_code}: \37$\\{print\_esc}(\.{"splittopskip"})$;\6
+\4\\{tab\_skip\_code}: \37$\\{print\_esc}(\.{"tabskip"})$;\6
+\4\\{space\_skip\_code}: \37$\\{print\_esc}(\.{"spaceskip"})$;\6
+\4\\{xspace\_skip\_code}: \37$\\{print\_esc}(\.{"xspaceskip"})$;\6
+\4\\{par\_fill\_skip\_code}: \37$\\{print\_esc}(\.{"parfillskip"})$;\6
+\4\\{thin\_mu\_skip\_code}: \37$\\{print\_esc}(\.{"thinmuskip"})$;\6
+\4\\{med\_mu\_skip\_code}: \37$\\{print\_esc}(\.{"medmuskip"})$;\6
+\4\\{thick\_mu\_skip\_code}: \37$\\{print\_esc}(\.{"thickmuskip"})$;\6
+\4\\{kanji\_skip\_code}: \37$\\{print\_esc}(\.{"kanjiskip"})$;\6
+\4\\{xkanji\_skip\_code}: \37$\\{print\_esc}(\.{"xkanjiskip"})$;\6
+\4\\{jfm\_skip}: \37$\\{print}(\.{"refer\ from\ jfm"})$;\6
+\4\&{othercases} \37$\\{print}(\.{"[unknown\ glue\ parameter!]"})$\2\6
+\&{endcases};\6
+\&{end};\par
+\U185.\fi
+
+\M232. The symbolic names for glue parameters are put into \TeX's hash table
+by using the routine called \\{primitive}, defined below. Let us enter them
+now, so that we don't have to list all those parameter names anywhere else.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\S$\6
+$\\{primitive}(\.{"lineskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{line%
+\_skip\_code})$;\6
+$\\{primitive}(\.{"baselineskip"},\39\\{assign\_glue},\39\\{glue\_base}+%
+\\{baseline\_skip\_code})$;\6
+$\\{primitive}(\.{"parskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{par\_skip%
+\_code})$;\6
+$\\{primitive}(\.{"abovedisplayskip"},\39\\{assign\_glue},\39\\{glue\_base}+%
+\\{above\_display\_skip\_code})$;\6
+$\\{primitive}(\.{"belowdisplayskip"},\39\\{assign\_glue},\39\\{glue\_base}+%
+\\{below\_display\_skip\_code})$;\6
+$\\{primitive}(\.{"abovedisplayshortskip"},\39\\{assign\_glue},\39\\{glue%
+\_base}+\\{above\_display\_short\_skip\_code})$;\6
+$\\{primitive}(\.{"belowdisplayshortskip"},\39\\{assign\_glue},\39\\{glue%
+\_base}+\\{below\_display\_short\_skip\_code})$;\6
+$\\{primitive}(\.{"leftskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{left%
+\_skip\_code})$;\6
+$\\{primitive}(\.{"rightskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{right%
+\_skip\_code})$;\6
+$\\{primitive}(\.{"topskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{top\_skip%
+\_code})$;\6
+$\\{primitive}(\.{"splittopskip"},\39\\{assign\_glue},\39\\{glue\_base}+%
+\\{split\_top\_skip\_code})$;\6
+$\\{primitive}(\.{"tabskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{tab\_skip%
+\_code})$;\6
+$\\{primitive}(\.{"spaceskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{space%
+\_skip\_code})$;\6
+$\\{primitive}(\.{"xspaceskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{xspace%
+\_skip\_code})$;\6
+$\\{primitive}(\.{"parfillskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{par%
+\_fill\_skip\_code})$;\6
+$\\{primitive}(\.{"thinmuskip"},\39\\{assign\_mu\_glue},\39\\{glue\_base}+%
+\\{thin\_mu\_skip\_code})$;\6
+$\\{primitive}(\.{"medmuskip"},\39\\{assign\_mu\_glue},\39\\{glue\_base}+\\{med%
+\_mu\_skip\_code})$;\6
+$\\{primitive}(\.{"thickmuskip"},\39\\{assign\_mu\_glue},\39\\{glue\_base}+%
+\\{thick\_mu\_skip\_code})$;\6
+$\\{primitive}(\.{"kanjiskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{kanji%
+\_skip\_code})$;\6
+$\\{primitive}(\.{"xkanjiskip"},\39\\{assign\_glue},\39\\{glue\_base}+\\{xkanji%
+\_skip\_code})$;\par
+\As236, 244, 254, 271, 340, 387, 395, 422, 427, 479, 498, 502, 564, 791, 994,
+1064, 1070, 1083, 1100, 1119, 1126, 1153, 1168, 1181, 1190, 1200, 1220, 1231,
+1234, 1242, 1263, 1267, 1275, 1285, 1290, 1299, 1304, 1357, 1421, 1426, 1433%
+\ETs1438.
+\U1349.\fi
+
+\M233. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\S$\6
+\4$\\{assign\_glue},\39\\{assign\_mu\_glue}$: \37\&{if} $\\{chr\_code}<\\{skip%
+\_base}$ \1\&{then}\5
+$\\{print\_skip\_param}(\\{chr\_code}-\\{glue\_base})$\6
+\4\&{else} \&{if} $\\{chr\_code}<\\{mu\_skip\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"skip"})$;\5
+$\\{print\_int}(\\{chr\_code}-\\{skip\_base})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"muskip"})$;\5
+$\\{print\_int}(\\{chr\_code}-\\{mu\_skip\_base})$;\6
+\&{end};\2\2\par
+\As237, 245, 255, 272, 341, 388, 396, 423, 428, 480, 499, 503, 792, 995, 1065,
+1071, 1084, 1101, 1120, 1127, 1155, 1169, 1182, 1191, 1201, 1221, 1232, 1235,
+1243, 1264, 1268, 1274, 1276, 1286, 1291, 1300, 1305, 1308, 1359, 1422, 1427,
+1434\ETs1439.
+\U304.\fi
+
+\M234. All glue parameters and registers are initially `\.{0pt plus0pt
+minus0pt}'.
+
+\Y\P$\4\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}\S$%
+\6
+$\\{equiv}(\\{glue\_base})\K\\{zero\_glue}$;\5
+$\\{eq\_level}(\\{glue\_base})\K\\{level\_one}$;\5
+$\\{eq\_type}(\\{glue\_base})\K\\{glue\_ref}$;\6
+\&{for} $\|k\K\\{glue\_base}+1\mathrel{\&{to}}\\{local\_base}-1$ \1\&{do}\5
+$\\{eqtb}[\|k]\K\\{eqtb}[\\{glue\_base}]$;\2\6
+$\\{glue\_ref\_count}(\\{zero\_glue})\K\\{glue\_ref\_count}(\\{zero\_glue})+%
+\\{local\_base}-\\{glue\_base}$;\par
+\fi
+
+\M235. \P$\X235:Show equivalent \|n, in region 3\X\S$\6
+\&{if} $\|n<\\{skip\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_skip\_param}(\|n-\\{glue\_base})$;\5
+$\\{print\_char}(\.{"="})$;\6
+\&{if} $\|n<\\{glue\_base}+\\{thin\_mu\_skip\_code}$ \1\&{then}\5
+$\\{print\_spec}(\\{equiv}(\|n),\39\.{"pt"})$\6
+\4\&{else} $\\{print\_spec}(\\{equiv}(\|n),\39\.{"mu"})$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{mu\_skip\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"skip"})$;\5
+$\\{print\_int}(\|n-\\{skip\_base})$;\5
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_spec}(\\{equiv}(\|n),\39\.{"pt"})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"muskip"})$;\5
+$\\{print\_int}(\|n-\\{mu\_skip\_base})$;\5
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_spec}(\\{equiv}(\|n),\39\.{"mu"})$;\6
+\&{end}\2\2\par
+\U258.\fi
+
+\M236. Region 4 of \\{eqtb} contains the local quantities defined here. The
+bulk of this region is taken up by five tables that are indexed by eight-bit
+characters; these tables are important to both the syntactic and semantic
+portions of \TeX. There are also a bunch of special things like font and
+token parameters, as well as the tables of \.{\\toks} and \.{\\box}
+registers.
+
+\Y\P\D \37$\\{par\_shape\_loc}=\\{local\_base}$\C{specifies paragraph shape}\par
+\P\D \37$\\{output\_routine\_loc}=\\{local\_base}+1$\C{points to token list for
+\.{\\output}}\par
+\P\D \37$\\{every\_par\_loc}=\\{local\_base}+2$\C{points to token list for \.{%
+\\everypar}}\par
+\P\D \37$\\{every\_math\_loc}=\\{local\_base}+3$\C{points to token list for \.{%
+\\everymath}}\par
+\P\D \37$\\{every\_display\_loc}=\\{local\_base}+4$\C{points to token list for %
+\.{\\everydisplay}}\par
+\P\D \37$\\{every\_hbox\_loc}=\\{local\_base}+5$\C{points to token list for \.{%
+\\everyhbox}}\par
+\P\D \37$\\{every\_vbox\_loc}=\\{local\_base}+6$\C{points to token list for \.{%
+\\everyvbox}}\par
+\P\D \37$\\{every\_job\_loc}=\\{local\_base}+7$\C{points to token list for \.{%
+\\everyjob}}\par
+\P\D \37$\\{every\_cr\_loc}=\\{local\_base}+8$\C{points to token list for \.{%
+\\everycr}}\par
+\P\D \37$\\{err\_help\_loc}=\\{local\_base}+9$\C{points to token list for \.{%
+\\errhelp}}\par
+\P\D \37$\\{toks\_base}=\\{local\_base}+10$\C{table of 256 token list
+registers}\par
+\P\D \37$\\{box\_base}=\\{toks\_base}+256$\C{table of 256 box registers}\par
+\P\D \37$\\{cur\_font\_loc}=\\{box\_base}+256$\C{internal font number outside
+math mode}\par
+\P\D \37$\\{math\_font\_base}=\\{cur\_font\_loc}+1$\C{table of 48 math font
+numbers}\par
+\P\D \37$\\{cur\_jfont\_loc}=\\{math\_font\_base}+48$\par
+\P\D \37$\\{cur\_tfont\_loc}=\\{cur\_jfont\_loc}+1$\par
+\P\D \37$\\{auto\_spacing\_code}=\\{cur\_tfont\_loc}+1$\par
+\P\D \37$\\{auto\_xspacing\_code}=\\{auto\_spacing\_code}+1$\par
+\P\D \37$\\{cat\_code\_base}=\\{auto\_xspacing\_code}+1$\C{table of 256 command
+codes (the ``catcodes'')}\par
+\P\D \37$\\{kcat\_code\_base}=\\{cat\_code\_base}+256$\C{table of 256 command
+codes for the wchar's catcodes }\par
+\P\D \37$\\{auto\_xsp\_code\_base}=\\{kcat\_code\_base}+256$\C{table of 256
+auto spacer flag}\par
+\P\D \37$\\{inhibit\_xsp\_code\_base}=\\{auto\_xsp\_code\_base}+256$\par
+\P\D \37$\\{kinsoku\_base}=\\{inhibit\_xsp\_code\_base}+256$\C{table of 256
+kinsoku mappings}\par
+\P\D \37$\\{kansuji\_base}=\\{kinsoku\_base}+256$\C{table of 10 kansuji
+mappings}\par
+\P\D \37$\\{lc\_code\_base}=\\{kansuji\_base}+10$\C{table of 256 lowercase
+mappings}\par
+\P\D \37$\\{uc\_code\_base}=\\{lc\_code\_base}+256$\C{table of 256 uppercase
+mappings}\par
+\P\D \37$\\{sf\_code\_base}=\\{uc\_code\_base}+256$\C{table of 256 spacefactor
+mappings}\par
+\P\D \37$\\{math\_code\_base}=\\{sf\_code\_base}+256$\C{table of 256 math mode
+mappings}\par
+\P\D \37$\\{char\_sub\_code\_base}=\\{math\_code\_base}+256$\C{table of
+character substitutions}\par
+\P\D \37$\\{int\_base}=\\{char\_sub\_code\_base}+256$\C{beginning of region 5}%
+\Y\par
+\P\D \37$\\{par\_shape\_ptr}\S\\{equiv}(\\{par\_shape\_loc})$\par
+\P\D \37$\\{output\_routine}\S\\{equiv}(\\{output\_routine\_loc})$\par
+\P\D \37$\\{every\_par}\S\\{equiv}(\\{every\_par\_loc})$\par
+\P\D \37$\\{every\_math}\S\\{equiv}(\\{every\_math\_loc})$\par
+\P\D \37$\\{every\_display}\S\\{equiv}(\\{every\_display\_loc})$\par
+\P\D \37$\\{every\_hbox}\S\\{equiv}(\\{every\_hbox\_loc})$\par
+\P\D \37$\\{every\_vbox}\S\\{equiv}(\\{every\_vbox\_loc})$\par
+\P\D \37$\\{every\_job}\S\\{equiv}(\\{every\_job\_loc})$\par
+\P\D \37$\\{every\_cr}\S\\{equiv}(\\{every\_cr\_loc})$\par
+\P\D \37$\\{err\_help}\S\\{equiv}(\\{err\_help\_loc})$\par
+\P\D \37$\\{toks}(\#)\S\\{equiv}(\\{toks\_base}+\#)$\par
+\P\D \37$\\{box}(\#)\S\\{equiv}(\\{box\_base}+\#)$\par
+\P\D \37$\\{cur\_font}\S\\{equiv}(\\{cur\_font\_loc})$\par
+\P\D \37$\\{fam\_fnt}(\#)\S\\{equiv}(\\{math\_font\_base}+\#)$\par
+\P\D \37$\\{cat\_code}(\#)\S\\{equiv}(\\{cat\_code\_base}+\#)$\par
+\P\D \37$\\{lc\_code}(\#)\S\\{equiv}(\\{lc\_code\_base}+\#)$\par
+\P\D \37$\\{uc\_code}(\#)\S\\{equiv}(\\{uc\_code\_base}+\#)$\par
+\P\D \37$\\{sf\_code}(\#)\S\\{equiv}(\\{sf\_code\_base}+\#)$\par
+\P\D \37$\\{math\_code}(\#)\S\\{equiv}(\\{math\_code\_base}+\#)$\C{Note: $%
+\\{math\_code}(\|c)$ is the true math code plus \\{min\_halfword}}\par
+\P\D \37$\\{char\_sub\_code}(\#)\S\\{equiv}(\\{char\_sub\_code\_base}+\#)$%
+\C{Note: $\\{char\_sub\_code}(\|c)$ is the true substitution info plus \\{min%
+\_halfword}}\Y\par
+\P\D \37$\\{cur\_jfont}\S\\{equiv}(\\{cur\_jfont\_loc})$\C{pTeX: }\par
+\P\D \37$\\{cur\_tfont}\S\\{equiv}(\\{cur\_tfont\_loc})$\par
+\P\D \37$\\{auto\_spacing}\S\\{equiv}(\\{auto\_spacing\_code})$\par
+\P\D \37$\\{auto\_xspacing}\S\\{equiv}(\\{auto\_xspacing\_code})$\par
+\P\D \37$\\{kcat\_code}(\#)\S\\{equiv}(\\{kcat\_code\_base}+\#)$\par
+\P\D \37$\\{auto\_xsp\_code}(\#)\S\\{equiv}(\\{auto\_xsp\_code\_base}+\#)$\par
+\P\D \37$\\{inhibit\_xsp\_type}(\#)\S\\{eq\_type}(\\{inhibit\_xsp\_code\_base}+%
+\#)$\par
+\P\D \37$\\{inhibit\_xsp\_code}(\#)\S\\{equiv}(\\{inhibit\_xsp\_code\_base}+%
+\#)$\par
+\P\D \37$\\{kinsoku\_type}(\#)\S\\{eq\_type}(\\{kinsoku\_base}+\#)$\par
+\P\D \37$\\{kinsoku\_code}(\#)\S\\{equiv}(\\{kinsoku\_base}+\#)$\par
+\P\D \37$\\{kansuji\_char}(\#)\S\\{equiv}(\\{kansuji\_base}+\#)$\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"output"},\39\\{assign\_toks},\39\\{output\_routine\_loc})$;\5
+$\\{primitive}(\.{"everypar"},\39\\{assign\_toks},\39\\{every\_par\_loc})$;\5
+$\\{primitive}(\.{"everymath"},\39\\{assign\_toks},\39\\{every\_math\_loc})$;\5
+$\\{primitive}(\.{"everydisplay"},\39\\{assign\_toks},\39\\{every\_display%
+\_loc})$;\5
+$\\{primitive}(\.{"everyhbox"},\39\\{assign\_toks},\39\\{every\_hbox\_loc})$;\5
+$\\{primitive}(\.{"everyvbox"},\39\\{assign\_toks},\39\\{every\_vbox\_loc})$;\5
+$\\{primitive}(\.{"everyjob"},\39\\{assign\_toks},\39\\{every\_job\_loc})$;\5
+$\\{primitive}(\.{"everycr"},\39\\{assign\_toks},\39\\{every\_cr\_loc})$;\5
+$\\{primitive}(\.{"errhelp"},\39\\{assign\_toks},\39\\{err\_help\_loc})$;\par
+\fi
+
+\M237. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{assign\_toks}: \37\&{if} $\\{chr\_code}\G\\{toks\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"toks"})$;\5
+$\\{print\_int}(\\{chr\_code}-\\{toks\_base})$;\6
+\&{end}\6
+\4\&{else} \&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{output\_routine\_loc}: \37$\\{print\_esc}(\.{"output"})$;\6
+\4\\{every\_par\_loc}: \37$\\{print\_esc}(\.{"everypar"})$;\6
+\4\\{every\_math\_loc}: \37$\\{print\_esc}(\.{"everymath"})$;\6
+\4\\{every\_display\_loc}: \37$\\{print\_esc}(\.{"everydisplay"})$;\6
+\4\\{every\_hbox\_loc}: \37$\\{print\_esc}(\.{"everyhbox"})$;\6
+\4\\{every\_vbox\_loc}: \37$\\{print\_esc}(\.{"everyvbox"})$;\6
+\4\\{every\_job\_loc}: \37$\\{print\_esc}(\.{"everyjob"})$;\6
+\4\\{every\_cr\_loc}: \37$\\{print\_esc}(\.{"everycr"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"errhelp"})$\2\6
+\&{endcases};\2\par
+\fi
+
+\M238. We initialize most things to null or undefined values. An undefined font
+is represented by the internal code \\{font\_base}.
+
+However, the character code tables are given initial values based on the
+conventional interpretation of ASCII code. These initial values should
+not be changed when \TeX\ is adapted for use with non-English languages;
+all changes to the initialization conventions should be made in format
+packages, not in \TeX\ itself, so that global interchange of formats is
+possible.
+
+\Y\P\D \37$\\{null\_font}\S\\{font\_base}$\par
+\P\D \37$\\{var\_code}\S\O{70000}$\C{math code meaning ``use the current
+family''}\par
+\Y\P$\4\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}\S$%
+\6
+$\\{par\_shape\_ptr}\K\\{null}$;\5
+$\\{eq\_type}(\\{par\_shape\_loc})\K\\{shape\_ref}$;\5
+$\\{eq\_level}(\\{par\_shape\_loc})\K\\{level\_one}$;\6
+\&{for} $\|k\K\\{output\_routine\_loc}\mathrel{\&{to}}\\{toks\_base}+255$ \1%
+\&{do}\5
+$\\{eqtb}[\|k]\K\\{eqtb}[\\{undefined\_control\_sequence}]$;\2\6
+$\\{box}(0)\K\\{null}$;\5
+$\\{eq\_type}(\\{box\_base})\K\\{box\_ref}$;\5
+$\\{eq\_level}(\\{box\_base})\K\\{level\_one}$;\6
+\&{for} $\|k\K\\{box\_base}+1\mathrel{\&{to}}\\{box\_base}+255$ \1\&{do}\5
+$\\{eqtb}[\|k]\K\\{eqtb}[\\{box\_base}]$;\2\6
+$\\{cur\_font}\K\\{null\_font}$;\5
+$\\{eq\_type}(\\{cur\_font\_loc})\K\\{data}$;\5
+$\\{eq\_level}(\\{cur\_font\_loc})\K\\{level\_one}$;\6
+$\\{cur\_jfont}\K\\{null\_font}$;\5
+$\\{eq\_type}(\\{cur\_jfont\_loc})\K\\{data}$;\5
+$\\{eq\_level}(\\{cur\_jfont\_loc})\K\\{level\_one}$;\6
+$\\{cur\_tfont}\K\\{null\_font}$;\5
+$\\{eq\_type}(\\{cur\_tfont\_loc})\K\\{data}$;\5
+$\\{eq\_level}(\\{cur\_tfont\_loc})\K\\{level\_one}$;\6
+\&{for} $\|k\K\\{math\_font\_base}\mathrel{\&{to}}\\{math\_font\_base}+47$ \1%
+\&{do}\5
+$\\{eqtb}[\|k]\K\\{eqtb}[\\{cur\_font\_loc}]$;\2\6
+$\\{equiv}(\\{cat\_code\_base})\K0$;\5
+$\\{eq\_type}(\\{cat\_code\_base})\K\\{data}$;\5
+$\\{eq\_level}(\\{cat\_code\_base})\K\\{level\_one}$;\6
+\&{for} $\|k\K\\{cat\_code\_base}+1\mathrel{\&{to}}\\{int\_base}-1$ \1\&{do}\5
+$\\{eqtb}[\|k]\K\\{eqtb}[\\{cat\_code\_base}]$;\2\6
+$\\{eqtb}[\\{auto\_spacing\_code}]\K\\{eqtb}[\\{cat\_code\_base}]$;\5
+$\\{eqtb}[\\{auto\_xspacing\_code}]\K\\{eqtb}[\\{cat\_code\_base}]$;\6
+\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\6
+\&{begin} \37$\\{cat\_code}(\|k)\K\\{other\_char}$;\5
+$\\{kcat\_code}(\|k)\K\\{other\_kchar}$;\5
+$\\{math\_code}(\|k)\K\\{hi}(\|k)$;\5
+$\\{sf\_code}(\|k)\K1000$;\5
+$\\{auto\_xsp\_code}(\|k)\K0$;\5
+$\\{inhibit\_xsp\_code}(\|k)\K0$;\5
+$\\{inhibit\_xsp\_type}(\|k)\K0$;\5
+$\\{kinsoku\_code}(\|k)\K0$;\5
+$\\{kinsoku\_type}(\|k)\K0$;\6
+\&{end};\2\6
+$\\{cat\_code}(\\{carriage\_return})\K\\{car\_ret}$;\5
+$\\{cat\_code}(\.{"\ "})\K\\{spacer}$;\5
+$\\{cat\_code}(\.{"\\"})\K\\{escape}$;\5
+$\\{cat\_code}(\.{"\%"})\K\\{comment}$;\5
+$\\{cat\_code}(\\{invalid\_code})\K\\{invalid\_char}$;\5
+$\\{cat\_code}(\\{null\_code})\K\\{ignore}$;\6
+\&{for} $\|k\K\.{"0"}\mathrel{\&{to}}\.{"9"}$ \1\&{do}\6
+\&{begin} \37$\\{math\_code}(\|k)\K\\{hi}(\|k+\\{var\_code})$;\5
+$\\{auto\_xsp\_code}(\|k)\K3$;\6
+\&{end};\2\6
+$\\{kansuji\_char}(0)\K\\{toDVI}(\\{fromJIS}(\H{213B}))$;\5
+$\\{kansuji\_char}(1)\K\\{toDVI}(\\{fromJIS}(\H{306C}))$;\5
+$\\{kansuji\_char}(2)\K\\{toDVI}(\\{fromJIS}(\H{4673}))$;\5
+$\\{kansuji\_char}(3)\K\\{toDVI}(\\{fromJIS}(\H{3B30}))$;\5
+$\\{kansuji\_char}(4)\K\\{toDVI}(\\{fromJIS}(\H{3B4D}))$;\5
+$\\{kansuji\_char}(5)\K\\{toDVI}(\\{fromJIS}(\H{385E}))$;\5
+$\\{kansuji\_char}(6)\K\\{toDVI}(\\{fromJIS}(\H{4F3B}))$;\5
+$\\{kansuji\_char}(7)\K\\{toDVI}(\\{fromJIS}(\H{3C37}))$;\5
+$\\{kansuji\_char}(8)\K\\{toDVI}(\\{fromJIS}(\H{482C}))$;\5
+$\\{kansuji\_char}(9)\K\\{toDVI}(\\{fromJIS}(\H{3665}))$;\6
+\&{for} $\|k\K\.{"A"}\mathrel{\&{to}}\.{"Z"}$ \1\&{do}\6
+\&{begin} \37$\\{cat\_code}(\|k)\K\\{letter}$;\5
+$\\{cat\_code}(\|k+\.{"a"}-\.{"A"})\K\\{letter}$;\6
+$\\{math\_code}(\|k)\K\\{hi}(\|k+\\{var\_code}+\H{100})$;\5
+$\\{math\_code}(\|k+\.{"a"}-\.{"A"})\K\\{hi}(\|k+\.{"a"}-\.{"A"}+\\{var\_code}+%
+\H{100})$;\6
+$\\{lc\_code}(\|k)\K\|k+\.{"a"}-\.{"A"}$;\5
+$\\{lc\_code}(\|k+\.{"a"}-\.{"A"})\K\|k+\.{"a"}-\.{"A"}$;\6
+$\\{uc\_code}(\|k)\K\|k$;\5
+$\\{uc\_code}(\|k+\.{"a"}-\.{"A"})\K\|k$;\6
+$\\{auto\_xsp\_code}(\|k)\K3$;\5
+$\\{auto\_xsp\_code}(\|k+\.{"a"}-\.{"A"})\K3$;\6
+$\\{sf\_code}(\|k)\K999$;\6
+\&{end};\2\6
+$\hbox{\hskip10pt}\\{kcat\_code}(\H{20}+1)\K\\{other\_kchar}$;\C{1 ku}\6
+$\hbox{\hskip10pt}\\{kcat\_code}(\H{20}+2)\K\\{other\_kchar}$;\C{2 ku}\ \hbox{%
+\1} \6
+\&{for} $\|k\K3\mathrel{\&{to}}6$ \1\&{do}\5
+$\\{kcat\_code}(\H{20}+\|k)\K\\{kana}$;\C{3 ku ... 6 ku}\ \2\6
+\hbox{\1} \6
+\&{for} $\|k\K7\mathrel{\&{to}}8$ \1\&{do}\5
+$\\{kcat\_code}(\H{20}+\|k)\K\\{other\_kchar}$;\C{7 ku ... 8 ku}\ \2\6
+\hbox{\1} \6
+\&{for} $\|k\K16\mathrel{\&{to}}84$ \1\&{do}\5
+$\\{kcat\_code}(\H{20}+\|k)\K\\{kanji}$;\C{16 ku ... 84 ku}\6
+\C{ $\.{@"20}+\|k = \\{kcatcodekey}(\\{fromKUTEN}(\\{HILO}(k,1))$ }\2\par
+\fi
+
+\M239. \P$\X239:Show equivalent \|n, in region 4\X\S$\6
+\&{if} $\|n=\\{par\_shape\_loc}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"parshape"})$;\5
+$\\{print\_char}(\.{"="})$;\6
+\&{if} $\\{par\_shape\_ptr}=\\{null}$ \1\&{then}\5
+$\\{print\_char}(\.{"0"})$\6
+\4\&{else} $\\{print\_int}(\\{info}(\\{par\_shape\_ptr}))$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{toks\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_cmd\_chr}(\\{assign\_toks},\39\|n)$;\5
+$\\{print\_char}(\.{"="})$;\6
+\&{if} $\\{equiv}(\|n)\I\\{null}$ \1\&{then}\5
+$\\{show\_token\_list}(\\{link}(\\{equiv}(\|n)),\39\\{null},\3932)$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{box\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"toks"})$;\5
+$\\{print\_int}(\|n-\\{toks\_base})$;\5
+$\\{print\_char}(\.{"="})$;\6
+\&{if} $\\{equiv}(\|n)\I\\{null}$ \1\&{then}\5
+$\\{show\_token\_list}(\\{link}(\\{equiv}(\|n)),\39\\{null},\3932)$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{cur\_font\_loc}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"box"})$;\5
+$\\{print\_int}(\|n-\\{box\_base})$;\5
+$\\{print\_char}(\.{"="})$;\6
+\&{if} $\\{equiv}(\|n)=\\{null}$ \1\&{then}\5
+$\\{print}(\.{"void"})$\6
+\4\&{else} \&{begin} \37$\\{depth\_threshold}\K0$;\5
+$\\{breadth\_max}\K1$;\5
+$\\{show\_node\_list}(\\{equiv}(\|n))$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{cat\_code\_base}$ \1\&{then}\5
+\X240:Show the font identifier in $\\{eqtb}[\|n]$\X\6
+\4\&{else} \X241:Show the halfword code in $\\{eqtb}[\|n]$\X\2\2\2\2\2\par
+\U258.\fi
+
+\M240. \P$\X240:Show the font identifier in $\\{eqtb}[\|n]$\X\S$\6
+\&{begin} \37\&{if} $\|n=\\{cur\_font\_loc}$ \1\&{then}\5
+$\\{print}(\.{"current\ font"})$\6
+\4\&{else} \&{if} $\|n<\\{math\_font\_base}+16$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"textfont"})$;\5
+$\\{print\_int}(\|n-\\{math\_font\_base})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{math\_font\_base}+32$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"scriptfont"})$;\5
+$\\{print\_int}(\|n-\\{math\_font\_base}-16)$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"scriptscriptfont"})$;\5
+$\\{print\_int}(\|n-\\{math\_font\_base}-32)$;\6
+\&{end};\2\2\2\6
+$\\{print\_char}(\.{"="})$;\6
+$\\{print\_esc}(\\{hash}[\\{font\_id\_base}+\\{equiv}(\|n)].\\{rh})$;\C{that's
+$\\{font\_id\_text}(\\{equiv}(\|n))$}\6
+\&{end}\par
+\U239.\fi
+
+\M241. \P$\X241:Show the halfword code in $\\{eqtb}[\|n]$\X\S$\6
+\&{if} $\|n<\\{math\_code\_base}$ \1\&{then}\6
+\&{begin} \37\&{if} $\|n<\\{kcat\_code\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"catcode"})$;\5
+$\\{print\_int}(\|n-\\{cat\_code\_base})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{auto\_xsp\_code\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"kcatcode"})$;\5
+$\\{print\_int}(\|n-\\{kcat\_code\_base})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{inhibit\_xsp\_code\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"xspcode"})$;\5
+$\\{print\_int}(\|n-\\{auto\_xsp\_code\_base})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{kinsoku\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"(inhibitxspcode\ table)\ "})$;\5
+$\\{print\_int}(\|n-\\{inhibit\_xsp\_code\_base})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{kansuji\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"(kinsoku\ table)\ "})$;\5
+$\\{print\_int}(\|n-\\{kinsoku\_base})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{lc\_code\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"kansujichar"})$;\5
+$\\{print\_int}(\|n-\\{kansuji\_base})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{uc\_code\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"lccode"})$;\5
+$\\{print\_int}(\|n-\\{lc\_code\_base})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<\\{sf\_code\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"uccode"})$;\5
+$\\{print\_int}(\|n-\\{uc\_code\_base})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"sfcode"})$;\5
+$\\{print\_int}(\|n-\\{sf\_code\_base})$;\6
+\&{end};\2\2\2\2\2\2\2\2\6
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_int}(\\{equiv}(\|n))$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"mathcode"})$;\5
+$\\{print\_int}(\|n-\\{math\_code\_base})$;\5
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_int}(\\{ho}(\\{equiv}(\|n)))$;\6
+\&{end}\2\par
+\U239.\fi
+
+\M242. Region 5 of \\{eqtb} contains the integer parameters and registers
+defined
+here, as well as the \\{del\_code} table. The latter table differs from the
+$\\{cat\_code}\to\\{math\_code}$ tables that precede it, since delimiter codes
+are
+fullword integers while the other kinds of codes occupy at most a
+halfword. This is what makes region~5 different from region~4. We will
+store the \\{eq\_level} information in an auxiliary array of quarterwords
+that will be defined later.
+
+\Y\P\D \37$\\{pretolerance\_code}=0$\C{badness tolerance before hyphenation}\par
+\P\D \37$\\{tolerance\_code}=1$\C{badness tolerance after hyphenation}\par
+\P\D \37$\\{line\_penalty\_code}=2$\C{added to the badness of every line}\par
+\P\D \37$\\{hyphen\_penalty\_code}=3$\C{penalty for break after discretionary
+hyphen}\par
+\P\D \37$\\{ex\_hyphen\_penalty\_code}=4$\C{penalty for break after explicit
+hyphen}\par
+\P\D \37$\\{club\_penalty\_code}=5$\C{penalty for creating a club line}\par
+\P\D \37$\\{widow\_penalty\_code}=6$\C{penalty for creating a widow line}\par
+\P\D \37$\\{display\_widow\_penalty\_code}=7$\C{ditto, just before a display}%
+\par
+\P\D \37$\\{broken\_penalty\_code}=8$\C{penalty for breaking a page at a broken
+line}\par
+\P\D \37$\\{bin\_op\_penalty\_code}=9$\C{penalty for breaking after a binary
+operation}\par
+\P\D \37$\\{rel\_penalty\_code}=10$\C{penalty for breaking after a relation}\par
+\P\D \37$\\{pre\_display\_penalty\_code}=11$\C{penalty for breaking just before
+a displayed formula}\par
+\P\D \37$\\{post\_display\_penalty\_code}=12$\C{penalty for breaking just after
+a displayed formula}\par
+\P\D \37$\\{inter\_line\_penalty\_code}=13$\C{additional penalty between lines}%
+\par
+\P\D \37$\\{double\_hyphen\_demerits\_code}=14$\C{demerits for double hyphen
+break}\par
+\P\D \37$\\{final\_hyphen\_demerits\_code}=15$\C{demerits for final hyphen
+break}\par
+\P\D \37$\\{adj\_demerits\_code}=16$\C{demerits for adjacent incompatible
+lines}\par
+\P\D \37$\\{mag\_code}=17$\C{magnification ratio}\par
+\P\D \37$\\{delimiter\_factor\_code}=18$\C{ratio for variable-size delimiters}%
+\par
+\P\D \37$\\{looseness\_code}=19$\C{change in number of lines for a paragraph}%
+\par
+\P\D \37$\\{time\_code}=20$\C{current time of day}\par
+\P\D \37$\\{day\_code}=21$\C{current day of the month}\par
+\P\D \37$\\{month\_code}=22$\C{current month of the year}\par
+\P\D \37$\\{year\_code}=23$\C{current year of our Lord}\par
+\P\D \37$\\{show\_box\_breadth\_code}=24$\C{nodes per level in \\{show\_box}}%
+\par
+\P\D \37$\\{show\_box\_depth\_code}=25$\C{maximum level in \\{show\_box}}\par
+\P\D \37$\\{hbadness\_code}=26$\C{hboxes exceeding this badness will be shown
+by \\{hpack}}\par
+\P\D \37$\\{vbadness\_code}=27$\C{vboxes exceeding this badness will be shown
+by \\{vpack}}\par
+\P\D \37$\\{pausing\_code}=28$\C{pause after each line is read from a file}\par
+\P\D \37$\\{tracing\_online\_code}=29$\C{show diagnostic output on terminal}\par
+\P\D \37$\\{tracing\_macros\_code}=30$\C{show macros as they are being
+expanded}\par
+\P\D \37$\\{tracing\_stats\_code}=31$\C{show memory usage if \TeX\ knows it}\par
+\P\D \37$\\{tracing\_paragraphs\_code}=32$\C{show line-break calculations}\par
+\P\D \37$\\{tracing\_pages\_code}=33$\C{show page-break calculations}\par
+\P\D \37$\\{tracing\_output\_code}=34$\C{show boxes when they are shipped out}%
+\par
+\P\D \37$\\{tracing\_lost\_chars\_code}=35$\C{show characters that aren't in
+the font}\par
+\P\D \37$\\{tracing\_commands\_code}=36$\C{show command codes at \\{big%
+\_switch}}\par
+\P\D \37$\\{tracing\_restores\_code}=37$\C{show equivalents when they are
+restored}\par
+\P\D \37$\\{uc\_hyph\_code}=38$\C{hyphenate words beginning with a capital
+letter}\par
+\P\D \37$\\{output\_penalty\_code}=39$\C{penalty found at current page break}%
+\par
+\P\D \37$\\{max\_dead\_cycles\_code}=40$\C{bound on consecutive dead cycles of
+output}\par
+\P\D \37$\\{hang\_after\_code}=41$\C{hanging indentation changes after this
+many lines}\par
+\P\D \37$\\{floating\_penalty\_code}=42$\C{penalty for insertions heldover
+after a split}\par
+\P\D \37$\\{global\_defs\_code}=43$\C{override \.{\\global} specifications}\par
+\P\D \37$\\{cur\_fam\_code}=44$\C{current family}\par
+\P\D \37$\\{cur\_jfam\_code}=45$\C{current kanji family}\par
+\P\D \37$\\{escape\_char\_code}=46$\C{escape character for token output}\par
+\P\D \37$\\{default\_hyphen\_char\_code}=47$\C{value of \.{\\hyphenchar} when a
+font is loaded}\par
+\P\D \37$\\{default\_skew\_char\_code}=48$\C{value of \.{\\skewchar} when a
+font is loaded}\par
+\P\D \37$\\{end\_line\_char\_code}=49$\C{character placed at the right end of
+the buffer}\par
+\P\D \37$\\{new\_line\_char\_code}=50$\C{character that prints as \\{print%
+\_ln}}\par
+\P\D \37$\\{language\_code}=51$\C{current hyphenation table}\par
+\P\D \37$\\{left\_hyphen\_min\_code}=52$\C{minimum left hyphenation fragment
+size}\par
+\P\D \37$\\{right\_hyphen\_min\_code}=53$\C{minimum right hyphenation fragment
+size}\par
+\P\D \37$\\{holding\_inserts\_code}=54$\C{do not remove insertion nodes from %
+\.{\\box255}}\par
+\P\D \37$\\{error\_context\_lines\_code}=55$\C{maximum intermediate line pairs
+shown}\par
+\P\D \37$\\{jchr\_widow\_penalty\_code}=56$\C{penalty for creating a widow
+KANJI character line}\par
+\P\D \37$\\{char\_sub\_def\_min\_code}=57$\C{smallest value in the charsubdef
+list}\par
+\P\D \37$\\{char\_sub\_def\_max\_code}=58$\C{largest value in the charsubdef
+list}\par
+\P\D \37$\\{tracing\_char\_sub\_def\_code}=59$\C{traces changes to a charsubdef
+def}\par
+\P\D \37$\\{int\_pars}=60$\C{total number of integer parameters}\par
+\P\D \37$\\{count\_base}=\\{int\_base}+\\{int\_pars}$\C{256 user \.{\\count}
+registers}\par
+\P\D \37$\\{del\_code\_base}=\\{count\_base}+256$\C{256 delimiter code
+mappings}\par
+\P\D \37$\\{dimen\_base}=\\{del\_code\_base}+256$\C{beginning of region 6}\Y\par
+\P\D \37$\\{del\_code}(\#)\S\\{eqtb}[\\{del\_code\_base}+\#].\\{int}$\par
+\P\D \37$\\{count}(\#)\S\\{eqtb}[\\{count\_base}+\#].\\{int}$\par
+\P\D \37$\\{int\_par}(\#)\S\\{eqtb}[\\{int\_base}+\#].\\{int}$\C{an integer
+parameter}\par
+\P\D \37$\\{pretolerance}\S\\{int\_par}(\\{pretolerance\_code})$\par
+\P\D \37$\\{tolerance}\S\\{int\_par}(\\{tolerance\_code})$\par
+\P\D \37$\\{line\_penalty}\S\\{int\_par}(\\{line\_penalty\_code})$\par
+\P\D \37$\\{hyphen\_penalty}\S\\{int\_par}(\\{hyphen\_penalty\_code})$\par
+\P\D \37$\\{ex\_hyphen\_penalty}\S\\{int\_par}(\\{ex\_hyphen\_penalty\_code})$%
+\par
+\P\D \37$\\{club\_penalty}\S\\{int\_par}(\\{club\_penalty\_code})$\par
+\P\D \37$\\{widow\_penalty}\S\\{int\_par}(\\{widow\_penalty\_code})$\par
+\P\D \37$\\{display\_widow\_penalty}\S\\{int\_par}(\\{display\_widow\_penalty%
+\_code})$\par
+\P\D \37$\\{broken\_penalty}\S\\{int\_par}(\\{broken\_penalty\_code})$\par
+\P\D \37$\\{bin\_op\_penalty}\S\\{int\_par}(\\{bin\_op\_penalty\_code})$\par
+\P\D \37$\\{rel\_penalty}\S\\{int\_par}(\\{rel\_penalty\_code})$\par
+\P\D \37$\\{pre\_display\_penalty}\S\\{int\_par}(\\{pre\_display\_penalty%
+\_code})$\par
+\P\D \37$\\{post\_display\_penalty}\S\\{int\_par}(\\{post\_display\_penalty%
+\_code})$\par
+\P\D \37$\\{inter\_line\_penalty}\S\\{int\_par}(\\{inter\_line\_penalty%
+\_code})$\par
+\P\D \37$\\{double\_hyphen\_demerits}\S\\{int\_par}(\\{double\_hyphen\_demerits%
+\_code})$\par
+\P\D \37$\\{final\_hyphen\_demerits}\S\\{int\_par}(\\{final\_hyphen\_demerits%
+\_code})$\par
+\P\D \37$\\{adj\_demerits}\S\\{int\_par}(\\{adj\_demerits\_code})$\par
+\P\D \37$\\{mag}\S\\{int\_par}(\\{mag\_code})$\par
+\P\D \37$\\{delimiter\_factor}\S\\{int\_par}(\\{delimiter\_factor\_code})$\par
+\P\D \37$\\{looseness}\S\\{int\_par}(\\{looseness\_code})$\par
+\P\D \37$\\{time}\S\\{int\_par}(\\{time\_code})$\par
+\P\D \37$\\{day}\S\\{int\_par}(\\{day\_code})$\par
+\P\D \37$\\{month}\S\\{int\_par}(\\{month\_code})$\par
+\P\D \37$\\{year}\S\\{int\_par}(\\{year\_code})$\par
+\P\D \37$\\{show\_box\_breadth}\S\\{int\_par}(\\{show\_box\_breadth\_code})$\par
+\P\D \37$\\{show\_box\_depth}\S\\{int\_par}(\\{show\_box\_depth\_code})$\par
+\P\D \37$\\{hbadness}\S\\{int\_par}(\\{hbadness\_code})$\par
+\P\D \37$\\{vbadness}\S\\{int\_par}(\\{vbadness\_code})$\par
+\P\D \37$\\{pausing}\S\\{int\_par}(\\{pausing\_code})$\par
+\P\D \37$\\{tracing\_online}\S\\{int\_par}(\\{tracing\_online\_code})$\par
+\P\D \37$\\{tracing\_macros}\S\\{int\_par}(\\{tracing\_macros\_code})$\par
+\P\D \37$\\{tracing\_stats}\S\\{int\_par}(\\{tracing\_stats\_code})$\par
+\P\D \37$\\{tracing\_paragraphs}\S\\{int\_par}(\\{tracing\_paragraphs\_code})$%
+\par
+\P\D \37$\\{tracing\_pages}\S\\{int\_par}(\\{tracing\_pages\_code})$\par
+\P\D \37$\\{tracing\_output}\S\\{int\_par}(\\{tracing\_output\_code})$\par
+\P\D \37$\\{tracing\_lost\_chars}\S\\{int\_par}(\\{tracing\_lost\_chars%
+\_code})$\par
+\P\D \37$\\{tracing\_commands}\S\\{int\_par}(\\{tracing\_commands\_code})$\par
+\P\D \37$\\{tracing\_restores}\S\\{int\_par}(\\{tracing\_restores\_code})$\par
+\P\D \37$\\{uc\_hyph}\S\\{int\_par}(\\{uc\_hyph\_code})$\par
+\P\D \37$\\{output\_penalty}\S\\{int\_par}(\\{output\_penalty\_code})$\par
+\P\D \37$\\{max\_dead\_cycles}\S\\{int\_par}(\\{max\_dead\_cycles\_code})$\par
+\P\D \37$\\{hang\_after}\S\\{int\_par}(\\{hang\_after\_code})$\par
+\P\D \37$\\{floating\_penalty}\S\\{int\_par}(\\{floating\_penalty\_code})$\par
+\P\D \37$\\{global\_defs}\S\\{int\_par}(\\{global\_defs\_code})$\par
+\P\D \37$\\{cur\_fam}\S\\{int\_par}(\\{cur\_fam\_code})$\par
+\P\D \37$\\{cur\_jfam}\S\\{int\_par}(\\{cur\_jfam\_code})$\par
+\P\D \37$\\{escape\_char}\S\\{int\_par}(\\{escape\_char\_code})$\par
+\P\D \37$\\{jchr\_widow\_penalty}\S\\{int\_par}(\\{jchr\_widow\_penalty%
+\_code})$\par
+\P\D \37$\\{default\_hyphen\_char}\S\\{int\_par}(\\{default\_hyphen\_char%
+\_code})$\par
+\P\D \37$\\{default\_skew\_char}\S\\{int\_par}(\\{default\_skew\_char\_code})$%
+\par
+\P\D \37$\\{end\_line\_char}\S\\{int\_par}(\\{end\_line\_char\_code})$\par
+\P\D \37$\\{new\_line\_char}\S\\{int\_par}(\\{new\_line\_char\_code})$\par
+\P\D \37$\\{language}\S\\{int\_par}(\\{language\_code})$\par
+\P\D \37$\\{left\_hyphen\_min}\S\\{int\_par}(\\{left\_hyphen\_min\_code})$\par
+\P\D \37$\\{right\_hyphen\_min}\S\\{int\_par}(\\{right\_hyphen\_min\_code})$\par
+\P\D \37$\\{holding\_inserts}\S\\{int\_par}(\\{holding\_inserts\_code})$\par
+\P\D \37$\\{error\_context\_lines}\S\\{int\_par}(\\{error\_context\_lines%
+\_code})$\Y\par
+\P\D \37$\\{char\_sub\_def\_min}\S\\{int\_par}(\\{char\_sub\_def\_min\_code})$%
+\par
+\P\D \37$\\{char\_sub\_def\_max}\S\\{int\_par}(\\{char\_sub\_def\_max\_code})$%
+\par
+\P\D \37$\\{tracing\_char\_sub\_def}\S\\{int\_par}(\\{tracing\_char\_sub\_def%
+\_code})$\par
+\Y\P$\4\X242:Assign the values $\\{depth\_threshold}\K\\{show\_box\_depth}$ and
+$\\{breadth\_max}\K\\{show\_box\_breadth}$\X\S$\6
+$\\{depth\_threshold}\K\\{show\_box\_depth}$;\5
+$\\{breadth\_max}\K\\{show\_box\_breadth}$\par
+\U204.\fi
+
+\M243. We can print the symbolic name of an integer parameter as follows.
+
+\Y\P\4\&{procedure}\1\  \37$\\{print\_param}(\|n:\\{integer})$;\2\6
+\&{begin} \37\&{case} $\|n$ \1\&{of}\6
+\4\\{pretolerance\_code}: \37$\\{print\_esc}(\.{"pretolerance"})$;\6
+\4\\{tolerance\_code}: \37$\\{print\_esc}(\.{"tolerance"})$;\6
+\4\\{line\_penalty\_code}: \37$\\{print\_esc}(\.{"linepenalty"})$;\6
+\4\\{hyphen\_penalty\_code}: \37$\\{print\_esc}(\.{"hyphenpenalty"})$;\6
+\4\\{ex\_hyphen\_penalty\_code}: \37$\\{print\_esc}(\.{"exhyphenpenalty"})$;\6
+\4\\{club\_penalty\_code}: \37$\\{print\_esc}(\.{"clubpenalty"})$;\6
+\4\\{widow\_penalty\_code}: \37$\\{print\_esc}(\.{"widowpenalty"})$;\6
+\4\\{display\_widow\_penalty\_code}: \37$\\{print\_esc}(%
+\.{"displaywidowpenalty"})$;\6
+\4\\{broken\_penalty\_code}: \37$\\{print\_esc}(\.{"brokenpenalty"})$;\6
+\4\\{bin\_op\_penalty\_code}: \37$\\{print\_esc}(\.{"binoppenalty"})$;\6
+\4\\{rel\_penalty\_code}: \37$\\{print\_esc}(\.{"relpenalty"})$;\6
+\4\\{pre\_display\_penalty\_code}: \37$\\{print\_esc}(%
+\.{"predisplaypenalty"})$;\6
+\4\\{post\_display\_penalty\_code}: \37$\\{print\_esc}(%
+\.{"postdisplaypenalty"})$;\6
+\4\\{inter\_line\_penalty\_code}: \37$\\{print\_esc}(\.{"interlinepenalty"})$;\6
+\4\\{double\_hyphen\_demerits\_code}: \37$\\{print\_esc}(%
+\.{"doublehyphendemerits"})$;\6
+\4\\{final\_hyphen\_demerits\_code}: \37$\\{print\_esc}(%
+\.{"finalhyphendemerits"})$;\6
+\4\\{adj\_demerits\_code}: \37$\\{print\_esc}(\.{"adjdemerits"})$;\6
+\4\\{mag\_code}: \37$\\{print\_esc}(\.{"mag"})$;\6
+\4\\{delimiter\_factor\_code}: \37$\\{print\_esc}(\.{"delimiterfactor"})$;\6
+\4\\{looseness\_code}: \37$\\{print\_esc}(\.{"looseness"})$;\6
+\4\\{time\_code}: \37$\\{print\_esc}(\.{"time"})$;\6
+\4\\{day\_code}: \37$\\{print\_esc}(\.{"day"})$;\6
+\4\\{month\_code}: \37$\\{print\_esc}(\.{"month"})$;\6
+\4\\{year\_code}: \37$\\{print\_esc}(\.{"year"})$;\6
+\4\\{show\_box\_breadth\_code}: \37$\\{print\_esc}(\.{"showboxbreadth"})$;\6
+\4\\{show\_box\_depth\_code}: \37$\\{print\_esc}(\.{"showboxdepth"})$;\6
+\4\\{hbadness\_code}: \37$\\{print\_esc}(\.{"hbadness"})$;\6
+\4\\{vbadness\_code}: \37$\\{print\_esc}(\.{"vbadness"})$;\6
+\4\\{pausing\_code}: \37$\\{print\_esc}(\.{"pausing"})$;\6
+\4\\{tracing\_online\_code}: \37$\\{print\_esc}(\.{"tracingonline"})$;\6
+\4\\{tracing\_macros\_code}: \37$\\{print\_esc}(\.{"tracingmacros"})$;\6
+\4\\{tracing\_stats\_code}: \37$\\{print\_esc}(\.{"tracingstats"})$;\6
+\4\\{tracing\_paragraphs\_code}: \37$\\{print\_esc}(\.{"tracingparagraphs"})$;\6
+\4\\{tracing\_pages\_code}: \37$\\{print\_esc}(\.{"tracingpages"})$;\6
+\4\\{tracing\_output\_code}: \37$\\{print\_esc}(\.{"tracingoutput"})$;\6
+\4\\{tracing\_lost\_chars\_code}: \37$\\{print\_esc}(\.{"tracinglostchars"})$;\6
+\4\\{tracing\_commands\_code}: \37$\\{print\_esc}(\.{"tracingcommands"})$;\6
+\4\\{tracing\_restores\_code}: \37$\\{print\_esc}(\.{"tracingrestores"})$;\6
+\4\\{uc\_hyph\_code}: \37$\\{print\_esc}(\.{"uchyph"})$;\6
+\4\\{output\_penalty\_code}: \37$\\{print\_esc}(\.{"outputpenalty"})$;\6
+\4\\{max\_dead\_cycles\_code}: \37$\\{print\_esc}(\.{"maxdeadcycles"})$;\6
+\4\\{hang\_after\_code}: \37$\\{print\_esc}(\.{"hangafter"})$;\6
+\4\\{floating\_penalty\_code}: \37$\\{print\_esc}(\.{"floatingpenalty"})$;\6
+\4\\{global\_defs\_code}: \37$\\{print\_esc}(\.{"globaldefs"})$;\6
+\4\\{cur\_fam\_code}: \37$\\{print\_esc}(\.{"fam"})$;\6
+\4\\{escape\_char\_code}: \37$\\{print\_esc}(\.{"escapechar"})$;\6
+\4\\{default\_hyphen\_char\_code}: \37$\\{print\_esc}(%
+\.{"defaulthyphenchar"})$;\6
+\4\\{default\_skew\_char\_code}: \37$\\{print\_esc}(\.{"defaultskewchar"})$;\6
+\4\\{end\_line\_char\_code}: \37$\\{print\_esc}(\.{"endlinechar"})$;\6
+\4\\{new\_line\_char\_code}: \37$\\{print\_esc}(\.{"newlinechar"})$;\6
+\4\\{cur\_jfam\_code}: \37$\\{print\_esc}(\.{"jfam"})$;\6
+\4\\{jchr\_widow\_penalty\_code}: \37$\\{print\_esc}(\.{"jcharwidowpenalty"})$;%
+\6
+\4\\{language\_code}: \37$\\{print\_esc}(\.{"language"})$;\6
+\4\\{left\_hyphen\_min\_code}: \37$\\{print\_esc}(\.{"lefthyphenmin"})$;\6
+\4\\{right\_hyphen\_min\_code}: \37$\\{print\_esc}(\.{"righthyphenmin"})$;\6
+\4\\{holding\_inserts\_code}: \37$\\{print\_esc}(\.{"holdinginserts"})$;\6
+\4\\{error\_context\_lines\_code}: \37$\\{print\_esc}(%
+\.{"errorcontextlines"})$;\6
+\4\\{char\_sub\_def\_min\_code}: \37$\\{print\_esc}(\.{"charsubdefmin"})$;\6
+\4\\{char\_sub\_def\_max\_code}: \37$\\{print\_esc}(\.{"charsubdefmax"})$;\6
+\4\\{tracing\_char\_sub\_def\_code}: \37$\\{print\_esc}(%
+\.{"tracingcharsubdef"})$;\6
+\4\&{othercases} \37$\\{print}(\.{"[unknown\ integer\ parameter!]"})$\2\6
+\&{endcases};\6
+\&{end};\par
+\fi
+
+\M244. The integer parameter names must be entered into the hash table.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"pretolerance"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{pretolerance\_code})$;\6
+$\\{primitive}(\.{"tolerance"},\39\\{assign\_int},\39\\{int\_base}+\\{tolerance%
+\_code})$;\6
+$\\{primitive}(\.{"linepenalty"},\39\\{assign\_int},\39\\{int\_base}+\\{line%
+\_penalty\_code})$;\6
+$\\{primitive}(\.{"hyphenpenalty"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{hyphen\_penalty\_code})$;\6
+$\\{primitive}(\.{"exhyphenpenalty"},\39\\{assign\_int},\39\\{int\_base}+\\{ex%
+\_hyphen\_penalty\_code})$;\6
+$\\{primitive}(\.{"clubpenalty"},\39\\{assign\_int},\39\\{int\_base}+\\{club%
+\_penalty\_code})$;\6
+$\\{primitive}(\.{"widowpenalty"},\39\\{assign\_int},\39\\{int\_base}+\\{widow%
+\_penalty\_code})$;\6
+$\\{primitive}(\.{"displaywidowpenalty"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{display\_widow\_penalty\_code})$;\6
+$\\{primitive}(\.{"brokenpenalty"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{broken\_penalty\_code})$;\6
+$\\{primitive}(\.{"binoppenalty"},\39\\{assign\_int},\39\\{int\_base}+\\{bin%
+\_op\_penalty\_code})$;\6
+$\\{primitive}(\.{"relpenalty"},\39\\{assign\_int},\39\\{int\_base}+\\{rel%
+\_penalty\_code})$;\6
+$\\{primitive}(\.{"predisplaypenalty"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{pre\_display\_penalty\_code})$;\6
+$\\{primitive}(\.{"postdisplaypenalty"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{post\_display\_penalty\_code})$;\6
+$\\{primitive}(\.{"interlinepenalty"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{inter\_line\_penalty\_code})$;\6
+$\\{primitive}(\.{"doublehyphendemerits"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{double\_hyphen\_demerits\_code})$;\6
+$\\{primitive}(\.{"finalhyphendemerits"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{final\_hyphen\_demerits\_code})$;\6
+$\\{primitive}(\.{"adjdemerits"},\39\\{assign\_int},\39\\{int\_base}+\\{adj%
+\_demerits\_code})$;\6
+$\\{primitive}(\.{"mag"},\39\\{assign\_int},\39\\{int\_base}+\\{mag\_code})$;\6
+$\\{primitive}(\.{"delimiterfactor"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{delimiter\_factor\_code})$;\6
+$\\{primitive}(\.{"looseness"},\39\\{assign\_int},\39\\{int\_base}+\\{looseness%
+\_code})$;\6
+$\\{primitive}(\.{"time"},\39\\{assign\_int},\39\\{int\_base}+\\{time\_code})$;%
+\6
+$\\{primitive}(\.{"day"},\39\\{assign\_int},\39\\{int\_base}+\\{day\_code})$;\6
+$\\{primitive}(\.{"month"},\39\\{assign\_int},\39\\{int\_base}+\\{month%
+\_code})$;\6
+$\\{primitive}(\.{"year"},\39\\{assign\_int},\39\\{int\_base}+\\{year\_code})$;%
+\6
+$\\{primitive}(\.{"showboxbreadth"},\39\\{assign\_int},\39\\{int\_base}+\\{show%
+\_box\_breadth\_code})$;\6
+$\\{primitive}(\.{"showboxdepth"},\39\\{assign\_int},\39\\{int\_base}+\\{show%
+\_box\_depth\_code})$;\6
+$\\{primitive}(\.{"hbadness"},\39\\{assign\_int},\39\\{int\_base}+\\{hbadness%
+\_code})$;\6
+$\\{primitive}(\.{"vbadness"},\39\\{assign\_int},\39\\{int\_base}+\\{vbadness%
+\_code})$;\6
+$\\{primitive}(\.{"pausing"},\39\\{assign\_int},\39\\{int\_base}+\\{pausing%
+\_code})$;\6
+$\\{primitive}(\.{"tracingonline"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_online\_code})$;\6
+$\\{primitive}(\.{"tracingmacros"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_macros\_code})$;\6
+$\\{primitive}(\.{"tracingstats"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_stats\_code})$;\6
+$\\{primitive}(\.{"tracingparagraphs"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_paragraphs\_code})$;\6
+$\\{primitive}(\.{"tracingpages"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_pages\_code})$;\6
+$\\{primitive}(\.{"tracingoutput"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_output\_code})$;\6
+$\\{primitive}(\.{"tracinglostchars"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_lost\_chars\_code})$;\6
+$\\{primitive}(\.{"tracingcommands"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_commands\_code})$;\6
+$\\{primitive}(\.{"tracingrestores"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_restores\_code})$;\6
+$\\{primitive}(\.{"uchyph"},\39\\{assign\_int},\39\\{int\_base}+\\{uc\_hyph%
+\_code})$;\6
+$\\{primitive}(\.{"outputpenalty"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{output\_penalty\_code})$;\6
+$\\{primitive}(\.{"maxdeadcycles"},\39\\{assign\_int},\39\\{int\_base}+\\{max%
+\_dead\_cycles\_code})$;\6
+$\\{primitive}(\.{"hangafter"},\39\\{assign\_int},\39\\{int\_base}+\\{hang%
+\_after\_code})$;\6
+$\\{primitive}(\.{"floatingpenalty"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{floating\_penalty\_code})$;\6
+$\\{primitive}(\.{"globaldefs"},\39\\{assign\_int},\39\\{int\_base}+\\{global%
+\_defs\_code})$;\6
+$\\{primitive}(\.{"fam"},\39\\{assign\_int},\39\\{int\_base}+\\{cur\_fam%
+\_code})$;\6
+$\\{primitive}(\.{"escapechar"},\39\\{assign\_int},\39\\{int\_base}+\\{escape%
+\_char\_code})$;\6
+$\\{primitive}(\.{"defaulthyphenchar"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{default\_hyphen\_char\_code})$;\6
+$\\{primitive}(\.{"defaultskewchar"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{default\_skew\_char\_code})$;\6
+$\\{primitive}(\.{"endlinechar"},\39\\{assign\_int},\39\\{int\_base}+\\{end%
+\_line\_char\_code})$;\6
+$\\{primitive}(\.{"newlinechar"},\39\\{assign\_int},\39\\{int\_base}+\\{new%
+\_line\_char\_code})$;\6
+$\\{primitive}(\.{"jfam"},\39\\{assign\_int},\39\\{int\_base}+\\{cur\_jfam%
+\_code})$;\6
+$\\{primitive}(\.{"jcharwidowpenalty"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{jchr\_widow\_penalty\_code})$;\6
+$\\{primitive}(\.{"language"},\39\\{assign\_int},\39\\{int\_base}+\\{language%
+\_code})$;\6
+$\\{primitive}(\.{"lefthyphenmin"},\39\\{assign\_int},\39\\{int\_base}+\\{left%
+\_hyphen\_min\_code})$;\6
+$\\{primitive}(\.{"righthyphenmin"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{right\_hyphen\_min\_code})$;\6
+$\\{primitive}(\.{"holdinginserts"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{holding\_inserts\_code})$;\6
+$\\{primitive}(\.{"errorcontextlines"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{error\_context\_lines\_code})$;\6
+\&{if} $\\{mltex\_p}$ \1\&{then}\6
+\&{begin} \37$\\{mltex\_enabled\_p}\K\\{true}$;\C{enable character
+substitution}\6
+\&{if} $\\{false}$ \1\&{then}\C{remove the if-clause to enable \.{%
+\\charsubdefmin}}\6
+$\\{primitive}(\.{"charsubdefmin"},\39\\{assign\_int},\39\\{int\_base}+\\{char%
+\_sub\_def\_min\_code})$;\2\6
+$\\{primitive}(\.{"charsubdefmax"},\39\\{assign\_int},\39\\{int\_base}+\\{char%
+\_sub\_def\_max\_code})$;\6
+$\\{primitive}(\.{"tracingcharsubdef"},\39\\{assign\_int},\39\\{int\_base}+%
+\\{tracing\_char\_sub\_def\_code})$;\6
+\&{end};\2\par
+\fi
+
+\M245. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{assign\_int}: \37\&{if} $\\{chr\_code}<\\{count\_base}$ \1\&{then}\5
+$\\{print\_param}(\\{chr\_code}-\\{int\_base})$\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"count"})$;\5
+$\\{print\_int}(\\{chr\_code}-\\{count\_base})$;\6
+\&{end};\2\par
+\fi
+
+\M246. The integer parameters should really be initialized by a macro package;
+the following initialization does the minimum to keep \TeX\ from
+complete failure.
+
+\Y\P$\4\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}\S$%
+\6
+\&{for} $\|k\K\\{int\_base}\mathrel{\&{to}}\\{del\_code\_base}-1$ \1\&{do}\5
+$\\{eqtb}[\|k].\\{int}\K0$;\2\6
+$\\{char\_sub\_def\_min}\K256$;\5
+$\\{char\_sub\_def\_max}\K-1$;\C{allow \.{\\charsubdef} for char 0}\6
+\C{$\\{tracing\_char\_sub\_def}\K0$ is already done}\6
+$\\{mag}\K1000$;\5
+$\\{tolerance}\K10000$;\5
+$\\{hang\_after}\K1$;\5
+$\\{max\_dead\_cycles}\K25$;\5
+$\\{escape\_char}\K\.{"\\"}$;\5
+$\\{end\_line\_char}\K\\{carriage\_return}$;\6
+\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{del\_code}(\|k)\K-1$;\2\6
+$\\{del\_code}(\.{"."})\K0$;\C{this null delimiter is used in error recovery}%
+\par
+\fi
+
+\M247. The following procedure, which is called just before \TeX\ initializes
+its
+input and output, establishes the initial values of the date and time.
+It calls a macro-defined \\{date\_and\_time} routine.  \\{date\_and\_time}
+in turn is a C macro, which calls \\{get\_date\_and\_time}, passing
+it the addresses of the day, month, etc., so they can be set by the
+routine.  \\{get\_date\_and\_time} also sets up interrupt catching if that
+is conditionally compiled in the C code.
+
+\Y\P\D \37$\\{fix\_date\_and\_time}\S\\{date\_and\_time}(\\{time},\39\\{day},%
+\39\\{month},\39\\{year})$\par
+\fi
+
+\M248. \P$\X248:Show equivalent \|n, in region 5\X\S$\6
+\&{begin} \37\&{if} $\|n<\\{count\_base}$ \1\&{then}\5
+$\\{print\_param}(\|n-\\{int\_base})$\6
+\4\&{else} \&{if} $\|n<\\{del\_code\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"count"})$;\5
+$\\{print\_int}(\|n-\\{count\_base})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"delcode"})$;\5
+$\\{print\_int}(\|n-\\{del\_code\_base})$;\6
+\&{end};\2\2\6
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_int}(\\{eqtb}[\|n].\\{int})$;\6
+\&{end}\par
+\U258.\fi
+
+\M249. \P$\X249:Set variable \|c to the current escape character\X\S$\6
+$\|c\K\\{escape\_char}$\par
+\U64.\fi
+
+\M250. \P$\X250:Character \|s is the current new-line character\X\S$\6
+$\|s=\\{new\_line\_char}$\par
+\Us59\ET60.\fi
+
+\M251. \TeX\ is occasionally supposed to print diagnostic information that
+goes only into the transcript file, unless \\{tracing\_online} is positive.
+Here are two routines that adjust the destination of print commands:
+
+\Y\P\4\&{procedure}\1\  \37\\{begin\_diagnostic};\C{prepare to do some tracing}%
+\2\6
+\&{begin} \37$\\{old\_setting}\K\\{selector}$;\6
+\&{if} $(\\{tracing\_online}\L0)\W(\\{selector}=\\{term\_and\_log})$ \1\&{then}%
+\6
+\&{begin} \37$\\{decr}(\\{selector})$;\6
+\&{if} $\\{history}=\\{spotless}$ \1\&{then}\5
+$\\{history}\K\\{warning\_issued}$;\2\6
+\&{end};\2\6
+\&{end};\7
+\4\&{procedure}\1\  \37$\\{end\_diagnostic}(\\{blank\_line}:\\{boolean})$;%
+\C{restore proper conditions after tracing}\2\6
+\&{begin} \37$\\{print\_nl}(\.{""})$;\6
+\&{if} $\\{blank\_line}$ \1\&{then}\5
+\\{print\_ln};\2\6
+$\\{selector}\K\\{old\_setting}$;\6
+\&{end};\par
+\fi
+
+\M252. Of course we had better declare another global variable, if the previous
+routines are going to work.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{old\_setting}: \37$0\to\\{max\_selector}$;\par
+\fi
+
+\M253. The final region of \\{eqtb} contains the dimension parameters defined
+here, and the 256 \.{\\dimen} registers.
+
+\Y\P\D \37$\\{par\_indent\_code}=0$\C{indentation of paragraphs}\par
+\P\D \37$\\{math\_surround\_code}=1$\C{space around math in text}\par
+\P\D \37$\\{line\_skip\_limit\_code}=2$\C{threshold for \\{line\_skip} instead
+of \\{baseline\_skip}}\par
+\P\D \37$\\{hsize\_code}=3$\C{line width in horizontal mode}\par
+\P\D \37$\\{vsize\_code}=4$\C{page height in vertical mode}\par
+\P\D \37$\\{max\_depth\_code}=5$\C{maximum depth of boxes on main pages}\par
+\P\D \37$\\{split\_max\_depth\_code}=6$\C{maximum depth of boxes on split
+pages}\par
+\P\D \37$\\{box\_max\_depth\_code}=7$\C{maximum depth of explicit vboxes}\par
+\P\D \37$\\{hfuzz\_code}=8$\C{tolerance for overfull hbox messages}\par
+\P\D \37$\\{vfuzz\_code}=9$\C{tolerance for overfull vbox messages}\par
+\P\D \37$\\{delimiter\_shortfall\_code}=10$\C{maximum amount uncovered by
+variable delimiters}\par
+\P\D \37$\\{null\_delimiter\_space\_code}=11$\C{blank space in null delimiters}%
+\par
+\P\D \37$\\{script\_space\_code}=12$\C{extra space after subscript or
+superscript}\par
+\P\D \37$\\{pre\_display\_size\_code}=13$\C{length of text preceding a display}%
+\par
+\P\D \37$\\{display\_width\_code}=14$\C{length of line for displayed equation}%
+\par
+\P\D \37$\\{display\_indent\_code}=15$\C{indentation of line for displayed
+equation}\par
+\P\D \37$\\{overfull\_rule\_code}=16$\C{width of rule that identifies overfull
+hboxes}\par
+\P\D \37$\\{hang\_indent\_code}=17$\C{amount of hanging indentation}\par
+\P\D \37$\\{h\_offset\_code}=18$\C{amount of horizontal offset when shipping
+pages out}\par
+\P\D \37$\\{v\_offset\_code}=19$\C{amount of vertical offset when shipping
+pages out}\par
+\P\D \37$\\{emergency\_stretch\_code}=20$\C{reduces badnesses on final pass of
+line-breaking}\par
+\P\D \37$\\{t\_baseline\_shift\_code}=21$\C{shift amount when mixing TATE-kumi
+and Alphabet}\par
+\P\D \37$\\{y\_baseline\_shift\_code}=22$\C{shift amount when mixing YOKO-kumi
+and Alphabet}\par
+\P\D \37$\\{dimen\_pars}=23$\C{total number of dimension parameters}\par
+\P\D \37$\\{scaled\_base}=\\{dimen\_base}+\\{dimen\_pars}$\C{table of 256
+user-defined \.{\\dimen} registers}\par
+\P\D \37$\\{kinsoku\_penalty\_base}=\\{scaled\_base}+256$\C{table of 256
+kinsoku registers}\par
+\P\D \37$\\{eqtb\_size}=\\{kinsoku\_penalty\_base}+255$\C{largest subscript of %
+\\{eqtb}}\Y\par
+\P\D \37$\\{dimen}(\#)\S\\{eqtb}[\\{scaled\_base}+\#].\\{sc}$\par
+\P\D \37$\\{dimen\_par}(\#)\S\\{eqtb}[\\{dimen\_base}+\#].\\{sc}$\C{a scaled
+quantity}\par
+\P\D \37$\\{kinsoku\_penalty}(\#)\S\\{eqtb}[\\{kinsoku\_penalty\_base}+\#].%
+\\{int}$\par
+\P\D \37$\\{par\_indent}\S\\{dimen\_par}(\\{par\_indent\_code})$\par
+\P\D \37$\\{math\_surround}\S\\{dimen\_par}(\\{math\_surround\_code})$\par
+\P\D \37$\\{line\_skip\_limit}\S\\{dimen\_par}(\\{line\_skip\_limit\_code})$\par
+\P\D \37$\\{hsize}\S\\{dimen\_par}(\\{hsize\_code})$\par
+\P\D \37$\\{vsize}\S\\{dimen\_par}(\\{vsize\_code})$\par
+\P\D \37$\\{max\_depth}\S\\{dimen\_par}(\\{max\_depth\_code})$\par
+\P\D \37$\\{split\_max\_depth}\S\\{dimen\_par}(\\{split\_max\_depth\_code})$\par
+\P\D \37$\\{box\_max\_depth}\S\\{dimen\_par}(\\{box\_max\_depth\_code})$\par
+\P\D \37$\\{hfuzz}\S\\{dimen\_par}(\\{hfuzz\_code})$\par
+\P\D \37$\\{vfuzz}\S\\{dimen\_par}(\\{vfuzz\_code})$\par
+\P\D \37$\\{delimiter\_shortfall}\S\\{dimen\_par}(\\{delimiter\_shortfall%
+\_code})$\par
+\P\D \37$\\{null\_delimiter\_space}\S\\{dimen\_par}(\\{null\_delimiter\_space%
+\_code})$\par
+\P\D \37$\\{script\_space}\S\\{dimen\_par}(\\{script\_space\_code})$\par
+\P\D \37$\\{pre\_display\_size}\S\\{dimen\_par}(\\{pre\_display\_size\_code})$%
+\par
+\P\D \37$\\{display\_width}\S\\{dimen\_par}(\\{display\_width\_code})$\par
+\P\D \37$\\{display\_indent}\S\\{dimen\_par}(\\{display\_indent\_code})$\par
+\P\D \37$\\{overfull\_rule}\S\\{dimen\_par}(\\{overfull\_rule\_code})$\par
+\P\D \37$\\{hang\_indent}\S\\{dimen\_par}(\\{hang\_indent\_code})$\par
+\P\D \37$\\{h\_offset}\S\\{dimen\_par}(\\{h\_offset\_code})$\par
+\P\D \37$\\{v\_offset}\S\\{dimen\_par}(\\{v\_offset\_code})$\par
+\P\D \37$\\{t\_baseline\_shift}\S\\{dimen\_par}(\\{t\_baseline\_shift\_code})$%
+\par
+\P\D \37$\\{y\_baseline\_shift}\S\\{dimen\_par}(\\{y\_baseline\_shift\_code})$%
+\par
+\P\D \37$\\{emergency\_stretch}\S\\{dimen\_par}(\\{emergency\_stretch\_code})$%
+\par
+\Y\P\4\&{procedure}\1\  \37$\\{print\_length\_param}(\|n:\\{integer})$;\2\6
+\&{begin} \37\&{case} $\|n$ \1\&{of}\6
+\4\\{par\_indent\_code}: \37$\\{print\_esc}(\.{"parindent"})$;\6
+\4\\{math\_surround\_code}: \37$\\{print\_esc}(\.{"mathsurround"})$;\6
+\4\\{line\_skip\_limit\_code}: \37$\\{print\_esc}(\.{"lineskiplimit"})$;\6
+\4\\{hsize\_code}: \37$\\{print\_esc}(\.{"hsize"})$;\6
+\4\\{vsize\_code}: \37$\\{print\_esc}(\.{"vsize"})$;\6
+\4\\{max\_depth\_code}: \37$\\{print\_esc}(\.{"maxdepth"})$;\6
+\4\\{split\_max\_depth\_code}: \37$\\{print\_esc}(\.{"splitmaxdepth"})$;\6
+\4\\{box\_max\_depth\_code}: \37$\\{print\_esc}(\.{"boxmaxdepth"})$;\6
+\4\\{hfuzz\_code}: \37$\\{print\_esc}(\.{"hfuzz"})$;\6
+\4\\{vfuzz\_code}: \37$\\{print\_esc}(\.{"vfuzz"})$;\6
+\4\\{delimiter\_shortfall\_code}: \37$\\{print\_esc}(%
+\.{"delimitershortfall"})$;\6
+\4\\{null\_delimiter\_space\_code}: \37$\\{print\_esc}(%
+\.{"nulldelimiterspace"})$;\6
+\4\\{script\_space\_code}: \37$\\{print\_esc}(\.{"scriptspace"})$;\6
+\4\\{pre\_display\_size\_code}: \37$\\{print\_esc}(\.{"predisplaysize"})$;\6
+\4\\{display\_width\_code}: \37$\\{print\_esc}(\.{"displaywidth"})$;\6
+\4\\{display\_indent\_code}: \37$\\{print\_esc}(\.{"displayindent"})$;\6
+\4\\{overfull\_rule\_code}: \37$\\{print\_esc}(\.{"overfullrule"})$;\6
+\4\\{hang\_indent\_code}: \37$\\{print\_esc}(\.{"hangindent"})$;\6
+\4\\{h\_offset\_code}: \37$\\{print\_esc}(\.{"hoffset"})$;\6
+\4\\{v\_offset\_code}: \37$\\{print\_esc}(\.{"voffset"})$;\6
+\4\\{t\_baseline\_shift\_code}: \37$\\{print\_esc}(\.{"tbaselineshift"})$;\6
+\4\\{y\_baseline\_shift\_code}: \37$\\{print\_esc}(\.{"ybaselineshift"})$;\6
+\4\\{emergency\_stretch\_code}: \37$\\{print\_esc}(\.{"emergencystretch"})$;\6
+\4\&{othercases} \37$\\{print}(\.{"[unknown\ dimen\ parameter!]"})$\2\6
+\&{endcases};\6
+\&{end};\par
+\fi
+
+\M254. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"parindent"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{par%
+\_indent\_code})$;\6
+$\\{primitive}(\.{"mathsurround"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{math\_surround\_code})$;\6
+$\\{primitive}(\.{"lineskiplimit"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{line\_skip\_limit\_code})$;\6
+$\\{primitive}(\.{"hsize"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{hsize%
+\_code})$;\6
+$\\{primitive}(\.{"vsize"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{vsize%
+\_code})$;\6
+$\\{primitive}(\.{"maxdepth"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{max%
+\_depth\_code})$;\6
+$\\{primitive}(\.{"splitmaxdepth"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{split\_max\_depth\_code})$;\6
+$\\{primitive}(\.{"boxmaxdepth"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{box%
+\_max\_depth\_code})$;\6
+$\\{primitive}(\.{"hfuzz"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{hfuzz%
+\_code})$;\6
+$\\{primitive}(\.{"vfuzz"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{vfuzz%
+\_code})$;\6
+$\\{primitive}(\.{"delimitershortfall"},\39\\{assign\_dimen},\39\\{dimen%
+\_base}+\\{delimiter\_shortfall\_code})$;\6
+$\\{primitive}(\.{"nulldelimiterspace"},\39\\{assign\_dimen},\39\\{dimen%
+\_base}+\\{null\_delimiter\_space\_code})$;\6
+$\\{primitive}(\.{"scriptspace"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{script\_space\_code})$;\6
+$\\{primitive}(\.{"predisplaysize"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{pre\_display\_size\_code})$;\6
+$\\{primitive}(\.{"displaywidth"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{display\_width\_code})$;\6
+$\\{primitive}(\.{"displayindent"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{display\_indent\_code})$;\6
+$\\{primitive}(\.{"overfullrule"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{overfull\_rule\_code})$;\6
+$\\{primitive}(\.{"hangindent"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{hang%
+\_indent\_code})$;\6
+$\\{primitive}(\.{"hoffset"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{h%
+\_offset\_code})$;\6
+$\\{primitive}(\.{"voffset"},\39\\{assign\_dimen},\39\\{dimen\_base}+\\{v%
+\_offset\_code})$;\6
+$\\{primitive}(\.{"tbaselineshift"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{t\_baseline\_shift\_code})$;\6
+$\\{primitive}(\.{"ybaselineshift"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{y\_baseline\_shift\_code})$;\6
+$\\{primitive}(\.{"emergencystretch"},\39\\{assign\_dimen},\39\\{dimen\_base}+%
+\\{emergency\_stretch\_code})$;\par
+\fi
+
+\M255. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{assign\_dimen}: \37\&{if} $\\{chr\_code}<\\{scaled\_base}$ \1\&{then}\5
+$\\{print\_length\_param}(\\{chr\_code}-\\{dimen\_base})$\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"dimen"})$;\5
+$\\{print\_int}(\\{chr\_code}-\\{scaled\_base})$;\6
+\&{end};\2\par
+\fi
+
+\M256. \P$\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}%
+\S$\6
+\&{for} $\|k\K\\{dimen\_base}\mathrel{\&{to}}\\{eqtb\_size}$ \1\&{do}\5
+$\\{eqtb}[\|k].\\{sc}\K0$;\2\par
+\fi
+
+\M257. \P$\X257:Show equivalent \|n, in region 6\X\S$\6
+\&{begin} \37\&{if} $\|n<\\{scaled\_base}$ \1\&{then}\5
+$\\{print\_length\_param}(\|n-\\{dimen\_base})$\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"dimen"})$;\5
+$\\{print\_int}(\|n-\\{scaled\_base})$;\6
+\&{end};\2\6
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_scaled}(\\{eqtb}[\|n].\\{sc})$;\5
+$\\{print}(\.{"pt"})$;\6
+\&{end}\par
+\U258.\fi
+
+\M258. Here is a procedure that displays the contents of $\\{eqtb}[\|n]$
+symbolically.
+
+\Y\P\hbox{\4}\X304:Declare the procedure called \\{print\_cmd\_chr}\X\6
+\&{stat} \37\&{procedure}\1\  \37$\\{show\_eqtb}(\|n:\\{pointer})$;\2\6
+\&{begin} \37\&{if} $\|n<\\{active\_base}$ \1\&{then}\5
+$\\{print\_char}(\.{"?"})$\C{this can't happen}\6
+\4\&{else} \&{if} $(\|n<\\{glue\_base})\V((\|n>\\{eqtb\_size})\W(\|n\L\\{eqtb%
+\_top}))$ \1\&{then}\5
+\X229:Show equivalent \|n, in region 1 or 2\X\6
+\4\&{else} \&{if} $\|n<\\{local\_base}$ \1\&{then}\5
+\X235:Show equivalent \|n, in region 3\X\6
+\4\&{else} \&{if} $\|n<\\{int\_base}$ \1\&{then}\5
+\X239:Show equivalent \|n, in region 4\X\6
+\4\&{else} \&{if} $\|n<\\{dimen\_base}$ \1\&{then}\5
+\X248:Show equivalent \|n, in region 5\X\6
+\4\&{else} \&{if} $\|n<\\{kinsoku\_penalty\_base}$ \1\&{then}\5
+\X257:Show equivalent \|n, in region 6\X\6
+\4\&{else} \&{if} $\|n\L\\{eqtb\_size}$ \1\&{then}\5
+$\\{print}(\.{"kinsoku"})$\6
+\4\&{else} $\\{print\_char}(\.{"?"})$;\C{this can't happen either}\2\2\2\2\2\2%
+\2\6
+\&{end};\6
+\&{tats}\par
+\fi
+
+\M259. The last two regions of \\{eqtb} have fullword values instead of the
+three fields \\{eq\_level}, \\{eq\_type}, and \\{equiv}. An \\{eq\_type} is
+unnecessary,
+but \TeX\ needs to store the \\{eq\_level} information in another array
+called \\{xeq\_level}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{zeqtb}: \37$\^\\{memory\_word}$;\6
+\4\\{xeq\_level}: \37\&{array} $[\\{int\_base}\to\\{eqtb\_size}]$ \1\&{of}\5
+\\{quarterword};\2\par
+\fi
+
+\M260. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+\&{for} $\|k\K\\{int\_base}\mathrel{\&{to}}\\{eqtb\_size}$ \1\&{do}\5
+$\\{xeq\_level}[\|k]\K\\{level\_one}$;\2\par
+\fi
+
+\M261. When the debugging routine \\{search\_mem} is looking for pointers
+having a
+given value, it is interested only in regions 1 to~3 of~\\{eqtb}, and in the
+first part of region~4.
+
+\Y\P$\4\X261:Search \\{eqtb} for equivalents equal to \|p\X\S$\6
+\&{for} $\|q\K\\{active\_base}\mathrel{\&{to}}\\{box\_base}+255$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{equiv}(\|q)=\|p$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"EQUIV("})$;\5
+$\\{print\_int}(\|q)$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\6
+\&{end}\2\par
+\U178.\fi
+
+\N262.  \[18] The hash table.
+Control sequences are stored and retrieved by means of a fairly standard hash
+table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
+in {\sl The Art of Computer Programming\/}). Once a control sequence enters the
+table, it is never removed, because there are complicated situations
+involving \.{\\gdef} where the removal of a control sequence at the end of
+a group would be a mistake preventable only by the introduction of a
+complicated reference-count mechanism.
+
+The actual sequence of letters forming a control sequence identifier is
+stored in the \\{str\_pool} array together with all the other strings. An
+auxiliary array \\{hash} consists of items with two halfword fields per
+word. The first of these, called $\\{next}(\|p)$, points to the next identifier
+belonging to the same coalesced list as the identifier corresponding to~\|p;
+and the other, called $\\{text}(\|p)$, points to the \\{str\_start} entry for
+\|p's identifier. If position~\|p of the hash table is empty, we have
+$\\{text}(\|p)=0$; if position \|p is either empty or the end of a coalesced
+hash list, we have $\\{next}(\|p)=0$. An auxiliary pointer variable called
+\\{hash\_used} is maintained in such a way that all locations $\|p\G\\{hash%
+\_used}$
+are nonempty. The global variable \\{cs\_count} tells how many multiletter
+control sequences have been defined, if statistics are being kept.
+
+A global boolean variable called \\{no\_new\_control\_sequence} is set to
+\\{true} during the time that new hash table entries are forbidden.
+
+\Y\P\D \37$\\{next}(\#)\S\\{hash}[\#].\\{lh}$\C{link for coalesced lists}\par
+\P\D \37$\\{text}(\#)\S\\{hash}[\#].\\{rh}$\C{string number for control
+sequence name}\par
+\P\D \37$\\{hash\_is\_full}\S(\\{hash\_used}=\\{hash\_base})$\C{test if all
+positions are occupied}\par
+\P\D \37$\\{font\_id\_text}(\#)\S\\{text}(\\{font\_id\_base}+\#)$\C{a frozen
+font identifier's name}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{hash}: \37$\^\\{two\_halves}$;\C{the hash table}\6
+\4\\{yhash}: \37$\^\\{two\_halves}$;\C{auxiliary pointer for freeing hash}\6
+\4\\{hash\_used}: \37\\{pointer};\C{allocation pointer for \\{hash}}\6
+\4\\{hash\_extra}: \37\\{pointer};\C{$\\{hash\_extra}=\\{hash}$ above \\{eqtb%
+\_size}}\6
+\4\\{hash\_top}: \37\\{pointer};\C{maximum of the hash array}\6
+\4\\{eqtb\_top}: \37\\{pointer};\C{maximum of the \\{eqtb}}\6
+\4\\{hash\_high}: \37\\{pointer};\C{pointer to next high hash location}\6
+\4\\{no\_new\_control\_sequence}: \37\\{boolean};\C{are new identifiers legal?}%
+\6
+\4\\{cs\_count}: \37\\{integer};\C{total number of known identifiers}\par
+\fi
+
+\M263. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{no\_new\_control\_sequence}\K\\{true}$;\C{new identifiers are usually
+forbidden}\par
+\fi
+
+\M264. \P$\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}%
+\S$\6
+$\\{hash\_used}\K\\{frozen\_control\_sequence}$;\C{nothing is used}\6
+$\\{hash\_high}\K0$;\5
+$\\{cs\_count}\K0$;\5
+$\\{eq\_type}(\\{frozen\_dont\_expand})\K\\{dont\_expand}$;\5
+$\\{text}(\\{frozen\_dont\_expand})\K\.{"notexpanded:"}$;\par
+\fi
+
+\M265. Here is the subroutine that searches the hash table for an identifier
+that matches a given string of length $\|l>1$ appearing in $\\{buffer}[\|j\to(%
+\|j+\|l-1)]$. If the identifier is found, the corresponding hash table address
+is returned. Otherwise, if the global variable \\{no\_new\_control\_sequence}
+is \\{true}, the dummy address \\{undefined\_control\_sequence} is returned.
+Otherwise the identifier is inserted into the hash table and its location
+is returned.
+
+\Y\P\4\&{function}\1\  \37$\\{id\_lookup}(\|j,\39\|l:\\{integer})$: \37%
+\\{pointer};\C{search the hash table}\6
+\4\&{label} \37\\{found};\C{go here if you found it}\6
+\4\&{var} \37\|h: \37\\{integer};\C{hash code}\6
+\|d: \37\\{integer};\C{number of characters in incomplete current string}\6
+\|p: \37\\{pointer};\C{index in \\{hash} array}\6
+\|k: \37\\{pointer};\C{index in \\{buffer} array}\2\6
+\&{begin} \37\X267:Compute the hash code \|h\X;\6
+$\|p\K\|h+\\{hash\_base}$;\C{we start searching here; note that $0\L\|h<\\{hash%
+\_prime}$}\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{text}(\|p)>0$ \1\&{then}\6
+\&{if} $\\{length}(\\{text}(\|p))=\|l$ \1\&{then}\6
+\&{if} $\\{str\_eq\_buf}(\\{text}(\|p),\39\|j)$ \1\&{then}\5
+\&{goto} \37\\{found};\2\2\2\6
+\&{if} $\\{next}(\|p)=0$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{no\_new\_control\_sequence}$ \1\&{then}\5
+$\|p\K\\{undefined\_control\_sequence}$\6
+\4\&{else} \X266:Insert a new control sequence after \|p, then make \|p point
+to it\X;\2\6
+\&{goto} \37\\{found};\6
+\&{end};\2\6
+$\|p\K\\{next}(\|p)$;\6
+\&{end};\2\6
+\4\\{found}: \37$\\{id\_lookup}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M266. \P$\X266:Insert a new control sequence after \|p, then make \|p point to
+it\X\S$\6
+\&{begin} \37\&{if} $\\{text}(\|p)>0$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{hash\_high}<\\{hash\_extra}$ \1\&{then}\6
+\&{begin} \37$\\{incr}(\\{hash\_high})$;\5
+$\\{next}(\|p)\K\\{hash\_high}+\\{eqtb\_size}$;\5
+$\|p\K\\{hash\_high}+\\{eqtb\_size}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\1\&{repeat} \37\&{if} $\\{hash\_is\_full}$ \1\&{then}\5
+$\\{overflow}(\.{"hash\ size"},\39\\{hash\_size}+\\{hash\_extra})$;\2\6
+$\\{decr}(\\{hash\_used})$;\6
+\4\&{until}\5
+$\\{text}(\\{hash\_used})=0$;\C{search for an empty location in \\{hash}}\2\6
+$\\{next}(\|p)\K\\{hash\_used}$;\5
+$\|p\K\\{hash\_used}$;\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{str\_room}(\|l)$;\5
+$\|d\K\\{cur\_length}$;\6
+\&{while} $\\{pool\_ptr}>\\{str\_start}[\\{str\_ptr}]$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\\{pool\_ptr})$;\5
+$\\{str\_pool}[\\{pool\_ptr}+\|l]\K\\{str\_pool}[\\{pool\_ptr}]$;\6
+\&{end};\C{move current string up to make room for another}\2\6
+\&{for} $\|k\K\|j\mathrel{\&{to}}\|j+\|l-1$ \1\&{do}\5
+$\\{append\_char}(\\{buffer}[\|k])$;\2\6
+$\\{text}(\|p)\K\\{make\_string}$;\5
+$\\{pool\_ptr}\K\\{pool\_ptr}+\|d$;\6
+\&{stat} \37$\\{incr}(\\{cs\_count})$;\ \&{tats}\6
+\&{end}\par
+\U265.\fi
+
+\M267. The value of \\{hash\_prime} should be roughly 85\pct! of \\{hash%
+\_size}, and it
+should be a prime number.  The theory of hashing tells us to expect fewer
+than two table probes, on the average, when the search is successful.
+[See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
+
+\Y\P$\4\X267:Compute the hash code \|h\X\S$\6
+$\|h\K\\{buffer}[\|j]$;\6
+\&{for} $\|k\K\|j+1\mathrel{\&{to}}\|j+\|l-1$ \1\&{do}\6
+\&{begin} \37$\|h\K\|h+\|h+\\{buffer}[\|k]$;\6
+\&{while} $\|h\G\\{hash\_prime}$ \1\&{do}\5
+$\|h\K\|h-\\{hash\_prime}$;\2\6
+\&{end}\2\par
+\U265.\fi
+
+\M268. Single-character control sequences do not need to be looked up in a hash
+table, since we can use the character code itself as a direct address.
+The procedure \\{print\_cs} prints the name of a control sequence, given
+a pointer to its address in \\{eqtb}. A space is printed after the name
+unless it is a single nonletter or an active character. This procedure
+might be invoked with invalid data, so it is ``extra robust.'' The
+individual characters must be printed one at a time using \\{print}, since
+they may be unprintable.
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_cs}(\|p:\\{integer})$;\C{prints a purported
+control sequence}\2\6
+\&{begin} \37\&{if} $\|p<\\{hash\_base}$ \1\&{then}\C{single character}\6
+\&{if} $\|p\G\\{single\_base}$ \1\&{then}\6
+\&{if} $\|p=\\{null\_cs}$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"csname"})$;\5
+$\\{print\_esc}(\.{"endcsname"})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\|p-\\{single\_base})$;\6
+\&{if} $\\{cat\_code}(\|p-\\{single\_base})=\\{letter}$ \1\&{then}\5
+$\\{print\_char}(\.{"\ "})$;\2\6
+\&{end}\2\6
+\4\&{else} \&{if} $\|p<\\{active\_base}$ \1\&{then}\5
+$\\{print\_esc}(\.{"IMPOSSIBLE."})$\6
+\4\&{else} $\\{print}(\|p-\\{active\_base})$\2\2\6
+\4\&{else} \&{if} $((\|p\G\\{undefined\_control\_sequence})\W(\|p\L\\{eqtb%
+\_size}))\V(\|p>\\{eqtb\_top})$ \1\&{then}\5
+$\\{print\_esc}(\.{"IMPOSSIBLE."})$\6
+\4\&{else} \&{if} $(\\{text}(\|p)\G\\{str\_ptr})$ \1\&{then}\5
+$\\{print\_esc}(\.{"NONEXISTENT."})$\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\\{text}(\|p))$;\5
+$\\{print\_char}(\.{"\ "})$;\6
+\&{end};\2\2\2\6
+\&{end};\par
+\fi
+
+\M269. Here is a similar procedure; it avoids the error checks, and it never
+prints a space after the control sequence.
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{sprint\_cs}(\|p:\\{pointer})$;\C{prints a control
+sequence}\2\6
+\&{begin} \37\&{if} $\|p<\\{hash\_base}$ \1\&{then}\6
+\&{if} $\|p<\\{single\_base}$ \1\&{then}\5
+$\\{print}(\|p-\\{active\_base})$\6
+\4\&{else} \&{if} $\|p<\\{null\_cs}$ \1\&{then}\5
+$\\{print\_esc}(\|p-\\{single\_base})$\6
+\4\&{else} \&{begin} \37$\\{print\_esc}(\.{"csname"})$;\5
+$\\{print\_esc}(\.{"endcsname"})$;\6
+\&{end}\2\2\6
+\4\&{else} $\\{print\_esc}(\\{text}(\|p))$;\2\6
+\&{end};\par
+\fi
+
+\M270. We need to put \TeX's ``primitive'' control sequences into the hash
+table, together with their command code (which will be the \\{eq\_type})
+and an operand (which will be the \\{equiv}). The \\{primitive} procedure
+does this, in a way that no \TeX\ user can. The global value \\{cur\_val}
+contains the new \\{eqtb} pointer after \\{primitive} has acted.
+
+\Y\P\&{init} \37\&{procedure}\1\  \37$\\{primitive}(\|s:\\{str\_number};\,\35%
+\|c:\\{quarterword};\,\35\|o:\\{halfword})$;\6
+\4\&{var} \37\|k: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\6
+\|j: \37\\{small\_number};\C{index into \\{buffer}}\6
+\|l: \37\\{small\_number};\C{length of the string}\2\6
+\&{begin} \37\&{if} $\|s<256$ \1\&{then}\5
+$\\{cur\_val}\K\|s+\\{single\_base}$\6
+\4\&{else} \&{begin} \37$\|k\K\\{str\_start}[\|s]$;\5
+$\|l\K\\{str\_start}[\|s+1]-\|k$;\C{we will move \|s into the (empty) %
+\\{buffer}}\6
+\&{for} $\|j\K0\mathrel{\&{to}}\|l-1$ \1\&{do}\5
+$\\{buffer}[\|j]\K\\{so}(\\{str\_pool}[\|k+\|j])$;\2\6
+$\\{cur\_val}\K\\{id\_lookup}(0,\39\|l)$;\C{\\{no\_new\_control\_sequence} is %
+\\{false}}\6
+\\{flush\_string};\5
+$\\{text}(\\{cur\_val})\K\|s$;\C{we don't want to have the string twice}\6
+\&{end};\2\6
+$\\{eq\_level}(\\{cur\_val})\K\\{level\_one}$;\5
+$\\{eq\_type}(\\{cur\_val})\K\|c$;\5
+$\\{equiv}(\\{cur\_val})\K\|o$;\6
+\&{end};\6
+\&{tini}\par
+\fi
+
+\M271. Many of \TeX's primitives need no \\{equiv}, since they are identifiable
+by their \\{eq\_type} alone. These primitives are loaded into the hash table
+as follows:
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"\ "},\39\\{ex\_space},\390)$;\6
+$\\{primitive}(\.{"/"},\39\\{ital\_corr},\390)$;\6
+$\\{primitive}(\.{"accent"},\39\\{accent},\390)$;\6
+$\\{primitive}(\.{"advance"},\39\\{advance},\390)$;\6
+$\\{primitive}(\.{"afterassignment"},\39\\{after\_assignment},\390)$;\6
+$\\{primitive}(\.{"aftergroup"},\39\\{after\_group},\390)$;\6
+$\\{primitive}(\.{"begingroup"},\39\\{begin\_group},\390)$;\6
+$\\{primitive}(\.{"char"},\39\\{char\_num},\390)$;\6
+$\\{primitive}(\.{"csname"},\39\\{cs\_name},\390)$;\6
+$\\{primitive}(\.{"delimiter"},\39\\{delim\_num},\390)$;\6
+$\\{primitive}(\.{"divide"},\39\\{divide},\390)$;\6
+$\\{primitive}(\.{"endcsname"},\39\\{end\_cs\_name},\390)$;\6
+$\\{primitive}(\.{"endgroup"},\39\\{end\_group},\390)$;\5
+$\\{text}(\\{frozen\_end\_group})\K\.{"endgroup"}$;\5
+$\\{eqtb}[\\{frozen\_end\_group}]\K\\{eqtb}[\\{cur\_val}]$;\6
+$\\{primitive}(\.{"expandafter"},\39\\{expand\_after},\390)$;\6
+$\\{primitive}(\.{"font"},\39\\{def\_font},\390)$;\6
+$\\{primitive}(\.{"jfont"},\39\\{def\_jfont},\390)$;\6
+$\\{primitive}(\.{"tfont"},\39\\{def\_tfont},\390)$;\6
+$\\{primitive}(\.{"fontdimen"},\39\\{assign\_font\_dimen},\390)$;\6
+$\\{primitive}(\.{"halign"},\39\\{halign},\390)$;\6
+$\\{primitive}(\.{"hrule"},\39\\{hrule},\390)$;\6
+$\\{primitive}(\.{"ignorespaces"},\39\\{ignore\_spaces},\390)$;\6
+$\\{primitive}(\.{"insert"},\39\\{insert},\390)$;\6
+$\\{primitive}(\.{"mark"},\39\\{mark},\390)$;\6
+$\\{primitive}(\.{"mathaccent"},\39\\{math\_accent},\390)$;\6
+$\\{primitive}(\.{"mathchar"},\39\\{math\_char\_num},\390)$;\6
+$\\{primitive}(\.{"mathchoice"},\39\\{math\_choice},\390)$;\6
+$\\{primitive}(\.{"multiply"},\39\\{multiply},\390)$;\6
+$\\{primitive}(\.{"noalign"},\39\\{no\_align},\390)$;\6
+$\\{primitive}(\.{"noboundary"},\39\\{no\_boundary},\390)$;\6
+$\\{primitive}(\.{"noexpand"},\39\\{no\_expand},\390)$;\6
+$\\{primitive}(\.{"nonscript"},\39\\{non\_script},\390)$;\6
+$\\{primitive}(\.{"omit"},\39\\{omit},\390)$;\6
+$\\{primitive}(\.{"parshape"},\39\\{set\_shape},\390)$;\6
+$\\{primitive}(\.{"penalty"},\39\\{break\_penalty},\390)$;\6
+$\\{primitive}(\.{"prevgraf"},\39\\{set\_prev\_graf},\390)$;\6
+$\\{primitive}(\.{"radical"},\39\\{radical},\390)$;\6
+$\\{primitive}(\.{"read"},\39\\{read\_to\_cs},\390)$;\6
+$\\{primitive}(\.{"relax"},\39\\{relax},\39256)$;\C{cf.\ \\{scan\_file\_name}}\6
+$\\{text}(\\{frozen\_relax})\K\.{"relax"}$;\5
+$\\{eqtb}[\\{frozen\_relax}]\K\\{eqtb}[\\{cur\_val}]$;\6
+$\\{primitive}(\.{"setbox"},\39\\{set\_box},\390)$;\6
+$\\{primitive}(\.{"the"},\39\\{the},\390)$;\6
+$\\{primitive}(\.{"toks"},\39\\{toks\_register},\390)$;\6
+$\\{primitive}(\.{"vadjust"},\39\\{vadjust},\390)$;\6
+$\\{primitive}(\.{"valign"},\39\\{valign},\390)$;\6
+$\\{primitive}(\.{"vcenter"},\39\\{vcenter},\390)$;\6
+$\\{primitive}(\.{"vrule"},\39\\{vrule},\390)$;\par
+\fi
+
+\M272. Each primitive has a corresponding inverse, so that it is possible to
+display the cryptic numeric contents of \\{eqtb} in symbolic form.
+Every call of \\{primitive} in this program is therefore accompanied by some
+straightforward code that forms part of the \\{print\_cmd\_chr} routine
+below.
+
+\Y\P$\4\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X%
+\mathrel{+}\S$\6
+\4\\{accent}: \37$\\{print\_esc}(\.{"accent"})$;\6
+\4\\{advance}: \37$\\{print\_esc}(\.{"advance"})$;\6
+\4\\{after\_assignment}: \37$\\{print\_esc}(\.{"afterassignment"})$;\6
+\4\\{after\_group}: \37$\\{print\_esc}(\.{"aftergroup"})$;\6
+\4\\{assign\_font\_dimen}: \37$\\{print\_esc}(\.{"fontdimen"})$;\6
+\4\\{begin\_group}: \37$\\{print\_esc}(\.{"begingroup"})$;\6
+\4\\{break\_penalty}: \37$\\{print\_esc}(\.{"penalty"})$;\6
+\4\\{char\_num}: \37$\\{print\_esc}(\.{"char"})$;\6
+\4\\{cs\_name}: \37$\\{print\_esc}(\.{"csname"})$;\6
+\4\\{def\_font}: \37$\\{print\_esc}(\.{"font"})$;\6
+\4\\{def\_jfont}: \37$\\{print\_esc}(\.{"jfont"})$;\6
+\4\\{def\_tfont}: \37$\\{print\_esc}(\.{"tfont"})$;\6
+\4\\{delim\_num}: \37$\\{print\_esc}(\.{"delimiter"})$;\6
+\4\\{divide}: \37$\\{print\_esc}(\.{"divide"})$;\6
+\4\\{end\_cs\_name}: \37$\\{print\_esc}(\.{"endcsname"})$;\6
+\4\\{end\_group}: \37$\\{print\_esc}(\.{"endgroup"})$;\6
+\4\\{ex\_space}: \37$\\{print\_esc}(\.{"\ "})$;\6
+\4\\{expand\_after}: \37$\\{print\_esc}(\.{"expandafter"})$;\6
+\4\\{halign}: \37$\\{print\_esc}(\.{"halign"})$;\6
+\4\\{hrule}: \37$\\{print\_esc}(\.{"hrule"})$;\6
+\4\\{ignore\_spaces}: \37$\\{print\_esc}(\.{"ignorespaces"})$;\6
+\4\\{insert}: \37$\\{print\_esc}(\.{"insert"})$;\6
+\4\\{ital\_corr}: \37$\\{print\_esc}(\.{"/"})$;\6
+\4\\{mark}: \37$\\{print\_esc}(\.{"mark"})$;\6
+\4\\{math\_accent}: \37$\\{print\_esc}(\.{"mathaccent"})$;\6
+\4\\{math\_char\_num}: \37$\\{print\_esc}(\.{"mathchar"})$;\6
+\4\\{math\_choice}: \37$\\{print\_esc}(\.{"mathchoice"})$;\6
+\4\\{multiply}: \37$\\{print\_esc}(\.{"multiply"})$;\6
+\4\\{no\_align}: \37$\\{print\_esc}(\.{"noalign"})$;\6
+\4\\{no\_boundary}: \37$\\{print\_esc}(\.{"noboundary"})$;\6
+\4\\{no\_expand}: \37$\\{print\_esc}(\.{"noexpand"})$;\6
+\4\\{non\_script}: \37$\\{print\_esc}(\.{"nonscript"})$;\6
+\4\\{omit}: \37$\\{print\_esc}(\.{"omit"})$;\6
+\4\\{radical}: \37$\\{print\_esc}(\.{"radical"})$;\6
+\4\\{read\_to\_cs}: \37$\\{print\_esc}(\.{"read"})$;\6
+\4\\{relax}: \37$\\{print\_esc}(\.{"relax"})$;\6
+\4\\{set\_box}: \37$\\{print\_esc}(\.{"setbox"})$;\6
+\4\\{set\_prev\_graf}: \37$\\{print\_esc}(\.{"prevgraf"})$;\6
+\4\\{set\_shape}: \37$\\{print\_esc}(\.{"parshape"})$;\6
+\4\\{the}: \37$\\{print\_esc}(\.{"the"})$;\6
+\4\\{toks\_register}: \37$\\{print\_esc}(\.{"toks"})$;\6
+\4\\{vadjust}: \37$\\{print\_esc}(\.{"vadjust"})$;\6
+\4\\{valign}: \37$\\{print\_esc}(\.{"valign"})$;\6
+\4\\{vcenter}: \37$\\{print\_esc}(\.{"vcenter"})$;\6
+\4\\{vrule}: \37$\\{print\_esc}(\.{"vrule"})$;\par
+\fi
+
+\M273. We will deal with the other primitives later, at some point in the
+program
+where their \\{eq\_type} and \\{equiv} values are more meaningful.  For
+example,
+the primitives for math mode will be loaded when we consider the routines
+that deal with formulas. It is easy to find where each particular
+primitive was treated by looking in the index at the end; for example, the
+section where \.{"radical"} entered \\{eqtb} is listed under `\.{\\radical}
+primitive'. (Primitives consisting of a single nonalphabetic character,
+like `\.{\\/}', are listed under `Single-character primitives'.)
+
+Meanwhile, this is a convenient place to catch up on something we were unable
+to do before the hash table was defined:
+
+\Y\P$\4\X273:Print the font identifier for $\\{font}(\|p)$\X\S$\6
+$\\{print\_esc}(\\{font\_id\_text}(\\{font}(\|p)))$\par
+\Us180\ET182.\fi
+
+\N274.  \[19] Saving and restoring equivalents.
+The nested structure provided by `$\.{\char'173}\ldots\.{\char'175}$' groups
+in \TeX\ means that \\{eqtb} entries valid in outer groups should be saved
+and restored later if they are overridden inside the braces. When a new %
+\\{eqtb}
+value is being assigned, the program therefore checks to see if the previous
+entry belongs to an outer level. In such a case, the old value is placed
+on the \\{save\_stack} just before the new value enters \\{eqtb}. At the
+end of a grouping level, i.e., when the right brace is sensed, the
+\\{save\_stack} is used to restore the outer values, and the inner ones are
+destroyed.
+
+Entries on the \\{save\_stack} are of type \\{memory\_word}. The top item on
+this stack is $\\{save\_stack}[\|p]$, where $\|p=\\{save\_ptr}-1$; it contains
+three
+fields called \\{save\_type}, \\{save\_level}, and \\{save\_index}, and it is
+interpreted in one of four ways:
+
+\yskip\hangg 1) If $\\{save\_type}(\|p)=\\{restore\_old\_value}$, then
+$\\{save\_index}(\|p)$ is a location in \\{eqtb} whose current value should
+be destroyed at the end of the current group and replaced by $\\{save\_stack}[%
+\|p-1]$.
+Furthermore if $\\{save\_index}(\|p)\G\\{int\_base}$, then $\\{save\_level}(%
+\|p)$
+should replace the corresponding entry in \\{xeq\_level}.
+
+\yskip\hangg 2) If $\\{save\_type}(\|p)=\\{restore\_zero}$, then $\\{save%
+\_index}(\|p)$
+is a location in \\{eqtb} whose current value should be destroyed at the end
+of the current group, when it should be
+replaced by the current value of $\\{eqtb}[\\{undefined\_control\_sequence}]$.
+
+\yskip\hangg 3) If $\\{save\_type}(\|p)=\\{insert\_token}$, then $\\{save%
+\_index}(\|p)$
+is a token that should be inserted into \TeX's input when the current
+group ends.
+
+\yskip\hangg 4) If $\\{save\_type}(\|p)=\\{level\_boundary}$, then $\\{save%
+\_level}(\|p)$
+is a code explaining what kind of group we were previously in, and
+$\\{save\_index}(\|p)$ points to the level boundary word at the bottom of
+the entries for that group.
+
+\Y\P\D \37$\\{save\_type}(\#)\S\\{save\_stack}[\#].\\{hh}.\\{b0}$\C{classifies
+a \\{save\_stack} entry}\par
+\P\D \37$\\{save\_level}(\#)\S\\{save\_stack}[\#].\\{hh}.\\{b1}$\C{saved level
+for regions 5 and 6, or group code}\par
+\P\D \37$\\{save\_index}(\#)\S\\{save\_stack}[\#].\\{hh}.\\{rh}$\C{\\{eqtb}
+location or token or \\{save\_stack} location}\par
+\P\D \37$\\{restore\_old\_value}=0$\C{\\{save\_type} when a value should be
+restored later}\par
+\P\D \37$\\{restore\_zero}=1$\C{\\{save\_type} when an undefined entry should
+be restored}\par
+\P\D \37$\\{insert\_token}=2$\C{\\{save\_type} when a token is being saved for
+later use}\par
+\P\D \37$\\{level\_boundary}=3$\C{\\{save\_type} corresponding to beginning of
+group}\par
+\fi
+
+\M275. Here are the group codes that are used to discriminate between different
+kinds of groups. They allow \TeX\ to decide what special actions, if any,
+should be performed when a group ends.
+\def\grp{\.{\char'173...\char'175}}
+
+Some groups are not supposed to be ended by right braces. For example,
+the `\.\$' that begins a math formula causes a \\{math\_shift\_group} to
+be started, and this should be terminated by a matching `\.\$'. Similarly,
+a group that starts with \.{\\left} should end with \.{\\right}, and
+one that starts with \.{\\begingroup} should end with \.{\\endgroup}.
+
+\Y\P\D \37$\\{bottom\_level}=0$\C{group code for the outside world}\par
+\P\D \37$\\{simple\_group}=1$\C{group code for local structure only}\par
+\P\D \37$\\{hbox\_group}=2$\C{code for `\.{\\hbox}\grp'}\par
+\P\D \37$\\{adjusted\_hbox\_group}=3$\C{code for `\.{\\hbox}\grp' in vertical
+mode}\par
+\P\D \37$\\{vbox\_group}=4$\C{code for `\.{\\vbox}\grp'}\par
+\P\D \37$\\{vtop\_group}=5$\C{code for `\.{\\vtop}\grp'}\par
+\P\D \37$\\{align\_group}=6$\C{code for `\.{\\halign}\grp', `\.{\\valign}\grp'}%
+\par
+\P\D \37$\\{no\_align\_group}=7$\C{code for `\.{\\noalign}\grp'}\par
+\P\D \37$\\{output\_group}=8$\C{code for output routine}\par
+\P\D \37$\\{math\_group}=9$\C{code for, e.g., `\.{\char'136}\grp'}\par
+\P\D \37$\\{disc\_group}=10$\C{code for `\.{\\discretionary}\grp\grp\grp'}\par
+\P\D \37$\\{insert\_group}=11$\C{code for `\.{\\insert}\grp', `\.{\\vadjust}%
+\grp'}\par
+\P\D \37$\\{vcenter\_group}=12$\C{code for `\.{\\vcenter}\grp'}\par
+\P\D \37$\\{math\_choice\_group}=13$\C{code for `\.{\\mathchoice}\grp\grp\grp%
+\grp'}\par
+\P\D \37$\\{semi\_simple\_group}=14$\C{code for `\.{\\begingroup...%
+\\endgroup}'}\par
+\P\D \37$\\{math\_shift\_group}=15$\C{code for `\.{\$...\$}'}\par
+\P\D \37$\\{math\_left\_group}=16$\C{code for `\.{\\left...\\right}'}\par
+\P\D \37$\\{max\_group\_code}=16$\par
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{group\_code}=0\to\\{max\_group\_code}$;\C{\\{save\_level} for a level
+boundary}\par
+\fi
+
+\M276. The global variable \\{cur\_group} keeps track of what sort of group we
+are
+currently in. Another global variable, \\{cur\_boundary}, points to the
+topmost \\{level\_boundary} word.  And \\{cur\_level} is the current depth of
+nesting. The routines are designed to preserve the condition that no entry
+in the \\{save\_stack} or in \\{eqtb} ever has a level greater than \\{cur%
+\_level}.
+
+\fi
+
+\M277. \P$\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{save\_stack}: \37$\^\\{memory\_word}$;\6
+\4\\{save\_ptr}: \37$0\to\\{save\_size}$;\C{first unused entry on \\{save%
+\_stack}}\6
+\4\\{max\_save\_stack}: \37$0\to\\{save\_size}$;\C{maximum usage of save stack}%
+\6
+\4\\{cur\_level}: \37\\{quarterword};\C{current nesting level for groups}\6
+\4\\{cur\_group}: \37\\{group\_code};\C{current group type}\6
+\4\\{cur\_boundary}: \37$0\to\\{save\_size}$;\C{where the current level begins}%
+\par
+\fi
+
+\M278. At this time it might be a good idea for the reader to review the
+introduction
+to \\{eqtb} that was given above just before the long lists of parameter names.
+Recall that the ``outer level'' of the program is \\{level\_one}, since
+undefined control sequences are assumed to be ``defined'' at \\{level\_zero}.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{save\_ptr}\K0$;\5
+$\\{cur\_level}\K\\{level\_one}$;\5
+$\\{cur\_group}\K\\{bottom\_level}$;\5
+$\\{cur\_boundary}\K0$;\5
+$\\{max\_save\_stack}\K0$;\par
+\fi
+
+\M279. The following macro is used to test if there is room for up to six more
+entries on \\{save\_stack}. By making a conservative test like this, we can
+get by with testing for overflow in only a few places.
+
+\Y\P\D \37$\\{check\_full\_save\_stack}\S$\1\6
+\&{if} $\\{save\_ptr}>\\{max\_save\_stack}$ \1\&{then}\6
+\&{begin} \37$\\{max\_save\_stack}\K\\{save\_ptr}$;\6
+\&{if} $\\{max\_save\_stack}>\\{save\_size}-6$ \1\&{then}\5
+$\\{overflow}(\.{"save\ size"},\39\\{save\_size})$;\2\6
+\&{end}\2\2\par
+\fi
+
+\M280. Procedure \\{new\_save\_level} is called when a group begins. The
+argument is a group identification code like `\\{hbox\_group}'. After
+calling this routine, it is safe to put five more entries on \\{save\_stack}.
+
+In some cases integer-valued items are placed onto the
+\\{save\_stack} just below a \\{level\_boundary} word, because this is a
+convenient place to keep information that is supposed to ``pop up'' just
+when the group has finished.
+For example, when `\.{\\hbox to 100pt}\grp' is being treated, the 100pt
+dimension is stored on \\{save\_stack} just before \\{new\_save\_level} is
+called.
+
+We use the notation $\\{saved}(\|k)$ to stand for an integer item that
+appears in location $\\{save\_ptr}+\|k$ of the save stack.
+
+\Y\P\D \37$\\{saved}(\#)\S\\{save\_stack}[\\{save\_ptr}+\#].\\{int}$\par
+\Y\P\4\&{procedure}\1\  \37$\\{new\_save\_level}(\|c:\\{group\_code})$;\C{begin
+a new level of grouping}\2\6
+\&{begin} \37\\{check\_full\_save\_stack};\5
+$\\{save\_type}(\\{save\_ptr})\K\\{level\_boundary}$;\5
+$\\{save\_level}(\\{save\_ptr})\K\\{cur\_group}$;\5
+$\\{save\_index}(\\{save\_ptr})\K\\{cur\_boundary}$;\6
+\&{if} $\\{cur\_level}=\\{max\_quarterword}$ \1\&{then}\5
+$\\{overflow}(\.{"grouping\ levels"},\39\\{max\_quarterword}-\\{min%
+\_quarterword})$;\C{quit if $(\\{cur\_level}+1)$ is too big to be stored in %
+\\{eqtb}}\2\6
+$\\{cur\_boundary}\K\\{save\_ptr}$;\5
+$\\{incr}(\\{cur\_level})$;\5
+$\\{incr}(\\{save\_ptr})$;\5
+$\\{cur\_group}\K\|c$;\6
+\&{end};\par
+\fi
+
+\M281. Just before an entry of \\{eqtb} is changed, the following procedure
+should
+be called to update the other data structures properly. It is important
+to keep in mind that reference counts in \\{mem} include references from
+within \\{save\_stack}, so these counts must be handled carefully.
+
+\Y\P\4\&{procedure}\1\  \37$\\{eq\_destroy}(\|w:\\{memory\_word})$;\C{gets
+ready to forget \|w}\6
+\4\&{var} \37\|q: \37\\{pointer};\C{\\{equiv} field of \|w}\2\6
+\&{begin} \37\&{case} $\\{eq\_type\_field}(\|w)$ \1\&{of}\6
+\4$\\{call},\39\\{long\_call},\39\\{outer\_call},\39\\{long\_outer\_call}$: %
+\37$\\{delete\_token\_ref}(\\{equiv\_field}(\|w))$;\6
+\4\\{glue\_ref}: \37$\\{delete\_glue\_ref}(\\{equiv\_field}(\|w))$;\6
+\4\\{shape\_ref}: \37\&{begin} \37$\|q\K\\{equiv\_field}(\|w)$;\C{we need to
+free a \.{\\parshape} block}\6
+\&{if} $\|q\I\\{null}$ \1\&{then}\5
+$\\{free\_node}(\|q,\39\\{info}(\|q)+\\{info}(\|q)+1)$;\2\6
+\&{end};\C{such a block is $2\|n+1$ words long, where $\|n=\\{info}(\|q)$}\6
+\4\\{box\_ref}: \37$\\{flush\_node\_list}(\\{equiv\_field}(\|w))$;\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\6
+\&{end};\par
+\fi
+
+\M282. To save a value of $\\{eqtb}[\|p]$ that was established at level \|l, we
+can use the following subroutine.
+
+\Y\P\4\&{procedure}\1\  \37$\\{eq\_save}(\|p:\\{pointer};\,\35\|l:%
+\\{quarterword})$;\C{saves $\\{eqtb}[\|p]$}\2\6
+\&{begin} \37\\{check\_full\_save\_stack};\6
+\&{if} $\|l=\\{level\_zero}$ \1\&{then}\5
+$\\{save\_type}(\\{save\_ptr})\K\\{restore\_zero}$\6
+\4\&{else} \&{begin} \37$\\{save\_stack}[\\{save\_ptr}]\K\\{eqtb}[\|p]$;\5
+$\\{incr}(\\{save\_ptr})$;\5
+$\\{save\_type}(\\{save\_ptr})\K\\{restore\_old\_value}$;\6
+\&{end};\2\6
+$\\{save\_level}(\\{save\_ptr})\K\|l$;\5
+$\\{save\_index}(\\{save\_ptr})\K\|p$;\5
+$\\{incr}(\\{save\_ptr})$;\6
+\&{end};\par
+\fi
+
+\M283. The procedure \\{eq\_define} defines an \\{eqtb} entry having specified
+\\{eq\_type} and \\{equiv} fields, and saves the former value if appropriate.
+This procedure is used only for entries in the first four regions of \\{eqtb},
+i.e., only for entries that have \\{eq\_type} and \\{equiv} fields.
+After calling this routine, it is safe to put four more entries on
+\\{save\_stack}, provided that there was room for four more entries before
+the call, since \\{eq\_save} makes the necessary test.
+
+\Y\P\4\&{procedure}\1\  \37$\\{eq\_define}(\|p:\\{pointer};\,\35\|t:%
+\\{quarterword};\,\35\|e:\\{halfword})$;\C{new data for \\{eqtb}}\2\6
+\&{begin} \37\&{if} $\\{eq\_level}(\|p)=\\{cur\_level}$ \1\&{then}\5
+$\\{eq\_destroy}(\\{eqtb}[\|p])$\6
+\4\&{else} \&{if} $\\{cur\_level}>\\{level\_one}$ \1\&{then}\5
+$\\{eq\_save}(\|p,\39\\{eq\_level}(\|p))$;\2\2\6
+$\\{eq\_level}(\|p)\K\\{cur\_level}$;\5
+$\\{eq\_type}(\|p)\K\|t$;\5
+$\\{equiv}(\|p)\K\|e$;\6
+\&{end};\par
+\fi
+
+\M284. The counterpart of \\{eq\_define} for the remaining (fullword) positions
+in
+\\{eqtb} is called \\{eq\_word\_define}. Since $\\{xeq\_level}[\|p]\G\\{level%
+\_one}$ for all
+\|p, a `\\{restore\_zero}' will never be used in this case.
+
+\Y\P\4\&{procedure}\1\  \37$\\{eq\_word\_define}(\|p:\\{pointer};\,\35\|w:%
+\\{integer})$;\2\6
+\&{begin} \37\&{if} $\\{xeq\_level}[\|p]\I\\{cur\_level}$ \1\&{then}\6
+\&{begin} \37$\\{eq\_save}(\|p,\39\\{xeq\_level}[\|p])$;\5
+$\\{xeq\_level}[\|p]\K\\{cur\_level}$;\6
+\&{end};\2\6
+$\\{eqtb}[\|p].\\{int}\K\|w$;\6
+\&{end};\par
+\fi
+
+\M285. The \\{eq\_define} and \\{eq\_word\_define} routines take care of local
+definitions.
+Global definitions are done in almost the same way, but there is no need
+to save old values, and the new value is associated with \\{level\_one}.
+
+\Y\P\4\&{procedure}\1\  \37$\\{geq\_define}(\|p:\\{pointer};\,\35\|t:%
+\\{quarterword};\,\35\|e:\\{halfword})$;\C{global \\{eq\_define}}\2\6
+\&{begin} \37$\\{eq\_destroy}(\\{eqtb}[\|p])$;\5
+$\\{eq\_level}(\|p)\K\\{level\_one}$;\5
+$\\{eq\_type}(\|p)\K\|t$;\5
+$\\{equiv}(\|p)\K\|e$;\6
+\&{end};\7
+\4\&{procedure}\1\  \37$\\{geq\_word\_define}(\|p:\\{pointer};\,\35\|w:%
+\\{integer})$;\C{global \\{eq\_word\_define}}\2\6
+\&{begin} \37$\\{eqtb}[\|p].\\{int}\K\|w$;\5
+$\\{xeq\_level}[\|p]\K\\{level\_one}$;\6
+\&{end};\par
+\fi
+
+\M286. Subroutine \\{save\_for\_after} puts a token on the stack for
+save-keeping.
+
+\Y\P\4\&{procedure}\1\  \37$\\{save\_for\_after}(\|t:\\{halfword})$;\2\6
+\&{begin} \37\&{if} $\\{cur\_level}>\\{level\_one}$ \1\&{then}\6
+\&{begin} \37\\{check\_full\_save\_stack};\5
+$\\{save\_type}(\\{save\_ptr})\K\\{insert\_token}$;\5
+$\\{save\_level}(\\{save\_ptr})\K\\{level\_zero}$;\5
+$\\{save\_index}(\\{save\_ptr})\K\|t$;\5
+$\\{incr}(\\{save\_ptr})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M287. The \\{unsave} routine goes the other way, taking items off of \\{save%
+\_stack}.
+This routine takes care of restoration when a level ends; everything
+belonging to the topmost group is cleared off of the save stack.
+
+\Y\P\hbox{\4}\X290:Declare the procedure called \\{restore\_trace}\X\6
+\4\&{procedure}\1\  \37\\{back\_input};\5
+\\{forward}; \hbox{\2} \6
+\4\&{procedure}\1\  \37\\{unsave};\C{pops the top level off the save stack}\6
+\4\&{label} \37\\{done};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{position to be restored}\6
+\|l: \37\\{quarterword};\C{saved level, if in fullword regions of \\{eqtb}}\6
+\|t: \37\\{halfword};\C{saved value of \\{cur\_tok}}\2\6
+\&{begin} \37\&{if} $\\{cur\_level}>\\{level\_one}$ \1\&{then}\6
+\&{begin} \37$\\{decr}(\\{cur\_level})$;\5
+\X288:Clear off top level from \\{save\_stack}\X;\6
+\&{end}\6
+\4\&{else} $\\{confusion}(\.{"curlevel"})$;\C{\\{unsave} is not used when $%
+\\{cur\_group}=\\{bottom\_level}$}\2\6
+\&{end};\par
+\fi
+
+\M288. \P$\X288:Clear off top level from \\{save\_stack}\X\S$\6
+\~ \1\&{loop}\ \&{begin} \37$\\{decr}(\\{save\_ptr})$;\6
+\&{if} $\\{save\_type}(\\{save\_ptr})=\\{level\_boundary}$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\|p\K\\{save\_index}(\\{save\_ptr})$;\6
+\&{if} $\\{save\_type}(\\{save\_ptr})=\\{insert\_token}$ \1\&{then}\5
+\X332:Insert token \|p into \TeX's input\X\6
+\4\&{else} \&{begin} \37\&{if} $\\{save\_type}(\\{save\_ptr})=\\{restore\_old%
+\_value}$ \1\&{then}\6
+\&{begin} \37$\|l\K\\{save\_level}(\\{save\_ptr})$;\5
+$\\{decr}(\\{save\_ptr})$;\6
+\&{end}\6
+\4\&{else} $\\{save\_stack}[\\{save\_ptr}]\K\\{eqtb}[\\{undefined\_control%
+\_sequence}]$;\2\6
+\X289:Store \(s)$\\{save\_stack}[\\{save\_ptr}]$ in $\\{eqtb}[\|p]$, unless $%
+\\{eqtb}[\|p]$ holds a global value\X;\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{done}: \37$\\{cur\_group}\K\\{save\_level}(\\{save\_ptr})$;\5
+$\\{cur\_boundary}\K\\{save\_index}(\\{save\_ptr})$\par
+\U287.\fi
+
+\M289. A global definition, which sets the level to \\{level\_one},
+will not be undone by \\{unsave}. If at least one global definition of
+$\\{eqtb}[\|p]$ has been carried out within the group that just ended, the
+last such definition will therefore survive.
+
+\Y\P$\4\X289:Store \(s)$\\{save\_stack}[\\{save\_ptr}]$ in $\\{eqtb}[\|p]$,
+unless $\\{eqtb}[\|p]$ holds a global value\X\S$\6
+\&{if} $(\|p<\\{int\_base})\V(\|p>\\{eqtb\_size})$ \1\&{then}\6
+\&{if} $\\{eq\_level}(\|p)=\\{level\_one}$ \1\&{then}\6
+\&{begin} \37$\\{eq\_destroy}(\\{save\_stack}[\\{save\_ptr}])$;\C{destroy the
+saved value}\6
+\&{stat} \37\&{if} $\\{tracing\_restores}>0$ \1\&{then}\5
+$\\{restore\_trace}(\|p,\39\.{"retaining"})$;\ \2\6
+\&{tats}\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{eq\_destroy}(\\{eqtb}[\|p])$;\C{destroy the current
+value}\6
+$\\{eqtb}[\|p]\K\\{save\_stack}[\\{save\_ptr}]$;\C{restore the saved value}\6
+\&{stat} \37\&{if} $\\{tracing\_restores}>0$ \1\&{then}\5
+$\\{restore\_trace}(\|p,\39\.{"restoring"})$;\ \2\6
+\&{tats}\6
+\&{end}\2\6
+\4\&{else} \&{if} $\\{xeq\_level}[\|p]\I\\{level\_one}$ \1\&{then}\6
+\&{begin} \37$\\{eqtb}[\|p]\K\\{save\_stack}[\\{save\_ptr}]$;\5
+$\\{xeq\_level}[\|p]\K\|l$;\6
+\&{stat} \37\&{if} $\\{tracing\_restores}>0$ \1\&{then}\5
+$\\{restore\_trace}(\|p,\39\.{"restoring"})$;\ \2\6
+\&{tats}\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{stat} \37\&{if} $\\{tracing\_restores}>0$ \1\&{then}%
+\5
+$\\{restore\_trace}(\|p,\39\.{"retaining"})$;\ \2\6
+\&{tats}\6
+\&{end}\2\2\par
+\U288.\fi
+
+\M290. \P$\X290:Declare the procedure called \\{restore\_trace}\X\S$\6
+\&{stat} \37\&{procedure}\1\  \37$\\{restore\_trace}(\|p:\\{pointer};\,\35\|s:%
+\\{str\_number})$;\C{$\\{eqtb}[\|p]$ has just been restored or retained}\2\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_char}(\.{"\{"})$;\5
+$\\{print}(\|s)$;\5
+$\\{print\_char}(\.{"\ "})$;\5
+$\\{show\_eqtb}(\|p)$;\5
+$\\{print\_char}(\.{"\}"})$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end};\6
+\&{tats}\par
+\U287.\fi
+
+\M291. When looking for possible pointers to a memory location, it is helpful
+to look for references from \\{eqtb} that might be waiting on the
+save stack. Of course, we might find spurious pointers too; but this
+routine is merely an aid when debugging, and at such times we are
+grateful for any scraps of information, even if they prove to be irrelevant.
+
+\Y\P$\4\X291:Search \\{save\_stack} for equivalents that point to \|p\X\S$\6
+\&{if} $\\{save\_ptr}>0$ \1\&{then}\6
+\&{for} $\|q\K0\mathrel{\&{to}}\\{save\_ptr}-1$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{equiv\_field}(\\{save\_stack}[\|q])=\|p$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"SAVE("})$;\5
+$\\{print\_int}(\|q)$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\6
+\&{end}\2\2\par
+\U178.\fi
+
+\M292. Most of the parameters kept in \\{eqtb} can be changed freely, but
+there's
+an exception:  The magnification should not be used with two different
+values during any \TeX\ job, since a single magnification is applied to an
+entire run. The global variable \\{mag\_set} is set to the current
+magnification
+whenever it becomes necessary to ``freeze'' it at a particular value.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{mag\_set}: \37\\{integer};\C{if nonzero, this magnification should be used
+henceforth}\par
+\fi
+
+\M293. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{mag\_set}\K0$;\par
+\fi
+
+\M294. The \\{prepare\_mag} subroutine is called whenever \TeX\ wants to use %
+\\{mag}
+for magnification.
+
+\Y\P\4\&{procedure}\1\  \37\\{prepare\_mag};\2\6
+\&{begin} \37\&{if} $(\\{mag\_set}>0)\W(\\{mag}\I\\{mag\_set})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Incompatible\ magnification\ ("})$;\5
+$\\{print\_int}(\\{mag})$;\5
+$\\{print}(\.{");"})$;\5
+$\\{print\_nl}(\.{"\ the\ previous\ value\ will\ be\ retained"})$;\5
+$\\{help2}(\.{"I\ can\ handle\ only\ one\ magnification\ ratio\ per\ job.\ So\
+I\'ve"})$\6
+$(\.{"reverted\ to\ the\ magnification\ you\ used\ earlier\ on\ this\ run."})$;%
+\6
+$\\{int\_error}(\\{mag\_set})$;\5
+$\\{geq\_word\_define}(\\{int\_base}+\\{mag\_code},\39\\{mag\_set})$;\C{$%
+\\{mag}\K\\{mag\_set}$}\6
+\&{end};\2\6
+\&{if} $(\\{mag}\L0)\V(\\{mag}>32768)$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Illegal\ magnification\ has\ been\ changed\ to%
+\ 1000"})$;\6
+$\\{help1}(\.{"The\ magnification\ ratio\ must\ be\ between\ 1\ and\
+32768."})$;\5
+$\\{int\_error}(\\{mag})$;\5
+$\\{geq\_word\_define}(\\{int\_base}+\\{mag\_code},\391000)$;\6
+\&{end};\2\6
+$\\{mag\_set}\K\\{mag}$;\6
+\&{end};\par
+\fi
+
+\N295.  \[20] Token lists.
+A \TeX\ token is either a character or a control sequence, and it is
+represented internally in one of two ways: (1)~A character whose ASCII
+code number is \|c and whose command code is \|m is represented as the
+number $2^8m+c$; the command code is in the range $1\L\|m\L14$. (2)~A control
+sequence whose \\{eqtb} address is \|p is represented as the number
+$\\{cs\_token\_flag}+\|p$. Here $\\{cs\_token\_flag}=\hbox{$2^{12}-1$}$ is
+larger than
+$2^8m+c$, yet it is small enough that $\\{cs\_token\_flag}+\|p<\\{max%
+\_halfword}$;
+thus, a token fits comfortably in a halfword.
+
+A token \|t represents a \\{left\_brace} command if and only if
+$\|t<\\{left\_brace\_limit}$; it represents a \\{right\_brace} command if and
+only if
+we have $\\{left\_brace\_limit}\L\|t<\\{right\_brace\_limit}$; and it
+represents a \\{match} or
+\\{end\_match} command if and only if $\\{match\_token}\L\|t\L\\{end\_match%
+\_token}$.
+The following definitions take care of these token-oriented constants
+and a few others.
+
+\Y\P\D \37$\\{cs\_token\_flag}\S\H{FFFF}$\C{amount added to the \\{eqtb}
+location in a token that stands for a control sequence; is a multiple of~256,
+less~1}\par
+\P\D \37$\\{left\_brace\_token}=\O{0400}$\C{$2^8\cdot\\{left\_brace}$}\par
+\P\D \37$\\{left\_brace\_limit}=\O{1000}$\C{$2^8\cdot(\\{left\_brace}+1)$}\par
+\P\D \37$\\{right\_brace\_token}=\O{1000}$\C{$2^8\cdot\\{right\_brace}$}\par
+\P\D \37$\\{right\_brace\_limit}=\O{1400}$\C{$2^8\cdot(\\{right\_brace}+1)$}\par
+\P\D \37$\\{math\_shift\_token}=\O{1400}$\C{$2^8\cdot\\{math\_shift}$}\par
+\P\D \37$\\{tab\_token}=\O{2000}$\C{$2^8\cdot\\{tab\_mark}$}\par
+\P\D \37$\\{out\_param\_token}=\O{2400}$\C{$2^8\cdot\\{out\_param}$}\par
+\P\D \37$\\{space\_token}=\O{5040}$\C{$2^8\cdot\\{spacer}+\.{"\ "}$}\par
+\P\D \37$\\{letter\_token}=\O{5400}$\C{$2^8\cdot\\{letter}$}\par
+\P\D \37$\\{other\_token}=\O{6000}$\C{$2^8\cdot\\{other\_char}$}\par
+\P\D \37$\\{match\_token}=\O{6400}$\C{$2^8\cdot\\{match}$}\par
+\P\D \37$\\{end\_match\_token}=\O{7000}$\C{$2^8\cdot\\{end\_match}$}\par
+\fi
+
+\M296. \P$\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6
+\&{if} $\\{cs\_token\_flag}+\\{eqtb\_size}+\\{hash\_extra}>\\{max\_halfword}$ %
+\1\&{then}\5
+$\\{bad}\K21$;\2\6
+\&{if} $(\\{hash\_offset}<0)\V(\\{hash\_offset}>\\{hash\_base})$ \1\&{then}\5
+$\\{bad}\K42$;\2\par
+\fi
+
+\M297. A token list is a singly linked list of one-word nodes in \\{mem}, where
+each word contains a token and a link. Macro definitions, output-routine
+definitions, marks, \.{\\write} texts, and a few other things
+are remembered by \TeX\ in the form
+of token lists, usually preceded by a node with a reference count in its
+\\{token\_ref\_count} field. The token stored in location \|p is called
+$\\{info}(\|p)$.
+
+Three special commands appear in the token lists of macro definitions.
+When $\|m=\\{match}$, it means that \TeX\ should scan a parameter
+for the current macro; when $\|m=\\{end\_match}$, it means that parameter
+matching should end and \TeX\ should start reading the macro text; and
+when $\|m=\\{out\_param}$, it means that \TeX\ should insert parameter
+number \|c into the text at this point.
+
+The enclosing \.{\char'173} and \.{\char'175} characters of a macro
+definition are omitted, but the final right brace of an output routine
+is included at the end of its token list.
+
+Here is an example macro definition that illustrates these conventions.
+After \TeX\ processes the text
+$$\.{\\def\\mac a\#1\#2 \\b \{\#1\\-a \#\#1\#2 \#2\}}$$
+the definition of \.{\\mac} is represented as a token list containing
+$$\def\,{\hskip2pt}
+\vbox{\halign{\hfil#\hfil\cr
+(reference count), \\{letter}\,\.a, \\{match}\,\#, \\{match}\,\#, \\{spacer}\,%
+\.\ ,
+\.{\\b}, \\{end\_match},\cr
+\\{out\_param}\,1, \.{\\-}, \\{letter}\,\.a, \\{spacer}\,\.\ , \\{mac\_param}\,%
+\#,
+\\{other\_char}\,\.1,\cr
+\\{out\_param}\,2, \\{spacer}\,\.\ , \\{out\_param}\,2.\cr}}$$
+The procedure \\{scan\_toks} builds such token lists, and \\{macro\_call}
+does the parameter matching.
+
+Examples such as
+$$\.{\\def\\m\{\\def\\m\{a\}\ b\}}$$
+explain why reference counts would be needed even if \TeX\ had no \.{\\let}
+operation: When the token list for \.{\\m} is being read, the redefinition of
+\.{\\m} changes the \\{eqtb} entry before the token list has been fully
+consumed, so we dare not simply destroy a token list when its
+control sequence is being redefined.
+
+If the parameter-matching part of a definition ends with `\.{\#\{}',
+the corresponding token list will have `\.\{' just before the `\\{end\_match}'
+and also at the very end. The first `\.\{' is used to delimit the parameter;
+the
+second one keeps the first from disappearing.
+
+\fi
+
+\M298. The procedure \\{show\_token\_list}, which prints a symbolic form of
+the token list that starts at a given node \|p, illustrates these
+conventions. The token list being displayed should not begin with a reference
+count. However, the procedure is intended to be robust, so that if the
+memory links are awry or if \|p is not really a pointer to a token list,
+nothing catastrophic will happen.
+
+An additional parameter \|q is also given; this parameter is either null
+or it points to a node in the token list where a certain magic computation
+takes place that will be explained later. (Basically, \|q is non-null when
+we are printing the two-line context information at the time of an error
+message; \|q marks the place corresponding to where the second line
+should begin.)
+
+For example, if \|p points to the node containing the first \.a in the
+token list above, then \\{show\_token\_list} will print the string
+$$\hbox{`\.{a\#1\#2\ \\b\ ->\#1\\-a\ \#\#1\#2\ \#2}';}$$
+and if \|q points to the node containing the second \.a,
+the magic computation will be performed just before the second \.a is printed.
+
+The generation will stop, and `\.{\\ETC.}' will be printed, if the length
+of printing exceeds a given limit~\|l. Anomalous entries are printed in the
+form of control sequences that are not followed by a blank space, e.g.,
+`\.{\\BAD.}'; this cannot be confused with actual control sequences because
+a real control sequence named \.{BAD} would come out `\.{\\BAD\ }'.
+
+\Y\P$\4\X298:Declare the procedure called \\{show\_token\_list}\X\S$\6
+\4\&{procedure}\1\  \37$\\{show\_token\_list}(\|p,\39\|q:\\{integer};\,\35\|l:%
+\\{integer})$;\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37$\|m,\39\|c$: \37\\{integer};\C{pieces of a token}\6
+\\{match\_chr}: \37\\{ASCII\_code};\C{character used in a `\\{match}'}\6
+\|n: \37\\{ASCII\_code};\C{the highest parameter number, as an ASCII digit}\2\6
+\&{begin} \37$\\{match\_chr}\K\.{"\#"}$;\5
+$\|n\K\.{"0"}$;\5
+$\\{tally}\K0$;\6
+\&{while} $(\|p\I\\{null})\W(\\{tally}<\|l)$ \1\&{do}\6
+\&{begin} \37\&{if} $\|p=\|q$ \1\&{then}\5
+\X326:Do magic computation\X;\2\6
+\X299:Display token \|p, and \&{return} if there are problems\X;\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\5
+$\\{print\_esc}(\.{"ETC."})$;\2\6
+\4\\{exit}: \37\&{end};\par
+\U120.\fi
+
+\M299. \P$\X299:Display token \|p, and \&{return} if there are problems\X\S$\6
+\&{if} $(\|p<\\{hi\_mem\_min})\V(\|p>\\{mem\_end})$ \1\&{then}\6
+\&{begin} \37$\\{print\_esc}(\.{"CLOBBERED."})$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $\\{info}(\|p)\G\\{cs\_token\_flag}$ \1\&{then}\5
+$\\{print\_cs}(\\{info}(\|p)-\\{cs\_token\_flag})$\C{\\{wchar\_token}}\6
+\4\&{else} \&{begin} \37\&{if} $\\{check\_kanji}(\\{info}(\|p))$ \1\&{then}\C{%
+\\{wchar\_token}}\6
+\&{begin} \37$\|m\K\\{kcat\_code}(\\{kcatcodekey}(\\{info}(\|p)))$;\5
+$\|c\K\\{info}(\|p)$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|m\K\\{Hi}(\\{info}(\|p))$;\5
+$\|c\K\\{Lo}(\\{info}(\|p))$;\6
+\&{end};\2\6
+\&{if} $(\|m<\\{kanji})\W(\|c>256)$ \1\&{then}\5
+$\\{print\_esc}(\.{"BAD."})$\6
+\4\&{else} \X300:Display the token $(\|m,\|c)$\X;\2\6
+\&{end}\2\par
+\U298.\fi
+
+\M300. The procedure usually ``learns'' the character code used for macro
+parameters by seeing one in a \\{match} command before it runs into any
+\\{out\_param} commands.
+
+\Y\P$\4\X300:Display the token $(\|m,\|c)$\X\S$\6
+\&{case} $\|m$ \1\&{of}\6
+\4$\\{kanji},\39\\{kana},\39\\{other\_kchar}$: \37$\\{print\_kanji}(\\{KANJI}(%
+\|c))$;\6
+\4$\\{left\_brace},\39\\{right\_brace},\39\\{math\_shift},\39\\{tab\_mark},\39%
+\\{sup\_mark},\39\\{sub\_mark},\39\\{spacer},\39\\{letter},\39\\{other\_char}$:
+\37$\\{print}(\|c)$;\6
+\4\\{mac\_param}: \37\&{begin} \37$\\{print}(\|c)$;\5
+$\\{print}(\|c)$;\6
+\&{end};\6
+\4\\{out\_param}: \37\&{begin} \37$\\{print}(\\{match\_chr})$;\6
+\&{if} $\|c\L9$ \1\&{then}\5
+$\\{print\_char}(\|c+\.{"0"})$\6
+\4\&{else} \&{begin} \37$\\{print\_char}(\.{"!"})$;\5
+\&{return};\6
+\&{end};\2\6
+\&{end};\6
+\4\\{match}: \37\&{begin} \37$\\{match\_chr}\K\|c$;\5
+$\\{print}(\|c)$;\5
+$\\{incr}(\|n)$;\5
+$\\{print\_char}(\|n)$;\6
+\&{if} $\|n>\.{"9"}$ \1\&{then}\5
+\&{return};\2\6
+\&{end};\6
+\4\\{end\_match}: \37$\\{print}(\.{"->"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"BAD."})$\2\6
+\&{endcases}\par
+\U299.\fi
+
+\M301. Here's the way we sometimes want to display a token list, given a
+pointer
+to its reference count; the pointer may be null.
+
+\Y\P\4\&{procedure}\1\  \37$\\{token\_show}(\|p:\\{pointer})$;\2\6
+\&{begin} \37\&{if} $\|p\I\\{null}$ \1\&{then}\5
+$\\{show\_token\_list}(\\{link}(\|p),\39\\{null},\3910000000)$;\2\6
+\&{end};\par
+\fi
+
+\M302. The \\{print\_meaning} subroutine displays \\{cur\_cmd} and \\{cur\_chr}
+in
+symbolic form, including the expansion of a macro or mark.
+
+\Y\P\4\&{procedure}\1\  \37\\{print\_meaning};\2\6
+\&{begin} \37$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\6
+\&{if} $\\{cur\_cmd}\G\\{call}$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{":"})$;\5
+\\{print\_ln};\5
+$\\{token\_show}(\\{cur\_chr})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{top\_bot\_mark}$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{":"})$;\5
+\\{print\_ln};\5
+$\\{token\_show}(\\{cur\_mark}[\\{cur\_chr}])$;\6
+\&{end};\2\2\6
+\&{end};\par
+\fi
+
+\N303.  \[21] Introduction to the syntactic routines.
+Let's pause a moment now and try to look at the Big Picture.
+The \TeX\ program consists of three main parts: syntactic routines,
+semantic routines, and output routines. The chief purpose of the
+syntactic routines is to deliver the user's input to the semantic routines,
+one token at a time. The semantic routines act as an interpreter
+responding to these tokens, which may be regarded as commands. And the
+output routines are periodically called on to convert box-and-glue
+lists into a compact set of instructions that will be sent
+to a typesetter. We have discussed the basic data structures and utility
+routines of \TeX, so we are good and ready to plunge into the real activity by
+considering the syntactic routines.
+
+Our current goal is to come to grips with the \\{get\_next} procedure,
+which is the keystone of \TeX's input mechanism. Each call of \\{get\_next}
+sets the value of three variables \\{cur\_cmd}, \\{cur\_chr}, and \\{cur\_cs},
+representing the next input token.
+$$\vbox{\halign{#\hfil\cr
+\hbox{\\{cur\_cmd} denotes a command code from the long list of codes
+given above;}\cr
+\hbox{\\{cur\_chr} denotes a character code or other modifier of the command
+code;}\cr
+\hbox{\\{cur\_cs} is the \\{eqtb} location of the current control sequence,}\cr
+\hbox{\qquad if the current token was a control sequence,
+otherwise it's zero.}\cr}}$$
+Underlying this external behavior of \\{get\_next} is all the machinery
+necessary to convert from character files to tokens. At a given time we
+may be only partially finished with the reading of several files (for
+which \.{\\input} was specified), and partially finished with the expansion
+of some user-defined macros and/or some macro parameters, and partially
+finished with the generation of some text in a template for \.{\\halign},
+and so on. When reading a character file, special characters must be
+classified as math delimiters, etc.; comments and extra blank spaces must
+be removed, paragraphs must be recognized, and control sequences must be
+found in the hash table. Furthermore there are occasions in which the
+scanning routines have looked ahead for a word like `\.{plus}' but only
+part of that word was found, hence a few characters must be put back
+into the input and scanned again.
+
+To handle these situations, which might all be present simultaneously,
+\TeX\ uses various stacks that hold information about the incomplete
+activities, and there is a finite state control for each level of the
+input mechanism. These stacks record the current state of an implicitly
+recursive process, but the \\{get\_next} procedure is not recursive.
+Therefore it will not be difficult to translate these algorithms into
+low-level languages that do not support recursion.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_cmd}: \37\\{eight\_bits};\C{current command set by \\{get\_next}}\6
+\4\\{cur\_chr}: \37\\{halfword};\C{operand of current command}\6
+\4\\{cur\_cs}: \37\\{pointer};\C{control sequence found here, zero if none
+found}\6
+\4\\{cur\_tok}: \37\\{halfword};\C{packed representative of \\{cur\_cmd} and %
+\\{cur\_chr}}\par
+\fi
+
+\M304. The \\{print\_cmd\_chr} routine prints a symbolic interpretation of a
+command code and its modifier. This is used in certain `\.{You can\'t}'
+error messages, and in the implementation of diagnostic routines like
+\.{\\show}.
+
+The body of \\{print\_cmd\_chr} is a rather tedious listing of print
+commands, and most of it is essentially an inverse to the \\{primitive}
+routine that enters a \TeX\ primitive into \\{eqtb}. Therefore much of
+this procedure appears elsewhere in the program,
+together with the corresponding \\{primitive} calls.
+
+\Y\P\D \37$\\{chr\_cmd}(\#)\S$\1\6
+\&{begin} \37$\\{print}(\#)$;\5
+$\\{print\_ASCII}(\\{chr\_code})$;\6
+\&{end}\2\par
+\Y\P$\4\X304:Declare the procedure called \\{print\_cmd\_chr}\X\S$\6
+\4\&{procedure}\1\  \37$\\{print\_cmd\_chr}(\\{cmd}:\\{quarterword};\,\35\\{chr%
+\_code}:\\{halfword})$;\2\6
+\&{begin} \37\&{case} $\\{cmd}$ \1\&{of}\6
+\4\\{left\_brace}: \37$\\{chr\_cmd}(\.{"begin-group\ character\ "})$;\6
+\4\\{right\_brace}: \37$\\{chr\_cmd}(\.{"end-group\ character\ "})$;\6
+\4\\{math\_shift}: \37$\\{chr\_cmd}(\.{"math\ shift\ character\ "})$;\6
+\4\\{mac\_param}: \37$\\{chr\_cmd}(\.{"macro\ parameter\ character\ "})$;\6
+\4\\{sup\_mark}: \37$\\{chr\_cmd}(\.{"superscript\ character\ "})$;\6
+\4\\{sub\_mark}: \37$\\{chr\_cmd}(\.{"subscript\ character\ "})$;\6
+\4\\{endv}: \37$\\{print}(\.{"end\ of\ alignment\ template"})$;\6
+\4\\{spacer}: \37$\\{chr\_cmd}(\.{"blank\ space\ "})$;\6
+\4\\{letter}: \37$\\{chr\_cmd}(\.{"the\ letter\ "})$;\6
+\4\\{other\_char}: \37$\\{chr\_cmd}(\.{"the\ character\ "})$;\6
+\4$\\{kanji},\39\\{kana},\39\\{other\_kchar}$: \37\&{begin} \37$\\{print}(%
+\.{"kanji\ character\ "})$;\5
+$\\{print\_kanji}(\\{KANJI}(\\{chr\_code}))$;\6
+\&{end};\6
+\hbox{\4}\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives%
+\X\6
+\4\&{othercases} \37$\\{print}(\.{"[unknown\ command\ code!]"})$\2\6
+\&{endcases};\6
+\&{end};\par
+\U258.\fi
+
+\M305. Here is a procedure that displays the current command.
+
+\Y\P\4\&{procedure}\1\  \37\\{show\_cur\_cmd\_chr};\2\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"\{"})$;\6
+\&{if} $\\{mode}\I\\{shown\_mode}$ \1\&{then}\6
+\&{begin} \37$\\{print\_mode}(\\{mode})$;\5
+$\\{print}(\.{":\ "})$;\5
+$\\{shown\_mode}\K\\{mode}$;\6
+\&{end};\2\6
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\5
+$\\{print\_char}(\.{"\}"})$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end};\par
+\fi
+
+\N306.  \[22] Input stacks and states.
+This implementation of
+\TeX\ uses two different conventions for representing sequential stacks.
+
+\yskip\hangg 1) If there is frequent access to the top entry, and if the
+stack is essentially never empty, then the top entry is kept in a global
+variable (even better would be a machine register), and the other entries
+appear in the array $\\{stack}[0\to(\\{ptr}-1)]$. For example, the
+semantic stack described above is handled this way, and so is the input
+stack that we are about to study.
+
+\yskip\hangg 2) If there is infrequent top access, the entire stack contents
+are in the array $\\{stack}[0\to(\\{ptr}-1)]$. For example, the \\{save\_stack}
+is treated this way, as we have seen.
+
+\yskip\noindent
+The state of \TeX's input mechanism appears in the input stack, whose
+entries are records with six fields, called \\{state}, \\{index}, \\{start}, %
+\\{loc},
+\\{limit}, and \\{name}. This stack is maintained with
+convention~(1), so it is declared in the following way:
+
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{in\_state\_record}=$\1\5
+\1\&{record} \37$\\{state\_field},\39\\{index\_field}$: \37\\{quarterword};\6
+\4$\\{start\_field},\39\\{loc\_field},\39\\{limit\_field},\39\\{name\_field}$: %
+\37\\{halfword};\2\6
+\&{end};\2\par
+\fi
+
+\M307. \P$\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{input\_stack}: \37$\^\\{in\_state\_record}$;\6
+\4\\{input\_ptr}: \37$0\to\\{stack\_size}$;\C{first unused location of \\{input%
+\_stack}}\6
+\4\\{max\_in\_stack}: \37$0\to\\{stack\_size}$;\C{largest value of \\{input%
+\_ptr} when pushing}\6
+\4\\{cur\_input}: \37\\{in\_state\_record};\C{the ``top'' input state,
+according to convention (1)}\par
+\fi
+
+\M308. We've already defined the special variable $\\{loc}\S\\{cur\_input}.%
+\\{loc\_field}$
+in our discussion of basic input-output routines. The other components of
+\\{cur\_input} are defined in the same way:
+
+\Y\P\D \37$\\{state}\S\\{cur\_input}.\\{state\_field}$\C{current scanner state}%
+\par
+\P\D \37$\\{index}\S\\{cur\_input}.\\{index\_field}$\C{reference for buffer
+information}\par
+\P\D \37$\\{start}\S\\{cur\_input}.\\{start\_field}$\C{starting position in %
+\\{buffer}}\par
+\P\D \37$\\{limit}\S\\{cur\_input}.\\{limit\_field}$\C{end of current line in %
+\\{buffer}}\par
+\P\D \37$\\{name}\S\\{cur\_input}.\\{name\_field}$\C{name of the current file}%
+\par
+\fi
+
+\M309. Let's look more closely now at the control variables
+(\\{state},~\\{index},~\\{start},~\\{loc},~\\{limit},~\\{name}),
+assuming that \TeX\ is reading a line of characters that have been input
+from some file or from the user's terminal. There is an array called
+\\{buffer} that acts as a stack of all lines of characters that are
+currently being read from files, including all lines on subsidiary
+levels of the input stack that are not yet completed. \TeX\ will return to
+the other lines when it is finished with the present input file.
+
+(Incidentally, on a machine with byte-oriented addressing, it might be
+appropriate to combine \\{buffer} with the \\{str\_pool} array,
+letting the buffer entries grow downward from the top of the string pool
+and checking that these two tables don't bump into each other.)
+
+The line we are currently working on begins in position \\{start} of the
+buffer; the next character we are about to read is $\\{buffer}[\\{loc}]$; and
+\\{limit} is the location of the last character present.  If $\\{loc}>%
+\\{limit}$,
+the line has been completely read. Usually $\\{buffer}[\\{limit}]$ is the
+\\{end\_line\_char}, denoting the end of a line, but this is not
+true if the current line is an insertion that was entered on the user's
+terminal in response to an error message.
+
+The \\{name} variable is a string number that designates the name of
+the current file, if we are reading a text file. It is zero if we
+are reading from the terminal; it is $\|n+1$ if we are reading from
+input stream \|n, where $0\L\|n\L16$. (Input stream 16 stands for
+an invalid stream number; in such cases the input is actually from
+the terminal, under control of the procedure \\{read\_toks}.)
+
+The \\{state} variable has one of three values, when we are scanning such
+files:
+$$\baselineskip 15pt\vbox{\halign{#\hfil\cr
+1) $\\{state}=\\{mid\_line}$ is the normal state.\cr
+2) $\\{state}=\\{mid\_kanji}$ is like \\{mid\_line}, and internal KANJI string.%
+\cr
+3) $\\{state}=\\{skip\_blanks}$ is like \\{mid\_line}, but blanks are ignored.%
+\cr
+4) $\\{state}=\\{new\_line}$ is the state at the beginning of a line.\cr}}$$
+These state values are assigned numeric codes so that if we add the state
+code to the next character's command code, we get distinct values. For
+example, `$\\{mid\_line}+\\{spacer}$' stands for the case that a blank
+space character occurs in the middle of a line when it is not being
+ignored; after this case is processed, the next value of \\{state} will
+be \\{skip\_blanks}.
+
+\Y\P\D \37$\\{mid\_line}=1$\C{\\{state} code when scanning a line of
+characters}\par
+\P\D \37$\\{mid\_kanji}=2+\\{max\_char\_code}$\C{\\{state} code when scanning a
+line of characters}\par
+\P\D \37$\\{skip\_blanks}=3+\\{max\_char\_code}+\\{max\_char\_code}$\C{%
+\\{state} code when ignoring blanks}\par
+\P\D \37$\\{new\_line}=4+\\{max\_char\_code}+\\{max\_char\_code}+\\{max\_char%
+\_code}$\C{\\{state} code at start of line}\par
+\fi
+
+\M310. Additional information about the current line is available via the
+\\{index} variable, which counts how many lines of characters are present
+in the buffer below the current level. We have $\\{index}=0$ when reading
+from the terminal and prompting the user for each line; then if the user types,
+e.g., `\.{\\input paper}', we will have $\\{index}=1$ while reading
+the file \.{paper.tex}. However, it does not follow that \\{index} is the
+same as the input stack pointer, since many of the levels on the input
+stack may come from token lists. For example, the instruction `\.{\\input
+paper}' might occur in a token list.
+
+The global variable \\{in\_open} is equal to the \\{index}
+value of the highest non-token-list level. Thus, the number of partially read
+lines in the buffer is $\\{in\_open}+1$, and we have $\\{in\_open}=\\{index}$
+when we are not reading a token list.
+
+If we are not currently reading from the terminal, or from an input
+stream, we are reading from the file variable $\\{input\_file}[\\{index}]$. We
+use
+the notation \\{terminal\_input} as a convenient abbreviation for $\\{name}=0$,
+and \\{cur\_file} as an abbreviation for $\\{input\_file}[\\{index}]$.
+
+The global variable \\{line} contains the line number in the topmost
+open file, for use in error messages. If we are not reading from
+the terminal, $\\{line\_stack}[\\{index}]$ holds the line number for the
+enclosing level, so that \\{line} can be restored when the current
+file has been read. Line numbers should never be negative, since the
+negative of the current line number is used to identify the user's output
+routine in the \\{mode\_line} field of the semantic nest entries.
+
+If more information about the input state is needed, it can be
+included in small arrays like those shown here. For example,
+the current page or segment number in the input file might be
+put into a variable \\{page}, maintained for enclosing levels in
+`\ignorespaces \\{page\_stack}: \&{array} $[1\to\\{max\_in\_open}]$ \&{of} %
+\\{integer}\unskip'
+by analogy with \\{line\_stack}.
+
+\Y\P\D \37$\\{terminal\_input}\S(\\{name}=0)$\C{are we reading from the
+terminal?}\par
+\P\D \37$\\{cur\_file}\S\\{input\_file}[\\{index}]$\C{the current \\{alpha%
+\_file} variable}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{in\_open}: \37$0\to\\{max\_in\_open}$;\C{the number of lines in the
+buffer, less one}\6
+\4\\{open\_parens}: \37$0\to\\{max\_in\_open}$;\C{the number of open text
+files}\6
+\4\\{input\_file}: \37$\^\\{alpha\_file}$;\6
+\4\\{line}: \37\\{integer};\C{current line number in the current source file}\6
+\4\\{line\_stack}: \37$\^\\{integer}$;\6
+\4\\{source\_filename\_stack}: \37$\^\\{str\_number}$;\6
+\4\\{full\_source\_filename\_stack}: \37$\^\\{str\_number}$;\par
+\fi
+
+\M311. Users of \TeX\ sometimes forget to balance left and right braces
+properly,
+and one of the ways \TeX\ tries to spot such errors is by considering an
+input file as broken into subfiles by control sequences that
+are declared to be \.{\\outer}.
+
+A variable called \\{scanner\_status} tells \TeX\ whether or not to complain
+when a subfile ends. This variable has six possible values:
+
+\yskip\hang\\{normal}, means that a subfile can safely end here without
+incident.
+
+\yskip\hang\\{skipping}, means that a subfile can safely end here, but not a
+file,
+because we're reading past some conditional text that was not selected.
+
+\yskip\hang\\{defining}, means that a subfile shouldn't end now because a
+macro is being defined.
+
+\yskip\hang\\{matching}, means that a subfile shouldn't end now because a
+macro is being used and we are searching for the end of its arguments.
+
+\yskip\hang\\{aligning}, means that a subfile shouldn't end now because we are
+not finished with the preamble of an \.{\\halign} or \.{\\valign}.
+
+\yskip\hang\\{absorbing}, means that a subfile shouldn't end now because we are
+reading a balanced token list for \.{\\message}, \.{\\write}, etc.
+
+\yskip\noindent
+If the \\{scanner\_status} is not \\{normal}, the variable \\{warning\_index}
+points
+to the \\{eqtb} location for the relevant control sequence name to print
+in an error message.
+
+\Y\P\D \37$\\{skipping}=1$\C{\\{scanner\_status} when passing conditional text}%
+\par
+\P\D \37$\\{defining}=2$\C{\\{scanner\_status} when reading a macro definition}%
+\par
+\P\D \37$\\{matching}=3$\C{\\{scanner\_status} when reading macro arguments}\par
+\P\D \37$\\{aligning}=4$\C{\\{scanner\_status} when reading an alignment
+preamble}\par
+\P\D \37$\\{absorbing}=5$\C{\\{scanner\_status} when reading a balanced text}%
+\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{scanner\_status}: \37$\\{normal}\to\\{absorbing}$;\C{can a subfile end
+now?}\6
+\4\\{warning\_index}: \37\\{pointer};\C{identifier relevant to non-\\{normal}
+scanner status}\6
+\4\\{def\_ref}: \37\\{pointer};\C{reference count of token list being defined}%
+\par
+\fi
+
+\M312. Here is a procedure that uses \\{scanner\_status} to print a warning
+message
+when a subfile has ended, and at certain other crucial times:
+
+\Y\P$\4\X312:Declare the procedure called \\{runaway}\X\S$\6
+\4\&{procedure}\1\  \37\\{runaway};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{head of runaway list}\2\6
+\&{begin} \37\&{if} $\\{scanner\_status}>\\{skipping}$ \1\&{then}\6
+\&{begin} \37\&{case} $\\{scanner\_status}$ \1\&{of}\6
+\4\\{defining}: \37\&{begin} \37$\\{print\_nl}(\.{"Runaway\ definition"})$;\5
+$\|p\K\\{def\_ref}$;\6
+\&{end};\6
+\4\\{matching}: \37\&{begin} \37$\\{print\_nl}(\.{"Runaway\ argument"})$;\5
+$\|p\K\\{temp\_head}$;\6
+\&{end};\6
+\4\\{aligning}: \37\&{begin} \37$\\{print\_nl}(\.{"Runaway\ preamble"})$;\5
+$\|p\K\\{hold\_head}$;\6
+\&{end};\6
+\4\\{absorbing}: \37\&{begin} \37$\\{print\_nl}(\.{"Runaway\ text"})$;\5
+$\|p\K\\{def\_ref}$;\6
+\&{end};\2\6
+\&{end};\C{there are no other cases}\6
+$\\{print\_char}(\.{"?"})$;\5
+\\{print\_ln};\5
+$\\{show\_token\_list}(\\{link}(\|p),\39\\{null},\39\\{error\_line}-10)$;\6
+\&{end};\2\6
+\&{end};\par
+\U120.\fi
+
+\M313. However, all this discussion about input state really applies only to
+the
+case that we are inputting from a file. There is another important case,
+namely when we are currently getting input from a token list. In this case
+$\\{state}=\\{token\_list}$, and the conventions about the other state
+variables
+are different:
+
+\yskip\hang\\{loc} is a pointer to the current node in the token list, i.e.,
+the node that will be read next. If $\\{loc}=\\{null}$, the token list has been
+fully read.
+
+\yskip\hang\\{start} points to the first node of the token list; this node
+may or may not contain a reference count, depending on the type of token
+list involved.
+
+\yskip\hang\\{token\_type}, which takes the place of \\{index} in the
+discussion above, is a code number that explains what kind of token list
+is being scanned.
+
+\yskip\hang\\{name} points to the \\{eqtb} address of the control sequence
+being expanded, if the current token list is a macro.
+
+\yskip\hang\\{param\_start}, which takes the place of \\{limit}, tells where
+the parameters of the current macro begin in the \\{param\_stack}, if the
+current token list is a macro.
+
+\yskip\noindent The \\{token\_type} can take several values, depending on
+where the current token list came from:
+
+\yskip\hang\\{parameter}, if a parameter is being scanned;
+
+\hang\\{u\_template}, if the \<u_j> part of an alignment
+template is being scanned;
+
+\hang\\{v\_template}, if the \<v_j> part of an alignment
+template is being scanned;
+
+\hang\\{backed\_up}, if the token list being scanned has been inserted as
+`to be read again'.
+
+\hang\\{inserted}, if the token list being scanned has been inserted as
+the text expansion of a \.{\\count} or similar variable;
+
+\hang\\{macro}, if a user-defined control sequence is being scanned;
+
+\hang\\{output\_text}, if an \.{\\output} routine is being scanned;
+
+\hang\\{every\_par\_text}, if the text of \.{\\everypar} is being scanned;
+
+\hang\\{every\_math\_text}, if the text of \.{\\everymath} is being scanned;
+
+\hang\\{every\_display\_text}, if the text of \.{\\everydisplay} is being
+scanned;
+
+\hang\\{every\_hbox\_text}, if the text of \.{\\everyhbox} is being scanned;
+
+\hang\\{every\_vbox\_text}, if the text of \.{\\everyvbox} is being scanned;
+
+\hang\\{every\_job\_text}, if the text of \.{\\everyjob} is being scanned;
+
+\hang\\{every\_cr\_text}, if the text of \.{\\everycr} is being scanned;
+
+\hang\\{mark\_text}, if the text of a \.{\\mark} is being scanned;
+
+\hang\\{write\_text}, if the text of a \.{\\write} is being scanned.
+
+\yskip\noindent
+The codes for \\{output\_text}, \\{every\_par\_text}, etc., are equal to a
+constant
+plus the corresponding codes for token list parameters \\{output\_routine%
+\_loc},
+\\{every\_par\_loc}, etc.  The token list begins with a reference count if and
+only if $\\{token\_type}\G\\{macro}$.
+
+\Y\P\D \37$\\{token\_list}=0$\C{\\{state} code when scanning a token list}\par
+\P\D \37$\\{token\_type}\S\\{index}$\C{type of current token list}\par
+\P\D \37$\\{param\_start}\S\\{limit}$\C{base of macro parameters in \\{param%
+\_stack}}\par
+\P\D \37$\\{parameter}=0$\C{\\{token\_type} code for parameter}\par
+\P\D \37$\\{u\_template}=1$\C{\\{token\_type} code for \<u_j> template}\par
+\P\D \37$\\{v\_template}=2$\C{\\{token\_type} code for \<v_j> template}\par
+\P\D \37$\\{backed\_up}=3$\C{\\{token\_type} code for text to be reread}\par
+\P\D \37$\\{inserted}=4$\C{\\{token\_type} code for inserted texts}\par
+\P\D \37$\\{macro}=5$\C{\\{token\_type} code for defined control sequences}\par
+\P\D \37$\\{output\_text}=6$\C{\\{token\_type} code for output routines}\par
+\P\D \37$\\{every\_par\_text}=7$\C{\\{token\_type} code for \.{\\everypar}}\par
+\P\D \37$\\{every\_math\_text}=8$\C{\\{token\_type} code for \.{\\everymath}}%
+\par
+\P\D \37$\\{every\_display\_text}=9$\C{\\{token\_type} code for \.{%
+\\everydisplay}}\par
+\P\D \37$\\{every\_hbox\_text}=10$\C{\\{token\_type} code for \.{\\everyhbox}}%
+\par
+\P\D \37$\\{every\_vbox\_text}=11$\C{\\{token\_type} code for \.{\\everyvbox}}%
+\par
+\P\D \37$\\{every\_job\_text}=12$\C{\\{token\_type} code for \.{\\everyjob}}\par
+\P\D \37$\\{every\_cr\_text}=13$\C{\\{token\_type} code for \.{\\everycr}}\par
+\P\D \37$\\{mark\_text}=14$\C{\\{token\_type} code for \.{\\topmark}, etc.}\par
+\P\D \37$\\{write\_text}=15$\C{\\{token\_type} code for \.{\\write}}\par
+\fi
+
+\M314. The \\{param\_stack} is an auxiliary array used to hold pointers to the
+token
+lists for parameters at the current level and subsidiary levels of input.
+This stack is maintained with convention (2), and it grows at a different
+rate from the others.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{param\_stack}: \37$\^\\{pointer}$;\C{token list pointers for parameters}\6
+\4\\{param\_ptr}: \37$0\to\\{param\_size}$;\C{first unused entry in \\{param%
+\_stack}}\6
+\4\\{max\_param\_stack}: \37\\{integer};\C{largest value of \\{param\_ptr},
+will be $\L\\{param\_size}+9$}\par
+\fi
+
+\M315. The input routines must also interact with the processing of
+\.{\\halign} and \.{\\valign}, since the appearance of tab marks and
+\.{\\cr} in certain places is supposed to trigger the beginning of special
+\<v_j> template text in the scanner. This magic is accomplished by an
+\\{align\_state} variable that is increased by~1 when a `\.{\char'173}' is
+scanned and decreased by~1 when a `\.{\char'175}' is scanned. The \\{align%
+\_state}
+is nonzero during the \<u_j> template, after which it is set to zero; the
+\<v_j> template begins when a tab mark or \.{\\cr} occurs at a time that
+$\\{align\_state}=0$.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{align\_state}: \37\\{integer};\C{group level with respect to current
+alignment}\par
+\fi
+
+\M316. Thus, the ``current input state'' can be very complicated indeed; there
+can be many levels and each level can arise in a variety of ways. The
+\\{show\_context} procedure, which is used by \TeX's error-reporting routine to
+print out the current input state on all levels down to the most recent
+line of characters from an input file, illustrates most of these conventions.
+The global variable \\{base\_ptr} contains the lowest level that was
+displayed by this procedure.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{base\_ptr}: \37$0\to\\{stack\_size}$;\C{shallowest level shown by \\{show%
+\_context}}\par
+\fi
+
+\M317. The status at each level is indicated by printing two lines, where the
+first
+line indicates what was read so far and the second line shows what remains
+to be read. The context is cropped, if necessary, so that the first line
+contains at most \\{half\_error\_line} characters, and the second contains
+at most \\{error\_line}. Non-current input levels whose \\{token\_type} is
+`\\{backed\_up}' are shown only if they have not been fully read.
+
+\Y\P\4\&{procedure}\1\  \37\\{show\_context};\C{prints where the scanner is}\6
+\4\&{label} \37$\\{done},\39\\{done1}$;\6
+\4\&{var} \37\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{saved \\{selector}
+setting}\6
+\|s: \37\\{pointer};\C{temporary pointer}\6
+\\{nn}: \37\\{integer};\C{number of contexts shown so far, less one}\6
+\\{bottom\_line}: \37\\{boolean};\C{have we reached the final context to be
+shown?}\6
+\X321:Local variables for formatting calculations\X\2\6
+\&{begin} \37$\\{base\_ptr}\K\\{input\_ptr}$;\5
+$\\{input\_stack}[\\{base\_ptr}]\K\\{cur\_input}$;\C{store current state}\6
+$\\{nn}\K-1$;\5
+$\\{bottom\_line}\K\\{false}$;\6
+\~ \1\&{loop}\ \&{begin} \37$\\{cur\_input}\K\\{input\_stack}[\\{base\_ptr}]$;%
+\C{enter into the context}\6
+\&{if} $(\\{state}\I\\{token\_list})$ \1\&{then}\6
+\&{if} $(\\{name}>17)\V(\\{base\_ptr}=0)$ \1\&{then}\5
+$\\{bottom\_line}\K\\{true}$;\2\2\6
+\&{if} $(\\{base\_ptr}=\\{input\_ptr})\V\\{bottom\_line}\V(\\{nn}<\\{error%
+\_context\_lines})$ \1\&{then}\5
+\X318:Display the current context\X\6
+\4\&{else} \&{if} $\\{nn}=\\{error\_context\_lines}$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"..."})$;\5
+$\\{incr}(\\{nn})$;\C{omitted if $\\{error\_context\_lines}<0$}\6
+\&{end};\2\2\6
+\&{if} $\\{bottom\_line}$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\\{decr}(\\{base\_ptr})$;\6
+\&{end};\2\6
+\4\\{done}: \37$\\{cur\_input}\K\\{input\_stack}[\\{input\_ptr}]$;\C{restore
+original state}\6
+\&{end};\par
+\fi
+
+\M318. \P$\X318:Display the current context\X\S$\6
+\&{begin} \37\&{if} $(\\{base\_ptr}=\\{input\_ptr})\V(\\{state}\I\\{token%
+\_list})\V(\\{token\_type}\I\\{backed\_up})\V(\\{loc}\I\\{null})$ \1\&{then}%
+\C{we omit backed-up token lists that have already been read}\6
+\&{begin} \37$\\{tally}\K0$;\C{get ready to count characters}\6
+$\\{old\_setting}\K\\{selector}$;\6
+\&{if} $\\{state}\I\\{token\_list}$ \1\&{then}\6
+\&{begin} \37\X319:Print location of current line\X;\6
+\X324:Pseudoprint the line\X;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\X320:Print type of token list\X;\6
+\X325:Pseudoprint the token list\X;\6
+\&{end};\2\6
+$\\{selector}\K\\{old\_setting}$;\C{stop pseudoprinting}\6
+\X323:Print two lines using the tricky pseudoprinted information\X;\6
+$\\{incr}(\\{nn})$;\6
+\&{end};\2\6
+\&{end}\par
+\U317.\fi
+
+\M319. This routine should be changed, if necessary, to give the best possible
+indication of where the current line resides in the input file.
+For example, on some systems it is best to print both a page and line number.
+
+\Y\P$\4\X319:Print location of current line\X\S$\6
+\&{if} $\\{name}\L17$ \1\&{then}\6
+\&{if} $\\{terminal\_input}$ \1\&{then}\6
+\&{if} $\\{base\_ptr}=0$ \1\&{then}\5
+$\\{print\_nl}(\.{"<*>"})$\6
+\4\&{else} $\\{print\_nl}(\.{"<insert>\ "})$\2\6
+\4\&{else} \&{begin} \37$\\{print\_nl}(\.{"<read\ "})$;\6
+\&{if} $\\{name}=17$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\ \&{else} $\\{print\_int}(\\{name}-1)$;\2\6
+$\\{print\_char}(\.{">"})$;\6
+\&{end}\2\6
+\4\&{else} \&{begin} \37$\\{print\_nl}(\.{"l."})$;\5
+$\\{print\_int}(\\{line})$;\6
+\&{end};\2\6
+$\\{print\_char}(\.{"\ "})$\par
+\U318.\fi
+
+\M320. \P$\X320:Print type of token list\X\S$\6
+\&{case} $\\{token\_type}$ \1\&{of}\6
+\4\\{parameter}: \37$\\{print\_nl}(\.{"<argument>\ "})$;\6
+\4$\\{u\_template},\39\\{v\_template}$: \37$\\{print\_nl}(\.{"<template>\ "})$;%
+\6
+\4\\{backed\_up}: \37\&{if} $\\{loc}=\\{null}$ \1\&{then}\5
+$\\{print\_nl}(\.{"<recently\ read>\ "})$\6
+\4\&{else} $\\{print\_nl}(\.{"<to\ be\ read\ again>\ "})$;\2\6
+\4\\{inserted}: \37$\\{print\_nl}(\.{"<inserted\ text>\ "})$;\6
+\4\\{macro}: \37\&{begin} \37\\{print\_ln};\5
+$\\{print\_cs}(\\{name})$;\6
+\&{end};\6
+\4\\{output\_text}: \37$\\{print\_nl}(\.{"<output>\ "})$;\6
+\4\\{every\_par\_text}: \37$\\{print\_nl}(\.{"<everypar>\ "})$;\6
+\4\\{every\_math\_text}: \37$\\{print\_nl}(\.{"<everymath>\ "})$;\6
+\4\\{every\_display\_text}: \37$\\{print\_nl}(\.{"<everydisplay>\ "})$;\6
+\4\\{every\_hbox\_text}: \37$\\{print\_nl}(\.{"<everyhbox>\ "})$;\6
+\4\\{every\_vbox\_text}: \37$\\{print\_nl}(\.{"<everyvbox>\ "})$;\6
+\4\\{every\_job\_text}: \37$\\{print\_nl}(\.{"<everyjob>\ "})$;\6
+\4\\{every\_cr\_text}: \37$\\{print\_nl}(\.{"<everycr>\ "})$;\6
+\4\\{mark\_text}: \37$\\{print\_nl}(\.{"<mark>\ "})$;\6
+\4\\{write\_text}: \37$\\{print\_nl}(\.{"<write>\ "})$;\6
+\4\&{othercases} \37$\\{print\_nl}(\.{"?"})$\C{this should never happen}\2\6
+\&{endcases}\par
+\U318.\fi
+
+\M321. Here it is necessary to explain a little trick. We don't want to store a
+long
+string that corresponds to a token list, because that string might take up
+lots of memory; and we are printing during a time when an error message is
+being given, so we dare not do anything that might overflow one of \TeX's
+tables. So `pseudoprinting' is the answer: We enter a mode of printing
+that stores characters into a buffer of length \\{error\_line}, where character
+$k+1$ is placed into \hbox{$\\{trick\_buf}[\|k\mathbin{\&{mod}}\\{error%
+\_line}]$} if
+$\|k<\\{trick\_count}$, otherwise character \|k is dropped. Initially we set
+$\\{tally}\K0$ and $\\{trick\_count}\K1000000$; then when we reach the
+point where transition from line 1 to line 2 should occur, we
+set $\\{first\_count}\K\\{tally}$ and $\\{trick\_count}\K\hbox{max}(\\{error%
+\_line},\\{tally}+1+\\{error\_line}-\\{half\_error\_line})$. At the end of the
+pseudoprinting, the values of \\{first\_count}, \\{tally}, and
+\\{trick\_count} give us all the information we need to print the two lines,
+and all of the necessary text is in \\{trick\_buf}.
+
+Namely, let \|l be the length of the descriptive information that appears
+on the first line. The length of the context information gathered for that
+line is $\|k=\\{first\_count}$, and the length of the context information
+gathered for line~2 is $m=\min(\\{tally}, \\{trick\_count})-k$. If $\|l+\|k\L%
+\|h$,
+where $\|h=\\{half\_error\_line}$, we print $\\{trick\_buf}[0\to\|k-1]$ after
+the
+descriptive information on line~1, and set $\|n\K\|l+\|k$; here \|n is the
+length of line~1. If $l+k>h$, some cropping is necessary, so we set $\|n\K\|h$
+and print `\.{...}' followed by
+$$\hbox{$\\{trick\_buf}[(\|l+\|k-\|h+3)\to\|k-1]$,}$$
+where subscripts of \\{trick\_buf} are circular modulo \\{error\_line}. The
+second line consists of \|n~spaces followed by $\\{trick\_buf}[\|k\to(\|k+%
+\|m-1)]$,
+unless $\|n+\|m>\\{error\_line}$; in the latter case, further cropping is done.
+This is easier to program than to explain.
+
+\Y\P$\4\X321:Local variables for formatting calculations\X\S$\6
+\4\|i: \37$0\to\\{buf\_size}$;\C{index into \\{buffer}}\6
+\4\|j: \37$0\to\\{buf\_size}$;\C{end of current line in \\{buffer}}\6
+\4\|l: \37$0\to\\{half\_error\_line}$;\C{length of descriptive information on
+line 1}\6
+\4\|m: \37\\{integer};\C{context information gathered for line 2}\6
+\4\|n: \37$0\to\\{error\_line}$;\C{length of line 1}\6
+\4\|p: \37\\{integer};\C{starting or ending place in \\{trick\_buf}}\6
+\4\|q: \37\\{integer};\C{temporary index}\par
+\U317.\fi
+
+\M322. The following code sets up the print routines so that they will gather
+the desired information.
+
+\Y\P\D \37$\\{begin\_pseudoprint}\S$\1\6
+\&{begin} \37$\|l\K\\{tally}$;\5
+$\\{tally}\K0$;\5
+$\\{selector}\K\\{pseudo}$;\5
+$\\{kcode\_pos}\K0$;\5
+$\\{trick\_count}\K1000000$;\6
+\&{end}\2\par
+\P\D \37$\\{set\_trick\_count}\S$\1\6
+\&{begin} \37$\\{first\_count}\K\\{tally}$;\6
+\&{if} $(\\{first\_count}>0)\W(\\{trick\_buf2}[(\\{first\_count}-1)\mathbin{%
+\&{mod}}\\{error\_line}]=1)$ \1\&{then}\5
+$\\{incr}(\\{first\_count})$;\2\6
+$\\{trick\_count}\K\\{first\_count}+1+\\{error\_line}-\\{half\_error\_line}$;\6
+\&{if} $\\{trick\_count}<\\{error\_line}$ \1\&{then}\5
+$\\{trick\_count}\K\\{error\_line}$;\2\6
+\&{end}\2\par
+\fi
+
+\M323. And the following code uses the information after it has been gathered.
+
+\Y\P$\4\X323:Print two lines using the tricky pseudoprinted information\X\S$\6
+\&{if} $\\{trick\_count}=1000000$ \1\&{then}\5
+\\{set\_trick\_count};\C{\\{set\_trick\_count} must be performed}\2\6
+\&{if} $\\{tally}<\\{trick\_count}$ \1\&{then}\5
+$\|m\K\\{tally}-\\{first\_count}$\6
+\4\&{else} $\|m\K\\{trick\_count}-\\{first\_count}$;\C{context on line 2}\2\6
+\&{if} $\|l+\\{first\_count}\L\\{half\_error\_line}$ \1\&{then}\6
+\&{begin} \37$\|p\K0$;\5
+$\|n\K\|l+\\{first\_count}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print}(\.{"..."})$;\5
+$\|p\K\|l+\\{first\_count}-\\{half\_error\_line}+3$;\5
+$\|n\K\\{half\_error\_line}$;\6
+\&{end};\2\6
+\&{if} $\\{trick\_buf2}[\|p\mathbin{\&{mod}}\\{error\_line}]=2$ \1\&{then}\6
+\&{begin} \37$\|p\K\|p+1$;\5
+$\|n\K\|n-1$;\6
+\&{end};\2\6
+\&{for} $\|q\K\|p\mathrel{\&{to}}\\{first\_count}-1$ \1\&{do}\5
+$\\{print\_char}(\\{trick\_buf}[\|q\mathbin{\&{mod}}\\{error\_line}])$;\2\6
+\\{print\_ln};\6
+\&{for} $\|q\K1\mathrel{\&{to}}\|n$ \1\&{do}\5
+$\\{print\_char}(\.{"\ "})$;\C{print \|n spaces to begin line~2}\2\6
+\&{if} $\|m+\|n\L\\{error\_line}$ \1\&{then}\5
+$\|p\K\\{first\_count}+\|m$\6
+\4\&{else} $\|p\K\\{first\_count}+(\\{error\_line}-\|n-3)$;\2\6
+\&{if} $\\{trick\_buf2}[(\|p-1)\mathbin{\&{mod}}\\{error\_line}]=1$ \1\&{then}\5
+$\|p\K\|p-1$;\2\6
+\&{for} $\|q\K\\{first\_count}\mathrel{\&{to}}\|p-1$ \1\&{do}\5
+$\\{print\_char}(\\{trick\_buf}[\|q\mathbin{\&{mod}}\\{error\_line}])$;\2\6
+\&{if} $\|m+\|n>\\{error\_line}$ \1\&{then}\5
+$\\{print}(\.{"..."})$\2\par
+\U318.\fi
+
+\M324. But the trick is distracting us from our current goal, which is to
+understand the input state. So let's concentrate on the data structures that
+are being pseudoprinted as we finish up the \\{show\_context} procedure.
+
+\Y\P$\4\X324:Pseudoprint the line\X\S$\6
+\\{begin\_pseudoprint};\6
+\&{if} $\\{buffer}[\\{limit}]=\\{end\_line\_char}$ \1\&{then}\5
+$\|j\K\\{limit}$\6
+\4\&{else} $\|j\K\\{limit}+1$;\C{determine the effective end of the line}\2\6
+\&{if} $\|j>0$ \1\&{then}\6
+\&{for} $\|i\K\\{start}\mathrel{\&{to}}\|j-1$ \1\&{do}\6
+\&{begin} \37\&{if} $\|i=\\{loc}$ \1\&{then}\5
+\\{set\_trick\_count};\2\6
+$\\{print}(\\{buffer}[\|i])$;\6
+\&{end}\2\2\par
+\U318.\fi
+
+\M325. \P$\X325:Pseudoprint the token list\X\S$\6
+\\{begin\_pseudoprint};\6
+\&{if} $\\{token\_type}<\\{macro}$ \1\&{then}\6
+\&{begin} \37\&{if} $(\\{token\_type}=\\{backed\_up})\W(\\{loc}\I\\{null})$ \1%
+\&{then}\6
+\&{begin} \37\&{if} $(\\{link}(\\{start})=\\{null})\W(\\{check\_kanji}(%
+\\{info}(\\{start})))$ \1\&{then}\C{\\{wchar\_token}}\6
+\&{begin} \37$\\{cur\_input}\K\\{input\_stack}[\\{base\_ptr}-1]$;\5
+$\|s\K\\{get\_avail}$;\5
+$\\{info}(\|s)\K\\{Lo}(\\{info}(\\{loc}))$;\5
+$\\{cur\_input}\K\\{input\_stack}[\\{base\_ptr}]$;\5
+$\\{link}(\\{start})\K\|s$;\5
+$\\{show\_token\_list}(\\{start},\39\\{loc},\39100000)$;\5
+$\\{free\_avail}(\|s)$;\5
+$\\{link}(\\{start})\K\\{null}$;\5
+\&{goto} \37\\{done1};\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{show\_token\_list}(\\{start},\39\\{loc},\39100000)$;\6
+\&{end}\6
+\4\&{else} $\\{show\_token\_list}(\\{link}(\\{start}),\39\\{loc},\39100000)$;%
+\C{avoid reference count}\2\6
+\4\\{done1}: \37\par
+\U318.\fi
+
+\M326. Here is the missing piece of \\{show\_token\_list} that is activated
+when the
+token beginning line~2 is about to be shown:
+
+\Y\P$\4\X326:Do magic computation\X\S$\6
+\\{set\_trick\_count}\par
+\U298.\fi
+
+\N327.  \[23] Maintaining the input stacks.
+The following subroutines change the input status in commonly needed ways.
+
+First comes \\{push\_input}, which stores the current state and creates a
+new level (having, initially, the same properties as the old).
+
+\Y\P\D \37$\\{push\_input}\S\hbox{}$\C{enter a new input level, save the old}\6
+\&{begin} \37\&{if} $\\{input\_ptr}>\\{max\_in\_stack}$ \1\&{then}\6
+\&{begin} \37$\\{max\_in\_stack}\K\\{input\_ptr}$;\6
+\&{if} $\\{input\_ptr}=\\{stack\_size}$ \1\&{then}\5
+$\\{overflow}(\.{"input\ stack\ size"},\39\\{stack\_size})$;\2\6
+\&{end};\2\6
+$\\{input\_stack}[\\{input\_ptr}]\K\\{cur\_input}$;\C{stack the record}\6
+$\\{incr}(\\{input\_ptr})$;\6
+\&{end}\par
+\fi
+
+\M328. And of course what goes up must come down.
+
+\Y\P\D \37$\\{pop\_input}\S\hbox{}$\C{leave an input level, re-enter the old}\6
+\&{begin} \37$\\{decr}(\\{input\_ptr})$;\5
+$\\{cur\_input}\K\\{input\_stack}[\\{input\_ptr}]$;\6
+\&{end}\par
+\fi
+
+\M329. Here is a procedure that starts a new level of token-list input, given
+a token list \|p and its type \|t. If $\|t=\\{macro}$, the calling routine
+should
+set \\{name} and \\{loc}.
+
+\Y\P\D \37$\\{back\_list}(\#)\S\\{begin\_token\_list}(\#,\39\\{backed\_up})$%
+\C{backs up a simple token list}\par
+\P\D \37$\\{ins\_list}(\#)\S\\{begin\_token\_list}(\#,\39\\{inserted})$%
+\C{inserts a simple token list}\par
+\Y\P\4\&{procedure}\1\  \37$\\{begin\_token\_list}(\|p:\\{pointer};\,\35\|t:%
+\\{quarterword})$;\2\6
+\&{begin} \37\\{push\_input};\5
+$\\{state}\K\\{token\_list}$;\5
+$\\{start}\K\|p$;\5
+$\\{token\_type}\K\|t$;\6
+\&{if} $\|t\G\\{macro}$ \1\&{then}\C{the token list starts with a reference
+count}\6
+\&{begin} \37$\\{add\_token\_ref}(\|p)$;\6
+\&{if} $\|t=\\{macro}$ \1\&{then}\5
+$\\{param\_start}\K\\{param\_ptr}$\6
+\4\&{else} \&{begin} \37$\\{loc}\K\\{link}(\|p)$;\6
+\&{if} $\\{tracing\_macros}>1$ \1\&{then}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{""})$;\6
+\&{case} $\|t$ \1\&{of}\6
+\4\\{mark\_text}: \37$\\{print\_esc}(\.{"mark"})$;\6
+\4\\{write\_text}: \37$\\{print\_esc}(\.{"write"})$;\6
+\4\&{othercases} \37$\\{print\_cmd\_chr}(\\{assign\_toks},\39\|t-\\{output%
+\_text}+\\{output\_routine\_loc})$\2\6
+\&{endcases};\6
+$\\{print}(\.{"->"})$;\5
+$\\{token\_show}(\|p)$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} $\\{loc}\K\|p$;\2\6
+\&{end};\par
+\fi
+
+\M330. When a token list has been fully scanned, the following computations
+should be done as we leave that level of input. The \\{token\_type} tends
+to be equal to either \\{backed\_up} or \\{inserted} about 2/3 of the time.
+
+\Y\P\4\&{procedure}\1\  \37\\{end\_token\_list};\C{leave a token-list input
+level}\2\6
+\&{begin} \37\&{if} $\\{token\_type}\G\\{backed\_up}$ \1\&{then}\C{token list
+to be deleted}\6
+\&{begin} \37\&{if} $\\{token\_type}\L\\{inserted}$ \1\&{then}\5
+$\\{flush\_list}(\\{start})$\6
+\4\&{else} \&{begin} \37$\\{delete\_token\_ref}(\\{start})$;\C{update reference
+count}\6
+\&{if} $\\{token\_type}=\\{macro}$ \1\&{then}\C{parameters must be flushed}\6
+\&{while} $\\{param\_ptr}>\\{param\_start}$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\\{param\_ptr})$;\5
+$\\{flush\_list}(\\{param\_stack}[\\{param\_ptr}])$;\6
+\&{end};\2\2\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{token\_type}=\\{u\_template}$ \1\&{then}\6
+\&{if} $\\{align\_state}>500000$ \1\&{then}\5
+$\\{align\_state}\K0$\6
+\4\&{else} $\\{fatal\_error}(\.{"(interwoven\ alignment\ preambles\ are\ not\
+allowed)"})$;\2\2\2\6
+\\{pop\_input};\5
+\\{check\_interrupt};\6
+\&{end};\par
+\fi
+
+\M331. Sometimes \TeX\ has read too far and wants to ``unscan'' what it has
+seen. The \\{back\_input} procedure takes care of this by putting the token
+just scanned back into the input stream, ready to be read again. This
+procedure can be used only if \\{cur\_tok} represents the token to be
+replaced. Some applications of \TeX\ use this procedure a lot,
+so it has been slightly optimized for speed.
+
+\Y\P\4\&{procedure}\1\  \37\\{back\_input};\C{undoes one token of input}\6
+\4\&{var} \37\|p: \37\\{pointer};\C{a token list of length one}\2\6
+\&{begin} \37\&{while} $(\\{state}=\\{token\_list})\W(\\{loc}=\\{null})\W(%
+\\{token\_type}\I\\{v\_template})$ \1\&{do}\5
+\\{end\_token\_list};\C{conserve stack space}\2\6
+$\|p\K\\{get\_avail}$;\5
+$\\{info}(\|p)\K\\{cur\_tok}$;\6
+\&{if} $\\{cur\_tok}<\\{right\_brace\_limit}$ \1\&{then}\6
+\&{if} $\\{cur\_tok}<\\{left\_brace\_limit}$ \1\&{then}\5
+$\\{decr}(\\{align\_state})$\6
+\4\&{else} $\\{incr}(\\{align\_state})$;\2\2\6
+\\{push\_input};\5
+$\\{state}\K\\{token\_list}$;\5
+$\\{start}\K\|p$;\5
+$\\{token\_type}\K\\{backed\_up}$;\5
+$\\{loc}\K\|p$;\C{that was $\\{back\_list}(\|p)$, without procedure overhead}\6
+\&{end};\par
+\fi
+
+\M332. \P$\X332:Insert token \|p into \TeX's input\X\S$\6
+\&{begin} \37$\|t\K\\{cur\_tok}$;\5
+$\\{cur\_tok}\K\|p$;\5
+\\{back\_input};\5
+$\\{cur\_tok}\K\|t$;\6
+\&{end}\par
+\U288.\fi
+
+\M333. The \\{back\_error} routine is used when we want to replace an offending
+token
+just before issuing an error message. This routine, like \\{back\_input},
+requires that \\{cur\_tok} has been set. We disable interrupts during the
+call of \\{back\_input} so that the help message won't be lost.
+
+\Y\P\4\&{procedure}\1\  \37\\{back\_error};\C{back up one token and call %
+\\{error}}\2\6
+\&{begin} \37$\\{OK\_to\_interrupt}\K\\{false}$;\5
+\\{back\_input};\5
+$\\{OK\_to\_interrupt}\K\\{true}$;\5
+\\{error};\6
+\&{end};\7
+\4\&{procedure}\1\  \37\\{ins\_error};\C{back up one inserted token and call %
+\\{error}}\2\6
+\&{begin} \37$\\{OK\_to\_interrupt}\K\\{false}$;\5
+\\{back\_input};\5
+$\\{token\_type}\K\\{inserted}$;\5
+$\\{OK\_to\_interrupt}\K\\{true}$;\5
+\\{error};\6
+\&{end};\par
+\fi
+
+\M334. The \\{begin\_file\_reading} procedure starts a new level of input for
+lines
+of characters to be read from a file, or as an insertion from the
+terminal. It does not take care of opening the file, nor does it set \\{loc}
+or \\{limit} or \\{line}.
+
+\Y\P\4\&{procedure}\1\  \37\\{begin\_file\_reading};\2\6
+\&{begin} \37\&{if} $\\{in\_open}=\\{max\_in\_open}$ \1\&{then}\5
+$\\{overflow}(\.{"text\ input\ levels"},\39\\{max\_in\_open})$;\2\6
+\&{if} $\\{first}=\\{buf\_size}$ \1\&{then}\5
+$\\{overflow}(\.{"buffer\ size"},\39\\{buf\_size})$;\2\6
+$\\{incr}(\\{in\_open})$;\5
+\\{push\_input};\5
+$\\{index}\K\\{in\_open}$;\5
+$\\{source\_filename\_stack}[\\{index}]\K0$;\5
+$\\{full\_source\_filename\_stack}[\\{index}]\K0$;\5
+$\\{line\_stack}[\\{index}]\K\\{line}$;\5
+$\\{start}\K\\{first}$;\5
+$\\{state}\K\\{mid\_line}$;\5
+$\\{name}\K0$;\C{\\{terminal\_input} is now \\{true}}\6
+\&{end};\par
+\fi
+
+\M335. Conversely, the variables must be downdated when such a level of input
+is finished:
+
+\Y\P\4\&{procedure}\1\  \37\\{end\_file\_reading};\2\6
+\&{begin} \37$\\{first}\K\\{start}$;\5
+$\\{line}\K\\{line\_stack}[\\{index}]$;\6
+\&{if} $\\{name}>17$ \1\&{then}\5
+$\\{a\_close}(\\{cur\_file})$;\C{forget it}\2\6
+\\{pop\_input};\5
+$\\{decr}(\\{in\_open})$;\6
+\&{end};\par
+\fi
+
+\M336. In order to keep the stack from overflowing during a long sequence of
+inserted `\.{\\show}' commands, the following routine removes completed
+error-inserted lines from memory.
+
+\Y\P\4\&{procedure}\1\  \37\\{clear\_for\_error\_prompt};\2\6
+\&{begin} \37\&{while} $(\\{state}\I\\{token\_list})\W\\{terminal\_input}\W\30(%
+\\{input\_ptr}>0)\W(\\{loc}>\\{limit})$ \1\&{do}\5
+\\{end\_file\_reading};\2\6
+\\{print\_ln};\5
+\\{clear\_terminal};\6
+\&{end};\par
+\fi
+
+\M337. To get \TeX's whole input mechanism going, we perform the following
+actions.
+
+\Y\P$\4\X337:Initialize the input routines\X\S$\6
+\&{begin} \37$\\{input\_ptr}\K0$;\5
+$\\{max\_in\_stack}\K0$;\5
+$\\{source\_filename\_stack}[0]\K0$;\5
+$\\{full\_source\_filename\_stack}[0]\K0$;\5
+$\\{in\_open}\K0$;\5
+$\\{open\_parens}\K0$;\5
+$\\{max\_buf\_stack}\K0$;\5
+$\\{param\_ptr}\K0$;\5
+$\\{max\_param\_stack}\K0$;\5
+$\\{first}\K\\{buf\_size}$;\6
+\1\&{repeat} \37$\\{buffer}[\\{first}]\K0$;\5
+$\\{decr}(\\{first})$;\6
+\4\&{until}\5
+$\\{first}=0$;\2\6
+$\\{scanner\_status}\K\\{normal}$;\5
+$\\{warning\_index}\K\\{null}$;\5
+$\\{first}\K1$;\5
+$\\{state}\K\\{new\_line}$;\5
+$\\{start}\K1$;\5
+$\\{index}\K0$;\5
+$\\{line}\K0$;\5
+$\\{name}\K0$;\5
+$\\{force\_eof}\K\\{false}$;\5
+$\\{align\_state}\K1000000$;\6
+\&{if} $\R\\{init\_terminal}$ \1\&{then}\5
+\&{goto} \37\\{final\_end};\2\6
+$\\{limit}\K\\{last}$;\5
+$\\{first}\K\\{last}+1$;\C{\\{init\_terminal} has set \\{loc} and \\{last}}\6
+\&{end}\par
+\U1350.\fi
+
+\N338.  \[24] Getting the next token.
+The heart of \TeX's input mechanism is the \\{get\_next} procedure, which
+we shall develop in the next few sections of the program. Perhaps we
+shouldn't actually call it the ``heart,'' however, because it really acts
+as \TeX's eyes and mouth, reading the source files and gobbling them up.
+And it also helps \TeX\ to regurgitate stored token lists that are to be
+processed again.
+
+The main duty of \\{get\_next} is to input one token and to set \\{cur\_cmd}
+and \\{cur\_chr} to that token's command code and modifier. Furthermore, if
+the input token is a control sequence, the \\{eqtb} location of that control
+sequence is stored in \\{cur\_cs}; otherwise \\{cur\_cs} is set to zero.
+
+Underlying this simple description is a certain amount of complexity
+because of all the cases that need to be handled.
+However, the inner loop of \\{get\_next} is reasonably short and fast.
+
+When \\{get\_next} is asked to get the next token of a \.{\\read} line,
+it sets $\\{cur\_cmd}=\\{cur\_chr}=\\{cur\_cs}=0$ in the case that no more
+tokens
+appear on that line. (There might not be any tokens at all, if the
+\\{end\_line\_char} has \\{ignore} as its catcode.)
+
+\fi
+
+\M339. The value of \\{par\_loc} is the \\{eqtb} address of `\.{\\par}'. This
+quantity
+is needed because a blank line of input is supposed to be exactly equivalent
+to the appearance of \.{\\par}; we must set $\\{cur\_cs}\K\\{par\_loc}$
+when detecting a blank line.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{par\_loc}: \37\\{pointer};\C{location of `\.{\\par}' in \\{eqtb}}\6
+\4\\{par\_token}: \37\\{halfword};\C{token representing `\.{\\par}'}\par
+\fi
+
+\M340. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"par"},\39\\{par\_end},\39256)$;\C{cf.\ \\{scan\_file\_name}}%
+\6
+$\\{par\_loc}\K\\{cur\_val}$;\5
+$\\{par\_token}\K\\{cs\_token\_flag}+\\{par\_loc}$;\par
+\fi
+
+\M341. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{par\_end}: \37$\\{print\_esc}(\.{"par"})$;\par
+\fi
+
+\M342. Before getting into \\{get\_next}, let's consider the subroutine that
+is called when an `\.{\\outer}' control sequence has been scanned or
+when the end of a file has been reached. These two cases are distinguished
+by \\{cur\_cs}, which is zero at the end of a file.
+
+\Y\P\4\&{procedure}\1\  \37\\{check\_outer\_validity};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{points to inserted token list}\6
+\|q: \37\\{pointer};\C{auxiliary pointer}\2\6
+\&{begin} \37\&{if} $\\{scanner\_status}\I\\{normal}$ \1\&{then}\6
+\&{begin} \37$\\{deletions\_allowed}\K\\{false}$;\5
+\X343:Back up an outer control sequence so that it can be reread\X;\6
+\&{if} $\\{scanner\_status}>\\{skipping}$ \1\&{then}\5
+\X344:Tell the user what has run away and try to recover\X\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Incomplete\ "})$;\5
+$\\{print\_cmd\_chr}(\\{if\_test},\39\\{cur\_if})$;\5
+$\\{print}(\.{";\ all\ text\ was\ ignored\ after\ line\ "})$;\5
+$\\{print\_int}(\\{skip\_line})$;\5
+$\\{help3}(\.{"A\ forbidden\ control\ sequence\ occurred\ in\ skipped\
+text."})$\6
+$(\.{"This\ kind\ of\ error\ happens\ when\ you\ say\ \`\\if...\'\ and\
+forget"})$\6
+$(\.{"the\ matching\ \`\\fi\'.\ I\'ve\ inserted\ a\ \`\\fi\';\ this\ might\
+work."})$;\6
+\&{if} $\\{cur\_cs}\I0$ \1\&{then}\5
+$\\{cur\_cs}\K0$\6
+\4\&{else} $\\{help\_line}[2]\K\30\.{"The\ file\ ended\ while\ I\ was\ skipping%
+\ conditional\ text."}$;\2\6
+$\\{cur\_tok}\K\\{cs\_token\_flag}+\\{frozen\_fi}$;\5
+\\{ins\_error};\6
+\&{end};\2\6
+$\\{deletions\_allowed}\K\\{true}$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M343. An outer control sequence that occurs in a \.{\\read} will not be
+reread,
+since the error recovery for \.{\\read} is not very powerful.
+
+\Y\P$\4\X343:Back up an outer control sequence so that it can be reread\X\S$\6
+\&{if} $\\{cur\_cs}\I0$ \1\&{then}\6
+\&{begin} \37\&{if} $(\\{state}=\\{token\_list})\V(\\{name}<1)\V(\\{name}>17)$ %
+\1\&{then}\6
+\&{begin} \37$\|p\K\\{get\_avail}$;\5
+$\\{info}(\|p)\K\\{cs\_token\_flag}+\\{cur\_cs}$;\5
+$\\{back\_list}(\|p)$;\C{prepare to read the control sequence again}\6
+\&{end};\2\6
+$\\{cur\_cmd}\K\\{spacer}$;\5
+$\\{cur\_chr}\K\.{"\ "}$;\C{replace it by a space}\6
+\&{end}\2\par
+\U342.\fi
+
+\M344. \P$\X344:Tell the user what has run away and try to recover\X\S$\6
+\&{begin} \37\\{runaway};\C{print a definition, argument, or preamble}\6
+\&{if} $\\{cur\_cs}=0$ \1\&{then}\5
+$\\{print\_err}(\.{"File\ ended"})$\6
+\4\&{else} \&{begin} \37$\\{cur\_cs}\K0$;\5
+$\\{print\_err}(\.{"Forbidden\ control\ sequence\ found"})$;\6
+\&{end};\2\6
+\X345:Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `%
+\.{text}', and insert tokens that should lead to recovery\X;\6
+$\\{print}(\.{"\ of\ "})$;\5
+$\\{sprint\_cs}(\\{warning\_index})$;\5
+$\\{help4}(\.{"I\ suspect\ you\ have\ forgotten\ a\ \`\}\',\ causing\ me"})$\6
+$(\.{"to\ read\ past\ where\ you\ wanted\ me\ to\ stop."})$\6
+$(\.{"I\'ll\ try\ to\ recover;\ but\ if\ the\ error\ is\ serious,"})$\6
+$(\.{"you\'d\ better\ type\ \`E\'\ or\ \`X\'\ now\ and\ fix\ your\ file."})$;\6
+\\{error};\6
+\&{end}\par
+\U342.\fi
+
+\M345. The recovery procedure can't be fully understood without knowing more
+about the \TeX\ routines that should be aborted, but we can sketch the
+ideas here:  For a runaway definition we will insert a right brace; for a
+runaway preamble, we will insert a special \.{\\cr} token and a right
+brace; and for a runaway argument, we will set \\{long\_state} to
+\\{outer\_call} and insert \.{\\par}.
+
+\Y\P$\4\X345:Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `%
+\.{text}', and insert tokens that should lead to recovery\X\S$\6
+$\|p\K\\{get\_avail}$;\6
+\&{case} $\\{scanner\_status}$ \1\&{of}\6
+\4\\{defining}: \37\&{begin} \37$\\{print}(\.{"\ while\ scanning\
+definition"})$;\5
+$\\{info}(\|p)\K\\{right\_brace\_token}+\.{"\}"}$;\6
+\&{end};\6
+\4\\{matching}: \37\&{begin} \37$\\{print}(\.{"\ while\ scanning\ use"})$;\5
+$\\{info}(\|p)\K\\{par\_token}$;\5
+$\\{long\_state}\K\\{outer\_call}$;\6
+\&{end};\6
+\4\\{aligning}: \37\&{begin} \37$\\{print}(\.{"\ while\ scanning\ preamble"})$;%
+\5
+$\\{info}(\|p)\K\\{right\_brace\_token}+\.{"\}"}$;\5
+$\|q\K\|p$;\5
+$\|p\K\\{get\_avail}$;\5
+$\\{link}(\|p)\K\|q$;\5
+$\\{info}(\|p)\K\\{cs\_token\_flag}+\\{frozen\_cr}$;\5
+$\\{align\_state}\K-1000000$;\6
+\&{end};\6
+\4\\{absorbing}: \37\&{begin} \37$\\{print}(\.{"\ while\ scanning\ text"})$;\5
+$\\{info}(\|p)\K\\{right\_brace\_token}+\.{"\}"}$;\6
+\&{end};\2\6
+\&{end};\C{there are no other cases}\6
+$\\{ins\_list}(\|p)$\par
+\U344.\fi
+
+\M346. We need to mention a procedure here that may be called by \\{get\_next}.
+
+\Y\P\4\&{procedure}\1\  \37\\{firm\_up\_the\_line};\5
+\\{forward};\par
+\fi
+
+\M347. Now we're ready to take the plunge into \\{get\_next} itself. Parts of
+this routine are executed more often than any other instructions of \TeX.
+
+\Y\P\D \37$\\{switch}=25$\C{a label in \\{get\_next}}\par
+\P\D \37$\\{start\_cs}=26$\C{another}\par
+\Y\P\4\&{procedure}\1\  \37\\{get\_next};\C{sets \\{cur\_cmd}, \\{cur\_chr}, %
+\\{cur\_cs} to next token}\6
+\4\&{label} \37$\\{restart},\39$\C{go here to get the next input token}\6
+$\\{switch},\39$\C{go here to eat the next character from a file}\6
+$\\{reswitch},\39$\C{go here to digest it again}\6
+$\\{start\_cs},\39$\C{go here to start looking for a control sequence}\6
+$\\{found},\39$\C{go here when a control sequence has been found}\6
+\\{exit};\C{go here when the next input token has been got}\6
+\4\&{var} \37\|k: \37$0\to\\{buf\_size}$;\C{an index into \\{buffer}}\6
+\|t: \37\\{halfword};\C{a token}\6
+\\{cat}: \37$\\{escape}\to\\{max\_char\_code}$;\C{$\\{cat\_code}(\\{cur%
+\_chr})$, usually}\6
+\|l: \37$0\to\\{buf\_size}$;\C{temporary index into \\{buffer}}\6
+$\|c,\39\\{cc}$: \37\\{ASCII\_code};\C{constituents of a possible expanded
+code}\6
+\|d: \37$2\to3$;\C{number of excess characters in an expanded code}\2\6
+\&{begin} \37\\{restart}: \37$\\{cur\_cs}\K0$;\6
+\&{if} $\\{state}\I\\{token\_list}$ \1\&{then}\5
+\X349:Input from external file, \&{goto} \\{restart} if no input found\X\6
+\4\&{else} \X365:Input from token list, \&{goto} \\{restart} if end of list or
+if a parameter needs to be expanded\X;\2\6
+\X348:If an alignment entry has just ended, take appropriate action\X;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M348. An alignment entry ends when a tab or \.{\\cr} occurs, provided that the
+current level of braces is the same as the level that was present at the
+beginning of that alignment entry; i.e., provided that \\{align\_state} has
+returned to the value it had after the \<u_j> template for that entry.
+
+\Y\P$\4\X348:If an alignment entry has just ended, take appropriate action\X\S$%
+\6
+\&{if} $\\{cur\_cmd}\L\\{car\_ret}$ \1\&{then}\6
+\&{if} $\\{cur\_cmd}\G\\{tab\_mark}$ \1\&{then}\6
+\&{if} $\\{align\_state}=0$ \1\&{then}\5
+\X800:Insert the \(v)\<v_j> template and \&{goto} \\{restart}\X\2\2\2\par
+\U347.\fi
+
+\M349. \P$\X349:Input from external file, \&{goto} \\{restart} if no input
+found\X\S$\6
+\&{begin} \37\\{switch}: \37\&{if} $\\{loc}\L\\{limit}$ \1\&{then}\C{current
+line not yet finished}\6
+\&{begin} \37$\\{cur\_chr}\K\\{buffer}[\\{loc}]$;\5
+$\\{incr}(\\{loc})$;\6
+\&{if} $\\{multistrlen}(\\{ustringcast}(\\{buffer}),\39\\{limit}+1,\39%
+\\{loc}-1)=2$ \1\&{then}\6
+\&{begin} \37$\\{cur\_chr}\K\\{fromBUFF}(\\{ustringcast}(\\{buffer}),\39%
+\\{limit}+1,\39\\{loc}-1)$;\5
+$\\{cur\_cmd}\K\\{kcat\_code}(\\{kcatcodekey}(\\{cur\_chr}))$;\5
+$\\{incr}(\\{loc})$;\6
+\&{end}\6
+\4\&{else} \\{reswitch}: \37$\\{cur\_cmd}\K\\{cat\_code}(\\{cur\_chr})$;\2\6
+\X350:Change state if necessary, and \&{goto} \\{switch} if the current
+character should be ignored, or \&{goto} \\{reswitch} if the current character
+changes to another\X;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{state}\K\\{new\_line}$;\6
+\X368:Move to next line of file, or \&{goto} \\{restart} if there is no next
+line, or \&{return} if a \.{\\read} line has finished\X;\6
+\\{check\_interrupt};\5
+\&{goto} \37\\{switch};\6
+\&{end};\2\6
+\&{end}\par
+\U347.\fi
+
+\M350. The following 48-way switch accomplishes the scanning quickly, assuming
+that a decent \PASCAL\ compiler has translated the code. Note that the numeric
+values for \\{mid\_line}, \\{skip\_blanks}, and \\{new\_line} are spaced
+apart from each other by $\\{max\_char\_code}+1$, so we can add a character's
+command code to the state to get a single number that characterizes both.
+
+\Y\P\D \37$\\{any\_state\_plus}(\#)\S\\{mid\_line}+\#,\39\\{mid\_kanji}+\#,\39%
+\\{skip\_blanks}+\#,\39\\{new\_line}+\#$\par
+\Y\P$\4\X350:Change state if necessary, and \&{goto} \\{switch} if the current
+character should be ignored, or \&{goto} \\{reswitch} if the current character
+changes to another\X\S$\6
+\&{case} $\\{state}+\\{cur\_cmd}$ \1\&{of}\6
+\4\X351:Cases where character is ignored\X: \37\&{goto} \37\\{switch};\6
+\4$\\{any\_state\_plus}(\\{escape})$: \37\X362:Scan a control sequence and set
+$\\{state}\K\\{skip\_blanks}$ or \\{mid\_line}\X;\6
+\4$\\{any\_state\_plus}(\\{active\_char})$: \37\X361:Process an
+active-character control sequence and set $\\{state}\K\\{mid\_line}$\X;\6
+\4$\\{any\_state\_plus}(\\{sup\_mark})$: \37\X360:If this \\{sup\_mark} starts
+an expanded character like~\.{\^\^A} or~\.{\^\^df}, then \&{goto} \\{reswitch},
+otherwise set $\\{state}\K\\{mid\_line}$\X;\6
+\4$\\{any\_state\_plus}(\\{invalid\_char})$: \37\X352:Decry the invalid
+character and \&{goto} \\{restart}\X;\6
+\hbox{\4}\X353:Handle situations involving spaces, braces, changes of state\X\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases}\par
+\U349.\fi
+
+\M351. \P$\X351:Cases where character is ignored\X\S$\6
+$\\{any\_state\_plus}(\\{ignore}),\39\\{skip\_blanks}+\\{spacer},\39\\{new%
+\_line}+\\{spacer}$\par
+\U350.\fi
+
+\M352. We go to \\{restart} instead of to \\{switch}, because \\{state} might
+equal
+\\{token\_list} after the error has been dealt with
+(cf.\ \\{clear\_for\_error\_prompt}).
+
+\Y\P$\4\X352:Decry the invalid character and \&{goto} \\{restart}\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Text\ line\ contains\ an\ invalid\
+character"})$;\5
+$\\{help2}(\.{"A\ funny\ symbol\ that\ I\ can\'t\ read\ has\ just\ been\
+input."})$\6
+$(\.{"Continue,\ and\ I\'ll\ forget\ that\ it\ ever\ happened."})$;\6
+$\\{deletions\_allowed}\K\\{false}$;\5
+\\{error};\5
+$\\{deletions\_allowed}\K\\{true}$;\5
+\&{goto} \37\\{restart};\6
+\&{end}\par
+\U350.\fi
+
+\M353. \P\D \37$\\{add\_delims\_to}(\#)\S\#+\\{math\_shift},\39\#+\\{tab%
+\_mark},\39\#+\\{mac\_param},\39\#+\\{sub\_mark},\39\#+\\{letter},\39\#+%
+\\{other\_char}$\par
+\P\D \37$\\{all\_jcode}(\#)\S\#+\\{kanji},\39\#+\\{kana},\39\#+\\{other%
+\_kchar}$\par
+\Y\P$\4\X353:Handle situations involving spaces, braces, changes of state\X\S$\6
+\4$\\{mid\_kanji}+\\{spacer},\39\\{mid\_line}+\\{spacer}$: \37\X357:Enter %
+\\{skip\_blanks} state, emit a space\X;\6
+\4$\\{mid\_line}+\\{car\_ret}$: \37\X356:Finish line, emit a space\X;\6
+\4$\\{mid\_kanji}+\\{car\_ret}$: \37\&{if} $\\{skip\_mode}$ \1\&{then}\5
+\X358:Finish line, \&{goto} \\{switch}\X\6
+\4\&{else} \X356:Finish line, emit a space\X;\2\6
+\4$\\{skip\_blanks}+\\{car\_ret},\39\\{any\_state\_plus}(\\{comment})$: \37%
+\X358:Finish line, \&{goto} \\{switch}\X;\6
+\4$\\{new\_line}+\\{car\_ret}$: \37\X359:Finish line, emit a \.{\\par}\X;\6
+\4$\\{mid\_line}+\\{left\_brace},\39\\{mid\_kanji}+\\{left\_brace}$: \37$%
+\\{incr}(\\{align\_state})$;\6
+\4$\\{skip\_blanks}+\\{left\_brace},\39\\{new\_line}+\\{left\_brace}$: \37%
+\&{begin} \37$\\{state}\K\\{mid\_line}$;\5
+$\\{incr}(\\{align\_state})$;\6
+\&{end};\6
+\4$\\{mid\_line}+\\{right\_brace},\39\\{mid\_kanji}+\\{right\_brace}$: \37$%
+\\{decr}(\\{align\_state})$;\6
+\4$\\{skip\_blanks}+\\{right\_brace},\39\\{new\_line}+\\{right\_brace}$: \37%
+\&{begin} \37$\\{state}\K\\{mid\_line}$;\5
+$\\{decr}(\\{align\_state})$;\6
+\&{end};\6
+\4$\\{add\_delims\_to}(\\{skip\_blanks}),\39\\{add\_delims\_to}(\\{new\_line}),%
+\39\\{add\_delims\_to}(\\{mid\_kanji})$: \37$\\{state}\K\\{mid\_line}$;\6
+\4$\\{all\_jcode}(\\{skip\_blanks}),\39\\{all\_jcode}(\\{new\_line}),\39\\{all%
+\_jcode}(\\{mid\_line})$: \37$\\{state}\K\\{mid\_kanji}$;\par
+\U350.\fi
+
+\M354. \P$\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{skip\_mode}: \37\\{boolean};\par
+\fi
+
+\M355. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{skip\_mode}\K\\{true}$;\par
+\fi
+
+\M356. When a character of type \\{spacer} gets through, its character code is
+changed to $\.{"\ "}=\O{40}$. This means that the ASCII codes for tab and
+space,
+and for the space inserted at the end of a line, will
+be treated alike when macro parameters are being matched. We do this
+since such characters are indistinguishable on most computer terminal displays.
+
+\Y\P$\4\X356:Finish line, emit a space\X\S$\6
+\&{begin} \37$\\{loc}\K\\{limit}+1$;\5
+$\\{cur\_cmd}\K\\{spacer}$;\5
+$\\{cur\_chr}\K\.{"\ "}$;\6
+\&{end}\par
+\Us353\ET353.\fi
+
+\M357. The following code is performed only when $\\{cur\_cmd}=\\{spacer}$.
+
+\Y\P$\4\X357:Enter \\{skip\_blanks} state, emit a space\X\S$\6
+\&{begin} \37$\\{state}\K\\{skip\_blanks}$;\5
+$\\{cur\_chr}\K\.{"\ "}$;\6
+\&{end}\par
+\U353.\fi
+
+\M358. \P$\X358:Finish line, \&{goto} \\{switch}\X\S$\6
+\&{begin} \37$\\{loc}\K\\{limit}+1$;\5
+\&{goto} \37\\{switch};\6
+\&{end}\par
+\Us353\ET353.\fi
+
+\M359. \P$\X359:Finish line, emit a \.{\\par}\X\S$\6
+\&{begin} \37$\\{loc}\K\\{limit}+1$;\5
+$\\{cur\_cs}\K\\{par\_loc}$;\5
+$\\{cur\_cmd}\K\\{eq\_type}(\\{cur\_cs})$;\5
+$\\{cur\_chr}\K\\{equiv}(\\{cur\_cs})$;\6
+\&{if} $\\{cur\_cmd}\G\\{outer\_call}$ \1\&{then}\5
+\\{check\_outer\_validity};\2\6
+\&{end}\par
+\U353.\fi
+
+\M360. Notice that a code like \.{\^\^8} becomes \.x if not followed by a hex
+digit.
+
+\Y\P\D \37$\\{is\_hex}(\#)\S(((\#\G\.{"0"})\W(\#\L\.{"9"}))\V((\#\G\.{"a"})\W(%
+\#\L\.{"f"})))$\par
+\P\D \37$\\{hex\_to\_cur\_chr}\S$\1\6
+\&{if} $\|c\L\.{"9"}$ \1\&{then}\5
+$\\{cur\_chr}\K\|c-\.{"0"}$\ \&{else} $\\{cur\_chr}\K\|c-\.{"a"}+10$;\2\2\6
+\&{if} $\\{cc}\L\.{"9"}$ \1\&{then}\5
+$\\{cur\_chr}\K16\ast\\{cur\_chr}+\\{cc}-\.{"0"}$\6
+\4\&{else} $\\{cur\_chr}\K16\ast\\{cur\_chr}+\\{cc}-\.{"a"}+10$\2\par
+\Y\P$\4\X360:If this \\{sup\_mark} starts an expanded character like~\.{\^\^A}
+or~\.{\^\^df}, then \&{goto} \\{reswitch}, otherwise set $\\{state}\K\\{mid%
+\_line}$\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_chr}=\\{buffer}[\\{loc}]$ \1\&{then}\6
+\&{if} $\\{loc}<\\{limit}$ \1\&{then}\6
+\&{begin} \37$\|c\K\\{buffer}[\\{loc}+1]$;\ \&{if} $\|c<\O{200}$ \1\&{then}%
+\C{yes we have an expanded char}\6
+\&{begin} \37$\\{loc}\K\\{loc}+2$;\6
+\&{if} $\\{is\_hex}(\|c)$ \1\&{then}\6
+\&{if} $\\{loc}\L\\{limit}$ \1\&{then}\6
+\&{begin} \37$\\{cc}\K\\{buffer}[\\{loc}]$;\ \&{if} $\\{is\_hex}(\\{cc})$ \1%
+\&{then}\6
+\&{begin} \37$\\{incr}(\\{loc})$;\5
+\\{hex\_to\_cur\_chr};\5
+\&{goto} \37\\{reswitch};\6
+\&{end};\2\6
+\&{end};\2\2\6
+\&{if} $\|c<\O{100}$ \1\&{then}\5
+$\\{cur\_chr}\K\|c+\O{100}$\ \&{else} $\\{cur\_chr}\K\|c-\O{100}$;\2\6
+\&{goto} \37\\{reswitch};\6
+\&{end};\2\6
+\&{end};\2\2\6
+$\\{state}\K\\{mid\_line}$;\6
+\&{end}\par
+\U350.\fi
+
+\M361. \P$\X361:Process an active-character control sequence and set $\\{state}%
+\K\\{mid\_line}$\X\S$\6
+\&{begin} \37$\\{cur\_cs}\K\\{cur\_chr}+\\{active\_base}$;\5
+$\\{cur\_cmd}\K\\{eq\_type}(\\{cur\_cs})$;\5
+$\\{cur\_chr}\K\\{equiv}(\\{cur\_cs})$;\5
+$\\{state}\K\\{mid\_line}$;\6
+\&{if} $\\{cur\_cmd}\G\\{outer\_call}$ \1\&{then}\5
+\\{check\_outer\_validity};\2\6
+\&{end}\par
+\U350.\fi
+
+\M362. Control sequence names are scanned only when they appear in some line of
+a file; once they have been scanned the first time, their \\{eqtb} location
+serves as a unique identification, so \TeX\ doesn't need to refer to the
+original name any more except when it prints the equivalent in symbolic form.
+
+The program that scans a control sequence has been written carefully
+in order to avoid the blowups that might otherwise occur if a malicious
+user tried something like `\.{\\catcode\'15=0}'. The algorithm might
+look at $\\{buffer}[\\{limit}+1]$, but it never looks at $\\{buffer}[%
+\\{limit}+2]$.
+
+If expanded characters like `\.{\^\^A}' or `\.{\^\^df}'
+appear in or just following
+a control sequence name, they are converted to single characters in the
+buffer and the process is repeated, slowly but surely.
+
+\Y\P$\4\X362:Scan a control sequence and set $\\{state}\K\\{skip\_blanks}$ or %
+\\{mid\_line}\X\S$\6
+\&{begin} \37\&{if} $\\{loc}>\\{limit}$ \1\&{then}\5
+$\\{cur\_cs}\K\\{null\_cs}$\C{\\{state} is irrelevant in this case}\6
+\4\&{else} \&{begin} \37$\|k\K\\{loc}$;\5
+$\\{cur\_chr}\K\\{buffer}[\|k]$;\5
+$\\{incr}(\|k)$;\6
+\&{if} $\\{multistrlen}(\\{ustringcast}(\\{buffer}),\39\\{limit}+1,\39\|k-1)=2$
+\1\&{then}\6
+\&{begin} \37$\\{cat}\K\\{kcat\_code}(\\{kcatcodekey}(\\{fromBUFF}(%
+\\{ustringcast}(\\{buffer}),\39\\{limit}+1,\39\|k-1)))$;\5
+$\\{incr}(\|k)$;\6
+\&{end}\6
+\4\&{else} $\\{cat}\K\\{cat\_code}(\\{cur\_chr})$;\2\6
+\4\\{start\_cs}: \37\&{if} $(\\{cat}=\\{letter})\V(\\{cat}=\\{kanji})\V(%
+\\{cat}=\\{kana})$ \1\&{then}\5
+$\\{state}\K\\{skip\_blanks}$\6
+\4\&{else} \&{if} $\\{cat}=\\{spacer}$ \1\&{then}\5
+$\\{state}\K\\{skip\_blanks}$\6
+\4\&{else} $\\{state}\K\\{mid\_line}$;\2\2\6
+\&{if} $\\{cat}=\\{other\_kchar}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_cs}\K\\{id\_lookup}(\\{loc},\39\|k-\\{loc})$;\5
+$\\{loc}\K\|k$;\5
+\&{goto} \37\\{found};\6
+\&{end}\6
+\4\&{else} \&{if} $((\\{cat}=\\{letter})\V(\\{cat}=\\{kanji})\V(\\{cat}=%
+\\{kana}))\W(\|k\L\\{limit})$ \1\&{then}\5
+\X364:Scan ahead in the buffer until finding a nonletter; if an expanded code
+is encountered, reduce it and \&{goto} \\{start\_cs}; otherwise if a
+multiletter control sequence is found, adjust \\{cur\_cs} and \\{loc}, and %
+\&{goto} \\{found}\X\6
+\4\&{else} \X363:If an expanded code is present, reduce it and \&{goto} %
+\\{start\_cs}\X;\2\2\6
+$\\{cur\_cs}\K\\{single\_base}+\\{buffer}[\\{loc}]$;\5
+$\\{incr}(\\{loc})$;\6
+\&{end};\2\6
+\4\\{found}: \37$\\{cur\_cmd}\K\\{eq\_type}(\\{cur\_cs})$;\5
+$\\{cur\_chr}\K\\{equiv}(\\{cur\_cs})$;\6
+\&{if} $\\{cur\_cmd}\G\\{outer\_call}$ \1\&{then}\5
+\\{check\_outer\_validity};\2\6
+\&{end}\par
+\U350.\fi
+
+\M363. Whenever we reach the following piece of code, we will have
+$\\{cur\_chr}=\\{buffer}[\|k-1]$ and $\|k\L\\{limit}+1$ and $\\{cat}=\\{cat%
+\_code}(\\{cur\_chr})$. If an
+expanded code like \.{\^\^A} or \.{\^\^df} appears in $\\{buffer}[(\|k-1)\to(%
+\|k+1)]$
+or $\\{buffer}[(\|k-1)\to(\|k+2)]$, we
+will store the corresponding code in $\\{buffer}[\|k-1]$ and shift the rest of
+the buffer left two or three places.
+
+\Y\P$\4\X363:If an expanded code is present, reduce it and \&{goto} \\{start%
+\_cs}\X\S$\6
+\&{begin} \37\&{if} $\\{buffer}[\|k]=\\{cur\_chr}$ \1\&{then}\ \&{if} $\\{cat}=%
+\\{sup\_mark}$ \1\&{then}\ \&{if} $\|k<\\{limit}$ \1\&{then}\6
+\&{begin} \37$\|c\K\\{buffer}[\|k+1]$;\ \&{if} $\|c<\O{200}$ \1\&{then}\C{yes,
+one is indeed present}\6
+\&{begin} \37$\|d\K2$;\6
+\&{if} $\\{is\_hex}(\|c)$ \1\&{then}\ \&{if} $\|k+2\L\\{limit}$ \1\&{then}\6
+\&{begin} \37$\\{cc}\K\\{buffer}[\|k+2]$;\ \&{if} $\\{is\_hex}(\\{cc})$ \1%
+\&{then}\5
+$\\{incr}(\|d)$;\2\6
+\&{end};\2\2\6
+\&{if} $\|d>2$ \1\&{then}\6
+\&{begin} \37\\{hex\_to\_cur\_chr};\5
+$\\{buffer}[\|k-1]\K\\{cur\_chr}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|c<\O{100}$ \1\&{then}\5
+$\\{buffer}[\|k-1]\K\|c+\O{100}$\6
+\4\&{else} $\\{buffer}[\|k-1]\K\|c-\O{100}$;\2\2\6
+$\\{limit}\K\\{limit}-\|d$;\5
+$\\{first}\K\\{first}-\|d$;\5
+$\|l\K\|k$;\5
+$\\{cur\_chr}\K\\{buffer}[\|k-1]$;\5
+$\\{cat}\K\\{cat\_code}(\\{cur\_chr})$;\6
+\&{while} $\|l\L\\{limit}$ \1\&{do}\6
+\&{begin} \37$\\{buffer}[\|l]\K\\{buffer}[\|l+\|d]$;\5
+$\\{incr}(\|l)$;\6
+\&{end};\2\6
+\&{goto} \37\\{start\_cs};\6
+\&{end};\2\6
+\&{end};\2\2\2\6
+\&{end}\par
+\U362.\fi
+
+\M364. \P$\X364:Scan ahead in the buffer until finding a nonletter; if an
+expanded code is encountered, reduce it and \&{goto} \\{start\_cs}; otherwise
+if a multiletter control sequence is found, adjust \\{cur\_cs} and \\{loc}, and
+\&{goto} \\{found}\X\S$\6
+\&{begin} \37\1\&{repeat} \37$\\{cur\_chr}\K\\{buffer}[\|k]$;\5
+$\\{incr}(\|k)$;\6
+\&{if} $\\{multistrlen}(\\{ustringcast}(\\{buffer}),\39\\{limit}+1,\39\|k-1)=2$
+\1\&{then}\6
+\&{begin} \37$\\{cat}\K\\{kcat\_code}(\\{kcatcodekey}(\\{fromBUFF}(%
+\\{ustringcast}(\\{buffer}),\39\\{limit}+1,\39\|k-1)))$;\5
+$\\{incr}(\|k)$;\6
+\&{end}\6
+\4\&{else} $\\{cat}\K\\{cat\_code}(\\{cur\_chr})$;\2\6
+\&{while} $(\\{buffer}[\|k]=\\{cur\_chr})\W(\\{cat}=\\{sup\_mark})\W(\|k<%
+\\{limit})$ \1\&{do}\6
+\&{begin} \37$\|c\K\\{buffer}[\|k+1]$;\ \&{if} $\|c<\O{200}$ \1\&{then}\C{yes,
+one is indeed present}\6
+\&{begin} \37$\|d\K2$;\6
+\&{if} $\\{is\_hex}(\|c)$ \1\&{then}\ \&{if} $\|k+2\L\\{limit}$ \1\&{then}\6
+\&{begin} \37$\\{cc}\K\\{buffer}[\|k+2]$;\ \&{if} $\\{is\_hex}(\\{cc})$ \1%
+\&{then}\5
+$\\{incr}(\|d)$;\2\6
+\&{end};\2\2\6
+\&{if} $\|d>2$ \1\&{then}\6
+\&{begin} \37\\{hex\_to\_cur\_chr};\6
+\&{end}\6
+\4\&{else} \&{if} $\|c<\O{100}$ \1\&{then}\5
+$\\{cur\_chr}\K\|c+\O{100}$\6
+\4\&{else} $\\{cur\_chr}\K\|c-\O{100}$;\2\2\6
+$\\{cat}\K\\{cat\_code}(\\{cur\_chr})$;\6
+\&{if} $(\\{cat}=\\{letter})\V(\\{cat}=\\{sup\_mark})$ \1\&{then}\6
+\&{begin} \37$\\{buffer}[\|k-1]\K\\{cur\_chr}$;\5
+$\\{limit}\K\\{limit}-\|d$;\5
+$\\{first}\K\\{first}-\|d$;\5
+$\|l\K\|k$;\6
+\&{while} $\|l\L\\{limit}$ \1\&{do}\6
+\&{begin} \37$\\{buffer}[\|l]\K\\{buffer}[\|l+\|d]$;\5
+$\\{incr}(\|l)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\2\6
+\4\&{until}\5
+$\R((\\{cat}=\\{letter})\V(\\{cat}=\\{kanji})\V(\\{cat}=\\{kana}))\V(\|k>%
+\\{limit})$;\C{@<If an expanded...@>;}\2\6
+\&{if} $\R((\\{cat}=\\{letter})\V(\\{cat}=\\{kanji})\V(\\{cat}=\\{kana}))$ \1%
+\&{then}\5
+$\\{decr}(\|k)$;\2\6
+\&{if} $\\{cat}=\\{other\_kchar}$ \1\&{then}\5
+$\\{decr}(\|k)$;\C{now \|k points to first nonletter}\2\6
+\&{if} $\|k>\\{loc}+1$ \1\&{then}\C{multiletter control sequence has been
+scanned}\6
+\&{begin} \37$\\{cur\_cs}\K\\{id\_lookup}(\\{loc},\39\|k-\\{loc})$;\5
+$\\{loc}\K\|k$;\5
+\&{goto} \37\\{found};\6
+\&{end};\2\6
+\&{end}\par
+\U362.\fi
+
+\M365. Let's consider now what happens when \\{get\_next} is looking at a token
+list.
+
+\Y\P$\4\X365:Input from token list, \&{goto} \\{restart} if end of list or if a
+parameter needs to be expanded\X\S$\6
+\&{if} $\\{loc}\I\\{null}$ \1\&{then}\C{list not exhausted}\6
+\&{begin} \37$\|t\K\\{info}(\\{loc})$;\5
+$\\{loc}\K\\{link}(\\{loc})$;\C{move to next}\6
+\&{if} $\|t\G\\{cs\_token\_flag}$ \1\&{then}\C{a control sequence token}\6
+\&{begin} \37$\\{cur\_cs}\K\|t-\\{cs\_token\_flag}$;\5
+$\\{cur\_cmd}\K\\{eq\_type}(\\{cur\_cs})$;\5
+$\\{cur\_chr}\K\\{equiv}(\\{cur\_cs})$;\6
+\&{if} $\\{cur\_cmd}\G\\{outer\_call}$ \1\&{then}\6
+\&{if} $\\{cur\_cmd}=\\{dont\_expand}$ \1\&{then}\5
+\X366:Get the next token, suppressing expansion\X\6
+\4\&{else} \\{check\_outer\_validity};\2\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{check\_kanji}(\|t)$ \1\&{then}\C{\\{wchar\_token}}\6
+\&{begin} \37$\\{cur\_chr}\K\|t$;\5
+$\\{cur\_cmd}\K\\{kcat\_code}(\\{kcatcodekey}(\|t))$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{cur\_cmd}\K\\{Hi}(\|t)$;\5
+$\\{cur\_chr}\K\\{Lo}(\|t)$;\6
+\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\4\\{left\_brace}: \37$\\{incr}(\\{align\_state})$;\6
+\4\\{right\_brace}: \37$\\{decr}(\\{align\_state})$;\6
+\4\\{out\_param}: \37\X367:Insert macro parameter and \&{goto} \\{restart}\X;\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\6
+\&{end};\2\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\C{we are done with this token list}\6
+\\{end\_token\_list};\5
+\&{goto} \37\\{restart};\C{resume previous level}\6
+\&{end}\2\par
+\U347.\fi
+
+\M366. The present point in the program is reached only when the \\{expand}
+routine has inserted a special marker into the input. In this special
+case, $\\{info}(\\{loc})$ is known to be a control sequence token, and $%
+\\{link}(\\{loc})=\\{null}$.
+
+\Y\P\D \37$\\{no\_expand\_flag}=257$\C{this characterizes a special variant of %
+\\{relax}}\par
+\Y\P$\4\X366:Get the next token, suppressing expansion\X\S$\6
+\&{begin} \37$\\{cur\_cs}\K\\{info}(\\{loc})-\\{cs\_token\_flag}$;\5
+$\\{loc}\K\\{null}$;\6
+$\\{cur\_cmd}\K\\{eq\_type}(\\{cur\_cs})$;\5
+$\\{cur\_chr}\K\\{equiv}(\\{cur\_cs})$;\6
+\&{if} $\\{cur\_cmd}>\\{max\_command}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_cmd}\K\\{relax}$;\5
+$\\{cur\_chr}\K\\{no\_expand\_flag}$;\6
+\&{end};\2\6
+\&{end}\par
+\U365.\fi
+
+\M367. \P$\X367:Insert macro parameter and \&{goto} \\{restart}\X\S$\6
+\&{begin} \37$\\{begin\_token\_list}(\\{param\_stack}[\\{param\_start}+\\{cur%
+\_chr}-1],\39\\{parameter})$;\5
+\&{goto} \37\\{restart};\6
+\&{end}\par
+\U365.\fi
+
+\M368. All of the easy branches of \\{get\_next} have now been taken care of.
+There is one more branch.
+
+\Y\P\D \37$\\{end\_line\_char\_inactive}\S(\\{end\_line\_char}<0)\V(\\{end%
+\_line\_char}>255)$\par
+\Y\P$\4\X368:Move to next line of file, or \&{goto} \\{restart} if there is no
+next line, or \&{return} if a \.{\\read} line has finished\X\S$\6
+\&{if} $\\{name}>17$ \1\&{then}\5
+\X370:Read next line of file into \\{buffer}, or \&{goto} \\{restart} if the
+file has ended\X\6
+\4\&{else} \&{begin} \37\&{if} $\R\\{terminal\_input}$ \1\&{then}\C{\.{\\read}
+line has ended}\6
+\&{begin} \37$\\{cur\_cmd}\K0$;\5
+$\\{cur\_chr}\K0$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $\\{input\_ptr}>0$ \1\&{then}\C{text was inserted during error recovery}%
+\6
+\&{begin} \37\\{end\_file\_reading};\5
+\&{goto} \37\\{restart};\C{resume previous level}\6
+\&{end};\2\6
+\&{if} $\\{selector}<\\{log\_only}$ \1\&{then}\5
+\\{open\_log\_file};\2\6
+\&{if} $\\{interaction}>\\{nonstop\_mode}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{end\_line\_char\_inactive}$ \1\&{then}\5
+$\\{incr}(\\{limit})$;\2\6
+\&{if} $\\{limit}=\\{start}$ \1\&{then}\C{previous line was empty}\6
+$\\{print\_nl}(\.{"(Please\ type\ a\ command\ or\ say\ \`\\end\')"})$;\2\6
+\\{print\_ln};\5
+$\\{first}\K\\{start}$;\5
+$\\{prompt\_input}(\.{"*"})$;\C{input on-line into \\{buffer}}\6
+$\\{limit}\K\\{last}$;\6
+\&{if} $\\{end\_line\_char\_inactive}$ \1\&{then}\5
+$\\{decr}(\\{limit})$\6
+\4\&{else} $\\{buffer}[\\{limit}]\K\\{end\_line\_char}$;\2\6
+$\\{first}\K\\{limit}+1$;\5
+$\\{loc}\K\\{start}$;\6
+\&{end}\6
+\4\&{else} $\\{fatal\_error}(\.{"***\ (job\ aborted,\ no\ legal\ \\end\
+found)"})$;\C{nonstop mode, which is intended for overnight batch processing,
+  never waits for on-line input}\2\6
+\&{end}\2\par
+\U349.\fi
+
+\M369. The global variable \\{force\_eof} is normally \\{false}; it is set %
+\\{true}
+by an \.{\\endinput} command.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{force\_eof}: \37\\{boolean};\C{should the next \.{\\input} be aborted
+early?}\par
+\fi
+
+\M370. \P$\X370:Read next line of file into \\{buffer}, or \&{goto} \\{restart}
+if the file has ended\X\S$\6
+\&{begin} \37$\\{incr}(\\{line})$;\5
+$\\{first}\K\\{start}$;\6
+\&{if} $\R\\{force\_eof}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{input\_ln}(\\{cur\_file},\39\\{true})$ \1\&{then}\C{not
+end of file}\6
+\\{firm\_up\_the\_line}\C{this sets \\{limit}}\6
+\4\&{else} $\\{force\_eof}\K\\{true}$;\2\6
+\&{end};\2\6
+\&{if} $\\{force\_eof}$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{")"})$;\5
+$\\{decr}(\\{open\_parens})$;\5
+\\{update\_terminal};\C{show user that file has been read}\6
+$\\{force\_eof}\K\\{false}$;\5
+\\{end\_file\_reading};\C{resume previous level}\6
+\\{check\_outer\_validity};\5
+\&{goto} \37\\{restart};\6
+\&{end};\2\6
+\&{if} $\\{end\_line\_char\_inactive}$ \1\&{then}\5
+$\\{decr}(\\{limit})$\6
+\4\&{else} $\\{buffer}[\\{limit}]\K\\{end\_line\_char}$;\2\6
+$\\{first}\K\\{limit}+1$;\5
+$\\{loc}\K\\{start}$;\C{ready to read}\6
+\&{end}\par
+\U368.\fi
+
+\M371. If the user has set the \\{pausing} parameter to some positive value,
+and if nonstop mode has not been selected, each line of input is displayed
+on the terminal and the transcript file, followed by `\.{=>}'.
+\TeX\ waits for a response. If the response is simply \\{carriage\_return}, the
+line is accepted as it stands, otherwise the line typed is
+used instead of the line in the file.
+
+\Y\P\4\&{procedure}\1\  \37\\{firm\_up\_the\_line};\6
+\4\&{var} \37\|k: \37$0\to\\{buf\_size}$;\C{an index into \\{buffer}}\2\6
+\&{begin} \37$\\{limit}\K\\{last}$;\6
+\&{if} $\\{pausing}>0$ \1\&{then}\6
+\&{if} $\\{interaction}>\\{nonstop\_mode}$ \1\&{then}\6
+\&{begin} \37\\{wake\_up\_terminal};\5
+\\{print\_ln};\6
+\&{if} $\\{start}<\\{limit}$ \1\&{then}\6
+\&{for} $\|k\K\\{start}\mathrel{\&{to}}\\{limit}-1$ \1\&{do}\5
+$\\{print}(\\{buffer}[\|k])$;\2\2\6
+$\\{first}\K\\{limit}$;\5
+$\\{prompt\_input}(\.{"=>"})$;\C{wait for user response}\6
+\&{if} $\\{last}>\\{first}$ \1\&{then}\6
+\&{begin} \37\&{for} $\|k\K\\{first}\mathrel{\&{to}}\\{last}-1$ \1\&{do}\C{move
+line down in buffer}\6
+$\\{buffer}[\|k+\\{start}-\\{first}]\K\\{buffer}[\|k]$;\2\6
+$\\{limit}\K\\{start}+\\{last}-\\{first}$;\6
+\&{end};\2\6
+\&{end};\2\2\6
+\&{end};\par
+\fi
+
+\M372. Since \\{get\_next} is used so frequently in \TeX, it is convenient
+to define three related procedures that do a little more:
+
+\yskip\hang\\{get\_token} not only sets \\{cur\_cmd} and \\{cur\_chr}, it
+also sets \\{cur\_tok}, a packed halfword version of the current token.
+
+\yskip\hang\\{get\_x\_token}, meaning ``get an expanded token,'' is like
+\\{get\_token}, but if the current token turns out to be a user-defined
+control sequence (i.e., a macro call), or a conditional,
+or something like \.{\\topmark} or \.{\\expandafter} or \.{\\csname},
+it is eliminated from the input by beginning the expansion of the macro
+or the evaluation of the conditional.
+
+\yskip\hang\\{x\_token} is like \\{get\_x\_token} except that it assumes that
+\\{get\_next} has already been called.
+
+\yskip\noindent
+In fact, these three procedures account for almost every use of \\{get\_next}.
+
+\fi
+
+\M373. No new control sequences will be defined except during a call of
+\\{get\_token}, or when \.{\\csname} compresses a token list, because
+\\{no\_new\_control\_sequence} is always \\{true} at other times.
+
+\Y\P\4\&{procedure}\1\  \37\\{get\_token};\C{sets \\{cur\_cmd}, \\{cur\_chr}, %
+\\{cur\_tok}}\2\6
+\&{begin} \37$\\{no\_new\_control\_sequence}\K\\{false}$;\5
+\\{get\_next};\5
+$\\{no\_new\_control\_sequence}\K\\{true}$;\6
+\&{if} $\\{cur\_cs}=0$ \1\&{then}\6
+\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=%
+\\{other\_kchar})$ \1\&{then}\C{\\{wchar\_token}}\6
+$\\{cur\_tok}\K\\{cur\_chr}$\6
+\4\&{else} $\\{cur\_tok}\K(\\{cur\_cmd}\ast\O{400})+\\{cur\_chr}$\2\6
+\4\&{else} $\\{cur\_tok}\K\\{cs\_token\_flag}+\\{cur\_cs}$;\2\6
+\&{end};\par
+\fi
+
+\N374.  \[25] Expanding the next token.
+Only a dozen or so command codes $>\\{max\_command}$ can possibly be returned
+by
+\\{get\_next}; in increasing order, they are \\{undefined\_cs}, \\{expand%
+\_after},
+\\{no\_expand}, \\{input}, \\{if\_test}, \\{fi\_or\_else}, \\{cs\_name}, %
+\\{convert}, \\{the},
+\\{top\_bot\_mark}, \\{call}, \\{long\_call}, \\{outer\_call}, \\{long\_outer%
+\_call}, and
+\\{end\_template}.{\emergencystretch=40pt\par}
+
+\fi
+
+\M375. Sometimes, recursive calls to the following \\{expand} routine may
+cause exhaustion of the run-time calling stack, resulting in
+forced execution stops by the operating system. To diminish the chance
+of this happening, a counter is used to keep track of the recursion
+depth, in conjunction with a constant called \\{expand\_depth}.
+
+This does not catch all possible infinite recursion loops, just the ones
+that exhaust the application calling stack. The actual maximum value of
+\\{expand\_depth} is outside of our control, but the initial setting of
+10000 should be enough to prevent problems.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{expand\_depth\_count}: \37\\{integer};\par
+\fi
+
+\M376. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{expand\_depth\_count}\K0$;\par
+\fi
+
+\M377. The \\{expand} subroutine is used when $\\{cur\_cmd}>\\{max\_command}$.
+It removes a
+``call'' or a conditional or one of the other special operations just
+listed.  It follows that \\{expand} might invoke itself recursively. In all
+cases, \\{expand} destroys the current token, but it sets things up so that
+the next \\{get\_next} will deliver the appropriate next token. The value of
+\\{cur\_tok} need not be known when \\{expand} is called.
+
+Since several of the basic scanning routines communicate via global variables,
+their values are saved as local variables of \\{expand} so that
+recursive calls don't invalidate them.
+
+\Y\P\hbox{\4}\X400:Declare the procedure called \\{macro\_call}\X\6
+\hbox{\4}\X390:Declare the procedure called \\{insert\_relax}\X\6
+\4\&{procedure}\1\  \37\\{pass\_text};\5
+\\{forward}; \hbox{\2} \6
+\4\&{procedure}\1\  \37\\{start\_input};\5
+\\{forward}; \hbox{\2} \6
+\4\&{procedure}\1\  \37\\{conditional};\5
+\\{forward}; \hbox{\2} \6
+\4\&{procedure}\1\  \37\\{get\_x\_token};\5
+\\{forward}; \hbox{\2} \6
+\4\&{procedure}\1\  \37\\{conv\_toks};\5
+\\{forward}; \hbox{\2} \6
+\4\&{procedure}\1\  \37\\{ins\_the\_toks};\5
+\\{forward}; \hbox{\2} \6
+\4\&{procedure}\1\  \37\\{expand};\6
+\4\&{var} \37\|t: \37\\{halfword};\C{token that is being ``expanded after''}\6
+$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{for list manipulation}\6
+\|j: \37$0\to\\{buf\_size}$;\C{index into \\{buffer}}\6
+\\{cv\_backup}: \37\\{integer};\C{to save the global quantity \\{cur\_val}}\6
+$\\{cvl\_backup},\39\\{radix\_backup},\39\\{co\_backup}$: \37\\{small\_number};%
+\C{to save \\{cur\_val\_level}, etc.}\6
+\\{backup\_backup}: \37\\{pointer};\C{to save $\\{link}(\\{backup\_head})$}\6
+\\{save\_scanner\_status}: \37\\{small\_number};\C{temporary storage of %
+\\{scanner\_status}}\2\6
+\&{begin} \37$\\{incr}(\\{expand\_depth\_count})$;\6
+\&{if} $\\{expand\_depth\_count}\G\\{expand\_depth}$ \1\&{then}\5
+$\\{overflow}(\.{"expansion\ depth"},\39\\{expand\_depth})$;\2\6
+$\\{cv\_backup}\K\\{cur\_val}$;\5
+$\\{cvl\_backup}\K\\{cur\_val\_level}$;\5
+$\\{radix\_backup}\K\\{radix}$;\5
+$\\{co\_backup}\K\\{cur\_order}$;\5
+$\\{backup\_backup}\K\\{link}(\\{backup\_head})$;\6
+\&{if} $\\{cur\_cmd}<\\{call}$ \1\&{then}\5
+\X378:Expand a nonmacro\X\6
+\4\&{else} \&{if} $\\{cur\_cmd}<\\{end\_template}$ \1\&{then}\5
+\\{macro\_call}\6
+\4\&{else} \X386:Insert a token containing \\{frozen\_endv}\X;\2\2\6
+$\\{cur\_val}\K\\{cv\_backup}$;\5
+$\\{cur\_val\_level}\K\\{cvl\_backup}$;\5
+$\\{radix}\K\\{radix\_backup}$;\5
+$\\{cur\_order}\K\\{co\_backup}$;\5
+$\\{link}(\\{backup\_head})\K\\{backup\_backup}$;\5
+$\\{decr}(\\{expand\_depth\_count})$;\6
+\&{end};\par
+\fi
+
+\M378. \P$\X378:Expand a nonmacro\X\S$\6
+\&{begin} \37\&{if} $\\{tracing\_commands}>1$ \1\&{then}\5
+\\{show\_cur\_cmd\_chr};\2\6
+\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\4\\{top\_bot\_mark}: \37\X397:Insert the \(a)appropriate mark text into the
+scanner\X;\6
+\4\\{expand\_after}: \37\X379:Expand the token after the next token\X;\6
+\4\\{no\_expand}: \37\X380:Suppress expansion of the next token\X;\6
+\4\\{cs\_name}: \37\X383:Manufacture a control sequence name\X;\6
+\4\\{convert}: \37\\{conv\_toks};\C{this procedure is discussed in Part 27
+below}\6
+\4\\{the}: \37\\{ins\_the\_toks};\C{this procedure is discussed in Part 27
+below}\6
+\4\\{if\_test}: \37\\{conditional};\C{this procedure is discussed in Part 28
+below}\6
+\4\\{fi\_or\_else}: \37\X521:Terminate the current conditional and skip to \.{%
+\\fi}\X;\6
+\4\\{input}: \37\X389:Initiate or terminate input from a file\X;\6
+\4\&{othercases} \37\X381:Complain about an undefined macro\X\2\6
+\&{endcases};\6
+\&{end}\par
+\U377.\fi
+
+\M379. It takes only a little shuffling to do what \TeX\ calls \.{%
+\\expandafter}.
+
+\Y\P$\4\X379:Expand the token after the next token\X\S$\6
+\&{begin} \37\\{get\_token};\5
+$\|t\K\\{cur\_tok}$;\5
+\\{get\_token};\6
+\&{if} $\\{cur\_cmd}>\\{max\_command}$ \1\&{then}\5
+\\{expand}\ \&{else} \\{back\_input};\2\6
+$\\{cur\_tok}\K\|t$;\5
+\\{back\_input};\6
+\&{end}\par
+\U378.\fi
+
+\M380. The implementation of \.{\\noexpand} is a bit trickier, because it is
+necessary to insert a special `\\{dont\_expand}' marker into \TeX's reading
+mechanism.  This special marker is processed by \\{get\_next}, but it does
+not slow down the inner loop.
+
+Since \.{\\outer} macros might arise here, we must also
+clear the \\{scanner\_status} temporarily.
+
+\Y\P$\4\X380:Suppress expansion of the next token\X\S$\6
+\&{begin} \37$\\{save\_scanner\_status}\K\\{scanner\_status}$;\5
+$\\{scanner\_status}\K\\{normal}$;\5
+\\{get\_token};\5
+$\\{scanner\_status}\K\\{save\_scanner\_status}$;\5
+$\|t\K\\{cur\_tok}$;\5
+\\{back\_input};\C{now \\{start} and \\{loc} point to the backed-up token \|t}\6
+\&{if} $\|t\G\\{cs\_token\_flag}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{get\_avail}$;\5
+$\\{info}(\|p)\K\\{cs\_token\_flag}+\\{frozen\_dont\_expand}$;\5
+$\\{link}(\|p)\K\\{loc}$;\5
+$\\{start}\K\|p$;\5
+$\\{loc}\K\|p$;\6
+\&{end};\2\6
+\&{end}\par
+\U378.\fi
+
+\M381. \P$\X381:Complain about an undefined macro\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Undefined\ control\ sequence"})$;\5
+$\\{help5}(\.{"The\ control\ sequence\ at\ the\ end\ of\ the\ top\ line"})$\6
+$(\.{"of\ your\ error\ message\ was\ never\ \\def\'ed.\ If\ you\ have"})$\6
+$(\.{"misspelled\ it\ (e.g.,\ \`\\hobx\'),\ type\ \`I\'\ and\ the\ correct"})$\6
+$(\.{"spelling\ (e.g.,\ \`I\\hbox\').\ Otherwise\ just\ continue,"})$\6
+$(\.{"and\ I\'ll\ forget\ about\ whatever\ was\ undefined."})$;\5
+\\{error};\6
+\&{end}\par
+\U378.\fi
+
+\M382. The \\{expand} procedure and some other routines that construct token
+lists find it convenient to use the following macros, which are valid only if
+the variables \|p and \|q are reserved for token-list building.
+
+\Y\P\D \37$\\{store\_new\_token}(\#)\S$\1\6
+\&{begin} \37$\|q\K\\{get\_avail}$;\5
+$\\{link}(\|p)\K\|q$;\5
+$\\{info}(\|q)\K\#$;\5
+$\|p\K\|q$;\C{$\\{link}(\|p)$ is \\{null}}\6
+\&{end}\2\par
+\P\D \37$\\{fast\_store\_new\_token}(\#)\S$\1\6
+\&{begin} \37$\\{fast\_get\_avail}(\|q)$;\5
+$\\{link}(\|p)\K\|q$;\5
+$\\{info}(\|q)\K\#$;\5
+$\|p\K\|q$;\C{$\\{link}(\|p)$ is \\{null}}\6
+\&{end}\2\par
+\fi
+
+\M383. \P$\X383:Manufacture a control sequence name\X\S$\6
+\&{begin} \37$\|r\K\\{get\_avail}$;\5
+$\|p\K\|r$;\C{head of the list of characters}\6
+\1\&{repeat} \37\\{get\_x\_token};\6
+\&{if} $\\{cur\_cs}=0$ \1\&{then}\5
+$\\{store\_new\_token}(\\{cur\_tok})$;\2\6
+\4\&{until}\5
+$\\{cur\_cs}\I0$;\2\6
+\&{if} $\\{cur\_cmd}\I\\{end\_cs\_name}$ \1\&{then}\5
+\X384:Complain about missing \.{\\endcsname}\X;\2\6
+\X385:Look up the characters of list \|r in the hash table, and set \\{cur\_cs}%
+\X;\6
+$\\{flush\_list}(\|r)$;\6
+\&{if} $\\{eq\_type}(\\{cur\_cs})=\\{undefined\_cs}$ \1\&{then}\6
+\&{begin} \37$\\{eq\_define}(\\{cur\_cs},\39\\{relax},\39256)$;\C{N.B.: The %
+\\{save\_stack} might change}\6
+\&{end};\C{the control sequence will now match `\.{\\relax}'}\2\6
+$\\{cur\_tok}\K\\{cur\_cs}+\\{cs\_token\_flag}$;\5
+\\{back\_input};\6
+\&{end}\par
+\U378.\fi
+
+\M384. \P$\X384:Complain about missing \.{\\endcsname}\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ "})$;\5
+$\\{print\_esc}(\.{"endcsname"})$;\5
+$\\{print}(\.{"\ inserted"})$;\5
+$\\{help2}(\.{"The\ control\ sequence\ marked\ <to\ be\ read\ again>\
+should"})$\6
+$(\.{"not\ appear\ between\ \\csname\ and\ \\endcsname."})$;\5
+\\{back\_error};\6
+\&{end}\par
+\U383.\fi
+
+\M385. \P$\X385:Look up the characters of list \|r in the hash table, and set %
+\\{cur\_cs}\X\S$\6
+$\|j\K\\{first}$;\5
+$\|p\K\\{link}(\|r)$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\|j\G\\{max\_buf\_stack}$ \1\&{then}\6
+\&{begin} \37$\\{max\_buf\_stack}\K\|j+1$;\6
+\&{if} $\\{max\_buf\_stack}=\\{buf\_size}$ \1\&{then}\5
+$\\{overflow}(\.{"buffer\ size"},\39\\{buf\_size})$;\2\6
+\&{end};\2\6
+\&{if} $\\{check\_kanji}(\\{info}(\|p))$ \1\&{then}\C{\\{wchar\_token}}\6
+\&{begin} \37$\\{buffer}[\|j]\K\\{Hi}(\\{info}(\|p))$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+$\\{buffer}[\|j]\K\\{Lo}(\\{info}(\|p))$;\5
+$\\{incr}(\|j)$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\&{if} $\|j>\\{first}+1$ \1\&{then}\6
+\&{begin} \37$\\{no\_new\_control\_sequence}\K\\{false}$;\5
+$\\{cur\_cs}\K\\{id\_lookup}(\\{first},\39\|j-\\{first})$;\5
+$\\{no\_new\_control\_sequence}\K\\{true}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|j=\\{first}$ \1\&{then}\5
+$\\{cur\_cs}\K\\{null\_cs}$\C{the list is empty}\6
+\4\&{else} $\\{cur\_cs}\K\\{single\_base}+\\{buffer}[\\{first}]$\C{the list has
+length one}\2\2\par
+\U383.\fi
+
+\M386. An \\{end\_template} command is effectively changed to an \\{endv}
+command
+by the following code. (The reason for this is discussed below; the
+\\{frozen\_end\_template} at the end of the template has passed the
+\\{check\_outer\_validity} test, so its mission of error detection has been
+accomplished.)
+
+\Y\P$\4\X386:Insert a token containing \\{frozen\_endv}\X\S$\6
+\&{begin} \37$\\{cur\_tok}\K\\{cs\_token\_flag}+\\{frozen\_endv}$;\5
+\\{back\_input};\6
+\&{end}\par
+\U377.\fi
+
+\M387. The processing of \.{\\input} involves the \\{start\_input} subroutine,
+which will be declared later; the processing of \.{\\endinput} is trivial.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"input"},\39\\{input},\390)$;\6
+$\\{primitive}(\.{"endinput"},\39\\{input},\391)$;\par
+\fi
+
+\M388. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{input}: \37\&{if} $\\{chr\_code}=0$ \1\&{then}\5
+$\\{print\_esc}(\.{"input"})$\ \&{else} $\\{print\_esc}(\.{"endinput"})$;\2\par
+\fi
+
+\M389. \P$\X389:Initiate or terminate input from a file\X\S$\6
+\&{if} $\\{cur\_chr}>0$ \1\&{then}\5
+$\\{force\_eof}\K\\{true}$\6
+\4\&{else} \&{if} $\\{name\_in\_progress}$ \1\&{then}\5
+\\{insert\_relax}\6
+\4\&{else} \\{start\_input}\2\2\par
+\U378.\fi
+
+\M390. Sometimes the expansion looks too far ahead, so we want to insert
+a harmless \.{\\relax} into the user's input.
+
+\Y\P$\4\X390:Declare the procedure called \\{insert\_relax}\X\S$\6
+\4\&{procedure}\1\  \37\\{insert\_relax};\2\6
+\&{begin} \37$\\{cur\_tok}\K\\{cs\_token\_flag}+\\{cur\_cs}$;\5
+\\{back\_input};\5
+$\\{cur\_tok}\K\\{cs\_token\_flag}+\\{frozen\_relax}$;\5
+\\{back\_input};\5
+$\\{token\_type}\K\\{inserted}$;\6
+\&{end};\par
+\U377.\fi
+
+\M391. Here is a recursive procedure that is \TeX's usual way to get the
+next token of input. It has been slightly optimized to take account of
+common cases.
+
+\Y\P\4\&{procedure}\1\  \37\\{get\_x\_token};\C{sets \\{cur\_cmd}, \\{cur%
+\_chr}, \\{cur\_tok},   and expands macros}\6
+\4\&{label} \37$\\{restart},\39\\{done}$;\2\6
+\&{begin} \37\\{restart}: \37\\{get\_next};\6
+\&{if} $\\{cur\_cmd}\L\\{max\_command}$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+\&{if} $\\{cur\_cmd}\G\\{call}$ \1\&{then}\6
+\&{if} $\\{cur\_cmd}<\\{end\_template}$ \1\&{then}\5
+\\{macro\_call}\6
+\4\&{else} \&{begin} \37$\\{cur\_cs}\K\\{frozen\_endv}$;\5
+$\\{cur\_cmd}\K\\{endv}$;\5
+\&{goto} \37\\{done};\C{$\\{cur\_chr}=\\{null\_list}$}\6
+\&{end}\2\6
+\4\&{else} \\{expand};\2\6
+\&{goto} \37\\{restart};\6
+\4\\{done}: \37\&{if} $\\{cur\_cs}=0$ \1\&{then}\6
+\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=%
+\\{other\_kchar})$ \1\&{then}\5
+$\\{cur\_tok}\K\\{cur\_chr}$\6
+\4\&{else} $\\{cur\_tok}\K(\\{cur\_cmd}\ast\O{400})+\\{cur\_chr}$\2\6
+\4\&{else} $\\{cur\_tok}\K\\{cs\_token\_flag}+\\{cur\_cs}$;\2\6
+\&{end};\par
+\fi
+
+\M392. The \\{get\_x\_token} procedure is equivalent to two consecutive
+procedure calls: \\{get\_next}; \\{x\_token}.
+
+\Y\P\4\&{procedure}\1\  \37\\{x\_token};\C{\\{get\_x\_token} without the
+initial \\{get\_next}}\2\6
+\&{begin} \37\&{while} $\\{cur\_cmd}>\\{max\_command}$ \1\&{do}\6
+\&{begin} \37\\{expand};\5
+\\{get\_next};\6
+\&{end};\2\6
+\&{if} $\\{cur\_cs}=0$ \1\&{then}\6
+\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=%
+\\{other\_kchar})$ \1\&{then}\5
+$\\{cur\_tok}\K\\{cur\_chr}$\6
+\4\&{else} $\\{cur\_tok}\K(\\{cur\_cmd}\ast\O{400})+\\{cur\_chr}$\2\6
+\4\&{else} $\\{cur\_tok}\K\\{cs\_token\_flag}+\\{cur\_cs}$;\2\6
+\&{end};\par
+\fi
+
+\M393. A control sequence that has been \.{\\def}'ed by the user is expanded by
+\TeX's \\{macro\_call} procedure.
+
+Before we get into the details of \\{macro\_call}, however, let's consider the
+treatment of primitives like \.{\\topmark}, since they are essentially
+macros without parameters. The token lists for such marks are kept in a
+global array of five pointers; we refer to the individual entries of this
+array by symbolic names \\{top\_mark}, etc. The value of \\{top\_mark} is
+either
+\\{null} or a pointer to the reference count of a token list.
+
+\Y\P\D \37$\\{top\_mark\_code}=0$\C{the mark in effect at the previous page
+break}\par
+\P\D \37$\\{first\_mark\_code}=1$\C{the first mark between \\{top\_mark} and %
+\\{bot\_mark}}\par
+\P\D \37$\\{bot\_mark\_code}=2$\C{the mark in effect at the current page break}%
+\par
+\P\D \37$\\{split\_first\_mark\_code}=3$\C{the first mark found by \.{%
+\\vsplit}}\par
+\P\D \37$\\{split\_bot\_mark\_code}=4$\C{the last mark found by \.{\\vsplit}}%
+\par
+\P\D \37$\\{top\_mark}\S\\{cur\_mark}[\\{top\_mark\_code}]$\par
+\P\D \37$\\{first\_mark}\S\\{cur\_mark}[\\{first\_mark\_code}]$\par
+\P\D \37$\\{bot\_mark}\S\\{cur\_mark}[\\{bot\_mark\_code}]$\par
+\P\D \37$\\{split\_first\_mark}\S\\{cur\_mark}[\\{split\_first\_mark\_code}]$%
+\par
+\P\D \37$\\{split\_bot\_mark}\S\\{cur\_mark}[\\{split\_bot\_mark\_code}]$\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_mark}: \37\&{array} $[\\{top\_mark\_code}\to\\{split\_bot\_mark%
+\_code}]$ \1\&{of}\5
+\\{pointer};\C{token lists for marks}\2\par
+\fi
+
+\M394. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{top\_mark}\K\\{null}$;\5
+$\\{first\_mark}\K\\{null}$;\5
+$\\{bot\_mark}\K\\{null}$;\5
+$\\{split\_first\_mark}\K\\{null}$;\5
+$\\{split\_bot\_mark}\K\\{null}$;\par
+\fi
+
+\M395. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"topmark"},\39\\{top\_bot\_mark},\39\\{top\_mark\_code})$;\5
+$\\{primitive}(\.{"firstmark"},\39\\{top\_bot\_mark},\39\\{first\_mark%
+\_code})$;\5
+$\\{primitive}(\.{"botmark"},\39\\{top\_bot\_mark},\39\\{bot\_mark\_code})$;\5
+$\\{primitive}(\.{"splitfirstmark"},\39\\{top\_bot\_mark},\39\\{split\_first%
+\_mark\_code})$;\5
+$\\{primitive}(\.{"splitbotmark"},\39\\{top\_bot\_mark},\39\\{split\_bot\_mark%
+\_code})$;\par
+\fi
+
+\M396. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{top\_bot\_mark}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{first\_mark\_code}: \37$\\{print\_esc}(\.{"firstmark"})$;\6
+\4\\{bot\_mark\_code}: \37$\\{print\_esc}(\.{"botmark"})$;\6
+\4\\{split\_first\_mark\_code}: \37$\\{print\_esc}(\.{"splitfirstmark"})$;\6
+\4\\{split\_bot\_mark\_code}: \37$\\{print\_esc}(\.{"splitbotmark"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"topmark"})$\2\6
+\&{endcases};\par
+\fi
+
+\M397. The following code is activated when $\\{cur\_cmd}=\\{top\_bot\_mark}$
+and
+when \\{cur\_chr} is a code like \\{top\_mark\_code}.
+
+\Y\P$\4\X397:Insert the \(a)appropriate mark text into the scanner\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_mark}[\\{cur\_chr}]\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{cur\_mark}[\\{cur\_chr}],\39\\{mark\_text})$;\2\6
+\&{end}\par
+\U378.\fi
+
+\M398. Now let's consider \\{macro\_call} itself, which is invoked when \TeX\
+is
+scanning a control sequence whose \\{cur\_cmd} is either \\{call}, \\{long%
+\_call},
+\\{outer\_call}, or \\{long\_outer\_call}.  The control sequence definition
+appears in the token list whose reference count is in location \\{cur\_chr}
+of \\{mem}.
+
+The global variable \\{long\_state} will be set to \\{call} or to \\{long%
+\_call},
+depending on whether or not the control sequence disallows \.{\\par}
+in its parameters. The \\{get\_next} routine will set \\{long\_state} to
+\\{outer\_call} and emit \.{\\par}, if a file ends or if an \.{\\outer}
+control sequence occurs in the midst of an argument.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{long\_state}: \37$\\{call}\to\\{long\_outer\_call}$;\C{governs the
+acceptance of \.{\\par}}\par
+\fi
+
+\M399. The parameters, if any, must be scanned before the macro is expanded.
+Parameters are token lists without reference counts. They are placed on
+an auxiliary stack called \\{pstack} while they are being scanned, since
+the \\{param\_stack} may be losing entries during the matching process.
+(Note that \\{param\_stack} can't be gaining entries, since \\{macro\_call} is
+the only routine that puts anything onto \\{param\_stack}, and it
+is not recursive.)
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{pstack}: \37\&{array} $[0\to8]$ \1\&{of}\5
+\\{pointer};\C{arguments supplied to a macro}\2\par
+\fi
+
+\M400. After parameter scanning is complete, the parameters are moved to the
+\\{param\_stack}. Then the macro body is fed to the scanner; in other words,
+\\{macro\_call} places the defined text of the control sequence at the
+top of\/ \TeX's input stack, so that \\{get\_next} will proceed to read it
+next.
+
+The global variable \\{cur\_cs} contains the \\{eqtb} address of the control
+sequence
+being expanded, when \\{macro\_call} begins. If this control sequence has not
+been
+declared \.{\\long}, i.e., if its command code in the \\{eq\_type} field is
+not \\{long\_call} or \\{long\_outer\_call}, its parameters are not allowed to
+contain
+the control sequence \.{\\par}. If an illegal \.{\\par} appears, the macro
+call is aborted, and the \.{\\par} will be rescanned.
+
+\Y\P$\4\X400:Declare the procedure called \\{macro\_call}\X\S$\6
+\4\&{procedure}\1\  \37\\{macro\_call};\C{invokes a user-defined control
+sequence}\6
+\4\&{label} \37$\\{exit},\39\\{continue},\39\\{done},\39\\{done1},\39%
+\\{found}$;\6
+\4\&{var} \37\|r: \37\\{pointer};\C{current node in the macro's token list}\6
+\|p: \37\\{pointer};\C{current node in parameter token list being built}\6
+\|q: \37\\{pointer};\C{new node being put into the token list}\6
+\|s: \37\\{pointer};\C{backup pointer for parameter matching}\6
+\|t: \37\\{pointer};\C{cycle pointer for backup recovery}\6
+$\|u,\39\|v$: \37\\{pointer};\C{auxiliary pointers for backup recovery}\6
+\\{rbrace\_ptr}: \37\\{pointer};\C{one step before the last \\{right\_brace}
+token}\6
+\|n: \37\\{small\_number};\C{the number of parameters scanned}\6
+\\{unbalance}: \37\\{halfword};\C{unmatched left braces in current parameter}\6
+\|m: \37\\{halfword};\C{the number of tokens or groups (usually)}\6
+\\{ref\_count}: \37\\{pointer};\C{start of the token list}\6
+\\{save\_scanner\_status}: \37\\{small\_number};\C{\\{scanner\_status} upon
+entry}\6
+\\{save\_warning\_index}: \37\\{pointer};\C{\\{warning\_index} upon entry}\6
+\\{match\_chr}: \37\\{ASCII\_code};\C{character used in parameter}\2\6
+\&{begin} \37$\\{save\_scanner\_status}\K\\{scanner\_status}$;\5
+$\\{save\_warning\_index}\K\\{warning\_index}$;\5
+$\\{warning\_index}\K\\{cur\_cs}$;\5
+$\\{ref\_count}\K\\{cur\_chr}$;\5
+$\|r\K\\{link}(\\{ref\_count})$;\5
+$\|n\K0$;\6
+\&{if} $\\{tracing\_macros}>0$ \1\&{then}\5
+\X412:Show the text of the macro being expanded\X;\2\6
+\&{if} $\\{info}(\|r)\I\\{end\_match\_token}$ \1\&{then}\5
+\X402:Scan the parameters and make $\\{link}(\|r)$ point to the macro body; but
+\&{return} if an illegal \.{\\par} is detected\X;\2\6
+\X401:Feed the macro body and its parameters to the scanner\X;\6
+\4\\{exit}: \37$\\{scanner\_status}\K\\{save\_scanner\_status}$;\5
+$\\{warning\_index}\K\\{save\_warning\_index}$;\6
+\&{end};\par
+\U377.\fi
+
+\M401. Before we put a new token list on the input stack, it is wise to clean
+off
+all token lists that have recently been depleted. Then a user macro that ends
+with a call to itself will not require unbounded stack space.
+
+\Y\P$\4\X401:Feed the macro body and its parameters to the scanner\X\S$\6
+\&{while} $(\\{state}=\\{token\_list})\W(\\{loc}=\\{null})\W(\\{token\_type}\I%
+\\{v\_template})$ \1\&{do}\5
+\\{end\_token\_list};\C{conserve stack space}\2\6
+$\\{begin\_token\_list}(\\{ref\_count},\39\\{macro})$;\5
+$\\{name}\K\\{warning\_index}$;\5
+$\\{loc}\K\\{link}(\|r)$;\6
+\&{if} $\|n>0$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{param\_ptr}+\|n>\\{max\_param\_stack}$ \1\&{then}\6
+\&{begin} \37$\\{max\_param\_stack}\K\\{param\_ptr}+\|n$;\6
+\&{if} $\\{max\_param\_stack}>\\{param\_size}$ \1\&{then}\5
+$\\{overflow}(\.{"parameter\ stack\ size"},\39\\{param\_size})$;\2\6
+\&{end};\2\6
+\&{for} $\|m\K0\mathrel{\&{to}}\|n-1$ \1\&{do}\5
+$\\{param\_stack}[\\{param\_ptr}+\|m]\K\\{pstack}[\|m]$;\2\6
+$\\{param\_ptr}\K\\{param\_ptr}+\|n$;\6
+\&{end}\2\par
+\U400.\fi
+
+\M402. At this point, the reader will find it advisable to review the
+explanation
+of token list format that was presented earlier, since many aspects of that
+format are of importance chiefly in the \\{macro\_call} routine.
+
+The token list might begin with a string of compulsory tokens before the
+first \\{match} or \\{end\_match}. In that case the macro name is supposed to
+be
+followed by those tokens; the following program will set $\|s=\\{null}$ to
+represent this restriction. Otherwise \|s will be set to the first token of
+a string that will delimit the next parameter.
+
+\Y\P$\4\X402:Scan the parameters and make $\\{link}(\|r)$ point to the macro
+body; but \&{return} if an illegal \.{\\par} is detected\X\S$\6
+\&{begin} \37$\\{scanner\_status}\K\\{matching}$;\5
+$\\{unbalance}\K0$;\5
+$\\{long\_state}\K\\{eq\_type}(\\{cur\_cs})$;\6
+\&{if} $\\{long\_state}\G\\{outer\_call}$ \1\&{then}\5
+$\\{long\_state}\K\\{long\_state}-2$;\2\6
+\1\&{repeat} \37$\\{link}(\\{temp\_head})\K\\{null}$;\6
+\&{if} $(\\{info}(\|r)>\\{match\_token}+255)\V(\\{info}(\|r)<\\{match\_token})$
+\1\&{then}\5
+$\|s\K\\{null}$\6
+\4\&{else} \&{begin} \37$\\{match\_chr}\K\\{info}(\|r)-\\{match\_token}$;\5
+$\|s\K\\{link}(\|r)$;\5
+$\|r\K\|s$;\5
+$\|p\K\\{temp\_head}$;\5
+$\|m\K0$;\6
+\&{end};\2\6
+\X403:Scan a parameter until its delimiter string has been found; or, if $\|s=%
+\\{null}$, simply scan the delimiter string\X;\6
+\C{now $\\{info}(\|r)$ is a token whose command code is either \\{match} or %
+\\{end\_match}}\6
+\4\&{until}\5
+$\\{info}(\|r)=\\{end\_match\_token}$;\2\6
+\&{end}\par
+\U400.\fi
+
+\M403. If $\\{info}(\|r)$ is a \\{match} or \\{end\_match} command, it cannot
+be equal to
+any token found by \\{get\_token}. Therefore an undelimited parameter---i.e.,
+a \\{match} that is immediately followed by \\{match} or \\{end\_match}---will
+always fail the test `$\\{cur\_tok}=\\{info}(\|r)$' in the following algorithm.
+
+\Y\P$\4\X403:Scan a parameter until its delimiter string has been found; or, if
+$\|s=\\{null}$, simply scan the delimiter string\X\S$\6
+\4\\{continue}: \37\\{get\_token};\C{set \\{cur\_tok} to the next token of
+input}\6
+\&{if} $\\{cur\_tok}=\\{info}(\|r)$ \1\&{then}\5
+\X405:Advance \(r)\|r; \&{goto} \\{found} if the parameter delimiter has been
+fully matched, otherwise \&{goto} \\{continue}\X;\2\6
+\X408:Contribute the recently matched tokens to the current parameter, and %
+\&{goto} \\{continue} if a partial match is still in effect; but abort if $\|s=%
+\\{null}$\X;\6
+\&{if} $\\{cur\_tok}=\\{par\_token}$ \1\&{then}\6
+\&{if} $\\{long\_state}\I\\{long\_call}$ \1\&{then}\5
+\X407:Report a runaway argument and abort\X;\2\2\6
+\&{if} $\\{cur\_tok}<\\{right\_brace\_limit}$ \1\&{then}\6
+\&{if} $\\{cur\_tok}<\\{left\_brace\_limit}$ \1\&{then}\5
+\X410:Contribute an entire group to the current parameter\X\6
+\4\&{else} \X406:Report an extra right brace and \&{goto} \\{continue}\X\2\6
+\4\&{else} \X404:Store the current token, but \&{goto} \\{continue} if it is a
+blank space that would become an undelimited parameter\X;\2\6
+$\\{incr}(\|m)$;\6
+\&{if} $\\{info}(\|r)>\\{end\_match\_token}$ \1\&{then}\5
+\&{goto} \37\\{continue};\2\6
+\&{if} $\\{info}(\|r)<\\{match\_token}$ \1\&{then}\5
+\&{goto} \37\\{continue};\2\6
+\4\\{found}: \37\&{if} $\|s\I\\{null}$ \1\&{then}\5
+\X411:Tidy up the parameter just scanned, and tuck it away\X\2\par
+\U402.\fi
+
+\M404. \P$\X404:Store the current token, but \&{goto} \\{continue} if it is a
+blank space that would become an undelimited parameter\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_tok}=\\{space\_token}$ \1\&{then}\6
+\&{if} $\\{info}(\|r)\L\\{end\_match\_token}$ \1\&{then}\6
+\&{if} $\\{info}(\|r)\G\\{match\_token}$ \1\&{then}\5
+\&{goto} \37\\{continue};\2\2\2\6
+$\\{store\_new\_token}(\\{cur\_tok})$;\6
+\&{end}\par
+\U403.\fi
+
+\M405. A slightly subtle point arises here: When the parameter delimiter ends
+with `\.{\#\{}', the token list will have a left brace both before and
+after the \\{end\_match}\kern-.4pt. Only one of these should affect the
+\\{align\_state}, but both will be scanned, so we must make a correction.
+
+\Y\P$\4\X405:Advance \(r)\|r; \&{goto} \\{found} if the parameter delimiter has
+been fully matched, otherwise \&{goto} \\{continue}\X\S$\6
+\&{begin} \37$\|r\K\\{link}(\|r)$;\6
+\&{if} $(\\{info}(\|r)\G\\{match\_token})\W(\\{info}(\|r)\L\\{end\_match%
+\_token})$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{cur\_tok}<\\{left\_brace\_limit}$ \1\&{then}\5
+$\\{decr}(\\{align\_state})$;\2\6
+\&{goto} \37\\{found};\6
+\&{end}\6
+\4\&{else} \&{goto} \37\\{continue};\2\6
+\&{end}\par
+\U403.\fi
+
+\M406. \P$\X406:Report an extra right brace and \&{goto} \\{continue}\X\S$\6
+\&{begin} \37\\{back\_input};\5
+$\\{print\_err}(\.{"Argument\ of\ "})$;\5
+$\\{sprint\_cs}(\\{warning\_index})$;\5
+$\\{print}(\.{"\ has\ an\ extra\ \}"})$;\5
+$\\{help6}(\.{"I\'ve\ run\ across\ a\ \`\}\'\ that\ doesn\'t\ seem\ to\ match\
+anything."})$\6
+$(\.{"For\ example,\ \`\\def\\a\#1\{...\}\'\ and\ \`\\a\}\'\ would\ produce"})$%
+\6
+$(\.{"this\ error.\ If\ you\ simply\ proceed\ now,\ the\ \`\\par\'\ that"})$\6
+$(\.{"I\'ve\ just\ inserted\ will\ cause\ me\ to\ report\ a\ runaway"})$\6
+$(\.{"argument\ that\ might\ be\ the\ root\ of\ the\ problem.\ But\ if"})$\6
+$(\.{"your\ \`\}\'\ was\ spurious,\ just\ type\ \`2\'\ and\ it\ will\ go\
+away."})$;\5
+$\\{incr}(\\{align\_state})$;\5
+$\\{long\_state}\K\\{call}$;\5
+$\\{cur\_tok}\K\\{par\_token}$;\5
+\\{ins\_error};\5
+\&{goto} \37\\{continue};\6
+\&{end}\C{a white lie; the \.{\\par} won't always trigger a runaway}\par
+\U403.\fi
+
+\M407. If $\\{long\_state}=\\{outer\_call}$, a runaway argument has already
+been reported.
+
+\Y\P$\4\X407:Report a runaway argument and abort\X\S$\6
+\&{begin} \37\&{if} $\\{long\_state}=\\{call}$ \1\&{then}\6
+\&{begin} \37\\{runaway};\5
+$\\{print\_err}(\.{"Paragraph\ ended\ before\ "})$;\5
+$\\{sprint\_cs}(\\{warning\_index})$;\5
+$\\{print}(\.{"\ was\ complete"})$;\5
+$\\{help3}(\.{"I\ suspect\ you\'ve\ forgotten\ a\ \`\}\',\ causing\ me\ to\
+apply\ this"})$\6
+$(\.{"control\ sequence\ to\ too\ much\ text.\ How\ can\ we\ recover?"})$\6
+$(\.{"My\ plan\ is\ to\ forget\ the\ whole\ thing\ and\ hope\ for\ the\
+best."})$;\5
+\\{back\_error};\6
+\&{end};\2\6
+$\\{pstack}[\|n]\K\\{link}(\\{temp\_head})$;\5
+$\\{align\_state}\K\\{align\_state}-\\{unbalance}$;\6
+\&{for} $\|m\K0\mathrel{\&{to}}\|n$ \1\&{do}\5
+$\\{flush\_list}(\\{pstack}[\|m])$;\2\6
+\&{return};\6
+\&{end}\par
+\Us403\ET410.\fi
+
+\M408. When the following code becomes active, we have matched tokens from \|s
+to
+the predecessor of \|r, and we have found that $\\{cur\_tok}\I\\{info}(\|r)$.
+An
+interesting situation now presents itself: If the parameter is to be
+delimited by a string such as `\.{ab}', and if we have scanned `\.{aa}',
+we want to contribute one `\.a' to the current parameter and resume
+looking for a `\.b'. The program must account for such partial matches and
+for others that can be quite complex.  But most of the time we have $\|s=\|r$
+and nothing needs to be done.
+
+Incidentally, it is possible for \.{\\par} tokens to sneak in to certain
+parameters of non-\.{\\long} macros. For example, consider a case like
+`\.{\\def\\a\#1\\par!\{...\}}' where the first \.{\\par} is not followed
+by an exclamation point. In such situations it does not seem appropriate
+to prohibit the \.{\\par}, so \TeX\ keeps quiet about this bending of
+the rules.
+
+\Y\P$\4\X408:Contribute the recently matched tokens to the current parameter,
+and \&{goto} \\{continue} if a partial match is still in effect; but abort if $%
+\|s=\\{null}$\X\S$\6
+\&{if} $\|s\I\|r$ \1\&{then}\6
+\&{if} $\|s=\\{null}$ \1\&{then}\5
+\X409:Report an improper use of the macro and abort\X\6
+\4\&{else} \&{begin} \37$\|t\K\|s$;\6
+\1\&{repeat} \37$\\{store\_new\_token}(\\{info}(\|t))$;\5
+$\\{incr}(\|m)$;\5
+$\|u\K\\{link}(\|t)$;\5
+$\|v\K\|s$;\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\|u=\|r$ \1\&{then}\6
+\&{if} $\\{cur\_tok}\I\\{info}(\|v)$ \1\&{then}\5
+\&{goto} \37\\{done}\6
+\4\&{else} \&{begin} \37$\|r\K\\{link}(\|v)$;\5
+\&{goto} \37\\{continue};\6
+\&{end};\2\2\6
+\&{if} $\\{info}(\|u)\I\\{info}(\|v)$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\|u\K\\{link}(\|u)$;\5
+$\|v\K\\{link}(\|v)$;\6
+\&{end};\2\6
+\4\\{done}: \37$\|t\K\\{link}(\|t)$;\6
+\4\&{until}\5
+$\|t=\|r$;\2\6
+$\|r\K\|s$;\C{at this point, no tokens are recently matched}\6
+\&{end}\2\2\par
+\U403.\fi
+
+\M409. \P$\X409:Report an improper use of the macro and abort\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Use\ of\ "})$;\5
+$\\{sprint\_cs}(\\{warning\_index})$;\5
+$\\{print}(\.{"\ doesn\'t\ match\ its\ definition"})$;\5
+$\\{help4}(\.{"If\ you\ say,\ e.g.,\ \`\\def\\a1\{...\}\',\ then\ you\ must\
+always"})$\6
+$(\.{"put\ \`1\'\ after\ \`\\a\',\ since\ control\ sequence\ names\ are"})$\6
+$(\.{"made\ up\ of\ letters\ only.\ The\ macro\ here\ has\ not\ been"})$\6
+$(\.{"followed\ by\ the\ required\ stuff,\ so\ I\'m\ ignoring\ it."})$;\5
+\\{error};\5
+\&{return};\6
+\&{end}\par
+\U408.\fi
+
+\M410. \P$\X410:Contribute an entire group to the current parameter\X\S$\6
+\&{begin} \37$\\{unbalance}\K1$;\6
+\~ \1\&{loop}\ \&{begin} \37$\\{fast\_store\_new\_token}(\\{cur\_tok})$;\5
+\\{get\_token};\6
+\&{if} $\\{cur\_tok}=\\{par\_token}$ \1\&{then}\6
+\&{if} $\\{long\_state}\I\\{long\_call}$ \1\&{then}\5
+\X407:Report a runaway argument and abort\X;\2\2\6
+\&{if} $\\{cur\_tok}<\\{right\_brace\_limit}$ \1\&{then}\6
+\&{if} $\\{cur\_tok}<\\{left\_brace\_limit}$ \1\&{then}\5
+$\\{incr}(\\{unbalance})$\6
+\4\&{else} \&{begin} \37$\\{decr}(\\{unbalance})$;\6
+\&{if} $\\{unbalance}=0$ \1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\&{end};\2\2\6
+\&{end};\2\6
+\4\\{done1}: \37$\\{rbrace\_ptr}\K\|p$;\5
+$\\{store\_new\_token}(\\{cur\_tok})$;\6
+\&{end}\par
+\U403.\fi
+
+\M411. If the parameter consists of a single group enclosed in braces, we must
+strip off the enclosing braces. That's why \\{rbrace\_ptr} was introduced.
+
+\Y\P$\4\X411:Tidy up the parameter just scanned, and tuck it away\X\S$\6
+\&{begin} \37\&{if} $(\|m=1)\W(\\{info}(\|p)<\\{right\_brace\_limit})\W(\|p\I%
+\\{temp\_head})$ \1\&{then}\6
+\&{begin} \37$\\{link}(\\{rbrace\_ptr})\K\\{null}$;\5
+$\\{free\_avail}(\|p)$;\5
+$\|p\K\\{link}(\\{temp\_head})$;\5
+$\\{pstack}[\|n]\K\\{link}(\|p)$;\5
+$\\{free\_avail}(\|p)$;\6
+\&{end}\6
+\4\&{else} $\\{pstack}[\|n]\K\\{link}(\\{temp\_head})$;\2\6
+$\\{incr}(\|n)$;\6
+\&{if} $\\{tracing\_macros}>0$ \1\&{then}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\\{match\_chr})$;\5
+$\\{print\_int}(\|n)$;\5
+$\\{print}(\.{"<-"})$;\5
+$\\{show\_token\_list}(\\{pstack}[\|n-1],\39\\{null},\391000)$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end};\2\6
+\&{end}\par
+\U403.\fi
+
+\M412. \P$\X412:Show the text of the macro being expanded\X\S$\6
+\&{begin} \37\\{begin\_diagnostic};\5
+\\{print\_ln};\5
+$\\{print\_cs}(\\{warning\_index})$;\5
+$\\{token\_show}(\\{ref\_count})$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end}\par
+\U400.\fi
+
+\N413.  \[26] Basic scanning subroutines.
+Let's turn now to some procedures that \TeX\ calls upon frequently to digest
+certain kinds of patterns in the input. Most of these are quite simple;
+some are quite elaborate. Almost all of the routines call \\{get\_x\_token},
+which can cause them to be invoked recursively.
+
+\fi
+
+\M414. The \\{scan\_left\_brace} routine is called when a left brace is
+supposed to be
+the next non-blank token. (The term ``left brace'' means, more precisely,
+a character whose catcode is \\{left\_brace}.) \TeX\ allows \.{\\relax} to
+appear before the \\{left\_brace}.
+
+\Y\P\4\&{procedure}\1\  \37\\{scan\_left\_brace};\C{reads a mandatory \\{left%
+\_brace}}\2\6
+\&{begin} \37\X415:Get the next non-blank non-relax non-call token\X;\6
+\&{if} $\\{cur\_cmd}\I\\{left\_brace}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ \{\ inserted"})$;\5
+$\\{help4}(\.{"A\ left\ brace\ was\ mandatory\ here,\ so\ I\'ve\ put\ one\
+in."})$\6
+$(\.{"You\ might\ want\ to\ delete\ and/or\ insert\ some\ corrections"})$\6
+$(\.{"so\ that\ I\ will\ find\ a\ matching\ right\ brace\ soon."})$\6
+$(\.{"(If\ you\'re\ confused\ by\ all\ this,\ try\ typing\ \`I\}\'\ now.)"})$;\5
+\\{back\_error};\5
+$\\{cur\_tok}\K\\{left\_brace\_token}+\.{"\{"}$;\5
+$\\{cur\_cmd}\K\\{left\_brace}$;\5
+$\\{cur\_chr}\K\.{"\{"}$;\5
+$\\{incr}(\\{align\_state})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M415. \P$\X415:Get the next non-blank non-relax non-call token\X\S$\6
+\1\&{repeat} \37\\{get\_x\_token};\6
+\4\&{until}\5
+$(\\{cur\_cmd}\I\\{spacer})\W(\\{cur\_cmd}\I\\{relax})$\2\par
+\Us414, 1090, 1096, 1163, 1172, 1223, 1238\ETs1283.\fi
+
+\M416. The \\{scan\_optional\_equals} routine looks for an optional `\.=' sign
+preceded
+by optional spaces; `\.{\\relax}' is not ignored here.
+
+\Y\P\4\&{procedure}\1\  \37\\{scan\_optional\_equals};\2\6
+\&{begin} \37\X417:Get the next non-blank non-call token\X;\6
+\&{if} $\\{cur\_tok}\I\\{other\_token}+\.{"="}$ \1\&{then}\5
+\\{back\_input};\2\6
+\&{end};\par
+\fi
+
+\M417. \P$\X417:Get the next non-blank non-call token\X\S$\6
+\1\&{repeat} \37\\{get\_x\_token};\6
+\4\&{until}\5
+$\\{cur\_cmd}\I\\{spacer}$\2\par
+\Us416, 452, 466, 514, 537, 588, 796, 802\ETs1057.\fi
+
+\M418. In case you are getting bored, here is a slightly less trivial routine:
+Given a string of lowercase letters, like `\.{pt}' or `\.{plus}' or
+`\.{width}', the \\{scan\_keyword} routine checks to see whether the next
+tokens of input match this string. The match must be exact, except that
+uppercase letters will match their lowercase counterparts; uppercase
+equivalents are determined by subtracting $\.{"a"}-\.{"A"}$, rather than using
+the
+\\{uc\_code} table, since \TeX\ uses this routine only for its own limited
+set of keywords.
+
+If a match is found, the characters are effectively removed from the input
+and \\{true} is returned. Otherwise \\{false} is returned, and the input
+is left essentially unchanged (except for the fact that some macros
+may have been expanded, etc.).
+
+\Y\P\4\&{function}\1\  \37$\\{scan\_keyword}(\|s:\\{str\_number})$: \37%
+\\{boolean};\C{look for a given string}\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{tail of the backup list}\6
+\|q: \37\\{pointer};\C{new node being added to the token list via \\{store\_new%
+\_token}}\6
+\|k: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\2\6
+\&{begin} \37$\|p\K\\{backup\_head}$;\5
+$\\{link}(\|p)\K\\{null}$;\5
+$\|k\K\\{str\_start}[\|s]$;\6
+\&{while} $\|k<\\{str\_start}[\|s+1]$ \1\&{do}\6
+\&{begin} \37\\{get\_x\_token};\C{recursion is possible here}\6
+\&{if} $(\\{cur\_cs}=0)\W\30((\\{cur\_chr}=\\{so}(\\{str\_pool}[\|k]))\V(\\{cur%
+\_chr}=\\{so}(\\{str\_pool}[\|k])-\.{"a"}+\.{"A"}))$ \1\&{then}\6
+\&{begin} \37$\\{store\_new\_token}(\\{cur\_tok})$;\5
+$\\{incr}(\|k)$;\6
+\&{end}\6
+\4\&{else} \&{if} $(\\{cur\_cmd}\I\\{spacer})\V(\|p\I\\{backup\_head})$ \1%
+\&{then}\6
+\&{begin} \37\\{back\_input};\6
+\&{if} $\|p\I\\{backup\_head}$ \1\&{then}\5
+$\\{back\_list}(\\{link}(\\{backup\_head}))$;\2\6
+$\\{scan\_keyword}\K\\{false}$;\5
+\&{return};\6
+\&{end};\2\2\6
+\&{end};\2\6
+$\\{flush\_list}(\\{link}(\\{backup\_head}))$;\5
+$\\{scan\_keyword}\K\\{true}$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M419. Here is a procedure that sounds an alarm when mu and non-mu units
+are being switched.
+
+\Y\P\4\&{procedure}\1\  \37\\{mu\_error};\2\6
+\&{begin} \37$\\{print\_err}(\.{"Incompatible\ glue\ units"})$;\5
+$\\{help1}(\.{"I\'m\ going\ to\ assume\ that\ 1mu=1pt\ when\ they\'re\
+mixed."})$;\5
+\\{error};\6
+\&{end};\par
+\fi
+
+\M420. The next routine `\\{scan\_something\_internal}' is used to fetch
+internal
+numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}'
+when expanding constructions like `\.{\\the\\toks0}' and
+`\.{\\the\\baselineskip}'. Soon we will be considering the \\{scan\_int}
+procedure, which calls \\{scan\_something\_internal}; on the other hand,
+\\{scan\_something\_internal} also calls \\{scan\_int}, for constructions like
+`\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we
+have to declare \\{scan\_int} as a \\{forward} procedure. A few other
+procedures are also declared at this point.
+
+\Y\P\4\&{procedure}\1\  \37\\{scan\_int};\5
+\\{forward};\C{scans an integer value}\6
+\hbox{\4\4}\X444:Declare procedures that scan restricted classes of integers\X\6
+\hbox{\4\4}\X588:Declare procedures that scan font-related stuff\X\par
+\fi
+
+\M421. \TeX\ doesn't know exactly what to expect when \\{scan\_something%
+\_internal}
+begins.  For example, an integer or dimension or glue value could occur
+immediately after `\.{\\hskip}'; and one can even say \.{\\the} with
+respect to token lists in constructions like
+`\.{\\xdef\\o\{\\the\\output\}}'.  On the other hand, only integers are
+allowed after a construction like `\.{\\count}'. To handle the various
+possibilities, \\{scan\_something\_internal} has a \\{level} parameter, which
+tells the ``highest'' kind of quantity that \\{scan\_something\_internal} is
+allowed to produce. Six levels are distinguished, namely \\{int\_val},
+\\{dimen\_val}, \\{glue\_val}, \\{mu\_val}, \\{ident\_val}, and \\{tok\_val}.
+
+The output of \\{scan\_something\_internal} (and of the other routines
+\\{scan\_int}, \\{scan\_dimen}, and \\{scan\_glue} below) is put into the
+global
+variable \\{cur\_val}, and its level is put into \\{cur\_val\_level}. The
+highest
+values of \\{cur\_val\_level} are special: \\{mu\_val} is used only when
+\\{cur\_val} points to something in a ``muskip'' register, or to one of the
+three parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip};
+\\{ident\_val} is used only when \\{cur\_val} points to a font identifier;
+\\{tok\_val} is used only when \\{cur\_val} points to \\{null} or to the
+reference
+count of a token list. The last two cases are allowed only when
+\\{scan\_something\_internal} is called with $\\{level}=\\{tok\_val}$.
+
+If the output is glue, \\{cur\_val} will point to a glue specification, and
+the reference count of that glue will have been updated to reflect this
+reference; if the output is a nonempty token list, \\{cur\_val} will point to
+its reference count, but in this case the count will not have been updated.
+Otherwise \\{cur\_val} will contain the integer or scaled value in question.
+
+\Y\P\D \37$\\{int\_val}=0$\C{integer values}\par
+\P\D \37$\\{dimen\_val}=1$\C{dimension values}\par
+\P\D \37$\\{glue\_val}=2$\C{glue specifications}\par
+\P\D \37$\\{mu\_val}=3$\C{math glue specifications}\par
+\P\D \37$\\{ident\_val}=4$\C{font identifier}\par
+\P\D \37$\\{tok\_val}=5$\C{token lists}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_val}: \37\\{integer};\C{value returned by numeric scanners}\6
+\4\\{cur\_val\_level}: \37$\\{int\_val}\to\\{tok\_val}$;\C{the ``level'' of
+this value}\par
+\fi
+
+\M422. The hash table is initialized with `\.{\\count}', `\.{\\dimen}', `\.{%
+\\skip}',
+and `\.{\\muskip}' all having \\{register} as their command code; they are
+distinguished by the \\{chr\_code}, which is either \\{int\_val}, \\{dimen%
+\_val},
+\\{glue\_val}, or \\{mu\_val}.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"count"},\39\\{register},\39\\{int\_val})$;\5
+$\\{primitive}(\.{"dimen"},\39\\{register},\39\\{dimen\_val})$;\5
+$\\{primitive}(\.{"skip"},\39\\{register},\39\\{glue\_val})$;\5
+$\\{primitive}(\.{"muskip"},\39\\{register},\39\\{mu\_val})$;\par
+\fi
+
+\M423. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{register}: \37\&{if} $\\{chr\_code}=\\{int\_val}$ \1\&{then}\5
+$\\{print\_esc}(\.{"count"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{dimen\_val}$ \1\&{then}\5
+$\\{print\_esc}(\.{"dimen"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{glue\_val}$ \1\&{then}\5
+$\\{print\_esc}(\.{"skip"})$\6
+\4\&{else} $\\{print\_esc}(\.{"muskip"})$;\2\2\2\par
+\fi
+
+\M424. OK, we're ready for \\{scan\_something\_internal} itself. A second
+parameter,
+\\{negative}, is set \\{true} if the value that is found should be negated.
+It is assumed that \\{cur\_cmd} and \\{cur\_chr} represent the first token of
+the internal quantity to be scanned; an error will be signalled if
+$\\{cur\_cmd}<\\{min\_internal}$ or $\\{cur\_cmd}>\\{max\_internal}$.
+
+\Y\P\D \37$\\{scanned\_result\_end}(\#)\S\\{cur\_val\_level}\K\#$;\ \&{end} \par
+\P\D \37$\\{scanned\_result}(\#)\S$\ \&{begin} \37$\\{cur\_val}\K\#$;\5
+\\{scanned\_result\_end}\par
+\Y\P\hbox{\4}\X1425:Declare procedures needed in \\{scan\_something\_internal}%
+\X\hbox{}\6
+\4\&{procedure}\1\  \37$\\{scan\_something\_internal}(\\{level}:\\{small%
+\_number};\,\35\\{negative}:\\{boolean})$;\C{fetch an internal parameter}\6
+\4\&{var} \37\|m: \37\\{halfword};\C{\\{chr\_code} part of the operand token}\6
+\\{tx}: \37\\{pointer};\C{effective tail node}\6
+\\{qx}: \37\\{halfword};\C{general purpose index}\6
+\|p: \37$0\to\\{nest\_size}$;\C{index into \\{nest}}\6
+$\|q,\39\|r$: \37\\{pointer};\2\6
+\&{begin} \37$\|m\K\\{cur\_chr}$;\6
+\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\4\\{assign\_kinsoku}: \37\X1442:Fetch breaking penalty from some table\X;\6
+\4\\{assign\_inhibit\_xsp\_code}: \37\X1437:Fetch inhibit type from some table%
+\X;\6
+\4\\{def\_code}: \37\X425:Fetch a character code from some table\X;\6
+\4$\\{toks\_register},\39\\{assign\_toks},\39\\{def\_family},\39\\{set\_font},%
+\39\\{def\_font},\39\\{def\_jfont},\39\\{def\_tfont}$: \37\X426:Fetch a token
+list or font identifier, provided that $\\{level}=\\{tok\_val}$\X;\6
+\4\\{assign\_int}: \37$\\{scanned\_result}(\\{eqtb}[\|m].\\{int})(\\{int%
+\_val})$;\6
+\4\\{assign\_dimen}: \37$\\{scanned\_result}(\\{eqtb}[\|m].\\{sc})(\\{dimen%
+\_val})$;\6
+\4\\{assign\_glue}: \37$\\{scanned\_result}(\\{equiv}(\|m))(\\{glue\_val})$;\6
+\4\\{assign\_mu\_glue}: \37$\\{scanned\_result}(\\{equiv}(\|m))(\\{mu\_val})$;\6
+\4\\{set\_aux}: \37\X429:Fetch the \\{space\_factor} or the \\{prev\_depth}\X;\6
+\4\\{set\_prev\_graf}: \37\X433:Fetch the \\{prev\_graf}\X;\6
+\4\\{set\_page\_int}: \37\X430:Fetch the \\{dead\_cycles} or the \\{insert%
+\_penalties}\X;\6
+\4\\{set\_page\_dimen}: \37\X432:Fetch something on the \\{page\_so\_far}\X;\6
+\4\\{set\_shape}: \37\X434:Fetch the \\{par\_shape} size\X;\6
+\4\\{set\_box\_dimen}: \37\X431:Fetch a box dimension\X;\6
+\4$\\{char\_given},\39\\{math\_given}$: \37$\\{scanned\_result}(\\{cur\_chr})(%
+\\{int\_val})$;\6
+\4\\{assign\_font\_dimen}: \37\X436:Fetch a font dimension\X;\6
+\4\\{assign\_font\_int}: \37\X437:Fetch a font integer\X;\6
+\4\\{register}: \37\X438:Fetch a register\X;\6
+\4\\{last\_item}: \37\X435:Fetch an item in the current node, if appropriate\X;%
+\6
+\4\&{othercases} \37\X439:Complain that \.{\\the} can't do this; give zero
+result\X\2\6
+\&{endcases};\6
+\&{while} $\\{cur\_val\_level}>\\{level}$ \1\&{do}\5
+\X440:Convert \(c)\\{cur\_val} to a lower level\X;\2\6
+\X441:Fix the reference count, if any, and negate \\{cur\_val} if \\{negative}%
+\X;\6
+\&{end};\par
+\fi
+
+\M425. \P$\X425:Fetch a character code from some table\X\S$\6
+\&{begin} \37\\{scan\_char\_num};\6
+\&{if} $\|m=\\{math\_code\_base}$ \1\&{then}\5
+$\\{scanned\_result}(\\{ho}(\\{math\_code}(\\{cur\_val})))(\\{int\_val})$\6
+\4\&{else} \&{if} $\|m=\\{kcat\_code\_base}$ \1\&{then}\5
+$\\{scanned\_result}(\\{equiv}(\|m+\\{kcatcodekey}(\\{cur\_val})))(\\{int%
+\_val})$\6
+\4\&{else} \&{if} $\|m<\\{math\_code\_base}$ \1\&{then}\C{ \.{\\lccode}, \.{%
+\\uccode}, \.{\\sfcode}, \.{\\catcode} }\6
+\&{begin} \37\&{if} $\R\\{is\_char\_ascii}(\\{cur\_val})$ \1\&{then}\5
+$\\{scanned\_result}(\\{equiv}(\|m+\\{Hi}(\\{cur\_val})))(\\{int\_val})$\6
+\4\&{else} $\\{scanned\_result}(\\{equiv}(\|m+\\{cur\_val}))(\\{int\_val})$\2\6
+\&{end}\6
+\4\&{else} \C{ \.{\\delcode} }\2\2\2\6
+\&{begin} \37\&{if} $\R\\{is\_char\_ascii}(\\{cur\_val})$ \1\&{then}\5
+$\\{scanned\_result}(\\{eqtb}[\|m+\\{Hi}(\\{cur\_val})].\\{int})(\\{int\_val})$%
+\6
+\4\&{else} $\\{scanned\_result}(\\{eqtb}[\|m+\\{cur\_val}].\\{int})(\\{int%
+\_val})$\2\6
+\&{end};\6
+\&{end}\par
+\U424.\fi
+
+\M426. \P$\X426:Fetch a token list or font identifier, provided that $%
+\\{level}=\\{tok\_val}$\X\S$\6
+\&{if} $\\{level}\I\\{tok\_val}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ number,\ treated\ as\ zero"})$;\5
+$\\{help3}(\.{"A\ number\ should\ have\ been\ here;\ I\ inserted\ \`0\'."})$\6
+$(\.{"(If\ you\ can\'t\ figure\ out\ why\ I\ needed\ to\ see\ a\ number,"})$\6
+$(\.{"look\ up\ \`weird\ error\'\ in\ the\ index\ to\ The\ TeXbook.)"})$;\5
+\\{back\_error};\5
+$\\{scanned\_result}(0)(\\{dimen\_val})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{cur\_cmd}\L\\{assign\_toks}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{cur\_cmd}<\\{assign\_toks}$ \1\&{then}\C{$\\{cur\_cmd}=%
+\\{toks\_register}$}\6
+\&{begin} \37\\{scan\_eight\_bit\_int};\5
+$\|m\K\\{toks\_base}+\\{cur\_val}$;\6
+\&{end};\2\6
+$\\{scanned\_result}(\\{equiv}(\|m))(\\{tok\_val})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\\{back\_input};\5
+\\{scan\_font\_ident};\5
+$\\{scanned\_result}(\\{font\_id\_base}+\\{cur\_val})(\\{ident\_val})$;\6
+\&{end}\2\2\par
+\U424.\fi
+
+\M427. Users refer to `\.{\\the\\spacefactor}' only in horizontal
+mode, and to `\.{\\the\\prevdepth}' only in vertical mode; so we put the
+associated mode in the modifier part of the \\{set\_aux} command.
+The \\{set\_page\_int} command has modifier 0 or 1, for `\.{\\deadcycles}' and
+`\.{\\insertpenalties}', respectively. The \\{set\_box\_dimen} command is
+modified by either \\{width\_offset}, \\{height\_offset}, or \\{depth\_offset}.
+And the \\{last\_item} command is modified by either \\{int\_val}, \\{dimen%
+\_val},
+\\{glue\_val}, \\{input\_line\_no\_code}, or \\{badness\_code}.
+
+\Y\P\D \37$\\{input\_line\_no\_code}=\\{glue\_val}+1$\C{code for \.{%
+\\inputlineno}}\par
+\P\D \37$\\{badness\_code}=\\{glue\_val}+2$\C{code for \.{\\badness}}\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"spacefactor"},\39\\{set\_aux},\39\\{hmode})$;\5
+$\\{primitive}(\.{"prevdepth"},\39\\{set\_aux},\39\\{vmode})$;\6
+$\\{primitive}(\.{"deadcycles"},\39\\{set\_page\_int},\390)$;\5
+$\\{primitive}(\.{"insertpenalties"},\39\\{set\_page\_int},\391)$;\5
+$\\{primitive}(\.{"wd"},\39\\{set\_box\_dimen},\39\\{width\_offset})$;\5
+$\\{primitive}(\.{"ht"},\39\\{set\_box\_dimen},\39\\{height\_offset})$;\5
+$\\{primitive}(\.{"dp"},\39\\{set\_box\_dimen},\39\\{depth\_offset})$;\5
+$\\{primitive}(\.{"lastpenalty"},\39\\{last\_item},\39\\{int\_val})$;\5
+$\\{primitive}(\.{"lastkern"},\39\\{last\_item},\39\\{dimen\_val})$;\5
+$\\{primitive}(\.{"lastskip"},\39\\{last\_item},\39\\{glue\_val})$;\5
+$\\{primitive}(\.{"inputlineno"},\39\\{last\_item},\39\\{input\_line\_no%
+\_code})$;\5
+$\\{primitive}(\.{"badness"},\39\\{last\_item},\39\\{badness\_code})$;\par
+\fi
+
+\M428. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{set\_aux}: \37\&{if} $\\{chr\_code}=\\{vmode}$ \1\&{then}\5
+$\\{print\_esc}(\.{"prevdepth"})$\ \&{else} $\\{print\_esc}(%
+\.{"spacefactor"})$;\2\6
+\4\\{set\_page\_int}: \37\&{if} $\\{chr\_code}=0$ \1\&{then}\5
+$\\{print\_esc}(\.{"deadcycles"})$\ \&{else} $\\{print\_esc}(%
+\.{"insertpenalties"})$;\2\6
+\4\\{set\_box\_dimen}: \37\&{if} $\\{chr\_code}=\\{width\_offset}$ \1\&{then}\5
+$\\{print\_esc}(\.{"wd"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{height\_offset}$ \1\&{then}\5
+$\\{print\_esc}(\.{"ht"})$\6
+\4\&{else} $\\{print\_esc}(\.{"dp"})$;\2\2\6
+\4\\{last\_item}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{int\_val}: \37$\\{print\_esc}(\.{"lastpenalty"})$;\6
+\4\\{dimen\_val}: \37$\\{print\_esc}(\.{"lastkern"})$;\6
+\4\\{glue\_val}: \37$\\{print\_esc}(\.{"lastskip"})$;\6
+\4\\{input\_line\_no\_code}: \37$\\{print\_esc}(\.{"inputlineno"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"badness"})$\2\6
+\&{endcases};\par
+\fi
+
+\M429. \P$\X429:Fetch the \\{space\_factor} or the \\{prev\_depth}\X\S$\6
+\&{if} $\\{abs}(\\{mode})\I\|m$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Improper\ "})$;\5
+$\\{print\_cmd\_chr}(\\{set\_aux},\39\|m)$;\5
+$\\{help4}(\.{"You\ can\ refer\ to\ \\spacefactor\ only\ in\ horizontal\
+mode;"})$\6
+$(\.{"you\ can\ refer\ to\ \\prevdepth\ only\ in\ vertical\ mode;\ and"})$\6
+$(\.{"neither\ of\ these\ is\ meaningful\ inside\ \\write.\ So"})$\6
+$(\.{"I\'m\ forgetting\ what\ you\ said\ and\ using\ zero\ instead."})$;\5
+\\{error};\6
+\&{if} $\\{level}\I\\{tok\_val}$ \1\&{then}\5
+$\\{scanned\_result}(0)(\\{dimen\_val})$\6
+\4\&{else} $\\{scanned\_result}(0)(\\{int\_val})$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|m=\\{vmode}$ \1\&{then}\5
+$\\{scanned\_result}(\\{prev\_depth})(\\{dimen\_val})$\6
+\4\&{else} $\\{scanned\_result}(\\{space\_factor})(\\{int\_val})$\2\2\par
+\U424.\fi
+
+\M430. \P$\X430:Fetch the \\{dead\_cycles} or the \\{insert\_penalties}\X\S$\6
+\&{begin} \37\&{if} $\|m=0$ \1\&{then}\5
+$\\{cur\_val}\K\\{dead\_cycles}$\ \&{else} $\\{cur\_val}\K\\{insert%
+\_penalties}$;\2\6
+$\\{cur\_val\_level}\K\\{int\_val}$;\6
+\&{end}\par
+\U424.\fi
+
+\M431. \P$\X431:Fetch a box dimension\X\S$\6
+\&{begin} \37\\{scan\_eight\_bit\_int};\5
+$\|q\K\\{box}(\\{cur\_val})$;\6
+\&{if} $\|q=\\{null}$ \1\&{then}\5
+$\\{cur\_val}\K0$\6
+\4\&{else} \&{begin} \37$\\{qx}\K\|q$;\6
+\&{while} $(\|q\I\\{null})\W(\\{box\_dir}(\|q)\I\\{abs}(\\{direction}))$ \1%
+\&{do}\5
+$\|q\K\\{link}(\|q)$;\2\6
+\&{if} $\|q=\\{null}$ \1\&{then}\6
+\&{begin} \37$\|r\K\\{link}(\\{qx})$;\5
+$\\{link}(\\{qx})\K\\{null}$;\5
+$\|q\K\\{new\_dir\_node}(\\{qx},\39\\{abs}(\\{direction}))$;\5
+$\\{link}(\\{qx})\K\|r$;\5
+$\\{cur\_val}\K\\{mem}[\|q+\|m].\\{sc}$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|q))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|q))$;\5
+$\\{free\_node}(\|q,\39\\{box\_node\_size})$;\6
+\&{end}\6
+\4\&{else} $\\{cur\_val}\K\\{mem}[\|q+\|m].\\{sc}$;\2\6
+\&{end};\2\6
+$\\{cur\_val\_level}\K\\{dimen\_val}$;\6
+\&{end}\par
+\U424.\fi
+
+\M432. Inside an \.{\\output} routine, a user may wish to look at the page
+totals
+that were present at the moment when output was triggered.
+
+\Y\P\D \37$\\{max\_dimen}\S\O{7777777777}$\C{$2^{30}-1$}\par
+\Y\P$\4\X432:Fetch something on the \\{page\_so\_far}\X\S$\6
+\&{begin} \37\&{if} $(\\{page\_contents}=\\{empty})\W(\R\\{output\_active})$ \1%
+\&{then}\6
+\&{if} $\|m=0$ \1\&{then}\5
+$\\{cur\_val}\K\\{max\_dimen}$\ \&{else} $\\{cur\_val}\K0$\2\6
+\4\&{else} $\\{cur\_val}\K\\{page\_so\_far}[\|m]$;\2\6
+$\\{cur\_val\_level}\K\\{dimen\_val}$;\6
+\&{end}\par
+\U424.\fi
+
+\M433. \P$\X433:Fetch the \\{prev\_graf}\X\S$\6
+\&{if} $\\{mode}=0$ \1\&{then}\5
+$\\{scanned\_result}(0)(\\{int\_val})$\C{$\\{prev\_graf}=0$ within \.{\\write}}%
+\6
+\4\&{else} \&{begin} \37$\\{nest}[\\{nest\_ptr}]\K\\{cur\_list}$;\5
+$\|p\K\\{nest\_ptr}$;\6
+\&{while} $\\{abs}(\\{nest}[\|p].\\{mode\_field})\I\\{vmode}$ \1\&{do}\5
+$\\{decr}(\|p)$;\2\6
+$\\{scanned\_result}(\\{nest}[\|p].\\{pg\_field})(\\{int\_val})$;\6
+\&{end}\2\par
+\U424.\fi
+
+\M434. \P$\X434:Fetch the \\{par\_shape} size\X\S$\6
+\&{begin} \37\&{if} $\\{par\_shape\_ptr}=\\{null}$ \1\&{then}\5
+$\\{cur\_val}\K0$\6
+\4\&{else} $\\{cur\_val}\K\\{info}(\\{par\_shape\_ptr})$;\2\6
+$\\{cur\_val\_level}\K\\{int\_val}$;\6
+\&{end}\par
+\U424.\fi
+
+\M435. Here is where \.{\\lastpenalty}, \.{\\lastkern}, and \.{\\lastskip} are
+implemented. The reference count for \.{\\lastskip} will be updated later.
+
+We also handle \.{\\inputlineno} and \.{\\badness} here, because they are
+legal in similar contexts.
+
+The macro \\{find\_effective\_tail\_pTeX} sets \\{tx} to the last non-\\{disp%
+\_node}
+of the current list.
+
+\Y\P\D \37$\\{find\_effective\_tail\_pTeX}\S\\{tx}\K\\{tail}$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tx})$ \1\&{then}\6
+\&{if} $\\{type}(\\{tx})=\\{disp\_node}$ \1\&{then}\6
+\&{begin} \37$\\{tx}\K\\{prev\_node}$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tx})$ \1\&{then}\6
+\&{if} $\\{type}(\\{tx})=\\{disp\_node}$ \1\&{then}\C{\\{disp\_node} from a
+discretionary}\6
+\&{begin} \37$\\{tx}\K\\{head}$;\5
+$\|q\K\\{link}(\\{head})$;\6
+\&{while} $\|q\I\\{prev\_node}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|q)$ \1\&{then}\5
+$\\{tx}\K\|q$\6
+\4\&{else} \&{if} $\\{type}(\|q)\I\\{disp\_node}$ \1\&{then}\5
+$\\{tx}\K\|q$;\2\2\6
+\&{end};\2\6
+$\|q\K\\{link}(\|q)$;\6
+\&{end};\2\2\6
+\&{end}\2\2\par
+\P\D \37$\\{find\_effective\_tail}\S\\{find\_effective\_tail\_pTeX}$\par
+\Y\P$\4\X435:Fetch an item in the current node, if appropriate\X\S$\6
+\&{if} $\\{cur\_chr}>\\{glue\_val}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{cur\_chr}=\\{input\_line\_no\_code}$ \1\&{then}\5
+$\\{cur\_val}\K\\{line}$\6
+\4\&{else} $\\{cur\_val}\K\\{last\_badness}$;\C{$\\{cur\_chr}=\\{badness%
+\_code}$}\2\6
+$\\{cur\_val\_level}\K\\{int\_val}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{cur\_chr}=\\{glue\_val}$ \1\&{then}\5
+$\\{cur\_val}\K\\{zero\_glue}$\ \&{else} $\\{cur\_val}\K0$;\2\6
+\\{find\_effective\_tail};\5
+$\\{cur\_val\_level}\K\\{cur\_chr}$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tx})\W(\\{tx}\I\\{head})\W(\\{mode}\I0)$ \1%
+\&{then}\6
+\&{case} $\\{cur\_chr}$ \1\&{of}\6
+\4\\{int\_val}: \37\&{if} $\\{type}(\\{tx})=\\{penalty\_node}$ \1\&{then}\5
+$\\{cur\_val}\K\\{penalty}(\\{tx})$;\2\6
+\4\\{dimen\_val}: \37\&{if} $\\{type}(\\{tx})=\\{kern\_node}$ \1\&{then}\5
+$\\{cur\_val}\K\\{width}(\\{tx})$;\2\6
+\4\\{glue\_val}: \37\&{if} $\\{type}(\\{tx})=\\{glue\_node}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_val}\K\\{glue\_ptr}(\\{tx})$;\6
+\&{if} $\\{subtype}(\\{tx})=\\{mu\_glue}$ \1\&{then}\5
+$\\{cur\_val\_level}\K\\{mu\_val}$;\2\6
+\&{end};\2\2\6
+\&{end}\C{there are no other cases}\6
+\4\&{else} \&{if} $(\\{mode}=\\{vmode})\W(\\{tx}=\\{head})$ \1\&{then}\6
+\&{case} $\\{cur\_chr}$ \1\&{of}\6
+\4\\{int\_val}: \37$\\{cur\_val}\K\\{last\_penalty}$;\6
+\4\\{dimen\_val}: \37$\\{cur\_val}\K\\{last\_kern}$;\6
+\4\\{glue\_val}: \37\&{if} $\\{last\_glue}\I\\{max\_halfword}$ \1\&{then}\5
+$\\{cur\_val}\K\\{last\_glue}$;\2\2\6
+\&{end};\C{there are no other cases}\2\2\6
+\&{end}\2\par
+\U424.\fi
+
+\M436. \P$\X436:Fetch a font dimension\X\S$\6
+\&{begin} \37$\\{find\_font\_dimen}(\\{false})$;\5
+$\\{font\_info}[\\{fmem\_ptr}].\\{sc}\K0$;\5
+$\\{scanned\_result}(\\{font\_info}[\\{cur\_val}].\\{sc})(\\{dimen\_val})$;\6
+\&{end}\par
+\U424.\fi
+
+\M437. \P$\X437:Fetch a font integer\X\S$\6
+\&{begin} \37\\{scan\_font\_ident};\6
+\&{if} $\|m=0$ \1\&{then}\5
+$\\{scanned\_result}(\\{hyphen\_char}[\\{cur\_val}])(\\{int\_val})$\6
+\4\&{else} $\\{scanned\_result}(\\{skew\_char}[\\{cur\_val}])(\\{int\_val})$;\2%
+\6
+\&{end}\par
+\U424.\fi
+
+\M438. \P$\X438:Fetch a register\X\S$\6
+\&{begin} \37\\{scan\_eight\_bit\_int};\6
+\&{case} $\|m$ \1\&{of}\6
+\4\\{int\_val}: \37$\\{cur\_val}\K\\{count}(\\{cur\_val})$;\6
+\4\\{dimen\_val}: \37$\\{cur\_val}\K\\{dimen}(\\{cur\_val})$;\6
+\4\\{glue\_val}: \37$\\{cur\_val}\K\\{skip}(\\{cur\_val})$;\6
+\4\\{mu\_val}: \37$\\{cur\_val}\K\\{mu\_skip}(\\{cur\_val})$;\2\6
+\&{end};\C{there are no other cases}\6
+$\\{cur\_val\_level}\K\|m$;\6
+\&{end}\par
+\U424.\fi
+
+\M439. \P$\X439:Complain that \.{\\the} can't do this; give zero result\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"You\ can\'t\ use\ \`"})$;\5
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\5
+$\\{print}(\.{"\'\ after\ "})$;\5
+$\\{print\_esc}(\.{"the"})$;\5
+$\\{help1}(\.{"I\'m\ forgetting\ what\ you\ said\ and\ using\ zero\
+instead."})$;\5
+\\{error};\6
+\&{if} $\\{level}\I\\{tok\_val}$ \1\&{then}\5
+$\\{scanned\_result}(0)(\\{dimen\_val})$\6
+\4\&{else} $\\{scanned\_result}(0)(\\{int\_val})$;\2\6
+\&{end}\par
+\U424.\fi
+
+\M440. When a \\{glue\_val} changes to a \\{dimen\_val}, we use the width
+component
+of the glue; there is no need to decrease the reference count, since it
+has not yet been increased.  When a \\{dimen\_val} changes to an \\{int\_val},
+we use scaled points so that the value doesn't actually change. And when a
+\\{mu\_val} changes to a \\{glue\_val}, the value doesn't change either.
+
+\Y\P$\4\X440:Convert \(c)\\{cur\_val} to a lower level\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_val\_level}=\\{glue\_val}$ \1\&{then}\5
+$\\{cur\_val}\K\\{width}(\\{cur\_val})$\6
+\4\&{else} \&{if} $\\{cur\_val\_level}=\\{mu\_val}$ \1\&{then}\5
+\\{mu\_error};\2\2\6
+$\\{decr}(\\{cur\_val\_level})$;\6
+\&{end}\par
+\U424.\fi
+
+\M441. If \\{cur\_val} points to a glue specification at this point, the
+reference
+count for the glue does not yet include the reference by \\{cur\_val}.
+If \\{negative} is \\{true}, \\{cur\_val\_level} is known to be $\L\\{mu%
+\_val}$.
+
+\Y\P$\4\X441:Fix the reference count, if any, and negate \\{cur\_val} if %
+\\{negative}\X\S$\6
+\&{if} $\\{negative}$ \1\&{then}\6
+\&{if} $\\{cur\_val\_level}\G\\{glue\_val}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_val}\K\\{new\_spec}(\\{cur\_val})$;\5
+\X442:Negate all three glue components of \\{cur\_val}\X;\6
+\&{end}\6
+\4\&{else} $\\{negate}(\\{cur\_val})$\2\6
+\4\&{else} \&{if} $(\\{cur\_val\_level}\G\\{glue\_val})\W(\\{cur\_val\_level}\L%
+\\{mu\_val})$ \1\&{then}\5
+$\\{add\_glue\_ref}(\\{cur\_val})$\2\2\par
+\U424.\fi
+
+\M442. \P$\X442:Negate all three glue components of \\{cur\_val}\X\S$\6
+\&{begin} \37$\\{negate}(\\{width}(\\{cur\_val}))$;\5
+$\\{negate}(\\{stretch}(\\{cur\_val}))$;\5
+$\\{negate}(\\{shrink}(\\{cur\_val}))$;\6
+\&{end}\par
+\U441.\fi
+
+\M443. Our next goal is to write the \\{scan\_int} procedure, which scans
+anything that
+\TeX\ treats as an integer. But first we might as well look at some simple
+applications of \\{scan\_int} that have already been made inside of
+\\{scan\_something\_internal}.
+
+\fi
+
+\M444. \P$\X444:Declare procedures that scan restricted classes of integers\X%
+\S$\6
+\4\&{procedure}\1\  \37\\{scan\_eight\_bit\_int};\2\6
+\&{begin} \37\\{scan\_int};\6
+\&{if} $(\\{cur\_val}<0)\V(\\{cur\_val}>255)$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Bad\ register\ code"})$;\5
+$\\{help2}(\.{"A\ register\ number\ must\ be\ between\ 0\ and\ 255."})$\6
+$(\.{"I\ changed\ this\ one\ to\ zero."})$;\5
+$\\{int\_error}(\\{cur\_val})$;\5
+$\\{cur\_val}\K0$;\6
+\&{end};\2\6
+\&{end};\par
+\As445, 446, 447, 448\ETs1399.
+\U420.\fi
+
+\M445. \P$\X444:Declare procedures that scan restricted classes of integers\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{scan\_char\_num};\2\6
+\&{begin} \37\\{scan\_int};\6
+\&{if} $\R\\{is\_char\_ascii}(\\{cur\_val})\W\R\\{is\_char\_kanji}(\\{cur%
+\_val})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Bad\ character\ code"})$;\5
+$\\{help2}(\.{"A\ character\ number\ must\ be\ between\ 0\ and\ 255,\ or\ KANJI%
+\ code."})$\6
+$(\.{"I\ changed\ this\ one\ to\ zero."})$;\5
+$\\{int\_error}(\\{cur\_val})$;\5
+$\\{cur\_val}\K0$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M446. While we're at it, we might as well deal with similar routines that
+will be needed later.
+
+\Y\P$\4\X444:Declare procedures that scan restricted classes of integers\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{scan\_four\_bit\_int};\2\6
+\&{begin} \37\\{scan\_int};\6
+\&{if} $(\\{cur\_val}<0)\V(\\{cur\_val}>15)$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Bad\ number"})$;\5
+$\\{help2}(\.{"Since\ I\ expected\ to\ read\ a\ number\ between\ 0\ and\
+15,"})$\6
+$(\.{"I\ changed\ this\ one\ to\ zero."})$;\5
+$\\{int\_error}(\\{cur\_val})$;\5
+$\\{cur\_val}\K0$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M447. \P$\X444:Declare procedures that scan restricted classes of integers\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{scan\_fifteen\_bit\_int};\2\6
+\&{begin} \37\\{scan\_int};\6
+\&{if} $(\\{cur\_val}<0)\V(\\{cur\_val}>\O{77777})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Bad\ mathchar"})$;\5
+$\\{help2}(\.{"A\ mathchar\ number\ must\ be\ between\ 0\ and\ 32767."})$\6
+$(\.{"I\ changed\ this\ one\ to\ zero."})$;\5
+$\\{int\_error}(\\{cur\_val})$;\5
+$\\{cur\_val}\K0$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M448. \P$\X444:Declare procedures that scan restricted classes of integers\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{scan\_twenty\_seven\_bit\_int};\2\6
+\&{begin} \37\\{scan\_int};\6
+\&{if} $(\\{cur\_val}<0)\V(\\{cur\_val}>\O{777777777})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Bad\ delimiter\ code"})$;\5
+$\\{help2}(\.{"A\ numeric\ delimiter\ code\ must\ be\ between\ 0\ and\ 2\^\{27%
+\}-1."})$\6
+$(\.{"I\ changed\ this\ one\ to\ zero."})$;\5
+$\\{int\_error}(\\{cur\_val})$;\5
+$\\{cur\_val}\K0$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M449. An integer number can be preceded by any number of spaces and `\.+' or
+`\.-' signs. Then comes either a decimal constant (i.e., radix 10), an
+octal constant (i.e., radix 8, preceded by~\.\'), a hexadecimal constant
+(radix 16, preceded by~\."), an alphabetic constant (preceded by~\.\`), or
+an internal variable. After scanning is complete,
+\\{cur\_val} will contain the answer, which must be at most
+$2^{31}-1=2147483647$ in absolute value. The value of \\{radix} is set to
+10, 8, or 16 in the cases of decimal, octal, or hexadecimal constants,
+otherwise \\{radix} is set to zero. An optional space follows a constant.
+
+\Y\P\D \37$\\{octal\_token}=\\{other\_token}+\.{"\'"}$\C{apostrophe, indicates
+an octal constant}\par
+\P\D \37$\\{hex\_token}=\\{other\_token}+\.{""}\.{""}$\C{double quote,
+indicates a hex constant}\par
+\P\D \37$\\{alpha\_token}=\\{other\_token}+\.{"\`"}$\C{reverse apostrophe,
+precedes alpha constants}\par
+\P\D \37$\\{point\_token}=\\{other\_token}+\.{"."}$\C{decimal point}\par
+\P\D \37$\\{continental\_point\_token}=\\{other\_token}+\.{","}$\C{decimal
+point, Eurostyle}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{radix}: \37\\{small\_number};\C{\\{scan\_int} sets this to 8, 10, 16, or
+zero}\par
+\fi
+
+\M450. We initialize the following global variables just in case \\{expand}
+comes into action before any of the basic scanning routines has assigned
+them a value.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{cur\_val}\K0$;\5
+$\\{cur\_val\_level}\K\\{int\_val}$;\5
+$\\{radix}\K0$;\5
+$\\{cur\_order}\K\\{normal}$;\par
+\fi
+
+\M451. The \\{scan\_int} routine is used also to scan the integer part of a
+fraction; for example, the `\.3' in `\.{3.14159}' will be found by
+\\{scan\_int}. The \\{scan\_dimen} routine assumes that $\\{cur\_tok}=\\{point%
+\_token}$
+after the integer part of such a fraction has been scanned by \\{scan\_int},
+and that the decimal point has been backed up to be scanned again.
+
+\Y\P\4\&{procedure}\1\  \37\\{scan\_int};\C{sets \\{cur\_val} to an integer}\6
+\4\&{label} \37\\{done};\6
+\4\&{var} \37\\{negative}: \37\\{boolean};\C{should the answer be negated?}\6
+\|m: \37\\{integer};\C{$\hbox{$2^{31}$}\mathbin{\&{div}}\\{radix}$, the
+threshold of danger}\6
+\|d: \37\\{small\_number};\C{the digit just scanned}\6
+\\{vacuous}: \37\\{boolean};\C{have no digits appeared?}\6
+\\{OK\_so\_far}: \37\\{boolean};\C{has an error message been issued?}\2\6
+\&{begin} \37$\\{radix}\K0$;\5
+$\\{OK\_so\_far}\K\\{true}$;\6
+\X452:Get the next non-blank non-sign token; set \\{negative} appropriately\X;\6
+\&{if} $\\{cur\_tok}=\\{alpha\_token}$ \1\&{then}\5
+\X453:Scan an alphabetic character code into \\{cur\_val}\X\6
+\4\&{else} \&{if} $(\\{cur\_cmd}\G\\{min\_internal})\W(\\{cur\_cmd}\L\\{max%
+\_internal})$ \1\&{then}\5
+$\\{scan\_something\_internal}(\\{int\_val},\39\\{false})$\6
+\4\&{else} \X455:Scan a numeric constant\X;\2\2\6
+\&{if} $\\{negative}$ \1\&{then}\5
+$\\{negate}(\\{cur\_val})$;\2\6
+\&{end};\par
+\fi
+
+\M452. \P$\X452:Get the next non-blank non-sign token; set \\{negative}
+appropriately\X\S$\6
+$\\{negative}\K\\{false}$;\6
+\1\&{repeat} \37\X417:Get the next non-blank non-call token\X;\6
+\&{if} $\\{cur\_tok}=\\{other\_token}+\.{"-"}$ \1\&{then}\6
+\&{begin} \37$\\{negative}\K\R\\{negative}$;\5
+$\\{cur\_tok}\K\\{other\_token}+\.{"+"}$;\6
+\&{end};\2\6
+\4\&{until}\5
+$\\{cur\_tok}\I\\{other\_token}+\.{"+"}$\2\par
+\Us451, 459\ETs472.\fi
+
+\M453. A space is ignored after an alphabetic character constant, so that
+such constants behave like numeric ones.
+
+\Y\P$\4\X453:Scan an alphabetic character code into \\{cur\_val}\X\S$\6
+\&{begin} \37\\{get\_token};\C{suppress macro expansion}\6
+\&{if} $\\{cur\_tok}<\\{cs\_token\_flag}$ \1\&{then}\6
+\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=%
+\\{other\_kchar})$ \1\&{then}\C{\\{wchar\_token}}\6
+\&{begin} \37$\\{skip\_mode}\K\\{false}$;\5
+$\\{cur\_val}\K\\{tonum}(\\{cur\_chr})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{cur\_val}\K\\{cur\_chr}$;\6
+\&{if} $\\{cur\_cmd}\L\\{right\_brace}$ \1\&{then}\6
+\&{if} $\\{cur\_cmd}=\\{right\_brace}$ \1\&{then}\5
+$\\{incr}(\\{align\_state})$\6
+\4\&{else} $\\{decr}(\\{align\_state})$;\2\2\6
+\&{end}\2\6
+\4\&{else} \&{if} $\\{cur\_tok}<\\{cs\_token\_flag}+\\{single\_base}$ \1%
+\&{then}\5
+$\\{cur\_val}\K\\{cur\_tok}-\\{cs\_token\_flag}-\\{active\_base}$\6
+\4\&{else} $\\{cur\_val}\K\\{cur\_tok}-\\{cs\_token\_flag}-\\{single\_base}$;\2%
+\2\6
+\&{if} $(\\{cur\_val}>255)\W((\\{cur\_cmd}<\\{kanji})\V(\\{cur\_cmd}>\\{max%
+\_char\_code}))$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Improper\ alphabetic\ or\ KANJI\ constant"})$;%
+\5
+$\\{help2}(\.{"A\ one-character\ control\ sequence\ belongs\ after\ a\ \`\
+mark."})$\6
+$(\.{"So\ I\'m\ essentially\ inserting\ \\0\ here."})$;\5
+$\\{cur\_val}\K\.{"0"}$;\5
+\\{back\_error};\6
+\&{end}\6
+\4\&{else} \X454:Scan an optional space\X;\2\6
+$\\{skip\_mode}\K\\{true}$;\6
+\&{end}\par
+\U451.\fi
+
+\M454. \P$\X454:Scan an optional space\X\S$\6
+\&{begin} \37\\{get\_x\_token};\6
+\&{if} $\\{cur\_cmd}\I\\{spacer}$ \1\&{then}\5
+\\{back\_input};\2\6
+\&{end}\par
+\Us453, 459, 466\ETs1212.\fi
+
+\M455. \P$\X455:Scan a numeric constant\X\S$\6
+\&{begin} \37$\\{radix}\K10$;\5
+$\|m\K214748364$;\6
+\&{if} $\\{cur\_tok}=\\{octal\_token}$ \1\&{then}\6
+\&{begin} \37$\\{radix}\K8$;\5
+$\|m\K\O{2000000000}$;\5
+\\{get\_x\_token};\6
+\&{end}\6
+\4\&{else} \&{if} $\\{cur\_tok}=\\{hex\_token}$ \1\&{then}\6
+\&{begin} \37$\\{radix}\K16$;\5
+$\|m\K\O{1000000000}$;\5
+\\{get\_x\_token};\6
+\&{end};\2\2\6
+$\\{vacuous}\K\\{true}$;\5
+$\\{cur\_val}\K0$;\6
+\X456:Accumulate the constant until \\{cur\_tok} is not a suitable digit\X;\6
+\&{if} $\\{vacuous}$ \1\&{then}\5
+\X457:Express astonishment that no number was here\X\6
+\4\&{else} \&{if} $\\{cur\_cmd}\I\\{spacer}$ \1\&{then}\5
+\\{back\_input};\2\2\6
+\&{end}\par
+\U451.\fi
+
+\M456. \P\D \37$\\{infinity}\S\O{17777777777}$\C{the largest positive value
+that \TeX\ knows}\par
+\P\D \37$\\{zero\_token}=\\{other\_token}+\.{"0"}$\C{zero, the smallest digit}%
+\par
+\P\D \37$\\{A\_token}=\\{letter\_token}+\.{"A"}$\C{the smallest special hex
+digit}\par
+\P\D \37$\\{other\_A\_token}=\\{other\_token}+\.{"A"}$\C{special hex digit of
+type \\{other\_char}}\par
+\Y\P$\4\X456:Accumulate the constant until \\{cur\_tok} is not a suitable digit%
+\X\S$\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $(\\{cur\_tok}<\\{zero\_token}+\\{radix})\W(%
+\\{cur\_tok}\G\\{zero\_token})\W(\\{cur\_tok}\L\\{zero\_token}+9)$ \1\&{then}\5
+$\|d\K\\{cur\_tok}-\\{zero\_token}$\6
+\4\&{else} \&{if} $\\{radix}=16$ \1\&{then}\6
+\&{if} $(\\{cur\_tok}\L\\{A\_token}+5)\W(\\{cur\_tok}\G\\{A\_token})$ \1%
+\&{then}\5
+$\|d\K\\{cur\_tok}-\\{A\_token}+10$\6
+\4\&{else} \&{if} $(\\{cur\_tok}\L\\{other\_A\_token}+5)\W(\\{cur\_tok}\G%
+\\{other\_A\_token})$ \1\&{then}\5
+$\|d\K\\{cur\_tok}-\\{other\_A\_token}+10$\6
+\4\&{else} \&{goto} \37\\{done}\2\2\6
+\4\&{else} \&{goto} \37\\{done};\2\2\6
+$\\{vacuous}\K\\{false}$;\6
+\&{if} $(\\{cur\_val}\G\|m)\W((\\{cur\_val}>\|m)\V(\|d>7)\V(\\{radix}\I10))$ \1%
+\&{then}\6
+\&{begin} \37\&{if} $\\{OK\_so\_far}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Number\ too\ big"})$;\5
+$\\{help2}(\.{"I\ can\ only\ go\ up\ to\ 2147483647=\'17777777777="}%
+\.{"7FFFFFFF,"})$\6
+$(\.{"so\ I\'m\ using\ that\ number\ instead\ of\ yours."})$;\5
+\\{error};\5
+$\\{cur\_val}\K\\{infinity}$;\5
+$\\{OK\_so\_far}\K\\{false}$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} $\\{cur\_val}\K\\{cur\_val}\ast\\{radix}+\|d$;\2\6
+\\{get\_x\_token};\6
+\&{end};\2\6
+\4\\{done}: \37\par
+\U455.\fi
+
+\M457. \P$\X457:Express astonishment that no number was here\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ number,\ treated\ as\ zero"})$;\5
+$\\{help3}(\.{"A\ number\ should\ have\ been\ here;\ I\ inserted\ \`0\'."})$\6
+$(\.{"(If\ you\ can\'t\ figure\ out\ why\ I\ needed\ to\ see\ a\ number,"})$\6
+$(\.{"look\ up\ \`weird\ error\'\ in\ the\ index\ to\ The\ TeXbook.)"})$;\5
+\\{back\_error};\6
+\&{end}\par
+\U455.\fi
+
+\M458. The \\{scan\_dimen} routine is similar to \\{scan\_int}, but it sets %
+\\{cur\_val} to
+a \\{scaled} value, i.e., an integral number of sp. One of its main tasks
+is therefore to interpret the abbreviations for various kinds of units and
+to convert measurements to scaled points.
+
+There are three parameters: \\{mu} is \\{true} if the finite units must be
+`\.{mu}', while \\{mu} is \\{false} if `\.{mu}' units are disallowed;
+\\{inf} is \\{true} if the infinite units `\.{fil}', `\.{fill}', `\.{filll}'
+are permitted; and \\{shortcut} is \\{true} if \\{cur\_val} already contains
+an integer and only the units need to be considered.
+
+The order of infinity that was found in the case of infinite glue is returned
+in the global variable \\{cur\_order}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_order}: \37\\{glue\_ord};\C{order of infinity found by \\{scan%
+\_dimen}}\par
+\fi
+
+\M459. Constructions like `\.{-\'77 pt}' are legal dimensions, so \\{scan%
+\_dimen}
+may begin with \\{scan\_int}. This explains why it is convenient to use
+\\{scan\_int} also for the integer part of a decimal fraction.
+
+Several branches of \\{scan\_dimen} work with \\{cur\_val} as an integer and
+with an auxiliary fraction \|f, so that the actual quantity of interest is
+$\\{cur\_val}+\|f/2^{16}$. At the end of the routine, this ``unpacked''
+representation is put into the single word \\{cur\_val}, which suddenly
+switches significance from \\{integer} to \\{scaled}.
+
+\Y\P\D \37$\\{attach\_fraction}=88$\C{go here to pack \\{cur\_val} and \|f into
+\\{cur\_val}}\par
+\P\D \37$\\{attach\_sign}=89$\C{go here when \\{cur\_val} is correct except
+perhaps for sign}\par
+\P\D \37$\\{scan\_normal\_dimen}\S\\{scan\_dimen}(\\{false},\39\\{false},\39%
+\\{false})$\par
+\Y\P\4\&{procedure}\1\  \37$\\{scan\_dimen}(\\{mu},\39\\{inf},\39\\{shortcut}:%
+\\{boolean})$;\C{sets \\{cur\_val} to a dimension}\6
+\4\&{label} \37$\\{done},\39\\{done1},\39\\{done2},\39\\{found},\39\\{not%
+\_found},\39\\{attach\_fraction},\39\\{attach\_sign}$;\6
+\4\&{var} \37\\{negative}: \37\\{boolean};\C{should the answer be negated?}\6
+\|f: \37\\{integer};\C{numerator of a fraction whose denominator is $2^{16}$}\6
+\X461:Local variables for dimension calculations\X\2\6
+\&{begin} \37$\|f\K0$;\5
+$\\{arith\_error}\K\\{false}$;\5
+$\\{cur\_order}\K\\{normal}$;\5
+$\\{negative}\K\\{false}$;\6
+\&{if} $\R\\{shortcut}$ \1\&{then}\6
+\&{begin} \37\X452:Get the next non-blank non-sign token; set \\{negative}
+appropriately\X;\6
+\&{if} $(\\{cur\_cmd}\G\\{min\_internal})\W(\\{cur\_cmd}\L\\{max\_internal})$ %
+\1\&{then}\5
+\X460:Fetch an internal dimension and \&{goto} \\{attach\_sign}, or fetch an
+internal integer\X\6
+\4\&{else} \&{begin} \37\\{back\_input};\6
+\&{if} $\\{cur\_tok}=\\{continental\_point\_token}$ \1\&{then}\5
+$\\{cur\_tok}\K\\{point\_token}$;\2\6
+\&{if} $\\{cur\_tok}\I\\{point\_token}$ \1\&{then}\5
+\\{scan\_int}\6
+\4\&{else} \&{begin} \37$\\{radix}\K10$;\5
+$\\{cur\_val}\K0$;\6
+\&{end};\2\6
+\&{if} $\\{cur\_tok}=\\{continental\_point\_token}$ \1\&{then}\5
+$\\{cur\_tok}\K\\{point\_token}$;\2\6
+\&{if} $(\\{radix}=10)\W(\\{cur\_tok}=\\{point\_token})$ \1\&{then}\5
+\X463:Scan decimal fraction\X;\2\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{cur\_val}<0$ \1\&{then}\C{in this case $\|f=0$}\6
+\&{begin} \37$\\{negative}\K\R\\{negative}$;\5
+$\\{negate}(\\{cur\_val})$;\6
+\&{end};\2\6
+\X464:Scan units and set \\{cur\_val} to $x\cdot(\\{cur\_val}+f/2^{16})$, where
+there are \|x sp per unit; \&{goto} \\{attach\_sign} if the units are internal%
+\X;\6
+\X454:Scan an optional space\X;\6
+\4\\{attach\_sign}: \37\&{if} $\\{arith\_error}\V(\\{abs}(\\{cur\_val})\G%
+\O{10000000000})$ \1\&{then}\5
+\X471:Report that this dimension is out of range\X;\2\6
+\&{if} $\\{negative}$ \1\&{then}\5
+$\\{negate}(\\{cur\_val})$;\2\6
+\&{end};\par
+\fi
+
+\M460. \P$\X460:Fetch an internal dimension and \&{goto} \\{attach\_sign}, or
+fetch an internal integer\X\S$\6
+\&{if} $\\{mu}$ \1\&{then}\6
+\&{begin} \37$\\{scan\_something\_internal}(\\{mu\_val},\39\\{false})$;\5
+\X462:Coerce glue to a dimension\X;\6
+\&{if} $\\{cur\_val\_level}=\\{mu\_val}$ \1\&{then}\5
+\&{goto} \37\\{attach\_sign};\2\6
+\&{if} $\\{cur\_val\_level}\I\\{int\_val}$ \1\&{then}\5
+\\{mu\_error};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{scan\_something\_internal}(\\{dimen\_val},\39%
+\\{false})$;\6
+\&{if} $\\{cur\_val\_level}=\\{dimen\_val}$ \1\&{then}\5
+\&{goto} \37\\{attach\_sign};\2\6
+\&{end}\2\par
+\U459.\fi
+
+\M461. \P$\X461:Local variables for dimension calculations\X\S$\6
+\4$\\{num},\39\\{denom}$: \37$1\to65536$;\C{conversion ratio for the scanned
+units}\6
+\4$\|k,\39\\{kk}$: \37\\{small\_number};\C{number of digits in a decimal
+fraction}\6
+\4$\|p,\39\|q$: \37\\{pointer};\C{top of decimal digit stack}\6
+\4\|v: \37\\{scaled};\C{an internal dimension}\6
+\4\\{save\_cur\_val}: \37\\{integer};\C{temporary storage of \\{cur\_val}}\par
+\A1417.
+\U459.\fi
+
+\M462. The following code is executed when \\{scan\_something\_internal} was
+called asking for \\{mu\_val}, when we really wanted a ``mudimen'' instead
+of ``muglue.''
+
+\Y\P$\4\X462:Coerce glue to a dimension\X\S$\6
+\&{if} $\\{cur\_val\_level}\G\\{glue\_val}$ \1\&{then}\6
+\&{begin} \37$\|v\K\\{width}(\\{cur\_val})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_val})$;\5
+$\\{cur\_val}\K\|v$;\6
+\&{end}\2\par
+\Us460\ET466.\fi
+
+\M463. When the following code is executed, we have $\\{cur\_tok}=\\{point%
+\_token}$, but this
+token has been backed up using \\{back\_input}; we must first discard it.
+
+It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
+Let's hope people don't use that fact.
+
+\Y\P$\4\X463:Scan decimal fraction\X\S$\6
+\&{begin} \37$\|k\K0$;\5
+$\|p\K\\{null}$;\5
+\\{get\_token};\C{\\{point\_token} is being re-scanned}\6
+\~ \1\&{loop}\ \&{begin} \37\\{get\_x\_token};\6
+\&{if} $(\\{cur\_tok}>\\{zero\_token}+9)\V(\\{cur\_tok}<\\{zero\_token})$ \1%
+\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\&{if} $\|k<17$ \1\&{then}\C{digits for $\|k\G17$ cannot affect the result}\6
+\&{begin} \37$\|q\K\\{get\_avail}$;\5
+$\\{link}(\|q)\K\|p$;\5
+$\\{info}(\|q)\K\\{cur\_tok}-\\{zero\_token}$;\5
+$\|p\K\|q$;\5
+$\\{incr}(\|k)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{done1}: \37\&{for} $\\{kk}\K\|k\mathrel{\&{downto}}1$ \1\&{do}\6
+\&{begin} \37$\\{dig}[\\{kk}-1]\K\\{info}(\|p)$;\5
+$\|q\K\|p$;\5
+$\|p\K\\{link}(\|p)$;\5
+$\\{free\_avail}(\|q)$;\6
+\&{end};\2\6
+$\|f\K\\{round\_decimals}(\|k)$;\6
+\&{if} $\\{cur\_cmd}\I\\{spacer}$ \1\&{then}\5
+\\{back\_input};\2\6
+\&{end}\par
+\U459.\fi
+
+\M464. Now comes the harder part: At this point in the program, \\{cur\_val} is
+a
+nonnegative integer and $f/2^{16}$ is a nonnegative fraction less than 1;
+we want to multiply the sum of these two quantities by the appropriate
+factor, based on the specified units, in order to produce a \\{scaled}
+result, and we want to do the calculation with fixed point arithmetic that
+does not overflow.
+
+\Y\P$\4\X464:Scan units and set \\{cur\_val} to $x\cdot(\\{cur%
+\_val}+f/2^{16})$, where there are \|x sp per unit; \&{goto} \\{attach\_sign}
+if the units are internal\X\S$\6
+\&{if} $\\{inf}$ \1\&{then}\5
+\X465:Scan for \(f)\.{fil} units; \&{goto} \\{attach\_fraction} if found\X;\2\6
+\X466:Scan for \(u)units that are internal dimensions; \&{goto} \\{attach%
+\_sign} with \\{cur\_val} set if found\X;\6
+\&{if} $\\{mu}$ \1\&{then}\5
+\X467:Scan for \(m)\.{mu} units and \&{goto} \\{attach\_fraction}\X;\2\6
+\&{if} $\\{scan\_keyword}(\.{"true"})$ \1\&{then}\5
+\X468:Adjust \(f)for the magnification ratio\X;\2\6
+\&{if} $\\{scan\_keyword}(\.{"pt"})$ \1\&{then}\5
+\&{goto} \37\\{attach\_fraction};\C{the easy case}\2\6
+\X469:Scan for \(a)all other units and adjust \\{cur\_val} and \|f accordingly;
+\&{goto} \\{done} in the case of scaled points\X;\6
+\4\\{attach\_fraction}: \37\&{if} $\\{cur\_val}\G\O{40000}$ \1\&{then}\5
+$\\{arith\_error}\K\\{true}$\6
+\4\&{else} $\\{cur\_val}\K\\{cur\_val}\ast\\{unity}+\|f$;\2\6
+\4\\{done}: \37\par
+\U459.\fi
+
+\M465. A specification like `\.{filllll}' or `\.{fill L L L}' will lead to two
+error messages (one for each additional keyword \.{"l"}).
+
+\Y\P$\4\X465:Scan for \(f)\.{fil} units; \&{goto} \\{attach\_fraction} if found%
+\X\S$\6
+\&{if} $\\{scan\_keyword}(\.{"fil"})$ \1\&{then}\6
+\&{begin} \37$\\{cur\_order}\K\\{fil}$;\6
+\&{while} $\\{scan\_keyword}(\.{"l"})$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{cur\_order}=\\{filll}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Illegal\ unit\ of\ measure\ ("})$;\5
+$\\{print}(\.{"replaced\ by\ filll)"})$;\5
+$\\{help1}(\.{"I\ dddon\'t\ go\ any\ higher\ than\ filll."})$;\5
+\\{error};\6
+\&{end}\6
+\4\&{else} $\\{incr}(\\{cur\_order})$;\2\6
+\&{end};\2\6
+\&{goto} \37\\{attach\_fraction};\6
+\&{end}\2\par
+\U464.\fi
+
+\M466. \P$\X466:Scan for \(u)units that are internal dimensions; \&{goto} %
+\\{attach\_sign} with \\{cur\_val} set if found\X\S$\6
+$\\{save\_cur\_val}\K\\{cur\_val}$;\5
+\X417:Get the next non-blank non-call token\X;\6
+\&{if} $(\\{cur\_cmd}<\\{min\_internal})\V(\\{cur\_cmd}>\\{max\_internal})$ \1%
+\&{then}\5
+\\{back\_input}\6
+\4\&{else} \&{begin} \37\&{if} $\\{mu}$ \1\&{then}\6
+\&{begin} \37$\\{scan\_something\_internal}(\\{mu\_val},\39\\{false})$;\5
+\X462:Coerce glue to a dimension\X;\6
+\&{if} $\\{cur\_val\_level}\I\\{mu\_val}$ \1\&{then}\5
+\\{mu\_error};\2\6
+\&{end}\6
+\4\&{else} $\\{scan\_something\_internal}(\\{dimen\_val},\39\\{false})$;\2\6
+$\|v\K\\{cur\_val}$;\5
+\&{goto} \37\\{found};\6
+\&{end};\2\6
+\&{if} $\\{mu}$ \1\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+\&{if} $\\{scan\_keyword}(\.{"em"})$ \1\&{then}\5
+$\|v\K(\X569:The em width for \\{cur\_font}\X)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"ex"})$ \1\&{then}\5
+$\|v\K(\X570:The x-height for \\{cur\_font}\X)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"zw"})$ \1\&{then}\5
+\X1418:The KANJI width for \\{cur\_jfont}\X\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"zh"})$ \1\&{then}\5
+\X1419:The KANJI height for \\{cur\_jfont}\X\6
+\4\&{else} \&{goto} \37\\{not\_found};\2\2\2\2\6
+\X454:Scan an optional space\X;\6
+\4\\{found}: \37$\\{cur\_val}\K\\{nx\_plus\_y}(\\{save\_cur\_val},\39\|v,\39%
+\\{xn\_over\_d}(\|v,\39\|f,\39\O{200000}))$;\5
+\&{goto} \37\\{attach\_sign};\6
+\4\\{not\_found}: \37\par
+\U464.\fi
+
+\M467. \P$\X467:Scan for \(m)\.{mu} units and \&{goto} \\{attach\_fraction}\X%
+\S$\6
+\&{if} $\\{scan\_keyword}(\.{"mu"})$ \1\&{then}\5
+\&{goto} \37\\{attach\_fraction}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Illegal\ unit\ of\ measure\ ("})$;\5
+$\\{print}(\.{"mu\ inserted)"})$;\5
+$\\{help4}(\.{"The\ unit\ of\ measurement\ in\ math\ glue\ must\ be\ mu."})$\6
+$(\.{"To\ recover\ gracefully\ from\ this\ error,\ it\'s\ best\ to"})$\6
+$(\.{"delete\ the\ erroneous\ units;\ e.g.,\ type\ \`2\'\ to\ delete"})$\6
+$(\.{"two\ letters.\ (See\ Chapter\ 27\ of\ The\ TeXbook.)"})$;\5
+\\{error};\5
+\&{goto} \37\\{attach\_fraction};\6
+\&{end}\2\par
+\U464.\fi
+
+\M468. \P$\X468:Adjust \(f)for the magnification ratio\X\S$\6
+\&{begin} \37\\{prepare\_mag};\6
+\&{if} $\\{mag}\I1000$ \1\&{then}\6
+\&{begin} \37$\\{cur\_val}\K\\{xn\_over\_d}(\\{cur\_val},\391000,\39\\{mag})$;\5
+$\|f\K(1000\ast\|f+\O{200000}\ast\\{remainder})\mathbin{\&{div}}\\{mag}$;\5
+$\\{cur\_val}\K\\{cur\_val}+(\|f\mathbin{\&{div}}\O{200000})$;\5
+$\|f\K\|f\mathbin{\&{mod}}\O{200000}$;\6
+\&{end};\2\6
+\&{end}\par
+\U464.\fi
+
+\M469. The necessary conversion factors can all be specified exactly as
+fractions whose numerator and denominator sum to 32768 or less.
+According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$;
+this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard
+in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980).
+
+\Y\P\D \37$\\{set\_conversion\_end}(\#)\S\\{denom}\K\#$; \6
+\&{end} \par
+\P\D \37$\\{set\_conversion}(\#)\S$\ \&{begin} \37$\\{num}\K\#$;\5
+\\{set\_conversion\_end}\par
+\Y\P$\4\X469:Scan for \(a)all other units and adjust \\{cur\_val} and \|f
+accordingly; \&{goto} \\{done} in the case of scaled points\X\S$\6
+\&{if} $\\{scan\_keyword}(\.{"in"})$ \1\&{then}\5
+$\\{set\_conversion}(7227)(100)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"pc"})$ \1\&{then}\5
+$\\{set\_conversion}(12)(1)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"cm"})$ \1\&{then}\5
+$\\{set\_conversion}(7227)(254)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"mm"})$ \1\&{then}\5
+$\\{set\_conversion}(7227)(2540)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"bp"})$ \1\&{then}\5
+$\\{set\_conversion}(7227)(7200)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"dd"})$ \1\&{then}\5
+$\\{set\_conversion}(1238)(1157)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"cc"})$ \1\&{then}\5
+$\\{set\_conversion}(14856)(1157)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"H"})$ \1\&{then}\5
+$\\{set\_conversion}(7227)(10160)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"Q"})$ \1\&{then}\5
+$\\{set\_conversion}(7227)(10160)$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"sp"})$ \1\&{then}\5
+\&{goto} \37\\{done}\6
+\4\&{else} \X470:Complain about unknown unit and \&{goto} \\{done2}\X;\2\2\2\2%
+\2\2\2\2\2\2\6
+$\\{cur\_val}\K\\{xn\_over\_d}(\\{cur\_val},\39\\{num},\39\\{denom})$;\5
+$\|f\K(\\{num}\ast\|f+\O{200000}\ast\\{remainder})\mathbin{\&{div}}\\{denom}$;\6
+$\\{cur\_val}\K\\{cur\_val}+(\|f\mathbin{\&{div}}\O{200000})$;\5
+$\|f\K\|f\mathbin{\&{mod}}\O{200000}$;\6
+\4\\{done2}: \37\par
+\U464.\fi
+
+\M470. \P$\X470:Complain about unknown unit and \&{goto} \\{done2}\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Illegal\ unit\ of\ measure\ ("})$;\5
+$\\{print}(\.{"pt\ inserted)"})$;\5
+$\\{help6}(\.{"Dimensions\ can\ be\ in\ units\ of\ em,\ ex,\ in,\ pt,\ pc,"})$\6
+$(\.{"cm,\ mm,\ dd,\ cc,\ bp,\ or\ sp;\ but\ yours\ is\ a\ new\ one!"})$\6
+$(\.{"I\'ll\ assume\ that\ you\ meant\ to\ say\ pt,\ for\ printer\'s\
+points."})$\6
+$(\.{"To\ recover\ gracefully\ from\ this\ error,\ it\'s\ best\ to"})$\6
+$(\.{"delete\ the\ erroneous\ units;\ e.g.,\ type\ \`2\'\ to\ delete"})$\6
+$(\.{"two\ letters.\ (See\ Chapter\ 27\ of\ The\ TeXbook.)"})$;\5
+\\{error};\5
+\&{goto} \37\\{done2};\6
+\&{end}\par
+\U469.\fi
+
+\M471. \P$\X471:Report that this dimension is out of range\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Dimension\ too\ large"})$;\5
+$\\{help2}(\.{"I\ can\'t\ work\ with\ sizes\ bigger\ than\ about\ 19\ feet."})$%
+\6
+$(\.{"Continue\ and\ I\'ll\ use\ the\ largest\ value\ I\ can."})$;\6
+\\{error};\5
+$\\{cur\_val}\K\\{max\_dimen}$;\5
+$\\{arith\_error}\K\\{false}$;\6
+\&{end}\par
+\U459.\fi
+
+\M472. The final member of \TeX's value-scanning trio is \\{scan\_glue}, which
+makes \\{cur\_val} point to a glue specification. The reference count of that
+glue spec will take account of the fact that \\{cur\_val} is pointing to~it.
+
+The \\{level} parameter should be either \\{glue\_val} or \\{mu\_val}.
+
+Since \\{scan\_dimen} was so much more complex than \\{scan\_int}, we might
+expect
+\\{scan\_glue} to be even worse. But fortunately, it is very simple, since
+most of the work has already been done.
+
+\Y\P\4\&{procedure}\1\  \37$\\{scan\_glue}(\\{level}:\\{small\_number})$;%
+\C{sets \\{cur\_val} to a glue spec pointer}\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\\{negative}: \37\\{boolean};\C{should the answer be negated?}\6
+\|q: \37\\{pointer};\C{new glue specification}\6
+\\{mu}: \37\\{boolean};\C{does $\\{level}=\\{mu\_val}$?}\2\6
+\&{begin} \37$\\{mu}\K(\\{level}=\\{mu\_val})$;\5
+\X452:Get the next non-blank non-sign token; set \\{negative} appropriately\X;\6
+\&{if} $(\\{cur\_cmd}\G\\{min\_internal})\W(\\{cur\_cmd}\L\\{max\_internal})$ %
+\1\&{then}\6
+\&{begin} \37$\\{scan\_something\_internal}(\\{level},\39\\{negative})$;\6
+\&{if} $\\{cur\_val\_level}\G\\{glue\_val}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{cur\_val\_level}\I\\{level}$ \1\&{then}\5
+\\{mu\_error};\2\6
+\&{return};\6
+\&{end};\2\6
+\&{if} $\\{cur\_val\_level}=\\{int\_val}$ \1\&{then}\5
+$\\{scan\_dimen}(\\{mu},\39\\{false},\39\\{true})$\6
+\4\&{else} \&{if} $\\{level}=\\{mu\_val}$ \1\&{then}\5
+\\{mu\_error};\2\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\\{back\_input};\5
+$\\{scan\_dimen}(\\{mu},\39\\{false},\39\\{false})$;\6
+\&{if} $\\{negative}$ \1\&{then}\5
+$\\{negate}(\\{cur\_val})$;\2\6
+\&{end};\2\6
+\X473:Create a new glue specification whose width is \\{cur\_val}; scan for its
+stretch and shrink components\X;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M473. \P$\X473:Create a new glue specification whose width is \\{cur\_val};
+scan for its stretch and shrink components\X\S$\6
+$\|q\K\\{new\_spec}(\\{zero\_glue})$;\5
+$\\{width}(\|q)\K\\{cur\_val}$;\6
+\&{if} $\\{scan\_keyword}(\.{"plus"})$ \1\&{then}\6
+\&{begin} \37$\\{scan\_dimen}(\\{mu},\39\\{true},\39\\{false})$;\5
+$\\{stretch}(\|q)\K\\{cur\_val}$;\5
+$\\{stretch\_order}(\|q)\K\\{cur\_order}$;\6
+\&{end};\2\6
+\&{if} $\\{scan\_keyword}(\.{"minus"})$ \1\&{then}\6
+\&{begin} \37$\\{scan\_dimen}(\\{mu},\39\\{true},\39\\{false})$;\5
+$\\{shrink}(\|q)\K\\{cur\_val}$;\5
+$\\{shrink\_order}(\|q)\K\\{cur\_order}$;\6
+\&{end};\2\6
+$\\{cur\_val}\K\|q$\par
+\U472.\fi
+
+\M474. Here's a similar procedure that returns a pointer to a rule node. This
+routine is called just after \TeX\ has seen \.{\\hrule} or \.{\\vrule};
+therefore \\{cur\_cmd} will be either \\{hrule} or \\{vrule}. The idea is to
+store
+the default rule dimensions in the node, then to override them if
+`\.{height}' or `\.{width}' or `\.{depth}' specifications are
+found (in any order).
+
+\Y\P\D \37$\\{default\_rule}=26214$\C{0.4\thinspace pt}\par
+\Y\P\4\&{function}\1\  \37\\{scan\_rule\_spec}: \37\\{pointer};\6
+\4\&{label} \37\\{reswitch};\6
+\4\&{var} \37\|q: \37\\{pointer};\C{the rule node being created}\2\6
+\&{begin} \37$\|q\K\\{new\_rule}$;\C{\\{width}, \\{depth}, and \\{height} all
+equal \\{null\_flag} now}\6
+\&{if} $\\{cur\_cmd}=\\{vrule}$ \1\&{then}\5
+$\\{width}(\|q)\K\\{default\_rule}$\6
+\4\&{else} \&{begin} \37$\\{height}(\|q)\K\\{default\_rule}$;\5
+$\\{depth}(\|q)\K0$;\6
+\&{end};\2\6
+\4\\{reswitch}: \37\&{if} $\\{scan\_keyword}(\.{"width"})$ \1\&{then}\6
+\&{begin} \37\\{scan\_normal\_dimen};\5
+$\\{width}(\|q)\K\\{cur\_val}$;\5
+\&{goto} \37\\{reswitch};\6
+\&{end};\2\6
+\&{if} $\\{scan\_keyword}(\.{"height"})$ \1\&{then}\6
+\&{begin} \37\\{scan\_normal\_dimen};\5
+$\\{height}(\|q)\K\\{cur\_val}$;\5
+\&{goto} \37\\{reswitch};\6
+\&{end};\2\6
+\&{if} $\\{scan\_keyword}(\.{"depth"})$ \1\&{then}\6
+\&{begin} \37\\{scan\_normal\_dimen};\5
+$\\{depth}(\|q)\K\\{cur\_val}$;\5
+\&{goto} \37\\{reswitch};\6
+\&{end};\2\6
+$\\{scan\_rule\_spec}\K\|q$;\6
+\&{end};\par
+\fi
+
+\N475.  \[27] Building token lists.
+The token lists for macros and for other things like \.{\\mark} and \.{%
+\\output}
+and \.{\\write} are produced by a procedure called \\{scan\_toks}.
+
+Before we get into the details of \\{scan\_toks}, let's consider a much
+simpler task, that of converting the current string into a token list.
+The \\{str\_toks} function does this; it classifies spaces as type \\{spacer}
+and everything else as type \\{other\_char}.
+
+The token list created by \\{str\_toks} begins at $\\{link}(\\{temp\_head})$
+and ends
+at the value \|p that is returned. (If $\|p=\\{temp\_head}$, the list is
+empty.)
+
+\Y\P\4\&{function}\1\  \37$\\{str\_toks}(\|b:\\{pool\_pointer})$: \37%
+\\{pointer};\C{changes the string $\\{str\_pool}[\|b\to\\{pool\_ptr}]$ to a
+token list}\6
+\4\&{var} \37\|p: \37\\{pointer};\C{tail of the token list}\6
+\|q: \37\\{pointer};\C{new node being added to the token list via \\{store\_new%
+\_token}}\6
+\|t: \37\\{halfword};\C{token being appended}\6
+\|k: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\2\6
+\&{begin} \37$\\{str\_room}(1)$;\5
+$\|p\K\\{temp\_head}$;\5
+$\\{link}(\|p)\K\\{null}$;\5
+$\|k\K\|b$;\6
+\&{while} $\|k<\\{pool\_ptr}$ \1\&{do}\6
+\&{begin} \37$\|t\K\\{so}(\\{str\_pool}[\|k])$;\6
+\&{if} $\\{multistrlen}(\\{ustringcast}(\\{str\_pool}),\39\\{pool\_ptr},\39%
+\|k)=2$ \1\&{then}\6
+\&{begin} \37$\|t\K\\{fromBUFF}(\\{ustringcast}(\\{str\_pool}),\39\\{pool%
+\_ptr},\39\|k)$;\5
+$\\{incr}(\|k)$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|t=\.{"\ "}$ \1\&{then}\5
+$\|t\K\\{space\_token}$\6
+\4\&{else} $\|t\K\\{other\_token}+\|t$;\2\2\6
+$\\{fast\_store\_new\_token}(\|t)$;\5
+$\\{incr}(\|k)$;\6
+\&{end};\2\6
+$\\{pool\_ptr}\K\|b$;\5
+$\\{str\_toks}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M476. The main reason for wanting \\{str\_toks} is the next function,
+\\{the\_toks}, which has similar input/output characteristics.
+
+This procedure is supposed to scan something like `\.{\\skip\\count12}',
+i.e., whatever can follow `\.{\\the}', and it constructs a token list
+containing something like `\.{-3.0pt minus 0.5fill}'.
+
+\Y\P\4\&{function}\1\  \37\\{the\_toks}: \37\\{pointer};\6
+\4\&{var} \37\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{holds \\{selector}
+setting}\6
+$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{used for copying a token list}\6
+\|b: \37\\{pool\_pointer};\C{base of temporary string}\2\6
+\&{begin} \37\\{get\_x\_token};\5
+$\\{scan\_something\_internal}(\\{tok\_val},\39\\{false})$;\6
+\&{if} $\\{cur\_val\_level}\G\\{ident\_val}$ \1\&{then}\5
+\X477:Copy the token list\X\6
+\4\&{else} \&{begin} \37$\\{old\_setting}\K\\{selector}$;\5
+$\\{selector}\K\\{new\_string}$;\5
+$\|b\K\\{pool\_ptr}$;\6
+\&{case} $\\{cur\_val\_level}$ \1\&{of}\6
+\4\\{int\_val}: \37$\\{print\_int}(\\{cur\_val})$;\6
+\4\\{dimen\_val}: \37\&{begin} \37$\\{print\_scaled}(\\{cur\_val})$;\5
+$\\{print}(\.{"pt"})$;\6
+\&{end};\6
+\4\\{glue\_val}: \37\&{begin} \37$\\{print\_spec}(\\{cur\_val},\39\.{"pt"})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_val})$;\6
+\&{end};\6
+\4\\{mu\_val}: \37\&{begin} \37$\\{print\_spec}(\\{cur\_val},\39\.{"mu"})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_val})$;\6
+\&{end};\2\6
+\&{end};\C{there are no other cases}\6
+$\\{selector}\K\\{old\_setting}$;\5
+$\\{the\_toks}\K\\{str\_toks}(\|b)$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M477. \P$\X477:Copy the token list\X\S$\6
+\&{begin} \37$\|p\K\\{temp\_head}$;\5
+$\\{link}(\|p)\K\\{null}$;\6
+\&{if} $\\{cur\_val\_level}=\\{ident\_val}$ \1\&{then}\5
+$\\{store\_new\_token}(\\{cs\_token\_flag}+\\{cur\_val})$\6
+\4\&{else} \&{if} $\\{cur\_val}\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\|r\K\\{link}(\\{cur\_val})$;\C{do not copy the reference count}\6
+\&{while} $\|r\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\\{fast\_store\_new\_token}(\\{info}(\|r))$;\5
+$\|r\K\\{link}(\|r)$;\6
+\&{end};\2\6
+\&{end};\2\2\6
+$\\{the\_toks}\K\|p$;\6
+\&{end}\par
+\U476.\fi
+
+\M478. Here's part of the \\{expand} subroutine that we are now ready to
+complete:
+
+\Y\P\4\&{procedure}\1\  \37\\{ins\_the\_toks};\2\6
+\&{begin} \37$\\{link}(\\{garbage})\K\\{the\_toks}$;\5
+$\\{ins\_list}(\\{link}(\\{temp\_head}))$;\6
+\&{end};\par
+\fi
+
+\M479. The primitives \.{\\number}, \.{\\romannumeral}, \.{\\string}, \.{%
+\\meaning},
+\.{\\fontname}, and \.{\\jobname} are defined as follows.
+
+\Y\P\D \37$\\{number\_code}=0$\C{command code for \.{\\number}}\par
+\P\D \37$\\{roman\_numeral\_code}=1$\C{command code for \.{\\romannumeral}}\par
+\P\D \37$\\{kansuji\_code}=2$\C{command code for \.{\\kansuji}}\par
+\P\D \37$\\{string\_code}=3$\C{command code for \.{\\string}}\par
+\P\D \37$\\{meaning\_code}=4$\C{command code for \.{\\meaning}}\par
+\P\D \37$\\{font\_name\_code}=5$\C{command code for \.{\\fontname}}\par
+\P\D \37$\\{euc\_code}=6$\C{command code for \.{\\euc}}\par
+\P\D \37$\\{sjis\_code}=7$\C{command code for \.{\\sjis}}\par
+\P\D \37$\\{jis\_code}=8$\C{command code for \.{\\jis}}\par
+\P\D \37$\\{kuten\_code}=9$\C{command code for \.{\\kuten}}\par
+\P\D \37$\\{ptex\_convert\_codes}=10$\C{end of \eTeX's command codes}\par
+\P\D \37$\\{job\_name\_code}=\\{ptex\_convert\_codes}$\C{command code for \.{%
+\\jobname}}\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"number"},\39\\{convert},\39\\{number\_code})$;\6
+$\\{primitive}(\.{"romannumeral"},\39\\{convert},\39\\{roman\_numeral\_code})$;%
+\6
+$\\{primitive}(\.{"string"},\39\\{convert},\39\\{string\_code})$;\6
+$\\{primitive}(\.{"meaning"},\39\\{convert},\39\\{meaning\_code})$;\6
+$\\{primitive}(\.{"fontname"},\39\\{convert},\39\\{font\_name\_code})$;\6
+$\\{primitive}(\.{"kansuji"},\39\\{convert},\39\\{kansuji\_code})$;\5
+$\\{primitive}(\.{"euc"},\39\\{convert},\39\\{euc\_code})$;\5
+$\\{primitive}(\.{"sjis"},\39\\{convert},\39\\{sjis\_code})$;\5
+$\\{primitive}(\.{"jis"},\39\\{convert},\39\\{jis\_code})$;\5
+$\\{primitive}(\.{"kuten"},\39\\{convert},\39\\{kuten\_code})$;\5
+$\\{primitive}(\.{"jobname"},\39\\{convert},\39\\{job\_name\_code})$;\par
+\fi
+
+\M480. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{convert}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{number\_code}: \37$\\{print\_esc}(\.{"number"})$;\6
+\4\\{roman\_numeral\_code}: \37$\\{print\_esc}(\.{"romannumeral"})$;\6
+\4\\{string\_code}: \37$\\{print\_esc}(\.{"string"})$;\6
+\4\\{meaning\_code}: \37$\\{print\_esc}(\.{"meaning"})$;\6
+\4\\{font\_name\_code}: \37$\\{print\_esc}(\.{"fontname"})$;\6
+\4\\{kansuji\_code}: \37$\\{print\_esc}(\.{"kansuji"})$;\6
+\4\\{euc\_code}: \37$\\{print\_esc}(\.{"euc"})$;\6
+\4\\{sjis\_code}: \37$\\{print\_esc}(\.{"sjis"})$;\6
+\4\\{jis\_code}: \37$\\{print\_esc}(\.{"jis"})$;\6
+\4\\{kuten\_code}: \37$\\{print\_esc}(\.{"kuten"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"jobname"})$\2\6
+\&{endcases};\par
+\fi
+
+\M481. The procedure \\{conv\_toks} uses \\{str\_toks} to insert the token list
+for \\{convert} functions into the scanner; `\.{\\outer}' control sequences
+are allowed to follow `\.{\\string}' and `\.{\\meaning}'.
+
+\Y\P\4\&{procedure}\1\  \37\\{conv\_toks};\6
+\4\&{var} \37\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{holds \\{selector}
+setting}\6
+\\{cx}: \37\\{KANJI\_code};\C{temporary register for KANJI}\6
+\|c: \37$\\{number\_code}\to\\{job\_name\_code}$;\C{desired type of conversion}%
+\6
+\\{save\_scanner\_status}: \37\\{small\_number};\C{\\{scanner\_status} upon
+entry}\6
+\|b: \37\\{pool\_pointer};\C{base of temporary string}\2\6
+\&{begin} \37$\|c\K\\{cur\_chr}$;\5
+\X482:Scan the argument for command \|c\X;\6
+$\\{old\_setting}\K\\{selector}$;\5
+$\\{selector}\K\\{new\_string}$;\5
+$\|b\K\\{pool\_ptr}$;\5
+\X483:Print the result of command \|c\X;\6
+$\\{selector}\K\\{old\_setting}$;\5
+$\\{link}(\\{garbage})\K\\{str\_toks}(\|b)$;\5
+$\\{ins\_list}(\\{link}(\\{temp\_head}))$;\6
+\&{end};\par
+\fi
+
+\M482. \P$\X482:Scan the argument for command \|c\X\S$\6
+$\\{KANJI}(\\{cx})\K0$;\6
+\&{case} $\|c$ \1\&{of}\6
+\4$\\{number\_code},\39\\{roman\_numeral\_code},\39\\{kansuji\_code},\39\\{euc%
+\_code},\39\\{sjis\_code},\39\\{jis\_code},\39\\{kuten\_code}$: \37\\{scan%
+\_int};\6
+\4$\\{string\_code},\39\\{meaning\_code}$: \37\&{begin} \37$\\{save\_scanner%
+\_status}\K\\{scanner\_status}$;\5
+$\\{scanner\_status}\K\\{normal}$;\5
+\\{get\_token};\6
+\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=%
+\\{other\_kchar})$ \1\&{then}\C{\\{wchar\_token}}\6
+$\\{KANJI}(\\{cx})\K\\{cur\_tok}$;\2\6
+$\\{scanner\_status}\K\\{save\_scanner\_status}$;\6
+\&{end};\6
+\4\\{font\_name\_code}: \37\\{scan\_font\_ident};\6
+\4\\{job\_name\_code}: \37\&{if} $\\{job\_name}=0$ \1\&{then}\5
+\\{open\_log\_file};\2\2\6
+\&{end}\C{there are no other cases}\par
+\U481.\fi
+
+\M483. \P$\X483:Print the result of command \|c\X\S$\6
+\&{case} $\|c$ \1\&{of}\6
+\4\\{number\_code}: \37$\\{print\_int}(\\{cur\_val})$;\6
+\4\\{roman\_numeral\_code}: \37$\\{print\_roman\_int}(\\{cur\_val})$;\6
+\4\\{jis\_code}: \37$\\{print\_int}(\\{fromJIS}(\\{cur\_val}))$;\6
+\4\\{euc\_code}: \37$\\{print\_int}(\\{fromEUC}(\\{cur\_val}))$;\6
+\4\\{sjis\_code}: \37$\\{print\_int}(\\{fromSJIS}(\\{cur\_val}))$;\6
+\4\\{kuten\_code}: \37$\\{print\_int}(\\{fromKUTEN}(\\{cur\_val}))$;\6
+\4\\{kansuji\_code}: \37$\\{print\_kansuji}(\\{cur\_val})$;\6
+\4\\{string\_code}: \37\&{if} $\\{cur\_cs}\I0$ \1\&{then}\5
+$\\{sprint\_cs}(\\{cur\_cs})$\6
+\4\&{else} \&{if} $\\{KANJI}(\\{cx})=0$ \1\&{then}\5
+$\\{print\_char}(\\{cur\_chr})$\6
+\4\&{else} $\\{print\_kanji}(\\{cx})$;\2\2\6
+\4\\{meaning\_code}: \37\\{print\_meaning};\6
+\4\\{font\_name\_code}: \37\&{begin} \37$\\{print}(\\{font\_name}[\\{cur%
+\_val}])$;\6
+\&{if} $\\{font\_size}[\\{cur\_val}]\I\\{font\_dsize}[\\{cur\_val}]$ \1\&{then}%
+\6
+\&{begin} \37$\\{print}(\.{"\ at\ "})$;\5
+$\\{print\_scaled}(\\{font\_size}[\\{cur\_val}])$;\5
+$\\{print}(\.{"pt"})$;\6
+\&{end};\2\6
+\&{end};\6
+\4\\{job\_name\_code}: \37$\\{print}(\\{job\_name})$;\2\6
+\&{end}\C{there are no other cases}\par
+\U481.\fi
+
+\M484. Now we can't postpone the difficulties any longer; we must bravely
+tackle
+\\{scan\_toks}. This function returns a pointer to the tail of a new token
+list, and it also makes \\{def\_ref} point to the reference count at the
+head of that list.
+
+There are two boolean parameters, \\{macro\_def} and \\{xpand}. If \\{macro%
+\_def}
+is true, the goal is to create the token list for a macro definition;
+otherwise the goal is to create the token list for some other \TeX\
+primitive: \.{\\mark}, \.{\\output}, \.{\\everypar}, \.{\\lowercase},
+\.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\write}, or
+\.{\\special}. In the latter cases a left brace must be scanned next; this
+left brace will not be part of the token list, nor will the matching right
+brace that comes at the end. If \\{xpand} is false, the token list will
+simply be copied from the input using \\{get\_token}. Otherwise all expandable
+tokens will be expanded until unexpandable tokens are left, except that
+the results of expanding `\.{\\the}' are not expanded further.
+If both \\{macro\_def} and \\{xpand} are true, the expansion applies
+only to the macro body (i.e., to the material following the first
+\\{left\_brace} character).
+
+The value of \\{cur\_cs} when \\{scan\_toks} begins should be the \\{eqtb}
+address of the control sequence to display in ``runaway'' error
+messages.
+
+\Y\P\4\&{function}\1\  \37$\\{scan\_toks}(\\{macro\_def},\39\\{xpand}:%
+\\{boolean})$: \37\\{pointer};\6
+\4\&{label} \37$\\{found},\39\\{done},\39\\{done1},\39\\{done2}$;\6
+\4\&{var} \37\|t: \37\\{halfword};\C{token representing the highest parameter
+number}\6
+\|s: \37\\{halfword};\C{saved token}\6
+\|p: \37\\{pointer};\C{tail of the token list being built}\6
+\|q: \37\\{pointer};\C{new node being added to the token list via \\{store\_new%
+\_token}}\6
+\\{unbalance}: \37\\{halfword};\C{number of unmatched left braces}\6
+\\{hash\_brace}: \37\\{halfword};\C{possible `\.{\#\{}' token}\2\6
+\&{begin} \37\&{if} $\\{macro\_def}$ \1\&{then}\5
+$\\{scanner\_status}\K\\{defining}$\ \&{else} $\\{scanner\_status}\K%
+\\{absorbing}$;\2\6
+$\\{warning\_index}\K\\{cur\_cs}$;\5
+$\\{def\_ref}\K\\{get\_avail}$;\5
+$\\{token\_ref\_count}(\\{def\_ref})\K\\{null}$;\5
+$\|p\K\\{def\_ref}$;\5
+$\\{hash\_brace}\K0$;\5
+$\|t\K\\{zero\_token}$;\6
+\&{if} $\\{macro\_def}$ \1\&{then}\5
+\X485:Scan and build the parameter part of the macro definition\X\6
+\4\&{else} \\{scan\_left\_brace};\C{remove the compulsory left brace}\2\6
+\X488:Scan and build the body of the token list; \&{goto} \\{found} when
+finished\X;\6
+\4\\{found}: \37$\\{scanner\_status}\K\\{normal}$;\6
+\&{if} $\\{hash\_brace}\I0$ \1\&{then}\5
+$\\{store\_new\_token}(\\{hash\_brace})$;\2\6
+$\\{scan\_toks}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M485. \P$\X485:Scan and build the parameter part of the macro definition\X\S$\6
+\&{begin} \37\~ \1\&{loop}\6
+\&{begin} \37\\{get\_token};\C{set \\{cur\_cmd}, \\{cur\_chr}, \\{cur\_tok}}\6
+\&{if} $\\{cur\_tok}<\\{right\_brace\_limit}$ \1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\&{if} $\\{cur\_cmd}=\\{mac\_param}$ \1\&{then}\5
+\X487:If the next character is a parameter number, make \\{cur\_tok} a %
+\\{match} token; but if it is a left brace, store `\\{left\_brace}, \\{end%
+\_match}', set \\{hash\_brace}, and \&{goto} \\{done}\X;\2\6
+$\\{store\_new\_token}(\\{cur\_tok})$;\6
+\&{end};\2\6
+\4\\{done1}: \37$\\{store\_new\_token}(\\{end\_match\_token})$;\6
+\&{if} $\\{cur\_cmd}=\\{right\_brace}$ \1\&{then}\5
+\X486:Express shock at the missing left brace; \&{goto} \\{found}\X;\2\6
+\4\\{done}: \37\&{end}\par
+\U484.\fi
+
+\M486. \P$\X486:Express shock at the missing left brace; \&{goto} \\{found}\X%
+\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ \{\ inserted"})$;\5
+$\\{incr}(\\{align\_state})$;\5
+$\\{help2}(\.{"Where\ was\ the\ left\ brace?\ You\ said\ something\ like\ \`%
+\\def\\a\}\',"})$\6
+$(\.{"which\ I\'m\ going\ to\ interpret\ as\ \`\\def\\a\{\}\'."})$;\5
+\\{error};\5
+\&{goto} \37\\{found};\6
+\&{end}\par
+\U485.\fi
+
+\M487. \P$\X487:If the next character is a parameter number, make \\{cur\_tok}
+a \\{match} token; but if it is a left brace, store `\\{left\_brace}, \\{end%
+\_match}', set \\{hash\_brace}, and \&{goto} \\{done}\X\S$\6
+\&{begin} \37$\|s\K\\{match\_token}+\\{cur\_chr}$;\5
+\\{get\_token};\6
+\&{if} $\\{cur\_cmd}=\\{left\_brace}$ \1\&{then}\6
+\&{begin} \37$\\{hash\_brace}\K\\{cur\_tok}$;\5
+$\\{store\_new\_token}(\\{cur\_tok})$;\5
+$\\{store\_new\_token}(\\{end\_match\_token})$;\5
+\&{goto} \37\\{done};\6
+\&{end};\2\6
+\&{if} $\|t=\\{zero\_token}+9$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"You\ already\ have\ nine\ parameters"})$;\5
+$\\{help1}(\.{"I\'m\ going\ to\ ignore\ the\ \#\ sign\ you\ just\ used."})$;\5
+\\{error};\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{incr}(\|t)$;\6
+\&{if} $\\{cur\_tok}\I\|t$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Parameters\ must\ be\ numbered\
+consecutively"})$;\5
+$\\{help2}(\.{"I\'ve\ inserted\ the\ digit\ you\ should\ have\ used\ after\ the%
+\ \#."})$\6
+$(\.{"Type\ \`1\'\ to\ delete\ what\ you\ did\ use."})$;\5
+\\{back\_error};\6
+\&{end};\2\6
+$\\{cur\_tok}\K\|s$;\6
+\&{end};\2\6
+\&{end}\par
+\U485.\fi
+
+\M488. \P$\X488:Scan and build the body of the token list; \&{goto} \\{found}
+when finished\X\S$\6
+$\\{unbalance}\K1$;\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{xpand}$ \1\&{then}\5
+\X489:Expand the next part of the input\X\6
+\4\&{else} \\{get\_token};\2\6
+\&{if} $\\{cur\_tok}<\\{right\_brace\_limit}$ \1\&{then}\6
+\&{if} $\\{cur\_cmd}<\\{right\_brace}$ \1\&{then}\5
+$\\{incr}(\\{unbalance})$\6
+\4\&{else} \&{begin} \37$\\{decr}(\\{unbalance})$;\6
+\&{if} $\\{unbalance}=0$ \1\&{then}\5
+\&{goto} \37\\{found};\2\6
+\&{end}\2\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{mac\_param}$ \1\&{then}\6
+\&{if} $\\{macro\_def}$ \1\&{then}\5
+\X490:Look for parameter number or \.{\#\#}\X;\2\2\2\6
+$\\{store\_new\_token}(\\{cur\_tok})$;\6
+\&{end}\2\par
+\U484.\fi
+
+\M489. Here we insert an entire token list created by \\{the\_toks} without
+expanding it further.
+
+\Y\P$\4\X489:Expand the next part of the input\X\S$\6
+\&{begin} \37\~ \1\&{loop}\6
+\&{begin} \37\\{get\_next};\6
+\&{if} $\\{cur\_cmd}\L\\{max\_command}$ \1\&{then}\5
+\&{goto} \37\\{done2};\2\6
+\&{if} $\\{cur\_cmd}\I\\{the}$ \1\&{then}\5
+\\{expand}\6
+\4\&{else} \&{begin} \37$\|q\K\\{the\_toks}$;\6
+\&{if} $\\{link}(\\{temp\_head})\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|p)\K\\{link}(\\{temp\_head})$;\5
+$\|p\K\|q$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{done2}: \37\\{x\_token}\6
+\&{end}\par
+\U488.\fi
+
+\M490. \P$\X490:Look for parameter number or \.{\#\#}\X\S$\6
+\&{begin} \37$\|s\K\\{cur\_tok}$;\6
+\&{if} $\\{xpand}$ \1\&{then}\5
+\\{get\_x\_token}\6
+\4\&{else} \\{get\_token};\2\6
+\&{if} $\\{cur\_cmd}\I\\{mac\_param}$ \1\&{then}\6
+\&{if} $(\\{cur\_tok}\L\\{zero\_token})\V(\\{cur\_tok}>\|t)$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Illegal\ parameter\ number\ in\ definition\ of%
+\ "})$;\5
+$\\{sprint\_cs}(\\{warning\_index})$;\5
+$\\{help3}(\.{"You\ meant\ to\ type\ \#\#\ instead\ of\ \#,\ right?"})$\6
+$(\.{"Or\ maybe\ a\ \}\ was\ forgotten\ somewhere\ earlier,\ and\ things"})$\6
+$(\.{"are\ all\ screwed\ up?\ I\'m\ going\ to\ assume\ that\ you\ meant\ \#%
+\#."})$;\5
+\\{back\_error};\5
+$\\{cur\_tok}\K\|s$;\6
+\&{end}\6
+\4\&{else} $\\{cur\_tok}\K\\{out\_param\_token}-\.{"0"}+\\{cur\_chr}$;\2\2\6
+\&{end}\par
+\U488.\fi
+
+\M491. Another way to create a token list is via the \.{\\read} command. The
+sixteen files potentially usable for reading appear in the following
+global variables. The value of $\\{read\_open}[\|n]$ will be \\{closed} if
+stream number \|n has not been opened or if it has been fully read;
+\\{just\_open} if an \.{\\openin} but not a \.{\\read} has been done;
+and \\{normal} if it is open and ready to read the next line.
+
+\Y\P\D \37$\\{closed}=2$\C{not open, or at end of file}\par
+\P\D \37$\\{just\_open}=1$\C{newly opened, first line not yet read}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{read\_file}: \37\&{array} $[0\to15]$ \1\&{of}\5
+\\{alpha\_file};\C{used for \.{\\read}}\2\6
+\4\\{read\_open}: \37\&{array} $[0\to16]$ \1\&{of}\5
+$\\{normal}\to\\{closed}$;\C{state of $\\{read\_file}[\|n]$}\2\par
+\fi
+
+\M492. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+\&{for} $\|k\K0\mathrel{\&{to}}16$ \1\&{do}\5
+$\\{read\_open}[\|k]\K\\{closed}$;\2\par
+\fi
+
+\M493. The \\{read\_toks} procedure constructs a token list like that for any
+macro definition, and makes \\{cur\_val} point to it. Parameter \|r points
+to the control sequence that will receive this token list.
+
+\Y\P\4\&{procedure}\1\  \37$\\{read\_toks}(\|n:\\{integer};\,\35\|r:%
+\\{pointer})$;\6
+\4\&{label} \37\\{done};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{tail of the token list}\6
+\|q: \37\\{pointer};\C{new node being added to the token list via \\{store\_new%
+\_token}}\6
+\|s: \37\\{integer};\C{saved value of \\{align\_state}}\6
+\|m: \37\\{small\_number};\C{stream number}\2\6
+\&{begin} \37$\\{scanner\_status}\K\\{defining}$;\5
+$\\{warning\_index}\K\|r$;\5
+$\\{def\_ref}\K\\{get\_avail}$;\5
+$\\{token\_ref\_count}(\\{def\_ref})\K\\{null}$;\5
+$\|p\K\\{def\_ref}$;\C{the reference count}\6
+$\\{store\_new\_token}(\\{end\_match\_token})$;\6
+\&{if} $(\|n<0)\V(\|n>15)$ \1\&{then}\5
+$\|m\K16$\ \&{else} $\|m\K\|n$;\2\6
+$\|s\K\\{align\_state}$;\5
+$\\{align\_state}\K1000000$;\C{disable tab marks, etc.}\6
+\1\&{repeat} \37\X494:Input and store tokens from the next line of the file\X;\6
+\4\&{until}\5
+$\\{align\_state}=1000000$;\2\6
+$\\{cur\_val}\K\\{def\_ref}$;\5
+$\\{scanner\_status}\K\\{normal}$;\5
+$\\{align\_state}\K\|s$;\6
+\&{end};\par
+\fi
+
+\M494. \P$\X494:Input and store tokens from the next line of the file\X\S$\6
+\\{begin\_file\_reading};\5
+$\\{name}\K\|m+1$;\6
+\&{if} $\\{read\_open}[\|m]=\\{closed}$ \1\&{then}\5
+\X495:Input for \.{\\read} from the terminal\X\6
+\4\&{else} \&{if} $\\{read\_open}[\|m]=\\{just\_open}$ \1\&{then}\5
+\X496:Input the first line of $\\{read\_file}[\|m]$\X\6
+\4\&{else} \X497:Input the next line of $\\{read\_file}[\|m]$\X;\2\2\6
+$\\{limit}\K\\{last}$;\6
+\&{if} $\\{end\_line\_char\_inactive}$ \1\&{then}\5
+$\\{decr}(\\{limit})$\6
+\4\&{else} $\\{buffer}[\\{limit}]\K\\{end\_line\_char}$;\2\6
+$\\{first}\K\\{limit}+1$;\5
+$\\{loc}\K\\{start}$;\5
+$\\{state}\K\\{new\_line}$;\6
+\~ \1\&{loop}\ \&{begin} \37\\{get\_token};\6
+\&{if} $\\{cur\_tok}=0$ \1\&{then}\5
+\&{goto} \37\\{done};\C{$\\{cur\_cmd}=\\{cur\_chr}=0$ will occur at the end of
+the line}\2\6
+\&{if} $\\{align\_state}<1000000$ \1\&{then}\C{unmatched `\.\}' aborts the
+line}\6
+\&{begin} \37\1\&{repeat} \37\\{get\_token};\6
+\4\&{until}\5
+$\\{cur\_tok}=0$;\2\6
+$\\{align\_state}\K1000000$;\5
+\&{goto} \37\\{done};\6
+\&{end};\2\6
+$\\{store\_new\_token}(\\{cur\_tok})$;\6
+\&{end};\2\6
+\4\\{done}: \37\\{end\_file\_reading}\par
+\U493.\fi
+
+\M495. Here we input on-line into the \\{buffer} array, prompting the user
+explicitly
+if $\|n\G0$.  The value of \|n is set negative so that additional prompts
+will not be given in the case of multi-line input.
+
+\Y\P$\4\X495:Input for \.{\\read} from the terminal\X\S$\6
+\&{if} $\\{interaction}>\\{nonstop\_mode}$ \1\&{then}\6
+\&{if} $\|n<0$ \1\&{then}\5
+$\\{prompt\_input}(\.{""})$\6
+\4\&{else} \&{begin} \37\\{wake\_up\_terminal};\5
+\\{print\_ln};\5
+$\\{sprint\_cs}(\|r)$;\5
+$\\{prompt\_input}(\.{"="})$;\5
+$\|n\K-1$;\6
+\&{end}\2\6
+\4\&{else} $\\{fatal\_error}(\.{"***\ (cannot\ \\read\ from\ terminal\ in\
+nonstop\ modes)"})$\2\par
+\U494.\fi
+
+\M496. The first line of a file must be treated specially, since \\{input\_ln}
+must be told not to start with \\{get}.
+
+\Y\P$\4\X496:Input the first line of $\\{read\_file}[\|m]$\X\S$\6
+\&{if} $\\{input\_ln}(\\{read\_file}[\|m],\39\\{false})$ \1\&{then}\5
+$\\{read\_open}[\|m]\K\\{normal}$\6
+\4\&{else} \&{begin} \37$\\{a\_close}(\\{read\_file}[\|m])$;\5
+$\\{read\_open}[\|m]\K\\{closed}$;\6
+\&{end}\2\par
+\U494.\fi
+
+\M497. An empty line is appended at the end of a \\{read\_file}.
+
+\Y\P$\4\X497:Input the next line of $\\{read\_file}[\|m]$\X\S$\6
+\&{begin} \37\&{if} $\R\\{input\_ln}(\\{read\_file}[\|m],\39\\{true})$ \1%
+\&{then}\6
+\&{begin} \37$\\{a\_close}(\\{read\_file}[\|m])$;\5
+$\\{read\_open}[\|m]\K\\{closed}$;\6
+\&{if} $\\{align\_state}\I1000000$ \1\&{then}\6
+\&{begin} \37\\{runaway};\5
+$\\{print\_err}(\.{"File\ ended\ within\ "})$;\5
+$\\{print\_esc}(\.{"read"})$;\5
+$\\{help1}(\.{"This\ \\read\ has\ unbalanced\ braces."})$;\5
+$\\{align\_state}\K1000000$;\5
+\\{error};\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end}\par
+\U494.\fi
+
+\N498.  \[28] Conditional processing.
+We consider now the way \TeX\ handles various kinds of \.{\\if} commands.
+
+\Y\P\D \37$\\{if\_char\_code}=0$\C{ `\.{\\if}' }\par
+\P\D \37$\\{if\_cat\_code}=1$\C{ `\.{\\ifcat}' }\par
+\P\D \37$\\{if\_int\_code}=2$\C{ `\.{\\ifnum}' }\par
+\P\D \37$\\{if\_dim\_code}=3$\C{ `\.{\\ifdim}' }\par
+\P\D \37$\\{if\_odd\_code}=4$\C{ `\.{\\ifodd}' }\par
+\P\D \37$\\{if\_vmode\_code}=5$\C{ `\.{\\ifvmode}' }\par
+\P\D \37$\\{if\_hmode\_code}=6$\C{ `\.{\\ifhmode}' }\par
+\P\D \37$\\{if\_mmode\_code}=7$\C{ `\.{\\ifmmode}' }\par
+\P\D \37$\\{if\_inner\_code}=8$\C{ `\.{\\ifinner}' }\par
+\P\D \37$\\{if\_void\_code}=9$\C{ `\.{\\ifvoid}' }\par
+\P\D \37$\\{if\_hbox\_code}=10$\C{ `\.{\\ifhbox}' }\par
+\P\D \37$\\{if\_vbox\_code}=11$\C{ `\.{\\ifvbox}' }\par
+\P\D \37$\\{ifx\_code}=12$\C{ `\.{\\ifx}' }\par
+\P\D \37$\\{if\_eof\_code}=13$\C{ `\.{\\ifeof}' }\par
+\P\D \37$\\{if\_true\_code}=14$\C{ `\.{\\iftrue}' }\par
+\P\D \37$\\{if\_false\_code}=15$\C{ `\.{\\iffalse}' }\par
+\P\D \37$\\{if\_case\_code}=16$\C{ `\.{\\ifcase}' }\Y\par
+\P\D \37$\\{if\_tdir\_code}=\\{if\_case\_code}+1$\C{ `\.{\\iftdir}' }\par
+\P\D \37$\\{if\_ydir\_code}=\\{if\_tdir\_code}+1$\C{ `\.{\\ifydir}' }\par
+\P\D \37$\\{if\_ddir\_code}=\\{if\_ydir\_code}+1$\C{ `\.{\\ifddir}' }\par
+\P\D \37$\\{if\_mdir\_code}=\\{if\_ddir\_code}+1$\C{ `\.{\\ifmdir}' }\par
+\P\D \37$\\{if\_tbox\_code}=\\{if\_mdir\_code}+1$\C{ `\.{\\iftbox}' }\par
+\P\D \37$\\{if\_ybox\_code}=\\{if\_tbox\_code}+1$\C{ `\.{\\ifybox}' }\par
+\P\D \37$\\{if\_dbox\_code}=\\{if\_ybox\_code}+1$\C{ `\.{\\ifdbox}' }\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"if"},\39\\{if\_test},\39\\{if\_char\_code})$;\5
+$\\{primitive}(\.{"ifcat"},\39\\{if\_test},\39\\{if\_cat\_code})$;\5
+$\\{primitive}(\.{"ifnum"},\39\\{if\_test},\39\\{if\_int\_code})$;\5
+$\\{primitive}(\.{"ifdim"},\39\\{if\_test},\39\\{if\_dim\_code})$;\5
+$\\{primitive}(\.{"ifodd"},\39\\{if\_test},\39\\{if\_odd\_code})$;\5
+$\\{primitive}(\.{"ifvmode"},\39\\{if\_test},\39\\{if\_vmode\_code})$;\5
+$\\{primitive}(\.{"ifhmode"},\39\\{if\_test},\39\\{if\_hmode\_code})$;\5
+$\\{primitive}(\.{"ifmmode"},\39\\{if\_test},\39\\{if\_mmode\_code})$;\5
+$\\{primitive}(\.{"ifinner"},\39\\{if\_test},\39\\{if\_inner\_code})$;\5
+$\\{primitive}(\.{"ifvoid"},\39\\{if\_test},\39\\{if\_void\_code})$;\5
+$\\{primitive}(\.{"ifhbox"},\39\\{if\_test},\39\\{if\_hbox\_code})$;\5
+$\\{primitive}(\.{"ifvbox"},\39\\{if\_test},\39\\{if\_vbox\_code})$;\5
+$\\{primitive}(\.{"ifx"},\39\\{if\_test},\39\\{ifx\_code})$;\5
+$\\{primitive}(\.{"ifeof"},\39\\{if\_test},\39\\{if\_eof\_code})$;\5
+$\\{primitive}(\.{"iftrue"},\39\\{if\_test},\39\\{if\_true\_code})$;\5
+$\\{primitive}(\.{"iffalse"},\39\\{if\_test},\39\\{if\_false\_code})$;\5
+$\\{primitive}(\.{"ifcase"},\39\\{if\_test},\39\\{if\_case\_code})$;\5
+$\\{primitive}(\.{"iftdir"},\39\\{if\_test},\39\\{if\_tdir\_code})$;\5
+$\\{primitive}(\.{"ifydir"},\39\\{if\_test},\39\\{if\_ydir\_code})$;\5
+$\\{primitive}(\.{"ifddir"},\39\\{if\_test},\39\\{if\_ddir\_code})$;\5
+$\\{primitive}(\.{"ifmdir"},\39\\{if\_test},\39\\{if\_mdir\_code})$;\5
+$\\{primitive}(\.{"iftbox"},\39\\{if\_test},\39\\{if\_tbox\_code})$;\5
+$\\{primitive}(\.{"ifybox"},\39\\{if\_test},\39\\{if\_ybox\_code})$;\5
+$\\{primitive}(\.{"ifdbox"},\39\\{if\_test},\39\\{if\_dbox\_code})$;\par
+\fi
+
+\M499. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{if\_test}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{if\_cat\_code}: \37$\\{print\_esc}(\.{"ifcat"})$;\6
+\4\\{if\_int\_code}: \37$\\{print\_esc}(\.{"ifnum"})$;\6
+\4\\{if\_dim\_code}: \37$\\{print\_esc}(\.{"ifdim"})$;\6
+\4\\{if\_odd\_code}: \37$\\{print\_esc}(\.{"ifodd"})$;\6
+\4\\{if\_vmode\_code}: \37$\\{print\_esc}(\.{"ifvmode"})$;\6
+\4\\{if\_hmode\_code}: \37$\\{print\_esc}(\.{"ifhmode"})$;\6
+\4\\{if\_mmode\_code}: \37$\\{print\_esc}(\.{"ifmmode"})$;\6
+\4\\{if\_inner\_code}: \37$\\{print\_esc}(\.{"ifinner"})$;\6
+\4\\{if\_void\_code}: \37$\\{print\_esc}(\.{"ifvoid"})$;\6
+\4\\{if\_hbox\_code}: \37$\\{print\_esc}(\.{"ifhbox"})$;\6
+\4\\{if\_vbox\_code}: \37$\\{print\_esc}(\.{"ifvbox"})$;\6
+\4\\{ifx\_code}: \37$\\{print\_esc}(\.{"ifx"})$;\6
+\4\\{if\_eof\_code}: \37$\\{print\_esc}(\.{"ifeof"})$;\6
+\4\\{if\_true\_code}: \37$\\{print\_esc}(\.{"iftrue"})$;\6
+\4\\{if\_false\_code}: \37$\\{print\_esc}(\.{"iffalse"})$;\6
+\4\\{if\_case\_code}: \37$\\{print\_esc}(\.{"ifcase"})$;\6
+\4\\{if\_tdir\_code}: \37$\\{print\_esc}(\.{"iftdir"})$;\6
+\4\\{if\_ydir\_code}: \37$\\{print\_esc}(\.{"ifydir"})$;\6
+\4\\{if\_ddir\_code}: \37$\\{print\_esc}(\.{"ifddir"})$;\6
+\4\\{if\_mdir\_code}: \37$\\{print\_esc}(\.{"ifmdir"})$;\6
+\4\\{if\_tbox\_code}: \37$\\{print\_esc}(\.{"iftbox"})$;\6
+\4\\{if\_ybox\_code}: \37$\\{print\_esc}(\.{"ifybox"})$;\6
+\4\\{if\_dbox\_code}: \37$\\{print\_esc}(\.{"ifdbox"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"if"})$\2\6
+\&{endcases};\par
+\fi
+
+\M500. Conditions can be inside conditions, and this nesting has a stack
+that is independent of the \\{save\_stack}.
+
+Four global variables represent the top of the condition stack:
+\\{cond\_ptr} points to pushed-down entries, if any; \\{if\_limit} specifies
+the largest code of a \\{fi\_or\_else} command that is syntactically legal;
+\\{cur\_if} is the name of the current type of conditional; and \\{if\_line}
+is the line number at which it began.
+
+If no conditions are currently in progress, the condition stack has the
+special state $\\{cond\_ptr}=\\{null}$, $\\{if\_limit}=\\{normal}$, $\\{cur%
+\_if}=0$, $\\{if\_line}=0$.
+Otherwise \\{cond\_ptr} points to a two-word node; the \\{type}, \\{subtype},
+and
+\\{link} fields of the first word contain \\{if\_limit}, \\{cur\_if}, and
+\\{cond\_ptr} at the next level, and the second word contains the
+corresponding \\{if\_line}.
+
+\Y\P\D \37$\\{if\_node\_size}=2$\C{number of words in stack entry for
+conditionals}\par
+\P\D \37$\\{if\_line\_field}(\#)\S\\{mem}[\#+1].\\{int}$\par
+\P\D \37$\\{if\_code}=1$\C{code for \.{\\if...} being evaluated}\par
+\P\D \37$\\{fi\_code}=2$\C{code for \.{\\fi}}\par
+\P\D \37$\\{else\_code}=3$\C{code for \.{\\else}}\par
+\P\D \37$\\{or\_code}=4$\C{code for \.{\\or}}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cond\_ptr}: \37\\{pointer};\C{top of the condition stack}\6
+\4\\{if\_limit}: \37$\\{normal}\to\\{or\_code}$;\C{upper bound on \\{fi\_or%
+\_else} codes}\6
+\4\\{cur\_if}: \37\\{small\_number};\C{type of conditional being worked on}\6
+\4\\{if\_line}: \37\\{integer};\C{line where that conditional began}\par
+\fi
+
+\M501. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{cond\_ptr}\K\\{null}$;\5
+$\\{if\_limit}\K\\{normal}$;\5
+$\\{cur\_if}\K0$;\5
+$\\{if\_line}\K0$;\par
+\fi
+
+\M502. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"fi"},\39\\{fi\_or\_else},\39\\{fi\_code})$;\5
+$\\{text}(\\{frozen\_fi})\K\.{"fi"}$;\5
+$\\{eqtb}[\\{frozen\_fi}]\K\\{eqtb}[\\{cur\_val}]$;\5
+$\\{primitive}(\.{"or"},\39\\{fi\_or\_else},\39\\{or\_code})$;\5
+$\\{primitive}(\.{"else"},\39\\{fi\_or\_else},\39\\{else\_code})$;\par
+\fi
+
+\M503. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{fi\_or\_else}: \37\&{if} $\\{chr\_code}=\\{fi\_code}$ \1\&{then}\5
+$\\{print\_esc}(\.{"fi"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{or\_code}$ \1\&{then}\5
+$\\{print\_esc}(\.{"or"})$\6
+\4\&{else} $\\{print\_esc}(\.{"else"})$;\2\2\par
+\fi
+
+\M504. When we skip conditional text, we keep track of the line number
+where skipping began, for use in error messages.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{skip\_line}: \37\\{integer};\C{skipping began here}\par
+\fi
+
+\M505. Here is a procedure that ignores text until coming to an \.{\\or},
+\.{\\else}, or \.{\\fi} at level zero of $\.{\\if}\ldots\.{\\fi}$
+nesting. After it has acted, \\{cur\_chr} will indicate the token that
+was found, but \\{cur\_tok} will not be set (because this makes the
+procedure run faster).
+
+\Y\P\4\&{procedure}\1\  \37\\{pass\_text};\6
+\4\&{label} \37\\{done};\6
+\4\&{var} \37\|l: \37\\{integer};\C{level of $\.{\\if}\ldots\.{\\fi}$ nesting}\6
+\\{save\_scanner\_status}: \37\\{small\_number};\C{\\{scanner\_status} upon
+entry}\2\6
+\&{begin} \37$\\{save\_scanner\_status}\K\\{scanner\_status}$;\5
+$\\{scanner\_status}\K\\{skipping}$;\5
+$\|l\K0$;\5
+$\\{skip\_line}\K\\{line}$;\6
+\~ \1\&{loop}\ \&{begin} \37\\{get\_next};\6
+\&{if} $\\{cur\_cmd}=\\{fi\_or\_else}$ \1\&{then}\6
+\&{begin} \37\&{if} $\|l=0$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+\&{if} $\\{cur\_chr}=\\{fi\_code}$ \1\&{then}\5
+$\\{decr}(\|l)$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{if\_test}$ \1\&{then}\5
+$\\{incr}(\|l)$;\2\2\6
+\&{end};\2\6
+\4\\{done}: \37$\\{scanner\_status}\K\\{save\_scanner\_status}$;\6
+\&{end};\par
+\fi
+
+\M506. When we begin to process a new \.{\\if}, we set $\\{if\_limit}\K\\{if%
+\_code}$; then
+if\/ \.{\\or} or \.{\\else} or \.{\\fi} occurs before the current \.{\\if}
+condition has been evaluated, \.{\\relax} will be inserted.
+For example, a sequence of commands like `\.{\\ifvoid1\\else...\\fi}'
+would otherwise require something after the `\.1'.
+
+\Y\P$\4\X506:Push the condition stack\X\S$\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{if\_node\_size})$;\5
+$\\{link}(\|p)\K\\{cond\_ptr}$;\5
+$\\{type}(\|p)\K\\{if\_limit}$;\5
+$\\{subtype}(\|p)\K\\{cur\_if}$;\5
+$\\{if\_line\_field}(\|p)\K\\{if\_line}$;\5
+$\\{cond\_ptr}\K\|p$;\5
+$\\{cur\_if}\K\\{cur\_chr}$;\5
+$\\{if\_limit}\K\\{if\_code}$;\5
+$\\{if\_line}\K\\{line}$;\6
+\&{end}\par
+\U509.\fi
+
+\M507. \P$\X507:Pop the condition stack\X\S$\6
+\&{begin} \37$\|p\K\\{cond\_ptr}$;\5
+$\\{if\_line}\K\\{if\_line\_field}(\|p)$;\5
+$\\{cur\_if}\K\\{subtype}(\|p)$;\5
+$\\{if\_limit}\K\\{type}(\|p)$;\5
+$\\{cond\_ptr}\K\\{link}(\|p)$;\5
+$\\{free\_node}(\|p,\39\\{if\_node\_size})$;\6
+\&{end}\par
+\Us509, 511, 520\ETs521.\fi
+
+\M508. Here's a procedure that changes the \\{if\_limit} code corresponding to
+a given value of \\{cond\_ptr}.
+
+\Y\P\4\&{procedure}\1\  \37$\\{change\_if\_limit}(\|l:\\{small\_number};\,\35%
+\|p:\\{pointer})$;\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|q: \37\\{pointer};\2\6
+\&{begin} \37\&{if} $\|p=\\{cond\_ptr}$ \1\&{then}\5
+$\\{if\_limit}\K\|l$\C{that's the easy case}\6
+\4\&{else} \&{begin} \37$\|q\K\\{cond\_ptr}$;\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\|q=\\{null}$ \1\&{then}\5
+$\\{confusion}(\.{"if"})$;\2\6
+\&{if} $\\{link}(\|q)=\|p$ \1\&{then}\6
+\&{begin} \37$\\{type}(\|q)\K\|l$;\5
+\&{return};\6
+\&{end};\2\6
+$\|q\K\\{link}(\|q)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M509. A condition is started when the \\{expand} procedure encounters
+an \\{if\_test} command; in that case \\{expand} reduces to \\{conditional},
+which is a recursive procedure.
+
+\Y\P\4\&{procedure}\1\  \37\\{conditional};\6
+\4\&{label} \37$\\{exit},\39\\{common\_ending}$;\6
+\4\&{var} \37\|b: \37\\{boolean};\C{is the condition true?}\6
+\|r: \37$\.{"<"}\to\.{">"}$;\C{relation to be evaluated}\6
+$\|m,\39\|n$: \37\\{integer};\C{to be tested against the second operand}\6
+$\|p,\39\|q$: \37\\{pointer};\C{for traversing token lists in \.{\\ifx} tests}\6
+\\{save\_scanner\_status}: \37\\{small\_number};\C{\\{scanner\_status} upon
+entry}\6
+\\{save\_cond\_ptr}: \37\\{pointer};\C{\\{cond\_ptr} corresponding to this
+conditional}\6
+\\{this\_if}: \37\\{small\_number};\C{type of this conditional}\2\6
+\&{begin} \37\X506:Push the condition stack\X;\ $\\{save\_cond\_ptr}\K\\{cond%
+\_ptr}$;\5
+$\\{this\_if}\K\\{cur\_chr}$;\6
+\X512:Either process \.{\\ifcase} or set \|b to the value of a boolean
+condition\X;\6
+\&{if} $\\{tracing\_commands}>1$ \1\&{then}\5
+\X513:Display the value of \|b\X;\2\6
+\&{if} $\|b$ \1\&{then}\6
+\&{begin} \37$\\{change\_if\_limit}(\\{else\_code},\39\\{save\_cond\_ptr})$;\5
+\&{return};\C{wait for \.{\\else} or \.{\\fi}}\6
+\&{end};\2\6
+\X511:Skip to \.{\\else} or \.{\\fi}, then \&{goto} \\{common\_ending}\X;\6
+\4\\{common\_ending}: \37\&{if} $\\{cur\_chr}=\\{fi\_code}$ \1\&{then}\5
+\X507:Pop the condition stack\X\6
+\4\&{else} $\\{if\_limit}\K\\{fi\_code}$;\C{wait for \.{\\fi}}\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M510. In a construction like `\.{\\if\\iftrue abc\\else d\\fi}', the first
+\.{\\else} that we come to after learning that the \.{\\if} is false is
+not the \.{\\else} we're looking for. Hence the following curious
+logic is needed.
+
+\fi
+
+\M511. \P$\X511:Skip to \.{\\else} or \.{\\fi}, then \&{goto} \\{common%
+\_ending}\X\S$\6
+\~ \1\&{loop}\ \&{begin} \37\\{pass\_text};\6
+\&{if} $\\{cond\_ptr}=\\{save\_cond\_ptr}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{cur\_chr}\I\\{or\_code}$ \1\&{then}\5
+\&{goto} \37\\{common\_ending};\2\6
+$\\{print\_err}(\.{"Extra\ "})$;\5
+$\\{print\_esc}(\.{"or"})$;\5
+$\\{help1}(\.{"I\'m\ ignoring\ this;\ it\ doesn\'t\ match\ any\ \\if."})$;\5
+\\{error};\6
+\&{end}\6
+\4\&{else} \&{if} $\\{cur\_chr}=\\{fi\_code}$ \1\&{then}\5
+\X507:Pop the condition stack\X;\2\2\6
+\&{end}\2\par
+\U509.\fi
+
+\M512. \P$\X512:Either process \.{\\ifcase} or set \|b to the value of a
+boolean condition\X\S$\6
+\&{case} $\\{this\_if}$ \1\&{of}\6
+\4$\\{if\_char\_code},\39\\{if\_cat\_code}$: \37\X517:Test if two characters
+match\X;\6
+\4$\\{if\_int\_code},\39\\{if\_dim\_code}$: \37\X514:Test relation between
+integers or dimensions\X;\6
+\4\\{if\_odd\_code}: \37\X515:Test if an integer is odd\X;\6
+\4\\{if\_vmode\_code}: \37$\|b\K(\\{abs}(\\{mode})=\\{vmode})$;\6
+\4\\{if\_hmode\_code}: \37$\|b\K(\\{abs}(\\{mode})=\\{hmode})$;\6
+\4\\{if\_mmode\_code}: \37$\|b\K(\\{abs}(\\{mode})=\\{mmode})$;\6
+\4\\{if\_inner\_code}: \37$\|b\K(\\{mode}<0)$;\6
+\4\\{if\_tdir\_code}: \37$\|b\K(\\{abs}(\\{direction})=\\{dir\_tate})$;\6
+\4\\{if\_ydir\_code}: \37$\|b\K(\\{abs}(\\{direction})=\\{dir\_yoko})$;\6
+\4\\{if\_ddir\_code}: \37$\|b\K(\\{abs}(\\{direction})=\\{dir\_dtou})$;\6
+\4\\{if\_mdir\_code}: \37$\|b\K(\\{direction}<0)$;\6
+\4$\\{if\_void\_code},\39\\{if\_hbox\_code},\39\\{if\_vbox\_code},\39\\{if%
+\_tbox\_code},\39\\{if\_ybox\_code},\39\\{if\_dbox\_code}$: \37\X516:Test box
+register status\X;\6
+\4\\{ifx\_code}: \37\X518:Test if two tokens match\X;\6
+\4\\{if\_eof\_code}: \37\&{begin} \37\\{scan\_four\_bit\_int\_or\_18};\6
+\&{if} $\\{cur\_val}=18$ \1\&{then}\5
+$\|b\K\R\\{shellenabledp}$\6
+\4\&{else} $\|b\K(\\{read\_open}[\\{cur\_val}]=\\{closed})$;\2\6
+\&{end};\6
+\4\\{if\_true\_code}: \37$\|b\K\\{true}$;\6
+\4\\{if\_false\_code}: \37$\|b\K\\{false}$;\6
+\4\\{if\_case\_code}: \37\X520:Select the appropriate case and \&{return} or %
+\&{goto} \\{common\_ending}\X;\2\6
+\&{end}\C{there are no other cases}\par
+\U509.\fi
+
+\M513. \P$\X513:Display the value of \|b\X\S$\6
+\&{begin} \37\\{begin\_diagnostic};\6
+\&{if} $\|b$ \1\&{then}\5
+$\\{print}(\.{"\{true\}"})$\ \&{else} $\\{print}(\.{"\{false\}"})$;\2\6
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end}\par
+\U509.\fi
+
+\M514. Here we use the fact that \.{"<"}, \.{"="}, and \.{">"} are consecutive
+ASCII
+codes.
+
+\Y\P$\4\X514:Test relation between integers or dimensions\X\S$\6
+\&{begin} \37\&{if} $\\{this\_if}=\\{if\_int\_code}$ \1\&{then}\5
+\\{scan\_int}\ \&{else} \\{scan\_normal\_dimen};\2\6
+$\|n\K\\{cur\_val}$;\5
+\X417:Get the next non-blank non-call token\X;\6
+\&{if} $(\\{cur\_tok}\G\\{other\_token}+\.{"<"})\W(\\{cur\_tok}\L\\{other%
+\_token}+\.{">"})$ \1\&{then}\5
+$\|r\K\\{cur\_tok}-\\{other\_token}$\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Missing\ =\ inserted\ for\ "})$;\5
+$\\{print\_cmd\_chr}(\\{if\_test},\39\\{this\_if})$;\5
+$\\{help1}(\.{"I\ was\ expecting\ to\ see\ \`<\',\ \`=\',\ or\ \`>\'.\ Didn%
+\'t."})$;\5
+\\{back\_error};\5
+$\|r\K\.{"="}$;\6
+\&{end};\2\6
+\&{if} $\\{this\_if}=\\{if\_int\_code}$ \1\&{then}\5
+\\{scan\_int}\ \&{else} \\{scan\_normal\_dimen};\2\6
+\&{case} $\|r$ \1\&{of}\6
+\4\.{"<"}: \37$\|b\K(\|n<\\{cur\_val})$;\6
+\4\.{"="}: \37$\|b\K(\|n=\\{cur\_val})$;\6
+\4\.{">"}: \37$\|b\K(\|n>\\{cur\_val})$;\2\6
+\&{end};\6
+\&{end}\par
+\U512.\fi
+
+\M515. \P$\X515:Test if an integer is odd\X\S$\6
+\&{begin} \37\\{scan\_int};\5
+$\|b\K\\{odd}(\\{cur\_val})$;\6
+\&{end}\par
+\U512.\fi
+
+\M516. \P$\X516:Test box register status\X\S$\6
+\&{begin} \37\\{scan\_eight\_bit\_int};\5
+$\|p\K\\{box}(\\{cur\_val})$;\6
+\&{if} $\\{this\_if}=\\{if\_void\_code}$ \1\&{then}\5
+$\|b\K(\|p=\\{null})$\6
+\4\&{else} \&{if} $\|p=\\{null}$ \1\&{then}\5
+$\|b\K\\{false}$\6
+\4\&{else} \&{begin} \37\&{if} $\\{type}(\|p)=\\{dir\_node}$ \1\&{then}\5
+$\|p\K\\{list\_ptr}(\|p)$;\2\6
+\&{if} $\\{this\_if}=\\{if\_hbox\_code}$ \1\&{then}\5
+$\|b\K(\\{type}(\|p)=\\{hlist\_node})$\6
+\4\&{else} \&{if} $\\{this\_if}=\\{if\_vbox\_code}$ \1\&{then}\5
+$\|b\K(\\{type}(\|p)=\\{vlist\_node})$\6
+\4\&{else} \&{if} $\\{this\_if}=\\{if\_tbox\_code}$ \1\&{then}\5
+$\|b\K(\\{box\_dir}(\|p)=\\{dir\_tate})$\6
+\4\&{else} \&{if} $\\{this\_if}=\\{if\_ybox\_code}$ \1\&{then}\5
+$\|b\K(\\{box\_dir}(\|p)=\\{dir\_yoko})$\6
+\4\&{else} $\|b\K(\\{box\_dir}(\|p)=\\{dir\_dtou})$;\2\2\2\2\6
+\&{end}\2\2\6
+\&{end}\par
+\U512.\fi
+
+\M517. An active character will be treated as category 13 following
+\.{\\if\\noexpand} or following \.{\\ifcat\\noexpand}. We use the fact that
+active characters have the smallest tokens, among all control sequences.
+
+\Y\P\D \37$\\{get\_x\_token\_or\_active\_char}\S\hbox{}$\6
+\&{begin} \37\\{get\_x\_token};\6
+\&{if} $\\{cur\_cmd}=\\{relax}$ \1\&{then}\6
+\&{if} $\\{cur\_chr}=\\{no\_expand\_flag}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_cmd}\K\\{active\_char}$;\5
+$\\{cur\_chr}\K\\{cur\_tok}-\\{cs\_token\_flag}-\\{active\_base}$;\6
+\&{end};\2\2\6
+\&{end}\par
+\Y\P$\4\X517:Test if two characters match\X\S$\6
+\&{begin} \37\\{get\_x\_token\_or\_active\_char};\6
+\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=%
+\\{other\_kchar})$ \1\&{then}\6
+\&{begin} \37$\|m\K\\{cur\_cmd}$;\5
+$\|n\K\\{cur\_chr}$;\6
+\&{end}\6
+\4\&{else} \&{if} $(\\{cur\_cmd}>\\{active\_char})\V(\\{cur\_chr}>255)$ \1%
+\&{then}\6
+\&{begin} \37$\|m\K\\{relax}$;\5
+$\|n\K256$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|m\K\\{cur\_cmd}$;\5
+$\|n\K\\{cur\_chr}$;\6
+\&{end};\2\2\6
+\\{get\_x\_token\_or\_active\_char};\6
+\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=%
+\\{other\_kchar})$ \1\&{then}\6
+\&{begin} \37$\\{cur\_cmd}\K\\{cur\_cmd}$;\6
+\&{end}\C{dummy}\6
+\4\&{else} \&{if} $(\\{cur\_cmd}>\\{active\_char})\V(\\{cur\_chr}>255)$ \1%
+\&{then}\6
+\&{begin} \37$\\{cur\_cmd}\K\\{relax}$;\5
+$\\{cur\_chr}\K256$;\6
+\&{end};\2\2\6
+\&{if} $\\{this\_if}=\\{if\_char\_code}$ \1\&{then}\5
+$\|b\K(\|n=\\{cur\_chr})$\ \&{else} $\|b\K(\|m=\\{cur\_cmd})$;\2\6
+\&{end}\par
+\U512.\fi
+
+\M518. Note that `\.{\\ifx}' will declare two macros different if one is %
+\\{long}
+or \\{outer} and the other isn't, even though the texts of the macros are
+the same.
+
+We need to reset \\{scanner\_status}, since \.{\\outer} control sequences
+are allowed, but we might be scanning a macro definition or preamble.
+
+\Y\P$\4\X518:Test if two tokens match\X\S$\6
+\&{begin} \37$\\{save\_scanner\_status}\K\\{scanner\_status}$;\5
+$\\{scanner\_status}\K\\{normal}$;\5
+\\{get\_next};\5
+$\|n\K\\{cur\_cs}$;\5
+$\|p\K\\{cur\_cmd}$;\5
+$\|q\K\\{cur\_chr}$;\5
+\\{get\_next};\6
+\&{if} $\\{cur\_cmd}\I\|p$ \1\&{then}\5
+$\|b\K\\{false}$\6
+\4\&{else} \&{if} $\\{cur\_cmd}<\\{call}$ \1\&{then}\5
+$\|b\K(\\{cur\_chr}=\|q)$\6
+\4\&{else} \X519:Test if two macro texts match\X;\2\2\6
+$\\{scanner\_status}\K\\{save\_scanner\_status}$;\6
+\&{end}\par
+\U512.\fi
+
+\M519. Note also that `\.{\\ifx}' decides that macros \.{\\a} and \.{\\b} are
+different in examples like this:
+$$\vbox{\halign{\.{#}\hfil&\qquad\.{#}\hfil\cr
+{}\\def\\a\{\\c\}&
+{}\\def\\c\{\}\cr
+{}\\def\\b\{\\d\}&
+{}\\def\\d\{\}\cr}}$$
+
+\Y\P$\4\X519:Test if two macro texts match\X\S$\6
+\&{begin} \37$\|p\K\\{link}(\\{cur\_chr})$;\5
+$\|q\K\\{link}(\\{equiv}(\|n))$;\C{omit reference counts}\6
+\&{if} $\|p=\|q$ \1\&{then}\5
+$\|b\K\\{true}$\6
+\4\&{else} \&{begin} \37\&{while} $(\|p\I\\{null})\W(\|q\I\\{null})$ \1\&{do}\6
+\&{if} $\\{info}(\|p)\I\\{info}(\|q)$ \1\&{then}\5
+$\|p\K\\{null}$\6
+\4\&{else} \&{begin} \37$\|p\K\\{link}(\|p)$;\5
+$\|q\K\\{link}(\|q)$;\6
+\&{end};\2\2\6
+$\|b\K((\|p=\\{null})\W(\|q=\\{null}))$;\6
+\&{end};\2\6
+\&{end}\par
+\U518.\fi
+
+\M520. \P$\X520:Select the appropriate case and \&{return} or \&{goto} %
+\\{common\_ending}\X\S$\6
+\&{begin} \37\\{scan\_int};\5
+$\|n\K\\{cur\_val}$;\C{\|n is the number of cases to pass}\6
+\&{if} $\\{tracing\_commands}>1$ \1\&{then}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print}(\.{"\{case\ "})$;\5
+$\\{print\_int}(\|n)$;\5
+$\\{print\_char}(\.{"\}"})$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end};\2\6
+\&{while} $\|n\I0$ \1\&{do}\6
+\&{begin} \37\\{pass\_text};\6
+\&{if} $\\{cond\_ptr}=\\{save\_cond\_ptr}$ \1\&{then}\6
+\&{if} $\\{cur\_chr}=\\{or\_code}$ \1\&{then}\5
+$\\{decr}(\|n)$\6
+\4\&{else} \&{goto} \37\\{common\_ending}\2\6
+\4\&{else} \&{if} $\\{cur\_chr}=\\{fi\_code}$ \1\&{then}\5
+\X507:Pop the condition stack\X;\2\2\6
+\&{end};\2\6
+$\\{change\_if\_limit}(\\{or\_code},\39\\{save\_cond\_ptr})$;\5
+\&{return};\C{wait for \.{\\or}, \.{\\else}, or \.{\\fi}}\6
+\&{end}\par
+\U512.\fi
+
+\M521. The processing of conditionals is complete except for the following
+code, which is actually part of \\{expand}. It comes into play when
+\.{\\or}, \.{\\else}, or \.{\\fi} is scanned.
+
+\Y\P$\4\X521:Terminate the current conditional and skip to \.{\\fi}\X\S$\6
+\&{if} $\\{cur\_chr}>\\{if\_limit}$ \1\&{then}\6
+\&{if} $\\{if\_limit}=\\{if\_code}$ \1\&{then}\5
+\\{insert\_relax}\C{condition not yet evaluated}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Extra\ "})$;\5
+$\\{print\_cmd\_chr}(\\{fi\_or\_else},\39\\{cur\_chr})$;\5
+$\\{help1}(\.{"I\'m\ ignoring\ this;\ it\ doesn\'t\ match\ any\ \\if."})$;\5
+\\{error};\6
+\&{end}\2\6
+\4\&{else} \&{begin} \37\&{while} $\\{cur\_chr}\I\\{fi\_code}$ \1\&{do}\5
+\\{pass\_text};\C{skip to \.{\\fi}}\2\6
+\X507:Pop the condition stack\X;\6
+\&{end}\2\par
+\U378.\fi
+
+\N522.  \[29] File names.
+It's time now to fret about file names.  Besides the fact that different
+operating systems treat files in different ways, we must cope with the
+fact that completely different naming conventions are used by different
+groups of people. The following programs show what is required for one
+particular operating system; similar routines for other systems are not
+difficult to devise.
+
+\TeX\ assumes that a file name has three parts: the name proper; its
+``extension''; and a ``file area'' where it is found in an external file
+system.  The extension of an input file or a write file is assumed to be
+`\.{.tex}' unless otherwise specified; it is `\.{.log}' on the
+transcript file that records each run of \TeX; it is `\.{.tfm}' on the font
+metric files that describe characters in the fonts \TeX\ uses; it is
+`\.{.dvi}' on the output files that specify typesetting information; and it
+is `\.{.fmt}' on the format files written by \.{INITEX} to initialize \TeX.
+The file area can be arbitrary on input files, but files are usually
+output to the user's current area.  If an input file cannot be
+found on the specified area, \TeX\ will look for it on a special system
+area; this special area is intended for commonly used input files like
+\.{webmac.tex}.
+
+Simple uses of \TeX\ refer only to file names that have no explicit
+extension or area. For example, a person usually says `\.{\\input} \.{paper}'
+or `\.{\\font\\tenrm} \.= \.{helvetica}' instead of `\.{\\input}
+\.{paper.new}' or `\.{\\font\\tenrm} \.= \.{<csd.knuth>test}'. Simple file
+names are best, because they make the \TeX\ source files portable;
+whenever a file name consists entirely of letters and digits, it should be
+treated in the same way by all implementations of \TeX. However, users
+need the ability to refer to other files in their environment, especially
+when responding to error messages concerning unopenable files; therefore
+we want to let them use the syntax that appears in their favorite
+operating system.
+
+The following procedures don't allow spaces to be part of
+file names; but some users seem to like names that are spaced-out.
+System-dependent changes to allow such things should probably
+be made with reluctance, and only when an entire file name that
+includes spaces is ``quoted'' somehow.
+
+\fi
+
+\M523. In order to isolate the system-dependent aspects of file names, the
+system-independent parts of \TeX\ are expressed in terms
+of three system-dependent
+procedures called \\{begin\_name}, \\{more\_name}, and \\{end\_name}. In
+essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
+the system-independent driver program does the operations
+$$\\{begin\_name};\,\\{more\_name}(c_1);\,\ldots\,;\,\\{more\_name}(c_n);
+\,\\{end\_name}.$$
+These three procedures communicate with each other via global variables.
+Afterwards the file name will appear in the string pool as three strings
+called \\{cur\_name}\penalty10000\hskip-.05em,
+\\{cur\_area}, and \\{cur\_ext}; the latter two are null (i.e.,
+\.{""}), unless they were explicitly specified by the user.
+
+Actually the situation is slightly more complicated, because \TeX\ needs
+to know when the file name ends. The \\{more\_name} routine is a function
+(with side effects) that returns \\{true} on the calls \\{more\_name}$(c_1)$,
+\dots, \\{more\_name}$(c_{n-1})$. The final call \\{more\_name}$(c_n)$
+returns \\{false}; or, it returns \\{true} and the token following $c_n$ is
+something like `\.{\\hbox}' (i.e., not a character). In other words,
+\\{more\_name} is supposed to return \\{true} unless it is sure that the
+file name has been completely scanned; and \\{end\_name} is supposed to be able
+to finish the assembly of \\{cur\_name}, \\{cur\_area}, and \\{cur\_ext}
+regardless of
+whether $\\{more\_name}(c_n)$ returned \\{true} or \\{false}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_name}: \37\\{str\_number};\C{name of file just scanned}\6
+\4\\{cur\_area}: \37\\{str\_number};\C{file area just scanned, or \.{""}}\6
+\4\\{cur\_ext}: \37\\{str\_number};\C{file extension just scanned, or \.{""}}%
+\par
+\fi
+
+\M524. The file names we shall deal with have the
+following structure:  If the name contains `\./' or `\.:'
+(for Amiga only), the file area
+consists of all characters up to and including the final such character;
+otherwise the file area is null.  If the remaining file name contains
+`\..', the file extension consists of all such characters from the last
+`\..' to the end, otherwise the file extension is null.
+
+We can scan such file names easily by using two global variables that keep
+track
+of the occurrences of area and extension delimiters:
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{area\_delimiter}: \37\\{pool\_pointer};\C{the most recent `\./', if any}\6
+\4\\{ext\_delimiter}: \37\\{pool\_pointer};\C{the most recent `\..', if any}\par
+\fi
+
+\M525. Input files that can't be found in the user's area may appear in a
+standard
+system area called \\{TEX\_area}. Font metric files whose areas are not given
+explicitly are assumed to appear in a standard system area called
+\\{TEX\_font\_area}.  These system area names will, of course, vary from place
+to place.
+
+In C, the default paths are specified separately.
+
+\fi
+
+\M526. Here now is the first of the system-dependent routines for file name
+scanning.
+
+\Y\P\4\&{procedure}\1\  \37\\{begin\_name};\2\6
+\&{begin} \37$\\{area\_delimiter}\K0$;\5
+$\\{ext\_delimiter}\K0$;\5
+$\\{quoted\_filename}\K\\{false}$;\5
+$\\{prev\_char}\K0$;\6
+\&{end};\par
+\fi
+
+\M527. And here's the second. The string pool might change as the file name is
+being scanned, since a new \.{\\csname} might be entered; therefore we keep
+\\{area\_delimiter} and \\{ext\_delimiter} relative to the beginning of the
+current
+string, instead of assigning an absolute address like \\{pool\_ptr} to them.
+
+\Y\P\4\&{function}\1\  \37$\\{more\_name}(\|c:\\{ASCII\_code})$: \37%
+\\{boolean};\2\6
+\&{begin} \37\&{if} $(\|c=\.{"\ "})\W\\{stop\_at\_space}\W(\R\\{quoted%
+\_filename})$ \1\&{then}\5
+$\\{more\_name}\K\\{false}$\6
+\4\&{else} \&{if} $\|c=\.{""}\.{""}$ \1\&{then}\6
+\&{begin} \37$\\{quoted\_filename}\K\R\\{quoted\_filename}$;\5
+$\\{more\_name}\K\\{true}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{str\_room}(1)$;\5
+$\\{append\_char}(\|c)$;\C{contribute \|c to the current string}\6
+\&{if} $(\\{IS\_DIR\_SEP}(\|c)\W(\\{not\_kanji\_char\_seq}(\\{prev\_char},\39%
+\|c)))$ \1\&{then}\6
+\&{begin} \37$\\{area\_delimiter}\K\\{cur\_length}$;\5
+$\\{ext\_delimiter}\K0$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|c=\.{"."}$ \1\&{then}\5
+$\\{ext\_delimiter}\K\\{cur\_length}$;\2\2\6
+$\\{more\_name}\K\\{true}$;\6
+\&{end};\2\2\6
+$\\{prev\_char}\K\|c$;\6
+\&{end};\par
+\fi
+
+\M528. The third.
+If a string is already in the string pool, the function
+\\{slow\_make\_string} does not create a new string but returns this string
+number, thus saving string space.  Because of this new property of the
+returned string number it is not possible to apply \\{flush\_string} to
+these strings.
+
+\Y\P\4\&{procedure}\1\  \37\\{end\_name};\6
+\4\&{var} \37\\{temp\_str}: \37\\{str\_number};\C{result of file name cache
+lookups}\6
+$\|j,\39\|s,\39\|t$: \37\\{pool\_pointer};\C{running indices}\6
+\\{must\_quote}: \37\\{boolean};\C{whether we need to quote a string}\2\6
+\&{begin} \37\&{if} $\\{str\_ptr}+3>\\{max\_strings}$ \1\&{then}\5
+$\\{overflow}(\.{"number\ of\ strings"},\39\\{max\_strings}-\\{init\_str%
+\_ptr})$;\2\6
+$\\{str\_room}(6)$;\C{Room for quotes, if needed.}\6
+\C{add quotes if needed}\6
+\&{if} $\\{area\_delimiter}\I0$ \1\&{then}\6
+\&{begin} \37\C{maybe quote \\{cur\_area}}\6
+$\\{must\_quote}\K\\{false}$;\5
+$\|s\K\\{str\_start}[\\{str\_ptr}]$;\5
+$\|t\K\\{str\_start}[\\{str\_ptr}]+\\{area\_delimiter}$;\5
+$\|j\K\|s$;\6
+\&{while} $(\R\\{must\_quote})\W(\|j<\|t)$ \1\&{do}\6
+\&{begin} \37$\\{must\_quote}\K\\{str\_pool}[\|j]=\.{"\ "}$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+\&{if} $\\{must\_quote}$ \1\&{then}\6
+\&{begin} \37\&{for} $\|j\K\\{pool\_ptr}-1\mathrel{\&{downto}}\|t$ \1\&{do}\5
+$\\{str\_pool}[\|j+2]\K\\{str\_pool}[\|j]$;\2\6
+$\\{str\_pool}[\|t+1]\K\.{""}\.{""}$;\6
+\&{for} $\|j\K\|t-1\mathrel{\&{downto}}\|s$ \1\&{do}\5
+$\\{str\_pool}[\|j+1]\K\\{str\_pool}[\|j]$;\2\6
+$\\{str\_pool}[\|s]\K\.{""}\.{""}$;\6
+\&{if} $\\{ext\_delimiter}\I0$ \1\&{then}\5
+$\\{ext\_delimiter}\K\\{ext\_delimiter}+2$;\2\6
+$\\{area\_delimiter}\K\\{area\_delimiter}+2$;\5
+$\\{pool\_ptr}\K\\{pool\_ptr}+2$;\6
+\&{end};\2\6
+\&{end};\C{maybe quote \\{cur\_name}}\2\6
+$\|s\K\\{str\_start}[\\{str\_ptr}]+\\{area\_delimiter}$;\6
+\&{if} $\\{ext\_delimiter}=0$ \1\&{then}\5
+$\|t\K\\{pool\_ptr}$\6
+\4\&{else} $\|t\K\\{str\_start}[\\{str\_ptr}]+\\{ext\_delimiter}-1$;\2\6
+$\\{must\_quote}\K\\{false}$;\5
+$\|j\K\|s$;\6
+\&{while} $(\R\\{must\_quote})\W(\|j<\|t)$ \1\&{do}\6
+\&{begin} \37$\\{must\_quote}\K\\{str\_pool}[\|j]=\.{"\ "}$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+\&{if} $\\{must\_quote}$ \1\&{then}\6
+\&{begin} \37\&{for} $\|j\K\\{pool\_ptr}-1\mathrel{\&{downto}}\|t$ \1\&{do}\5
+$\\{str\_pool}[\|j+2]\K\\{str\_pool}[\|j]$;\2\6
+$\\{str\_pool}[\|t+1]\K\.{""}\.{""}$;\6
+\&{for} $\|j\K\|t-1\mathrel{\&{downto}}\|s$ \1\&{do}\5
+$\\{str\_pool}[\|j+1]\K\\{str\_pool}[\|j]$;\2\6
+$\\{str\_pool}[\|s]\K\.{""}\.{""}$;\6
+\&{if} $\\{ext\_delimiter}\I0$ \1\&{then}\5
+$\\{ext\_delimiter}\K\\{ext\_delimiter}+2$;\2\6
+$\\{pool\_ptr}\K\\{pool\_ptr}+2$;\6
+\&{end};\2\6
+\&{if} $\\{ext\_delimiter}\I0$ \1\&{then}\6
+\&{begin} \37\C{maybe quote \\{cur\_ext}}\6
+$\|s\K\\{str\_start}[\\{str\_ptr}]+\\{ext\_delimiter}-1$;\5
+$\|t\K\\{pool\_ptr}$;\5
+$\\{must\_quote}\K\\{false}$;\5
+$\|j\K\|s$;\6
+\&{while} $(\R\\{must\_quote})\W(\|j<\|t)$ \1\&{do}\6
+\&{begin} \37$\\{must\_quote}\K\\{str\_pool}[\|j]=\.{"\ "}$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+\&{if} $\\{must\_quote}$ \1\&{then}\6
+\&{begin} \37$\\{str\_pool}[\|t+1]\K\.{""}\.{""}$;\6
+\&{for} $\|j\K\|t-1\mathrel{\&{downto}}\|s$ \1\&{do}\5
+$\\{str\_pool}[\|j+1]\K\\{str\_pool}[\|j]$;\2\6
+$\\{str\_pool}[\|s]\K\.{""}\.{""}$;\5
+$\\{pool\_ptr}\K\\{pool\_ptr}+2$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{area\_delimiter}=0$ \1\&{then}\5
+$\\{cur\_area}\K\.{""}$\6
+\4\&{else} \&{begin} \37$\\{cur\_area}\K\\{str\_ptr}$;\5
+$\\{str\_start}[\\{str\_ptr}+1]\K\\{str\_start}[\\{str\_ptr}]+\\{area%
+\_delimiter}$;\5
+$\\{incr}(\\{str\_ptr})$;\5
+$\\{temp\_str}\K\\{search\_string}(\\{cur\_area})$;\6
+\&{if} $\\{temp\_str}>0$ \1\&{then}\6
+\&{begin} \37$\\{cur\_area}\K\\{temp\_str}$;\5
+$\\{decr}(\\{str\_ptr})$;\C{no \\{flush\_string}, \\{pool\_ptr} will be wrong!}%
+\6
+\&{for} $\|j\K\\{str\_start}[\\{str\_ptr}+1]\mathrel{\&{to}}\\{pool\_ptr}-1$ \1%
+\&{do}\6
+\&{begin} \37$\\{str\_pool}[\|j-\\{area\_delimiter}]\K\\{str\_pool}[\|j]$;\6
+\&{end};\2\6
+$\\{pool\_ptr}\K\\{pool\_ptr}-\\{area\_delimiter}$;\C{update \\{pool\_ptr}}\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{ext\_delimiter}=0$ \1\&{then}\6
+\&{begin} \37$\\{cur\_ext}\K\.{""}$;\5
+$\\{cur\_name}\K\\{slow\_make\_string}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{cur\_name}\K\\{str\_ptr}$;\5
+$\\{str\_start}[\\{str\_ptr}+1]\K\\{str\_start}[\\{str\_ptr}]+\\{ext%
+\_delimiter}-\\{area\_delimiter}-1$;\5
+$\\{incr}(\\{str\_ptr})$;\5
+$\\{cur\_ext}\K\\{make\_string}$;\5
+$\\{decr}(\\{str\_ptr})$;\C{undo extension string to look at name part}\6
+$\\{temp\_str}\K\\{search\_string}(\\{cur\_name})$;\6
+\&{if} $\\{temp\_str}>0$ \1\&{then}\6
+\&{begin} \37$\\{cur\_name}\K\\{temp\_str}$;\5
+$\\{decr}(\\{str\_ptr})$;\C{no \\{flush\_string}, \\{pool\_ptr} will be wrong!}%
+\6
+\&{for} $\|j\K\\{str\_start}[\\{str\_ptr}+1]\mathrel{\&{to}}\\{pool\_ptr}-1$ \1%
+\&{do}\6
+\&{begin} \37$\\{str\_pool}[\|j-\\{ext\_delimiter}+\\{area\_delimiter}+1]\K%
+\\{str\_pool}[\|j]$;\6
+\&{end};\2\6
+$\\{pool\_ptr}\K\\{pool\_ptr}-\\{ext\_delimiter}+\\{area\_delimiter}+1$;%
+\C{update \\{pool\_ptr}}\6
+\&{end};\2\6
+$\\{cur\_ext}\K\\{slow\_make\_string}$;\C{remake extension string}\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M529. Conversely, here is a routine that takes three strings and prints a file
+name that might have produced them. (The routine is system dependent, because
+some operating systems put the file area last instead of first.)
+
+\Y\P\D \37$\\{check\_quoted}(\#)\S$\C{check if string $\#$ needs quoting}\6
+\&{if} $\#\I0$ \1\&{then}\6
+\&{begin} \37$\|j\K\\{str\_start}[\#]$;\6
+\&{while} $(\R\\{must\_quote})\W(\|j<\\{str\_start}[\#+1])$ \1\&{do}\6
+\&{begin} \37$\\{must\_quote}\K\\{str\_pool}[\|j]=\.{"\ "}$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+\&{end}\2\par
+\P\D \37$\\{print\_quoted}(\#)\S$\C{print string $\#$, omitting quotes}\6
+\&{if} $\#\I0$ \1\&{then}\6
+\&{for} $\|j\K\\{str\_start}[\#]\mathrel{\&{to}}\\{str\_start}[\#+1]-1$ \1%
+\&{do}\6
+\&{if} $\\{so}(\\{str\_pool}[\|j])\I\.{""}\.{""}$ \1\&{then}\5
+$\\{print}(\\{so}(\\{str\_pool}[\|j]))$\2\2\2\par
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_file\_name}(\|n,\39\|a,\39\|e:\\{integer})$;\6
+\4\&{var} \37\\{must\_quote}: \37\\{boolean};\C{whether to quote the filename}\6
+\|j: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\2\6
+\&{begin} \37$\\{must\_quote}\K\\{false}$;\5
+$\\{check\_quoted}(\|a)$;\5
+$\\{check\_quoted}(\|n)$;\5
+$\\{check\_quoted}(\|e)$;\C{FIXME: Alternative is to assume that any filename
+that has to be quoted has  at least one quoted component...if we pick this, a
+number of insertions  of \\{print\_file\_name} should go away. \\{must%
+\_quote}:=((\|a<>0)and(\\{str\_pool}[\\{str\_start}[\|a]]=""""))or
+ ((\|n<>0)and(\\{str\_pool}[\\{str\_start}[\|n]]=""""))or               ((%
+\|e<>0)and(\\{str\_pool}[\\{str\_start}[\|e]]=""""));}\6
+\&{if} $\\{must\_quote}$ \1\&{then}\5
+$\\{print\_char}(\.{""}\.{""})$;\2\6
+$\\{print\_quoted}(\|a)$;\5
+$\\{print\_quoted}(\|n)$;\5
+$\\{print\_quoted}(\|e)$;\6
+\&{if} $\\{must\_quote}$ \1\&{then}\5
+$\\{print\_char}(\.{""}\.{""})$;\2\6
+\&{end};\par
+\fi
+
+\M530. Another system-dependent routine is needed to convert three internal
+\TeX\ strings
+into the \\{name\_of\_file} value that is used to open files. The present code
+allows both lowercase and uppercase letters in the file name.
+
+\Y\P\D \37$\\{append\_to\_name}(\#)\S$\1\6
+\&{begin} \37$\|c\K\#$;\6
+\&{if} $\R(\|c=\.{""}\.{""})$ \1\&{then}\6
+\&{begin} \37$\\{incr}(\|k)$;\6
+\&{if} $\|k\L\\{file\_name\_size}$ \1\&{then}\5
+$\\{name\_of\_file}[\|k]\K\\{xchr}[\|c]$;\2\6
+\&{end}\2\6
+\&{end}\2\par
+\Y\P\4\&{procedure}\1\  \37$\\{pack\_file\_name}(\|n,\39\|a,\39\|e:\\{str%
+\_number})$;\6
+\4\&{var} \37\|k: \37\\{integer};\C{number of positions filled in \\{name\_of%
+\_file}}\6
+\|c: \37\\{ASCII\_code};\C{character being packed}\6
+\|j: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\2\6
+\&{begin} \37$\|k\K0$;\6
+\&{if} $\\{name\_of\_file}$ \1\&{then}\5
+$\\{libc\_free}(\\{name\_of\_file})$;\2\6
+$\\{name\_of\_file}\K\\{xmalloc\_array}(\\{ASCII\_code},\39\\{length}(\|a)+%
+\\{length}(\|n)+\\{length}(\|e)+1)$;\6
+\&{for} $\|j\K\\{str\_start}[\|a]\mathrel{\&{to}}\\{str\_start}[\|a+1]-1$ \1%
+\&{do}\5
+$\\{append\_to\_name}(\\{so}(\\{str\_pool}[\|j]))$;\2\6
+\&{for} $\|j\K\\{str\_start}[\|n]\mathrel{\&{to}}\\{str\_start}[\|n+1]-1$ \1%
+\&{do}\5
+$\\{append\_to\_name}(\\{so}(\\{str\_pool}[\|j]))$;\2\6
+\&{for} $\|j\K\\{str\_start}[\|e]\mathrel{\&{to}}\\{str\_start}[\|e+1]-1$ \1%
+\&{do}\5
+$\\{append\_to\_name}(\\{so}(\\{str\_pool}[\|j]))$;\2\6
+\&{if} $\|k\L\\{file\_name\_size}$ \1\&{then}\5
+$\\{name\_length}\K\|k$\ \&{else} $\\{name\_length}\K\\{file\_name\_size}$;\2\6
+$\\{name\_of\_file}[\\{name\_length}+1]\K0$;\6
+\&{end};\par
+\fi
+
+\M531. A messier routine is also needed, since format file names must be
+scanned
+before \TeX's string mechanism has been initialized. We shall use the
+global variable \\{TEX\_format\_default} to supply the text for default system
+areas
+and extensions related to format files.
+
+Under {\mc UNIX} we don't give the area part, instead depending
+on the path searching that will happen during file opening.  Also, the
+length will be set in the main program.
+
+\Y\P\D \37$\\{format\_area\_length}=0$\C{length of its area part}\par
+\P\D \37$\\{format\_ext\_length}=4$\C{length of its `\.{.fmt}' part}\par
+\P\D \37$\\{format\_extension}=\.{".fmt"}$\C{the extension, as a \.{WEB}
+constant}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{format\_default\_length}: \37\\{integer};\6
+\4\\{TEX\_format\_default}: \37\\{cstring};\par
+\fi
+
+\M532. We set the name of the default format file and the length of that name
+in C, instead of Pascal, since we want them to depend on the name of the
+program.
+
+\fi
+
+\M533. \P$\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6
+\&{if} $\\{format\_default\_length}>\\{file\_name\_size}$ \1\&{then}\5
+$\\{bad}\K31$;\2\par
+\fi
+
+\M534. Here is the messy routine that was just mentioned. It sets \\{name\_of%
+\_file}
+from the first \|n characters of \\{TEX\_format\_default}, followed by
+$\\{buffer}[\|a\to\|b]$, followed by the last \\{format\_ext\_length}
+characters of
+\\{TEX\_format\_default}.
+
+We dare not give error messages here, since \TeX\ calls this routine before
+the \\{error} routine is ready to roll. Instead, we simply drop excess
+characters,
+since the error will be detected in another way when a strange file name
+isn't found.
+
+\Y\P\4\&{procedure}\1\  \37$\\{pack\_buffered\_name}(\|n:\\{small\_number};\,%
+\35\|a,\39\|b:\\{integer})$;\6
+\4\&{var} \37\|k: \37\\{integer};\C{number of positions filled in \\{name\_of%
+\_file}}\6
+\|c: \37\\{ASCII\_code};\C{character being packed}\6
+\|j: \37\\{integer};\C{index into \\{buffer} or \\{TEX\_format\_default}}\2\6
+\&{begin} \37\&{if} $\|n+\|b-\|a+1+\\{format\_ext\_length}>\\{file\_name%
+\_size}$ \1\&{then}\5
+$\|b\K\|a+\\{file\_name\_size}-\|n-1-\\{format\_ext\_length}$;\2\6
+$\|k\K0$;\6
+\&{if} $\\{name\_of\_file}$ \1\&{then}\5
+$\\{libc\_free}(\\{name\_of\_file})$;\2\6
+$\\{name\_of\_file}\K\\{xmalloc\_array}(\\{ASCII\_code},\39\|n+(\|b-\|a+1)+%
+\\{format\_ext\_length}+1)$;\6
+\&{for} $\|j\K1\mathrel{\&{to}}\|n$ \1\&{do}\5
+$\\{append\_to\_name}(\\{xord}[\\{ucharcast}(\\{TEX\_format\_default}[\|j])])$;%
+\2\6
+\&{for} $\|j\K\|a\mathrel{\&{to}}\|b$ \1\&{do}\5
+$\\{append\_to\_name}(\\{buffer}[\|j])$;\2\6
+\&{for} $\|j\K\\{format\_default\_length}-\\{format\_ext\_length}+1\mathrel{%
+\&{to}}\\{format\_default\_length}$ \1\&{do}\5
+$\\{append\_to\_name}(\\{xord}[\\{ucharcast}(\\{TEX\_format\_default}[\|j])])$;%
+\2\6
+\&{if} $\|k\L\\{file\_name\_size}$ \1\&{then}\5
+$\\{name\_length}\K\|k$\ \&{else} $\\{name\_length}\K\\{file\_name\_size}$;\2\6
+$\\{name\_of\_file}[\\{name\_length}+1]\K0$;\6
+\&{end};\par
+\fi
+
+\M535. Here is the only place we use \\{pack\_buffered\_name}. This part of the
+program
+becomes active when a ``virgin'' \TeX\ is trying to get going, just after
+the preliminary initialization, or when the user is substituting another
+format file by typing `\.\&' after the initial `\.{**}' prompt.  The buffer
+contains the first line of input in $\\{buffer}[\\{loc}\to(\\{last}-1)]$, where
+$\\{loc}<\\{last}$ and $\\{buffer}[\\{loc}]\I\.{"\ "}$.
+
+\Y\P$\4\X535:Declare the function called \\{open\_fmt\_file}\X\S$\6
+\4\&{function}\1\  \37\\{open\_fmt\_file}: \37\\{boolean};\6
+\4\&{label} \37$\\{found},\39\\{exit}$;\6
+\4\&{var} \37\|j: \37$0\to\\{buf\_size}$;\C{the first space after the format
+file name}\2\6
+\&{begin} \37$\|j\K\\{loc}$;\6
+\&{if} $\\{buffer}[\\{loc}]=\.{"\&"}$ \1\&{then}\6
+\&{begin} \37$\\{incr}(\\{loc})$;\5
+$\|j\K\\{loc}$;\5
+$\\{buffer}[\\{last}]\K\.{"\ "}$;\6
+\&{while} $\\{buffer}[\|j]\I\.{"\ "}$ \1\&{do}\5
+$\\{incr}(\|j)$;\2\6
+$\\{pack\_buffered\_name}(0,\39\\{loc},\39\|j-1)$;\C{Kpathsea does everything}\6
+\&{if} $\\{w\_open\_in}(\\{fmt\_file})$ \1\&{then}\5
+\&{goto} \37\\{found};\2\6
+\\{wake\_up\_terminal};\5
+$\\{wterm}(\.{\'Sorry,\ I\ can\'}\.{\'t\ find\ the\ format\ \`\'})$;\5
+$\\{fputs}(\\{stringcast}(\\{name\_of\_file}+1),\39\\{stdout})$;\5
+$\\{wterm}(\.{\'\'}\.{\';\ will\ try\ \`\'})$;\5
+$\\{fputs}(\\{TEX\_format\_default}+1,\39\\{stdout})$;\5
+$\\{wterm\_ln}(\.{\'\'}\.{\'.\'})$;\5
+\\{update\_terminal};\6
+\&{end};\C{now pull out all the stops: try for the system \.{plain} file}\2\6
+$\\{pack\_buffered\_name}(\\{format\_default\_length}-\\{format\_ext\_length},%
+\391,\390)$;\6
+\&{if} $\R\\{w\_open\_in}(\\{fmt\_file})$ \1\&{then}\6
+\&{begin} \37\\{wake\_up\_terminal};\5
+$\\{wterm}(\.{\'I\ can\'}\.{\'t\ find\ the\ format\ file\ \`\'})$;\5
+$\\{fputs}(\\{TEX\_format\_default}+1,\39\\{stdout})$;\5
+$\\{wterm\_ln}(\.{\'\'}\.{\'!\'})$;\5
+$\\{open\_fmt\_file}\K\\{false}$;\5
+\&{return};\6
+\&{end};\2\6
+\4\\{found}: \37$\\{loc}\K\|j$;\5
+$\\{open\_fmt\_file}\K\\{true}$;\6
+\4\\{exit}: \37\&{end};\par
+\U1316.\fi
+
+\M536. Operating systems often make it possible to determine the exact name
+(and
+possible version number) of a file that has been opened. The following routine,
+which simply makes a \TeX\ string from the value of \\{name\_of\_file}, should
+ideally be changed to deduce the full name of file~\|f, which is the file
+most recently opened, if it is possible to do this in a \PASCAL\ program.
+
+This routine might be called after string memory has overflowed, hence
+we dare not use `\\{str\_room}'.
+
+\Y\P\4\&{function}\1\  \37\\{make\_name\_string}: \37\\{str\_number};\6
+\4\&{var} \37\|k: \37$1\to\\{file\_name\_size}$;\C{index into \\{name\_of%
+\_file}}\6
+$\\{save\_area\_delimiter},\39\\{save\_ext\_delimiter}$: \37\\{pool\_pointer};\5
+$\\{save\_name\_in\_progress},\39\\{save\_stop\_at\_space}$: \37\\{boolean};\2\6
+\&{begin} \37\&{if} $(\\{pool\_ptr}+\\{name\_length}>\\{pool\_size})\V(\\{str%
+\_ptr}=\\{max\_strings})\V(\\{cur\_length}>0)$ \1\&{then}\5
+$\\{make\_name\_string}\K\.{"?"}$\6
+\4\&{else} \&{begin} \37\&{for} $\|k\K1\mathrel{\&{to}}\\{name\_length}$ \1%
+\&{do}\5
+$\\{append\_char}(\\{xord}[\\{name\_of\_file}[\|k]])$;\2\6
+$\\{make\_name\_string}\K\\{make\_string}$;\C{At this point we also set \\{cur%
+\_name}, \\{cur\_ext}, and \\{cur\_area} to    match the contents of \\{name%
+\_of\_file}.}\6
+$\\{save\_area\_delimiter}\K\\{area\_delimiter}$;\5
+$\\{save\_ext\_delimiter}\K\\{ext\_delimiter}$;\5
+$\\{save\_name\_in\_progress}\K\\{name\_in\_progress}$;\5
+$\\{save\_stop\_at\_space}\K\\{stop\_at\_space}$;\5
+$\\{name\_in\_progress}\K\\{true}$;\5
+\\{begin\_name};\5
+$\\{stop\_at\_space}\K\\{false}$;\5
+$\|k\K1$;\6
+\&{while} $(\|k\L\\{name\_length})\W(\\{more\_name}(\\{name\_of\_file}[\|k]))$ %
+\1\&{do}\5
+$\\{incr}(\|k)$;\2\6
+$\\{stop\_at\_space}\K\\{save\_stop\_at\_space}$;\5
+\\{end\_name};\5
+$\\{name\_in\_progress}\K\\{save\_name\_in\_progress}$;\5
+$\\{area\_delimiter}\K\\{save\_area\_delimiter}$;\5
+$\\{ext\_delimiter}\K\\{save\_ext\_delimiter}$;\6
+\&{end};\2\6
+\&{end};\6
+\4\&{function}\1\  \37$\\{a\_make\_name\_string}(\mathop{\&{var}}\|f:\\{alpha%
+\_file})$: \37\\{str\_number};\2\6
+\&{begin} \37$\\{a\_make\_name\_string}\K\\{make\_name\_string}$;\6
+\&{end};\6
+\4\&{function}\1\  \37$\\{b\_make\_name\_string}(\mathop{\&{var}}\|f:\\{byte%
+\_file})$: \37\\{str\_number};\2\6
+\&{begin} \37$\\{b\_make\_name\_string}\K\\{make\_name\_string}$;\6
+\&{end};\6
+\4\&{function}\1\  \37$\\{w\_make\_name\_string}(\mathop{\&{var}}\|f:\\{word%
+\_file})$: \37\\{str\_number};\2\6
+\&{begin} \37$\\{w\_make\_name\_string}\K\\{make\_name\_string}$;\6
+\&{end};\par
+\fi
+
+\M537. Now let's consider the ``driver''
+routines by which \TeX\ deals with file names
+in a system-independent manner.  First comes a procedure that looks for a
+file name in the input by calling \\{get\_x\_token} for the information.
+
+\Y\P\4\&{procedure}\1\  \37\\{scan\_file\_name};\6
+\4\&{label} \37\\{done};\2\6
+\&{begin} \37$\\{name\_in\_progress}\K\\{true}$;\5
+\\{begin\_name};\5
+\X417:Get the next non-blank non-call token\X;\6
+$\\{skip\_mode}\K\\{false}$;\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=%
+\\{kana})\V(\\{cur\_cmd}=\\{other\_kchar})$ \1\&{then}\C{is kanji}\6
+\&{begin} \37$\\{str\_room}(2)$;\5
+$\\{append\_char}(\\{Hi}(\\{cur\_chr}))$;\C{kanji upper byte}\6
+$\\{append\_char}(\\{Lo}(\\{cur\_chr}))$;\C{kanji lower byte}\6
+\&{end}\6
+\4\&{else} \&{if} $(\\{cur\_cmd}>\\{other\_char})\V(\\{cur\_chr}>255)$ \1%
+\&{then}\C{not a alphabet}\6
+\&{begin} \37\\{back\_input};\5
+\&{goto} \37\\{done};\6
+\&{end}\C{If \\{cur\_chr} is a space and we're not scanning a token list, check
+   whether we're at the end of the buffer. Otherwise we end up adding
+spurious spaces to file names in some cases.}\6
+\4\&{else} \&{if} $((\\{cur\_chr}=\.{"\ "})\W(\\{state}\I\\{token\_list})\W(%
+\\{loc}>\\{limit}))\V\R\\{more\_name}(\\{cur\_chr})$ \1\&{then}\5
+\&{goto} \37\\{done};\2\2\2\6
+\\{get\_x\_token};\6
+\&{end};\2\6
+\4\\{done}: \37\\{end\_name};\5
+$\\{name\_in\_progress}\K\\{false}$;\5
+$\\{skip\_mode}\K\\{true}$;\6
+\&{end};\par
+\fi
+
+\M538. The global variable \\{name\_in\_progress} is used to prevent recursive
+use of \\{scan\_file\_name}, since the \\{begin\_name} and other procedures
+communicate via global variables. Recursion would arise only by
+devious tricks like `\.{\\input\\input f}'; such attempts at sabotage
+must be thwarted. Furthermore, \\{name\_in\_progress} prevents \.{\\input}
+from being initiated when a font size specification is being scanned.
+
+Another global variable, \\{job\_name}, contains the file name that was first
+\.{\\input} by the user. This name is extended by `\.{.log}' and `\.{.dvi}'
+and `\.{.fmt}' in the names of \TeX's output files.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{name\_in\_progress}: \37\\{boolean};\C{is a file name being scanned?}\6
+\4\\{job\_name}: \37\\{str\_number};\C{principal file name}\6
+\4\\{log\_opened}: \37\\{boolean};\C{has the transcript file been opened?}\par
+\fi
+
+\M539. Initially $\\{job\_name}=0$; it becomes nonzero as soon as the true name
+is known.
+We have $\\{job\_name}=0$ if and only if the `\.{log}' file has not been
+opened,
+except of course for a short time just after \\{job\_name} has become nonzero.
+
+\Y\P$\4\X56:Initialize the output routines\X\mathrel{+}\S$\6
+$\\{job\_name}\K0$;\5
+$\\{name\_in\_progress}\K\\{false}$;\5
+$\\{log\_opened}\K\\{false}$;\par
+\fi
+
+\M540. Here is a routine that manufactures the output file names, assuming that
+$\\{job\_name}\I0$. It ignores and changes the current settings of \\{cur%
+\_area}
+and \\{cur\_ext}.
+
+\Y\P\D \37$\\{pack\_cur\_name}\S\\{pack\_file\_name}(\\{cur\_name},\39\\{cur%
+\_area},\39\\{cur\_ext})$\par
+\Y\P\4\&{procedure}\1\  \37$\\{pack\_job\_name}(\|s:\\{str\_number})$;\C{$\|s=%
+\.{".log"}$, \.{".dvi"}, or   \\{format\_extension}}\2\6
+\&{begin} \37$\\{cur\_area}\K\.{""}$;\5
+$\\{cur\_ext}\K\|s$;\5
+$\\{cur\_name}\K\\{job\_name}$;\5
+\\{pack\_cur\_name};\6
+\&{end};\par
+\fi
+
+\M541. If some trouble arises when \TeX\ tries to open a file, the following
+routine calls upon the user to supply another file name. Parameter~\|s
+is used in the error message to identify the type of file; parameter~\|e
+is the default extension if none is given. Upon exit from the routine,
+variables \\{cur\_name}, \\{cur\_area}, \\{cur\_ext}, and \\{name\_of\_file}
+are
+ready for another attempt at file opening.
+
+\Y\P\4\&{procedure}\1\  \37$\\{prompt\_file\_name}(\|s,\39\|e:\\{str%
+\_number})$;\6
+\4\&{label} \37\\{done};\6
+\4\&{var} \37\|k: \37$0\to\\{buf\_size}$;\C{index into \\{buffer}}\6
+\\{saved\_cur\_name}: \37\\{str\_number};\C{to catch empty terminal input}\6
+\\{saved\_cur\_ext}: \37\\{str\_number};\C{to catch empty terminal input}\6
+\\{saved\_cur\_area}: \37\\{str\_number};\C{to catch empty terminal input}\2\6
+\&{begin} \37\&{if} $\\{interaction}=\\{scroll\_mode}$ \1\&{then}\5
+\\{wake\_up\_terminal};\2\6
+\&{if} $\|s=\.{"input\ file\ name"}$ \1\&{then}\5
+$\\{print\_err}(\.{"I\ can\'t\ find\ file\ \`"})$\6
+\4\&{else} $\\{print\_err}(\.{"I\ can\'t\ write\ on\ file\ \`"})$;\2\6
+$\\{print\_file\_name}(\\{cur\_name},\39\\{cur\_area},\39\\{cur\_ext})$;\5
+$\\{print}(\.{"\'."})$;\6
+\&{if} $(\|e=\.{".tex"})\V(\|e=\.{""})$ \1\&{then}\5
+\\{show\_context};\2\6
+\\{print\_ln};\5
+$\\{print\_c\_string}(\\{prompt\_file\_name\_help\_msg})$;\6
+\&{if} $(\|e\I\.{""})$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{";\ default\ file\ extension\ is\ \`"})$;\5
+$\\{print}(\|e)$;\5
+$\\{print}(\.{"\'"})$;\6
+\&{end};\2\6
+$\\{print}(\.{")"})$;\5
+\\{print\_ln};\5
+$\\{print\_nl}(\.{"Please\ type\ another\ "})$;\5
+$\\{print}(\|s)$;\6
+\&{if} $\\{interaction}<\\{scroll\_mode}$ \1\&{then}\5
+$\\{fatal\_error}(\.{"***\ (job\ aborted,\ file\ error\ in\ nonstop\ mode)"})$;%
+\2\6
+$\\{saved\_cur\_name}\K\\{cur\_name}$;\5
+$\\{saved\_cur\_ext}\K\\{cur\_ext}$;\5
+$\\{saved\_cur\_area}\K\\{cur\_area}$;\5
+\\{clear\_terminal};\5
+$\\{prompt\_input}(\.{":\ "})$;\5
+\X542:Scan file name in the buffer\X;\6
+\&{if} $(\\{length}(\\{cur\_name})=0)\W(\\{cur\_ext}=\.{""})\W(\\{cur\_area}=%
+\.{""})$ \1\&{then}\6
+\&{begin} \37$\\{cur\_name}\K\\{saved\_cur\_name}$;\5
+$\\{cur\_ext}\K\\{saved\_cur\_ext}$;\5
+$\\{cur\_area}\K\\{saved\_cur\_area}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{cur\_ext}=\.{""}$ \1\&{then}\5
+$\\{cur\_ext}\K\|e$;\2\2\6
+\\{pack\_cur\_name};\6
+\&{end};\par
+\fi
+
+\M542. \P$\X542:Scan file name in the buffer\X\S$\6
+\&{begin} \37\\{begin\_name};\5
+$\|k\K\\{first}$;\6
+\&{while} $(\\{buffer}[\|k]=\.{"\ "})\W(\|k<\\{last})$ \1\&{do}\5
+$\\{incr}(\|k)$;\2\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\|k=\\{last}$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+\&{if} $\R\\{more\_name}(\\{buffer}[\|k])$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\\{incr}(\|k)$;\6
+\&{end};\2\6
+\4\\{done}: \37\\{end\_name};\6
+\&{end}\par
+\U541.\fi
+
+\M543. Here's an example of how these conventions are used. Whenever it is time
+to
+ship out a box of stuff, we shall use the macro \\{ensure\_dvi\_open}.
+
+\Y\P\D \37$\\{log\_name}\S\\{texmf\_log\_name}$\par
+\P\D \37$\\{ensure\_dvi\_open}\S$\1\6
+\&{if} $\\{output\_file\_name}=0$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{job\_name}=0$ \1\&{then}\5
+\\{open\_log\_file};\2\6
+$\\{pack\_job\_name}(\.{".dvi"})$;\6
+\&{while} $\R\\{b\_open\_out}(\\{dvi\_file})$ \1\&{do}\5
+$\\{prompt\_file\_name}(\.{"file\ name\ for\ output"},\39\.{".dvi"})$;\2\6
+$\\{output\_file\_name}\K\\{b\_make\_name\_string}(\\{dvi\_file})$;\6
+\&{end}\2\2\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{dvi\_file}: \37\\{byte\_file};\C{the device-independent output goes here}\6
+\4\\{output\_file\_name}: \37\\{str\_number};\C{full name of the output file}\6
+\4\\{log\_name}: \37\\{str\_number};\C{full name of the log file}\par
+\fi
+
+\M544. \P$\X56:Initialize the output routines\X\mathrel{+}\S$\6
+$\\{output\_file\_name}\K0$;\par
+\fi
+
+\M545. The \\{open\_log\_file} routine is used to open the transcript file and
+to help
+it catch up to what has previously been printed on the terminal.
+
+\Y\P\4\&{procedure}\1\  \37\\{open\_log\_file};\6
+\4\&{var} \37\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{previous %
+\\{selector} setting}\6
+\|k: \37$0\to\\{buf\_size}$;\C{index into \\{months} and \\{buffer}}\6
+\|l: \37$0\to\\{buf\_size}$;\C{end of first input line}\6
+\\{months}: \37\\{const\_cstring};\2\6
+\&{begin} \37$\\{old\_setting}\K\\{selector}$;\6
+\&{if} $\\{job\_name}=0$ \1\&{then}\5
+$\\{job\_name}\K\\{get\_job\_name}(\.{"texput"})$;\2\6
+$\\{pack\_job\_name}(\.{".fls"})$;\5
+$\\{recorder\_change\_filename}(\\{stringcast}(\\{name\_of\_file}+1))$;\5
+$\\{pack\_job\_name}(\.{".log"})$;\6
+\&{while} $\R\\{a\_open\_out}(\\{log\_file})$ \1\&{do}\5
+\X546:Try to get a different log file name\X;\2\6
+$\\{log\_name}\K\\{a\_make\_name\_string}(\\{log\_file})$;\5
+$\\{selector}\K\\{log\_only}$;\5
+$\\{log\_opened}\K\\{true}$;\5
+\X547:Print the banner line, including the date and time\X;\6
+\&{if} $\\{mltex\_enabled\_p}$ \1\&{then}\6
+\&{begin} \37\\{wlog\_cr};\5
+$\\{wlog}(\.{\'MLTeX\ v2.2\ enabled\'})$;\6
+\&{end};\2\6
+$\\{input\_stack}[\\{input\_ptr}]\K\\{cur\_input}$;\C{make sure bottom level is
+in memory}\6
+$\\{print\_nl}(\.{"**"})$;\5
+$\|l\K\\{input\_stack}[0].\\{limit\_field}$;\C{last position of first line}\6
+\&{if} $\\{buffer}[\|l]=\\{end\_line\_char}$ \1\&{then}\5
+$\\{decr}(\|l)$;\2\6
+\&{for} $\|k\K1\mathrel{\&{to}}\|l$ \1\&{do}\5
+$\\{print}(\\{buffer}[\|k])$;\2\6
+\\{print\_ln};\C{now the transcript file contains the first line of input}\6
+$\\{selector}\K\\{old\_setting}+2$;\C{\\{log\_only} or \\{term\_and\_log}}\6
+\&{end};\par
+\fi
+
+\M546. Sometimes \\{open\_log\_file} is called at awkward moments when \TeX\ is
+unable to print error messages or even to \\{show\_context}.
+The \\{prompt\_file\_name} routine can result in a \\{fatal\_error}, but the %
+\\{error}
+routine will not be invoked because \\{log\_opened} will be false.
+
+The normal idea of \\{batch\_mode} is that nothing at all should be written
+on the terminal. However, in the unusual case that
+no log file could be opened, we make an exception and allow
+an explanatory message to be seen.
+
+Incidentally, the program always refers to the log file as a `\.{transcript
+file}', because some systems cannot use the extension `\.{.log}' for
+this file.
+
+\Y\P$\4\X546:Try to get a different log file name\X\S$\6
+\&{begin} \37$\\{selector}\K\\{term\_only}$;\5
+$\\{prompt\_file\_name}(\.{"transcript\ file\ name"},\39\.{".log"})$;\6
+\&{end}\par
+\U545.\fi
+
+\M547. \P$\X547:Print the banner line, including the date and time\X\S$\6
+\&{begin} \37\&{if} $\\{src\_specials\_p}\V\\{file\_line\_error\_style\_p}\V%
+\\{parse\_first\_line\_p}$ \1\&{then}\5
+$\\{wlog}(\\{banner\_k})$\6
+\4\&{else} $\\{wlog}(\\{banner})$;\2\6
+$\\{wlog}(\.{\'\ (\'})$;\5
+$\\{wlog}(\\{conststringcast}(\\{get\_enc\_string}))$;\5
+$\\{wlog}(\.{\')\'})$;\5
+$\\{wlog}(\\{version\_string})$;\5
+$\\{slow\_print}(\\{format\_ident})$;\5
+$\\{print}(\.{"\ \ "})$;\5
+$\\{print\_int}(\\{day})$;\5
+$\\{print\_char}(\.{"\ "})$;\5
+$\\{months}\K\.{\'\ JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC\'}$;\6
+\&{for} $\|k\K3\ast\\{month}-2\mathrel{\&{to}}3\ast\\{month}$ \1\&{do}\5
+$\\{wlog}(\\{months}[\|k])$;\2\6
+$\\{print\_char}(\.{"\ "})$;\5
+$\\{print\_int}(\\{year})$;\5
+$\\{print\_char}(\.{"\ "})$;\5
+$\\{print\_two}(\\{time}\mathbin{\&{div}}60)$;\5
+$\\{print\_char}(\.{":"})$;\5
+$\\{print\_two}(\\{time}\mathbin{\&{mod}}60)$;\6
+\&{if} $\\{shellenabledp}$ \1\&{then}\6
+\&{begin} \37\\{wlog\_cr};\5
+$\\{wlog}(\.{\'\ \'})$;\6
+\&{if} $\\{restrictedshell}$ \1\&{then}\6
+\&{begin} \37$\\{wlog}(\.{\'restricted\ \'})$;\6
+\&{end};\2\6
+$\\{wlog}(\.{\'\\write18\ enabled.\'})$\6
+\&{end};\2\6
+\&{if} $\\{src\_specials\_p}$ \1\&{then}\6
+\&{begin} \37\\{wlog\_cr};\5
+$\\{wlog}(\.{\'\ Source\ specials\ enabled.\'})$\6
+\&{end};\2\6
+\&{if} $\\{file\_line\_error\_style\_p}$ \1\&{then}\6
+\&{begin} \37\\{wlog\_cr};\5
+$\\{wlog}(\.{\'\ file:line:error\ style\ messages\ enabled.\'})$\6
+\&{end};\2\6
+\&{if} $\\{parse\_first\_line\_p}$ \1\&{then}\6
+\&{begin} \37\\{wlog\_cr};\5
+$\\{wlog}(\.{\'\ \%\&-line\ parsing\ enabled.\'})$;\6
+\&{end};\2\6
+\&{if} $\\{translate\_filename}$ \1\&{then}\6
+\&{begin} \37\\{wlog\_cr};\5
+$\\{wlog}(\.{\'\ (\'})$;\5
+$\\{fputs}(\\{translate\_filename},\39\\{log\_file})$;\5
+$\\{wlog}(\.{\')\'})$;\6
+\&{end};\2\6
+\&{end}\par
+\U545.\fi
+
+\M548. Let's turn now to the procedure that is used to initiate file reading
+when an `\.{\\input}' command is being processed.
+
+\Y\P\4\&{procedure}\1\  \37\\{start\_input};\C{\TeX\ will \.{\\input}
+something}\6
+\4\&{label} \37\\{done};\6
+\4\&{var} \37\\{temp\_str}: \37\\{str\_number};\2\6
+\&{begin} \37\\{scan\_file\_name};\C{set \\{cur\_name} to desired file name}\6
+\\{pack\_cur\_name};\6
+\~ \1\&{loop}\ \&{begin} \37\\{begin\_file\_reading};\C{set up \\{cur\_file}
+and new level of input}\6
+$\\{tex\_input\_type}\K1$;\C{Tell \\{open\_input} we are \.{\\input}.}\6
+\C{Kpathsea tries all the various ways to get the file.}\6
+\&{if} $\\{kpse\_in\_name\_ok}(\\{stringcast}(\\{name\_of\_file}+1))\W\\{a%
+\_open\_in}(\\{cur\_file},\39\\{kpse\_tex\_format})$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+\\{end\_file\_reading};\C{remove the level that didn't work}\6
+$\\{prompt\_file\_name}(\.{"input\ file\ name"},\39\.{""})$;\6
+\&{end};\2\6
+\4\\{done}: \37$\\{name}\K\\{a\_make\_name\_string}(\\{cur\_file})$;\5
+$\\{source\_filename\_stack}[\\{in\_open}]\K\\{name}$;\5
+$\\{full\_source\_filename\_stack}[\\{in\_open}]\K\\{make\_full\_name%
+\_string}$;\6
+\&{if} $\\{name}=\\{str\_ptr}-1$ \1\&{then}\C{we can try to conserve string
+pool space now}\6
+\&{begin} \37$\\{temp\_str}\K\\{search\_string}(\\{name})$;\6
+\&{if} $\\{temp\_str}>0$ \1\&{then}\6
+\&{begin} \37$\\{name}\K\\{temp\_str}$;\5
+\\{flush\_string};\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{job\_name}=0$ \1\&{then}\6
+\&{begin} \37$\\{job\_name}\K\\{get\_job\_name}(\\{cur\_name})$;\5
+\\{open\_log\_file};\6
+\&{end};\C{\\{open\_log\_file} doesn't \\{show\_context}, so \\{limit}     and %
+\\{loc} needn't be set to meaningful values yet}\2\6
+\&{if} $\\{term\_offset}+\\{length}(\\{full\_source\_filename\_stack}[\\{in%
+\_open}])>\\{max\_print\_line}-2$ \1\&{then}\5
+\\{print\_ln}\6
+\4\&{else} \&{if} $(\\{term\_offset}>0)\V(\\{file\_offset}>0)$ \1\&{then}\5
+$\\{print\_char}(\.{"\ "})$;\2\2\6
+$\\{print\_char}(\.{"("})$;\5
+$\\{incr}(\\{open\_parens})$;\5
+$\\{slow\_print}(\\{full\_source\_filename\_stack}[\\{in\_open}])$;\5
+\\{update\_terminal};\5
+$\\{state}\K\\{new\_line}$;\5
+\X549:Read the first line of the new file\X;\6
+\&{end};\par
+\fi
+
+\M549. Here we have to remember to tell the \\{input\_ln} routine not to
+start with a \\{get}. If the file is empty, it is considered to
+contain a single blank line.
+
+\Y\P$\4\X549:Read the first line of the new file\X\S$\6
+\&{begin} \37$\\{line}\K1$;\6
+\&{if} $\\{input\_ln}(\\{cur\_file},\39\\{false})$ \1\&{then}\5
+\\{do\_nothing};\2\6
+\\{firm\_up\_the\_line};\6
+\&{if} $\\{end\_line\_char\_inactive}$ \1\&{then}\5
+$\\{decr}(\\{limit})$\6
+\4\&{else} $\\{buffer}[\\{limit}]\K\\{end\_line\_char}$;\2\6
+$\\{first}\K\\{limit}+1$;\5
+$\\{loc}\K\\{start}$;\6
+\&{end}\par
+\U548.\fi
+
+\N550.  \[30] Font metric data.
+\TeX\ gets its knowledge about fonts from font metric files, also called
+\.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX,
+but other programs know about them too.
+
+The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
+Since the number of bytes is always a multiple of 4, we could
+also regard the file as a sequence of 32-bit words, but \TeX\ uses the
+byte interpretation. The format of \.{TFM} files was designed by
+Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
+of information in a compact but useful form.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{tfm\_file}: \37\\{byte\_file};\par
+\fi
+
+\M551. The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
+integers that give the lengths of the various subsequent portions
+of the file. These twelve integers are, in order:
+$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
+\\{lf}&length of the entire file, in words;\cr
+\\{lh}&length of the header data, in words;\cr
+\\{bc}&smallest character code in the font;\cr
+\\{ec}&largest character code in the font;\cr
+\\{nw}&number of words in the width table;\cr
+\\{nh}&number of words in the height table;\cr
+\\{nd}&number of words in the depth table;\cr
+\\{ni}&number of words in the italic correction table;\cr
+\\{nl}&number of words in the lig/kern table;\cr
+\\{nk}&number of words in the kern table;\cr
+\\{ne}&number of words in the extensible character table;\cr
+\\{np}&number of font parameter words.\cr}}$$
+They are all nonnegative and less than $2^{15}$. We must have $\\{bc}-1\L\\{ec}%
+\L255$,
+and
+$$\hbox{$\\{lf}=6+\\{lh}+(\\{ec}-\\{bc}+1)+\\{nw}+\\{nh}+\\{nd}+\\{ni}+\\{nl}+%
+\\{nk}+\\{ne}+\\{np}$.}$$
+Note that a font may contain as many as 256 characters (if $\\{bc}=0$ and $%
+\\{ec}=255$),
+and as few as 0 characters (if $\\{bc}=\\{ec}+1$).
+
+Incidentally, when two or more 8-bit bytes are combined to form an integer of
+16 or more bits, the most significant bytes appear first in the file.
+This is called BigEndian order.
+
+We use to get \TeX\ knowledge about KANJI fonts from \.{JFM} files.
+The \.{JFM} format holds more two 16-bit integers ,\\{id} and \\{nt},
+at the top of the file.
+$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
+\\{id}&identification code of the file;\cr
+\\{nt}&number of words in the \\{char\_type} table;\cr}}$$
+The identification byte, \\{id} equals~11 or~9. When \TeX read a font file,
+the \\{id} equals~11 or~9 then the font is the \.{JFM}, othercases it is
+the \.{TFM} file. The \.{TFM} holds \\{lf} at the same postion of \\{id},
+usually it take a larger number than~9 or~11.
+The \\{nt} is nonngative and less than $2^{15}$.
+
+We must have $\\{ec}=0$,
+$$\hbox{$\\{lf}=7+\\{lh}+\\{nt}+(\\{ec}-\\{bc}+1)+\\{nw}+\\{nh}+\\{nd}+\\{ni}+%
+\\{nl}+\\{nk}+\\{ne}+\\{np}$.}$$
+
+\Y\P\D \37$\\{yoko\_jfm\_id}=11$\C{for `yoko-kumi' fonts}\par
+\P\D \37$\\{tate\_jfm\_id}=9$\C{for `tate-kumi' fonts}\par
+\fi
+
+\M552. The rest of the \.{TFM} file may be regarded as a sequence of ten data
+arrays having the informal specification
+$$\def\arr$[#1]#2${\&{array} $[#1]$ \&{of} #2}
+\vbox{\halign{\hfil\\{#}&$\,:\,$\arr#\hfil\cr
+header&$[0\to\\{lh}-1]\hbox{\\{stuff}}$\cr
+char\_info&$[\\{bc}\to\\{ec}]\\{char\_info\_word}$\cr
+width&$[0\to\\{nw}-1]\\{fix\_word}$\cr
+height&$[0\to\\{nh}-1]\\{fix\_word}$\cr
+depth&$[0\to\\{nd}-1]\\{fix\_word}$\cr
+italic&$[0\to\\{ni}-1]\\{fix\_word}$\cr
+lig\_kern&$[0\to\\{nl}-1]\\{lig\_kern\_command}$\cr
+kern&$[0\to\\{nk}-1]\\{fix\_word}$\cr
+exten&$[0\to\\{ne}-1]\\{extensible\_recipe}$\cr
+param&$[1\to\\{np}]\\{fix\_word}$\cr}}$$
+The most important data type used here is a \\{fix\_word}, which is
+a 32-bit representation of a binary fraction. A \\{fix\_word} is a signed
+quantity, with the two's complement of the entire word used to represent
+negation. Of the 32 bits in a \\{fix\_word}, exactly 12 are to the left of the
+binary point; thus, the largest \\{fix\_word} value is $2048-2^{-20}$, and
+the smallest is $-2048$. We will see below, however, that all but two of
+the \\{fix\_word} values must lie between $-16$ and $+16$.
+
+\fi
+
+\M553. The first data array is a block of header information, which contains
+general facts about the font. The header must contain at least two words,
+$\\{header}[0]$ and $\\{header}[1]$, whose meaning is explained below.
+Additional header information of use to other software routines might
+also be included, but \TeX82 does not need to know about such details.
+For example, 16 more words of header information are in use at the Xerox
+Palo Alto Research Center; the first ten specify the character coding
+scheme used (e.g., `\.{XEROX text}' or `\.{TeX math symbols}'), the next five
+give the font identifier (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
+last gives the ``face byte.'' The program that converts \.{DVI} files
+to Xerox printing format gets this information by looking at the \.{TFM}
+file, which it needs to read anyway because of other information that
+is not explicitly repeated in \.{DVI}~format.
+
+\yskip\hang$\\{header}[0]$ is a 32-bit check sum that \TeX\ will copy into
+the \.{DVI} output file. Later on when the \.{DVI} file is printed,
+possibly on another computer, the actual font that gets used is supposed
+to have a check sum that agrees with the one in the \.{TFM} file used by
+\TeX. In this way, users will be warned about potential incompatibilities.
+(However, if the check sum is zero in either the font file or the \.{TFM}
+file, no check is made.)  The actual relation between this check sum and
+the rest of the \.{TFM} file is not important; the check sum is simply an
+identification number with the property that incompatible fonts almost
+always have distinct check sums.
+
+\yskip\hang$\\{header}[1]$ is a \\{fix\_word} containing the design size of
+the font, in units of \TeX\ points. This number must be at least 1.0; it is
+fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
+font, i.e., a font that was designed to look best at a 10-point size,
+whatever that really means. When a \TeX\ user asks for a font
+`\.{at} $\delta$ \.{pt}', the effect is to override the design size
+and replace it by $\delta$, and to multiply the $x$ and~$y$ coordinates
+of the points in the font image by a factor of $\delta$ divided by the
+design size.  {\sl All other dimensions in the\/ \.{TFM} file are
+\\{fix\_word}\kern-1pt\ numbers in design-size units}, with the exception of
+$\\{param}[1]$ (which denotes the slant ratio). Thus, for example, the value
+of $\\{param}[6]$, which defines the \.{em} unit, is often the \\{fix\_word}
+value
+$2^{20}=1.0$, since many fonts have a design size equal to one em.
+The other dimensions must be less than 16 design-size units in absolute
+value; thus, $\\{header}[1]$ and $\\{param}[1]$ are the only \\{fix\_word}
+entries in the whole \.{TFM} file whose first byte might be something
+besides 0 or 255.
+
+\fi
+
+\M554. Next comes the \\{char\_info} array, which contains one \\{char\_info%
+\_word}
+per character. Each word in this part of the file contains six fields
+packed into four bytes as follows.
+
+\yskip\hang first byte: \\{width\_index} (8 bits)\par
+\hang second byte: \\{height\_index} (4 bits) times 16, plus \\{depth\_index}
+(4~bits)\par
+\hang third byte: \\{italic\_index} (6 bits) times 4, plus \\{tag}
+(2~bits)\par
+\hang fourth byte: \\{remainder} (8 bits)\par
+\yskip\noindent
+The actual width of a character is \\{width}$[\\{width\_index}]$, in
+design-size
+units; this is a device for compressing information, since many characters
+have the same width. Since it is quite common for many characters
+to have the same height, depth, or italic correction, the \.{TFM} format
+imposes a limit of 16 different heights, 16 different depths, and
+64 different italic corrections.
+
+The italic correction of a character has two different uses.
+(a)~In ordinary text, the italic correction is added to the width only if
+the \TeX\ user specifies `\.{\\/}' after the character.
+(b)~In math formulas, the italic correction is always added to the width,
+except with respect to the positioning of subscripts.
+
+Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
+\\{italic}[0]=0$ should always hold, so that an index of zero implies a
+value of zero.  The \\{width\_index} should never be zero unless the
+character does not exist in the font, since a character is valid if and
+only if it lies between \\{bc} and \\{ec} and has a nonzero \\{width\_index}.
+
+\fi
+
+\M555. The \\{tag} field in a \\{char\_info\_word} has four values that explain
+how to
+interpret the \\{remainder} field.
+
+\yskip\hangg$\\{tag}=0$ (\\{no\_tag}) means that \\{remainder} is unused.\par
+\hangg$\\{tag}=1$ (\\{lig\_tag}) means that this character has a
+ligature/kerning
+program starting at position \\{remainder} in the \\{lig\_kern} array.\par
+\hangg$\\{tag}=2$ (\\{list\_tag}) means that this character is part of a chain
+of
+characters of ascending sizes, and not the largest in the chain.  The
+\\{remainder} field gives the character code of the next larger character.\par
+\hangg$\\{tag}=3$ (\\{ext\_tag}) means that this character code represents an
+extensible character, i.e., a character that is built up of smaller pieces
+so that it can be made arbitrarily large. The pieces are specified in
+$\\{exten}[\\{remainder}]$.\par
+\yskip\noindent
+Characters with $\\{tag}=2$ and $\\{tag}=3$ are treated as characters with $%
+\\{tag}=0$
+unless they are used in special circumstances in math formulas. For example,
+the \.{\\sum} operation looks for a \\{list\_tag}, and the \.{\\left}
+operation looks for both \\{list\_tag} and \\{ext\_tag}.
+
+If the \.{JFM}, the \\{lig\_tag} is called \\{gk\_tag}. The \\{gk\_tag} means
+that
+this character has a glue/kerning program starting at position \\{remainder}
+in the \\{glue\_kern} array. And a \.{JFM} not used $\\{tag}=2$ and $%
+\\{tag}=3$.
+
+\Y\P\D \37$\\{no\_tag}=0$\C{vanilla character}\par
+\P\D \37$\\{lig\_tag}=1$\C{character has a ligature/kerning program}\par
+\P\D \37$\\{gk\_tag}=1$\C{character has a glue/kerning program}\par
+\P\D \37$\\{list\_tag}=2$\C{character has a successor in a charlist}\par
+\P\D \37$\\{ext\_tag}=3$\C{character is extensible}\par
+\fi
+
+\M556. The \\{lig\_kern} array contains instructions in a simple programming
+language
+that explains what to do for special letter pairs. Each word in this array is a
+\\{lig\_kern\_command} of four bytes.
+
+\yskip\hang first byte: \\{skip\_byte}, indicates that this is the final
+program
+step if the byte is 128 or more, otherwise the next step is obtained by
+skipping this number of intervening steps.\par
+\hang second byte: \\{next\_char}, ``if \\{next\_char} follows the current
+character,
+then perform the operation and stop, otherwise continue.''\par
+\hang third byte: \\{op\_byte}, indicates a ligature step if less than~128,
+a kern step otherwise.\par
+\hang fourth byte: \\{remainder}.\par
+\yskip\noindent
+In a kern step, an
+additional space equal to $\\{kern}[256\ast(\\{op\_byte}-128)+\\{remainder}]$
+is inserted
+between the current character and \\{next\_char}. This amount is
+often negative, so that the characters are brought closer together
+by kerning; but it might be positive.
+
+There are eight kinds of ligature steps, having \\{op\_byte} codes $4a+2b+c$
+where
+$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
+\\{remainder} is inserted between the current character and \\{next\_char};
+then the current character is deleted if $b=0$, and \\{next\_char} is
+deleted if $c=0$; then we pass over $a$~characters to reach the next
+current character (which may have a ligature/kerning program of its own).
+
+If the very first instruction of the \\{lig\_kern} array has $\\{skip%
+\_byte}=255$,
+the \\{next\_char} byte is the so-called right boundary character of this font;
+the value of \\{next\_char} need not lie between \\{bc} and~\\{ec}.
+If the very last instruction of the \\{lig\_kern} array has $\\{skip%
+\_byte}=255$,
+there is a special ligature/kerning program for a left boundary character,
+beginning at location $256\ast\\{op\_byte}+\\{remainder}$.
+The interpretation is that \TeX\ puts implicit boundary characters
+before and after each consecutive string of characters from the same font.
+These implicit characters do not appear in the output, but they can affect
+ligatures and kerning.
+
+If the very first instruction of a character's \\{lig\_kern} program has
+$\\{skip\_byte}>128$, the program actually begins in location
+$256\ast\\{op\_byte}+\\{remainder}$. This feature allows access to large \\{lig%
+\_kern}
+arrays, because the first instruction must otherwise
+appear in a location $\L255$.
+
+Any instruction with $\\{skip\_byte}>128$ in the \\{lig\_kern} array must
+satisfy
+the condition
+$$\hbox{$256\ast\\{op\_byte}+\\{remainder}<\\{nl}$.}$$
+If such an instruction is encountered during
+normal program execution, it denotes an unconditional halt; no ligature
+or kerning command is performed.
+
+\Y\P\D \37$\\{stop\_flag}\S\\{qi}(128)$\C{value indicating `\.{STOP}' in a
+lig/kern program}\par
+\P\D \37$\\{kern\_flag}\S\\{qi}(128)$\C{op code for a kern step}\par
+\P\D \37$\\{skip\_byte}(\#)\S\#.\\{b0}$\par
+\P\D \37$\\{next\_char}(\#)\S\#.\\{b1}$\par
+\P\D \37$\\{op\_byte}(\#)\S\#.\\{b2}$\par
+\P\D \37$\\{rem\_byte}(\#)\S\#.\\{b3}$\par
+\fi
+
+\M557. Extensible characters are specified by an \\{extensible\_recipe}, which
+consists of four bytes called \\{top}, \\{mid}, \\{bot}, and \\{rep} (in this
+order). These bytes are the character codes of individual pieces used to
+build up a large symbol.  If \\{top}, \\{mid}, or \\{bot} are zero, they are
+not
+present in the built-up result. For example, an extensible vertical line is
+like an extensible bracket, except that the top and bottom pieces are missing.
+
+Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
+if the piece isn't present. Then the extensible characters have the form
+$TR^kMR^kB$ from top to bottom, for some $\|k\G0$, unless $M$ is absent;
+in the latter case we can have $TR^kB$ for both even and odd values of~\|k.
+The width of the extensible character is the width of $R$; and the
+height-plus-depth is the sum of the individual height-plus-depths of the
+components used, since the pieces are butted together in a vertical list.
+
+\Y\P\D \37$\\{ext\_top}(\#)\S\#.\\{b0}$\C{\\{top} piece in a recipe}\par
+\P\D \37$\\{ext\_mid}(\#)\S\#.\\{b1}$\C{\\{mid} piece in a recipe}\par
+\P\D \37$\\{ext\_bot}(\#)\S\#.\\{b2}$\C{\\{bot} piece in a recipe}\par
+\P\D \37$\\{ext\_rep}(\#)\S\#.\\{b3}$\C{\\{rep} piece in a recipe}\par
+\fi
+
+\M558. The final portion of a \.{TFM} file is the \\{param} array, which is
+another
+sequence of \\{fix\_word} values.
+
+\yskip\hang$\\{param}[1]=\\{slant}$ is the amount of italic slant, which is
+used
+to help position accents. For example, $\\{slant}=.25$ means that when you go
+up one unit, you also go .25 units to the right. The \\{slant} is a pure
+number; it's the only \\{fix\_word} other than the design size itself that is
+not scaled by the design size.
+
+\hang$\\{param}[2]=\\{space}$ is the normal spacing between words in text.
+Note that character \.{"\ "} in the font need not have anything to do with
+blank spaces.
+
+\hang$\\{param}[3]=\\{space\_stretch}$ is the amount of glue stretching between
+words.
+
+\hang$\\{param}[4]=\\{space\_shrink}$ is the amount of glue shrinking between
+words.
+
+\hang$\\{param}[5]=\\{x\_height}$ is the size of one ex in the font; it is also
+the height of letters for which accents don't have to be raised or lowered.
+
+\hang$\\{param}[6]=\\{quad}$ is the size of one em in the font.
+
+\hang$\\{param}[7]=\\{extra\_space}$ is the amount added to $\\{param}[2]$ at
+the
+ends of sentences.
+
+\yskip\noindent
+If fewer than seven parameters are present, \TeX\ sets the missing parameters
+to zero. Fonts used for math symbols are required to have
+additional parameter information, which is explained later.
+
+\Y\P\D \37$\\{slant\_code}=1$\par
+\P\D \37$\\{space\_code}=2$\par
+\P\D \37$\\{space\_stretch\_code}=3$\par
+\P\D \37$\\{space\_shrink\_code}=4$\par
+\P\D \37$\\{x\_height\_code}=5$\par
+\P\D \37$\\{quad\_code}=6$\par
+\P\D \37$\\{extra\_space\_code}=7$\par
+\fi
+
+\M559. So that is what \.{TFM} files hold. Since \TeX\ has to absorb such
+information
+about lots of fonts, it stores most of the data in a large array called
+\\{font\_info}. Each item of \\{font\_info} is a \\{memory\_word}; the \\{fix%
+\_word}
+data gets converted into \\{scaled} entries, while everything else goes into
+words of type \\{four\_quarters}.
+
+When the user defines \.{\\font\\f}, say, \TeX\ assigns an internal number
+to the user's font~\.{\\f}. Adding this number to \\{font\_id\_base} gives the
+\\{eqtb} location of a ``frozen'' control sequence that will always select
+the font.
+
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{internal\_font\_number}=\\{integer}$;\C{\\{font} in a \\{char\_node}}\6
+$\\{font\_index}=\\{integer}$;\C{index into \\{font\_info}}\6
+$\\{nine\_bits}=\\{min\_quarterword}\to\\{non\_char}$;\par
+\fi
+
+\M560. Here now is the (rather formidable) array of font arrays.
+
+\Y\P\D \37$\\{non\_char}\S\\{qi}(256)$\C{a \\{halfword} code that can't match a
+real character}\par
+\P\D \37$\\{non\_address}=0$\C{a spurious \\{bchar\_label}}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{font\_info}: \37$\^\\{memory\_word}$;\C{pTeX: use halfword for \\{char%
+\_type} table.}\6
+\4\\{font\_dir}: \37$\^\\{eight\_bits}$;\C{pTeX: direction of fonts, 0 is
+default, 1 is Yoko, 2 is Tate}\6
+\4\\{font\_num\_ext}: \37$\^\\{integer}$;\C{pTeX: number of the \\{char\_type}
+table.}\6
+\C{the big collection of font data}\6
+\4\\{fmem\_ptr}: \37\\{font\_index};\C{first unused word of \\{font\_info}}\6
+\4\\{font\_ptr}: \37\\{internal\_font\_number};\C{largest internal font number
+in use}\6
+\4\\{font\_check}: \37$\^\\{four\_quarters}$;\C{check sum}\6
+\4\\{font\_size}: \37$\^\\{scaled}$;\C{``at'' size}\6
+\4\\{font\_dsize}: \37$\^\\{scaled}$;\C{``design'' size}\6
+\4\\{font\_params}: \37$\^\\{font\_index}$;\C{how many font   parameters are
+present}\6
+\4\\{font\_name}: \37$\^\\{str\_number}$;\C{name of the font}\6
+\4\\{font\_area}: \37$\^\\{str\_number}$;\C{area of the font}\6
+\4\\{font\_bc}: \37$\^\\{eight\_bits}$;\C{beginning (smallest) character code}\6
+\4\\{font\_ec}: \37$\^\\{eight\_bits}$;\C{ending (largest) character code}\6
+\4\\{font\_glue}: \37$\^\\{pointer}$;\C{glue specification for interword space,
+\\{null} if not allocated}\6
+\4\\{font\_used}: \37$\^\\{boolean}$;\C{has a character from this font actually
+appeared in the output?}\6
+\4\\{hyphen\_char}: \37$\^\\{integer}$;\C{current \.{\\hyphenchar} values}\6
+\4\\{skew\_char}: \37$\^\\{integer}$;\C{current \.{\\skewchar} values}\6
+\4\\{bchar\_label}: \37$\^\\{font\_index}$;\C{start of \\{lig\_kern} program
+for left boundary character,   \\{non\_address} if there is none}\6
+\4\\{font\_bchar}: \37$\^\\{nine\_bits}$;\C{right boundary character, \\{non%
+\_char} if there is none}\6
+\4\\{font\_false\_bchar}: \37$\^\\{nine\_bits}$;\C{\\{font\_bchar} if it
+doesn't exist in the font, otherwise \\{non\_char}}\par
+\fi
+
+\M561. Besides the arrays just enumerated, we have directory arrays that make
+it
+easy to get at the individual entries in \\{font\_info}. For example, the
+\\{char\_info} data for character \|c in font \|f will be in
+$\\{font\_info}[\\{char\_base}[\|f]+\|c].\\{qqqq}$; and if \|w is the \\{width%
+\_index}
+part of this word (the \\{b0} field), the width of the character is
+$\\{font\_info}[\\{width\_base}[\|f]+\|w].\\{sc}$. (These formulas assume that
+\\{min\_quarterword} has already been added to \|c and to \|w, since \TeX\
+stores its quarterwords that way.)
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{char\_base}: \37$\^\\{integer}$;\C{base addresses for \\{char\_info}}\6
+\4\\{ctype\_base}: \37$\^\\{integer}$;\C{pTeX: base addresses for KANJI
+character type parameters}\6
+\4\\{width\_base}: \37$\^\\{integer}$;\C{base addresses for widths}\6
+\4\\{height\_base}: \37$\^\\{integer}$;\C{base addresses for heights}\6
+\4\\{depth\_base}: \37$\^\\{integer}$;\C{base addresses for depths}\6
+\4\\{italic\_base}: \37$\^\\{integer}$;\C{base addresses for italic
+corrections}\6
+\4\\{lig\_kern\_base}: \37$\^\\{integer}$;\C{base addresses for
+ligature/kerning programs}\6
+\4\\{kern\_base}: \37$\^\\{integer}$;\C{base addresses for kerns}\6
+\4\\{exten\_base}: \37$\^\\{integer}$;\C{base addresses for extensible recipes}%
+\6
+\4\\{param\_base}: \37$\^\\{integer}$;\C{base addresses for font parameters}\par
+\fi
+
+\M562. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\par
+\fi
+
+\M563. \TeX\ always knows at least one font, namely the null font. It has no
+characters, and its seven parameters are all equal to zero.
+
+\Y\P$\4\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}\S$%
+\par
+\fi
+
+\M564. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"nullfont"},\39\\{set\_font},\39\\{null\_font})$;\5
+$\\{text}(\\{frozen\_null\_font})\K\.{"nullfont"}$;\5
+$\\{eqtb}[\\{frozen\_null\_font}]\K\\{eqtb}[\\{cur\_val}]$;\par
+\fi
+
+\M565. Of course we want to define macros that suppress the detail of how font
+information is actually packed, so that we don't have to write things like
+$$\hbox{$\\{font\_info}[\\{width\_base}[\|f]+\\{font\_info}[\\{char\_base}[%
+\|f]+\|c].\\{qqqq}.\\{b0}].\\{sc}$}$$
+too often. The \.{WEB} definitions here make $\\{char\_info}(\|f)(\|c)$ the
+\\{four\_quarters} word of font information corresponding to character
+\|c of font \|f. If \|q is such a word, $\\{char\_width}(\|f)(\|q)$ will be
+the character's width; hence the long formula above is at least
+abbreviated to
+$$\hbox{$\\{char\_width}(\|f)(\\{char\_info}(\|f)(\|c))$.}$$
+Usually, of course, we will fetch \|q first and look at several of its
+fields at the same time.
+
+The italic correction of a character will be denoted by
+$\\{char\_italic}(\|f)(\|q)$, so it is analogous to \\{char\_width}.  But we
+will get
+at the height and depth in a slightly different way, since we usually want
+to compute both height and depth if we want either one.  The value of
+$\\{height\_depth}(\|q)$ will be the 8-bit quantity
+$$b=\\{height\_index}\times16+\\{depth\_index},$$ and if \|b is such a byte we
+will write $\\{char\_height}(\|f)(\|b)$ and $\\{char\_depth}(\|f)(\|b)$ for the
+height and
+depth of the character \|c for which $\|q=\\{char\_info}(\|f)(\|c)$. Got that?
+
+The tag field will be called $\\{char\_tag}(\|q)$; the remainder byte will be
+called $\\{rem\_byte}(\|q)$, using a macro that we have already defined above.
+
+Access to a character's \\{width}, \\{height}, \\{depth}, and \\{tag} fields is
+part of \TeX's inner loop, so we want these macros to produce code that is
+as fast as possible under the circumstances.
+
+ML\TeX{} will assume that a character \|c exists iff either exists in
+the current font or a character substitution definition for this
+character was defined using \.{\\charsubdef}.  To avoid the
+distinction between these two cases, ML\TeX{} introduces the notion
+``effective character'' of an input character \|c.  If \|c exists in
+the current font, the effective character of \|c is the character \|c
+itself.  If it doesn't exist but a character substitution is defined,
+the effective character of \|c is the base character defined in the
+character substitution.  If there is an effective character for a
+non-existing character \|c, the ``virtual character'' \|c will get
+appended to the horizontal lists.
+
+The effective character is used within \\{char\_info} to access
+appropriate character descriptions in the font.  For example, when
+calculating the width of a box, ML\TeX{} will use the metrics of the
+effective characters.  For the case of a substitution, ML\TeX{} uses
+the metrics of the base character, ignoring the metrics of the accent
+character.
+
+If character substitutions are changed, it will be possible that a
+character \|c neither exists in a font nor there is a valid character
+substitution for \|c.  To handle these cases \\{effective\_char} should
+be called with its first argument set to \\{true} to ensure that it
+will still return an existing character in the font.  If neither \|c
+nor the substituted base character in the current character
+substitution exists, \\{effective\_char} will output a warning and
+return the character $\\{font\_bc}[\|f]$ (which is incorrect, but can not be
+changed within the current framework).
+
+Sometimes character substitutions are unwanted, therefore the
+original definition of \\{char\_info} can be used using the macro
+\\{orig\_char\_info}.  Operations in which character substitutions should
+be avoided are, for example, loading a new font and checking the font
+metric information in this font, and character accesses in math mode.
+
+\Y\P\D \37$\\{char\_list\_exists}(\#)\S(\\{char\_sub\_code}(\#)>\\{hi}(0))$\par
+\P\D \37$\\{char\_list\_accent}(\#)\S(\\{ho}(\\{char\_sub\_code}(\#))\mathbin{%
+\&{div}}256)$\par
+\P\D \37$\\{char\_list\_char}(\#)\S(\\{ho}(\\{char\_sub\_code}(\#))\mathbin{%
+\&{mod}}256)$\Y\par
+\P\D \37$\\{char\_info\_end}(\#)\S\#\={)}$ ] .\\{qqqq}\par
+\P\D $\\{char\_info}(\#)\S\\{font\_info}$ [ $\\{char\_base}[\#]+\\{effective%
+\_char}\={(}\\{true},\39\#,\39\\{char\_info\_end}$\Y\par
+\P\D \37$\\{orig\_char\_info\_end}(\#)\S\#$ ] .\\{qqqq}\par
+\P\D $\\{orig\_char\_info}(\#)\S\\{font\_info}$ [ $\\{char\_base}[\#]+\\{orig%
+\_char\_info\_end}$\Y\par
+\P\D \37$\\{kchar\_code\_end}(\#)\S\#$ ] .\\{hh}.\\{rh}\par
+\P\D $\\{kchar\_code}(\#)\S\\{font\_info}$ [ $\\{ctype\_base}[\#]+\\{kchar%
+\_code\_end}$\par
+\P\D \37$\\{kchar\_type\_end}(\#)\S\#$ ] .\\{hh}.\\{lhfield}\par
+\P\D $\\{kchar\_type}(\#)\S\\{font\_info}$ [ $\\{ctype\_base}[\#]+\\{kchar%
+\_type\_end}$\Y\par
+\P\D \37$\\{char\_width\_end}(\#)\S\#.\\{b0}$ ] .\\{sc}\par
+\P\D $\\{char\_width}(\#)\S\\{font\_info}$ [ $\\{width\_base}[\#]+\\{char%
+\_width\_end}$\par
+\P\D \37$\\{char\_exists}(\#)\S(\#.\\{b0}>\\{min\_quarterword})$\par
+\P\D \37$\\{char\_italic\_end}(\#)\S(\\{qo}(\#.\\{b2}))\mathbin{\&{div}}4$ ] .%
+\\{sc}\par
+\P\D $\\{char\_italic}(\#)\S\\{font\_info}$ [ $\\{italic\_base}[\#]+\\{char%
+\_italic\_end}$\par
+\P\D \37$\\{height\_depth}(\#)\S\\{qo}(\#.\\{b1})$\par
+\P\D \37$\\{char\_height\_end}(\#)\S(\#)\mathbin{\&{div}}16$ ] .\\{sc}\par
+\P\D $\\{char\_height}(\#)\S\\{font\_info}$ [ $\\{height\_base}[\#]+\\{char%
+\_height\_end}$\par
+\P\D \37$\\{char\_depth\_end}(\#)\S(\#)\mathbin{\&{mod}}16$ ] .\\{sc}\par
+\P\D $\\{char\_depth}(\#)\S\\{font\_info}$ [ $\\{depth\_base}[\#]+\\{char%
+\_depth\_end}$\par
+\P\D \37$\\{char\_tag}(\#)\S((\\{qo}(\#.\\{b2}))\mathbin{\&{mod}}4)$\par
+\fi
+
+\M566. The global variable \\{null\_character} is set up to be a word of
+\\{char\_info} for a character that doesn't exist. Such a word provides a
+convenient way to deal with erroneous situations.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{null\_character}: \37\\{four\_quarters};\C{nonexistent character
+information}\par
+\fi
+
+\M567. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{null\_character}.\\{b0}\K\\{min\_quarterword}$;\5
+$\\{null\_character}.\\{b1}\K\\{min\_quarterword}$;\5
+$\\{null\_character}.\\{b2}\K\\{min\_quarterword}$;\5
+$\\{null\_character}.\\{b3}\K\\{min\_quarterword}$;\par
+\fi
+
+\M568. Here are some macros that help process ligatures and kerns.
+We write $\\{char\_kern}(\|f)(\|j)$ to find the amount of kerning specified by
+kerning command~\|j in font~\|f. If \|j is the \\{char\_info} for a character
+with a ligature/kern program, the first instruction of that program is either
+$\|i=\\{font\_info}[\\{lig\_kern\_start}(\|f)(\|j)]$ or $\\{font\_info}[\\{lig%
+\_kern\_restart}(\|f)(\|i)]$,
+depending on whether or not $\\{skip\_byte}(\|i)\L\\{stop\_flag}$.
+
+The constant \\{kern\_base\_offset} should be simplified, for \PASCAL\
+compilers
+that do not do local optimization.
+
+\Y\P\D \37$\\{char\_kern\_end}(\#)\S256\ast\\{op\_byte}(\#)+\\{rem\_byte}(\#)$
+] .\\{sc}\par
+\P\D $\\{char\_kern}(\#)\S\\{font\_info}$ [ $\\{kern\_base}[\#]+\\{char\_kern%
+\_end}$\par
+\P\D \37$\\{kern\_base\_offset}\S256\ast(128+\\{min\_quarterword})$\par
+\P\D \37$\\{lig\_kern\_start}(\#)\S\\{lig\_kern\_base}[\#]+\\{rem\_byte}$%
+\C{beginning of lig/kern program}\par
+\P\D \37$\\{glue\_kern\_start}(\#)\S\\{lig\_kern\_base}[\#]+\\{rem\_byte}$%
+\C{beginning of glue/kern program}\par
+\P\D \37$\\{lig\_kern\_restart\_end}(\#)\S256\ast\\{op\_byte}(\#)+\\{rem%
+\_byte}(\#)+32768-\\{kern\_base\_offset}$\par
+\P\D \37$\\{lig\_kern\_restart}(\#)\S\\{lig\_kern\_base}[\#]+\\{lig\_kern%
+\_restart\_end}$\par
+\fi
+
+\M569. Font parameters are referred to as $\\{slant}(\|f)$, $\\{space}(\|f)$,
+etc.
+
+\Y\P\D \37$\\{param\_end}(\#)\S\\{param\_base}[\#]$ ] .\\{sc}\par
+\P\D $\\{param}(\#)\S\\{font\_info}$ [ $\#+\\{param\_end}$\par
+\P\D \37$\\{slant}\S\\{param}(\\{slant\_code})$\C{slant to the right, per unit
+distance upward}\par
+\P\D \37$\\{space}\S\\{param}(\\{space\_code})$\C{normal space between words}%
+\par
+\P\D \37$\\{space\_stretch}\S\\{param}(\\{space\_stretch\_code})$\C{stretch
+between words}\par
+\P\D \37$\\{space\_shrink}\S\\{param}(\\{space\_shrink\_code})$\C{shrink
+between words}\par
+\P\D \37$\\{x\_height}\S\\{param}(\\{x\_height\_code})$\C{one ex}\par
+\P\D \37$\\{quad}\S\\{param}(\\{quad\_code})$\C{one em}\par
+\P\D \37$\\{extra\_space}\S\\{param}(\\{extra\_space\_code})$\C{additional
+space at end of sentence}\par
+\Y\P$\4\X569:The em width for \\{cur\_font}\X\S$\6
+$\\{quad}(\\{cur\_font})$\par
+\U466.\fi
+
+\M570. \P$\X570:The x-height for \\{cur\_font}\X\S$\6
+$\\{x\_height}(\\{cur\_font})$\par
+\U466.\fi
+
+\M571. \TeX\ checks the information of a \.{TFM} file for validity as the
+file is being read in, so that no further checks will be needed when
+typesetting is going on. The somewhat tedious subroutine that does this
+is called \\{read\_font\_info}. It has four parameters: the user font
+identifier~\|u, the file name and area strings \\{nom} and \\{aire}, and the
+``at'' size~\|s. If \|s~is negative, it's the negative of a scale factor
+to be applied to the design size; $\|s=-1000$ is the normal case.
+Otherwise \|s will be substituted for the design size; in this
+case, \|s must be positive and less than $2048\rm\,pt$
+(i.e., it must be less than $2^{27}$ when considered as an integer).
+
+The subroutine opens and closes a global file variable called \\{tfm\_file}.
+It returns the value of the internal font number that was just loaded.
+If an error is detected, an error message is issued and no font
+information is stored; \\{null\_font} is returned in this case.
+
+\Y\P\D \37$\\{bad\_tfm}=11$\C{label for \\{read\_font\_info}}\par
+\P\D \37$\\{abort}\S$\1\5
+\&{goto} \37\\{bad\_tfm}\C{do this when the \.{TFM} data is wrong}\2\par
+\Y\P\hbox{\4}\X1407:Declare additional functions for ML\TeX\X\6
+\4\&{function}\1\  \37$\\{read\_font\_info}(\|u:\\{pointer};\,\35\\{nom},\39%
+\\{aire}:\\{str\_number};\,\35\|s:\\{scaled})$: \37\\{internal\_font\_number};%
+\C{input a \.{TFM} file}\6
+\4\&{label} \37$\\{done},\39\\{bad\_tfm},\39\\{not\_found}$;\6
+\4\&{var} \37\|k: \37\\{font\_index};\C{index into \\{font\_info}}\6
+\\{jfm\_flag}: \37$\\{dir\_default}\to\\{dir\_tate}$;\C{direction of the %
+\.{JFM}}\6
+\\{nt}: \37\\{halfword};\C{number of the \\{char\_type} tables}\6
+\\{cx}: \37\\{KANJI\_code};\C{kanji code}\6
+\\{name\_too\_long}: \37\\{boolean};\C{\\{nom} or \\{aire} exceeds 255 bytes?}\6
+\\{file\_opened}: \37\\{boolean};\C{was \\{tfm\_file} successfully opened?}\6
+$\\{lf},\39\\{lh},\39\\{bc},\39\\{ec},\39\\{nw},\39\\{nh},\39\\{nd},\39\\{ni},%
+\39\\{nl},\39\\{nk},\39\\{ne},\39\\{np}$: \37\\{halfword};\C{sizes of subfiles}%
+\6
+\|f: \37\\{internal\_font\_number};\C{the new font's number}\6
+\|g: \37\\{internal\_font\_number};\C{the number to return}\6
+$\|a,\39\|b,\39\|c,\39\|d$: \37\\{eight\_bits};\C{byte variables}\6
+\\{qw}: \37\\{four\_quarters};\5
+\\{sw}: \37\\{scaled};\C{accumulators}\6
+\\{bch\_label}: \37\\{integer};\C{left boundary start location, or infinity}\6
+\\{bchar}: \37$0\to256$;\C{right boundary character, or 256}\6
+\|z: \37\\{scaled};\C{the design size or the ``at'' size}\6
+\\{alpha}: \37\\{integer};\5
+\\{beta}: \37$1\to16$;\C{auxiliary quantities used in fixed-point
+multiplication}\2\6
+\&{begin} \37$\|g\K\\{null\_font}$;\6
+\X573:Read and check the font data; \\{abort} if the \.{TFM} file is malformed;
+if there's no room for this font, say so and \&{goto} \\{done}; otherwise $%
+\\{incr}(\\{font\_ptr})$ and \&{goto} \\{done}\X;\6
+\4\\{bad\_tfm}: \37\X572:Report that the font won't be loaded\X;\6
+\4\\{done}: \37\&{if} $\\{file\_opened}$ \1\&{then}\5
+$\\{b\_close}(\\{tfm\_file})$;\2\6
+$\\{read\_font\_info}\K\|g$;\6
+\&{end};\par
+\fi
+
+\M572. There are programs called \.{TFtoPL} and \.{PLtoTF} that convert
+between the \.{TFM} format and a symbolic property-list format
+that can be easily edited. These programs contain extensive
+diagnostic information, so \TeX\ does not have to bother giving
+precise details about why it rejects a particular \.{TFM} file.
+
+\Y\P\D \37$\\{start\_font\_error\_message}\S\\{print\_err}(\.{"Font\ "})$;\5
+$\\{sprint\_cs}(\|u)$;\5
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_file\_name}(\\{nom},\39\\{aire},\39\.{""})$;\6
+\&{if} $\|s\G0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ at\ "})$;\5
+$\\{print\_scaled}(\|s)$;\5
+$\\{print}(\.{"pt"})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|s\I-1000$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ scaled\ "})$;\5
+$\\{print\_int}(-\|s)$;\6
+\&{end}\2\2\par
+\Y\P$\4\X572:Report that the font won't be loaded\X\S$\6
+\\{start\_font\_error\_message};\6
+\&{if} $\\{file\_opened}$ \1\&{then}\5
+$\\{print}(\.{"\ not\ loadable:\ Bad\ metric\ (TFM)\ file"})$\6
+\4\&{else} \&{if} $\\{name\_too\_long}$ \1\&{then}\5
+$\\{print}(\.{"\ not\ loadable:\ Metric\ (TFM)\ file\ name\ too\ long"})$\6
+\4\&{else} $\\{print}(\.{"\ not\ loadable:\ Metric\ (TFM)\ file\ not\
+found"})$;\2\2\6
+$\\{help5}(\.{"I\ wasn\'t\ able\ to\ read\ the\ size\ data\ for\ this\
+font,"})$\6
+$(\.{"so\ I\ will\ ignore\ the\ font\ specification."})$\6
+$(\.{"[Wizards\ can\ fix\ TFM\ files\ using\ TFtoPL/PLtoTF.]"})$\6
+$(\.{"You\ might\ try\ inserting\ a\ different\ font\ spec;"})$\6
+$(\.{"e.g.,\ type\ \`I\\font<same\ font\ id>=<substitute\ font\ name>\'."})$;\5
+\\{error}\par
+\U571.\fi
+
+\M573. \P$\X573:Read and check the font data; \\{abort} if the \.{TFM} file is
+malformed; if there's no room for this font, say so and \&{goto} \\{done};
+otherwise $\\{incr}(\\{font\_ptr})$ and \&{goto} \\{done}\X\S$\6
+\X574:Open \\{tfm\_file} for input\X;\6
+\X576:Read the {\.{TFM}} size fields\X;\6
+\X577:Use size fields to allocate font information\X;\6
+\X579:Read the {\.{TFM}} header\X;\6
+\X580:Read character data\X;\6
+\X582:Read box dimensions\X;\6
+\X584:Read ligature/kern program\X;\6
+\X585:Read extensible character recipes\X;\6
+\X586:Read font parameters\X;\6
+\X587:Make final adjustments and \&{goto} \\{done}\X\par
+\U571.\fi
+
+\M574. \P$\X574:Open \\{tfm\_file} for input\X\S$\6
+$\\{file\_opened}\K\\{false}$;\5
+$\\{name\_too\_long}\K(\\{length}(\\{nom})>255)\V(\\{length}(\\{aire})>255)$;\6
+\&{if} $\\{name\_too\_long}$ \1\&{then}\5
+\\{abort};\C{\\{kpse\_find\_file} will append the \.{".tfm"}, and avoid
+searching the disk  before the font alias files as well.}\2\6
+$\\{pack\_file\_name}(\\{nom},\39\\{aire},\39\.{""})$;\6
+\&{if} $\R\\{b\_open\_in}(\\{tfm\_file})$ \1\&{then}\5
+\\{abort};\2\6
+$\\{file\_opened}\K\\{true}$\par
+\U573.\fi
+
+\M575. Note: A malformed \.{TFM} file might be shorter than it claims to be;
+thus $\\{eof}(\\{tfm\_file})$ might be true when \\{read\_font\_info} refers to
+$\\{tfm\_file}\^$ or when it says $\\{get}(\\{tfm\_file})$. If such
+circumstances
+cause system error messages, you will have to defeat them somehow,
+for example by defining \\{fget} to be `\ignorespaces \&{begin} $\\{get}(\\{tfm%
+\_file})$;
+ \&{if} $\\{eof}(\\{tfm\_file})$ \&{then} \\{abort}; \&{end} \unskip'.
+
+\Y\P\D \37$\\{fget}\S\\{tfm\_temp}\K\\{getc}(\\{tfm\_file})$\par
+\P\D \37$\\{fbyte}\S\\{tfm\_temp}$\par
+\P\D \37$\\{read\_sixteen}(\#)\S$\1\6
+\&{begin} \37$\#\K\\{fbyte}$;\6
+\&{if} $\#>127$ \1\&{then}\5
+\\{abort};\2\6
+\\{fget};\5
+$\#\K\#\ast\O{400}+\\{fbyte}$;\6
+\&{end}\2\par
+\P\D \37$\\{store\_four\_quarters}(\#)\S$\1\6
+\&{begin} \37\\{fget};\5
+$\|a\K\\{fbyte}$;\5
+$\\{qw}.\\{b0}\K\\{qi}(\|a)$;\5
+\\{fget};\5
+$\|b\K\\{fbyte}$;\5
+$\\{qw}.\\{b1}\K\\{qi}(\|b)$;\5
+\\{fget};\5
+$\|c\K\\{fbyte}$;\5
+$\\{qw}.\\{b2}\K\\{qi}(\|c)$;\5
+\\{fget};\5
+$\|d\K\\{fbyte}$;\5
+$\\{qw}.\\{b3}\K\\{qi}(\|d)$;\5
+$\#\K\\{qw}$;\6
+\&{end}\2\par
+\fi
+
+\M576. \P$\X576:Read the {\.{TFM}} size fields\X\S$\6
+\&{begin} \37$\\{read\_sixteen}(\\{lf})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{lh})$;\6
+\&{if} $\\{lf}=\\{yoko\_jfm\_id}$ \1\&{then}\6
+\&{begin} \37$\\{jfm\_flag}\K\\{dir\_yoko}$;\5
+$\\{nt}\K\\{lh}$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{lf})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{lh})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{lf}=\\{tate\_jfm\_id}$ \1\&{then}\6
+\&{begin} \37$\\{jfm\_flag}\K\\{dir\_tate}$;\5
+$\\{nt}\K\\{lh}$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{lf})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{lh})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{jfm\_flag}\K\\{dir\_default}$;\5
+$\\{nt}\K0$;\6
+\&{end};\2\2\6
+\\{fget};\5
+$\\{read\_sixteen}(\\{bc})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{ec})$;\6
+\&{if} $(\\{bc}>\\{ec}+1)\V(\\{ec}>255)$ \1\&{then}\5
+\\{abort};\2\6
+\&{if} $\\{bc}>255$ \1\&{then}\C{$\\{bc}=256$ and $\\{ec}=255$}\6
+\&{begin} \37$\\{bc}\K1$;\5
+$\\{ec}\K0$;\6
+\&{end};\2\6
+\\{fget};\5
+$\\{read\_sixteen}(\\{nw})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{nh})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{nd})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{ni})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{nl})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{nk})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{ne})$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\\{np})$;\6
+\&{if} $\\{jfm\_flag}\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{lf}\I7+\\{lh}+\\{nt}+(\\{ec}-\\{bc}+1)+\\{nw}+\\{nh}+%
+\\{nd}+\\{ni}+\\{nl}+\\{nk}+\\{ne}+\\{np}$ \1\&{then}\5
+\\{abort};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{lf}\I6+\\{lh}+(\\{ec}-\\{bc}+1)+\\{nw}+%
+\\{nh}+\\{nd}+\\{ni}+\\{nl}+\\{nk}+\\{ne}+\\{np}$ \1\&{then}\5
+\\{abort};\2\6
+\&{end};\2\6
+\&{if} $(\\{nw}=0)\V(\\{nh}=0)\V(\\{nd}=0)\V(\\{ni}=0)$ \1\&{then}\5
+\\{abort};\2\6
+\&{end}\par
+\U573.\fi
+
+\M577. The preliminary settings of the index-offset variables \\{char\_base},
+\\{width\_base}, \\{lig\_kern\_base}, \\{kern\_base}, and \\{exten\_base} will
+be
+corrected later by subtracting \\{min\_quarterword} from them; and we will
+subtract 1 from \\{param\_base} too. It's best to forget about such anomalies
+until later.
+
+\Y\P$\4\X577:Use size fields to allocate font information\X\S$\6
+\&{if} $\\{jfm\_flag}\I\\{dir\_default}$ \1\&{then}\5
+$\\{lf}\K\\{lf}-7-\\{lh}$\C{If \.{JFM}, \\{lf} holds more two-16bit records
+than \.{TFM}}\6
+\4\&{else} $\\{lf}\K\\{lf}-6-\\{lh}$;\C{\\{lf} words should be loaded into %
+\\{font\_info}}\2\6
+\&{if} $\\{np}<7$ \1\&{then}\5
+$\\{lf}\K\\{lf}+7-\\{np}$;\C{at least seven parameters will appear}\2\6
+\&{if} $(\\{font\_ptr}=\\{font\_max})\V(\\{fmem\_ptr}+\\{lf}>\\{font\_mem%
+\_size})$ \1\&{then}\5
+\X578:Apologize for not loading the font, \&{goto} \\{done}\X;\2\6
+$\|f\K\\{font\_ptr}+1$;\5
+$\\{font\_dir}[\|f]\K\\{jfm\_flag}$;\5
+$\\{font\_num\_ext}[\|f]\K\\{nt}$;\5
+$\\{ctype\_base}[\|f]\K\\{fmem\_ptr}$;\5
+$\\{char\_base}[\|f]\K\\{ctype\_base}[\|f]+\\{nt}-\\{bc}$;\5
+$\\{width\_base}[\|f]\K\\{char\_base}[\|f]+\\{ec}+1$;\5
+$\\{height\_base}[\|f]\K\\{width\_base}[\|f]+\\{nw}$;\5
+$\\{depth\_base}[\|f]\K\\{height\_base}[\|f]+\\{nh}$;\5
+$\\{italic\_base}[\|f]\K\\{depth\_base}[\|f]+\\{nd}$;\5
+$\\{lig\_kern\_base}[\|f]\K\\{italic\_base}[\|f]+\\{ni}$;\5
+$\\{kern\_base}[\|f]\K\\{lig\_kern\_base}[\|f]+\\{nl}-\\{kern\_base\_offset}$;\5
+$\\{exten\_base}[\|f]\K\\{kern\_base}[\|f]+\\{kern\_base\_offset}+\\{nk}$;\5
+$\\{param\_base}[\|f]\K\\{exten\_base}[\|f]+\\{ne}$;\par
+\U573.\fi
+
+\M578. \P$\X578:Apologize for not loading the font, \&{goto} \\{done}\X\S$\6
+\&{begin} \37\\{start\_font\_error\_message};\5
+$\\{print}(\.{"\ not\ loaded:\ Not\ enough\ room\ left"})$;\5
+$\\{help4}(\.{"I\'m\ afraid\ I\ won\'t\ be\ able\ to\ make\ use\ of\ this\
+font,"})$\6
+$(\.{"because\ my\ memory\ for\ character-size\ data\ is\ too\ small."})$\6
+$(\.{"If\ you\'re\ really\ stuck,\ ask\ a\ wizard\ to\ enlarge\ me."})$\6
+$(\.{"Or\ maybe\ try\ \`I\\font<same\ font\ id>=<name\ of\ loaded\ font>%
+\'."})$;\5
+\\{error};\5
+\&{goto} \37\\{done};\6
+\&{end}\par
+\U577.\fi
+
+\M579. Only the first two words of the header are needed by \TeX82.
+
+\Y\P$\4\X579:Read the {\.{TFM}} header\X\S$\6
+\&{begin} \37\&{if} $\\{lh}<2$ \1\&{then}\5
+\\{abort};\2\6
+$\\{store\_four\_quarters}(\\{font\_check}[\|f])$;\5
+\\{fget};\5
+$\\{read\_sixteen}(\|z)$;\C{this rejects a negative design size}\6
+\\{fget};\5
+$\|z\K\|z\ast\O{400}+\\{fbyte}$;\5
+\\{fget};\5
+$\|z\K(\|z\ast\O{20})+(\\{fbyte}\mathbin{\&{div}}\O{20})$;\6
+\&{if} $\|z<\\{unity}$ \1\&{then}\5
+\\{abort};\2\6
+\&{while} $\\{lh}>2$ \1\&{do}\6
+\&{begin} \37\\{fget};\5
+\\{fget};\5
+\\{fget};\5
+\\{fget};\5
+$\\{decr}(\\{lh})$;\C{ignore the rest of the header}\6
+\&{end};\2\6
+$\\{font\_dsize}[\|f]\K\|z$;\6
+\&{if} $\|s\I-1000$ \1\&{then}\6
+\&{if} $\|s\G0$ \1\&{then}\5
+$\|z\K\|s$\6
+\4\&{else} $\|z\K\\{xn\_over\_d}(\|z,\39-\|s,\391000)$;\2\2\6
+$\\{font\_size}[\|f]\K\|z$;\6
+\&{end}\par
+\U573.\fi
+
+\M580. \P$\X580:Read character data\X\S$\6
+\&{if} $\\{jfm\_flag}\I\\{dir\_default}$ \1\&{then}\6
+\&{for} $\|k\K\\{ctype\_base}[\|f]\mathrel{\&{to}}\\{ctype\_base}[\|f]+%
+\\{nt}-1$ \1\&{do}\6
+\&{begin} \37\\{fget};\5
+$\\{read\_sixteen}(\\{cx})$;\5
+$\\{font\_info}[\|k].\\{hh}.\\{rh}\K\\{tokanji}(\\{cx})$;\C{\\{kchar\_code}}\6
+\\{fget};\5
+$\\{read\_sixteen}(\\{cx})$;\5
+$\\{font\_info}[\|k].\\{hh}.\\{lhfield}\K\\{tonum}(\\{cx})$;\C{\\{kchar\_type}}%
+\6
+\&{end};\2\2\6
+\&{for} $\|k\K\\{char\_base}[\|f]+\\{bc}\mathrel{\&{to}}\\{width\_base}[\|f]-1$
+\1\&{do}\6
+\&{begin} \37$\\{store\_four\_quarters}(\\{font\_info}[\|k].\\{qqqq})$;\6
+\&{if} $(\|a\G\\{nw})\V(\|b\mathbin{\&{div}}\O{20}\G\\{nh})\V(\|b\mathbin{%
+\&{mod}}\O{20}\G\\{nd})\V(\|c\mathbin{\&{div}}4\G\\{ni})$ \1\&{then}\5
+\\{abort};\2\6
+\&{case} $\|c\mathbin{\&{mod}}4$ \1\&{of}\6
+\4\\{lig\_tag}: \37\&{if} $\|d\G\\{nl}$ \1\&{then}\5
+\\{abort};\2\6
+\4\\{ext\_tag}: \37\&{if} $\|d\G\\{ne}$ \1\&{then}\5
+\\{abort};\2\6
+\4\\{list\_tag}: \37\X581:Check for charlist cycle\X;\6
+\4\&{othercases} \37\\{do\_nothing}\C{\\{no\_tag}}\2\6
+\&{endcases};\6
+\&{end}\2\par
+\U573.\fi
+
+\M581. We want to make sure that there is no cycle of characters linked
+together
+by \\{list\_tag} entries, since such a cycle would get \TeX\ into an endless
+loop. If such a cycle exists, the routine here detects it when processing
+the largest character code in the cycle.
+
+\Y\P\D \37$\\{check\_byte\_range}(\#)\S$\1\6
+\&{begin} \37\&{if} $(\#<\\{bc})\V(\#>\\{ec})$ \1\&{then}\5
+\\{abort}\ \2\6
+\&{end}\2\par
+\P\D \37$\\{current\_character\_being\_worked\_on}\S\|k-\\{char\_base}[\|f]$\par
+\Y\P$\4\X581:Check for charlist cycle\X\S$\6
+\&{begin} \37$\\{check\_byte\_range}(\|d)$;\6
+\&{while} $\|d<\\{current\_character\_being\_worked\_on}$ \1\&{do}\6
+\&{begin} \37$\\{qw}\K\\{orig\_char\_info}(\|f)(\|d)$;\C{N.B.: not $\\{qi}(%
+\|d)$, since $\\{char\_base}[\|f]$ hasn't been adjusted yet}\6
+\&{if} $\\{char\_tag}(\\{qw})\I\\{list\_tag}$ \1\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+$\|d\K\\{qo}(\\{rem\_byte}(\\{qw}))$;\C{next character on the list}\6
+\&{end};\2\6
+\&{if} $\|d=\\{current\_character\_being\_worked\_on}$ \1\&{then}\5
+\\{abort};\C{yes, there's a cycle}\2\6
+\4\\{not\_found}: \37\&{end}\par
+\U580.\fi
+
+\M582. A \\{fix\_word} whose four bytes are $(a,b,c,d)$ from left to right
+represents
+the number
+$$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
+-16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$
+(No other choices of \|a are allowed, since the magnitude of a number in
+design-size units must be less than 16.)  We want to multiply this
+quantity by the integer~\|z, which is known to be less than $2^{27}$.
+If $\|z<2^{23}$, the individual multiplications $b\cdot z$,
+$c\cdot z$, $d\cdot z$ cannot overflow; otherwise we will divide \|z by 2,
+4, 8, or 16, to obtain a multiplier less than $2^{23}$, and we can
+compensate for this later. If \|z has thereby been replaced by
+$\|z^\prime=\|z/2^e$, let $\beta=2^{4-e}$; we shall compute
+$$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$
+if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$.
+This calculation must be done exactly, in order to guarantee portability
+of \TeX\ between computers.
+
+\Y\P\D \37$\\{store\_scaled}(\#)\S$\1\6
+\&{begin} \37\\{fget};\5
+$\|a\K\\{fbyte}$;\5
+\\{fget};\5
+$\|b\K\\{fbyte}$;\5
+\\{fget};\5
+$\|c\K\\{fbyte}$;\5
+\\{fget};\5
+$\|d\K\\{fbyte}$;\6
+$\\{sw}\K(((((\|d\ast\|z)\mathbin{\&{div}}\O{400})+(\|c\ast\|z))\mathbin{%
+\&{div}}\O{400})+(\|b\ast\|z))\mathbin{\&{div}}\\{beta}$;\6
+\&{if} $\|a=0$ \1\&{then}\5
+$\#\K\\{sw}$\ \&{else} \&{if} $\|a=255$ \1\&{then}\5
+$\#\K\\{sw}-\\{alpha}$\ \&{else} \\{abort};\2\2\6
+\&{end}\2\par
+\Y\P$\4\X582:Read box dimensions\X\S$\6
+\&{begin} \37\X583:Replace \|z by $\|z^\prime$ and compute $\alpha,\beta$\X;\6
+\&{for} $\|k\K\\{width\_base}[\|f]\mathrel{\&{to}}\\{lig\_kern\_base}[\|f]-1$ %
+\1\&{do}\5
+$\\{store\_scaled}(\\{font\_info}[\|k].\\{sc})$;\2\6
+\&{if} $\\{font\_info}[\\{width\_base}[\|f]].\\{sc}\I0$ \1\&{then}\5
+\\{abort};\C{\\{width}[0] must be zero}\2\6
+\&{if} $\\{font\_info}[\\{height\_base}[\|f]].\\{sc}\I0$ \1\&{then}\5
+\\{abort};\C{\\{height}[0] must be zero}\2\6
+\&{if} $\\{font\_info}[\\{depth\_base}[\|f]].\\{sc}\I0$ \1\&{then}\5
+\\{abort};\C{\\{depth}[0] must be zero}\2\6
+\&{if} $\\{font\_info}[\\{italic\_base}[\|f]].\\{sc}\I0$ \1\&{then}\5
+\\{abort};\C{\\{italic}[0] must be zero}\2\6
+\&{end}\par
+\U573.\fi
+
+\M583. \P$\X583:Replace \|z by $\|z^\prime$ and compute $\alpha,\beta$\X\S$\6
+\&{begin} \37$\\{alpha}\K16$;\6
+\&{while} $\|z\G\O{40000000}$ \1\&{do}\6
+\&{begin} \37$\|z\K\|z\mathbin{\&{div}}2$;\5
+$\\{alpha}\K\\{alpha}+\\{alpha}$;\6
+\&{end};\2\6
+$\\{beta}\K256\mathbin{\&{div}}\\{alpha}$;\5
+$\\{alpha}\K\\{alpha}\ast\|z$;\6
+\&{end}\par
+\U582.\fi
+
+\M584. \P\D \37$\\{check\_existence}(\#)\S\hbox{}$\6
+\&{begin} \37$\\{check\_byte\_range}(\#)$;\5
+$\\{qw}\K\\{orig\_char\_info}(\|f)(\#)$;\C{N.B.: not $\\{qi}(\#)$}\6
+\&{if} $\R\\{char\_exists}(\\{qw})$ \1\&{then}\5
+\\{abort};\2\6
+\&{end}\par
+\Y\P$\4\X584:Read ligature/kern program\X\S$\6
+$\\{bch\_label}\K\O{77777}$;\5
+$\\{bchar}\K256$;\6
+\&{if} $\\{nl}>0$ \1\&{then}\6
+\&{begin} \37\&{for} $\|k\K\\{lig\_kern\_base}[\|f]\mathrel{\&{to}}\\{kern%
+\_base}[\|f]+\\{kern\_base\_offset}-1$ \1\&{do}\6
+\&{begin} \37$\\{store\_four\_quarters}(\\{font\_info}[\|k].\\{qqqq})$;\6
+\&{if} $\|a>128$ \1\&{then}\6
+\&{begin} \37\&{if} $256\ast\|c+\|d\G\\{nl}$ \1\&{then}\5
+\\{abort};\2\6
+\&{if} $\|a=255$ \1\&{then}\6
+\&{if} $\|k=\\{lig\_kern\_base}[\|f]$ \1\&{then}\5
+$\\{bchar}\K\|b$;\2\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\|b\I\\{bchar}$ \1\&{then}\5
+$\\{check\_existence}(\|b)$;\2\6
+\&{if} $\|c<128$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{jfm\_flag}\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37\&{if} $\|d\G\\{ne}$ \1\&{then}\5
+\\{abort};\2\6
+\&{end}\6
+\4\&{else} $\\{check\_existence}(\|d)$;\C{check ligature}\2\6
+\&{end}\6
+\4\&{else} \&{if} $256\ast(\|c-128)+\|d\G\\{nk}$ \1\&{then}\5
+\\{abort};\C{check kern}\2\2\6
+\&{if} $\|a<128$ \1\&{then}\6
+\&{if} $\|k-\\{lig\_kern\_base}[\|f]+\|a+1\G\\{nl}$ \1\&{then}\5
+\\{abort};\2\2\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\|a=255$ \1\&{then}\5
+$\\{bch\_label}\K256\ast\|c+\|d$;\2\6
+\&{end};\2\6
+\&{for} $\|k\K\\{kern\_base}[\|f]+\\{kern\_base\_offset}\mathrel{\&{to}}%
+\\{exten\_base}[\|f]-1$ \1\&{do}\5
+$\\{store\_scaled}(\\{font\_info}[\|k].\\{sc})$;\2\par
+\U573.\fi
+
+\M585. \P$\X585:Read extensible character recipes\X\S$\6
+\&{if} $\\{jfm\_flag}\I\\{dir\_default}$ \1\&{then}\6
+\&{for} $\|k\K\\{exten\_base}[\|f]\mathrel{\&{to}}\\{param\_base}[\|f]-1$ \1%
+\&{do}\5
+$\\{store\_scaled}(\\{font\_info}[\|k].\\{sc})$\C{NOTE: this area subst for
+glue program}\2\6
+\4\&{else} \&{for} $\|k\K\\{exten\_base}[\|f]\mathrel{\&{to}}\\{param\_base}[%
+\|f]-1$ \1\&{do}\6
+\&{begin} \37$\\{store\_four\_quarters}(\\{font\_info}[\|k].\\{qqqq})$;\6
+\&{if} $\|a\I0$ \1\&{then}\5
+$\\{check\_existence}(\|a)$;\2\6
+\&{if} $\|b\I0$ \1\&{then}\5
+$\\{check\_existence}(\|b)$;\2\6
+\&{if} $\|c\I0$ \1\&{then}\5
+$\\{check\_existence}(\|c)$;\2\6
+$\\{check\_existence}(\|d)$;\6
+\&{end}\2\2\par
+\U573.\fi
+
+\M586. We check to see that the \.{TFM} file doesn't end prematurely; but
+no error message is given for files having more than \\{lf} words.
+
+\Y\P$\4\X586:Read font parameters\X\S$\6
+\&{begin} \37\&{for} $\|k\K1\mathrel{\&{to}}\\{np}$ \1\&{do}\6
+\&{if} $\|k=1$ \1\&{then}\C{the \\{slant} parameter is a pure number}\6
+\&{begin} \37\\{fget};\5
+$\\{sw}\K\\{fbyte}$;\6
+\&{if} $\\{sw}>127$ \1\&{then}\5
+$\\{sw}\K\\{sw}-256$;\2\6
+\\{fget};\5
+$\\{sw}\K\\{sw}\ast\O{400}+\\{fbyte}$;\5
+\\{fget};\5
+$\\{sw}\K\\{sw}\ast\O{400}+\\{fbyte}$;\5
+\\{fget};\5
+$\\{font\_info}[\\{param\_base}[\|f]].\\{sc}\K(\\{sw}\ast\O{20})+(\\{fbyte}%
+\mathbin{\&{div}}\O{20})$;\6
+\&{end}\6
+\4\&{else} $\\{store\_scaled}(\\{font\_info}[\\{param\_base}[\|f]+\|k-1].%
+\\{sc})$;\2\2\6
+\&{if} $\\{feof}(\\{tfm\_file})$ \1\&{then}\5
+\\{abort};\2\6
+\&{for} $\|k\K\\{np}+1\mathrel{\&{to}}7$ \1\&{do}\5
+$\\{font\_info}[\\{param\_base}[\|f]+\|k-1].\\{sc}\K0$;\2\6
+\&{end}\par
+\U573.\fi
+
+\M587. Now to wrap it up, we have checked all the necessary things about the %
+\.{TFM}
+file, and all we need to do is put the finishing touches on the data for
+the new font.
+
+\Y\P\D \37$\\{adjust}(\#)\S\#[\|f]\K\\{qo}(\#[\|f])$\C{correct for the excess %
+\\{min\_quarterword} that was added}\par
+\Y\P$\4\X587:Make final adjustments and \&{goto} \\{done}\X\S$\6
+\&{if} $\\{np}\G7$ \1\&{then}\5
+$\\{font\_params}[\|f]\K\\{np}$\ \&{else} $\\{font\_params}[\|f]\K7$;\2\6
+$\\{hyphen\_char}[\|f]\K\\{default\_hyphen\_char}$;\5
+$\\{skew\_char}[\|f]\K\\{default\_skew\_char}$;\6
+\&{if} $\\{bch\_label}<\\{nl}$ \1\&{then}\5
+$\\{bchar\_label}[\|f]\K\\{bch\_label}+\\{lig\_kern\_base}[\|f]$\6
+\4\&{else} $\\{bchar\_label}[\|f]\K\\{non\_address}$;\2\6
+$\\{font\_bchar}[\|f]\K\\{qi}(\\{bchar})$;\5
+$\\{font\_false\_bchar}[\|f]\K\\{qi}(\\{bchar})$;\6
+\&{if} $\\{bchar}\L\\{ec}$ \1\&{then}\6
+\&{if} $\\{bchar}\G\\{bc}$ \1\&{then}\6
+\&{begin} \37$\\{qw}\K\\{orig\_char\_info}(\|f)(\\{bchar})$;\C{N.B.: not $%
+\\{qi}(\\{bchar})$}\6
+\&{if} $\\{char\_exists}(\\{qw})$ \1\&{then}\5
+$\\{font\_false\_bchar}[\|f]\K\\{non\_char}$;\2\6
+\&{end};\2\2\6
+$\\{font\_name}[\|f]\K\\{nom}$;\5
+$\\{font\_area}[\|f]\K\\{aire}$;\5
+$\\{font\_bc}[\|f]\K\\{bc}$;\5
+$\\{font\_ec}[\|f]\K\\{ec}$;\5
+$\\{font\_glue}[\|f]\K\\{null}$;\5
+$\\{adjust}(\\{ctype\_base})$;\5
+$\\{adjust}(\\{char\_base})$;\5
+$\\{adjust}(\\{width\_base})$;\5
+$\\{adjust}(\\{lig\_kern\_base})$;\5
+$\\{adjust}(\\{kern\_base})$;\5
+$\\{adjust}(\\{exten\_base})$;\5
+$\\{decr}(\\{param\_base}[\|f])$;\5
+$\\{fmem\_ptr}\K\\{fmem\_ptr}+\\{lf}$;\5
+$\\{font\_ptr}\K\|f$;\5
+$\|g\K\|f$;\5
+\&{goto} \37\\{done}\par
+\U573.\fi
+
+\M588. Before we forget about the format of these tables, let's deal with two
+of \TeX's basic scanning routines related to font information.
+
+\Y\P$\4\X588:Declare procedures that scan font-related stuff\X\S$\6
+\4\&{procedure}\1\  \37\\{scan\_font\_ident};\6
+\4\&{var} \37\|f: \37\\{internal\_font\_number};\5
+\|m: \37\\{halfword};\2\6
+\&{begin} \37\X417:Get the next non-blank non-call token\X;\6
+\&{if} $\\{cur\_cmd}=\\{def\_jfont}$ \1\&{then}\5
+$\|f\K\\{cur\_jfont}$\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{def\_tfont}$ \1\&{then}\5
+$\|f\K\\{cur\_tfont}$\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{def\_font}$ \1\&{then}\5
+$\|f\K\\{cur\_font}$\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{set\_font}$ \1\&{then}\5
+$\|f\K\\{cur\_chr}$\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{def\_family}$ \1\&{then}\6
+\&{begin} \37$\|m\K\\{cur\_chr}$;\5
+\\{scan\_four\_bit\_int};\5
+$\|f\K\\{equiv}(\|m+\\{cur\_val})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Missing\ font\ identifier"})$;\5
+$\\{help2}(\.{"I\ was\ looking\ for\ a\ control\ sequence\ whose"})$\6
+$(\.{"current\ meaning\ has\ been\ defined\ by\ \\font."})$;\5
+\\{back\_error};\5
+$\|f\K\\{null\_font}$;\6
+\&{end};\2\2\2\2\2\6
+$\\{cur\_val}\K\|f$;\6
+\&{end};\par
+\As589\ET1416.
+\U420.\fi
+
+\M589. The following routine is used to implement `\.{\\fontdimen} \|n \|f'.
+The boolean parameter \\{writing} is set \\{true} if the calling program
+intends to change the parameter value.
+
+\Y\P$\4\X588:Declare procedures that scan font-related stuff\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{find\_font\_dimen}(\\{writing}:\\{boolean})$;\C{sets
+\\{cur\_val} to \\{font\_info} location}\6
+\4\&{var} \37\|f: \37\\{internal\_font\_number};\5
+\|n: \37\\{integer};\C{the parameter number}\2\6
+\&{begin} \37\\{scan\_int};\5
+$\|n\K\\{cur\_val}$;\5
+\\{scan\_font\_ident};\5
+$\|f\K\\{cur\_val}$;\6
+\&{if} $\|n\L0$ \1\&{then}\5
+$\\{cur\_val}\K\\{fmem\_ptr}$\6
+\4\&{else} \&{begin} \37\&{if} $\\{writing}\W(\|n\L\\{space\_shrink\_code})\W%
+\30(\|n\G\\{space\_code})\W(\\{font\_glue}[\|f]\I\\{null})$ \1\&{then}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{font\_glue}[\|f])$;\5
+$\\{font\_glue}[\|f]\K\\{null}$;\6
+\&{end};\2\6
+\&{if} $\|n>\\{font\_params}[\|f]$ \1\&{then}\6
+\&{if} $\|f<\\{font\_ptr}$ \1\&{then}\5
+$\\{cur\_val}\K\\{fmem\_ptr}$\6
+\4\&{else} \X591:Increase the number of parameters in the last font\X\2\6
+\4\&{else} $\\{cur\_val}\K\|n+\\{param\_base}[\|f]$;\2\6
+\&{end};\2\6
+\X590:Issue an error message if $\\{cur\_val}=\\{fmem\_ptr}$\X;\6
+\&{end};\par
+\fi
+
+\M590. \P$\X590:Issue an error message if $\\{cur\_val}=\\{fmem\_ptr}$\X\S$\6
+\&{if} $\\{cur\_val}=\\{fmem\_ptr}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Font\ "})$;\5
+$\\{print\_esc}(\\{font\_id\_text}(\|f))$;\5
+$\\{print}(\.{"\ has\ only\ "})$;\5
+$\\{print\_int}(\\{font\_params}[\|f])$;\5
+$\\{print}(\.{"\ fontdimen\ parameters"})$;\5
+$\\{help2}(\.{"To\ increase\ the\ number\ of\ font\ parameters,\ you\ must"})$\6
+$(\.{"use\ \\fontdimen\ immediately\ after\ the\ \\font\ is\ loaded."})$;\5
+\\{error};\6
+\&{end}\2\par
+\U589.\fi
+
+\M591. \P$\X591:Increase the number of parameters in the last font\X\S$\6
+\&{begin} \37\1\&{repeat} \37\&{if} $\\{fmem\_ptr}=\\{font\_mem\_size}$ \1%
+\&{then}\5
+$\\{overflow}(\.{"font\ memory"},\39\\{font\_mem\_size})$;\2\6
+$\\{font\_info}[\\{fmem\_ptr}].\\{sc}\K0$;\5
+$\\{incr}(\\{fmem\_ptr})$;\5
+$\\{incr}(\\{font\_params}[\|f])$;\6
+\4\&{until}\5
+$\|n=\\{font\_params}[\|f]$;\2\6
+$\\{cur\_val}\K\\{fmem\_ptr}-1$;\C{this equals $\\{param\_base}[\|f]+\\{font%
+\_params}[\|f]$}\6
+\&{end}\par
+\U589.\fi
+
+\M592. When \TeX\ wants to typeset a character that doesn't exist, the
+character node is not created; thus the output routine can assume
+that characters exist when it sees them. The following procedure
+prints a warning message unless the user has suppressed it.
+
+\Y\P\D \37$\\{print\_lc\_hex}(\#)\S\|l\K\#$;\6
+\&{if} $\|l<10$ \1\&{then}\5
+$\\{print\_char}(\|l+\.{"0"})$\ \&{else} $\\{print\_char}(\|l-10+\.{"a"})$\2\par
+\Y\P\4\&{procedure}\1\  \37$\\{char\_warning}(\|f:\\{internal\_font\_number};\,%
+\35\|c:\\{eight\_bits})$;\6
+\4\&{var} \37\|l: \37$0\to255$;\C{small indices or counters}\2\6
+\&{begin} \37\&{if} $\\{tracing\_lost\_chars}>0$ \1\&{then}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"Missing\ character:\ There\ is\ no\ "})$;\6
+\&{if} $(\|c<\.{"\ "})\V(\|c>\.{"\~"})$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{"\^"})$;\5
+$\\{print\_char}(\.{"\^"})$;\6
+\&{if} $\|c<64$ \1\&{then}\5
+$\\{print\_char}(\|c+64)$\6
+\4\&{else} \&{if} $\|c<128$ \1\&{then}\5
+$\\{print\_char}(\|c-64)$\6
+\4\&{else} \&{begin} \37$\\{print\_lc\_hex}(\|c\mathbin{\&{div}}16)$;\5
+$\\{print\_lc\_hex}(\|c\mathbin{\&{mod}}16)$;\6
+\&{end}\2\2\6
+\&{end}\6
+\4\&{else} $\\{print\_ASCII}(\|c)$;\2\6
+$\\{print}(\.{"\ in\ font\ "})$;\5
+$\\{slow\_print}(\\{font\_name}[\|f])$;\5
+$\\{print\_char}(\.{"!"})$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M593. Here is a function that returns a pointer to a character node for a
+given character in a given font. If that character doesn't exist,
+\\{null} is returned instead.
+
+
+This allows a character node to be used if there is an equivalent
+in the \\{char\_sub\_code} list.
+
+\Y\P\4\&{function}\1\  \37$\\{new\_character}(\|f:\\{internal\_font\_number};\,%
+\35\|c:\\{eight\_bits})$: \37\\{pointer};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{newly allocated node}\6
+\\{ec}: \37\\{quarterword};\C{effective character of \|c}\2\6
+\&{begin} \37$\\{ec}\K\\{effective\_char}(\\{false},\39\|f,\39\\{qi}(\|c))$;\6
+\&{if} $\\{font\_bc}[\|f]\L\\{qo}(\\{ec})$ \1\&{then}\6
+\&{if} $\\{font\_ec}[\|f]\G\\{qo}(\\{ec})$ \1\&{then}\6
+\&{if} $\\{char\_exists}(\\{orig\_char\_info}(\|f)(\\{ec}))$ \1\&{then}\C{N.B.:
+not \\{char\_info}}\6
+\&{begin} \37$\|p\K\\{get\_avail}$;\5
+$\\{font}(\|p)\K\|f$;\5
+$\\{character}(\|p)\K\\{qi}(\|c)$;\5
+$\\{new\_character}\K\|p$;\5
+\&{return};\6
+\&{end};\2\2\2\6
+$\\{char\_warning}(\|f,\39\|c)$;\5
+$\\{new\_character}\K\\{null}$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\N594.  \[31] Device-independent file format.
+The most important output produced by a run of \TeX\ is the ``device
+independent'' (\.{DVI}) file that specifies where characters and rules
+are to appear on printed pages. The form of these files was designed by
+David R. Fuchs in 1979. Almost any reasonable typesetting device can be
+driven by a program that takes \.{DVI} files as input, and dozens of such
+\.{DVI}-to-whatever programs have been written. Thus, it is possible to
+print the output of \TeX\ on many different kinds of equipment, using \TeX\
+as a device-independent ``front end.''
+
+A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a
+series of commands in a machine-like language. The first byte of each command
+is the operation code, and this code is followed by zero or more bytes
+that provide parameters to the command. The parameters themselves may consist
+of several consecutive bytes; for example, the `\\{set\_rule}' command has two
+parameters, each of which is four bytes long. Parameters are usually
+regarded as nonnegative integers; but four-byte-long parameters,
+and shorter parameters that denote distances, can be
+either positive or negative. Such parameters are given in two's complement
+notation. For example, a two-byte-long distance parameter has a value between
+$-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy
+more than one byte position appear in BigEndian order.
+
+A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one
+or more ``pages,'' followed by a ``postamble.'' The preamble is simply a
+\\{pre} command, with its parameters that define the dimensions used in the
+file; this must come first.  Each ``page'' consists of a \\{bop} command,
+followed by any number of other commands that tell where characters are to
+be placed on a physical page, followed by an \\{eop} command. The pages
+appear in the order that \TeX\ generated them. If we ignore \\{nop} commands
+and \\{fnt\_def} commands (which are allowed between any two commands in
+the file), each \\{eop} command is immediately followed by a \\{bop} command,
+or by a \\{post} command; in the latter case, there are no more pages in the
+file, and the remaining bytes form the postamble.  Further details about
+the postamble will be explained later.
+
+Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
+quantities that give the location number of some other byte in the file;
+the first byte is number~0, then comes number~1, and so on. For example,
+one of the parameters of a \\{bop} command points to the previous \\{bop};
+this makes it feasible to read the pages in backwards order, in case the
+results are being directed to a device that stacks its output face up.
+Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the
+first page occupies bytes 100 to 999, say, and if the second
+page occupies bytes 1000 to 1999, then the \\{bop} that starts in byte 1000
+points to 100 and the \\{bop} that starts in byte 2000 points to 1000. (The
+very first \\{bop}, i.e., the one starting in byte 100, has a pointer of~$-1$.)
+
+\fi
+
+\M595. The \.{DVI} format is intended to be both compact and easily interpreted
+by a machine. Compactness is achieved by making most of the information
+implicit instead of explicit. When a \.{DVI}-reading program reads the
+commands for a page, it keeps track of several quantities: (a)~The current
+font \|f is an integer; this value is changed only
+by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page
+is given by two numbers called the horizontal and vertical coordinates,
+\|h and \|v. Both coordinates are zero at the upper left corner of the page;
+moving to the right corresponds to increasing the horizontal coordinate, and
+moving down corresponds to increasing the vertical coordinate. Thus, the
+coordinates are essentially Cartesian, except that vertical directions are
+flipped; the Cartesian version of $(\|h,\|v)$ would be $(\|h,-\|v)$.  (c)~The
+current spacing amounts are given by four numbers \|w, \|x, \|y, and \|z,
+where \|w and~\|x are used for horizontal spacing and where \|y and~\|z
+are used for vertical spacing. (d)~There is a stack containing
+$(\|h,\|v,\|w,\|x,\|y,\|z)$ values; the \.{DVI} commands \\{push} and \\{pop}
+are used to
+change the current level of operation. Note that the current font~\|f is
+not pushed and popped; the stack contains only information about
+positioning.
+
+The values of \|h, \|v, \|w, \|x, \|y, and \|z are signed integers having up
+to 32 bits, including the sign. Since they represent physical distances,
+there is a small unit of measurement such that increasing \|h by~1 means
+moving a certain tiny distance to the right. The actual unit of
+measurement is variable, as explained below; \TeX\ sets things up so that
+its \.{DVI} output is in sp units, i.e., scaled points, in agreement with
+all the \\{scaled} dimensions in \TeX's data structures.
+
+\fi
+
+\M596. Here is a list of all the commands that may appear in a \.{DVI} file.
+Each
+command is specified by its symbolic name (e.g., \\{bop}), its opcode byte
+(e.g., 139), and its parameters (if any). The parameters are followed
+by a bracketed number telling how many bytes they occupy; for example,
+`$\|p[4]$' means that parameter \|p is four bytes long.
+
+\yskip\hang\\{set\_char\_0} 0. Typeset character number~0 from font~\|f
+such that the reference point of the character is at $(\|h,\|v)$. Then
+increase \|h by the width of that character. Note that a character may
+have zero or negative width, so one cannot be sure that \|h will advance
+after this command; but \|h usually does increase.
+
+\yskip\hang\\{set\_char\_1} through \\{set\_char\_127} (opcodes 1 to 127).
+Do the operations of \\{set\_char\_0}; but use the character whose number
+matches the opcode, instead of character~0.
+
+\yskip\hang\\{set1} 128 $\|c[1]$. Same as \\{set\_char\_0}, except that
+character
+number~\|c is typeset. \TeX82 uses this command for characters in the
+range $128\L\|c<256$.
+
+\yskip\hang\\{set2} 129 $\|c[2]$. Same as \\{set1}, except that \|c~is two
+bytes long, so it is in the range $0\L\|c<65536$. \TeX82 never uses this
+command, but it should come in handy for extensions of \TeX\ that deal
+with oriental languages.
+
+\yskip\hang\\{set3} 130 $\|c[3]$. Same as \\{set1}, except that \|c~is three
+bytes long, so it can be as large as $2^{24}-1$. Not even the Chinese
+language has this many characters, but this command might prove useful
+in some yet unforeseen extension.
+
+\yskip\hang\\{set4} 131 $\|c[4]$. Same as \\{set1}, except that \|c~is four
+bytes long. Imagine that.
+
+\yskip\hang\\{set\_rule} 132 $\|a[4]$ $\|b[4]$. Typeset a solid black rectangle
+of height~\|a and width~\|b, with its bottom left corner at $(\|h,\|v)$. Then
+set $\|h\K\|h+\|b$. If either $\|a\L0$ or $\|b\L0$, nothing should be typeset.
+Note
+that if $\|b<0$, the value of \|h will decrease even though nothing else
+happens.
+See below for details about how to typeset rules so that consistency with
+\MF\ is guaranteed.
+
+\yskip\hang\\{put1} 133 $\|c[1]$. Typeset character number~\|c from font~\|f
+such that the reference point of the character is at $(\|h,\|v)$. (The `put'
+commands are exactly like the `set' commands, except that they simply put out a
+character or a rule without moving the reference point afterwards.)
+
+\yskip\hang\\{put2} 134 $\|c[2]$. Same as \\{set2}, except that \|h is not
+changed.
+
+\yskip\hang\\{put3} 135 $\|c[3]$. Same as \\{set3}, except that \|h is not
+changed.
+
+\yskip\hang\\{put4} 136 $\|c[4]$. Same as \\{set4}, except that \|h is not
+changed.
+
+\yskip\hang\\{put\_rule} 137 $\|a[4]$ $\|b[4]$. Same as \\{set\_rule}, except
+that
+\|h is not changed.
+
+\yskip\hang\\{nop} 138. No operation, do nothing. Any number of \\{nop}'s
+may occur between \.{DVI} commands, but a \\{nop} cannot be inserted between
+a command and its parameters or between two parameters.
+
+\yskip\hang\\{bop} 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning
+of a page: Set $(\|h,\|v,\|w,\|x,\|y,\|z)\K(0,0,0,0,0,0)$ and set the stack
+empty. Set
+the current font \|f to an undefined value.  The ten $c_i$ parameters hold
+the values of \.{\\count0} $\ldots$ \.{\\count9} in \TeX\ at the time
+\.{\\shipout} was invoked for this page; they can be used to identify
+pages, if a user wants to print only part of a \.{DVI} file. The parameter
+\|p points to the previous \\{bop} in the file; the first
+\\{bop} has $p=-1$.
+
+\yskip\hang\\{eop} 140.  End of page: Print what you have read since the
+previous \\{bop}. At this point the stack should be empty. (The \.{DVI}-reading
+programs that drive most output devices will have kept a buffer of the
+material that appears on the page that has just ended. This material is
+largely, but not entirely, in order by \|v coordinate and (for fixed \|v) by
+\|h~coordinate; so it usually needs to be sorted into some order that is
+appropriate for the device in question.)
+
+\yskip\hang\\{push} 141. Push the current values of $(\|h,\|v,\|w,\|x,\|y,\|z)$
+onto the
+top of the stack; do not change any of these values. Note that \|f is
+not pushed.
+
+\yskip\hang\\{pop} 142. Pop the top six values off of the stack and assign
+them respectively to $(\|h,\|v,\|w,\|x,\|y,\|z)$. The number of pops should
+never
+exceed the number of pushes, since it would be highly embarrassing if the
+stack were empty at the time of a \\{pop} command.
+
+\yskip\hang\\{right1} 143 $\|b[1]$. Set $\|h\K\|h+\|b$, i.e., move right \|b
+units.
+The parameter is a signed number in two's complement notation, $-128\L\|b<128$;
+if $\|b<0$, the reference point moves left.
+
+\yskip\hang\\{right2} 144 $\|b[2]$. Same as \\{right1}, except that \|b is a
+two-byte quantity in the range $-32768\L\|b<32768$.
+
+\yskip\hang\\{right3} 145 $\|b[3]$. Same as \\{right1}, except that \|b is a
+three-byte quantity in the range $\hbox{$-2^{23}$}\L\|b<\hbox{$2^{23}$}$.
+
+\yskip\hang\\{right4} 146 $\|b[4]$. Same as \\{right1}, except that \|b is a
+four-byte quantity in the range $\hbox{$-2^{31}$}\L\|b<\hbox{$2^{31}$}$.
+
+\yskip\hang\\{w0} 147. Set $\|h\K\|h+\|w$; i.e., move right \|w units. With
+luck,
+this parameterless command will usually suffice, because the same kind of
+motion
+will occur several times in succession; the following commands explain how
+\|w gets particular values.
+
+\yskip\hang\\{w1} 148 $\|b[1]$. Set $\|w\K\|b$ and $\|h\K\|h+\|b$. The value of
+\|b is a
+signed quantity in two's complement notation, $-128\L\|b<128$. This command
+changes the current \|w~spacing and moves right by \|b.
+
+\yskip\hang\\{w2} 149 $\|b[2]$. Same as \\{w1}, but \|b is two bytes long,
+$-32768\L\|b<32768$.
+
+\yskip\hang\\{w3} 150 $\|b[3]$. Same as \\{w1}, but \|b is three bytes long,
+$\hbox{$-2^{23}$}\L\|b<\hbox{$2^{23}$}$.
+
+\yskip\hang\\{w4} 151 $\|b[4]$. Same as \\{w1}, but \|b is four bytes long,
+$\hbox{$-2^{31}$}\L\|b<\hbox{$2^{31}$}$.
+
+\yskip\hang\\{x0} 152. Set $\|h\K\|h+\|x$; i.e., move right \|x units. The `%
+\|x'
+commands are like the `\|w' commands except that they involve \|x instead
+of \|w.
+
+\yskip\hang\\{x1} 153 $\|b[1]$. Set $\|x\K\|b$ and $\|h\K\|h+\|b$. The value of
+\|b is a
+signed quantity in two's complement notation, $-128\L\|b<128$. This command
+changes the current \|x~spacing and moves right by \|b.
+
+\yskip\hang\\{x2} 154 $\|b[2]$. Same as \\{x1}, but \|b is two bytes long,
+$-32768\L\|b<32768$.
+
+\yskip\hang\\{x3} 155 $\|b[3]$. Same as \\{x1}, but \|b is three bytes long,
+$\hbox{$-2^{23}$}\L\|b<\hbox{$2^{23}$}$.
+
+\yskip\hang\\{x4} 156 $\|b[4]$. Same as \\{x1}, but \|b is four bytes long,
+$\hbox{$-2^{31}$}\L\|b<\hbox{$2^{31}$}$.
+
+\yskip\hang\\{down1} 157 $\|a[1]$. Set $\|v\K\|v+\|a$, i.e., move down \|a
+units.
+The parameter is a signed number in two's complement notation, $-128\L\|a<128$;
+if $\|a<0$, the reference point moves up.
+
+\yskip\hang\\{down2} 158 $\|a[2]$. Same as \\{down1}, except that \|a is a
+two-byte quantity in the range $-32768\L\|a<32768$.
+
+\yskip\hang\\{down3} 159 $\|a[3]$. Same as \\{down1}, except that \|a is a
+three-byte quantity in the range $\hbox{$-2^{23}$}\L\|a<\hbox{$2^{23}$}$.
+
+\yskip\hang\\{down4} 160 $\|a[4]$. Same as \\{down1}, except that \|a is a
+four-byte quantity in the range $\hbox{$-2^{31}$}\L\|a<\hbox{$2^{31}$}$.
+
+\yskip\hang\\{y0} 161. Set $\|v\K\|v+\|y$; i.e., move down \|y units. With
+luck,
+this parameterless command will usually suffice, because the same kind of
+motion
+will occur several times in succession; the following commands explain how
+\|y gets particular values.
+
+\yskip\hang\\{y1} 162 $\|a[1]$. Set $\|y\K\|a$ and $\|v\K\|v+\|a$. The value of
+\|a is a
+signed quantity in two's complement notation, $-128\L\|a<128$. This command
+changes the current \|y~spacing and moves down by \|a.
+
+\yskip\hang\\{y2} 163 $\|a[2]$. Same as \\{y1}, but \|a is two bytes long,
+$-32768\L\|a<32768$.
+
+\yskip\hang\\{y3} 164 $\|a[3]$. Same as \\{y1}, but \|a is three bytes long,
+$\hbox{$-2^{23}$}\L\|a<\hbox{$2^{23}$}$.
+
+\yskip\hang\\{y4} 165 $\|a[4]$. Same as \\{y1}, but \|a is four bytes long,
+$\hbox{$-2^{31}$}\L\|a<\hbox{$2^{31}$}$.
+
+\yskip\hang\\{z0} 166. Set $\|v\K\|v+\|z$; i.e., move down \|z units. The `\|z'
+commands
+are like the `\|y' commands except that they involve \|z instead of \|y.
+
+\yskip\hang\\{z1} 167 $\|a[1]$. Set $\|z\K\|a$ and $\|v\K\|v+\|a$. The value of
+\|a is a
+signed quantity in two's complement notation, $-128\L\|a<128$. This command
+changes the current \|z~spacing and moves down by \|a.
+
+\yskip\hang\\{z2} 168 $\|a[2]$. Same as \\{z1}, but \|a is two bytes long,
+$-32768\L\|a<32768$.
+
+\yskip\hang\\{z3} 169 $\|a[3]$. Same as \\{z1}, but \|a is three bytes long,
+$\hbox{$-2^{23}$}\L\|a<\hbox{$2^{23}$}$.
+
+\yskip\hang\\{z4} 170 $\|a[4]$. Same as \\{z1}, but \|a is four bytes long,
+$\hbox{$-2^{31}$}\L\|a<\hbox{$2^{31}$}$.
+
+\yskip\hang\\{fnt\_num\_0} 171. Set $\|f\K0$. Font 0 must previously have been
+defined by a \\{fnt\_def} instruction, as explained below.
+
+\yskip\hang\\{fnt\_num\_1} through \\{fnt\_num\_63} (opcodes 172 to 234). Set
+$\|f\K1$, \dots, \hbox{$\|f\K63$}, respectively.
+
+\yskip\hang\\{fnt1} 235 $\|k[1]$. Set $\|f\K\|k$. \TeX82 uses this command for
+font
+numbers in the range $64\L\|k<256$.
+
+\yskip\hang\\{fnt2} 236 $\|k[2]$. Same as \\{fnt1}, except that \|k~is two
+bytes long, so it is in the range $0\L\|k<65536$. \TeX82 never generates this
+command, but large font numbers may prove useful for specifications of
+color or texture, or they may be used for special fonts that have fixed
+numbers in some external coding scheme.
+
+\yskip\hang\\{fnt3} 237 $\|k[3]$. Same as \\{fnt1}, except that \|k~is three
+bytes long, so it can be as large as $2^{24}-1$.
+
+\yskip\hang\\{fnt4} 238 $\|k[4]$. Same as \\{fnt1}, except that \|k~is four
+bytes long; this is for the really big font numbers (and for the negative
+ones).
+
+\yskip\hang\\{xxx1} 239 $\|k[1]$ $\|x[\|k]$. This command is undefined in
+general; it functions as a $(k+2)$-byte \\{nop} unless special \.{DVI}-reading
+programs are being used. \TeX82 generates \\{xxx1} when a short enough
+\.{\\special} appears, setting \|k to the number of bytes being sent. It
+is recommended that \|x be a string having the form of a keyword followed
+by possible parameters relevant to that keyword.
+
+\yskip\hang\\{xxx2} 240 $\|k[2]$ $\|x[\|k]$. Like \\{xxx1}, but $0\L\|k<65536$.
+
+\yskip\hang\\{xxx3} 241 $\|k[3]$ $\|x[\|k]$. Like \\{xxx1}, but $0\L\|k<%
+\hbox{$2^{24}$}$.
+
+\yskip\hang\\{xxx4} 242 $\|k[4]$ $\|x[\|k]$. Like \\{xxx1}, but \|k can be
+ridiculously
+large. \TeX82 uses \\{xxx4} when sending a string of length 256 or more.
+
+\yskip\hang\\{fnt\_def1} 243 $\|k[1]$ $\|c[4]$ $\|s[4]$ $\|d[4]$ $\|a[1]$ $%
+\|l[1]$ $\|n[\|a+\|l]$.
+Define font \|k, where $0\L\|k<256$; font definitions will be explained
+shortly.
+
+\yskip\hang\\{fnt\_def2} 244 $\|k[2]$ $\|c[4]$ $\|s[4]$ $\|d[4]$ $\|a[1]$ $%
+\|l[1]$ $\|n[\|a+\|l]$.
+Define font \|k, where $0\L\|k<65536$.
+
+\yskip\hang\\{fnt\_def3} 245 $\|k[3]$ $\|c[4]$ $\|s[4]$ $\|d[4]$ $\|a[1]$ $%
+\|l[1]$ $\|n[\|a+\|l]$.
+Define font \|k, where $0\L\|k<\hbox{$2^{24}$}$.
+
+\yskip\hang\\{fnt\_def4} 246 $\|k[4]$ $\|c[4]$ $\|s[4]$ $\|d[4]$ $\|a[1]$ $%
+\|l[1]$ $\|n[\|a+\|l]$.
+Define font \|k, where $\hbox{$-2^{31}$}\L\|k<\hbox{$2^{31}$}$.
+
+\yskip\hang\\{pre} 247 $\|i[1]$ $\\{num}[4]$ $\\{den}[4]$ $\\{mag}[4]$ $\|k[1]$
+$\|x[\|k]$.
+Beginning of the preamble; this must come at the very beginning of the
+file. Parameters \|i, \\{num}, \\{den}, \\{mag}, \|k, and \|x are explained
+below.
+
+\yskip\hang\\{post} 248. Beginning of the postamble, see below.
+
+\yskip\hang\\{post\_post} 249. Ending of the postamble, see below.
+
+\yskip\noindent Commands 250--255 are undefined at the present time.
+
+\fi
+
+\M597. \P\D \37$\\{set\_char\_0}=0$\C{typeset character 0 and move right}\par
+\P\D \37$\\{set1}=128$\C{typeset a character and move right}\par
+\P\D \37$\\{set2}=129$\C{typeset a character and move right}\par
+\P\D \37$\\{set\_rule}=132$\C{typeset a rule and move right}\par
+\P\D \37$\\{put\_rule}=137$\C{typeset a rule}\par
+\P\D \37$\\{nop}=138$\C{no operation}\par
+\P\D \37$\\{bop}=139$\C{beginning of page}\par
+\P\D \37$\\{eop}=140$\C{ending of page}\par
+\P\D \37$\\{push}=141$\C{save the current positions}\par
+\P\D \37$\\{pop}=142$\C{restore previous positions}\par
+\P\D \37$\\{right1}=143$\C{move right}\par
+\P\D \37$\\{w0}=147$\C{move right by \|w}\par
+\P\D \37$\\{w1}=148$\C{move right and set \|w}\par
+\P\D \37$\\{x0}=152$\C{move right by \|x}\par
+\P\D \37$\\{x1}=153$\C{move right and set \|x}\par
+\P\D \37$\\{down1}=157$\C{move down}\par
+\P\D \37$\\{y0}=161$\C{move down by \|y}\par
+\P\D \37$\\{y1}=162$\C{move down and set \|y}\par
+\P\D \37$\\{z0}=166$\C{move down by \|z}\par
+\P\D \37$\\{z1}=167$\C{move down and set \|z}\par
+\P\D \37$\\{fnt\_num\_0}=171$\C{set current font to 0}\par
+\P\D \37$\\{fnt1}=235$\C{set current font}\par
+\P\D \37$\\{xxx1}=239$\C{extension to \.{DVI} primitives}\par
+\P\D \37$\\{xxx4}=242$\C{potentially long extension to \.{DVI} primitives}\par
+\P\D \37$\\{fnt\_def1}=243$\C{define the meaning of a font number}\par
+\P\D \37$\\{pre}=247$\C{preamble}\par
+\P\D \37$\\{post}=248$\C{postamble beginning}\par
+\P\D \37$\\{post\_post}=249$\C{postamble ending}\par
+\P\D \37$\\{dirchg}=255$\C{direction change}\par
+\fi
+
+\M598. The preamble contains basic information about the file as a whole. As
+stated above, there are six parameters:
+$$\hbox{$\|i[1]$ $\\{num}[4]$ $\\{den}[4]$ $\\{mag}[4]$ $\|k[1]$ $\|x[\|k]$.}$$
+The \|i byte identifies \.{DVI} format; currently this byte is always set
+to~2. (The value $\|i=3$ is currently used for an extended format that
+allows a mixture of right-to-left and left-to-right typesetting.
+Some day we will set $\|i=4$, when \.{DVI} format makes another
+incompatible change---perhaps in the year 2048.)
+
+The next two parameters, \\{num} and \\{den}, are positive integers that define
+the units of measurement; they are the numerator and denominator of a
+fraction by which all dimensions in the \.{DVI} file could be multiplied
+in order to get lengths in units of $10^{-7}$ meters. Since $\rm 7227{pt} =
+254{cm}$, and since \TeX\ works with scaled points where there are $2^{16}$
+sp in a point, \TeX\ sets
+$\\{num}/\\{den}=(254\cdot10^5)/(7227\cdot2^{16})=25400000/473628672$.
+
+The \\{mag} parameter is what \TeX\ calls \.{\\mag}, i.e., 1000 times the
+desired magnification. The actual fraction by which dimensions are
+multiplied is therefore $\\{mag}\cdot\\{num}/1000\\{den}$. Note that if a \TeX\
+source document does not call for any `\.{true}' dimensions, and if you
+change it only by specifying a different \.{\\mag} setting, the \.{DVI}
+file that \TeX\ creates will be completely unchanged except for the value
+of \\{mag} in the preamble and postamble. (Fancy \.{DVI}-reading programs allow
+users to override the \\{mag}~setting when a \.{DVI} file is being printed.)
+
+Finally, \|k and \|x allow the \.{DVI} writer to include a comment, which is
+not
+interpreted further. The length of comment \|x is \|k, where $0\L\|k<256$.
+
+\Y\P\D \37$\\{id\_byte}=2$\C{identifies the kind of \.{DVI} files described
+here}\par
+\P\D \37$\\{ex\_id\_byte}=3$\C{identifies the kind of extended \.{DVI} files}%
+\par
+\fi
+
+\M599. Font definitions for a given font number \|k contain further parameters
+$$\hbox{$\|c[4]$ $\|s[4]$ $\|d[4]$ $\|a[1]$ $\|l[1]$ $\|n[\|a+\|l]$.}$$
+The four-byte value \|c is the check sum that \TeX\ found in the \.{TFM}
+file for this font; \|c should match the check sum of the font found by
+programs that read this \.{DVI} file.
+
+Parameter \|s contains a fixed-point scale factor that is applied to
+the character widths in font \|k; font dimensions in \.{TFM} files and
+other font files are relative to this quantity, which is called the
+``at size'' elsewhere in this documentation. The value of \|s is
+always positive and less than $2^{27}$. It is given in the same units
+as the other \.{DVI} dimensions, i.e., in sp when \TeX82 has made the
+file.  Parameter \|d is similar to \|s; it is the ``design size,'' and
+(like~\|s) it is given in \.{DVI} units. Thus, font \|k is to be used
+at $\\{mag}\cdot s/1000d$ times its normal size.
+
+The remaining part of a font definition gives the external name of the font,
+which is an ASCII string of length $\|a+\|l$. The number \|a is the length
+of the ``area'' or directory, and \|l is the length of the font name itself;
+the standard local system font area is supposed to be used when $\|a=0$.
+The \|n field contains the area in its first \|a bytes.
+
+Font definitions must appear before the first use of a particular font number.
+Once font \|k is defined, it must not be defined again; however, we
+shall see below that font definitions appear in the postamble as well as
+in the pages, so in this sense each font number is defined exactly twice,
+if at all. Like \\{nop} commands, font definitions can
+appear before the first \\{bop}, or between an \\{eop} and a \\{bop}.
+
+\fi
+
+\M600. Sometimes it is desirable to make horizontal or vertical rules line up
+precisely with certain features in characters of a font. It is possible to
+guarantee the correct matching between \.{DVI} output and the characters
+generated by \MF\ by adhering to the following principles: (1)~The \MF\
+characters should be positioned so that a bottom edge or left edge that is
+supposed to line up with the bottom or left edge of a rule appears at the
+reference point, i.e., in row~0 and column~0 of the \MF\ raster. This
+ensures that the position of the rule will not be rounded differently when
+the pixel size is not a perfect multiple of the units of measurement in
+the \.{DVI} file. (2)~A typeset rule of height $a>0$ and width $b>0$
+should be equivalent to a \MF-generated character having black pixels in
+precisely those raster positions whose \MF\ coordinates satisfy
+$0\L\|x<\hbox{$\alpha$}\|b$ and $0\L\|y<\hbox{$\alpha$}\|a$, where $\alpha$ is
+the number
+of pixels per \.{DVI} unit.
+
+\fi
+
+\M601. The last page in a \.{DVI} file is followed by `\\{post}'; this command
+introduces the postamble, which summarizes important facts that \TeX\ has
+accumulated about the file, making it possible to print subsets of the data
+with reasonable efficiency. The postamble has the form
+$$\vbox{\halign{\hbox{#\hfil}\cr
+\\{post} $\|p[4]$ $\\{num}[4]$ $\\{den}[4]$ $\\{mag}[4]$ $\|l[4]$ $\|u[4]$ $%
+\|s[2]$ $\|t[2]$\cr
+$\langle\,$font definitions$\,\rangle$\cr
+\\{post\_post} $\|q[4]$ $\|i[1]$ 223's$[{\G}4]$\cr}}$$
+Here \|p is a pointer to the final \\{bop} in the file. The next three
+parameters, \\{num}, \\{den}, and \\{mag}, are duplicates of the quantities
+that
+appeared in the preamble.
+
+Parameters \|l and \|u give respectively the height-plus-depth of the tallest
+page and the width of the widest page, in the same units as other dimensions
+of the file. These numbers might be used by a \.{DVI}-reading program to
+position individual ``pages'' on large sheets of film or paper; however,
+the standard convention for output on normal size paper is to position each
+page so that the upper left-hand corner is exactly one inch from the left
+and the top. Experience has shown that it is unwise to design %
+\.{DVI}-to-printer
+software that attempts cleverly to center the output; a fixed position of
+the upper left corner is easiest for users to understand and to work with.
+Therefore \|l and~\|u are often ignored.
+
+Parameter \|s is the maximum stack depth (i.e., the largest excess of
+\\{push} commands over \\{pop} commands) needed to process this file. Then
+comes \|t, the total number of pages (\\{bop} commands) present.
+
+The postamble continues with font definitions, which are any number of
+\\{fnt\_def} commands as described above, possibly interspersed with \\{nop}
+commands. Each font number that is used in the \.{DVI} file must be defined
+exactly twice: Once before it is first selected by a \\{fnt} command, and once
+in the postamble.
+
+\fi
+
+\M602. The last part of the postamble, following the \\{post\_post} byte that
+signifies the end of the font definitions, contains \|q, a pointer to the
+\\{post} command that started the postamble.  An identification byte, \|i,
+comes next; this equals~2 or~3. If not used p\TeX primitives then the
+identification byte equals~2, othercase this is set to~3.
+
+The \|i byte is followed by four or more bytes that are all equal to
+the decimal number 223 (i.e., \O{337} in octal). \TeX\ puts out four to seven
+of
+these trailing bytes, until the total length of the file is a multiple of
+four bytes, since this works out best on machines that pack four bytes per
+word; but any number of 223's is allowed, as long as there are at least four
+of them. In effect, 223 is a sort of signature that is added at the very end.
+
+This curious way to finish off a \.{DVI} file makes it feasible for
+\.{DVI}-reading programs to find the postamble first, on most computers,
+even though \TeX\ wants to write the postamble last. Most operating
+systems permit random access to individual words or bytes of a file, so
+the \.{DVI} reader can start at the end and skip backwards over the 223's
+until finding the identification byte. Then it can back up four bytes, read
+\|q, and move to byte \|q of the file. This byte should, of course,
+contain the value 248 (\\{post}); now the postamble can be read, so the
+\.{DVI} reader can discover all the information needed for typesetting the
+pages. Note that it is also possible to skip through the \.{DVI} file at
+reasonably high speed to locate a particular page, if that proves
+desirable. This saves a lot of time, since \.{DVI} files used in production
+jobs tend to be large.
+
+Unfortunately, however, standard \PASCAL\ does not include the ability to
+access a random position in a file, or even to determine the length of a file.
+Almost all systems nowadays provide the necessary capabilities, so \.{DVI}
+format has been designed to work most efficiently with modern operating
+systems.
+But if \.{DVI} files have to be processed under the restrictions of standard
+\PASCAL, one can simply read them from front to back, since the necessary
+header information is present in the preamble and in the font definitions.
+(The \|l and \|u and \|s and \|t parameters, which appear only in the
+postamble, are ``frills'' that are handy but not absolutely necessary.)
+
+\fi
+
+\N603.  \[32] Shipping pages out.
+After considering \TeX's eyes and stomach, we come now to the bowels.
+
+The \\{ship\_out} procedure is given a pointer to a box; its mission is
+to describe that box in \.{DVI} form, outputting a ``page'' to \\{dvi\_file}.
+The \.{DVI} coordinates $(h,v)=(0,0)$ should correspond to the upper left
+corner of the box being shipped.
+
+Since boxes can be inside of boxes inside of boxes, the main work of
+\\{ship\_out} is done by two mutually recursive routines, \\{hlist\_out}
+and \\{vlist\_out}, which traverse the hlists and vlists inside of horizontal
+and vertical boxes.
+
+As individual pages are being processed, we need to accumulate
+information about the entire set of pages, since such statistics must be
+reported in the postamble. The global variables \\{total\_pages}, \\{max\_v},
+\\{max\_h}, \\{max\_push}, and \\{last\_bop} are used to record this
+information.
+
+The variable \\{doing\_leaders} is \\{true} while leaders are being output.
+The variable \\{dead\_cycles} contains the number of times an output routine
+has been initiated since the last \\{ship\_out}.
+
+A few additional global variables are also defined here for use in
+\\{vlist\_out} and \\{hlist\_out}. They could have been local variables, but
+that would waste stack space when boxes are deeply nested, since the
+values of these variables are not needed during recursive calls.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{total\_pages}: \37\\{integer};\C{the number of pages that have been
+shipped out}\6
+\4\\{max\_v}: \37\\{scaled};\C{maximum height-plus-depth of pages shipped so
+far}\6
+\4\\{max\_h}: \37\\{scaled};\C{maximum width of pages shipped so far}\6
+\4\\{max\_push}: \37\\{integer};\C{deepest nesting of \\{push} commands
+encountered so far}\6
+\4\\{last\_bop}: \37\\{integer};\C{location of previous \\{bop} in the \.{DVI}
+output}\6
+\4\\{dead\_cycles}: \37\\{integer};\C{recent outputs that didn't ship anything
+out}\6
+\4\\{doing\_leaders}: \37\\{boolean};\C{are we inside a leader box?}\7
+\C{character and font in current \\{char\_node}}\6
+\4\|c: \37\\{quarterword};\6
+\4\|f: \37\\{internal\_font\_number};\6
+\4\\{dir\_used}: \37\\{boolean};\C{Is this dvi extended?}\6
+\4$\\{rule\_ht},\39\\{rule\_dp},\39\\{rule\_wd}$: \37\\{scaled};\C{size of
+current rule being output}\6
+\4\|g: \37\\{pointer};\C{current glue specification}\6
+\4$\\{lq},\39\\{lr}$: \37\\{integer};\C{quantities used in calculations for
+leaders}\par
+\fi
+
+\M604. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{total\_pages}\K0$;\5
+$\\{max\_v}\K0$;\5
+$\\{max\_h}\K0$;\5
+$\\{max\_push}\K0$;\5
+$\\{last\_bop}\K-1$;\5
+$\\{doing\_leaders}\K\\{false}$;\5
+$\\{dead\_cycles}\K0$;\5
+$\\{cur\_s}\K-1$;\5
+$\\{dir\_used}\K\\{false}$;\par
+\fi
+
+\M605. The \.{DVI} bytes are output to a buffer instead of being written
+directly
+to the output file. This makes it possible to reduce the overhead of
+subroutine calls, thereby measurably speeding up the computation, since
+output of \.{DVI} bytes is part of \TeX's inner loop. And it has another
+advantage as well, since we can change instructions in the buffer in order to
+make the output more compact. For example, a `\\{down2}' command can be
+changed to a `\\{y2}', thereby making a subsequent `\\{y0}' command possible,
+saving two bytes.
+
+The output buffer is divided into two parts of equal size; the bytes found
+in $\\{dvi\_buf}[0\to\\{half\_buf}-1]$ constitute the first half, and those in
+$\\{dvi\_buf}[\\{half\_buf}\to\\{dvi\_buf\_size}-1]$ constitute the second. The
+global
+variable \\{dvi\_ptr} points to the position that will receive the next
+output byte. When \\{dvi\_ptr} reaches \\{dvi\_limit}, which is always equal
+to one of the two values \\{half\_buf} or \\{dvi\_buf\_size}, the half buffer
+that
+is about to be invaded next is sent to the output and \\{dvi\_limit} is
+changed to its other value. Thus, there is always at least a half buffer's
+worth of information present, except at the very beginning of the job.
+
+Bytes of the \.{DVI} file are numbered sequentially starting with 0;
+the next byte to be generated will be number $\\{dvi\_offset}+\\{dvi\_ptr}$.
+A byte is present in the buffer only if its number is $\G\\{dvi\_gone}$.
+
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{dvi\_index}=0\to\\{dvi\_buf\_size}$;\C{an index into the output buffer}\par
+\fi
+
+\M606. Some systems may find it more efficient to make \\{dvi\_buf} a %
+\&{packed}
+array, since output of four bytes at once may be facilitated.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{dvi\_buf}: \37$\^\\{eight\_bits}$;\C{buffer for \.{DVI} output}\6
+\4\\{half\_buf}: \37\\{integer};\C{half of \\{dvi\_buf\_size}}\6
+\4\\{dvi\_limit}: \37\\{integer};\C{end of the current half buffer}\6
+\4\\{dvi\_ptr}: \37\\{integer};\C{the next available buffer address}\6
+\4\\{dvi\_offset}: \37\\{integer};\C{\\{dvi\_buf\_size} times the number of
+times the   output buffer has been fully emptied}\6
+\4\\{dvi\_gone}: \37\\{integer};\C{the number of bytes already output to \\{dvi%
+\_file}}\par
+\fi
+
+\M607. Initially the buffer is all in one piece; we will output half of it only
+after it first fills up.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{half\_buf}\K\\{dvi\_buf\_size}\mathbin{\&{div}}2$;\5
+$\\{dvi\_limit}\K\\{dvi\_buf\_size}$;\5
+$\\{dvi\_ptr}\K0$;\5
+$\\{dvi\_offset}\K0$;\5
+$\\{dvi\_gone}\K0$;\par
+\fi
+
+\M608. The actual output of $\\{dvi\_buf}[\|a\to\|b]$ to \\{dvi\_file} is
+performed by calling
+$\\{write\_dvi}(\|a,\|b)$. For best results, this procedure should be optimized
+to
+run as fast as possible on each particular system, since it is part of
+\TeX's inner loop. It is safe to assume that \|a and $\|b+1$ will both be
+multiples of 4 when $\\{write\_dvi}(\|a,\|b)$ is called; therefore it is
+possible on
+many machines to use efficient methods to pack four bytes per word and to
+output an array of words with one system call.
+
+In C, we use a macro to call \\{fwrite} or \\{write} directly, writing all
+the bytes in one shot.  Much better even than writing four
+bytes at a time.
+
+\fi
+
+\M609. To put a byte in the buffer without paying the cost of invoking a
+procedure
+each time, we use the macro \\{dvi\_out}.
+
+The length of \\{dvi\_file} should not exceed \H{7FFFFFFF}; we set $\\{cur\_s}%
+\K-2$
+to prevent further \.{DVI} output causing infinite recursion.
+
+\Y\P\D \37$\\{dvi\_out}(\#)\S$\ \&{begin} \37$\\{dvi\_buf}[\\{dvi\_ptr}]\K\#$;\5
+$\\{incr}(\\{dvi\_ptr})$;\6
+\&{if} $\\{dvi\_ptr}=\\{dvi\_limit}$ \1\&{then}\5
+\\{dvi\_swap};\2\6
+\&{end}\par
+\Y\P\4\&{procedure}\1\  \37\\{dvi\_swap};\C{outputs half of the buffer}\2\6
+\&{begin} \37\&{if} $\\{dvi\_ptr}>(\H{7FFFFFFF}-\\{dvi\_offset})$ \1\&{then}\6
+\&{begin} \37$\\{cur\_s}\K-2$;\5
+$\\{fatal\_error}(\.{"dvi\ length\ exceeds\ "}\.{"7FFFFFFF"})$;\6
+\&{end};\2\6
+\&{if} $\\{dvi\_limit}=\\{dvi\_buf\_size}$ \1\&{then}\6
+\&{begin} \37$\\{write\_dvi}(0,\39\\{half\_buf}-1)$;\5
+$\\{dvi\_limit}\K\\{half\_buf}$;\5
+$\\{dvi\_offset}\K\\{dvi\_offset}+\\{dvi\_buf\_size}$;\5
+$\\{dvi\_ptr}\K0$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{write\_dvi}(\\{half\_buf},\39\\{dvi\_buf%
+\_size}-1)$;\5
+$\\{dvi\_limit}\K\\{dvi\_buf\_size}$;\6
+\&{end};\2\6
+$\\{dvi\_gone}\K\\{dvi\_gone}+\\{half\_buf}$;\6
+\&{end};\par
+\fi
+
+\M610. Here is how we clean out the buffer when \TeX\ is all through; \\{dvi%
+\_ptr}
+will be a multiple of~4.
+
+\Y\P$\4\X610:Empty the last bytes out of \\{dvi\_buf}\X\S$\6
+\&{if} $\\{dvi\_limit}=\\{half\_buf}$ \1\&{then}\5
+$\\{write\_dvi}(\\{half\_buf},\39\\{dvi\_buf\_size}-1)$;\2\6
+\&{if} $\\{dvi\_ptr}>(\H{7FFFFFFF}-\\{dvi\_offset})$ \1\&{then}\6
+\&{begin} \37$\\{cur\_s}\K-2$;\5
+$\\{fatal\_error}(\.{"dvi\ length\ exceeds\ "}\.{"7FFFFFFF"})$;\6
+\&{end};\2\6
+\&{if} $\\{dvi\_ptr}>0$ \1\&{then}\5
+$\\{write\_dvi}(0,\39\\{dvi\_ptr}-1)$\2\par
+\U653.\fi
+
+\M611. The \\{dvi\_four} procedure outputs four bytes in two's complement
+notation,
+without risking arithmetic overflow.
+
+\Y\P\4\&{procedure}\1\  \37$\\{dvi\_four}(\|x:\\{integer})$;\2\6
+\&{begin} \37\&{if} $\|x\G0$ \1\&{then}\5
+$\\{dvi\_out}(\|x\mathbin{\&{div}}\O{100000000})$\6
+\4\&{else} \&{begin} \37$\|x\K\|x+\O{10000000000}$;\5
+$\|x\K\|x+\O{10000000000}$;\5
+$\\{dvi\_out}((\|x\mathbin{\&{div}}\O{100000000})+128)$;\6
+\&{end};\2\6
+$\|x\K\|x\mathbin{\&{mod}}\O{100000000}$;\5
+$\\{dvi\_out}(\|x\mathbin{\&{div}}\O{200000})$;\5
+$\|x\K\|x\mathbin{\&{mod}}\O{200000}$;\5
+$\\{dvi\_out}(\|x\mathbin{\&{div}}\O{400})$;\5
+$\\{dvi\_out}(\|x\mathbin{\&{mod}}\O{400})$;\6
+\&{end};\par
+\fi
+
+\M612. A mild optimization of the output is performed by the \\{dvi\_pop}
+routine, which issues a \\{pop} unless it is possible to cancel a
+`\\{push} \\{pop}' pair. The parameter to \\{dvi\_pop} is the byte address
+following the old \\{push} that matches the new \\{pop}.
+
+\Y\P\4\&{procedure}\1\  \37$\\{dvi\_pop}(\|l:\\{integer})$;\2\6
+\&{begin} \37\&{if} $(\|l=\\{dvi\_offset}+\\{dvi\_ptr})\W(\\{dvi\_ptr}>0)$ \1%
+\&{then}\5
+$\\{decr}(\\{dvi\_ptr})$\6
+\4\&{else} $\\{dvi\_out}(\\{pop})$;\2\6
+\&{end};\par
+\fi
+
+\M613. Here's a procedure that outputs a font definition. Since \TeX82 uses at
+most 256 different fonts per job, \\{fnt\_def1} is always used as the command
+code.
+
+\Y\P\4\&{procedure}\1\  \37$\\{dvi\_font\_def}(\|f:\\{internal\_font%
+\_number})$;\6
+\4\&{var} \37\|k: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\2\6
+\&{begin} \37\&{if} $\|f\L256+\\{font\_base}$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_out}(\\{fnt\_def1})$;\5
+$\\{dvi\_out}(\|f-\\{font\_base}-1)$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{dvi\_out}(\\{fnt\_def1}+1)$;\5
+$\\{dvi\_out}((\|f-\\{font\_base}-1)\mathbin{\&{div}}\O{400})$;\5
+$\\{dvi\_out}((\|f-\\{font\_base}-1)\mathbin{\&{mod}}\O{400})$;\6
+\&{end};\2\6
+$\\{dvi\_out}(\\{qo}(\\{font\_check}[\|f].\\{b0}))$;\5
+$\\{dvi\_out}(\\{qo}(\\{font\_check}[\|f].\\{b1}))$;\5
+$\\{dvi\_out}(\\{qo}(\\{font\_check}[\|f].\\{b2}))$;\5
+$\\{dvi\_out}(\\{qo}(\\{font\_check}[\|f].\\{b3}))$;\6
+$\\{dvi\_four}(\\{font\_size}[\|f])$;\5
+$\\{dvi\_four}(\\{font\_dsize}[\|f])$;\6
+$\\{dvi\_out}(\\{length}(\\{font\_area}[\|f]))$;\5
+$\\{dvi\_out}(\\{length}(\\{font\_name}[\|f]))$;\5
+\X614:Output the font name whose internal number is \|f\X;\6
+\&{end};\par
+\fi
+
+\M614. \P$\X614:Output the font name whose internal number is \|f\X\S$\6
+\&{for} $\|k\K\\{str\_start}[\\{font\_area}[\|f]]\mathrel{\&{to}}\\{str%
+\_start}[\\{font\_area}[\|f]+1]-1$ \1\&{do}\5
+$\\{dvi\_out}(\\{so}(\\{str\_pool}[\|k]))$;\2\6
+\&{for} $\|k\K\\{str\_start}[\\{font\_name}[\|f]]\mathrel{\&{to}}\\{str%
+\_start}[\\{font\_name}[\|f]+1]-1$ \1\&{do}\5
+$\\{dvi\_out}(\\{so}(\\{str\_pool}[\|k]))$\2\par
+\U613.\fi
+
+\M615. Versions of \TeX\ intended for small computers might well choose to omit
+the ideas in the next few parts of this program, since it is not really
+necessary to optimize the \.{DVI} code by making use of the \\{w0}, \\{x0},
+\\{y0}, and \\{z0} commands. Furthermore, the algorithm that we are about to
+describe does not pretend to give an optimum reduction in the length
+of the \.{DVI} code; after all, speed is more important than compactness.
+But the method is surprisingly effective, and it takes comparatively little
+time.
+
+We can best understand the basic idea by first considering a simpler problem
+that has the same essential characteristics. Given a sequence of digits,
+say $3\,1\,4\,1\,5\,9\,2\,6\,5\,3\,5\,8\,9$, we want to assign subscripts
+$d$, $y$, or $z$ to each digit so as to maximize the number of ``$y$-hits''
+and ``$z$-hits''; a $y$-hit is an instance of two appearances of the same
+digit with the subscript $y$, where no $y$'s intervene between the two
+appearances, and a $z$-hit is defined similarly. For example, the sequence
+above could be decorated with subscripts as follows:
+$$3_z\,1_y\,4_d\,1_y\,5_y\,9_d\,2_d\,6_d\,5_y\,3_z\,5_y\,8_d\,9_d.$$
+There are three $y$-hits ($1_y\ldots1_y$ and $5_y\ldots5_y\ldots5_y$) and
+one $z$-hit ($3_z\ldots3_z$); there are no $d$-hits, since the two appearances
+of $9_d$ have $d$'s between them, but we don't count $d$-hits so it doesn't
+matter how many there are. These subscripts are analogous to the \.{DVI}
+commands called \\{down}, $y$, and $z$, and the digits are analogous to
+different amounts of vertical motion; a $y$-hit or $z$-hit corresponds to
+the opportunity to use the one-byte commands \\{y0} or \\{z0} in a \.{DVI}
+file.
+
+\TeX's method of assigning subscripts works like this: Append a new digit,
+say $\delta$, to the right of the sequence. Now look back through the
+sequence until one of the following things happens: (a)~You see
+$\delta_y$ or $\delta_z$, and this was the first time you encountered a
+$y$ or $z$ subscript, respectively.  Then assign $y$ or $z$ to the new
+$\delta$; you have scored a hit. (b)~You see $\delta_d$, and no $y$
+subscripts have been encountered so far during this search.  Then change
+the previous $\delta_d$ to $\delta_y$ (this corresponds to changing a
+command in the output buffer), and assign $y$ to the new $\delta$; it's
+another hit.  (c)~You see $\delta_d$, and a $y$ subscript has been seen
+but not a $z$.  Change the previous $\delta_d$ to $\delta_z$ and assign
+$z$ to the new $\delta$. (d)~You encounter both $y$ and $z$ subscripts
+before encountering a suitable $\delta$, or you scan all the way to the
+front of the sequence. Assign $d$ to the new $\delta$; this assignment may
+be changed later.
+
+The subscripts $3_z\,1_y\,4_d\ldots\,$ in the example above were, in fact,
+produced by this procedure, as the reader can verify. (Go ahead and try it.)
+
+\fi
+
+\M616. In order to implement such an idea, \TeX\ maintains a stack of pointers
+to the \\{down}, $y$, and $z$ commands that have been generated for the
+current page. And there is a similar stack for \\{right}, \|w, and \|x
+commands. These stacks are called the down stack and right stack, and their
+top elements are maintained in the variables \\{down\_ptr} and \\{right\_ptr}.
+
+Each entry in these stacks contains four fields: The \\{width} field is
+the amount of motion down or to the right; the \\{location} field is the
+byte number of the \.{DVI} command in question (including the appropriate
+\\{dvi\_offset}); the \\{link} field points to the next item below this one
+on the stack; and the \\{info} field encodes the options for possible change
+in the \.{DVI} command.
+
+\Y\P\D \37$\\{movement\_node\_size}=3$\C{number of words per entry in the down
+and right stacks}\par
+\P\D \37$\\{location}(\#)\S\\{mem}[\#+2].\\{int}$\C{\.{DVI} byte number for a
+movement command}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4$\\{down\_ptr},\39\\{right\_ptr}$: \37\\{pointer};\C{heads of the down and
+right stacks}\par
+\fi
+
+\M617. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{down\_ptr}\K\\{null}$;\5
+$\\{right\_ptr}\K\\{null}$;\par
+\fi
+
+\M618. Here is a subroutine that produces a \.{DVI} command for some specified
+downward or rightward motion. It has two parameters: \|w is the amount
+of motion, and \|o is either \\{down1} or \\{right1}. We use the fact that
+the command codes have convenient arithmetic properties: $\\{y1}-\\{down1}=%
+\\{w1}-\\{right1}$
+and $\\{z1}-\\{down1}=\\{x1}-\\{right1}$.
+
+\Y\P\4\&{procedure}\1\  \37$\\{movement}(\|w:\\{scaled};\,\35\|o:\\{eight%
+\_bits})$;\6
+\4\&{label} \37$\\{exit},\39\\{found},\39\\{not\_found},\392,\391$;\6
+\4\&{var} \37\\{mstate}: \37\\{small\_number};\C{have we seen a \|y or \|z?}\6
+$\|p,\39\|q$: \37\\{pointer};\C{current and top nodes on the stack}\6
+\|k: \37\\{integer};\C{index into \\{dvi\_buf}, modulo \\{dvi\_buf\_size}}\2\6
+\&{begin} \37$\|q\K\\{get\_node}(\\{movement\_node\_size})$;\C{new node for the
+top of the stack}\6
+$\\{width}(\|q)\K\|w$;\5
+$\\{location}(\|q)\K\\{dvi\_offset}+\\{dvi\_ptr}$;\6
+\&{if} $\|o=\\{down1}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|q)\K\\{down\_ptr}$;\5
+$\\{down\_ptr}\K\|q$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{link}(\|q)\K\\{right\_ptr}$;\5
+$\\{right\_ptr}\K\|q$;\6
+\&{end};\2\6
+\X622:Look at the other stack entries until deciding what sort of \.{DVI}
+command to generate; \&{goto} \\{found} if node \|p is a ``hit''\X;\6
+\X621:Generate a \\{down} or \\{right} command for \|w and \&{return}\X;\6
+\4\\{found}: \37\X620:Generate a \\{y0} or \\{z0} command in order to reuse a
+previous appearance of~\|w\X;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M619. The \\{info} fields in the entries of the down stack or the right stack
+have six possible settings: \\{y\_here} or \\{z\_here} mean that the \.{DVI}
+command refers to \|y or \|z, respectively (or to \|w or \|x, in the
+case of horizontal motion); \\{yz\_OK} means that the \.{DVI} command is
+\\{down} (or \\{right}) but can be changed to either \|y or \|z (or
+to either \|w or \|x); \\{y\_OK} means that it is \\{down} and can be changed
+to \|y but not \|z; \\{z\_OK} is similar; and \\{d\_fixed} means it must stay
+\\{down}.
+
+The four settings \\{yz\_OK}, \\{y\_OK}, \\{z\_OK}, \\{d\_fixed} would not need
+to
+be distinguished from each other if we were simply solving the
+digit-subscripting problem mentioned above. But in \TeX's case there is
+a complication because of the nested structure of \\{push} and \\{pop}
+commands. Suppose we add parentheses to the digit-subscripting problem,
+redefining hits so that $\delta_y\ldots \delta_y$ is a hit if all $y$'s between
+the $\delta$'s are enclosed in properly nested parentheses, and if the
+parenthesis level of the right-hand $\delta_y$ is deeper than or equal to
+that of the left-hand one. Thus, `(' and `)' correspond to `\\{push}'
+and `\\{pop}'. Now if we want to assign a subscript to the final 1 in the
+sequence
+$$2_y\,7_d\,1_d\,(\,8_z\,2_y\,8_z\,)\,1$$
+we cannot change the previous $1_d$ to $1_y$, since that would invalidate
+the $2_y\ldots2_y$ hit. But we can change it to $1_z$, scoring a hit
+since the intervening $8_z$'s are enclosed in parentheses.
+
+The program below removes movement nodes that are introduced after a \\{push},
+before it outputs the corresponding \\{pop}.
+
+\Y\P\D \37$\\{y\_here}=1$\C{\\{info} when the movement entry points to a \|y
+command}\par
+\P\D \37$\\{z\_here}=2$\C{\\{info} when the movement entry points to a \|z
+command}\par
+\P\D \37$\\{yz\_OK}=3$\C{\\{info} corresponding to an unconstrained \\{down}
+command}\par
+\P\D \37$\\{y\_OK}=4$\C{\\{info} corresponding to a \\{down} that can't become
+a \|z}\par
+\P\D \37$\\{z\_OK}=5$\C{\\{info} corresponding to a \\{down} that can't become
+a \|y}\par
+\P\D \37$\\{d\_fixed}=6$\C{\\{info} corresponding to a \\{down} that can't
+change}\par
+\fi
+
+\M620. When the \\{movement} procedure gets to the label \\{found}, the value
+of
+$\\{info}(\|p)$ will be either \\{y\_here} or \\{z\_here}. If it is, say, \\{y%
+\_here},
+the procedure generates a \\{y0} command (or a \\{w0} command), and marks
+all \\{info} fields between \|q and \|p so that \|y is not OK in that range.
+
+\Y\P$\4\X620:Generate a \\{y0} or \\{z0} command in order to reuse a previous
+appearance of~\|w\X\S$\6
+$\\{info}(\|q)\K\\{info}(\|p)$;\6
+\&{if} $\\{info}(\|q)=\\{y\_here}$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_out}(\|o+\\{y0}-\\{down1})$;\C{\\{y0} or \\{w0}}\6
+\&{while} $\\{link}(\|q)\I\|p$ \1\&{do}\6
+\&{begin} \37$\|q\K\\{link}(\|q)$;\6
+\&{case} $\\{info}(\|q)$ \1\&{of}\6
+\4\\{yz\_OK}: \37$\\{info}(\|q)\K\\{z\_OK}$;\6
+\4\\{y\_OK}: \37$\\{info}(\|q)\K\\{d\_fixed}$;\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{dvi\_out}(\|o+\\{z0}-\\{down1})$;\C{\\{z0} or %
+\\{x0}}\6
+\&{while} $\\{link}(\|q)\I\|p$ \1\&{do}\6
+\&{begin} \37$\|q\K\\{link}(\|q)$;\6
+\&{case} $\\{info}(\|q)$ \1\&{of}\6
+\4\\{yz\_OK}: \37$\\{info}(\|q)\K\\{y\_OK}$;\6
+\4\\{z\_OK}: \37$\\{info}(\|q)\K\\{d\_fixed}$;\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\6
+\&{end};\2\6
+\&{end}\2\par
+\U618.\fi
+
+\M621. \P$\X621:Generate a \\{down} or \\{right} command for \|w and \&{return}%
+\X\S$\6
+$\\{info}(\|q)\K\\{yz\_OK}$;\6
+\&{if} $\\{abs}(\|w)\G\O{40000000}$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_out}(\|o+3)$;\C{\\{down4} or \\{right4}}\6
+$\\{dvi\_four}(\|w)$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $\\{abs}(\|w)\G\O{100000}$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_out}(\|o+2)$;\C{\\{down3} or \\{right3}}\6
+\&{if} $\|w<0$ \1\&{then}\5
+$\|w\K\|w+\O{100000000}$;\2\6
+$\\{dvi\_out}(\|w\mathbin{\&{div}}\O{200000})$;\5
+$\|w\K\|w\mathbin{\&{mod}}\O{200000}$;\5
+\&{goto} \372;\6
+\&{end};\2\6
+\&{if} $\\{abs}(\|w)\G\O{200}$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_out}(\|o+1)$;\C{\\{down2} or \\{right2}}\6
+\&{if} $\|w<0$ \1\&{then}\5
+$\|w\K\|w+\O{200000}$;\2\6
+\&{goto} \372;\6
+\&{end};\2\6
+$\\{dvi\_out}(\|o)$;\C{\\{down1} or \\{right1}}\6
+\&{if} $\|w<0$ \1\&{then}\5
+$\|w\K\|w+\O{400}$;\2\6
+\&{goto} \371;\6
+\42: \37$\\{dvi\_out}(\|w\mathbin{\&{div}}\O{400})$;\6
+\41: \37$\\{dvi\_out}(\|w\mathbin{\&{mod}}\O{400})$;\5
+\&{return}\par
+\U618.\fi
+
+\M622. As we search through the stack, we are in one of three states,
+\\{y\_seen}, \\{z\_seen}, or \\{none\_seen}, depending on whether we have
+encountered \\{y\_here} or \\{z\_here} nodes. These states are encoded as
+multiples of 6, so that they can be added to the \\{info} fields for quick
+decision-making.
+
+\Y\P\D \37$\\{none\_seen}=0$\C{no \\{y\_here} or \\{z\_here} nodes have been
+encountered yet}\par
+\P\D \37$\\{y\_seen}=6$\C{we have seen \\{y\_here} but not \\{z\_here}}\par
+\P\D \37$\\{z\_seen}=12$\C{we have seen \\{z\_here} but not \\{y\_here}}\par
+\Y\P$\4\X622:Look at the other stack entries until deciding what sort of %
+\.{DVI} command to generate; \&{goto} \\{found} if node \|p is a ``hit''\X\S$\6
+$\|p\K\\{link}(\|q)$;\5
+$\\{mstate}\K\\{none\_seen}$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{width}(\|p)=\|w$ \1\&{then}\5
+\X623:Consider a node with matching width; \&{goto} \\{found} if it's a hit\X\6
+\4\&{else} \&{case} $\\{mstate}+\\{info}(\|p)$ \1\&{of}\6
+\4$\\{none\_seen}+\\{y\_here}$: \37$\\{mstate}\K\\{y\_seen}$;\6
+\4$\\{none\_seen}+\\{z\_here}$: \37$\\{mstate}\K\\{z\_seen}$;\6
+\4$\\{y\_seen}+\\{z\_here},\39\\{z\_seen}+\\{y\_here}$: \37\&{goto} \37\\{not%
+\_found};\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\2\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\4\\{not\_found}: \37\par
+\U618.\fi
+
+\M623. We might find a valid hit in a \|y or \|z byte that is already gone
+from the buffer. But we can't change bytes that are gone forever; ``the
+moving finger writes, $\ldots\,\,$.''
+
+\Y\P$\4\X623:Consider a node with matching width; \&{goto} \\{found} if it's a
+hit\X\S$\6
+\&{case} $\\{mstate}+\\{info}(\|p)$ \1\&{of}\6
+\4$\\{none\_seen}+\\{yz\_OK},\39\\{none\_seen}+\\{y\_OK},\39\\{z\_seen}+\\{yz%
+\_OK},\39\\{z\_seen}+\\{y\_OK}$: \37\hbox{}\6
+\&{if} $\\{location}(\|p)<\\{dvi\_gone}$ \1\&{then}\5
+\&{goto} \37\\{not\_found}\6
+\4\&{else} \X624:Change buffered instruction to \|y or \|w and \&{goto} %
+\\{found}\X;\2\6
+\4$\\{none\_seen}+\\{z\_OK},\39\\{y\_seen}+\\{yz\_OK},\39\\{y\_seen}+\\{z%
+\_OK}$: \37\hbox{}\6
+\&{if} $\\{location}(\|p)<\\{dvi\_gone}$ \1\&{then}\5
+\&{goto} \37\\{not\_found}\6
+\4\&{else} \X625:Change buffered instruction to \|z or \|x and \&{goto} %
+\\{found}\X;\2\6
+\4$\\{none\_seen}+\\{y\_here},\39\\{none\_seen}+\\{z\_here},\39\\{y\_seen}+\\{z%
+\_here},\39\\{z\_seen}+\\{y\_here}$: \37\&{goto} \37\\{found};\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases}\par
+\U622.\fi
+
+\M624. \P$\X624:Change buffered instruction to \|y or \|w and \&{goto} %
+\\{found}\X\S$\6
+\&{begin} \37$\|k\K\\{location}(\|p)-\\{dvi\_offset}$;\6
+\&{if} $\|k<0$ \1\&{then}\5
+$\|k\K\|k+\\{dvi\_buf\_size}$;\2\6
+$\\{dvi\_buf}[\|k]\K\\{dvi\_buf}[\|k]+\\{y1}-\\{down1}$;\5
+$\\{info}(\|p)\K\\{y\_here}$;\5
+\&{goto} \37\\{found};\6
+\&{end}\par
+\U623.\fi
+
+\M625. \P$\X625:Change buffered instruction to \|z or \|x and \&{goto} %
+\\{found}\X\S$\6
+\&{begin} \37$\|k\K\\{location}(\|p)-\\{dvi\_offset}$;\6
+\&{if} $\|k<0$ \1\&{then}\5
+$\|k\K\|k+\\{dvi\_buf\_size}$;\2\6
+$\\{dvi\_buf}[\|k]\K\\{dvi\_buf}[\|k]+\\{z1}-\\{down1}$;\5
+$\\{info}(\|p)\K\\{z\_here}$;\5
+\&{goto} \37\\{found};\6
+\&{end}\par
+\U623.\fi
+
+\M626. In case you are wondering when all the movement nodes are removed from
+\TeX's memory, the answer is that they are recycled just before
+\\{hlist\_out} and \\{vlist\_out} finish outputting a box. This restores the
+down and right stacks to the state they were in before the box was output,
+except that some \\{info}'s may have become more restrictive.
+
+\Y\P\4\&{procedure}\1\  \37$\\{prune\_movements}(\|l:\\{integer})$;\C{delete
+movement nodes with $\\{location}\G\|l$}\6
+\4\&{label} \37$\\{done},\39\\{exit}$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{node being deleted}\2\6
+\&{begin} \37\&{while} $\\{down\_ptr}\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{location}(\\{down\_ptr})<\|l$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\|p\K\\{down\_ptr}$;\5
+$\\{down\_ptr}\K\\{link}(\|p)$;\5
+$\\{free\_node}(\|p,\39\\{movement\_node\_size})$;\6
+\&{end};\2\6
+\4\\{done}: \37\&{while} $\\{right\_ptr}\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{location}(\\{right\_ptr})<\|l$ \1\&{then}\5
+\&{return};\2\6
+$\|p\K\\{right\_ptr}$;\5
+$\\{right\_ptr}\K\\{link}(\|p)$;\5
+$\\{free\_node}(\|p,\39\\{movement\_node\_size})$;\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M627. The actual distances by which we want to move might be computed as the
+sum of several separate movements. For example, there might be several
+glue nodes in succession, or we might want to move right by the width of
+some box plus some amount of glue. More importantly, the baselineskip
+distances are computed in terms of glue together with the depth and
+height of adjacent boxes, and we want the \.{DVI} file to lump these
+three quantities together into a single motion.
+
+Therefore, \TeX\ maintains two pairs of global variables: \\{dvi\_h} and \\{dvi%
+\_v}
+are the \|h and \|v coordinates corresponding to the commands actually
+output to the \.{DVI} file, while \\{cur\_h} and \\{cur\_v} are the coordinates
+corresponding to the current state of the output routines. Coordinate
+changes will accumulate in \\{cur\_h} and \\{cur\_v} without being reflected
+in the output, until such a change becomes necessary or desirable; we
+can call the \\{movement} procedure whenever we want to make $\\{dvi\_h}=\\{cur%
+\_h}$
+or $\\{dvi\_v}=\\{cur\_v}$.
+
+The current font reflected in the \.{DVI} output is called \\{dvi\_f};
+there is no need for a `\\{cur\_f}' variable.
+
+The depth of nesting of \\{hlist\_out} and \\{vlist\_out} is called \\{cur\_s};
+this is essentially the depth of \\{push} commands in the \.{DVI} output.
+
+\Y\P\D \37$\\{synch\_h}\S$\1\6
+\&{if} $\\{cur\_h}\I\\{dvi\_h}$ \1\&{then}\6
+\&{begin} \37$\\{movement}(\\{cur\_h}-\\{dvi\_h},\39\\{right1})$;\5
+$\\{dvi\_h}\K\\{cur\_h}$;\6
+\&{end}\2\2\par
+\P\D \37$\\{synch\_v}\S$\1\6
+\&{if} $\\{cur\_v}\I\\{dvi\_v}$ \1\&{then}\6
+\&{begin} \37$\\{movement}(\\{cur\_v}-\\{dvi\_v},\39\\{down1})$;\5
+$\\{dvi\_v}\K\\{cur\_v}$;\6
+\&{end}\2\2\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4$\\{dvi\_h},\39\\{dvi\_v}$: \37\\{scaled};\C{a \.{DVI} reader program thinks
+we are here}\6
+\4$\\{cur\_h},\39\\{cur\_v}$: \37\\{scaled};\C{\TeX\ thinks we are here}\6
+\4\\{dvi\_f}: \37\\{internal\_font\_number};\C{the current font}\6
+\4\\{cur\_s}: \37\\{integer};\C{current depth of output box nesting, initially
+$-1$}\par
+\fi
+
+\M628. \P$\X628:Initialize variables as \\{ship\_out} begins\X\S$\6
+$\\{dvi\_h}\K0$;\5
+$\\{dvi\_v}\K0$;\5
+$\\{cur\_h}\K\\{h\_offset}$;\5
+$\\{dvi\_f}\K\\{null\_font}$;\5
+$\\{dvi\_dir}\K\\{dir\_yoko}$;\5
+$\\{cur\_dir\_hv}\K\\{dvi\_dir}$;\5
+\\{ensure\_dvi\_open};\6
+\&{if} $\\{total\_pages}=0$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_out}(\\{pre})$;\5
+$\\{dvi\_out}(\\{id\_byte})$;\C{output the preamble}\6
+$\\{dvi\_four}(25400000)$;\5
+$\\{dvi\_four}(473628672)$;\C{conversion ratio for sp}\6
+\\{prepare\_mag};\5
+$\\{dvi\_four}(\\{mag})$;\C{magnification factor is frozen}\6
+\&{if} $\\{output\_comment}$ \1\&{then}\6
+\&{begin} \37$\|l\K\\{strlen}(\\{output\_comment})$;\5
+$\\{dvi\_out}(\|l)$;\6
+\&{for} $\|s\K0\mathrel{\&{to}}\|l-1$ \1\&{do}\5
+$\\{dvi\_out}(\\{output\_comment}[\|s])$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\C{the default code is unchanged}\6
+$\\{old\_setting}\K\\{selector}$;\5
+$\\{selector}\K\\{new\_string}$;\5
+$\\{print}(\.{"\ TeX\ output\ "})$;\5
+$\\{print\_int}(\\{year})$;\5
+$\\{print\_char}(\.{"."})$;\5
+$\\{print\_two}(\\{month})$;\5
+$\\{print\_char}(\.{"."})$;\5
+$\\{print\_two}(\\{day})$;\5
+$\\{print\_char}(\.{":"})$;\5
+$\\{print\_two}(\\{time}\mathbin{\&{div}}60)$;\5
+$\\{print\_two}(\\{time}\mathbin{\&{mod}}60)$;\5
+$\\{selector}\K\\{old\_setting}$;\5
+$\\{dvi\_out}(\\{cur\_length})$;\6
+\&{for} $\|s\K\\{str\_start}[\\{str\_ptr}]\mathrel{\&{to}}\\{pool\_ptr}-1$ \1%
+\&{do}\5
+$\\{dvi\_out}(\\{so}(\\{str\_pool}[\|s]))$;\2\6
+$\\{pool\_ptr}\K\\{str\_start}[\\{str\_ptr}]$;\C{flush the current string}\6
+\&{end};\2\6
+\&{end}\2\par
+\U651.\fi
+
+\M629. When \\{hlist\_out} is called, its duty is to output the box represented
+by the \\{hlist\_node} pointed to by \\{temp\_ptr}. The reference point of that
+box has coordinates $(\\{cur\_h},\\{cur\_v})$.
+
+Similarly, when \\{vlist\_out} is called, its duty is to output the box
+represented
+by the \\{vlist\_node} pointed to by \\{temp\_ptr}. The reference point of that
+box has coordinates $(\\{cur\_h},\\{cur\_v})$.
+
+\Y\P\4\&{procedure}\1\  \37\\{vlist\_out};\5
+\\{forward};\C{\\{hlist\_out} and \\{vlist\_out} are mutually   recursive}\par
+\fi
+
+\M630. The recursive procedures \\{hlist\_out} and \\{vlist\_out} each have
+local variables
+\\{save\_h} and \\{save\_v} to hold the values of \\{dvi\_h} and \\{dvi\_v}
+just before
+entering a new level of recursion.  In effect, the values of \\{save\_h} and
+\\{save\_v} on \TeX's run-time stack correspond to the values of \|h and \|v
+that a \.{DVI}-reading program will push onto its coordinate stack.
+
+\Y\P\D \37$\\{move\_past}=13$\C{go to this label when advancing past glue or a
+rule}\par
+\P\D \37$\\{fin\_rule}=14$\C{go to this label to finish processing a rule}\par
+\P\D \37$\\{next\_p}=15$\C{go to this label when finished with node \|p}\par
+\Y\P\hbox{\4}\X1381:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}%
+\X\hbox{}\6
+\4\&{procedure}\1\  \37\\{hlist\_out};\C{output an \\{hlist\_node} box}\6
+\4\&{label} \37$\\{reswitch},\39\\{move\_past},\39\\{fin\_rule},\39\\{next\_p},%
+\39\\{continue},\39\\{found}$;\6
+\4\&{var} \37\\{base\_line}: \37\\{scaled};\C{the baseline coordinate for this
+box}\6
+\\{disp}: \37\\{scaled};\C{displacement}\6
+\\{save\_dir}: \37\\{eight\_bits};\C{what \\{dvi\_dir} should pop to}\6
+\\{jc}: \37\\{KANJI\_code};\C{temporary register for KANJI codes}\6
+\\{ksp\_ptr}: \37\\{pointer};\C{position of \\{auto\_spacing\_glue} in the
+hlist}\6
+\\{left\_edge}: \37\\{scaled};\C{the left coordinate for this box}\6
+$\\{save\_h},\39\\{save\_v}$: \37\\{scaled};\C{what \\{dvi\_h} and \\{dvi\_v}
+should pop to}\6
+\\{this\_box}: \37\\{pointer};\C{pointer to containing box}\6
+\\{g\_order}: \37\\{glue\_ord};\C{applicable order of infinity for glue}\6
+\\{g\_sign}: \37$\\{normal}\to\\{shrinking}$;\C{selects type of glue}\6
+\|p: \37\\{pointer};\C{current position in the hlist}\6
+\\{save\_loc}: \37\\{integer};\C{\.{DVI} byte location upon entry}\6
+\\{leader\_box}: \37\\{pointer};\C{the leader box being replicated}\6
+\\{leader\_wd}: \37\\{scaled};\C{width of leader box being replicated}\6
+\\{lx}: \37\\{scaled};\C{extra space between leader boxes}\6
+\\{outer\_doing\_leaders}: \37\\{boolean};\C{were we doing leaders?}\6
+\\{edge}: \37\\{scaled};\C{left edge of sub-box, or right edge of leader space}%
+\6
+\\{glue\_temp}: \37\\{real};\C{glue value before rounding}\6
+\\{cur\_glue}: \37\\{real};\C{glue seen so far}\6
+\\{cur\_g}: \37\\{scaled};\C{rounded equivalent of \\{cur\_glue} times the glue
+ratio}\2\6
+\&{begin} \37$\\{cur\_g}\K0$;\5
+$\\{cur\_glue}\K\\{float\_constant}(0)$;\5
+$\\{this\_box}\K\\{temp\_ptr}$;\5
+$\\{g\_order}\K\\{glue\_order}(\\{this\_box})$;\5
+$\\{g\_sign}\K\\{glue\_sign}(\\{this\_box})$;\5
+$\|p\K\\{list\_ptr}(\\{this\_box})$;\5
+$\\{ksp\_ptr}\K\\{space\_ptr}(\\{this\_box})$;\5
+$\\{incr}(\\{cur\_s})$;\6
+\&{if} $\\{cur\_s}>0$ \1\&{then}\5
+$\\{dvi\_out}(\\{push})$;\2\6
+\&{if} $\\{cur\_s}>\\{max\_push}$ \1\&{then}\5
+$\\{max\_push}\K\\{cur\_s}$;\2\6
+$\\{save\_loc}\K\\{dvi\_offset}+\\{dvi\_ptr}$;\5
+\\{synch\_dir};\5
+$\\{base\_line}\K\\{cur\_v}$;\5
+$\\{left\_edge}\K\\{cur\_h}$;\5
+$\\{disp}\K0$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\5
+\X631:Output node \|p for \\{hlist\_out} and move to the next node, maintaining
+the condition $\\{cur\_v}=\\{base\_line}$\X;\2\6
+$\\{prune\_movements}(\\{save\_loc})$;\6
+\&{if} $\\{cur\_s}>0$ \1\&{then}\5
+$\\{dvi\_pop}(\\{save\_loc})$;\2\6
+$\\{decr}(\\{cur\_s})$;\6
+\&{end};\par
+\fi
+
+\M631. We ought to give special care to the efficiency of one part of \\{hlist%
+\_out},
+since it belongs to \TeX's inner loop. When a \\{char\_node} is encountered,
+we save a little time by processing several nodes in succession until
+reaching a non-\\{char\_node}. The program uses the fact that $\\{set\_char%
+\_0}=0$.
+
+In ML\TeX{} this part looks for the existence of a substitution
+definition for a character \|c, if \|c does not exist in the font,
+and create appropriate \.{DVI} commands.  Former versions of ML\TeX{}
+have spliced appropriate character, kern, and box nodes into the
+horizontal list.
+%
+% 91/05/08 \charsubdefmax bug detected by Bernd Raichle
+Because the user can change character substitions or
+\.{\\charsubdefmax} on the fly, we have to test a again
+for valid substitutions.
+%
+% 93/10/29 \leaders bug detected by Eberhard Mattes
+(Additional it is necessary to be careful---if leaders are used
+the current hlist is normally traversed more than once!)
+
+\Y\P$\4\X631:Output node \|p for \\{hlist\_out} and move to the next node,
+maintaining the condition $\\{cur\_v}=\\{base\_line}$\X\S$\6
+\4\\{reswitch}: \37\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{begin} \37\\{synch\_h};\5
+\\{synch\_v};\5
+$\\{chain}\K\\{false}$;\6
+\1\&{repeat} \37$\|f\K\\{font}(\|p)$;\5
+$\|c\K\\{character}(\|p)$;\6
+\&{if} $\|f\I\\{dvi\_f}$ \1\&{then}\5
+\X632:Change font \\{dvi\_f} to \|f\X;\2\6
+\&{if} $\\{font\_dir}[\|f]=\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\\{chain}\K\\{false}$;\6
+\&{if} $\\{font\_ec}[\|f]\G\\{qo}(\|c)$ \1\&{then}\6
+\&{if} $\\{font\_bc}[\|f]\L\\{qo}(\|c)$ \1\&{then}\6
+\&{if} $\\{char\_exists}(\\{orig\_char\_info}(\|f)(\|c))$ \1\&{then}\C{N.B.:
+not \\{char\_info}}\6
+\&{begin} \37\&{if} $\|c\G\\{qi}(128)$ \1\&{then}\5
+$\\{dvi\_out}(\\{set1})$;\2\6
+$\\{dvi\_out}(\\{qo}(\|c))$;\6
+$\\{cur\_h}\K\\{cur\_h}+\\{char\_width}(\|f)(\\{orig\_char\_info}(\|f)(\|c))$;\5
+\&{goto} \37\\{continue};\6
+\&{end};\2\2\2\6
+\&{if} $\\{mltex\_enabled\_p}$ \1\&{then}\5
+\X1409:Output a substitution, \&{goto} \\{continue} if not possible\X;\2\6
+\4\\{continue}: \37\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{chain}=\\{false}$ \1\&{then}\5
+$\\{chain}\K\\{true}$\6
+\4\&{else} \&{begin} \37$\\{cur\_h}\K\\{cur\_h}+\\{width}(\\{ksp\_ptr})$;\6
+\&{if} $\\{g\_sign}\I\\{normal}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{g\_sign}=\\{stretching}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{stretch\_order}(\\{ksp\_ptr})=\\{g\_order}$ \1\&{then}\5
+$\\{cur\_h}\K\\{cur\_h}+\\{round}(\\{float}(\\{glue\_set}(\\{this\_box}))\ast%
+\\{stretch}(\\{ksp\_ptr}))$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{shrink\_order}(\\{ksp\_ptr})=\\{g\_order}$ %
+\1\&{then}\5
+$\\{cur\_h}\K\\{cur\_h}-\\{round}(\\{float}(\\{glue\_set}(\\{this\_box}))\ast%
+\\{shrink}(\\{ksp\_ptr}))$;\2\6
+\&{end};\2\6
+\&{end};\2\6
+\\{synch\_h};\6
+\&{end};\2\6
+$\|p\K\\{link}(\|p)$;\5
+$\\{jc}\K\\{toDVI}(\\{KANJI}(\\{info}(\|p)))$;\5
+$\\{dvi\_out}(\\{set2})$;\5
+$\\{dvi\_out}(\\{Hi}(\\{jc}))$;\5
+$\\{dvi\_out}(\\{Lo}(\\{jc}))$;\5
+$\\{cur\_h}\K\\{cur\_h}+\\{char\_width}(\|f)(\\{orig\_char\_info}(\|f)(\|c))$;%
+\C{not \\{jc}}\6
+\&{end};\2\6
+$\\{dvi\_h}\K\\{cur\_h}$;\5
+$\|p\K\\{link}(\|p)$;\6
+\4\&{until}\5
+$\R\\{is\_char\_node}(\|p)$;\2\6
+$\\{chain}\K\\{false}$;\6
+\&{end}\6
+\4\&{else} \X633:Output the non-\\{char\_node} \|p for \\{hlist\_out} and move
+to the next node\X\2\par
+\U630.\fi
+
+\M632. \P$\X632:Change font \\{dvi\_f} to \|f\X\S$\6
+\&{begin} \37\&{if} $\R\\{font\_used}[\|f]$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_font\_def}(\|f)$;\5
+$\\{font\_used}[\|f]\K\\{true}$;\6
+\&{end};\2\6
+\&{if} $\|f\L64+\\{font\_base}$ \1\&{then}\5
+$\\{dvi\_out}(\|f-\\{font\_base}-1+\\{fnt\_num\_0})$\6
+\4\&{else} \&{if} $\|f\L256+\\{font\_base}$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_out}(\\{fnt1})$;\5
+$\\{dvi\_out}(\|f-\\{font\_base}-1)$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{dvi\_out}(\\{fnt1}+1)$;\5
+$\\{dvi\_out}((\|f-\\{font\_base}-1)\mathbin{\&{div}}\O{400})$;\5
+$\\{dvi\_out}((\|f-\\{font\_base}-1)\mathbin{\&{mod}}\O{400})$;\6
+\&{end};\2\2\6
+$\\{dvi\_f}\K\|f$;\6
+\&{end}\par
+\U631.\fi
+
+\M633. \P$\X633:Output the non-\\{char\_node} \|p for \\{hlist\_out} and move
+to the next node\X\S$\6
+\&{begin} \37\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node}$: \37\X634:Output a box
+in an hlist\X;\6
+\4\\{rule\_node}: \37\&{begin} \37$\\{rule\_ht}\K\\{height}(\|p)$;\5
+$\\{rule\_dp}\K\\{depth}(\|p)$;\5
+$\\{rule\_wd}\K\\{width}(\|p)$;\5
+\&{goto} \37\\{fin\_rule};\6
+\&{end};\6
+\4\\{whatsit\_node}: \37\X1380:Output the whatsit node \|p in an hlist\X;\6
+\4\\{disp\_node}: \37\&{begin} \37$\\{disp}\K\\{disp\_dimen}(\|p)$;\5
+$\\{cur\_v}\K\\{base\_line}+\\{disp}$;\6
+\&{end};\6
+\4\\{glue\_node}: \37\X636:Move right or output leaders\X;\6
+\4$\\{kern\_node},\39\\{math\_node}$: \37$\\{cur\_h}\K\\{cur\_h}+\\{width}(%
+\|p)$;\6
+\4\\{ligature\_node}: \37\X663:Make node \|p look like a \\{char\_node} and %
+\&{goto} \\{reswitch}\X;\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\6
+\&{goto} \37\\{next\_p};\6
+\4\\{fin\_rule}: \37\X635:Output a rule in an hlist\X;\6
+\4\\{move\_past}: \37$\\{cur\_h}\K\\{cur\_h}+\\{rule\_wd}$;\6
+\4\\{next\_p}: \37$\|p\K\\{link}(\|p)$;\6
+\&{end}\par
+\U631.\fi
+
+\M634. \P$\X634:Output a box in an hlist\X\S$\6
+\&{if} $\\{list\_ptr}(\|p)=\\{null}$ \1\&{then}\5
+$\\{cur\_h}\K\\{cur\_h}+\\{width}(\|p)$\6
+\4\&{else} \&{begin} \37$\\{save\_h}\K\\{dvi\_h}$;\5
+$\\{save\_v}\K\\{dvi\_v}$;\5
+$\\{save\_dir}\K\\{dvi\_dir}$;\5
+$\\{cur\_v}\K\\{base\_line}+\\{disp}+\\{shift\_amount}(\|p)$;\C{shift the box
+down}\6
+$\\{temp\_ptr}\K\|p$;\5
+$\\{edge}\K\\{cur\_h}$;\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4\\{hlist\_node}: \37\\{hlist\_out};\6
+\4\\{vlist\_node}: \37\\{vlist\_out};\6
+\4\\{dir\_node}: \37\\{dir\_out};\2\6
+\&{endcases};\5
+$\\{dvi\_h}\K\\{save\_h}$;\5
+$\\{dvi\_v}\K\\{save\_v}$;\5
+$\\{dvi\_dir}\K\\{save\_dir}$;\5
+$\\{cur\_h}\K\\{edge}+\\{width}(\|p)$;\5
+$\\{cur\_v}\K\\{base\_line}+\\{disp}$;\5
+$\\{cur\_dir\_hv}\K\\{save\_dir}$;\6
+\&{end}\2\par
+\U633.\fi
+
+\M635. \P$\X635:Output a rule in an hlist\X\S$\6
+\&{if} $\\{is\_running}(\\{rule\_ht})$ \1\&{then}\5
+$\\{rule\_ht}\K\\{height}(\\{this\_box})+\\{disp}$;\2\6
+\&{if} $\\{is\_running}(\\{rule\_dp})$ \1\&{then}\5
+$\\{rule\_dp}\K\\{depth}(\\{this\_box})-\\{disp}$;\2\6
+$\\{rule\_ht}\K\\{rule\_ht}+\\{rule\_dp}$;\C{this is the rule thickness}\6
+\&{if} $(\\{rule\_ht}>0)\W(\\{rule\_wd}>0)$ \1\&{then}\C{we don't output empty
+rules}\6
+\&{begin} \37\\{synch\_h};\5
+$\\{cur\_v}\K\\{base\_line}+\\{rule\_dp}$;\5
+\\{synch\_v};\5
+$\\{dvi\_out}(\\{set\_rule})$;\5
+$\\{dvi\_four}(\\{rule\_ht})$;\5
+$\\{dvi\_four}(\\{rule\_wd})$;\5
+$\\{cur\_v}\K\\{base\_line}$;\5
+$\\{dvi\_h}\K\\{dvi\_h}+\\{rule\_wd}$;\6
+\&{end}\2\par
+\U633.\fi
+
+\M636. \P\D \37$\\{billion}\S\\{float\_constant}(1000000000)$\par
+\P\D \37$\\{vet\_glue}(\#)\S\\{glue\_temp}\K\#$;\6
+\&{if} $\\{glue\_temp}>\\{billion}$ \1\&{then}\5
+$\\{glue\_temp}\K\\{billion}$\6
+\4\&{else} \&{if} $\\{glue\_temp}<-\\{billion}$ \1\&{then}\5
+$\\{glue\_temp}\K-\\{billion}$\2\2\par
+\Y\P$\4\X636:Move right or output leaders\X\S$\6
+\&{begin} \37$\|g\K\\{glue\_ptr}(\|p)$;\5
+$\\{rule\_wd}\K\\{width}(\|g)-\\{cur\_g}$;\6
+\&{if} $\\{g\_sign}\I\\{normal}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{g\_sign}=\\{stretching}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{stretch\_order}(\|g)=\\{g\_order}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_glue}\K\\{cur\_glue}+\\{stretch}(\|g)$;\5
+$\\{vet\_glue}(\\{float}(\\{glue\_set}(\\{this\_box}))\ast\\{cur\_glue})$;\5
+$\\{cur\_g}\K\\{round}(\\{glue\_temp})$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{shrink\_order}(\|g)=\\{g\_order}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_glue}\K\\{cur\_glue}-\\{shrink}(\|g)$;\5
+$\\{vet\_glue}(\\{float}(\\{glue\_set}(\\{this\_box}))\ast\\{cur\_glue})$;\5
+$\\{cur\_g}\K\\{round}(\\{glue\_temp})$;\6
+\&{end};\2\2\6
+\&{end};\2\6
+$\\{rule\_wd}\K\\{rule\_wd}+\\{cur\_g}$;\6
+\&{if} $\\{subtype}(\|p)\G\\{a\_leaders}$ \1\&{then}\5
+\X637:Output leaders in an hlist, \&{goto} \\{fin\_rule} if a rule or to %
+\\{next\_p} if done\X;\2\6
+\&{goto} \37\\{move\_past};\6
+\&{end}\par
+\U633.\fi
+
+\M637. \P$\X637:Output leaders in an hlist, \&{goto} \\{fin\_rule} if a rule or
+to \\{next\_p} if done\X\S$\6
+\&{begin} \37$\\{leader\_box}\K\\{leader\_ptr}(\|p)$;\6
+\&{if} $\\{type}(\\{leader\_box})=\\{rule\_node}$ \1\&{then}\6
+\&{begin} \37$\\{rule\_ht}\K\\{height}(\\{leader\_box})$;\5
+$\\{rule\_dp}\K\\{depth}(\\{leader\_box})$;\5
+\&{goto} \37\\{fin\_rule};\6
+\&{end};\2\6
+$\\{leader\_wd}\K\\{width}(\\{leader\_box})$;\6
+\&{if} $(\\{leader\_wd}>0)\W(\\{rule\_wd}>0)$ \1\&{then}\6
+\&{begin} \37$\\{rule\_wd}\K\\{rule\_wd}+10$;\C{compensate for floating-point
+rounding}\6
+$\\{edge}\K\\{cur\_h}+\\{rule\_wd}$;\5
+$\\{lx}\K0$;\5
+\X638:Let \\{cur\_h} be the position of the first box, and set $\\{leader\_wd}+%
+\\{lx}$ to the spacing between corresponding parts of boxes\X;\6
+\&{while} $\\{cur\_h}+\\{leader\_wd}\L\\{edge}$ \1\&{do}\5
+\X639:Output a leader box at \\{cur\_h}, then advance \\{cur\_h} by $\\{leader%
+\_wd}+\\{lx}$\X;\2\6
+$\\{cur\_h}\K\\{edge}-10$;\5
+\&{goto} \37\\{next\_p};\6
+\&{end};\2\6
+\&{end}\par
+\U636.\fi
+
+\M638. The calculations related to leaders require a bit of care. First, in the
+case of \\{a\_leaders} (aligned leaders), we want to move \\{cur\_h} to
+\\{left\_edge} plus the smallest multiple of \\{leader\_wd} for which the
+result
+is not less than the current value of \\{cur\_h}; i.e., \\{cur\_h} should
+become
+$\\{left\_edge}+\\{leader\_wd}\times\lceil
+(\\{cur\_h}-\\{left\_edge})/\\{leader\_wd}\rceil$.  The program here should
+work in
+all cases even though some implementations of \PASCAL\ give nonstandard
+results for the $\mathbin{\&{div}}$ operation when \\{cur\_h} is less than %
+\\{left\_edge}.
+
+In the case of \\{c\_leaders} (centered leaders), we want to increase \\{cur%
+\_h}
+by half of the excess space not occupied by the leaders; and in the
+case of \\{x\_leaders} (expanded leaders) we increase \\{cur\_h}
+by $1/(q+1)$ of this excess space, where $q$ is the number of times the
+leader box will be replicated. Slight inaccuracies in the division might
+accumulate; half of this rounding error is placed at each end of the leaders.
+
+\Y\P$\4\X638:Let \\{cur\_h} be the position of the first box, and set $%
+\\{leader\_wd}+\\{lx}$ to the spacing between corresponding parts of boxes\X\S$%
+\6
+\&{if} $\\{subtype}(\|p)=\\{a\_leaders}$ \1\&{then}\6
+\&{begin} \37$\\{save\_h}\K\\{cur\_h}$;\5
+$\\{cur\_h}\K\\{left\_edge}+\\{leader\_wd}\ast((\\{cur\_h}-\\{left\_edge})%
+\mathbin{\&{div}}\\{leader\_wd})$;\6
+\&{if} $\\{cur\_h}<\\{save\_h}$ \1\&{then}\5
+$\\{cur\_h}\K\\{cur\_h}+\\{leader\_wd}$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{lq}\K\\{rule\_wd}\mathbin{\&{div}}\\{leader\_wd}$;%
+\C{the number of box copies}\6
+$\\{lr}\K\\{rule\_wd}\mathbin{\&{mod}}\\{leader\_wd}$;\C{the remaining space}\6
+\&{if} $\\{subtype}(\|p)=\\{c\_leaders}$ \1\&{then}\5
+$\\{cur\_h}\K\\{cur\_h}+(\\{lr}\mathbin{\&{div}}2)$\6
+\4\&{else} \&{begin} \37$\\{lx}\K\\{lr}\mathbin{\&{div}}(\\{lq}+1)$;\5
+$\\{cur\_h}\K\\{cur\_h}+((\\{lr}-(\\{lq}-1)\ast\\{lx})\mathbin{\&{div}}2)$;\6
+\&{end};\2\6
+\&{end}\2\par
+\U637.\fi
+
+\M639. The `\\{synch}' operations here are intended to decrease the number of
+bytes needed to specify horizontal and vertical motion in the \.{DVI} output.
+
+\Y\P$\4\X639:Output a leader box at \\{cur\_h}, then advance \\{cur\_h} by $%
+\\{leader\_wd}+\\{lx}$\X\S$\6
+\&{begin} \37$\\{cur\_v}\K\\{base\_line}+\\{disp}+\\{shift\_amount}(\\{leader%
+\_box})$;\5
+\\{synch\_v};\5
+$\\{save\_v}\K\\{dvi\_v}$;\6
+\\{synch\_h};\5
+$\\{save\_h}\K\\{dvi\_h}$;\5
+$\\{save\_dir}\K\\{dvi\_dir}$;\5
+$\\{temp\_ptr}\K\\{leader\_box}$;\5
+$\\{outer\_doing\_leaders}\K\\{doing\_leaders}$;\5
+$\\{doing\_leaders}\K\\{true}$;\6
+\&{case} $\\{type}(\\{leader\_box})$ \1\&{of}\6
+\4\\{hlist\_node}: \37\\{hlist\_out};\6
+\4\\{vlist\_node}: \37\\{vlist\_out};\6
+\4\\{dir\_node}: \37\\{dir\_out};\2\6
+\&{endcases};\5
+$\\{doing\_leaders}\K\\{outer\_doing\_leaders}$;\5
+$\\{dvi\_v}\K\\{save\_v}$;\5
+$\\{dvi\_h}\K\\{save\_h}$;\5
+$\\{dvi\_dir}\K\\{save\_dir}$;\5
+$\\{cur\_v}\K\\{base\_line}$;\5
+$\\{cur\_h}\K\\{save\_h}+\\{leader\_wd}+\\{lx}$;\5
+$\\{cur\_dir\_hv}\K\\{save\_dir}$;\6
+\&{end}\par
+\U637.\fi
+
+\M640. The \\{vlist\_out} routine is similar to \\{hlist\_out}, but a bit
+simpler.
+
+\Y\P\4\&{procedure}\1\  \37\\{vlist\_out};\C{output a \\{vlist\_node} box}\6
+\4\&{label} \37$\\{move\_past},\39\\{fin\_rule},\39\\{next\_p}$;\6
+\4\&{var} \37\\{left\_edge}: \37\\{scaled};\C{the left coordinate for this box}%
+\6
+\\{top\_edge}: \37\\{scaled};\C{the top coordinate for this box}\6
+$\\{save\_h},\39\\{save\_v}$: \37\\{scaled};\C{what \\{dvi\_h} and \\{dvi\_v}
+should pop to}\6
+\\{this\_box}: \37\\{pointer};\C{pointer to containing box}\6
+\\{g\_order}: \37\\{glue\_ord};\C{applicable order of infinity for glue}\6
+\\{g\_sign}: \37$\\{normal}\to\\{shrinking}$;\C{selects type of glue}\6
+\|p: \37\\{pointer};\C{current position in the vlist}\6
+\\{save\_loc}: \37\\{integer};\C{\.{DVI} byte location upon entry}\6
+\\{leader\_box}: \37\\{pointer};\C{the leader box being replicated}\6
+\\{leader\_ht}: \37\\{scaled};\C{height of leader box being replicated}\6
+\\{lx}: \37\\{scaled};\C{extra space between leader boxes}\6
+\\{outer\_doing\_leaders}: \37\\{boolean};\C{were we doing leaders?}\6
+\\{edge}: \37\\{scaled};\C{bottom boundary of leader space}\6
+\\{glue\_temp}: \37\\{real};\C{glue value before rounding}\6
+\\{cur\_glue}: \37\\{real};\C{glue seen so far}\6
+\\{cur\_g}: \37\\{scaled};\C{rounded equivalent of \\{cur\_glue} times the glue
+ratio}\6
+\\{save\_dir}: \37\\{integer};\C{what \\{dvi\_dir} should pop to}\2\6
+\&{begin} \37$\\{cur\_g}\K0$;\5
+$\\{cur\_glue}\K\\{float\_constant}(0)$;\5
+$\\{this\_box}\K\\{temp\_ptr}$;\5
+$\\{g\_order}\K\\{glue\_order}(\\{this\_box})$;\5
+$\\{g\_sign}\K\\{glue\_sign}(\\{this\_box})$;\5
+$\|p\K\\{list\_ptr}(\\{this\_box})$;\5
+$\\{incr}(\\{cur\_s})$;\6
+\&{if} $\\{cur\_s}>0$ \1\&{then}\5
+$\\{dvi\_out}(\\{push})$;\2\6
+\&{if} $\\{cur\_s}>\\{max\_push}$ \1\&{then}\5
+$\\{max\_push}\K\\{cur\_s}$;\2\6
+$\\{save\_loc}\K\\{dvi\_offset}+\\{dvi\_ptr}$;\5
+\\{synch\_dir};\5
+$\\{left\_edge}\K\\{cur\_h}$;\5
+$\\{cur\_v}\K\\{cur\_v}-\\{height}(\\{this\_box})$;\5
+$\\{top\_edge}\K\\{cur\_v}$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\5
+\X641:Output node \|p for \\{vlist\_out} and move to the next node, maintaining
+the condition $\\{cur\_h}=\\{left\_edge}$\X;\2\6
+$\\{prune\_movements}(\\{save\_loc})$;\6
+\&{if} $\\{cur\_s}>0$ \1\&{then}\5
+$\\{dvi\_pop}(\\{save\_loc})$;\2\6
+$\\{decr}(\\{cur\_s})$;\6
+\&{end};\par
+\fi
+
+\M641. \P$\X641:Output node \|p for \\{vlist\_out} and move to the next node,
+maintaining the condition $\\{cur\_h}=\\{left\_edge}$\X\S$\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\5
+$\\{confusion}(\.{"vlistout"})$\6
+\4\&{else} \X642:Output the non-\\{char\_node} \|p for \\{vlist\_out}\X;\2\6
+\4\\{next\_p}: \37$\|p\K\\{link}(\|p)$;\6
+\&{end}\par
+\U640.\fi
+
+\M642. \P$\X642:Output the non-\\{char\_node} \|p for \\{vlist\_out}\X\S$\6
+\&{begin} \37\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node}$: \37\X643:Output a box
+in a vlist\X;\6
+\4\\{rule\_node}: \37\&{begin} \37$\\{rule\_ht}\K\\{height}(\|p)$;\5
+$\\{rule\_dp}\K\\{depth}(\|p)$;\5
+$\\{rule\_wd}\K\\{width}(\|p)$;\5
+\&{goto} \37\\{fin\_rule};\6
+\&{end};\6
+\4\\{whatsit\_node}: \37\X1379:Output the whatsit node \|p in a vlist\X;\6
+\4\\{glue\_node}: \37\X645:Move down or output leaders\X;\6
+\4\\{kern\_node}: \37$\\{cur\_v}\K\\{cur\_v}+\\{width}(\|p)$;\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\6
+\&{goto} \37\\{next\_p};\6
+\4\\{fin\_rule}: \37\X644:Output a rule in a vlist, \&{goto} \\{next\_p}\X;\6
+\4\\{move\_past}: \37$\\{cur\_v}\K\\{cur\_v}+\\{rule\_ht}$;\6
+\&{end}\par
+\U641.\fi
+
+\M643. The \\{synch\_v} here allows the \.{DVI} output to use one-byte commands
+for adjusting \|v in most cases, since the baselineskip distance will
+usually be constant.
+
+\Y\P$\4\X643:Output a box in a vlist\X\S$\6
+\&{if} $\\{list\_ptr}(\|p)=\\{null}$ \1\&{then}\5
+$\\{cur\_v}\K\\{cur\_v}+\\{height}(\|p)+\\{depth}(\|p)$\6
+\4\&{else} \&{begin} \37$\\{cur\_v}\K\\{cur\_v}+\\{height}(\|p)$;\5
+\\{synch\_v};\5
+$\\{save\_h}\K\\{dvi\_h}$;\5
+$\\{save\_v}\K\\{dvi\_v}$;\5
+$\\{save\_dir}\K\\{dvi\_dir}$;\5
+$\\{cur\_h}\K\\{left\_edge}+\\{shift\_amount}(\|p)$;\C{shift the box right}\6
+$\\{temp\_ptr}\K\|p$;\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4\\{hlist\_node}: \37\\{hlist\_out};\6
+\4\\{vlist\_node}: \37\\{vlist\_out};\6
+\4\\{dir\_node}: \37\\{dir\_out};\2\6
+\&{endcases};\5
+$\\{dvi\_h}\K\\{save\_h}$;\5
+$\\{dvi\_v}\K\\{save\_v}$;\5
+$\\{dvi\_dir}\K\\{save\_dir}$;\5
+$\\{cur\_v}\K\\{save\_v}+\\{depth}(\|p)$;\5
+$\\{cur\_h}\K\\{left\_edge}$;\5
+$\\{cur\_dir\_hv}\K\\{save\_dir}$;\6
+\&{end}\2\par
+\U642.\fi
+
+\M644. \P$\X644:Output a rule in a vlist, \&{goto} \\{next\_p}\X\S$\6
+\&{if} $\\{is\_running}(\\{rule\_wd})$ \1\&{then}\5
+$\\{rule\_wd}\K\\{width}(\\{this\_box})$;\2\6
+$\\{rule\_ht}\K\\{rule\_ht}+\\{rule\_dp}$;\C{this is the rule thickness}\6
+$\\{cur\_v}\K\\{cur\_v}+\\{rule\_ht}$;\6
+\&{if} $(\\{rule\_ht}>0)\W(\\{rule\_wd}>0)$ \1\&{then}\C{we don't output empty
+rules}\6
+\&{begin} \37\\{synch\_h};\5
+\\{synch\_v};\5
+$\\{dvi\_out}(\\{put\_rule})$;\5
+$\\{dvi\_four}(\\{rule\_ht})$;\5
+$\\{dvi\_four}(\\{rule\_wd})$;\6
+\&{end};\2\6
+\&{goto} \37\\{next\_p}\par
+\U642.\fi
+
+\M645. \P$\X645:Move down or output leaders\X\S$\6
+\&{begin} \37$\|g\K\\{glue\_ptr}(\|p)$;\5
+$\\{rule\_ht}\K\\{width}(\|g)-\\{cur\_g}$;\6
+\&{if} $\\{g\_sign}\I\\{normal}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{g\_sign}=\\{stretching}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{stretch\_order}(\|g)=\\{g\_order}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_glue}\K\\{cur\_glue}+\\{stretch}(\|g)$;\5
+$\\{vet\_glue}(\\{float}(\\{glue\_set}(\\{this\_box}))\ast\\{cur\_glue})$;\5
+$\\{cur\_g}\K\\{round}(\\{glue\_temp})$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{shrink\_order}(\|g)=\\{g\_order}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_glue}\K\\{cur\_glue}-\\{shrink}(\|g)$;\5
+$\\{vet\_glue}(\\{float}(\\{glue\_set}(\\{this\_box}))\ast\\{cur\_glue})$;\5
+$\\{cur\_g}\K\\{round}(\\{glue\_temp})$;\6
+\&{end};\2\2\6
+\&{end};\2\6
+$\\{rule\_ht}\K\\{rule\_ht}+\\{cur\_g}$;\6
+\&{if} $\\{subtype}(\|p)\G\\{a\_leaders}$ \1\&{then}\5
+\X646:Output leaders in a vlist, \&{goto} \\{fin\_rule} if a rule or to \\{next%
+\_p} if done\X;\2\6
+\&{goto} \37\\{move\_past};\6
+\&{end}\par
+\U642.\fi
+
+\M646. \P$\X646:Output leaders in a vlist, \&{goto} \\{fin\_rule} if a rule or
+to \\{next\_p} if done\X\S$\6
+\&{begin} \37$\\{leader\_box}\K\\{leader\_ptr}(\|p)$;\6
+\&{if} $\\{type}(\\{leader\_box})=\\{rule\_node}$ \1\&{then}\6
+\&{begin} \37$\\{rule\_wd}\K\\{width}(\\{leader\_box})$;\5
+$\\{rule\_dp}\K0$;\5
+\&{goto} \37\\{fin\_rule};\6
+\&{end};\2\6
+$\\{leader\_ht}\K\\{height}(\\{leader\_box})+\\{depth}(\\{leader\_box})$;\6
+\&{if} $(\\{leader\_ht}>0)\W(\\{rule\_ht}>0)$ \1\&{then}\6
+\&{begin} \37$\\{rule\_ht}\K\\{rule\_ht}+10$;\C{compensate for floating-point
+rounding}\6
+$\\{edge}\K\\{cur\_v}+\\{rule\_ht}$;\5
+$\\{lx}\K0$;\5
+\X647:Let \\{cur\_v} be the position of the first box, and set $\\{leader\_ht}+%
+\\{lx}$ to the spacing between corresponding parts of boxes\X;\6
+\&{while} $\\{cur\_v}+\\{leader\_ht}\L\\{edge}$ \1\&{do}\5
+\X648:Output a leader box at \\{cur\_v}, then advance \\{cur\_v} by $\\{leader%
+\_ht}+\\{lx}$\X;\2\6
+$\\{cur\_v}\K\\{edge}-10$;\5
+\&{goto} \37\\{next\_p};\6
+\&{end};\2\6
+\&{end}\par
+\U645.\fi
+
+\M647. \P$\X647:Let \\{cur\_v} be the position of the first box, and set $%
+\\{leader\_ht}+\\{lx}$ to the spacing between corresponding parts of boxes\X\S$%
+\6
+\&{if} $\\{subtype}(\|p)=\\{a\_leaders}$ \1\&{then}\6
+\&{begin} \37$\\{save\_v}\K\\{cur\_v}$;\5
+$\\{cur\_v}\K\\{top\_edge}+\\{leader\_ht}\ast((\\{cur\_v}-\\{top\_edge})%
+\mathbin{\&{div}}\\{leader\_ht})$;\6
+\&{if} $\\{cur\_v}<\\{save\_v}$ \1\&{then}\5
+$\\{cur\_v}\K\\{cur\_v}+\\{leader\_ht}$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{lq}\K\\{rule\_ht}\mathbin{\&{div}}\\{leader\_ht}$;%
+\C{the number of box copies}\6
+$\\{lr}\K\\{rule\_ht}\mathbin{\&{mod}}\\{leader\_ht}$;\C{the remaining space}\6
+\&{if} $\\{subtype}(\|p)=\\{c\_leaders}$ \1\&{then}\5
+$\\{cur\_v}\K\\{cur\_v}+(\\{lr}\mathbin{\&{div}}2)$\6
+\4\&{else} \&{begin} \37$\\{lx}\K\\{lr}\mathbin{\&{div}}(\\{lq}+1)$;\5
+$\\{cur\_v}\K\\{cur\_v}+((\\{lr}-(\\{lq}-1)\ast\\{lx})\mathbin{\&{div}}2)$;\6
+\&{end};\2\6
+\&{end}\2\par
+\U646.\fi
+
+\M648. When we reach this part of the program, \\{cur\_v} indicates the top of
+a
+leader box, not its baseline.
+
+\Y\P$\4\X648:Output a leader box at \\{cur\_v}, then advance \\{cur\_v} by $%
+\\{leader\_ht}+\\{lx}$\X\S$\6
+\&{begin} \37$\\{cur\_h}\K\\{left\_edge}+\\{shift\_amount}(\\{leader\_box})$;\5
+\\{synch\_h};\5
+$\\{save\_h}\K\\{dvi\_h}$;\6
+$\\{cur\_v}\K\\{cur\_v}+\\{height}(\\{leader\_box})$;\5
+\\{synch\_v};\5
+$\\{save\_v}\K\\{dvi\_v}$;\5
+$\\{save\_dir}\K\\{dvi\_dir}$;\5
+$\\{temp\_ptr}\K\\{leader\_box}$;\5
+$\\{outer\_doing\_leaders}\K\\{doing\_leaders}$;\5
+$\\{doing\_leaders}\K\\{true}$;\6
+\&{case} $\\{type}(\\{leader\_box})$ \1\&{of}\6
+\4\\{hlist\_node}: \37\\{hlist\_out};\6
+\4\\{vlist\_node}: \37\\{vlist\_out};\6
+\4\\{dir\_node}: \37\\{dir\_out};\2\6
+\&{endcases};\5
+$\\{doing\_leaders}\K\\{outer\_doing\_leaders}$;\5
+$\\{dvi\_v}\K\\{save\_v}$;\5
+$\\{dvi\_h}\K\\{save\_h}$;\5
+$\\{dvi\_dir}\K\\{save\_dir}$;\5
+$\\{cur\_h}\K\\{left\_edge}$;\5
+$\\{cur\_v}\K\\{save\_v}-\\{height}(\\{leader\_box})+\\{leader\_ht}+\\{lx}$;\5
+$\\{cur\_dir\_hv}\K\\{save\_dir}$;\6
+\&{end}\par
+\U646.\fi
+
+\M649. The \\{hlist\_out} and \\{vlist\_out} procedures are now complete, so we
+are
+ready for the \\{ship\_out} routine that gets them started in the first place.
+
+\Y\P\4\&{procedure}\1\  \37$\\{ship\_out}(\|p:\\{pointer})$;\C{output the box %
+\|p}\6
+\4\&{label} \37\\{done};\6
+\4\&{var} \37\\{page\_loc}: \37\\{integer};\C{location of the current \\{bop}}\6
+\\{del\_node}: \37\\{pointer};\C{used when delete the \\{dir\_node} continued
+box}\6
+$\|j,\39\|k$: \37$0\to9$;\C{indices to first ten count registers}\6
+\|s: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\6
+\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{saved \\{selector} setting}\2\6
+\&{begin} \37\&{if} $\\{tracing\_output}>0$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{""})$;\5
+\\{print\_ln};\5
+$\\{print}(\.{"Completed\ box\ being\ shipped\ out"})$;\6
+\&{end};\2\6
+\&{if} $\\{term\_offset}>\\{max\_print\_line}-9$ \1\&{then}\5
+\\{print\_ln}\6
+\4\&{else} \&{if} $(\\{term\_offset}>0)\V(\\{file\_offset}>0)$ \1\&{then}\5
+$\\{print\_char}(\.{"\ "})$;\2\2\6
+$\\{print\_char}(\.{"["})$;\5
+$\|j\K9$;\6
+\&{while} $(\\{count}(\|j)=0)\W(\|j>0)$ \1\&{do}\5
+$\\{decr}(\|j)$;\2\6
+\&{for} $\|k\K0\mathrel{\&{to}}\|j$ \1\&{do}\6
+\&{begin} \37$\\{print\_int}(\\{count}(\|k))$;\6
+\&{if} $\|k<\|j$ \1\&{then}\5
+$\\{print\_char}(\.{"."})$;\2\6
+\&{end};\2\6
+\\{update\_terminal};\6
+\&{if} $\\{tracing\_output}>0$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\.{"]"})$;\5
+\\{begin\_diagnostic};\5
+$\\{show\_box}(\|p)$;\5
+$\\{end\_diagnostic}(\\{true})$;\6
+\&{end};\2\6
+\&{if} $\\{type}(\|p)=\\{dir\_node}$ \1\&{then}\6
+\&{begin} \37$\\{del\_node}\K\|p$;\5
+$\|p\K\\{list\_ptr}(\|p)$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\\{del\_node}))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\\{del\_node}))$;\5
+$\\{free\_node}(\\{del\_node},\39\\{box\_node\_size})$;\6
+\&{end};\2\6
+$\\{flush\_node\_list}(\\{link}(\|p))$;\5
+$\\{link}(\|p)\K\\{null}$;\6
+\&{if} $\\{box\_dir}(\|p)\I\\{dir\_yoko}$ \1\&{then}\5
+$\|p\K\\{new\_dir\_node}(\|p,\39\\{dir\_yoko})$;\2\6
+\X651:Ship box \|p out\X;\6
+\&{if} $\\{tracing\_output}\L0$ \1\&{then}\5
+$\\{print\_char}(\.{"]"})$;\2\6
+$\\{dead\_cycles}\K0$;\5
+\\{update\_terminal};\C{progress report}\6
+\X650:Flush the box from memory, showing statistics if requested\X;\6
+\&{end};\par
+\fi
+
+\M650. \P$\X650:Flush the box from memory, showing statistics if requested\X\S$%
+\6
+\&{stat} \37\&{if} $\\{tracing\_stats}>1$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"Memory\ usage\ before:\ "})$;\5
+$\\{print\_int}(\\{var\_used})$;\5
+$\\{print\_char}(\.{"\&"})$;\5
+$\\{print\_int}(\\{dyn\_used})$;\5
+$\\{print\_char}(\.{";"})$;\6
+\&{end};\2\6
+\&{tats}\6
+$\\{flush\_node\_list}(\|p)$;\6
+\&{stat} \37\&{if} $\\{tracing\_stats}>1$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ after:\ "})$;\5
+$\\{print\_int}(\\{var\_used})$;\5
+$\\{print\_char}(\.{"\&"})$;\5
+$\\{print\_int}(\\{dyn\_used})$;\5
+$\\{print}(\.{";\ still\ untouched:\ "})$;\5
+$\\{print\_int}(\\{hi\_mem\_min}-\\{lo\_mem\_max}-1)$;\5
+\\{print\_ln};\6
+\&{end};\2\6
+\&{tats}\par
+\U649.\fi
+
+\M651. \P$\X651:Ship box \|p out\X\S$\6
+\X652:Update the values of \\{max\_h} and \\{max\_v}; but if the page is too
+large, \&{goto} \\{done}\X;\6
+\X628:Initialize variables as \\{ship\_out} begins\X;\6
+$\\{page\_loc}\K\\{dvi\_offset}+\\{dvi\_ptr}$;\5
+$\\{dvi\_out}(\\{bop})$;\6
+\&{for} $\|k\K0\mathrel{\&{to}}9$ \1\&{do}\5
+$\\{dvi\_four}(\\{count}(\|k))$;\2\6
+$\\{dvi\_four}(\\{last\_bop})$;\5
+$\\{last\_bop}\K\\{page\_loc}$;\5
+$\\{cur\_v}\K\\{height}(\|p)+\\{v\_offset}$;\5
+$\\{temp\_ptr}\K\|p$;\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4\\{hlist\_node}: \37\\{hlist\_out};\6
+\4\\{vlist\_node}: \37\\{vlist\_out};\6
+\4\\{dir\_node}: \37\\{dir\_out};\2\6
+\&{endcases};\5
+$\\{dvi\_out}(\\{eop})$;\5
+$\\{incr}(\\{total\_pages})$;\5
+$\\{cur\_s}\K-1$;\5
+$\\{ifdef}(\.{\'IPC\'})$\1\6
+\&{if} $\\{ipc\_on}>0$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{dvi\_limit}=\\{half\_buf}$ \1\&{then}\6
+\&{begin} \37$\\{write\_dvi}(\\{half\_buf},\39\\{dvi\_buf\_size}-1)$;\5
+\\{flush\_dvi};\5
+$\\{dvi\_gone}\K\\{dvi\_gone}+\\{half\_buf}$;\6
+\&{end};\2\6
+\&{if} $\\{dvi\_ptr}>(\H{7FFFFFFF}-\\{dvi\_offset})$ \1\&{then}\6
+\&{begin} \37$\\{cur\_s}\K-2$;\5
+$\\{fatal\_error}(\.{"dvi\ length\ exceeds\ "}\.{"7FFFFFFF"})$;\6
+\&{end};\2\6
+\&{if} $\\{dvi\_ptr}>0$ \1\&{then}\6
+\&{begin} \37$\\{write\_dvi}(0,\39\\{dvi\_ptr}-1)$;\5
+\\{flush\_dvi};\5
+$\\{dvi\_offset}\K\\{dvi\_offset}+\\{dvi\_ptr}$;\5
+$\\{dvi\_gone}\K\\{dvi\_gone}+\\{dvi\_ptr}$;\6
+\&{end};\2\6
+$\\{dvi\_ptr}\K0$;\5
+$\\{dvi\_limit}\K\\{dvi\_buf\_size}$;\5
+$\\{ipc\_page}(\\{dvi\_gone})$;\6
+\&{end};\2\2\6
+$\\{endif}(\.{\'IPC\'})$;\6
+\4\\{done}: \37\par
+\U649.\fi
+
+\M652. Sometimes the user will generate a huge page because other error
+messages
+are being ignored. Such pages are not output to the \.{dvi} file, since they
+may confuse the printing software.
+
+\Y\P$\4\X652:Update the values of \\{max\_h} and \\{max\_v}; but if the page is
+too large, \&{goto} \\{done}\X\S$\6
+\&{if} $(\\{height}(\|p)>\\{max\_dimen})\V\30(\\{depth}(\|p)>\\{max\_dimen})\V%
+\30(\\{height}(\|p)+\\{depth}(\|p)+\\{v\_offset}>\\{max\_dimen})\V\30(%
+\\{width}(\|p)+\\{h\_offset}>\\{max\_dimen})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Huge\ page\ cannot\ be\ shipped\ out"})$;\5
+$\\{help2}(\.{"The\ page\ just\ created\ is\ more\ than\ 18\ feet\ tall\ or"})$%
+\6
+$(\.{"more\ than\ 18\ feet\ wide,\ so\ I\ suspect\ something\ went\ wrong."})$;%
+\5
+\\{error};\6
+\&{if} $\\{tracing\_output}\L0$ \1\&{then}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"The\ following\ box\ has\ been\ deleted:"})$;\5
+$\\{show\_box}(\|p)$;\5
+$\\{end\_diagnostic}(\\{true})$;\6
+\&{end};\2\6
+\&{goto} \37\\{done};\6
+\&{end};\2\6
+\&{if} $\\{height}(\|p)+\\{depth}(\|p)+\\{v\_offset}>\\{max\_v}$ \1\&{then}\5
+$\\{max\_v}\K\\{height}(\|p)+\\{depth}(\|p)+\\{v\_offset}$;\2\6
+\&{if} $\\{width}(\|p)+\\{h\_offset}>\\{max\_h}$ \1\&{then}\5
+$\\{max\_h}\K\\{width}(\|p)+\\{h\_offset}$\2\par
+\U651.\fi
+
+\M653. At the end of the program, we must finish things off by writing the
+post\-amble. If $\\{total\_pages}=0$, the \.{DVI} file was never opened.
+If $\\{total\_pages}\G65536$, the \.{DVI} file will lie. And if
+$\\{max\_push}\G65536$, the user deserves whatever chaos might ensue.
+
+An integer variable \|k will be declared for use by this routine.
+
+\Y\P$\4\X653:Finish the \.{DVI} file\X\S$\6
+\&{while} $\\{cur\_s}>-1$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{cur\_s}>0$ \1\&{then}\5
+$\\{dvi\_out}(\\{pop})$\6
+\4\&{else} \&{begin} \37$\\{dvi\_out}(\\{eop})$;\5
+$\\{incr}(\\{total\_pages})$;\6
+\&{end};\2\6
+$\\{decr}(\\{cur\_s})$;\6
+\&{end};\2\6
+\&{if} $\\{total\_pages}=0$ \1\&{then}\5
+$\\{print\_nl}(\.{"No\ pages\ of\ output."})$\6
+\4\&{else} \&{if} $\\{cur\_s}\I-2$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_out}(\\{post})$;\C{beginning of the postamble}\6
+$\\{dvi\_four}(\\{last\_bop})$;\5
+$\\{last\_bop}\K\\{dvi\_offset}+\\{dvi\_ptr}-5$;\C{\\{post} location}\6
+$\\{dvi\_four}(25400000)$;\5
+$\\{dvi\_four}(473628672)$;\C{conversion ratio for sp}\6
+\\{prepare\_mag};\5
+$\\{dvi\_four}(\\{mag})$;\C{magnification factor}\6
+$\\{dvi\_four}(\\{max\_v})$;\5
+$\\{dvi\_four}(\\{max\_h})$;\6
+$\\{dvi\_out}(\\{max\_push}\mathbin{\&{div}}256)$;\5
+$\\{dvi\_out}(\\{max\_push}\mathbin{\&{mod}}256)$;\6
+$\\{dvi\_out}((\\{total\_pages}\mathbin{\&{div}}256)\mathbin{\&{mod}}256)$;\5
+$\\{dvi\_out}(\\{total\_pages}\mathbin{\&{mod}}256)$;\6
+\X654:Output the font definitions for all fonts that were used\X;\6
+$\\{dvi\_out}(\\{post\_post})$;\5
+$\\{dvi\_four}(\\{last\_bop})$;\6
+\&{if} $\\{dir\_used}$ \1\&{then}\5
+$\\{dvi\_out}(\\{ex\_id\_byte})$\6
+\4\&{else} $\\{dvi\_out}(\\{id\_byte})$;\2\6
+$\\{ifdef}(\.{\'IPC\'})\|k\K7-((3+\\{dvi\_offset}+\\{dvi\_ptr})\mathbin{%
+\&{mod}}4)$;\C{the number of 223's}\6
+$\\{endif}(\.{\'IPC\'})\\{ifndef}(\.{\'IPC\'})\|k\K4+((\\{dvi\_buf\_size}-%
+\\{dvi\_ptr})\mathbin{\&{mod}}4)$;\C{the number of 223's}\6
+$\\{endifn}(\.{\'IPC\'})$\1\6
+\&{while} $\|k>0$ \1\&{do}\6
+\&{begin} \37$\\{dvi\_out}(223)$;\5
+$\\{decr}(\|k)$;\6
+\&{end};\2\2\6
+\X610:Empty the last bytes out of \\{dvi\_buf}\X;\6
+$\\{print\_nl}(\.{"Output\ written\ on\ "})$;\5
+$\\{print\_file\_name}(0,\39\\{output\_file\_name},\390)$;\5
+$\\{print}(\.{"\ ("})$;\5
+$\\{print\_int}(\\{total\_pages})$;\6
+\&{if} $\\{total\_pages}\I1$ \1\&{then}\5
+$\\{print}(\.{"\ pages"})$\6
+\4\&{else} $\\{print}(\.{"\ page"})$;\2\6
+$\\{print}(\.{",\ "})$;\5
+$\\{print\_int}(\\{dvi\_offset}+\\{dvi\_ptr})$;\5
+$\\{print}(\.{"\ bytes)."})$;\5
+$\\{b\_close}(\\{dvi\_file})$;\6
+\&{end}\2\2\par
+\U1346.\fi
+
+\M654. \P$\X654:Output the font definitions for all fonts that were used\X\S$\6
+\&{while} $\\{font\_ptr}>\\{font\_base}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{font\_used}[\\{font\_ptr}]$ \1\&{then}\5
+$\\{dvi\_font\_def}(\\{font\_ptr})$;\2\6
+$\\{decr}(\\{font\_ptr})$;\6
+\&{end}\2\par
+\U653.\fi
+
+\N655.  \[33] Packaging.
+We're essentially done with the parts of \TeX\ that are concerned with
+the input (\\{get\_next}) and the output (\\{ship\_out}). So it's time to
+get heavily into the remaining part, which does the real work of typesetting.
+
+After lists are constructed, \TeX\ wraps them up and puts them into boxes.
+Two major subroutines are given the responsibility for this task: \\{hpack}
+applies to horizontal lists (hlists) and \\{vpack} applies to vertical lists
+(vlists). The main duty of \\{hpack} and \\{vpack} is to compute the dimensions
+of the resulting boxes, and to adjust the glue if one of those dimensions
+is pre-specified. The computed sizes normally enclose all of the material
+inside the new box; but some items may stick out if negative glue is used,
+if the box is overfull, or if a \.{\\vbox} includes other boxes that have
+been shifted left.
+
+The subroutine call $\\{hpack}(\|p,\|w,\|m)$ returns a pointer to an \\{hlist%
+\_node}
+for a box containing the hlist that starts at \|p. Parameter \|w specifies
+a width; and parameter \|m is either `\\{exactly}' or `\\{additional}'.  Thus,
+$\\{hpack}(\|p,\|w,\\{exactly})$ produces a box whose width is exactly \|w,
+while
+$\\{hpack}(\|p,\|w,\\{additional})$ yields a box whose width is the natural
+width plus
+\|w.  It is convenient to define a macro called `\\{natural}' to cover the
+most common case, so that we can say $\\{hpack}(\|p,\\{natural})$ to get a box
+that
+has the natural width of list \|p.
+
+Similarly, $\\{vpack}(\|p,\|w,\|m)$ returns a pointer to a \\{vlist\_node} for
+a
+box containing the vlist that starts at \|p. In this case \|w represents
+a height instead of a width; the parameter \|m is interpreted as in \\{hpack}.
+
+\Y\P\D \37$\\{exactly}=0$\C{a box dimension is pre-specified}\par
+\P\D \37$\\{additional}=1$\C{a box dimension is increased from the natural one}%
+\par
+\P\D \37$\\{natural}\S0,\39\\{additional}$\C{shorthand for parameters to %
+\\{hpack} and \\{vpack}}\par
+\fi
+
+\M656. The parameters to \\{hpack} and \\{vpack} correspond to \TeX's
+primitives
+like `\.{\\hbox} \.{to} \.{300pt}', `\.{\\hbox} \.{spread} \.{10pt}'; note
+that `\.{\\hbox}' with no dimension following it is equivalent to
+`\.{\\hbox} \.{spread} \.{0pt}'.  The \\{scan\_spec} subroutine scans such
+constructions in the user's input, including the mandatory left brace that
+follows them, and it puts the specification onto \\{save\_stack} so that the
+desired box can later be obtained by executing the following code:
+$$\vbox{\halign{#\hfil\cr
+$\\{save\_ptr}\K\\{save\_ptr}-2$;\cr
+$\\{hpack}(\|p,\\{saved}(1),\\{saved}(0)).$\cr}}$$
+Special care is necessary to ensure that the special \\{save\_stack} codes
+are placed just below the new group code, because scanning can change
+\\{save\_stack} when \.{\\csname} appears.
+
+\Y\P\4\&{procedure}\1\  \37$\\{scan\_spec}(\|c:\\{group\_code};\,\35\\{three%
+\_codes}:\\{boolean})$;\C{scans a box specification and left brace}\6
+\4\&{label} \37\\{found};\6
+\4\&{var} \37\|s: \37\\{integer};\C{temporarily saved value}\6
+\\{spec\_code}: \37$\\{exactly}\to\\{additional}$;\2\6
+\&{begin} \37\&{if} $\\{three\_codes}$ \1\&{then}\5
+$\|s\K\\{saved}(0)$;\2\6
+\&{if} $\\{scan\_keyword}(\.{"to"})$ \1\&{then}\5
+$\\{spec\_code}\K\\{exactly}$\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"spread"})$ \1\&{then}\5
+$\\{spec\_code}\K\\{additional}$\6
+\4\&{else} \&{begin} \37$\\{spec\_code}\K\\{additional}$;\5
+$\\{cur\_val}\K0$;\5
+\&{goto} \37\\{found};\6
+\&{end};\2\2\6
+\\{scan\_normal\_dimen};\6
+\4\\{found}: \37\&{if} $\\{three\_codes}$ \1\&{then}\6
+\&{begin} \37$\\{saved}(0)\K\|s$;\5
+$\\{incr}(\\{save\_ptr})$;\6
+\&{end};\2\6
+$\\{saved}(0)\K\\{spec\_code}$;\5
+$\\{saved}(1)\K\\{cur\_val}$;\5
+$\\{save\_ptr}\K\\{save\_ptr}+2$;\5
+$\\{new\_save\_level}(\|c)$;\5
+\\{scan\_left\_brace};\6
+\&{end};\par
+\fi
+
+\M657. To figure out the glue setting, \\{hpack} and \\{vpack} determine how
+much
+stretchability and shrinkability are present, considering all four orders
+of infinity. The highest order of infinity that has a nonzero coefficient
+is then used as if no other orders were present.
+
+For example, suppose that the given list contains six glue nodes with
+the respective stretchabilities 3pt, 8fill, 5fil, 6pt, $-3$fil, $-8$fill.
+Then the total is essentially 2fil; and if a total additional space of 6pt
+is to be achieved by stretching, the actual amounts of stretch will be
+0pt, 0pt, 15pt, 0pt, $-9$pt, and 0pt, since only `fil' glue will be
+considered. (The `fill' glue is therefore not really stretching infinitely
+with respect to `fil'; nobody would actually want that to happen.)
+
+The arrays \\{total\_stretch} and \\{total\_shrink} are used to determine how
+much
+glue of each kind is present. A global variable \\{last\_badness} is used
+to implement \.{\\badness}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4$\\{total\_stretch},\39\\{total\_shrink}$: \37\&{array} $[\\{glue\_ord}]$ \1%
+\&{of}\5
+\\{scaled};\C{glue found by \\{hpack} or \\{vpack}}\2\6
+\4\\{last\_badness}: \37\\{integer};\C{badness of the most recently packaged
+box}\par
+\fi
+
+\M658. If the global variable \\{adjust\_tail} is non-null, the \\{hpack}
+routine
+also removes all occurrences of \\{ins\_node}, \\{mark\_node}, and \\{adjust%
+\_node}
+items and appends the resulting material onto the list that ends at
+location \\{adjust\_tail}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{adjust\_tail}: \37\\{pointer};\C{tail of adjustment list}\6
+\4\\{last\_disp}: \37\\{scaled};\C{displacement at end of list}\6
+\4\\{cur\_kanji\_skip}: \37\\{pointer};\6
+\4\\{cur\_xkanji\_skip}: \37\\{pointer};\par
+\fi
+
+\M659. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{adjust\_tail}\K\\{null}$;\5
+$\\{last\_badness}\K0$;\5
+$\\{cur\_kanji\_skip}\K\\{zero\_glue}$;\5
+$\\{cur\_xkanji\_skip}\K\\{zero\_glue}$;\C{ koko   $\\{incr}(\\{glue\_ref%
+\_count}(\\{cur\_kanji\_skip}))$;   $\\{incr}(\\{glue\_ref\_count}(\\{cur%
+\_xkanji\_skip}))$; }\par
+\fi
+
+\M660. Here now is \\{hpack}, which contains few if any surprises.
+
+\Y\P\4\&{function}\1\  \37$\\{hpack}(\|p:\\{pointer};\,\35\|w:\\{scaled};\,\35%
+\|m:\\{small\_number})$: \37\\{pointer};\6
+\4\&{label} \37$\\{reswitch},\39\\{common\_ending},\39\\{exit}$;\6
+\4\&{var} \37\|r: \37\\{pointer};\C{the box node that will be returned}\6
+\|k: \37\\{pointer};\C{points to a \\{kanji\_space} specification}\6
+\\{disp}: \37\\{scaled};\C{displacement}\6
+\|q: \37\\{pointer};\C{trails behind \|p}\6
+$\|h,\39\|d,\39\|x$: \37\\{scaled};\C{height, depth, and natural width}\6
+\|s: \37\\{scaled};\C{shift amount}\6
+\|g: \37\\{pointer};\C{points to a glue specification}\6
+\|o: \37\\{glue\_ord};\C{order of infinity}\6
+\|f: \37\\{internal\_font\_number};\C{the font in a \\{char\_node}}\6
+\|i: \37\\{four\_quarters};\C{font information about a \\{char\_node}}\6
+\\{hd}: \37\\{eight\_bits};\C{height and depth indices for a character}\2\6
+\&{begin} \37$\\{last\_badness}\K0$;\5
+$\|r\K\\{get\_node}(\\{box\_node\_size})$;\5
+$\\{type}(\|r)\K\\{hlist\_node}$;\5
+$\\{subtype}(\|r)\K\\{min\_quarterword}$;\5
+$\\{shift\_amount}(\|r)\K0$;\5
+$\\{space\_ptr}(\|r)\K\\{cur\_kanji\_skip}$;\5
+$\\{xspace\_ptr}(\|r)\K\\{cur\_xkanji\_skip}$;\5
+$\\{add\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{add\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\|k\K\\{cur\_kanji\_skip}$;\5
+$\|q\K\|r+\\{list\_offset}$;\5
+$\\{link}(\|q)\K\|p$;\6
+$\|h\K0$;\5
+\X661:Clear dimensions to zero\X;\6
+$\\{disp}\K0$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\5
+\X662:Examine node \|p in the hlist, taking account of its effect on the
+dimensions of the new box, or moving it to the adjustment list; then advance %
+\|p to the next node\X;\2\6
+\&{if} $\\{adjust\_tail}\I\\{null}$ \1\&{then}\5
+$\\{link}(\\{adjust\_tail})\K\\{null}$;\2\6
+$\\{height}(\|r)\K\|h$;\5
+$\\{depth}(\|r)\K\|d$;\6
+\X668:Determine the value of $\\{width}(\|r)$ and the appropriate glue setting;
+then \&{return} or \&{goto} \\{common\_ending}\X;\6
+\4\\{common\_ending}: \37\X674:Finish issuing a diagnostic message for an
+overfull or underfull hbox\X;\6
+\4\\{exit}: \37$\\{last\_disp}\K\\{disp}$;\5
+$\\{hpack}\K\|r$;\6
+\&{end};\par
+\fi
+
+\M661. \P$\X661:Clear dimensions to zero\X\S$\6
+$\|d\K0$;\5
+$\|x\K0$;\5
+$\\{total\_stretch}[\\{normal}]\K0$;\5
+$\\{total\_shrink}[\\{normal}]\K0$;\5
+$\\{total\_stretch}[\\{fil}]\K0$;\5
+$\\{total\_shrink}[\\{fil}]\K0$;\5
+$\\{total\_stretch}[\\{fill}]\K0$;\5
+$\\{total\_shrink}[\\{fill}]\K0$;\5
+$\\{total\_stretch}[\\{filll}]\K0$;\5
+$\\{total\_shrink}[\\{filll}]\K0$\par
+\Us660\ET679.\fi
+
+\M662. \P$\X662:Examine node \|p in the hlist, taking account of its effect on
+the dimensions of the new box, or moving it to the adjustment list; then
+advance \|p to the next node\X\S$\6
+\&{begin} \37\\{reswitch}: \37$\\{chain}\K\\{false}$;\6
+\&{while} $\\{is\_char\_node}(\|p)$ \1\&{do}\5
+\X665:Incorporate character dimensions into the dimensions of the hbox that
+will contain~it, then move to the next node\X;\2\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{begin} \37\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node},\39%
+\\{unset\_node}$: \37\X664:Incorporate box dimensions into the dimensions of
+the hbox that will contain~it\X;\6
+\4$\\{ins\_node},\39\\{mark\_node},\39\\{adjust\_node}$: \37\&{if} $\\{adjust%
+\_tail}\I\\{null}$ \1\&{then}\5
+\X666:Transfer node \|p to the adjustment list\X;\2\6
+\4\\{whatsit\_node}: \37\X1373:Incorporate a whatsit node into an hbox\X;\6
+\4\\{disp\_node}: \37$\\{disp}\K\\{disp\_dimen}(\|p)$;\6
+\4\\{glue\_node}: \37\X667:Incorporate glue into the horizontal totals\X;\6
+\4$\\{kern\_node},\39\\{math\_node}$: \37$\|x\K\|x+\\{width}(\|p)$;\6
+\4\\{ligature\_node}: \37\X663:Make node \|p look like a \\{char\_node} and %
+\&{goto} \\{reswitch}\X;\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\&{end}\par
+\U660.\fi
+
+\M663. \P$\X663:Make node \|p look like a \\{char\_node} and \&{goto} %
+\\{reswitch}\X\S$\6
+\&{begin} \37$\\{mem}[\\{lig\_trick}]\K\\{mem}[\\{lig\_char}(\|p)]$;\5
+$\\{link}(\\{lig\_trick})\K\\{link}(\|p)$;\5
+$\|p\K\\{lig\_trick}$;\5
+\&{goto} \37\\{reswitch};\6
+\&{end}\par
+\Us633, 662\ETs1159.\fi
+
+\M664. The code here implicitly uses the fact that running dimensions are
+indicated by \\{null\_flag}, which will be ignored in the calculations
+because it is a highly negative number.
+
+\Y\P$\4\X664:Incorporate box dimensions into the dimensions of the hbox that
+will contain~it\X\S$\6
+\&{begin} \37$\|x\K\|x+\\{width}(\|p)$;\6
+\&{if} $\\{type}(\|p)\G\\{rule\_node}$ \1\&{then}\5
+$\|s\K\\{disp}$\ \&{else} $\|s\K\\{shift\_amount}(\|p)+\\{disp}$;\2\6
+\&{if} $\\{height}(\|p)-\|s>\|h$ \1\&{then}\5
+$\|h\K\\{height}(\|p)-\|s$;\2\6
+\&{if} $\\{depth}(\|p)+\|s>\|d$ \1\&{then}\5
+$\|d\K\\{depth}(\|p)+\|s$;\2\6
+\&{end}\par
+\U662.\fi
+
+\M665. The following code is part of \TeX's inner loop; i.e., adding another
+character of text to the user's input will cause each of these instructions
+to be exercised one more time.
+
+\Y\P$\4\X665:Incorporate character dimensions into the dimensions of the hbox
+that will contain~it, then move to the next node\X\S$\6
+\&{begin} \37$\|f\K\\{font}(\|p)$;\5
+$\|i\K\\{char\_info}(\|f)(\\{character}(\|p))$;\5
+$\\{hd}\K\\{height\_depth}(\|i)$;\5
+$\|x\K\|x+\\{char\_width}(\|f)(\|i)$;\6
+$\|s\K\\{char\_height}(\|f)(\\{hd})-\\{disp}$;\6
+\&{if} $\|s>\|h$ \1\&{then}\5
+$\|h\K\|s$;\2\6
+$\|s\K\\{char\_depth}(\|f)(\\{hd})+\\{disp}$;\6
+\&{if} $\|s>\|d$ \1\&{then}\5
+$\|d\K\|s$;\2\6
+\&{if} $\\{font\_dir}[\|f]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{link}(\|p)$;\6
+\&{if} $\\{chain}$ \1\&{then}\6
+\&{begin} \37$\|x\K\|x+\\{width}(\|k)$;\6
+$\|o\K\\{stretch\_order}(\|k)$;\5
+$\\{total\_stretch}[\|o]\K\\{total\_stretch}[\|o]+\\{stretch}(\|k)$;\5
+$\|o\K\\{shrink\_order}(\|k)$;\5
+$\\{total\_shrink}[\|o]\K\\{total\_shrink}[\|o]+\\{shrink}(\|k)$;\6
+\&{end}\6
+\4\&{else} $\\{chain}\K\\{true}$;\2\6
+\&{end}\6
+\4\&{else} $\\{chain}\K\\{false}$;\2\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end}\par
+\U662.\fi
+
+\M666. Although node \|q is not necessarily the immediate predecessor of node %
+\|p,
+it always points to some node in the list preceding \|p. Thus, we can delete
+nodes by moving \|q when necessary. The algorithm takes linear time, and the
+extra computation does not intrude on the inner loop unless it is necessary
+to make a deletion.
+
+\Y\P$\4\X666:Transfer node \|p to the adjustment list\X\S$\6
+\&{begin} \37\&{while} $\\{link}(\|q)\I\|p$ \1\&{do}\5
+$\|q\K\\{link}(\|q)$;\2\6
+\&{if} $\\{type}(\|p)=\\{adjust\_node}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\\{adjust\_tail})\K\\{adjust\_ptr}(\|p)$;\6
+\&{while} $\\{link}(\\{adjust\_tail})\I\\{null}$ \1\&{do}\5
+$\\{adjust\_tail}\K\\{link}(\\{adjust\_tail})$;\2\6
+$\|p\K\\{link}(\|p)$;\5
+$\\{free\_node}(\\{link}(\|q),\39\\{small\_node\_size})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{link}(\\{adjust\_tail})\K\|p$;\5
+$\\{adjust\_tail}\K\|p$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+$\\{link}(\|q)\K\|p$;\5
+$\|p\K\|q$;\6
+\&{end}\par
+\U662.\fi
+
+\M667. \P$\X667:Incorporate glue into the horizontal totals\X\S$\6
+\&{begin} \37$\|g\K\\{glue\_ptr}(\|p)$;\5
+$\|x\K\|x+\\{width}(\|g)$;\6
+$\|o\K\\{stretch\_order}(\|g)$;\5
+$\\{total\_stretch}[\|o]\K\\{total\_stretch}[\|o]+\\{stretch}(\|g)$;\5
+$\|o\K\\{shrink\_order}(\|g)$;\5
+$\\{total\_shrink}[\|o]\K\\{total\_shrink}[\|o]+\\{shrink}(\|g)$;\6
+\&{if} $\\{subtype}(\|p)\G\\{a\_leaders}$ \1\&{then}\6
+\&{begin} \37$\|g\K\\{leader\_ptr}(\|p)$;\6
+\&{if} $\\{height}(\|g)>\|h$ \1\&{then}\5
+$\|h\K\\{height}(\|g)$;\2\6
+\&{if} $\\{depth}(\|g)>\|d$ \1\&{then}\5
+$\|d\K\\{depth}(\|g)$;\2\6
+\&{end};\2\6
+\&{end}\par
+\U662.\fi
+
+\M668. When we get to the present part of the program, \|x is the natural width
+of the box being packaged.
+
+\Y\P$\4\X668:Determine the value of $\\{width}(\|r)$ and the appropriate glue
+setting; then \&{return} or \&{goto} \\{common\_ending}\X\S$\6
+\&{if} $\|m=\\{additional}$ \1\&{then}\5
+$\|w\K\|x+\|w$;\2\6
+$\\{width}(\|r)\K\|w$;\5
+$\|x\K\|w-\|x$;\C{now \|x is the excess to be made up}\6
+\&{if} $\|x=0$ \1\&{then}\6
+\&{begin} \37$\\{glue\_sign}(\|r)\K\\{normal}$;\5
+$\\{glue\_order}(\|r)\K\\{normal}$;\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$;\5
+\&{return};\6
+\&{end}\6
+\4\&{else} \&{if} $\|x>0$ \1\&{then}\5
+\X669:Determine horizontal glue stretch setting, then \&{return} or \hbox{%
+\&{goto} \\{common\_ending}}\X\6
+\4\&{else} \X675:Determine horizontal glue shrink setting, then \&{return} or %
+\hbox{\&{goto} \\{common\_ending}}\X\2\2\par
+\U660.\fi
+
+\M669. \P$\X669:Determine horizontal glue stretch setting, then \&{return} or %
+\hbox{\&{goto} \\{common\_ending}}\X\S$\6
+\&{begin} \37\X670:Determine the stretch order\X;\6
+$\\{glue\_order}(\|r)\K\|o$;\5
+$\\{glue\_sign}(\|r)\K\\{stretching}$;\6
+\&{if} $\\{total\_stretch}[\|o]\I0$ \1\&{then}\5
+$\\{glue\_set}(\|r)\K\\{unfloat}(\|x/\\{total\_stretch}[\|o])$\6
+\4\&{else} \&{begin} \37$\\{glue\_sign}(\|r)\K\\{normal}$;\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$;\C{there's nothing to stretch}%
+\6
+\&{end};\2\6
+\&{if} $\|o=\\{normal}$ \1\&{then}\6
+\&{if} $\\{list\_ptr}(\|r)\I\\{null}$ \1\&{then}\5
+\X671:Report an underfull hbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X;\2\2\6
+\&{return};\6
+\&{end}\par
+\U668.\fi
+
+\M670. \P$\X670:Determine the stretch order\X\S$\6
+\&{if} $\\{total\_stretch}[\\{filll}]\I0$ \1\&{then}\5
+$\|o\K\\{filll}$\6
+\4\&{else} \&{if} $\\{total\_stretch}[\\{fill}]\I0$ \1\&{then}\5
+$\|o\K\\{fill}$\6
+\4\&{else} \&{if} $\\{total\_stretch}[\\{fil}]\I0$ \1\&{then}\5
+$\|o\K\\{fil}$\6
+\4\&{else} $\|o\K\\{normal}$\2\2\2\par
+\Us669, 684\ETs807.\fi
+
+\M671. \P$\X671:Report an underfull hbox and \&{goto} \\{common\_ending}, if
+this box is sufficiently bad\X\S$\6
+\&{begin} \37$\\{last\_badness}\K\\{badness}(\|x,\39\\{total\_stretch}[%
+\\{normal}])$;\6
+\&{if} $\\{last\_badness}>\\{hbadness}$ \1\&{then}\6
+\&{begin} \37\\{print\_ln};\6
+\&{if} $\\{last\_badness}>100$ \1\&{then}\5
+$\\{print\_nl}(\.{"Underfull"})$\ \&{else} $\\{print\_nl}(\.{"Loose"})$;\2\6
+$\\{print}(\.{"\ \\hbox\ (badness\ "})$;\5
+$\\{print\_int}(\\{last\_badness})$;\5
+\&{goto} \37\\{common\_ending};\6
+\&{end};\2\6
+\&{end}\par
+\U669.\fi
+
+\M672. In order to provide a decent indication of where an overfull or
+underfull
+box originated, we use a global variable \\{pack\_begin\_line} that is
+set nonzero only when \\{hpack} is being called by the paragraph builder
+or the alignment finishing routine.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{pack\_begin\_line}: \37\\{integer};\C{source file line where the current
+paragraph   or alignment began; a negative value denotes alignment}\par
+\fi
+
+\M673. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{pack\_begin\_line}\K0$;\par
+\fi
+
+\M674. \P$\X674:Finish issuing a diagnostic message for an overfull or
+underfull hbox\X\S$\6
+\&{if} $\\{output\_active}$ \1\&{then}\5
+$\\{print}(\.{")\ has\ occurred\ while\ \\output\ is\ active"})$\6
+\4\&{else} \&{begin} \37\&{if} $\\{pack\_begin\_line}\I0$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{pack\_begin\_line}>0$ \1\&{then}\5
+$\\{print}(\.{")\ in\ paragraph\ at\ lines\ "})$\6
+\4\&{else} $\\{print}(\.{")\ in\ alignment\ at\ lines\ "})$;\2\6
+$\\{print\_int}(\\{abs}(\\{pack\_begin\_line}))$;\5
+$\\{print}(\.{"--"})$;\6
+\&{end}\6
+\4\&{else} $\\{print}(\.{")\ detected\ at\ line\ "})$;\2\6
+$\\{print\_int}(\\{line})$;\6
+\&{end};\2\6
+\\{print\_ln};\6
+$\\{font\_in\_short\_display}\K\\{null\_font}$;\5
+$\\{short\_display}(\\{list\_ptr}(\|r))$;\5
+\\{print\_ln};\6
+\\{begin\_diagnostic};\5
+$\\{show\_box}(\|r)$;\5
+$\\{end\_diagnostic}(\\{true})$\par
+\U660.\fi
+
+\M675. \P$\X675:Determine horizontal glue shrink setting, then \&{return} or %
+\hbox{\&{goto} \\{common\_ending}}\X\S$\6
+\&{begin} \37\X676:Determine the shrink order\X;\6
+$\\{glue\_order}(\|r)\K\|o$;\5
+$\\{glue\_sign}(\|r)\K\\{shrinking}$;\6
+\&{if} $\\{total\_shrink}[\|o]\I0$ \1\&{then}\5
+$\\{glue\_set}(\|r)\K\\{unfloat}((-\|x)/\\{total\_shrink}[\|o])$\6
+\4\&{else} \&{begin} \37$\\{glue\_sign}(\|r)\K\\{normal}$;\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$;\C{there's nothing to shrink}\6
+\&{end};\2\6
+\&{if} $(\\{total\_shrink}[\|o]<-\|x)\W(\|o=\\{normal})\W(\\{list\_ptr}(\|r)\I%
+\\{null})$ \1\&{then}\6
+\&{begin} \37$\\{last\_badness}\K1000000$;\5
+$\\{set\_glue\_ratio\_one}(\\{glue\_set}(\|r))$;\C{use the maximum shrinkage}\6
+\X677:Report an overfull hbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X;\6
+\&{end}\6
+\4\&{else} \&{if} $\|o=\\{normal}$ \1\&{then}\6
+\&{if} $\\{list\_ptr}(\|r)\I\\{null}$ \1\&{then}\5
+\X678:Report a tight hbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X;\2\2\2\6
+\&{return};\6
+\&{end}\par
+\U668.\fi
+
+\M676. \P$\X676:Determine the shrink order\X\S$\6
+\&{if} $\\{total\_shrink}[\\{filll}]\I0$ \1\&{then}\5
+$\|o\K\\{filll}$\6
+\4\&{else} \&{if} $\\{total\_shrink}[\\{fill}]\I0$ \1\&{then}\5
+$\|o\K\\{fill}$\6
+\4\&{else} \&{if} $\\{total\_shrink}[\\{fil}]\I0$ \1\&{then}\5
+$\|o\K\\{fil}$\6
+\4\&{else} $\|o\K\\{normal}$\2\2\2\par
+\Us675, 687\ETs807.\fi
+
+\M677. \P$\X677:Report an overfull hbox and \&{goto} \\{common\_ending}, if
+this box is sufficiently bad\X\S$\6
+\&{if} $(-\|x-\\{total\_shrink}[\\{normal}]>\\{hfuzz})\V(\\{hbadness}<100)$ \1%
+\&{then}\6
+\&{begin} \37\&{if} $(\\{overfull\_rule}>0)\W(-\|x-\\{total\_shrink}[%
+\\{normal}]>\\{hfuzz})$ \1\&{then}\6
+\&{begin} \37\&{while} $\\{link}(\|q)\I\\{null}$ \1\&{do}\5
+$\|q\K\\{link}(\|q)$;\2\6
+$\\{link}(\|q)\K\\{new\_rule}$;\5
+$\\{width}(\\{link}(\|q))\K\\{overfull\_rule}$;\6
+\&{end};\2\6
+\\{print\_ln};\5
+$\\{print\_nl}(\.{"Overfull\ \\hbox\ ("})$;\5
+$\\{print\_scaled}(-\|x-\\{total\_shrink}[\\{normal}])$;\5
+$\\{print}(\.{"pt\ too\ wide"})$;\5
+\&{goto} \37\\{common\_ending};\6
+\&{end}\2\par
+\U675.\fi
+
+\M678. \P$\X678:Report a tight hbox and \&{goto} \\{common\_ending}, if this
+box is sufficiently bad\X\S$\6
+\&{begin} \37$\\{last\_badness}\K\\{badness}(-\|x,\39\\{total\_shrink}[%
+\\{normal}])$;\6
+\&{if} $\\{last\_badness}>\\{hbadness}$ \1\&{then}\6
+\&{begin} \37\\{print\_ln};\5
+$\\{print\_nl}(\.{"Tight\ \\hbox\ (badness\ "})$;\5
+$\\{print\_int}(\\{last\_badness})$;\5
+\&{goto} \37\\{common\_ending};\6
+\&{end};\2\6
+\&{end}\par
+\U675.\fi
+
+\M679. The \\{vpack} subroutine is actually a special case of a slightly more
+general routine called \\{vpackage}, which has four parameters. The fourth
+parameter, which is \\{max\_dimen} in the case of \\{vpack}, specifies the
+maximum depth of the page box that is constructed. The depth is first
+computed by the normal rules; if it exceeds this limit, the reference
+point is simply moved down until the limiting depth is attained.
+
+\Y\P\D \37$\\{vpack}(\#)\S\\{vpackage}(\#,\39\\{max\_dimen})$\C{special case of
+unconstrained depth}\par
+\Y\P\4\&{function}\1\  \37$\\{vpackage}(\|p:\\{pointer};\,\35\|h:\\{scaled};\,%
+\35\|m:\\{small\_number};\,\35\|l:\\{scaled})$: \37\\{pointer};\6
+\4\&{label} \37$\\{common\_ending},\39\\{exit}$;\6
+\4\&{var} \37\|r: \37\\{pointer};\C{the box node that will be returned}\6
+$\|w,\39\|d,\39\|x$: \37\\{scaled};\C{width, depth, and natural height}\6
+\|s: \37\\{scaled};\C{shift amount}\6
+\|g: \37\\{pointer};\C{points to a glue specification}\6
+\|o: \37\\{glue\_ord};\C{order of infinity}\2\6
+\&{begin} \37$\\{last\_badness}\K0$;\5
+$\|r\K\\{get\_node}(\\{box\_node\_size})$;\5
+$\\{type}(\|r)\K\\{vlist\_node}$;\5
+$\\{subtype}(\|r)\K\\{min\_quarterword}$;\5
+$\\{shift\_amount}(\|r)\K0$;\5
+$\\{space\_ptr}(\|r)\K\\{zero\_glue}$;\5
+$\\{xspace\_ptr}(\|r)\K\\{zero\_glue}$;\5
+$\\{add\_glue\_ref}(\\{zero\_glue})$;\5
+$\\{add\_glue\_ref}(\\{zero\_glue})$;\5
+$\\{list\_ptr}(\|r)\K\|p$;\6
+$\|w\K0$;\5
+\X661:Clear dimensions to zero\X;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\5
+\X680:Examine node \|p in the vlist, taking account of its effect on the
+dimensions of the new box; then advance \|p to the next node\X;\2\6
+$\\{width}(\|r)\K\|w$;\6
+\&{if} $\|d>\|l$ \1\&{then}\6
+\&{begin} \37$\|x\K\|x+\|d-\|l$;\5
+$\\{depth}(\|r)\K\|l$;\6
+\&{end}\6
+\4\&{else} $\\{depth}(\|r)\K\|d$;\2\6
+\X683:Determine the value of $\\{height}(\|r)$ and the appropriate glue
+setting; then \&{return} or \&{goto} \\{common\_ending}\X;\6
+\4\\{common\_ending}: \37\X686:Finish issuing a diagnostic message for an
+overfull or underfull vbox\X;\6
+\4\\{exit}: \37$\\{vpackage}\K\|r$;\6
+\&{end};\par
+\fi
+
+\M680. \P$\X680:Examine node \|p in the vlist, taking account of its effect on
+the dimensions of the new box; then advance \|p to the next node\X\S$\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\5
+$\\{confusion}(\.{"vpack"})$\6
+\4\&{else} \&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node},\39%
+\\{unset\_node}$: \37\X681:Incorporate box dimensions into the dimensions of
+the vbox that will contain~it\X;\6
+\4\\{whatsit\_node}: \37\X1372:Incorporate a whatsit node into a vbox\X;\6
+\4\\{glue\_node}: \37\X682:Incorporate glue into the vertical totals\X;\6
+\4\\{kern\_node}: \37\&{begin} \37$\|x\K\|x+\|d+\\{width}(\|p)$;\5
+$\|d\K0$;\6
+\&{end};\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\2\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end}\par
+\U679.\fi
+
+\M681. \P$\X681:Incorporate box dimensions into the dimensions of the vbox that
+will contain~it\X\S$\6
+\&{begin} \37$\|x\K\|x+\|d+\\{height}(\|p)$;\5
+$\|d\K\\{depth}(\|p)$;\6
+\&{if} $\\{type}(\|p)\G\\{rule\_node}$ \1\&{then}\5
+$\|s\K0$\ \&{else} $\|s\K\\{shift\_amount}(\|p)$;\2\6
+\&{if} $\\{width}(\|p)+\|s>\|w$ \1\&{then}\5
+$\|w\K\\{width}(\|p)+\|s$;\2\6
+\&{end}\par
+\U680.\fi
+
+\M682. \P$\X682:Incorporate glue into the vertical totals\X\S$\6
+\&{begin} \37$\|x\K\|x+\|d$;\5
+$\|d\K0$;\6
+$\|g\K\\{glue\_ptr}(\|p)$;\5
+$\|x\K\|x+\\{width}(\|g)$;\6
+$\|o\K\\{stretch\_order}(\|g)$;\5
+$\\{total\_stretch}[\|o]\K\\{total\_stretch}[\|o]+\\{stretch}(\|g)$;\5
+$\|o\K\\{shrink\_order}(\|g)$;\5
+$\\{total\_shrink}[\|o]\K\\{total\_shrink}[\|o]+\\{shrink}(\|g)$;\6
+\&{if} $\\{subtype}(\|p)\G\\{a\_leaders}$ \1\&{then}\6
+\&{begin} \37$\|g\K\\{leader\_ptr}(\|p)$;\6
+\&{if} $\\{width}(\|g)>\|w$ \1\&{then}\5
+$\|w\K\\{width}(\|g)$;\2\6
+\&{end};\2\6
+\&{end}\par
+\U680.\fi
+
+\M683. When we get to the present part of the program, \|x is the natural
+height
+of the box being packaged.
+
+\Y\P$\4\X683:Determine the value of $\\{height}(\|r)$ and the appropriate glue
+setting; then \&{return} or \&{goto} \\{common\_ending}\X\S$\6
+\&{if} $\|m=\\{additional}$ \1\&{then}\5
+$\|h\K\|x+\|h$;\2\6
+$\\{height}(\|r)\K\|h$;\5
+$\|x\K\|h-\|x$;\C{now \|x is the excess to be made up}\6
+\&{if} $\|x=0$ \1\&{then}\6
+\&{begin} \37$\\{glue\_sign}(\|r)\K\\{normal}$;\5
+$\\{glue\_order}(\|r)\K\\{normal}$;\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$;\5
+\&{return};\6
+\&{end}\6
+\4\&{else} \&{if} $\|x>0$ \1\&{then}\5
+\X684:Determine vertical glue stretch setting, then \&{return} or \hbox{%
+\&{goto} \\{common\_ending}}\X\6
+\4\&{else} \X687:Determine vertical glue shrink setting, then \&{return} or %
+\hbox{\&{goto} \\{common\_ending}}\X\2\2\par
+\U679.\fi
+
+\M684. \P$\X684:Determine vertical glue stretch setting, then \&{return} or %
+\hbox{\&{goto} \\{common\_ending}}\X\S$\6
+\&{begin} \37\X670:Determine the stretch order\X;\6
+$\\{glue\_order}(\|r)\K\|o$;\5
+$\\{glue\_sign}(\|r)\K\\{stretching}$;\6
+\&{if} $\\{total\_stretch}[\|o]\I0$ \1\&{then}\5
+$\\{glue\_set}(\|r)\K\\{unfloat}(\|x/\\{total\_stretch}[\|o])$\6
+\4\&{else} \&{begin} \37$\\{glue\_sign}(\|r)\K\\{normal}$;\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$;\C{there's nothing to stretch}%
+\6
+\&{end};\2\6
+\&{if} $\|o=\\{normal}$ \1\&{then}\6
+\&{if} $\\{list\_ptr}(\|r)\I\\{null}$ \1\&{then}\5
+\X685:Report an underfull vbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X;\2\2\6
+\&{return};\6
+\&{end}\par
+\U683.\fi
+
+\M685. \P$\X685:Report an underfull vbox and \&{goto} \\{common\_ending}, if
+this box is sufficiently bad\X\S$\6
+\&{begin} \37$\\{last\_badness}\K\\{badness}(\|x,\39\\{total\_stretch}[%
+\\{normal}])$;\6
+\&{if} $\\{last\_badness}>\\{vbadness}$ \1\&{then}\6
+\&{begin} \37\\{print\_ln};\6
+\&{if} $\\{last\_badness}>100$ \1\&{then}\5
+$\\{print\_nl}(\.{"Underfull"})$\ \&{else} $\\{print\_nl}(\.{"Loose"})$;\2\6
+$\\{print}(\.{"\ \\vbox\ (badness\ "})$;\5
+$\\{print\_int}(\\{last\_badness})$;\5
+\&{goto} \37\\{common\_ending};\6
+\&{end};\2\6
+\&{end}\par
+\U684.\fi
+
+\M686. \P$\X686:Finish issuing a diagnostic message for an overfull or
+underfull vbox\X\S$\6
+\&{if} $\\{output\_active}$ \1\&{then}\5
+$\\{print}(\.{")\ has\ occurred\ while\ \\output\ is\ active"})$\6
+\4\&{else} \&{begin} \37\&{if} $\\{pack\_begin\_line}\I0$ \1\&{then}\C{it's
+actually negative}\6
+\&{begin} \37$\\{print}(\.{")\ in\ alignment\ at\ lines\ "})$;\5
+$\\{print\_int}(\\{abs}(\\{pack\_begin\_line}))$;\5
+$\\{print}(\.{"--"})$;\6
+\&{end}\6
+\4\&{else} $\\{print}(\.{")\ detected\ at\ line\ "})$;\2\6
+$\\{print\_int}(\\{line})$;\5
+\\{print\_ln};\6
+\&{end};\2\6
+\\{begin\_diagnostic};\5
+$\\{show\_box}(\|r)$;\5
+$\\{end\_diagnostic}(\\{true})$\par
+\U679.\fi
+
+\M687. \P$\X687:Determine vertical glue shrink setting, then \&{return} or %
+\hbox{\&{goto} \\{common\_ending}}\X\S$\6
+\&{begin} \37\X676:Determine the shrink order\X;\6
+$\\{glue\_order}(\|r)\K\|o$;\5
+$\\{glue\_sign}(\|r)\K\\{shrinking}$;\6
+\&{if} $\\{total\_shrink}[\|o]\I0$ \1\&{then}\5
+$\\{glue\_set}(\|r)\K\\{unfloat}((-\|x)/\\{total\_shrink}[\|o])$\6
+\4\&{else} \&{begin} \37$\\{glue\_sign}(\|r)\K\\{normal}$;\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$;\C{there's nothing to shrink}\6
+\&{end};\2\6
+\&{if} $(\\{total\_shrink}[\|o]<-\|x)\W(\|o=\\{normal})\W(\\{list\_ptr}(\|r)\I%
+\\{null})$ \1\&{then}\6
+\&{begin} \37$\\{last\_badness}\K1000000$;\5
+$\\{set\_glue\_ratio\_one}(\\{glue\_set}(\|r))$;\C{use the maximum shrinkage}\6
+\X688:Report an overfull vbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X;\6
+\&{end}\6
+\4\&{else} \&{if} $\|o=\\{normal}$ \1\&{then}\6
+\&{if} $\\{list\_ptr}(\|r)\I\\{null}$ \1\&{then}\5
+\X689:Report a tight vbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X;\2\2\2\6
+\&{return};\6
+\&{end}\par
+\U683.\fi
+
+\M688. \P$\X688:Report an overfull vbox and \&{goto} \\{common\_ending}, if
+this box is sufficiently bad\X\S$\6
+\&{if} $(-\|x-\\{total\_shrink}[\\{normal}]>\\{vfuzz})\V(\\{vbadness}<100)$ \1%
+\&{then}\6
+\&{begin} \37\\{print\_ln};\5
+$\\{print\_nl}(\.{"Overfull\ \\vbox\ ("})$;\5
+$\\{print\_scaled}(-\|x-\\{total\_shrink}[\\{normal}])$;\5
+$\\{print}(\.{"pt\ too\ high"})$;\5
+\&{goto} \37\\{common\_ending};\6
+\&{end}\2\par
+\U687.\fi
+
+\M689. \P$\X689:Report a tight vbox and \&{goto} \\{common\_ending}, if this
+box is sufficiently bad\X\S$\6
+\&{begin} \37$\\{last\_badness}\K\\{badness}(-\|x,\39\\{total\_shrink}[%
+\\{normal}])$;\6
+\&{if} $\\{last\_badness}>\\{vbadness}$ \1\&{then}\6
+\&{begin} \37\\{print\_ln};\5
+$\\{print\_nl}(\.{"Tight\ \\vbox\ (badness\ "})$;\5
+$\\{print\_int}(\\{last\_badness})$;\5
+\&{goto} \37\\{common\_ending};\6
+\&{end};\2\6
+\&{end}\par
+\U687.\fi
+
+\M690. When a box is being appended to the current vertical list, the
+baselineskip calculation is handled by the \\{append\_to\_vlist} routine.
+
+\Y\P\4\&{procedure}\1\  \37$\\{append\_to\_vlist}(\|b:\\{pointer})$;\6
+\4\&{var} \37\|d: \37\\{scaled};\C{deficiency of space between baselines}\6
+\|p: \37\\{pointer};\C{a new glue node}\2\6
+\&{begin} \37\&{if} $\\{prev\_depth}>\\{ignore\_depth}$ \1\&{then}\6
+\&{begin} \37$\|d\K\\{width}(\\{baseline\_skip})-\\{prev\_depth}-\\{height}(%
+\|b)$;\6
+\&{if} $\|d<\\{line\_skip\_limit}$ \1\&{then}\5
+$\|p\K\\{new\_param\_glue}(\\{line\_skip\_code})$\6
+\4\&{else} \&{begin} \37$\|p\K\\{new\_skip\_param}(\\{baseline\_skip\_code})$;\5
+$\\{width}(\\{temp\_ptr})\K\|d$;\C{$\\{temp\_ptr}=\\{glue\_ptr}(\|p)$}\6
+\&{end};\2\6
+$\\{link}(\\{tail})\K\|p$;\5
+$\\{tail}\K\|p$;\6
+\&{end};\2\6
+$\\{link}(\\{tail})\K\|b$;\5
+$\\{tail}\K\|b$;\5
+$\\{prev\_depth}\K\\{depth}(\|b)$;\6
+\&{end};\par
+\fi
+
+\N691.  \[34] Data structures for math mode.
+When \TeX\ reads a formula that is enclosed between \.\$'s, it constructs an
+{\sl mlist}, which is essentially a tree structure representing that
+formula.  An mlist is a linear sequence of items, but we can regard it as
+a tree structure because mlists can appear within mlists. For example, many
+of the entries can be subscripted or superscripted, and such ``scripts''
+are mlists in their own right.
+
+An entire formula is parsed into such a tree before any of the actual
+typesetting is done, because the current style of type is usually not
+known until the formula has been fully scanned. For example, when the
+formula `\.{\$a+b \\over c+d\$}' is being read, there is no way to tell
+that `\.{a+b}' will be in script size until `\.{\\over}' has appeared.
+
+During the scanning process, each element of the mlist being built is
+classified as a relation, a binary operator, an open parenthesis, etc.,
+or as a construct like `\.{\\sqrt}' that must be built up. This classification
+appears in the mlist data structure.
+
+After a formula has been fully scanned, the mlist is converted to an hlist
+so that it can be incorporated into the surrounding text. This conversion is
+controlled by a recursive procedure that decides all of the appropriate
+styles by a ``top-down'' process starting at the outermost level and working
+in towards the subformulas. The formula is ultimately pasted together using
+combinations of horizontal and vertical boxes, with glue and penalty nodes
+inserted as necessary.
+
+An mlist is represented internally as a linked list consisting chiefly
+of ``noads'' (pronounced ``no-adds''), to distinguish them from the somewhat
+similar ``nodes'' in hlists and vlists. Certain kinds of ordinary nodes are
+allowed to appear in mlists together with the noads; \TeX\ tells the difference
+by means of the \\{type} field, since a noad's \\{type} is always greater than
+that of a node. An mlist does not contain character nodes, hlist nodes, vlist
+nodes, math nodes, ligature nodes,
+or unset nodes; in particular, each mlist item appears in the
+variable-size part of \\{mem}, so the \\{type} field is always present.
+
+\fi
+
+\M692. Each noad is four or more words long. The first word contains the %
+\\{type}
+and \\{subtype} and \\{link} fields that are already so familiar to us; the
+second, third, and fourth words are called the noad's \\{nucleus}, \\{subscr},
+and \\{supscr} fields.
+
+Consider, for example, the simple formula `\.{\$x\^2\$}', which would be
+parsed into an mlist containing a single element called an \\{ord\_noad}.
+The \\{nucleus} of this noad is a representation of `\.x', the \\{subscr} is
+empty, and the \\{supscr} is a representation of `\.2'.
+
+The \\{nucleus}, \\{subscr}, and \\{supscr} fields are further broken into
+subfields. If \|p points to a noad, and if \|q is one of its principal
+fields (e.g., $\|q=\\{subscr}(\|p)$), there are several possibilities for the
+subfields, depending on the \\{math\_type} of \|q.
+
+\yskip\hang$\\{math\_type}(\|q)=\\{math\_char}$ means that $\\{fam}(\|q)$
+refers to one of
+the sixteen font families, and $\\{character}(\|q)$ is the number of a
+character
+within a font of that family, as in a character node.
+
+\yskip\hang$\\{math\_type}(\|q)=\\{math\_text\_char}$ is similar, but the
+character is
+unsubscripted and unsuperscripted and it is followed immediately by another
+character from the same font. (This \\{math\_type} setting appears only
+briefly during the processing; it is used to suppress unwanted italic
+corrections.)
+
+\yskip\hang$\\{math\_type}(\|q)=\\{empty}$ indicates a field with no value (the
+corresponding attribute of noad \|p is not present).
+
+\yskip\hang$\\{math\_type}(\|q)=\\{sub\_box}$ means that $\\{info}(\|q)$ points
+to a box
+node (either an \\{hlist\_node} or a \\{vlist\_node}) that should be used as
+the
+value of the field.  The \\{shift\_amount} in the subsidiary box node is the
+amount by which that box will be shifted downward.
+
+\yskip\hang$\\{math\_type}(\|q)=\\{sub\_mlist}$ means that $\\{info}(\|q)$
+points to
+an mlist; the mlist must be converted to an hlist in order to obtain
+the value of this field.
+
+\yskip\noindent In the latter case, we might have $\\{info}(\|q)=\\{null}$.
+This
+is not the same as $\\{math\_type}(\|q)=\\{empty}$; for example, `\.{\$P\_\{\}%
+\$}'
+and `\.{\$P\$}' produce different results (the former will not have the
+``italic correction'' added to the width of \|P, but the ``script skip''
+will be added).
+
+The definitions of subfields given here are evidently wasteful of space,
+since a halfword is being used for the \\{math\_type} although only three
+bits would be needed. However, there are hardly ever many noads present at
+once, since they are soon converted to nodes that take up even more space,
+so we can afford to represent them in whatever way simplifies the
+programming.
+
+\yskip\hang In Japanese, $\\{math\_type}(\|q)=\\{math\_jchar}$ means that $%
+\\{fam}(\|q)$
+refers to one of the sixteen kanji font families, and $\\{KANJI}(\|q)$ is the
+internal kanji code number.
+
+\Y\P\D \37$\\{noad\_size}=5$\C{number of words in a normal noad}\par
+\P\D \37$\\{nucleus}(\#)\S\#+1$\C{the \\{nucleus} field of a noad}\par
+\P\D \37$\\{supscr}(\#)\S\#+2$\C{the \\{supscr} field of a noad}\par
+\P\D \37$\\{subscr}(\#)\S\#+3$\C{the \\{subscr} field of a noad}\par
+\P\D \37$\\{kcode\_noad}(\#)\S\#+4$\par
+\P\D \37$\\{math\_kcode}(\#)\S\\{info}(\#+4)$\C{the \\{kanji}\\{character}
+field of a noad}\par
+\P\D \37$\\{kcode\_noad\_nucleus}(\#)\S\#+3$\par
+\P\D \37$\\{math\_kcode\_nucleus}(\#)\S\\{info}(\#+3)$\C{the \\{kanji}%
+\\{character} field offset from nucleus}\Y\par
+\P\D \37$\\{math\_jchar}=5$\par
+\P\D \37$\\{math\_text\_jchar}=6$\par
+\P\D \37$\\{math\_type}\S\\{link}$\C{a \\{halfword} in \\{mem}}\par
+\P\D \37$\\{fam}\S\\{font}$\C{a \\{quarterword} in \\{mem}}\par
+\P\D \37$\\{math\_char}=1$\C{\\{math\_type} when the attribute is simple}\par
+\P\D \37$\\{sub\_box}=2$\C{\\{math\_type} when the attribute is a box}\par
+\P\D \37$\\{sub\_mlist}=3$\C{\\{math\_type} when the attribute is a formula}\par
+\P\D \37$\\{math\_text\_char}=4$\C{\\{math\_type} when italic correction is
+dubious}\par
+\fi
+
+\M693. Each portion of a formula is classified as Ord, Op, Bin, Rel, Ope,
+Clo, Pun, or Inn, for purposes of spacing and line breaking. An
+\\{ord\_noad}, \\{op\_noad}, \\{bin\_noad}, \\{rel\_noad}, \\{open\_noad}, %
+\\{close\_noad},
+\\{punct\_noad}, or \\{inner\_noad} is used to represent portions of the
+various
+types. For example, an `\.=' sign in a formula leads to the creation of a
+\\{rel\_noad} whose \\{nucleus} field is a representation of an equals sign
+(usually $\\{fam}=0$, $\\{character}=\O{75}$).  A formula preceded by \.{%
+\\mathrel}
+also results in a \\{rel\_noad}.  When a \\{rel\_noad} is followed by an
+\\{op\_noad}, say, and possibly separated by one or more ordinary nodes (not
+noads), \TeX\ will insert a penalty node (with the current \\{rel\_penalty})
+just after the formula that corresponds to the \\{rel\_noad}, unless there
+already was a penalty immediately following; and a ``thick space'' will be
+inserted just before the formula that corresponds to the \\{op\_noad}.
+
+A noad of type \\{ord\_noad}, \\{op\_noad}, \dots, \\{inner\_noad} usually
+has a $\\{subtype}=\\{normal}$. The only exception is that an \\{op\_noad}
+might
+have $\\{subtype}=\\{limits}$ or \\{no\_limits}, if the normal positioning of
+limits has been overridden for this operator.
+
+\Y\P\D \37$\\{ord\_noad}=\\{unset\_node}+3$\C{\\{type} of a noad classified
+Ord}\par
+\P\D \37$\\{op\_noad}=\\{ord\_noad}+1$\C{\\{type} of a noad classified Op}\par
+\P\D \37$\\{bin\_noad}=\\{ord\_noad}+2$\C{\\{type} of a noad classified Bin}\par
+\P\D \37$\\{rel\_noad}=\\{ord\_noad}+3$\C{\\{type} of a noad classified Rel}\par
+\P\D \37$\\{open\_noad}=\\{ord\_noad}+4$\C{\\{type} of a noad classified Ope}%
+\par
+\P\D \37$\\{close\_noad}=\\{ord\_noad}+5$\C{\\{type} of a noad classified Clo}%
+\par
+\P\D \37$\\{punct\_noad}=\\{ord\_noad}+6$\C{\\{type} of a noad classified Pun}%
+\par
+\P\D \37$\\{inner\_noad}=\\{ord\_noad}+7$\C{\\{type} of a noad classified Inn}%
+\par
+\P\D \37$\\{limits}=1$\C{\\{subtype} of \\{op\_noad} whose scripts are to be
+above, below}\par
+\P\D \37$\\{no\_limits}=2$\C{\\{subtype} of \\{op\_noad} whose scripts are to
+be normal}\par
+\fi
+
+\M694. A \\{radical\_noad} is five words long; the fifth word is the \\{left%
+\_delimiter}
+field, which usually represents a square root sign.
+
+A \\{fraction\_noad} is six words long; it has a \\{right\_delimiter} field
+as well as a \\{left\_delimiter}.
+
+Delimiter fields are of type \\{four\_quarters}, and they have four subfields
+called \\{small\_fam}, \\{small\_char}, \\{large\_fam}, \\{large\_char}. These
+subfields
+represent variable-size delimiters by giving the ``small'' and ``large''
+starting characters, as explained in Chapter~17 of {\sl The \TeX book}.
+
+A \\{fraction\_noad} is actually quite different from all other noads. Not
+only does it have six words, it has \\{thickness}, \\{denominator}, and
+\\{numerator} fields instead of \\{nucleus}, \\{subscr}, and \\{supscr}. The
+\\{thickness} is a scaled value that tells how thick to make a fraction
+rule; however, the special value \\{default\_code} is used to stand for the
+\\{default\_rule\_thickness} of the current size. The \\{numerator} and
+\\{denominator} point to mlists that define a fraction; we always have
+$$\hbox{$\\{math\_type}(\\{numerator})=\\{math\_type}(\\{denominator})=\\{sub%
+\_mlist}$}.$$ The
+\\{left\_delimiter} and \\{right\_delimiter} fields specify delimiters that
+will
+be placed at the left and right of the fraction. In this way, a
+\\{fraction\_noad} is able to represent all of \TeX's operators \.{\\over},
+\.{\\atop}, \.{\\above}, \.{\\overwithdelims}, \.{\\atopwithdelims}, and
+\.{\\abovewithdelims}.
+
+\Y\P\D \37$\\{left\_delimiter}(\#)\S\#+5$\C{first delimiter field of a noad}\par
+\P\D \37$\\{right\_delimiter}(\#)\S\#+4$\C{second delimiter field of a fraction
+noad}\par
+\P\D \37$\\{radical\_noad}=\\{inner\_noad}+1$\C{\\{type} of a noad for square
+roots}\par
+\P\D \37$\\{radical\_noad\_size}=6$\C{number of \\{mem} words in a radical
+noad}\par
+\P\D \37$\\{fraction\_noad}=\\{radical\_noad}+1$\C{\\{type} of a noad for
+generalized fractions}\par
+\P\D \37$\\{fraction\_noad\_size}=6$\C{number of \\{mem} words in a fraction
+noad}\par
+\P\D \37$\\{small\_fam}(\#)\S\\{mem}[\#].\\{qqqq}.\\{b0}$\C{\\{fam} for
+``small'' delimiter}\par
+\P\D \37$\\{small\_char}(\#)\S\\{mem}[\#].\\{qqqq}.\\{b1}$\C{\\{character} for
+``small'' delimiter}\par
+\P\D \37$\\{large\_fam}(\#)\S\\{mem}[\#].\\{qqqq}.\\{b2}$\C{\\{fam} for
+``large'' delimiter}\par
+\P\D \37$\\{large\_char}(\#)\S\\{mem}[\#].\\{qqqq}.\\{b3}$\C{\\{character} for
+``large'' delimiter}\par
+\P\D \37$\\{thickness}\S\\{width}$\C{\\{thickness} field in a fraction noad}\par
+\P\D \37$\\{default\_code}\S\O{10000000000}$\C{denotes \\{default\_rule%
+\_thickness}}\par
+\P\D \37$\\{numerator}\S\\{supscr}$\C{\\{numerator} field in a fraction noad}%
+\par
+\P\D \37$\\{denominator}\S\\{subscr}$\C{\\{denominator} field in a fraction
+noad}\par
+\fi
+
+\M695. The global variable \\{empty\_field} is set up for initialization of
+empty
+fields in new noads. Similarly, \\{null\_delimiter} is for the initialization
+of delimiter fields.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{empty\_field}: \37\\{two\_halves};\6
+\4\\{null\_delimiter}: \37\\{four\_quarters};\par
+\fi
+
+\M696. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{empty\_field}.\\{rh}\K\\{empty}$;\5
+$\\{empty\_field}.\\{lh}\K\\{null}$;\6
+$\\{null\_delimiter}.\\{b0}\K0$;\5
+$\\{null\_delimiter}.\\{b1}\K\\{min\_quarterword}$;\6
+$\\{null\_delimiter}.\\{b2}\K0$;\5
+$\\{null\_delimiter}.\\{b3}\K\\{min\_quarterword}$;\par
+\fi
+
+\M697. The \\{new\_noad} function creates an \\{ord\_noad} that is completely
+null.
+
+\Y\P\4\&{function}\1\  \37\\{new\_noad}: \37\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{noad\_size})$;\5
+$\\{type}(\|p)\K\\{ord\_noad}$;\5
+$\\{subtype}(\|p)\K\\{normal}$;\5
+$\\{mem}[\\{nucleus}(\|p)].\\{hh}\K\\{empty\_field}$;\5
+$\\{mem}[\\{subscr}(\|p)].\\{hh}\K\\{empty\_field}$;\5
+$\\{mem}[\\{supscr}(\|p)].\\{hh}\K\\{empty\_field}$;\5
+$\\{mem}[\\{kcode\_noad}(\|p)].\\{hh}\K\\{empty\_field}$;\5
+$\\{new\_noad}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M698. A few more kinds of noads will complete the set: An \\{under\_noad} has
+its
+nucleus underlined; an \\{over\_noad} has it overlined. An \\{accent\_noad}
+places
+an accent over its nucleus; the accent character appears as
+$\\{fam}(\\{accent\_chr}(\|p))$ and $\\{character}(\\{accent\_chr}(\|p))$. A %
+\\{vcenter\_noad}
+centers its nucleus vertically with respect to the axis of the formula;
+in such noads we always have $\\{math\_type}(\\{nucleus}(\|p))=\\{sub\_box}$.
+
+And finally, we have \\{left\_noad} and \\{right\_noad} types, to implement
+\TeX's \.{\\left} and \.{\\right}. The \\{nucleus} of such noads is
+replaced by a \\{delimiter} field; thus, for example, `\.{\\left(}' produces
+a \\{left\_noad} such that $\\{delimiter}(\|p)$ holds the family and character
+codes for all left parentheses. A \\{left\_noad} never appears in an mlist
+except as the first element, and a \\{right\_noad} never appears in an mlist
+except as the last element; furthermore, we either have both a \\{left\_noad}
+and a \\{right\_noad}, or neither one is present. The \\{subscr} and \\{supscr}
+fields are always \\{empty} in a \\{left\_noad} and a \\{right\_noad}.
+
+\Y\P\D \37$\\{under\_noad}=\\{fraction\_noad}+1$\C{\\{type} of a noad for
+underlining}\par
+\P\D \37$\\{over\_noad}=\\{under\_noad}+1$\C{\\{type} of a noad for overlining}%
+\par
+\P\D \37$\\{accent\_noad}=\\{over\_noad}+1$\C{\\{type} of a noad for accented
+subformulas}\par
+\P\D \37$\\{accent\_noad\_size}=6$\C{number of \\{mem} words in an accent noad}%
+\par
+\P\D \37$\\{accent\_chr}(\#)\S\#+5$\C{the \\{accent\_chr} field of an accent
+noad}\par
+\P\D \37$\\{vcenter\_noad}=\\{accent\_noad}+1$\C{\\{type} of a noad for \.{%
+\\vcenter}}\par
+\P\D \37$\\{left\_noad}=\\{vcenter\_noad}+1$\C{\\{type} of a noad for \.{%
+\\left}}\par
+\P\D \37$\\{right\_noad}=\\{left\_noad}+1$\C{\\{type} of a noad for \.{%
+\\right}}\par
+\P\D \37$\\{delimiter}\S\\{nucleus}$\C{\\{delimiter} field in left and right
+noads}\par
+\P\D \37$\\{scripts\_allowed}(\#)\S(\\{type}(\#)\G\\{ord\_noad})\W(\\{type}(%
+\#)<\\{left\_noad})$\par
+\fi
+
+\M699. Math formulas can also contain instructions like \.{\\textstyle} that
+override \TeX's normal style rules. A \\{style\_node} is inserted into the
+data structure to record such instructions; it is three words long, so it
+is considered a node instead of a noad. The \\{subtype} is either \\{display%
+\_style}
+or \\{text\_style} or \\{script\_style} or \\{script\_script\_style}. The
+second and third words of a \\{style\_node} are not used, but they are
+present because a \\{choice\_node} is converted to a \\{style\_node}.
+
+\TeX\ uses even numbers 0, 2, 4, 6 to encode the basic styles
+\\{display\_style}, \dots, \\{script\_script\_style}, and adds~1 to get the
+``cramped'' versions of these styles. This gives a numerical order that
+is backwards from the convention of Appendix~G in {\sl The \TeX book\/};
+i.e., a smaller style has a larger numerical value.
+
+\Y\P\D \37$\\{style\_node}=\\{unset\_node}+1$\C{\\{type} of a style node}\par
+\P\D \37$\\{style\_node\_size}=3$\C{number of words in a style node}\par
+\P\D \37$\\{display\_style}=0$\C{\\{subtype} for \.{\\displaystyle}}\par
+\P\D \37$\\{text\_style}=2$\C{\\{subtype} for \.{\\textstyle}}\par
+\P\D \37$\\{script\_style}=4$\C{\\{subtype} for \.{\\scriptstyle}}\par
+\P\D \37$\\{script\_script\_style}=6$\C{\\{subtype} for \.{%
+\\scriptscriptstyle}}\par
+\P\D \37$\\{cramped}=1$\C{add this to an uncramped style if you want to cramp
+it}\par
+\Y\P\4\&{function}\1\  \37$\\{new\_style}(\|s:\\{small\_number})$: \37%
+\\{pointer};\C{create a style node}\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{style\_node\_size})$;\5
+$\\{type}(\|p)\K\\{style\_node}$;\5
+$\\{subtype}(\|p)\K\|s$;\5
+$\\{width}(\|p)\K0$;\5
+$\\{depth}(\|p)\K0$;\C{the \\{width} and \\{depth} are not used}\6
+$\\{new\_style}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M700. Finally, the \.{\\mathchoice} primitive creates a \\{choice\_node},
+which
+has special subfields \\{display\_mlist}, \\{text\_mlist}, \\{script\_mlist},
+and \\{script\_script\_mlist} pointing to the mlists for each style.
+
+\Y\P\D \37$\\{choice\_node}=\\{unset\_node}+2$\C{\\{type} of a choice node}\par
+\P\D \37$\\{display\_mlist}(\#)\S\\{info}(\#+1)$\C{mlist to be used in display
+style}\par
+\P\D \37$\\{text\_mlist}(\#)\S\\{link}(\#+1)$\C{mlist to be used in text style}%
+\par
+\P\D \37$\\{script\_mlist}(\#)\S\\{info}(\#+2)$\C{mlist to be used in script
+style}\par
+\P\D \37$\\{script\_script\_mlist}(\#)\S\\{link}(\#+2)$\C{mlist to be used in
+scriptscript style}\par
+\Y\P\4\&{function}\1\  \37\\{new\_choice}: \37\\{pointer};\C{create a choice
+node}\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{style\_node\_size})$;\5
+$\\{type}(\|p)\K\\{choice\_node}$;\5
+$\\{subtype}(\|p)\K0$;\C{the \\{subtype} is not used}\6
+$\\{display\_mlist}(\|p)\K\\{null}$;\5
+$\\{text\_mlist}(\|p)\K\\{null}$;\5
+$\\{script\_mlist}(\|p)\K\\{null}$;\5
+$\\{script\_script\_mlist}(\|p)\K\\{null}$;\5
+$\\{new\_choice}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M701. Let's consider now the previously unwritten part of \\{show\_node\_list}
+that displays the things that can only be present in mlists; this
+program illustrates how to access the data structures just defined.
+
+In the context of the following program, \|p points to a node or noad that
+should be displayed, and the current string contains the ``recursion history''
+that leads to this point. The recursion history consists of a dot for each
+outer level in which \|p is subsidiary to some node, or in which \|p is
+subsidiary to the \\{nucleus} field of some noad; the dot is replaced by
+`\.\_' or `\.\^' or `\./' or `\.\\' if \|p is descended from the \\{subscr}
+or \\{supscr} or \\{denominator} or \\{numerator} fields of noads. For example,
+the current string would be `\.{.\^.\_/}' if \|p points to the \\{ord\_noad}
+for
+\|x in the (ridiculous) formula
+`\.{\$\\sqrt\{a\^\{\\mathinner\{b\_\{c\\over x+y\}\}\}\}\$}'.
+
+\Y\P$\4\X701:Cases of \\{show\_node\_list} that arise in mlists only\X\S$\6
+\4\\{style\_node}: \37$\\{print\_style}(\\{subtype}(\|p))$;\6
+\4\\{choice\_node}: \37\X706:Display choice node \|p\X;\6
+\4$\\{ord\_noad},\39\\{op\_noad},\39\\{bin\_noad},\39\\{rel\_noad},\39\\{open%
+\_noad},\39\\{close\_noad},\39\\{punct\_noad},\39\\{inner\_noad},\39\\{radical%
+\_noad},\39\\{over\_noad},\39\\{under\_noad},\39\\{vcenter\_noad},\39\\{accent%
+\_noad},\39\\{left\_noad},\39\\{right\_noad}$: \37\X707:Display normal noad \|p%
+\X;\6
+\4\\{fraction\_noad}: \37\X708:Display fraction noad \|p\X;\par
+\U189.\fi
+
+\M702. Here are some simple routines used in the display of noads.
+
+\Y\P$\4\X702:Declare procedures needed for displaying the elements of mlists\X%
+\S$\6
+\4\&{procedure}\1\  \37$\\{print\_fam\_and\_char}(\|p:\\{pointer};\,\35\|t:%
+\\{small\_number})$;\C{prints family and character}\6
+\4\&{var} \37\\{cx}: \37\\{KANJI\_code};\C{temporary register for KANJI}\2\6
+\&{begin} \37$\\{print\_esc}(\.{"fam"})$;\5
+$\\{print\_int}(\\{fam}(\|p))$;\5
+$\\{print\_char}(\.{"\ "})$;\6
+\&{if} $\|t=\\{math\_char}$ \1\&{then}\5
+$\\{print\_ASCII}(\\{qo}(\\{character}(\|p)))$\6
+\4\&{else} \&{begin} \37$\\{KANJI}(\\{cx})\K\\{math\_kcode\_nucleus}(\|p)$;\5
+$\\{print\_kanji}(\\{cx})$;\6
+\&{end};\2\6
+\&{end};\7
+\4\&{procedure}\1\  \37$\\{print\_delimiter}(\|p:\\{pointer})$;\C{prints a
+delimiter as 24-bit hex value}\6
+\4\&{var} \37\|a: \37\\{integer};\C{accumulator}\2\6
+\&{begin} \37$\|a\K\\{small\_fam}(\|p)\ast256+\\{qo}(\\{small\_char}(\|p))$;\5
+$\|a\K\|a\ast\H{1000}+\\{large\_fam}(\|p)\ast256+\\{qo}(\\{large\_char}(\|p))$;%
+\6
+\&{if} $\|a<0$ \1\&{then}\5
+$\\{print\_int}(\|a)$\C{this should never happen}\6
+\4\&{else} $\\{print\_hex}(\|a)$;\2\6
+\&{end};\par
+\As703\ET705.
+\U185.\fi
+
+\M703. The next subroutine will descend to another level of recursion when a
+subsidiary mlist needs to be displayed. The parameter \|c indicates what
+character is to become part of the recursion history. An empty mlist is
+distinguished from a field with $\\{math\_type}(\|p)=\\{empty}$, because these
+are
+not equivalent (as explained above).
+
+\Y\P$\4\X702:Declare procedures needed for displaying the elements of mlists\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{show\_info};\5
+\\{forward};\5
+\hbox{\2}\C{$\\{show\_node\_list}(\\{info}(\\{temp\_ptr}))$}\6
+\4\&{procedure}\1\  \37$\\{print\_subsidiary\_data}(\|p:\\{pointer};\,\35\|c:%
+\\{ASCII\_code})$;\C{display a noad field}\2\6
+\&{begin} \37\&{if} $\\{cur\_length}\G\\{depth\_threshold}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{math\_type}(\|p)\I\\{empty}$ \1\&{then}\5
+$\\{print}(\.{"\ []"})$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{append\_char}(\|c)$;\C{include \|c in the recursion
+history}\6
+$\\{temp\_ptr}\K\|p$;\C{prepare for \\{show\_info} if recursion is needed}\6
+\&{case} $\\{math\_type}(\|p)$ \1\&{of}\6
+\4$\\{math\_char},\39\\{math\_jchar}$: \37\&{begin} \37\\{print\_ln};\5
+\\{print\_current\_string};\5
+$\\{print\_fam\_and\_char}(\|p,\39\\{math\_type}(\|p))$;\6
+\&{end};\6
+\4\\{sub\_box}: \37\\{show\_info};\C{recursive call}\6
+\4\\{sub\_mlist}: \37\&{if} $\\{info}(\|p)=\\{null}$ \1\&{then}\6
+\&{begin} \37\\{print\_ln};\5
+\\{print\_current\_string};\5
+$\\{print}(\.{"\{\}"})$;\6
+\&{end}\6
+\4\&{else} \\{show\_info};\C{recursive call}\2\6
+\4\&{othercases} \37\\{do\_nothing}\C{\\{empty}}\2\6
+\&{endcases};\6
+\\{flush\_char};\C{remove \|c from the recursion history}\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M704. The inelegant introduction of \\{show\_info} in the code above seems
+better
+than the alternative of using \PASCAL's strange \\{forward} declaration for a
+procedure with parameters. The \PASCAL\ convention about dropping parameters
+from a post-\\{forward} procedure is, frankly, so intolerable to the author
+of \TeX\ that he would rather stoop to communication via a global temporary
+variable. (A similar stoopidity occurred with respect to \\{hlist\_out} and
+\\{vlist\_out} above, and it will occur with respect to \\{mlist\_to\_hlist}
+below.)
+
+\Y\P\4\&{procedure}\1\  \37\\{show\_info};\C{the reader will kindly forgive
+this}\2\6
+\&{begin} \37$\\{show\_node\_list}(\\{info}(\\{temp\_ptr}))$;\6
+\&{end};\par
+\fi
+
+\M705. \P$\X702:Declare procedures needed for displaying the elements of mlists%
+\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_style}(\|c:\\{integer})$;\2\6
+\&{begin} \37\&{case} $\|c\mathbin{\&{div}}2$ \1\&{of}\6
+\40: \37$\\{print\_esc}(\.{"displaystyle"})$;\C{$\\{display\_style}=0$}\6
+\41: \37$\\{print\_esc}(\.{"textstyle"})$;\C{$\\{text\_style}=2$}\6
+\42: \37$\\{print\_esc}(\.{"scriptstyle"})$;\C{$\\{script\_style}=4$}\6
+\43: \37$\\{print\_esc}(\.{"scriptscriptstyle"})$;\C{$\\{script\_script%
+\_style}=6$}\6
+\4\&{othercases} \37$\\{print}(\.{"Unknown\ style!"})$\2\6
+\&{endcases};\6
+\&{end};\par
+\fi
+
+\M706. \P$\X706:Display choice node \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{"mathchoice"})$;\5
+$\\{append\_char}(\.{"D"})$;\5
+$\\{show\_node\_list}(\\{display\_mlist}(\|p))$;\5
+\\{flush\_char};\5
+$\\{append\_char}(\.{"T"})$;\5
+$\\{show\_node\_list}(\\{text\_mlist}(\|p))$;\5
+\\{flush\_char};\5
+$\\{append\_char}(\.{"S"})$;\5
+$\\{show\_node\_list}(\\{script\_mlist}(\|p))$;\5
+\\{flush\_char};\5
+$\\{append\_char}(\.{"s"})$;\5
+$\\{show\_node\_list}(\\{script\_script\_mlist}(\|p))$;\5
+\\{flush\_char};\6
+\&{end}\par
+\U701.\fi
+
+\M707. \P$\X707:Display normal noad \|p\X\S$\6
+\&{begin} \37\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4\\{ord\_noad}: \37$\\{print\_esc}(\.{"mathord"})$;\6
+\4\\{op\_noad}: \37$\\{print\_esc}(\.{"mathop"})$;\6
+\4\\{bin\_noad}: \37$\\{print\_esc}(\.{"mathbin"})$;\6
+\4\\{rel\_noad}: \37$\\{print\_esc}(\.{"mathrel"})$;\6
+\4\\{open\_noad}: \37$\\{print\_esc}(\.{"mathopen"})$;\6
+\4\\{close\_noad}: \37$\\{print\_esc}(\.{"mathclose"})$;\6
+\4\\{punct\_noad}: \37$\\{print\_esc}(\.{"mathpunct"})$;\6
+\4\\{inner\_noad}: \37$\\{print\_esc}(\.{"mathinner"})$;\6
+\4\\{over\_noad}: \37$\\{print\_esc}(\.{"overline"})$;\6
+\4\\{under\_noad}: \37$\\{print\_esc}(\.{"underline"})$;\6
+\4\\{vcenter\_noad}: \37$\\{print\_esc}(\.{"vcenter"})$;\6
+\4\\{radical\_noad}: \37\&{begin} \37$\\{print\_esc}(\.{"radical"})$;\5
+$\\{print\_delimiter}(\\{left\_delimiter}(\|p))$;\6
+\&{end};\6
+\4\\{accent\_noad}: \37\&{begin} \37$\\{print\_esc}(\.{"accent"})$;\5
+$\\{print\_fam\_and\_char}(\\{accent\_chr}(\|p),\39\\{math\_char})$;\6
+\&{end};\6
+\4\\{left\_noad}: \37\&{begin} \37$\\{print\_esc}(\.{"left"})$;\5
+$\\{print\_delimiter}(\\{delimiter}(\|p))$;\6
+\&{end};\6
+\4\\{right\_noad}: \37\&{begin} \37$\\{print\_esc}(\.{"right"})$;\5
+$\\{print\_delimiter}(\\{delimiter}(\|p))$;\6
+\&{end};\2\6
+\&{end};\6
+\&{if} $\\{subtype}(\|p)\I\\{normal}$ \1\&{then}\6
+\&{if} $\\{subtype}(\|p)=\\{limits}$ \1\&{then}\5
+$\\{print\_esc}(\.{"limits"})$\6
+\4\&{else} $\\{print\_esc}(\.{"nolimits"})$;\2\2\6
+\&{if} $\\{type}(\|p)<\\{left\_noad}$ \1\&{then}\5
+$\\{print\_subsidiary\_data}(\\{nucleus}(\|p),\39\.{"."})$;\2\6
+$\\{print\_subsidiary\_data}(\\{supscr}(\|p),\39\.{"\^"})$;\5
+$\\{print\_subsidiary\_data}(\\{subscr}(\|p),\39\.{"\_"})$;\6
+\&{end}\par
+\U701.\fi
+
+\M708. \P$\X708:Display fraction noad \|p\X\S$\6
+\&{begin} \37$\\{print\_esc}(\.{"fraction,\ thickness\ "})$;\6
+\&{if} $\\{thickness}(\|p)=\\{default\_code}$ \1\&{then}\5
+$\\{print}(\.{"=\ default"})$\6
+\4\&{else} $\\{print\_scaled}(\\{thickness}(\|p))$;\2\6
+\&{if} $(\\{small\_fam}(\\{left\_delimiter}(\|p))\I0)\V$\ $(\\{small\_char}(%
+\\{left\_delimiter}(\|p))\I\\{min\_quarterword})\V\30(\\{large\_fam}(\\{left%
+\_delimiter}(\|p))\I0)\V\30(\\{large\_char}(\\{left\_delimiter}(\|p))\I\\{min%
+\_quarterword})$ \&{then} \6
+\&{begin} \37$\\{print}(\.{",\ left-delimiter\ "})$;\5
+$\\{print\_delimiter}(\\{left\_delimiter}(\|p))$;\6
+\&{end};\6
+\&{if} $(\\{small\_fam}(\\{right\_delimiter}(\|p))\I0)\V\30(\\{small\_char}(%
+\\{right\_delimiter}(\|p))\I\\{min\_quarterword})\V\30(\\{large\_fam}(\\{right%
+\_delimiter}(\|p))\I0)\V\30(\\{large\_char}(\\{right\_delimiter}(\|p))\I\\{min%
+\_quarterword})$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{",\ right-delimiter\ "})$;\5
+$\\{print\_delimiter}(\\{right\_delimiter}(\|p))$;\6
+\&{end};\2\6
+$\\{print\_subsidiary\_data}(\\{numerator}(\|p),\39\.{"\\"})$;\5
+$\\{print\_subsidiary\_data}(\\{denominator}(\|p),\39\.{"/"})$; \6
+\&{end} \par
+\U701.\fi
+
+\M709. That which can be displayed can also be destroyed.
+
+\Y\P$\4\X709:Cases of \\{flush\_node\_list} that arise in mlists only\X\S$\6
+\4\\{style\_node}: \37\&{begin} \37$\\{free\_node}(\|p,\39\\{style\_node%
+\_size})$;\5
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4\\{choice\_node}: \37\&{begin} \37$\\{flush\_node\_list}(\\{display\_mlist}(%
+\|p))$;\5
+$\\{flush\_node\_list}(\\{text\_mlist}(\|p))$;\5
+$\\{flush\_node\_list}(\\{script\_mlist}(\|p))$;\5
+$\\{flush\_node\_list}(\\{script\_script\_mlist}(\|p))$;\5
+$\\{free\_node}(\|p,\39\\{style\_node\_size})$;\5
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4$\\{ord\_noad},\39\\{op\_noad},\39\\{bin\_noad},\39\\{rel\_noad},\39\\{open%
+\_noad},\39\\{close\_noad},\39\\{punct\_noad},\39\\{inner\_noad},\39\\{radical%
+\_noad},\39\\{over\_noad},\39\\{under\_noad},\39\\{vcenter\_noad},\39\\{accent%
+\_noad}$: \37\hbox{}\6
+\&{begin} \37\&{if} $\\{math\_type}(\\{nucleus}(\|p))\G\\{sub\_box}$ \1\&{then}%
+\5
+$\\{flush\_node\_list}(\\{info}(\\{nucleus}(\|p)))$;\2\6
+\&{if} $\\{math\_type}(\\{supscr}(\|p))\G\\{sub\_box}$ \1\&{then}\5
+$\\{flush\_node\_list}(\\{info}(\\{supscr}(\|p)))$;\2\6
+\&{if} $\\{math\_type}(\\{subscr}(\|p))\G\\{sub\_box}$ \1\&{then}\5
+$\\{flush\_node\_list}(\\{info}(\\{subscr}(\|p)))$;\2\6
+\&{if} $\\{type}(\|p)=\\{radical\_noad}$ \1\&{then}\5
+$\\{free\_node}(\|p,\39\\{radical\_noad\_size})$\6
+\4\&{else} \&{if} $\\{type}(\|p)=\\{accent\_noad}$ \1\&{then}\5
+$\\{free\_node}(\|p,\39\\{accent\_noad\_size})$\6
+\4\&{else} $\\{free\_node}(\|p,\39\\{noad\_size})$;\2\2\6
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4$\\{left\_noad},\39\\{right\_noad}$: \37\&{begin} \37$\\{free\_node}(\|p,\39%
+\\{noad\_size})$;\5
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4\\{fraction\_noad}: \37\&{begin} \37$\\{flush\_node\_list}(\\{info}(%
+\\{numerator}(\|p)))$;\5
+$\\{flush\_node\_list}(\\{info}(\\{denominator}(\|p)))$;\5
+$\\{free\_node}(\|p,\39\\{fraction\_noad\_size})$;\5
+\&{goto} \37\\{done};\6
+\&{end};\par
+\U208.\fi
+
+\N710.  \[35] Subroutines for math mode.
+In order to convert mlists to hlists, i.e., noads to nodes, we need several
+subroutines that are conveniently dealt with now.
+
+Let us first introduce the macros that make it easy to get at the parameters
+and
+other font information. A size code, which is a multiple of 16, is added to a
+family number to get an index into the table of internal font numbers
+for each combination of family and size.  (Be alert: Size codes get
+larger as the type gets smaller.)
+
+\Y\P\D \37$\\{text\_size}=0$\C{size code for the largest size in a family}\par
+\P\D \37$\\{script\_size}=16$\C{size code for the medium size in a family}\par
+\P\D \37$\\{script\_script\_size}=32$\C{size code for the smallest size in a
+family}\par
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_size}(\|s:\\{integer})$;\2\6
+\&{begin} \37\&{if} $\|s=\\{text\_size}$ \1\&{then}\5
+$\\{print\_esc}(\.{"textfont"})$\6
+\4\&{else} \&{if} $\|s=\\{script\_size}$ \1\&{then}\5
+$\\{print\_esc}(\.{"scriptfont"})$\6
+\4\&{else} $\\{print\_esc}(\.{"scriptscriptfont"})$;\2\2\6
+\&{end};\par
+\fi
+
+\M711. Before an mlist is converted to an hlist, \TeX\ makes sure that
+the fonts in family~2 have enough parameters to be math-symbol
+fonts, and that the fonts in family~3 have enough parameters to be
+math-extension fonts. The math-symbol parameters are referred to by using the
+following macros, which take a size code as their parameter; for example,
+$\\{num1}(\\{cur\_size})$ gives the value of the \\{num1} parameter for the
+current size.
+
+\Y\P\D \37$\\{mathsy\_end}(\#)\S\\{fam\_fnt}(2+\#)$ ] ] .\\{sc}\par
+\P\D $\\{mathsy}(\#)\S\\{font\_info}$ [ $\#+\\{param\_base}$ [ $\\{mathsy%
+\_end}$\par
+\P\D \37$\\{math\_x\_height}\S\\{mathsy}(5)$\C{height of `\.x'}\par
+\P\D \37$\\{math\_quad}\S\\{mathsy}(6)$\C{\.{18mu}}\par
+\P\D \37$\\{num1}\S\\{mathsy}(8)$\C{numerator shift-up in display styles}\par
+\P\D \37$\\{num2}\S\\{mathsy}(9)$\C{numerator shift-up in non-display, non-\.{%
+\\atop}}\par
+\P\D \37$\\{num3}\S\\{mathsy}(10)$\C{numerator shift-up in non-display \.{%
+\\atop}}\par
+\P\D \37$\\{denom1}\S\\{mathsy}(11)$\C{denominator shift-down in display
+styles}\par
+\P\D \37$\\{denom2}\S\\{mathsy}(12)$\C{denominator shift-down in non-display
+styles}\par
+\P\D \37$\\{sup1}\S\\{mathsy}(13)$\C{superscript shift-up in uncramped display
+style}\par
+\P\D \37$\\{sup2}\S\\{mathsy}(14)$\C{superscript shift-up in uncramped
+non-display}\par
+\P\D \37$\\{sup3}\S\\{mathsy}(15)$\C{superscript shift-up in cramped styles}\par
+\P\D \37$\\{sub1}\S\\{mathsy}(16)$\C{subscript shift-down if superscript is
+absent}\par
+\P\D \37$\\{sub2}\S\\{mathsy}(17)$\C{subscript shift-down if superscript is
+present}\par
+\P\D \37$\\{sup\_drop}\S\\{mathsy}(18)$\C{superscript baseline below top of
+large box}\par
+\P\D \37$\\{sub\_drop}\S\\{mathsy}(19)$\C{subscript baseline below bottom of
+large box}\par
+\P\D \37$\\{delim1}\S\\{mathsy}(20)$\C{size of \.{\\atopwithdelims} delimiters
+ in display styles}\par
+\P\D \37$\\{delim2}\S\\{mathsy}(21)$\C{size of \.{\\atopwithdelims} delimiters
+in non-displays}\par
+\P\D \37$\\{axis\_height}\S\\{mathsy}(22)$\C{height of fraction lines above the
+baseline}\par
+\P\D \37$\\{total\_mathsy\_params}=22$\par
+\fi
+
+\M712. The math-extension parameters have similar macros, but the size code is
+omitted (since it is always \\{cur\_size} when we refer to such parameters).
+
+\Y\P\D \37$\\{mathex}(\#)\S\\{font\_info}[\#+\\{param\_base}[\\{fam\_fnt}(3+%
+\\{cur\_size})]].\\{sc}$\par
+\P\D \37$\\{default\_rule\_thickness}\S\\{mathex}(8)$\C{thickness of \.{\\over}
+bars}\par
+\P\D \37$\\{big\_op\_spacing1}\S\\{mathex}(9)$\C{minimum clearance above a
+displayed op}\par
+\P\D \37$\\{big\_op\_spacing2}\S\\{mathex}(10)$\C{minimum clearance below a
+displayed op}\par
+\P\D \37$\\{big\_op\_spacing3}\S\\{mathex}(11)$\C{minimum baselineskip above
+displayed op}\par
+\P\D \37$\\{big\_op\_spacing4}\S\\{mathex}(12)$\C{minimum baselineskip below
+displayed op}\par
+\P\D \37$\\{big\_op\_spacing5}\S\\{mathex}(13)$\C{padding above and below
+displayed limits}\par
+\P\D \37$\\{total\_mathex\_params}=13$\par
+\fi
+
+\M713. We also need to compute the change in style between mlists and their
+subsidiaries. The following macros define the subsidiary style for
+an overlined nucleus (\\{cramped\_style}), for a subscript or a superscript
+(\\{sub\_style} or \\{sup\_style}), or for a numerator or denominator (\\{num%
+\_style}
+or \\{denom\_style}).
+
+\Y\P\D \37$\\{cramped\_style}(\#)\S2\ast(\#\mathbin{\&{div}}2)+\\{cramped}$%
+\C{cramp the style}\par
+\P\D \37$\\{sub\_style}(\#)\S2\ast(\#\mathbin{\&{div}}4)+\\{script\_style}+%
+\\{cramped}$\C{smaller and cramped}\par
+\P\D \37$\\{sup\_style}(\#)\S2\ast(\#\mathbin{\&{div}}4)+\\{script\_style}+(\#%
+\mathbin{\&{mod}}2)$\C{smaller}\par
+\P\D \37$\\{num\_style}(\#)\S\#+2-2\ast(\#\mathbin{\&{div}}6)$\C{smaller unless
+already script-script}\par
+\P\D \37$\\{denom\_style}(\#)\S2\ast(\#\mathbin{\&{div}}2)+\\{cramped}+2-2\ast(%
+\#\mathbin{\&{div}}6)$\C{smaller, cramped}\par
+\fi
+
+\M714. When the style changes, the following piece of program computes
+associated
+information:
+
+\Y\P$\4\X714:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on %
+\\{cur\_style}\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_style}<\\{script\_style}$ \1\&{then}\5
+$\\{cur\_size}\K\\{text\_size}$\6
+\4\&{else} $\\{cur\_size}\K16\ast((\\{cur\_style}-\\{text\_style})\mathbin{%
+\&{div}}2)$;\2\6
+$\\{cur\_mu}\K\\{x\_over\_n}(\\{math\_quad}(\\{cur\_size}),\3918)$;\6
+\&{end}\par
+\Us731, 737, 741, 765, 771\ETs774.\fi
+
+\M715. Here is a function that returns a pointer to a rule node having a given
+thickness \|t. The rule will extend horizontally to the boundary of the vlist
+that eventually contains it.
+
+\Y\P\4\&{function}\1\  \37$\\{fraction\_rule}(\|t:\\{scaled})$: \37\\{pointer};%
+\C{construct the bar for a fraction}\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{new\_rule}$;\5
+$\\{height}(\|p)\K\|t$;\5
+$\\{depth}(\|p)\K0$;\5
+$\\{fraction\_rule}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M716. The \\{overbar} function returns a pointer to a vlist box that consists
+of
+a given box \|b, above which has been placed a kern of height \|k under a
+fraction rule of thickness \|t under additional space of height \|t.
+
+\Y\P\4\&{function}\1\  \37$\\{overbar}(\|b:\\{pointer};\,\35\|k,\39\|t:%
+\\{scaled})$: \37\\{pointer};\6
+\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{nodes being constructed}\2\6
+\&{begin} \37$\|p\K\\{new\_kern}(\|k)$;\5
+$\\{link}(\|p)\K\|b$;\5
+$\|q\K\\{fraction\_rule}(\|t)$;\5
+$\\{link}(\|q)\K\|p$;\5
+$\|p\K\\{new\_kern}(\|t)$;\5
+$\\{link}(\|p)\K\|q$;\5
+$\\{overbar}\K\\{vpack}(\|p,\39\\{natural})$;\6
+\&{end};\par
+\fi
+
+\M717. The \\{var\_delimiter} function, which finds or constructs a
+sufficiently
+large delimiter, is the most interesting of the auxiliary functions that
+currently concern us. Given a pointer \|d to a delimiter field in some noad,
+together with a size code \|s and a vertical distance \|v, this function
+returns a pointer to a box that contains the smallest variant of \|d whose
+height plus depth is \|v or more. (And if no variant is large enough, it
+returns the largest available variant.) In particular, this routine will
+construct arbitrarily large delimiters from extensible components, if
+\|d leads to such characters.
+
+The value returned is a box whose \\{shift\_amount} has been set so that
+the box is vertically centered with respect to the axis in the given size.
+If a built-up symbol is returned, the height of the box before shifting
+will be the height of its topmost component.
+
+\Y\P\hbox{\4}\X720:Declare subprocedures for \\{var\_delimiter}\X \6
+\4\&{function}\1\  \37$\\{var\_delimiter}(\|d:\\{pointer};\,\35\|s:\\{small%
+\_number};\,\35\|v:\\{scaled})$: \37\\{pointer};\6
+\4\&{label} \37$\\{found},\39\\{continue}$;\6
+\4\&{var} \37\|b: \37\\{pointer};\C{the box that will be constructed}\6
+$\|f,\39\|g$: \37\\{internal\_font\_number};\C{best-so-far and tentative font
+codes}\6
+$\|c,\39\|x,\39\|y$: \37\\{quarterword};\C{best-so-far and tentative character
+codes}\6
+$\|m,\39\|n$: \37\\{integer};\C{the number of extensible pieces}\6
+\|u: \37\\{scaled};\C{height-plus-depth of a tentative character}\6
+\|w: \37\\{scaled};\C{largest height-plus-depth so far}\6
+\|q: \37\\{four\_quarters};\C{character info}\6
+\\{hd}: \37\\{eight\_bits};\C{height-depth byte}\6
+\|r: \37\\{four\_quarters};\C{extensible pieces}\6
+\|z: \37\\{small\_number};\C{runs through font family members}\6
+\\{large\_attempt}: \37\\{boolean};\C{are we trying the ``large'' variant?}\2\6
+\&{begin} \37$\|f\K\\{null\_font}$;\5
+$\|w\K0$;\5
+$\\{large\_attempt}\K\\{false}$;\5
+$\|z\K\\{small\_fam}(\|d)$;\5
+$\|x\K\\{small\_char}(\|d)$;\6
+\~ \1\&{loop}\ \&{begin} \37\X718:Look at the variants of $(\|z,\|x)$; set \|f
+and \|c whenever a better character is found; \&{goto} \\{found} as soon as a
+large enough variant is encountered\X;\6
+\&{if} $\\{large\_attempt}$ \1\&{then}\5
+\&{goto} \37\\{found};\C{there were none large enough}\2\6
+$\\{large\_attempt}\K\\{true}$;\5
+$\|z\K\\{large\_fam}(\|d)$;\5
+$\|x\K\\{large\_char}(\|d)$;\6
+\&{end};\2\6
+\4\\{found}: \37\&{if} $\|f\I\\{null\_font}$ \1\&{then}\5
+\X721:Make variable \|b point to a box for $(\|f,\|c)$\X\6
+\4\&{else} \&{begin} \37$\|b\K\\{new\_null\_box}$;\5
+$\\{width}(\|b)\K\\{null\_delimiter\_space}$;\C{use this width if no delimiter
+was found}\6
+\&{end};\2\6
+$\\{shift\_amount}(\|b)\K\\{half}(\\{height}(\|b)-\\{depth}(\|b))-\\{axis%
+\_height}(\|s)$;\5
+$\\{var\_delimiter}\K\|b$;\6
+\&{end};\par
+\fi
+
+\M718. The search process is complicated slightly by the facts that some of the
+characters might not be present in some of the fonts, and they might not
+be probed in increasing order of height.
+
+\Y\P$\4\X718:Look at the variants of $(\|z,\|x)$; set \|f and \|c whenever a
+better character is found; \&{goto} \\{found} as soon as a large enough variant
+is encountered\X\S$\6
+\&{if} $(\|z\I0)\V(\|x\I\\{min\_quarterword})$ \1\&{then}\6
+\&{begin} \37$\|z\K\|z+\|s+16$;\6
+\1\&{repeat} \37$\|z\K\|z-16$;\5
+$\|g\K\\{fam\_fnt}(\|z)$;\6
+\&{if} $\|g\I\\{null\_font}$ \1\&{then}\5
+\X719:Look at the list of characters starting with \|x in font \|g; set \|f and
+\|c whenever a better character is found; \&{goto} \\{found} as soon as a large
+enough variant is encountered\X;\2\6
+\4\&{until}\5
+$\|z<16$;\2\6
+\&{end}\2\par
+\U717.\fi
+
+\M719. \P$\X719:Look at the list of characters starting with \|x in font \|g;
+set \|f and \|c whenever a better character is found; \&{goto} \\{found} as
+soon as a large enough variant is encountered\X\S$\6
+\&{begin} \37$\|y\K\|x$;\6
+\&{if} $(\\{qo}(\|y)\G\\{font\_bc}[\|g])\W(\\{qo}(\|y)\L\\{font\_ec}[\|g])$ \1%
+\&{then}\6
+\&{begin} \37\\{continue}: \37$\|q\K\\{orig\_char\_info}(\|g)(\|y)$;\6
+\&{if} $\\{char\_exists}(\|q)$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{char\_tag}(\|q)=\\{ext\_tag}$ \1\&{then}\6
+\&{begin} \37$\|f\K\|g$;\5
+$\|c\K\|y$;\5
+\&{goto} \37\\{found};\6
+\&{end};\2\6
+$\\{hd}\K\\{height\_depth}(\|q)$;\5
+$\|u\K\\{char\_height}(\|g)(\\{hd})+\\{char\_depth}(\|g)(\\{hd})$;\6
+\&{if} $\|u>\|w$ \1\&{then}\6
+\&{begin} \37$\|f\K\|g$;\5
+$\|c\K\|y$;\5
+$\|w\K\|u$;\6
+\&{if} $\|u\G\|v$ \1\&{then}\5
+\&{goto} \37\\{found};\2\6
+\&{end};\2\6
+\&{if} $\\{char\_tag}(\|q)=\\{list\_tag}$ \1\&{then}\6
+\&{begin} \37$\|y\K\\{rem\_byte}(\|q)$;\5
+\&{goto} \37\\{continue};\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end}\par
+\U718.\fi
+
+\M720. Here is a subroutine that creates a new box, whose list contains a
+single character, and whose width includes the italic correction for
+that character. The height or depth of the box will be negative, if
+the height or depth of the character is negative; thus, this routine
+may deliver a slightly different result than \\{hpack} would produce.
+
+\Y\P$\4\X720:Declare subprocedures for \\{var\_delimiter}\X\S$\6
+\4\&{function}\1\  \37$\\{char\_box}(\|f:\\{internal\_font\_number};\,\35\|c:%
+\\{quarterword})$: \37\\{pointer};\6
+\4\&{var} \37\|q: \37\\{four\_quarters};\5
+\\{hd}: \37\\{eight\_bits};\C{\\{height\_depth} byte}\6
+$\|b,\39\|p$: \37\\{pointer};\C{the new box and its character node}\2\6
+\&{begin} \37$\|q\K\\{char\_info}(\|f)(\|c)$;\5
+$\\{hd}\K\\{height\_depth}(\|q)$;\5
+$\|b\K\\{new\_null\_box}$;\5
+$\\{width}(\|b)\K\\{char\_width}(\|f)(\|q)+\\{char\_italic}(\|f)(\|q)$;\5
+$\\{height}(\|b)\K\\{char\_height}(\|f)(\\{hd})$;\5
+$\\{depth}(\|b)\K\\{char\_depth}(\|f)(\\{hd})$;\5
+$\|p\K\\{get\_avail}$;\5
+$\\{character}(\|p)\K\|c$;\5
+$\\{font}(\|p)\K\|f$;\5
+$\\{list\_ptr}(\|b)\K\|p$;\5
+$\\{char\_box}\K\|b$;\6
+\&{end};\par
+\As722\ET723.
+\U717.\fi
+
+\M721. When the following code is executed, $\\{char\_tag}(\|q)$ will be equal
+to
+\\{ext\_tag} if and only if a built-up symbol is supposed to be returned.
+
+\Y\P$\4\X721:Make variable \|b point to a box for $(\|f,\|c)$\X\S$\6
+\&{if} $\\{char\_tag}(\|q)=\\{ext\_tag}$ \1\&{then}\5
+\X724:Construct an extensible character in a new box \|b, using recipe $\\{rem%
+\_byte}(\|q)$ and font \|f\X\6
+\4\&{else} $\|b\K\\{char\_box}(\|f,\39\|c)$\2\par
+\U717.\fi
+
+\M722. When we build an extensible character, it's handy to have the
+following subroutine, which puts a given character on top
+of the characters already in box \|b:
+
+\Y\P$\4\X720:Declare subprocedures for \\{var\_delimiter}\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{stack\_into\_box}(\|b:\\{pointer};\,\35\|f:%
+\\{internal\_font\_number};\,\35\|c:\\{quarterword})$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{new node placed into \|b}\2\6
+\&{begin} \37$\|p\K\\{char\_box}(\|f,\39\|c)$;\5
+$\\{link}(\|p)\K\\{list\_ptr}(\|b)$;\5
+$\\{list\_ptr}(\|b)\K\|p$;\5
+$\\{height}(\|b)\K\\{height}(\|p)$;\6
+\&{end};\par
+\fi
+
+\M723. Another handy subroutine computes the height plus depth of
+a given character:
+
+\Y\P$\4\X720:Declare subprocedures for \\{var\_delimiter}\X\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{height\_plus\_depth}(\|f:\\{internal\_font\_number};%
+\,\35\|c:\\{quarterword})$: \37\\{scaled};\6
+\4\&{var} \37\|q: \37\\{four\_quarters};\5
+\\{hd}: \37\\{eight\_bits};\C{\\{height\_depth} byte}\2\6
+\&{begin} \37$\|q\K\\{char\_info}(\|f)(\|c)$;\5
+$\\{hd}\K\\{height\_depth}(\|q)$;\5
+$\\{height\_plus\_depth}\K\\{char\_height}(\|f)(\\{hd})+\\{char\_depth}(\|f)(%
+\\{hd})$;\6
+\&{end};\par
+\fi
+
+\M724. \P$\X724:Construct an extensible character in a new box \|b, using
+recipe $\\{rem\_byte}(\|q)$ and font \|f\X\S$\6
+\&{begin} \37$\|b\K\\{new\_null\_box}$;\5
+$\\{type}(\|b)\K\\{vlist\_node}$;\5
+$\|r\K\\{font\_info}[\\{exten\_base}[\|f]+\\{rem\_byte}(\|q)].\\{qqqq}$;\6
+\X725:Compute the minimum suitable height, \|w, and the corresponding number of
+extension steps, \|n; also set $\\{width}(\|b)$\X;\6
+$\|c\K\\{ext\_bot}(\|r)$;\6
+\&{if} $\|c\I\\{min\_quarterword}$ \1\&{then}\5
+$\\{stack\_into\_box}(\|b,\39\|f,\39\|c)$;\2\6
+$\|c\K\\{ext\_rep}(\|r)$;\6
+\&{for} $\|m\K1\mathrel{\&{to}}\|n$ \1\&{do}\5
+$\\{stack\_into\_box}(\|b,\39\|f,\39\|c)$;\2\6
+$\|c\K\\{ext\_mid}(\|r)$;\6
+\&{if} $\|c\I\\{min\_quarterword}$ \1\&{then}\6
+\&{begin} \37$\\{stack\_into\_box}(\|b,\39\|f,\39\|c)$;\5
+$\|c\K\\{ext\_rep}(\|r)$;\6
+\&{for} $\|m\K1\mathrel{\&{to}}\|n$ \1\&{do}\5
+$\\{stack\_into\_box}(\|b,\39\|f,\39\|c)$;\2\6
+\&{end};\2\6
+$\|c\K\\{ext\_top}(\|r)$;\6
+\&{if} $\|c\I\\{min\_quarterword}$ \1\&{then}\5
+$\\{stack\_into\_box}(\|b,\39\|f,\39\|c)$;\2\6
+$\\{depth}(\|b)\K\|w-\\{height}(\|b)$;\6
+\&{end}\par
+\U721.\fi
+
+\M725. The width of an extensible character is the width of the repeatable
+module. If this module does not have positive height plus depth,
+we don't use any copies of it, otherwise we use as few as possible
+(in groups of two if there is a middle part).
+
+\Y\P$\4\X725:Compute the minimum suitable height, \|w, and the corresponding
+number of extension steps, \|n; also set $\\{width}(\|b)$\X\S$\6
+$\|c\K\\{ext\_rep}(\|r)$;\5
+$\|u\K\\{height\_plus\_depth}(\|f,\39\|c)$;\5
+$\|w\K0$;\5
+$\|q\K\\{char\_info}(\|f)(\|c)$;\5
+$\\{width}(\|b)\K\\{char\_width}(\|f)(\|q)+\\{char\_italic}(\|f)(\|q)$;\6
+$\|c\K\\{ext\_bot}(\|r)$;\ \&{if} $\|c\I\\{min\_quarterword}$ \1\&{then}\5
+$\|w\K\|w+\\{height\_plus\_depth}(\|f,\39\|c)$;\2\6
+$\|c\K\\{ext\_mid}(\|r)$;\ \&{if} $\|c\I\\{min\_quarterword}$ \1\&{then}\5
+$\|w\K\|w+\\{height\_plus\_depth}(\|f,\39\|c)$;\2\6
+$\|c\K\\{ext\_top}(\|r)$;\ \&{if} $\|c\I\\{min\_quarterword}$ \1\&{then}\5
+$\|w\K\|w+\\{height\_plus\_depth}(\|f,\39\|c)$;\2\6
+$\|n\K0$;\6
+\&{if} $\|u>0$ \1\&{then}\6
+\&{while} $\|w<\|v$ \1\&{do}\6
+\&{begin} \37$\|w\K\|w+\|u$;\5
+$\\{incr}(\|n)$;\6
+\&{if} $\\{ext\_mid}(\|r)\I\\{min\_quarterword}$ \1\&{then}\5
+$\|w\K\|w+\|u$;\2\6
+\&{end}\2\2\par
+\U724.\fi
+
+\M726. The next subroutine is much simpler; it is used for numerators and
+denominators of fractions as well as for displayed operators and
+their limits above and below. It takes a given box~\|b and
+changes it so that the new box is centered in a box of width~\|w.
+The centering is done by putting \.{\\hss} glue at the left and right
+of the list inside \|b, then packaging the new box; thus, the
+actual box might not really be centered, if it already contains
+infinite glue.
+
+The given box might contain a single character whose italic correction
+has been added to the width of the box; in this case a compensating
+kern is inserted.
+
+\Y\P\4\&{function}\1\  \37$\\{rebox}(\|b:\\{pointer};\,\35\|w:\\{scaled})$: \37%
+\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{temporary register for list manipulation}\6
+\|f: \37\\{internal\_font\_number};\C{font in a one-character box}\6
+\|v: \37\\{scaled};\C{width of a character without italic correction}\2\6
+\&{begin} \37\&{if} $(\\{width}(\|b)\I\|w)\W(\\{list\_ptr}(\|b)\I\\{null})$ \1%
+\&{then}\6
+\&{begin} \37\&{if} $\\{type}(\|b)\I\\{hlist\_node}$ \1\&{then}\5
+$\|b\K\\{hpack}(\|b,\39\\{natural})$;\2\6
+$\|p\K\\{list\_ptr}(\|b)$;\6
+\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{link}(\\{link}(\|p))=\\{null}$ \1\&{then}\6
+\&{begin} \37$\|f\K\\{font}(\|p)$;\5
+$\|v\K\\{char\_width}(\|f)(\\{orig\_char\_info}(\|f)(\\{character}(\|p)))$;\6
+\&{if} $\|v\I\\{width}(\|b)$ \1\&{then}\5
+$\\{link}(\\{link}(\|p))\K\\{new\_kern}(\\{width}(\|b)-\|v)$;\2\6
+\&{end}\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{link}(\|p)=\\{null}$ \1\&{then}\6
+\&{begin} \37$\|f\K\\{font}(\|p)$;\5
+$\|v\K\\{char\_width}(\|f)(\\{orig\_char\_info}(\|f)(\\{character}(\|p)))$;\6
+\&{if} $\|v\I\\{width}(\|b)$ \1\&{then}\5
+$\\{link}(\|p)\K\\{new\_kern}(\\{width}(\|b)-\|v)$;\2\6
+\&{end};\2\2\2\6
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|b))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|b))$;\5
+$\\{free\_node}(\|b,\39\\{box\_node\_size})$;\5
+$\|b\K\\{new\_glue}(\\{ss\_glue})$;\5
+$\\{link}(\|b)\K\|p$;\6
+\&{while} $\\{link}(\|p)\I\\{null}$ \1\&{do}\5
+$\|p\K\\{link}(\|p)$;\2\6
+$\\{link}(\|p)\K\\{new\_glue}(\\{ss\_glue})$;\5
+$\\{rebox}\K\\{hpack}(\|b,\39\|w,\39\\{exactly})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{width}(\|b)\K\|w$;\5
+$\\{rebox}\K\|b$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M727. Here is a subroutine that creates a new glue specification from another
+one that is expressed in `\.{mu}', given the value of the math unit.
+
+\Y\P\D \37$\\{mu\_mult}(\#)\S\\{nx\_plus\_y}(\|n,\39\#,\39\\{xn\_over\_d}(\#,%
+\39\|f,\39\O{200000}))$\par
+\Y\P\4\&{function}\1\  \37$\\{math\_glue}(\|g:\\{pointer};\,\35\|m:%
+\\{scaled})$: \37\\{pointer};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new glue specification}\6
+\|n: \37\\{integer};\C{integer part of \|m}\6
+\|f: \37\\{scaled};\C{fraction part of \|m}\2\6
+\&{begin} \37$\|n\K\\{x\_over\_n}(\|m,\39\O{200000})$;\5
+$\|f\K\\{remainder}$;\6
+\&{if} $\|f<0$ \1\&{then}\6
+\&{begin} \37$\\{decr}(\|n)$;\5
+$\|f\K\|f+\O{200000}$;\6
+\&{end};\2\6
+$\|p\K\\{get\_node}(\\{glue\_spec\_size})$;\5
+$\\{width}(\|p)\K\\{mu\_mult}(\\{width}(\|g))$;\C{convert \.{mu} to \.{pt}}\6
+$\\{stretch\_order}(\|p)\K\\{stretch\_order}(\|g)$;\6
+\&{if} $\\{stretch\_order}(\|p)=\\{normal}$ \1\&{then}\5
+$\\{stretch}(\|p)\K\\{mu\_mult}(\\{stretch}(\|g))$\6
+\4\&{else} $\\{stretch}(\|p)\K\\{stretch}(\|g)$;\2\6
+$\\{shrink\_order}(\|p)\K\\{shrink\_order}(\|g)$;\6
+\&{if} $\\{shrink\_order}(\|p)=\\{normal}$ \1\&{then}\5
+$\\{shrink}(\|p)\K\\{mu\_mult}(\\{shrink}(\|g))$\6
+\4\&{else} $\\{shrink}(\|p)\K\\{shrink}(\|g)$;\2\6
+$\\{math\_glue}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M728. The \\{math\_kern} subroutine removes \\{mu\_glue} from a kern node,
+given
+the value of the math unit.
+
+\Y\P\4\&{procedure}\1\  \37$\\{math\_kern}(\|p:\\{pointer};\,\35\|m:%
+\\{scaled})$;\6
+\4\&{var} \37\|n: \37\\{integer};\C{integer part of \|m}\6
+\|f: \37\\{scaled};\C{fraction part of \|m}\2\6
+\&{begin} \37\&{if} $\\{subtype}(\|p)=\\{mu\_glue}$ \1\&{then}\6
+\&{begin} \37$\|n\K\\{x\_over\_n}(\|m,\39\O{200000})$;\5
+$\|f\K\\{remainder}$;\6
+\&{if} $\|f<0$ \1\&{then}\6
+\&{begin} \37$\\{decr}(\|n)$;\5
+$\|f\K\|f+\O{200000}$;\6
+\&{end};\2\6
+$\\{width}(\|p)\K\\{mu\_mult}(\\{width}(\|p))$;\5
+$\\{subtype}(\|p)\K\\{explicit}$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M729. Sometimes it is necessary to destroy an mlist. The following
+subroutine empties the current list, assuming that $\\{abs}(\\{mode})=%
+\\{mmode}$.
+
+\Y\P\4\&{procedure}\1\  \37\\{flush\_math};\2\6
+\&{begin} \37$\\{flush\_node\_list}(\\{link}(\\{head}))$;\5
+$\\{flush\_node\_list}(\\{incompleat\_noad})$;\5
+$\\{link}(\\{head})\K\\{null}$;\5
+$\\{tail}\K\\{head}$;\5
+$\\{incompleat\_noad}\K\\{null}$;\6
+\&{end};\par
+\fi
+
+\N730.  \[36] Typesetting math formulas.
+\TeX's most important routine for dealing with formulas is called
+\\{mlist\_to\_hlist}.  After a formula has been scanned and represented as an
+mlist, this routine converts it to an hlist that can be placed into a box
+or incorporated into the text of a paragraph. There are three implicit
+parameters, passed in global variables: \\{cur\_mlist} points to the first
+node or noad in the given mlist (and it might be \\{null}); \\{cur\_style} is a
+style code; and \\{mlist\_penalties} is \\{true} if penalty nodes for potential
+line breaks are to be inserted into the resulting hlist. After
+\\{mlist\_to\_hlist} has acted, $\\{link}(\\{temp\_head})$ points to the
+translated hlist.
+
+Since mlists can be inside mlists, the procedure is recursive. And since this
+is not part of \TeX's inner loop, the program has been written in a manner
+that stresses compactness over efficiency.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_mlist}: \37\\{pointer};\C{beginning of mlist to be translated}\6
+\4\\{cur\_style}: \37\\{small\_number};\C{style code at current place in the
+list}\6
+\4\\{cur\_size}: \37\\{small\_number};\C{size code corresponding to \\{cur%
+\_style}}\6
+\4\\{cur\_mu}: \37\\{scaled};\C{the math unit width corresponding to \\{cur%
+\_size}}\6
+\4\\{mlist\_penalties}: \37\\{boolean};\C{should \\{mlist\_to\_hlist} insert
+penalties?}\par
+\fi
+
+\M731. The recursion in \\{mlist\_to\_hlist} is due primarily to a subroutine
+called \\{clean\_box} that puts a given noad field into a box using a given
+math style; \\{mlist\_to\_hlist} can call \\{clean\_box}, which can call
+\\{mlist\_to\_hlist}.
+
+The box returned by \\{clean\_box} is ``clean'' in the
+sense that its \\{shift\_amount} is zero.
+
+\Y\P\4\&{procedure}\1\  \37\\{mlist\_to\_hlist};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{function}\1\  \37$\\{clean\_box}(\|p:\\{pointer};\,\35\|s:\\{small%
+\_number};\,\35\\{jc}:\\{halfword})$: \37\\{pointer};\6
+\4\&{label} \37\\{found};\6
+\4\&{var} \37\|q: \37\\{pointer};\C{beginning of a list to be boxed}\6
+\\{save\_style}: \37\\{small\_number};\C{\\{cur\_style} to be restored}\6
+\|x: \37\\{pointer};\C{box to be returned}\6
+\|r: \37\\{pointer};\C{temporary pointer}\2\6
+\&{begin} \37\&{case} $\\{math\_type}(\|p)$ \1\&{of}\6
+\4\\{math\_char}: \37\&{begin} \37$\\{cur\_mlist}\K\\{new\_noad}$;\5
+$\\{mem}[\\{nucleus}(\\{cur\_mlist})]\K\\{mem}[\|p]$;\6
+\&{end};\6
+\4\\{math\_jchar}: \37\&{begin} \37$\\{cur\_mlist}\K\\{new\_noad}$;\5
+$\\{mem}[\\{nucleus}(\\{cur\_mlist})]\K\\{mem}[\|p]$;\5
+$\\{math\_kcode}(\\{cur\_mlist})\K\\{jc}$;\6
+\&{end};\6
+\4\\{sub\_box}: \37\&{begin} \37$\|q\K\\{info}(\|p)$;\5
+\&{goto} \37\\{found};\6
+\&{end};\6
+\4\\{sub\_mlist}: \37$\\{cur\_mlist}\K\\{info}(\|p)$;\6
+\4\&{othercases} \37\&{begin} \37$\|q\K\\{new\_null\_box}$;\5
+\&{goto} \37\\{found};\6
+\&{end}\2\6
+\&{endcases};\6
+$\\{save\_style}\K\\{cur\_style}$;\5
+$\\{cur\_style}\K\|s$;\5
+$\\{mlist\_penalties}\K\\{false}$;\6
+\\{mlist\_to\_hlist};\5
+$\|q\K\\{link}(\\{temp\_head})$;\C{recursive call}\6
+$\\{cur\_style}\K\\{save\_style}$;\C{restore the style}\6
+\X714:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur%
+\_style}\X;\6
+\4\\{found}: \37\&{if} $\\{is\_char\_node}(\|q)\V(\|q=\\{null})$ \1\&{then}\5
+$\|x\K\\{hpack}(\|q,\39\\{natural})$\6
+\4\&{else} \&{if} $(\\{link}(\|q)=\\{null})\W(\\{type}(\|q)\L\\{dir\_node})\W(%
+\\{shift\_amount}(\|q)=0)$ \1\&{then}\5
+$\|x\K\|q$\C{it's already clean}\6
+\4\&{else} $\|x\K\\{hpack}(\|q,\39\\{natural})$;\2\2\6
+\X732:Simplify a trivial box\X;\6
+$\\{clean\_box}\K\|x$;\6
+\&{end};\par
+\fi
+
+\M732. Here we save memory space in a common case.
+
+\Y\P$\4\X732:Simplify a trivial box\X\S$\6
+$\|q\K\\{list\_ptr}(\|x)$;\6
+\&{if} $\\{is\_char\_node}(\|q)$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{font\_dir}[\\{font}(\|q)]\I\\{dir\_default}$ \1\&{then}%
+\5
+$\|q\K\\{link}(\|q)$;\2\6
+$\|r\K\\{link}(\|q)$;\6
+\&{if} $\|r\I\\{null}$ \1\&{then}\6
+\&{if} $\\{link}(\|r)=\\{null}$ \1\&{then}\6
+\&{if} $\R\\{is\_char\_node}(\|r)$ \1\&{then}\6
+\&{if} $\\{type}(\|r)=\\{kern\_node}$ \1\&{then}\C{unneeded italic correction}\6
+\&{begin} \37$\\{free\_node}(\|r,\39\\{small\_node\_size})$;\5
+$\\{link}(\|q)\K\\{null}$;\6
+\&{end};\2\2\2\2\6
+\&{end}\2\par
+\U731.\fi
+
+\M733. It is convenient to have a procedure that converts a \\{math\_char}
+field to an ``unpacked'' form. The \\{fetch} routine sets \\{cur\_f}, \\{cur%
+\_c},
+and \\{cur\_i} to the font code, character code, and character information
+bytes of
+a given noad field. It also takes care of issuing error messages for
+nonexistent characters; in such cases, $\\{char\_exists}(\\{cur\_i})$ will be %
+\\{false}
+after \\{fetch} has acted, and the field will also have been reset to %
+\\{empty}.
+
+\Y\P\4\&{procedure}\1\  \37$\\{fetch}(\|a:\\{pointer})$;\C{unpack the \\{math%
+\_char} field \|a}\2\6
+\&{begin} \37$\\{cur\_c}\K\\{character}(\|a)$;\5
+$\\{cur\_f}\K\\{fam\_fnt}(\\{fam}(\|a)+\\{cur\_size})$;\6
+\&{if} $\\{cur\_f}=\\{null\_font}$ \1\&{then}\5
+\X734:Complain about an undefined family and set \\{cur\_i} null\X\6
+\4\&{else} \&{begin} \37\&{if} $\\{font\_dir}[\\{cur\_f}]\I\\{dir\_default}$ \1%
+\&{then}\5
+$\\{cur\_c}\K\\{qi}(\\{get\_jfm\_pos}(\\{KANJI}(\\{math\_kcode\_nucleus}(\|a)),%
+\39\\{cur\_f}))$;\2\6
+\&{if} $(\\{qo}(\\{cur\_c})\G\\{font\_bc}[\\{cur\_f}])\W(\\{qo}(\\{cur\_c})\L%
+\\{font\_ec}[\\{cur\_f}])$ \1\&{then}\5
+$\\{cur\_i}\K\\{orig\_char\_info}(\\{cur\_f})(\\{cur\_c})$\6
+\4\&{else} $\\{cur\_i}\K\\{null\_character}$;\2\6
+\&{if} $\R(\\{char\_exists}(\\{cur\_i}))$ \1\&{then}\6
+\&{begin} \37$\\{char\_warning}(\\{cur\_f},\39\\{qo}(\\{cur\_c}))$;\5
+$\\{math\_type}(\|a)\K\\{empty}$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M734. \P$\X734:Complain about an undefined family and set \\{cur\_i} null\X\S$%
+\6
+\&{begin} \37$\\{print\_err}(\.{""})$;\5
+$\\{print\_size}(\\{cur\_size})$;\5
+$\\{print\_char}(\.{"\ "})$;\5
+$\\{print\_int}(\\{fam}(\|a))$;\5
+$\\{print}(\.{"\ is\ undefined\ (character\ "})$;\5
+$\\{print\_ASCII}(\\{qo}(\\{cur\_c}))$;\5
+$\\{print\_char}(\.{")"})$;\5
+$\\{help4}(\.{"Somewhere\ in\ the\ math\ formula\ just\ ended,\ you\ used\
+the"})$\6
+$(\.{"stated\ character\ from\ an\ undefined\ font\ family.\ For\ example,"})$\6
+$(\.{"plain\ TeX\ doesn\'t\ allow\ \\it\ or\ \\sl\ in\ subscripts.\
+Proceed,"})$\6
+$(\.{"and\ I\'ll\ try\ to\ forget\ that\ I\ needed\ that\ character."})$;\5
+\\{error};\5
+$\\{cur\_i}\K\\{null\_character}$;\5
+$\\{math\_type}(\|a)\K\\{empty}$;\6
+\&{end}\par
+\U733.\fi
+
+\M735. The outputs of \\{fetch} are placed in global variables.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_f}: \37\\{internal\_font\_number};\C{the \\{font} field of a \\{math%
+\_char}}\6
+\4\\{cur\_c}: \37\\{quarterword};\C{the \\{character} field of a \\{math%
+\_char}}\6
+\4\\{cur\_i}: \37\\{four\_quarters};\C{the \\{char\_info} of a \\{math\_char},
+ or a lig/kern instruction}\par
+\fi
+
+\M736. We need to do a lot of different things, so \\{mlist\_to\_hlist} makes
+two
+passes over the given mlist.
+
+The first pass does most of the processing: It removes ``mu'' spacing from
+glue, it recursively evaluates all subsidiary mlists so that only the
+top-level mlist remains to be handled, it puts fractions and square roots
+and such things into boxes, it attaches subscripts and superscripts, and
+it computes the overall height and depth of the top-level mlist so that
+the size of delimiters for a \\{left\_noad} and a \\{right\_noad} will be
+known.
+The hlist resulting from each noad is recorded in that noad's \\{new\_hlist}
+field, an integer field that replaces the \\{nucleus} or \\{thickness}.
+
+The second pass eliminates all noads and inserts the correct glue and
+penalties between nodes.
+
+\Y\P\D \37$\\{new\_hlist}(\#)\S\\{mem}[\\{nucleus}(\#)].\\{int}$\C{the
+translation of an mlist}\par
+\fi
+
+\M737. Here is the overall plan of \\{mlist\_to\_hlist}, and the list of its
+local variables.
+
+\Y\P\D \37$\\{done\_with\_noad}=80$\C{go here when a noad has been fully
+translated}\par
+\P\D \37$\\{done\_with\_node}=81$\C{go here when a node has been fully
+converted}\par
+\P\D \37$\\{check\_dimensions}=82$\C{go here to update \\{max\_h} and \\{max%
+\_d}}\par
+\P\D \37$\\{delete\_q}=83$\C{go here to delete \|q and move to the next node}%
+\par
+\Y\P\hbox{\4}\X745:Declare math construction procedures\X \6
+\4\&{procedure}\1\  \37\\{mlist\_to\_hlist};\6
+\4\&{label} \37$\\{reswitch},\39\\{check\_dimensions},\39\\{done\_with\_noad},%
+\39\\{done\_with\_node},\39\\{delete\_q},\39\\{done}$;\6
+\4\&{var} \37\\{mlist}: \37\\{pointer};\C{beginning of the given list}\6
+\\{penalties}: \37\\{boolean};\C{should penalty nodes be inserted?}\6
+\\{style}: \37\\{small\_number};\C{the given style}\6
+\|u: \37\\{pointer};\C{temporary register}\6
+\\{save\_style}: \37\\{small\_number};\C{holds \\{cur\_style} during recursion}%
+\6
+\|q: \37\\{pointer};\C{runs through the mlist}\6
+\|r: \37\\{pointer};\C{the most recent noad preceding \|q}\6
+\\{r\_type}: \37\\{small\_number};\C{the \\{type} of noad \|r, or \\{op\_noad}
+if $\|r=\\{null}$}\6
+\|t: \37\\{small\_number};\C{the effective \\{type} of noad \|q during the
+second pass}\6
+$\|p,\39\|x,\39\|y,\39\|z$: \37\\{pointer};\C{temporary registers for list
+construction}\6
+\\{pen}: \37\\{integer};\C{a penalty to be inserted}\6
+\|s: \37\\{small\_number};\C{the size of a noad to be deleted}\6
+$\\{max\_h},\39\\{max\_d}$: \37\\{scaled};\C{maximum height and depth of the
+list translated so far}\6
+\\{delta}: \37\\{scaled};\C{offset between subscript and superscript}\2\6
+\&{begin} \37$\\{mlist}\K\\{cur\_mlist}$;\5
+$\\{penalties}\K\\{mlist\_penalties}$;\5
+$\\{style}\K\\{cur\_style}$;\C{tuck global parameters away as local variables}\6
+$\|q\K\\{mlist}$;\5
+$\|r\K\\{null}$;\5
+$\\{r\_type}\K\\{op\_noad}$;\5
+$\\{max\_h}\K0$;\5
+$\\{max\_d}\K0$;\5
+\X714:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur%
+\_style}\X;\6
+\&{while} $\|q\I\\{null}$ \1\&{do}\5
+\X738:Process node-or-noad \|q as much as possible in preparation for the
+second pass of \\{mlist\_to\_hlist}, then move to the next item in the mlist\X;%
+\2\6
+\X740:Convert \(a)a final \\{bin\_noad} to an \\{ord\_noad}\X;\6
+\X771:Make a second pass over the mlist, removing all noads and inserting the
+proper spacing and penalties\X;\6
+$\|p\K\\{new\_null\_box}$;\5
+$\\{link}(\|p)\K\\{link}(\\{temp\_head})$;\5
+$\\{adjust\_hlist}(\|p,\39\\{false})$;\5
+$\\{link}(\\{temp\_head})\K\\{link}(\|p)$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|p))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|p))$;\5
+$\\{free\_node}(\|p,\39\\{box\_node\_size})$;\6
+\&{end};\par
+\fi
+
+\M738. We use the fact that no character nodes appear in an mlist, hence
+the field $\\{type}(\|q)$ is always present.
+
+\Y\P$\4\X738:Process node-or-noad \|q as much as possible in preparation for
+the second pass of \\{mlist\_to\_hlist}, then move to the next item in the
+mlist\X\S$\6
+\&{begin} \37\X739:Do first-pass processing based on $\\{type}(\|q)$; \&{goto} %
+\\{done\_with\_noad} if a noad has been fully processed, \&{goto} \\{check%
+\_dimensions} if it has been translated into $\\{new\_hlist}(\|q)$, or \&{goto}
+\\{done\_with\_node} if a node has been fully processed\X;\6
+\4\\{check\_dimensions}: \37$\|z\K\\{hpack}(\\{new\_hlist}(\|q),\39%
+\\{natural})$;\6
+\&{if} $\\{height}(\|z)>\\{max\_h}$ \1\&{then}\5
+$\\{max\_h}\K\\{height}(\|z)$;\2\6
+\&{if} $\\{depth}(\|z)>\\{max\_d}$ \1\&{then}\5
+$\\{max\_d}\K\\{depth}(\|z)$;\2\6
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|z))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|z))$;\5
+$\\{free\_node}(\|z,\39\\{box\_node\_size})$;\6
+\4\\{done\_with\_noad}: \37$\|r\K\|q$;\5
+$\\{r\_type}\K\\{type}(\|r)$;\6
+\4\\{done\_with\_node}: \37$\|q\K\\{link}(\|q)$;\6
+\&{end}\par
+\U737.\fi
+
+\M739. One of the things we must do on the first pass is change a \\{bin\_noad}
+to
+an \\{ord\_noad} if the \\{bin\_noad} is not in the context of a binary
+operator.
+The values of \|r and \\{r\_type} make this fairly easy.
+
+\Y\P$\4\X739:Do first-pass processing based on $\\{type}(\|q)$; \&{goto} %
+\\{done\_with\_noad} if a noad has been fully processed, \&{goto} \\{check%
+\_dimensions} if it has been translated into $\\{new\_hlist}(\|q)$, or \&{goto}
+\\{done\_with\_node} if a node has been fully processed\X\S$\6
+\4\\{reswitch}: \37$\\{delta}\K0$;\6
+\&{case} $\\{type}(\|q)$ \1\&{of}\6
+\4\\{bin\_noad}: \37\&{case} $\\{r\_type}$ \1\&{of}\6
+\4$\\{bin\_noad},\39\\{op\_noad},\39\\{rel\_noad},\39\\{open\_noad},\39\\{punct%
+\_noad},\39\\{left\_noad}$: \37\&{begin} \37$\\{type}(\|q)\K\\{ord\_noad}$;\5
+\&{goto} \37\\{reswitch};\6
+\&{end};\6
+\4\&{othercases} \37\\{do\_nothing}\2\6
+\&{endcases};\6
+\4$\\{rel\_noad},\39\\{close\_noad},\39\\{punct\_noad},\39\\{right\_noad}$: \37%
+\&{begin} \37\hbox{}\6
+\X740:Convert \(a)a final \\{bin\_noad} to an \\{ord\_noad}\X;\6
+\&{if} $\\{type}(\|q)=\\{right\_noad}$ \1\&{then}\5
+\&{goto} \37\\{done\_with\_noad};\2\6
+\&{end};\6
+\hbox{\4}\X744:Cases for noads that can follow a \\{bin\_noad}\X\6
+\hbox{\4}\X741:Cases for nodes that can appear in an mlist, after which we %
+\&{goto} \\{done\_with\_node}\X\6
+\4\&{othercases} \37$\\{confusion}(\.{"mlist1"})$\2\6
+\&{endcases};\6
+\X765:Convert \(n)$\\{nucleus}(\|q)$ to an hlist and attach the
+sub/superscripts\X\par
+\U738.\fi
+
+\M740. \P$\X740:Convert \(a)a final \\{bin\_noad} to an \\{ord\_noad}\X\S$\6
+\&{if} $\\{r\_type}=\\{bin\_noad}$ \1\&{then}\5
+$\\{type}(\|r)\K\\{ord\_noad}$\2\par
+\Us737\ET739.\fi
+
+\M741. \P$\X741:Cases for nodes that can appear in an mlist, after which we %
+\&{goto} \\{done\_with\_node}\X\S$\6
+\4\\{style\_node}: \37\&{begin} \37$\\{cur\_style}\K\\{subtype}(\|q)$;\5
+\X714:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur%
+\_style}\X;\6
+\&{goto} \37\\{done\_with\_node};\6
+\&{end};\6
+\4\\{choice\_node}: \37\X742:Change this node to a style node followed by the
+correct choice, then \&{goto} \\{done\_with\_node}\X;\6
+\4$\\{ins\_node},\39\\{mark\_node},\39\\{adjust\_node},\39\\{whatsit\_node},\39%
+\\{penalty\_node},\39\\{disc\_node}$: \37\&{goto} \37\\{done\_with\_node};\6
+\4\\{rule\_node}: \37\&{begin} \37\&{if} $\\{height}(\|q)>\\{max\_h}$ \1%
+\&{then}\5
+$\\{max\_h}\K\\{height}(\|q)$;\2\6
+\&{if} $\\{depth}(\|q)>\\{max\_d}$ \1\&{then}\5
+$\\{max\_d}\K\\{depth}(\|q)$;\2\6
+\&{goto} \37\\{done\_with\_node};\6
+\&{end};\6
+\4\\{glue\_node}: \37\&{begin} \37\X743:Convert \(m)math glue to ordinary glue%
+\X;\6
+\&{goto} \37\\{done\_with\_node};\6
+\&{end};\6
+\4\\{kern\_node}: \37\&{begin} \37$\\{math\_kern}(\|q,\39\\{cur\_mu})$;\5
+\&{goto} \37\\{done\_with\_node};\6
+\&{end};\6
+\4\\{disp\_node}: \37\&{goto} \37\\{done\_with\_node};\par
+\U739.\fi
+
+\M742. \P\D \37$\\{choose\_mlist}(\#)\S$\1\6
+\&{begin} \37$\|p\K\#(\|q)$;\5
+$\#(\|q)\K\\{null}$;\ \&{end}\2\par
+\Y\P$\4\X742:Change this node to a style node followed by the correct choice,
+then \&{goto} \\{done\_with\_node}\X\S$\6
+\&{begin} \37\&{case} $\\{cur\_style}\mathbin{\&{div}}2$ \1\&{of}\6
+\40: \37$\\{choose\_mlist}(\\{display\_mlist})$;\C{$\\{display\_style}=0$}\6
+\41: \37$\\{choose\_mlist}(\\{text\_mlist})$;\C{$\\{text\_style}=2$}\6
+\42: \37$\\{choose\_mlist}(\\{script\_mlist})$;\C{$\\{script\_style}=4$}\6
+\43: \37$\\{choose\_mlist}(\\{script\_script\_mlist})$;\C{$\\{script\_script%
+\_style}=6$}\2\6
+\&{end};\C{there are no other cases}\6
+$\\{flush\_node\_list}(\\{display\_mlist}(\|q))$;\5
+$\\{flush\_node\_list}(\\{text\_mlist}(\|q))$;\5
+$\\{flush\_node\_list}(\\{script\_mlist}(\|q))$;\5
+$\\{flush\_node\_list}(\\{script\_script\_mlist}(\|q))$;\6
+$\\{type}(\|q)\K\\{style\_node}$;\5
+$\\{subtype}(\|q)\K\\{cur\_style}$;\5
+$\\{width}(\|q)\K0$;\5
+$\\{depth}(\|q)\K0$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\|z\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\|p$;\6
+\&{while} $\\{link}(\|p)\I\\{null}$ \1\&{do}\5
+$\|p\K\\{link}(\|p)$;\2\6
+$\\{link}(\|p)\K\|z$;\6
+\&{end};\2\6
+\&{goto} \37\\{done\_with\_node};\6
+\&{end}\par
+\U741.\fi
+
+\M743. Conditional math glue (`\.{\\nonscript}') results in a \\{glue\_node}
+pointing to \\{zero\_glue}, with $\\{subtype}(\|q)=\\{cond\_math\_glue}$; in
+such a case
+the node following will be eliminated if it is a glue or kern node and if the
+current size is different from \\{text\_size}. Unconditional math glue
+(`\.{\\muskip}') is converted to normal glue by multiplying the dimensions
+by \\{cur\_mu}.
+
+\Y\P$\4\X743:Convert \(m)math glue to ordinary glue\X\S$\6
+\&{if} $\\{subtype}(\|q)=\\{mu\_glue}$ \1\&{then}\6
+\&{begin} \37$\|x\K\\{glue\_ptr}(\|q)$;\5
+$\|y\K\\{math\_glue}(\|x,\39\\{cur\_mu})$;\5
+$\\{delete\_glue\_ref}(\|x)$;\5
+$\\{glue\_ptr}(\|q)\K\|y$;\5
+$\\{subtype}(\|q)\K\\{normal}$;\6
+\&{end}\6
+\4\&{else} \&{if} $(\\{cur\_size}\I\\{text\_size})\W(\\{subtype}(\|q)=\\{cond%
+\_math\_glue})$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{link}(\|q)$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{if} $(\\{type}(\|p)=\\{glue\_node})\V(\\{type}(\|p)=\\{kern\_node})$ \1%
+\&{then}\6
+\&{begin} \37$\\{link}(\|q)\K\\{link}(\|p)$;\5
+$\\{link}(\|p)\K\\{null}$;\5
+$\\{flush\_node\_list}(\|p)$;\6
+\&{end};\2\2\6
+\&{end}\2\2\par
+\U741.\fi
+
+\M744. \P$\X744:Cases for noads that can follow a \\{bin\_noad}\X\S$\6
+\4\\{left\_noad}: \37\&{goto} \37\\{done\_with\_noad};\6
+\4\\{fraction\_noad}: \37\&{begin} \37$\\{make\_fraction}(\|q)$;\5
+\&{goto} \37\\{check\_dimensions};\6
+\&{end};\6
+\4\\{op\_noad}: \37\&{begin} \37$\\{delta}\K\\{make\_op}(\|q)$;\6
+\&{if} $\\{subtype}(\|q)=\\{limits}$ \1\&{then}\5
+\&{goto} \37\\{check\_dimensions};\2\6
+\&{end};\6
+\4\\{ord\_noad}: \37$\\{make\_ord}(\|q)$;\6
+\4$\\{open\_noad},\39\\{inner\_noad}$: \37\\{do\_nothing};\6
+\4\\{radical\_noad}: \37$\\{make\_radical}(\|q)$;\6
+\4\\{over\_noad}: \37$\\{make\_over}(\|q)$;\6
+\4\\{under\_noad}: \37$\\{make\_under}(\|q)$;\6
+\4\\{accent\_noad}: \37$\\{make\_math\_accent}(\|q)$;\6
+\4\\{vcenter\_noad}: \37$\\{make\_vcenter}(\|q)$;\par
+\U739.\fi
+
+\M745. Most of the actual construction work of \\{mlist\_to\_hlist} is done
+by procedures with names
+like \\{make\_fraction}, \\{make\_radical}, etc. To illustrate
+the general setup of such procedures, let's begin with a couple of
+simple ones.
+
+\Y\P$\4\X745:Declare math construction procedures\X\S$\6
+\4\&{procedure}\1\  \37$\\{make\_over}(\|q:\\{pointer})$;\2\6
+\&{begin} \37$\\{info}(\\{nucleus}(\|q))\K\30\\{overbar}(\\{clean\_box}(%
+\\{nucleus}(\|q),\39\\{cramped\_style}(\\{cur\_style}),\39\\{math\_kcode}(%
+\|q)),\39\303\ast\\{default\_rule\_thickness},\39\\{default\_rule%
+\_thickness})$;\5
+$\\{math\_type}(\\{nucleus}(\|q))\K\\{sub\_box}$;\6
+\&{end};\par
+\As746, 747, 748, 749, 754, 760, 763, 767\ETs773.
+\U737.\fi
+
+\M746. \P$\X745:Declare math construction procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{make\_under}(\|q:\\{pointer})$;\6
+\4\&{var} \37$\|p,\39\|x,\39\|y$: \37\\{pointer};\C{temporary registers for box
+construction}\6
+\\{delta}: \37\\{scaled};\C{overall height plus depth}\2\6
+\&{begin} \37$\|x\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cur\_style},\39\\{math%
+\_kcode}(\|q))$;\5
+$\|p\K\\{new\_kern}(3\ast\\{default\_rule\_thickness})$;\5
+$\\{link}(\|x)\K\|p$;\5
+$\\{link}(\|p)\K\\{fraction\_rule}(\\{default\_rule\_thickness})$;\5
+$\|y\K\\{vpack}(\|x,\39\\{natural})$;\5
+$\\{delta}\K\\{height}(\|y)+\\{depth}(\|y)+\\{default\_rule\_thickness}$;\5
+$\\{height}(\|y)\K\\{height}(\|x)$;\5
+$\\{depth}(\|y)\K\\{delta}-\\{height}(\|y)$;\5
+$\\{info}(\\{nucleus}(\|q))\K\|y$;\5
+$\\{math\_type}(\\{nucleus}(\|q))\K\\{sub\_box}$;\6
+\&{end};\par
+\fi
+
+\M747. \P$\X745:Declare math construction procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{make\_vcenter}(\|q:\\{pointer})$;\6
+\4\&{var} \37\|v: \37\\{pointer};\C{the box that should be centered vertically}%
+\6
+\\{delta}: \37\\{scaled};\C{its height plus depth}\2\6
+\&{begin} \37$\|v\K\\{info}(\\{nucleus}(\|q))$;\6
+\&{if} $\\{type}(\|v)=\\{dir\_node}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{type}(\\{list\_ptr}(\|v))\I\\{vlist\_node}$ \1\&{then}\5
+$\\{confusion}(\.{"dircenter"})$\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{type}(\|v)\I\\{vlist\_node}$ \1\&{then}\5
+$\\{confusion}(\.{"vcenter"})$\2\6
+\&{end};\2\6
+$\\{delta}\K\\{height}(\|v)+\\{depth}(\|v)$;\5
+$\\{height}(\|v)\K\\{axis\_height}(\\{cur\_size})+\\{half}(\\{delta})$;\5
+$\\{depth}(\|v)\K\\{delta}-\\{height}(\|v)$;\6
+\&{end};\par
+\fi
+
+\M748. According to the rules in the \.{DVI} file specifications, we ensure
+alignment
+between a square root sign and the rule above its nucleus by assuming that the
+baseline of the square-root symbol is the same as the bottom of the rule. The
+height of the square-root symbol will be the thickness of the rule, and the
+depth of the square-root symbol should exceed or equal the height-plus-depth
+of the nucleus plus a certain minimum clearance~\\{clr}. The symbol will be
+placed so that the actual clearance is \\{clr} plus half the excess.
+
+\Y\P$\4\X745:Declare math construction procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{make\_radical}(\|q:\\{pointer})$;\6
+\4\&{var} \37$\|x,\39\|y$: \37\\{pointer};\C{temporary registers for box
+construction}\6
+$\\{delta},\39\\{clr}$: \37\\{scaled};\C{dimensions involved in the
+calculation}\2\6
+\&{begin} \37$\|x\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cramped\_style}(\\{cur%
+\_style}),\39\\{math\_kcode}(\|q))$;\6
+\&{if} $\\{cur\_style}<\\{text\_style}$ \1\&{then}\C{display style}\6
+$\\{clr}\K\\{default\_rule\_thickness}+(\\{abs}(\\{math\_x\_height}(\\{cur%
+\_size}))\mathbin{\&{div}}4)$\6
+\4\&{else} \&{begin} \37$\\{clr}\K\\{default\_rule\_thickness}$;\5
+$\\{clr}\K\\{clr}+(\\{abs}(\\{clr})\mathbin{\&{div}}4)$;\6
+\&{end};\2\6
+$\|y\K\\{var\_delimiter}(\\{left\_delimiter}(\|q),\39\\{cur\_size},\39%
+\\{height}(\|x)+\\{depth}(\|x)+\\{clr}+\\{default\_rule\_thickness})$;\5
+$\\{delta}\K\\{depth}(\|y)-(\\{height}(\|x)+\\{depth}(\|x)+\\{clr})$;\6
+\&{if} $\\{delta}>0$ \1\&{then}\5
+$\\{clr}\K\\{clr}+\\{half}(\\{delta})$;\C{increase the actual clearance}\2\6
+$\\{shift\_amount}(\|y)\K-(\\{height}(\|x)+\\{clr})$;\5
+$\\{link}(\|y)\K\\{overbar}(\|x,\39\\{clr},\39\\{height}(\|y))$;\5
+$\\{info}(\\{nucleus}(\|q))\K\\{hpack}(\|y,\39\\{natural})$;\5
+$\\{math\_type}(\\{nucleus}(\|q))\K\\{sub\_box}$;\6
+\&{end};\par
+\fi
+
+\M749. Slants are not considered when placing accents in math mode. The
+accenter is
+centered over the accentee, and the accent width is treated as zero with
+respect to the size of the final box.
+
+\Y\P$\4\X745:Declare math construction procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{make\_math\_accent}(\|q:\\{pointer})$;\6
+\4\&{label} \37$\\{done},\39\\{done1}$;\6
+\4\&{var} \37$\|p,\39\|x,\39\|y$: \37\\{pointer};\C{temporary registers for box
+construction}\6
+\|a: \37\\{integer};\C{address of lig/kern instruction}\6
+\|c: \37\\{quarterword};\C{accent character}\6
+\|f: \37\\{internal\_font\_number};\C{its font}\6
+\|i: \37\\{four\_quarters};\C{its \\{char\_info}}\6
+\|s: \37\\{scaled};\C{amount to skew the accent to the right}\6
+\|h: \37\\{scaled};\C{height of character being accented}\6
+\\{delta}: \37\\{scaled};\C{space to remove between accent and accentee}\6
+\|w: \37\\{scaled};\C{width of the accentee, not including sub/superscripts}\2\6
+\&{begin} \37$\\{fetch}(\\{accent\_chr}(\|q))$;\6
+\&{if} $\\{char\_exists}(\\{cur\_i})$ \1\&{then}\6
+\&{begin} \37$\|i\K\\{cur\_i}$;\5
+$\|c\K\\{cur\_c}$;\5
+$\|f\K\\{cur\_f}$;\6
+\X752:Compute the amount of skew\X;\6
+$\|x\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cramped\_style}(\\{cur\_style}),\39%
+\\{math\_kcode}(\|q))$;\5
+$\|w\K\\{width}(\|x)$;\5
+$\|h\K\\{height}(\|x)$;\5
+\X751:Switch to a larger accent if available and appropriate\X;\6
+\&{if} $\|h<\\{x\_height}(\|f)$ \1\&{then}\5
+$\\{delta}\K\|h$\ \&{else} $\\{delta}\K\\{x\_height}(\|f)$;\2\6
+\&{if} $(\\{math\_type}(\\{supscr}(\|q))\I\\{empty})\V(\\{math\_type}(%
+\\{subscr}(\|q))\I\\{empty})$ \1\&{then}\6
+\&{if} $\\{math\_type}(\\{nucleus}(\|q))=\\{math\_char}$ \1\&{then}\5
+\X753:Swap the subscript and superscript into box \|x\X;\2\2\6
+$\|y\K\\{char\_box}(\|f,\39\|c)$;\5
+$\\{shift\_amount}(\|y)\K\|s+\\{half}(\|w-\\{width}(\|y))$;\5
+$\\{width}(\|y)\K0$;\5
+$\|p\K\\{new\_kern}(-\\{delta})$;\5
+$\\{link}(\|p)\K\|x$;\5
+$\\{link}(\|y)\K\|p$;\5
+$\|y\K\\{vpack}(\|y,\39\\{natural})$;\5
+$\\{width}(\|y)\K\\{width}(\|x)$;\6
+\&{if} $\\{height}(\|y)<\|h$ \1\&{then}\5
+\X750:Make the height of box \|y equal to \|h\X;\2\6
+$\\{info}(\\{nucleus}(\|q))\K\|y$;\5
+$\\{math\_type}(\\{nucleus}(\|q))\K\\{sub\_box}$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M750. \P$\X750:Make the height of box \|y equal to \|h\X\S$\6
+\&{begin} \37$\|p\K\\{new\_kern}(\|h-\\{height}(\|y))$;\5
+$\\{link}(\|p)\K\\{list\_ptr}(\|y)$;\5
+$\\{list\_ptr}(\|y)\K\|p$;\5
+$\\{height}(\|y)\K\|h$;\6
+\&{end}\par
+\U749.\fi
+
+\M751. \P$\X751:Switch to a larger accent if available and appropriate\X\S$\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{char\_tag}(\|i)\I\\{list\_tag}$ \1%
+\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\|y\K\\{rem\_byte}(\|i)$;\5
+$\|i\K\\{orig\_char\_info}(\|f)(\|y)$;\6
+\&{if} $\R\\{char\_exists}(\|i)$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+\&{if} $\\{char\_width}(\|f)(\|i)>\|w$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\|c\K\|y$;\6
+\&{end};\2\6
+\4\\{done}: \37\par
+\U749.\fi
+
+\M752. \P$\X752:Compute the amount of skew\X\S$\6
+$\|s\K0$;\6
+\&{if} $\\{math\_type}(\\{nucleus}(\|q))=\\{math\_char}$ \1\&{then}\6
+\&{begin} \37$\\{fetch}(\\{nucleus}(\|q))$;\6
+\&{if} $\\{char\_tag}(\\{cur\_i})=\\{lig\_tag}$ \1\&{then}\6
+\&{begin} \37$\|a\K\\{lig\_kern\_start}(\\{cur\_f})(\\{cur\_i})$;\5
+$\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq}$;\6
+\&{if} $\\{skip\_byte}(\\{cur\_i})>\\{stop\_flag}$ \1\&{then}\6
+\&{begin} \37$\|a\K\\{lig\_kern\_restart}(\\{cur\_f})(\\{cur\_i})$;\5
+$\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq}$;\6
+\&{end};\2\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{qo}(\\{next\_char}(\\{cur\_i}))=\\{skew%
+\_char}[\\{cur\_f}]$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{op\_byte}(\\{cur\_i})\G\\{kern\_flag}$ \1\&{then}\6
+\&{if} $\\{skip\_byte}(\\{cur\_i})\L\\{stop\_flag}$ \1\&{then}\5
+$\|s\K\\{char\_kern}(\\{cur\_f})(\\{cur\_i})$;\2\2\6
+\&{goto} \37\\{done1};\6
+\&{end};\2\6
+\&{if} $\\{skip\_byte}(\\{cur\_i})\G\\{stop\_flag}$ \1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+$\|a\K\|a+\\{qo}(\\{skip\_byte}(\\{cur\_i}))+1$;\5
+$\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq}$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{done1}: \37\par
+\U749.\fi
+
+\M753. \P$\X753:Swap the subscript and superscript into box \|x\X\S$\6
+\&{begin} \37$\\{flush\_node\_list}(\|x)$;\5
+$\|x\K\\{new\_noad}$;\5
+$\\{mem}[\\{nucleus}(\|x)]\K\\{mem}[\\{nucleus}(\|q)]$;\5
+$\\{mem}[\\{supscr}(\|x)]\K\\{mem}[\\{supscr}(\|q)]$;\5
+$\\{mem}[\\{subscr}(\|x)]\K\\{mem}[\\{subscr}(\|q)]$;\6
+$\\{mem}[\\{supscr}(\|q)].\\{hh}\K\\{empty\_field}$;\5
+$\\{mem}[\\{subscr}(\|q)].\\{hh}\K\\{empty\_field}$;\6
+$\\{math\_type}(\\{nucleus}(\|q))\K\\{sub\_mlist}$;\5
+$\\{info}(\\{nucleus}(\|q))\K\|x$;\5
+$\|x\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cur\_style},\39\\{math\_kcode}(%
+\|q))$;\5
+$\\{delta}\K\\{delta}+\\{height}(\|x)-\|h$;\5
+$\|h\K\\{height}(\|x)$;\6
+\&{end}\par
+\U749.\fi
+
+\M754. The \\{make\_fraction} procedure is a bit different because it sets
+$\\{new\_hlist}(\|q)$ directly rather than making a sub-box.
+
+\Y\P$\4\X745:Declare math construction procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{make\_fraction}(\|q:\\{pointer})$;\6
+\4\&{var} \37$\|p,\39\|v,\39\|x,\39\|y,\39\|z$: \37\\{pointer};\C{temporary
+registers for box construction}\6
+$\\{delta},\39\\{delta1},\39\\{delta2},\39\\{shift\_up},\39\\{shift\_down},\39%
+\\{clr}$: \37\\{scaled};\C{dimensions for box calculations}\2\6
+\&{begin} \37\&{if} $\\{thickness}(\|q)=\\{default\_code}$ \1\&{then}\5
+$\\{thickness}(\|q)\K\\{default\_rule\_thickness}$;\2\6
+\X755:Create equal-width boxes \|x and \|z for the numerator and denominator,
+and compute the default amounts \\{shift\_up} and \\{shift\_down} by which they
+are displaced from the baseline\X;\6
+\&{if} $\\{thickness}(\|q)=0$ \1\&{then}\5
+\X756:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of no fraction
+line\X\6
+\4\&{else} \X757:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of a
+fraction line\X;\2\6
+\X758:Construct a vlist box for the fraction, according to \\{shift\_up} and %
+\\{shift\_down}\X;\6
+\X759:Put the \(f)fraction into a box with its delimiters, and make $\\{new%
+\_hlist}(\|q)$ point to it\X;\6
+\&{end};\par
+\fi
+
+\M755. \P$\X755:Create equal-width boxes \|x and \|z for the numerator and
+denominator, and compute the default amounts \\{shift\_up} and \\{shift\_down}
+by which they are displaced from the baseline\X\S$\6
+$\|x\K\\{clean\_box}(\\{numerator}(\|q),\39\\{num\_style}(\\{cur\_style}),\39%
+\\{math\_kcode}(\|q))$;\5
+$\|z\K\\{clean\_box}(\\{denominator}(\|q),\39\\{denom\_style}(\\{cur\_style}),%
+\39\\{math\_kcode}(\|q))$;\6
+\&{if} $\\{width}(\|x)<\\{width}(\|z)$ \1\&{then}\5
+$\|x\K\\{rebox}(\|x,\39\\{width}(\|z))$\6
+\4\&{else} $\|z\K\\{rebox}(\|z,\39\\{width}(\|x))$;\2\6
+\&{if} $\\{cur\_style}<\\{text\_style}$ \1\&{then}\C{display style}\6
+\&{begin} \37$\\{shift\_up}\K\\{num1}(\\{cur\_size})$;\5
+$\\{shift\_down}\K\\{denom1}(\\{cur\_size})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{shift\_down}\K\\{denom2}(\\{cur\_size})$;\6
+\&{if} $\\{thickness}(\|q)\I0$ \1\&{then}\5
+$\\{shift\_up}\K\\{num2}(\\{cur\_size})$\6
+\4\&{else} $\\{shift\_up}\K\\{num3}(\\{cur\_size})$;\2\6
+\&{end}\2\par
+\U754.\fi
+
+\M756. The numerator and denominator must be separated by a certain minimum
+clearance, called \\{clr} in the following program. The difference between
+\\{clr} and the actual clearance is 2\\{delta}.
+
+\Y\P$\4\X756:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of no
+fraction line\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_style}<\\{text\_style}$ \1\&{then}\5
+$\\{clr}\K7\ast\\{default\_rule\_thickness}$\6
+\4\&{else} $\\{clr}\K3\ast\\{default\_rule\_thickness}$;\2\6
+$\\{delta}\K\\{half}(\\{clr}-((\\{shift\_up}-\\{depth}(\|x))-(\\{height}(\|z)-%
+\\{shift\_down})))$;\6
+\&{if} $\\{delta}>0$ \1\&{then}\6
+\&{begin} \37$\\{shift\_up}\K\\{shift\_up}+\\{delta}$;\5
+$\\{shift\_down}\K\\{shift\_down}+\\{delta}$;\6
+\&{end};\2\6
+\&{end}\par
+\U754.\fi
+
+\M757. In the case of a fraction line, the minimum clearance depends on the
+actual
+thickness of the line.
+
+\Y\P$\4\X757:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of a
+fraction line\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_style}<\\{text\_style}$ \1\&{then}\5
+$\\{clr}\K3\ast\\{thickness}(\|q)$\6
+\4\&{else} $\\{clr}\K\\{thickness}(\|q)$;\2\6
+$\\{delta}\K\\{half}(\\{thickness}(\|q))$;\5
+$\\{delta1}\K\\{clr}-((\\{shift\_up}-\\{depth}(\|x))-(\\{axis\_height}(\\{cur%
+\_size})+\\{delta}))$;\5
+$\\{delta2}\K\\{clr}-((\\{axis\_height}(\\{cur\_size})-\\{delta})-(\\{height}(%
+\|z)-\\{shift\_down}))$;\6
+\&{if} $\\{delta1}>0$ \1\&{then}\5
+$\\{shift\_up}\K\\{shift\_up}+\\{delta1}$;\2\6
+\&{if} $\\{delta2}>0$ \1\&{then}\5
+$\\{shift\_down}\K\\{shift\_down}+\\{delta2}$;\2\6
+\&{end}\par
+\U754.\fi
+
+\M758. \P$\X758:Construct a vlist box for the fraction, according to \\{shift%
+\_up} and \\{shift\_down}\X\S$\6
+$\|v\K\\{new\_null\_box}$;\5
+$\\{type}(\|v)\K\\{vlist\_node}$;\5
+$\\{height}(\|v)\K\\{shift\_up}+\\{height}(\|x)$;\5
+$\\{depth}(\|v)\K\\{depth}(\|z)+\\{shift\_down}$;\5
+$\\{width}(\|v)\K\\{width}(\|x)$;\C{this also equals $\\{width}(\|z)$}\6
+\&{if} $\\{thickness}(\|q)=0$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{new\_kern}((\\{shift\_up}-\\{depth}(\|x))-(\\{height}(%
+\|z)-\\{shift\_down}))$;\5
+$\\{link}(\|p)\K\|z$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|y\K\\{fraction\_rule}(\\{thickness}(\|q))$;\6
+$\|p\K\\{new\_kern}((\\{axis\_height}(\\{cur\_size})-\\{delta})-\30(\\{height}(%
+\|z)-\\{shift\_down}))$;\6
+$\\{link}(\|y)\K\|p$;\5
+$\\{link}(\|p)\K\|z$;\6
+$\|p\K\\{new\_kern}((\\{shift\_up}-\\{depth}(\|x))-(\\{axis\_height}(\\{cur%
+\_size})+\\{delta}))$;\5
+$\\{link}(\|p)\K\|y$;\6
+\&{end};\2\6
+$\\{link}(\|x)\K\|p$;\5
+$\\{list\_ptr}(\|v)\K\|x$\par
+\U754.\fi
+
+\M759. \P$\X759:Put the \(f)fraction into a box with its delimiters, and make $%
+\\{new\_hlist}(\|q)$ point to it\X\S$\6
+\&{if} $\\{cur\_style}<\\{text\_style}$ \1\&{then}\5
+$\\{delta}\K\\{delim1}(\\{cur\_size})$\6
+\4\&{else} $\\{delta}\K\\{delim2}(\\{cur\_size})$;\2\6
+$\|x\K\\{var\_delimiter}(\\{left\_delimiter}(\|q),\39\\{cur\_size},\39%
+\\{delta})$;\5
+$\\{link}(\|x)\K\|v$;\6
+$\|z\K\\{var\_delimiter}(\\{right\_delimiter}(\|q),\39\\{cur\_size},\39%
+\\{delta})$;\5
+$\\{link}(\|v)\K\|z$;\6
+$\\{new\_hlist}(\|q)\K\\{hpack}(\|x,\39\\{natural})$\par
+\U754.\fi
+
+\M760. If the nucleus of an \\{op\_noad} is a single character, it is to be
+centered vertically with respect to the axis, after first being enlarged
+(via a character list in the font) if we are in display style.  The normal
+convention for placing displayed limits is to put them above and below the
+operator in display style.
+
+The italic correction is removed from the character if there is a subscript
+and the limits are not being displayed. The \\{make\_op}
+routine returns the value that should be used as an offset between
+subscript and superscript.
+
+After \\{make\_op} has acted, $\\{subtype}(\|q)$ will be \\{limits} if and only
+if
+the limits have been set above and below the operator. In that case,
+$\\{new\_hlist}(\|q)$ will already contain the desired final box.
+
+\Y\P$\4\X745:Declare math construction procedures\X\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{make\_op}(\|q:\\{pointer})$: \37\\{scaled};\6
+\4\&{var} \37\\{delta}: \37\\{scaled};\C{offset between subscript and
+superscript}\6
+$\|p,\39\|v,\39\|x,\39\|y,\39\|z$: \37\\{pointer};\C{temporary registers for
+box construction}\6
+\|c: \37\\{quarterword};\ \|i: \37\\{four\_quarters};\C{registers for character
+examination}\6
+$\\{shift\_up},\39\\{shift\_down}$: \37\\{scaled};\C{dimensions for box
+calculation}\2\6
+\&{begin} \37\&{if} $(\\{subtype}(\|q)=\\{normal})\W(\\{cur\_style}<\\{text%
+\_style})$ \1\&{then}\5
+$\\{subtype}(\|q)\K\\{limits}$;\2\6
+\&{if} $\\{math\_type}(\\{nucleus}(\|q))=\\{math\_char}$ \1\&{then}\6
+\&{begin} \37$\\{fetch}(\\{nucleus}(\|q))$;\6
+\&{if} $(\\{cur\_style}<\\{text\_style})\W(\\{char\_tag}(\\{cur\_i})=\\{list%
+\_tag})$ \1\&{then}\C{make it larger}\6
+\&{begin} \37$\|c\K\\{rem\_byte}(\\{cur\_i})$;\5
+$\|i\K\\{orig\_char\_info}(\\{cur\_f})(\|c)$;\6
+\&{if} $\\{char\_exists}(\|i)$ \1\&{then}\6
+\&{begin} \37$\\{cur\_c}\K\|c$;\5
+$\\{cur\_i}\K\|i$;\5
+$\\{character}(\\{nucleus}(\|q))\K\|c$;\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{delta}\K\\{char\_italic}(\\{cur\_f})(\\{cur\_i})$;\5
+$\|x\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cur\_style},\39\\{math\_kcode}(%
+\|q))$;\6
+\&{if} $(\\{math\_type}(\\{subscr}(\|q))\I\\{empty})\W(\\{subtype}(\|q)\I%
+\\{limits})$ \1\&{then}\5
+$\\{width}(\|x)\K\\{width}(\|x)-\\{delta}$;\C{remove italic correction}\2\6
+$\\{shift\_amount}(\|x)\K\\{half}(\\{height}(\|x)-\\{depth}(\|x))-\\{axis%
+\_height}(\\{cur\_size})$;\C{center vertically}\6
+$\\{math\_type}(\\{nucleus}(\|q))\K\\{sub\_box}$;\5
+$\\{info}(\\{nucleus}(\|q))\K\|x$;\6
+\&{end}\6
+\4\&{else} $\\{delta}\K0$;\2\6
+\&{if} $\\{subtype}(\|q)=\\{limits}$ \1\&{then}\5
+\X761:Construct a box with limits above and below it, skewed by \\{delta}\X;\2\6
+$\\{make\_op}\K\\{delta}$;\6
+\&{end};\par
+\fi
+
+\M761. The following program builds a vlist box \|v for displayed limits. The
+width of the box is not affected by the fact that the limits may be skewed.
+
+\Y\P$\4\X761:Construct a box with limits above and below it, skewed by %
+\\{delta}\X\S$\6
+\&{begin} \37$\|x\K\\{clean\_box}(\\{supscr}(\|q),\39\\{sup\_style}(\\{cur%
+\_style}),\39\\{math\_kcode}(\|q))$;\5
+$\|y\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cur\_style},\39\\{math\_kcode}(%
+\|q))$;\5
+$\|z\K\\{clean\_box}(\\{subscr}(\|q),\39\\{sub\_style}(\\{cur\_style}),\39%
+\\{math\_kcode}(\|q))$;\5
+$\|v\K\\{new\_null\_box}$;\5
+$\\{type}(\|v)\K\\{vlist\_node}$;\5
+$\\{width}(\|v)\K\\{width}(\|y)$;\6
+\&{if} $\\{width}(\|x)>\\{width}(\|v)$ \1\&{then}\5
+$\\{width}(\|v)\K\\{width}(\|x)$;\2\6
+\&{if} $\\{width}(\|z)>\\{width}(\|v)$ \1\&{then}\5
+$\\{width}(\|v)\K\\{width}(\|z)$;\2\6
+$\|x\K\\{rebox}(\|x,\39\\{width}(\|v))$;\5
+$\|y\K\\{rebox}(\|y,\39\\{width}(\|v))$;\5
+$\|z\K\\{rebox}(\|z,\39\\{width}(\|v))$;\6
+$\\{shift\_amount}(\|x)\K\\{half}(\\{delta})$;\5
+$\\{shift\_amount}(\|z)\K-\\{shift\_amount}(\|x)$;\5
+$\\{height}(\|v)\K\\{height}(\|y)$;\5
+$\\{depth}(\|v)\K\\{depth}(\|y)$;\5
+\X762:Attach the limits to \|y and adjust $\\{height}(\|v)$, $\\{depth}(\|v)$
+to account for their presence\X;\6
+$\\{new\_hlist}(\|q)\K\|v$;\6
+\&{end}\par
+\U760.\fi
+
+\M762. We use \\{shift\_up} and \\{shift\_down} in the following program for
+the
+amount of glue between the displayed operator \|y and its limits \|x and
+\|z. The vlist inside box \|v will consist of \|x followed by \|y followed
+by \|z, with kern nodes for the spaces between and around them.
+
+\Y\P$\4\X762:Attach the limits to \|y and adjust $\\{height}(\|v)$, $\\{depth}(%
+\|v)$ to account for their presence\X\S$\6
+\&{if} $\\{math\_type}(\\{supscr}(\|q))=\\{empty}$ \1\&{then}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{space\_ptr}(\|x))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|x))$;\5
+$\\{free\_node}(\|x,\39\\{box\_node\_size})$;\5
+$\\{list\_ptr}(\|v)\K\|y$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{shift\_up}\K\\{big\_op\_spacing3}-\\{depth}(\|x)$;\6
+\&{if} $\\{shift\_up}<\\{big\_op\_spacing1}$ \1\&{then}\5
+$\\{shift\_up}\K\\{big\_op\_spacing1}$;\2\6
+$\|p\K\\{new\_kern}(\\{shift\_up})$;\5
+$\\{link}(\|p)\K\|y$;\5
+$\\{link}(\|x)\K\|p$;\6
+$\|p\K\\{new\_kern}(\\{big\_op\_spacing5})$;\5
+$\\{link}(\|p)\K\|x$;\5
+$\\{list\_ptr}(\|v)\K\|p$;\5
+$\\{height}(\|v)\K\\{height}(\|v)+\\{big\_op\_spacing5}+\\{height}(\|x)+%
+\\{depth}(\|x)+\\{shift\_up}$;\6
+\&{end};\2\6
+\&{if} $\\{math\_type}(\\{subscr}(\|q))=\\{empty}$ \1\&{then}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{space\_ptr}(\|z))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|z))$;\5
+$\\{free\_node}(\|z,\39\\{box\_node\_size})$\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{shift\_down}\K\\{big\_op\_spacing4}-\\{height}(%
+\|z)$;\6
+\&{if} $\\{shift\_down}<\\{big\_op\_spacing2}$ \1\&{then}\5
+$\\{shift\_down}\K\\{big\_op\_spacing2}$;\2\6
+$\|p\K\\{new\_kern}(\\{shift\_down})$;\5
+$\\{link}(\|y)\K\|p$;\5
+$\\{link}(\|p)\K\|z$;\6
+$\|p\K\\{new\_kern}(\\{big\_op\_spacing5})$;\5
+$\\{link}(\|z)\K\|p$;\5
+$\\{depth}(\|v)\K\\{depth}(\|v)+\\{big\_op\_spacing5}+\\{height}(\|z)+%
+\\{depth}(\|z)+\\{shift\_down}$;\6
+\&{end}\2\par
+\U761.\fi
+
+\M763. A ligature found in a math formula does not create a \\{ligature\_node},
+because
+there is no question of hyphenation afterwards; the ligature will simply be
+stored in an ordinary \\{char\_node}, after residing in an \\{ord\_noad}.
+
+The \\{math\_type} is converted to \\{math\_text\_char} here if we would not
+want to
+apply an italic correction to the current character unless it belongs
+to a math font (i.e., a font with $\\{space}=0$).
+
+No boundary characters enter into these ligatures.
+
+\Y\P$\4\X745:Declare math construction procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{make\_ord}(\|q:\\{pointer})$;\6
+\4\&{label} \37$\\{restart},\39\\{exit}$;\6
+\4\&{var} \37\|a: \37\\{integer};\C{address of lig/kern instruction}\6
+$\\{gp},\39\\{gq},\39\|p,\39\|r$: \37\\{pointer};\C{temporary registers for
+list manipulation}\6
+\\{rr}: \37\\{halfword};\2\6
+\&{begin} \37\\{restart}: \37\hbox{}\6
+\&{if} $(\\{math\_type}(\\{subscr}(\|q))=\\{empty})\W(\\{math\_type}(%
+\\{supscr}(\|q))=\\{empty})\W\30((\\{math\_type}(\\{nucleus}(\|q))=\\{math%
+\_char})\V(\\{math\_type}(\\{nucleus}(\|q))=\\{math\_jchar}))$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{link}(\|q)$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{if} $(\\{type}(\|p)\G\\{ord\_noad})\W(\\{type}(\|p)\L\\{punct\_noad})$ \1%
+\&{then}\6
+\&{if} $\\{fam}(\\{nucleus}(\|p))=\\{fam}(\\{nucleus}(\|q))$ \1\&{then}\6
+\&{if} $\\{math\_type}(\\{nucleus}(\|p))=\\{math\_char}$ \1\&{then}\6
+\&{begin} \37$\\{math\_type}(\\{nucleus}(\|q))\K\\{math\_text\_char}$;\5
+$\\{fetch}(\\{nucleus}(\|q))$;\6
+\&{if} $\\{char\_tag}(\\{cur\_i})=\\{lig\_tag}$ \1\&{then}\6
+\&{begin} \37$\|a\K\\{lig\_kern\_start}(\\{cur\_f})(\\{cur\_i})$;\5
+$\\{cur\_c}\K\\{character}(\\{nucleus}(\|p))$;\5
+$\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq}$;\6
+\&{if} $\\{skip\_byte}(\\{cur\_i})>\\{stop\_flag}$ \1\&{then}\6
+\&{begin} \37$\|a\K\\{lig\_kern\_restart}(\\{cur\_f})(\\{cur\_i})$;\5
+$\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq}$;\6
+\&{end};\2\6
+\~ \1\&{loop}\ \&{begin} \37\X764:If instruction \\{cur\_i} is a kern with %
+\\{cur\_c}, attach the kern after~\|q; or if it is a ligature with \\{cur\_c},
+combine noads \|q and~\|p appropriately; then \&{return} if the cursor has
+moved past a noad, or \&{goto} \\{restart}\X;\6
+\&{if} $\\{skip\_byte}(\\{cur\_i})\G\\{stop\_flag}$ \1\&{then}\5
+\&{return};\2\6
+$\|a\K\|a+\\{qo}(\\{skip\_byte}(\\{cur\_i}))+1$;\5
+$\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq}$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{math\_type}(\\{nucleus}(\|p))=\\{math\_jchar}$ \1\&{then}%
+\6
+\&{begin} \37$\\{math\_type}(\\{nucleus}(\|q))\K\\{math\_text\_jchar}$;\5
+$\\{fetch}(\\{nucleus}(\|p))$;\5
+$\|a\K\\{cur\_c}$;\5
+$\\{fetch}(\\{nucleus}(\|q))$;\6
+\&{if} $\\{char\_tag}(\\{cur\_i})=\\{gk\_tag}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_c}\K\|a$;\5
+$\|a\K\\{glue\_kern\_start}(\\{cur\_f})(\\{cur\_i})$;\C{\\{cur\_c}:=qi(\\{get%
+\_jfm\_pos}(\\{math\_kcode}(p),                    \\{fam%
+\_fnt}(fam(nucleus(p))+\\{cur\_size})));}\6
+\1\&{repeat} \37$\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq}$;\6
+\&{if} $\\{next\_char}(\\{cur\_i})=\\{cur\_c}$ \1\&{then}\6
+\&{if} $\\{op\_byte}(\\{cur\_i})<\\{kern\_flag}$ \1\&{then}\6
+\&{begin} \37$\\{gp}\K\\{font\_glue}[\\{cur\_f}]$;\5
+$\\{rr}\K\\{rem\_byte}(\\{cur\_i})$;\6
+\&{if} $\\{gp}\I\\{null}$ \1\&{then}\6
+\&{begin} \37\&{while} $((\\{type}(\\{gp})\I\\{rr})\W(\\{link}(\\{gp})\I%
+\\{null}))$ \1\&{do}\6
+\&{begin} \37$\\{gp}\K\\{link}(\\{gp})$;\6
+\&{end};\2\6
+$\\{gq}\K\\{glue\_ptr}(\\{gp})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{gp}\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{font\_glue}[\\{cur\_f}]\K\\{gp}$;\5
+$\\{gq}\K\\{null}$;\6
+\&{end};\2\6
+\&{if} $\\{gq}=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{type}(\\{gp})\K\\{rr}$;\5
+$\\{gq}\K\\{new\_spec}(\\{zero\_glue})$;\5
+$\\{glue\_ptr}(\\{gp})\K\\{gq}$;\5
+$\|a\K\\{exten\_base}[\\{cur\_f}]+\\{qi}((\\{qo}(\\{rr}))\ast3)$;\5
+$\\{width}(\\{gq})\K\\{font\_info}[\|a].\\{sc}$;\5
+$\\{stretch}(\\{gq})\K\\{font\_info}[\|a+1].\\{sc}$;\5
+$\\{shrink}(\\{gq})\K\\{font\_info}[\|a+2].\\{sc}$;\5
+$\\{add\_glue\_ref}(\\{gq})$;\5
+$\\{link}(\\{gp})\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{gp}\K\\{link}(\\{gp})$;\5
+$\\{glue\_ptr}(\\{gp})\K\\{null}$;\5
+$\\{link}(\\{gp})\K\\{null}$;\6
+\&{end};\2\6
+$\|p\K\\{new\_glue}(\\{gq})$;\5
+$\\{link}(\|p)\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\|p$;\5
+\&{return};\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|p\K\\{new\_kern}(\\{char\_kern}(\\{cur\_f})(\\{cur%
+\_i}))$;\5
+$\\{link}(\|p)\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\|p$;\5
+\&{return};\6
+\&{end};\2\2\6
+$\\{incr}(\|a)$;\6
+\4\&{until}\5
+$\\{skip\_byte}(\\{cur\_i})\G\\{stop\_flag}$;\2\6
+\&{end};\2\6
+\&{end};\2\2\2\2\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M764. Note that a ligature between an \\{ord\_noad} and another kind of noad
+is replaced by an \\{ord\_noad}, when the two noads collapse into one.
+But we could make a parenthesis (say) change shape when it follows
+certain letters. Presumably a font designer will define such
+ligatures only when this convention makes sense.
+
+\chardef\?='174 % vertical line to indicate character retention
+
+\Y\P$\4\X764:If instruction \\{cur\_i} is a kern with \\{cur\_c}, attach the
+kern after~\|q; or if it is a ligature with \\{cur\_c}, combine noads \|q and~%
+\|p appropriately; then \&{return} if the cursor has moved past a noad, or %
+\&{goto} \\{restart}\X\S$\6
+\&{if} $\\{next\_char}(\\{cur\_i})=\\{cur\_c}$ \1\&{then}\6
+\&{if} $\\{skip\_byte}(\\{cur\_i})\L\\{stop\_flag}$ \1\&{then}\6
+\&{if} $\\{op\_byte}(\\{cur\_i})\G\\{kern\_flag}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{new\_kern}(\\{char\_kern}(\\{cur\_f})(\\{cur\_i}))$;\5
+$\\{link}(\|p)\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\|p$;\5
+\&{return};\6
+\&{end}\6
+\4\&{else} \&{begin} \37\\{check\_interrupt};\C{allow a way out of infinite
+ligature loop}\6
+\&{case} $\\{op\_byte}(\\{cur\_i})$ \1\&{of}\6
+\4$\\{qi}(1),\39\\{qi}(5)$: \37$\\{character}(\\{nucleus}(\|q))\K\\{rem\_byte}(%
+\\{cur\_i})$;\C{\.{=:\?}, \.{=:\?>}}\6
+\4$\\{qi}(2),\39\\{qi}(6)$: \37$\\{character}(\\{nucleus}(\|p))\K\\{rem\_byte}(%
+\\{cur\_i})$;\C{\.{\?=:}, \.{\?=:>}}\6
+\4$\\{qi}(3),\39\\{qi}(7),\39\\{qi}(11)$: \37\&{begin} \37$\|r\K\\{new\_noad}$;%
+\C{\.{\?=:\?}, \.{\?=:\?>}, \.{\?=:\?>>}}\6
+$\\{character}(\\{nucleus}(\|r))\K\\{rem\_byte}(\\{cur\_i})$;\5
+$\\{fam}(\\{nucleus}(\|r))\K\\{fam}(\\{nucleus}(\|q))$;\6
+$\\{link}(\|q)\K\|r$;\5
+$\\{link}(\|r)\K\|p$;\6
+\&{if} $\\{op\_byte}(\\{cur\_i})<\\{qi}(11)$ \1\&{then}\5
+$\\{math\_type}(\\{nucleus}(\|r))\K\\{math\_char}$\6
+\4\&{else} $\\{math\_type}(\\{nucleus}(\|r))\K\\{math\_text\_char}$;\C{prevent
+combination}\2\6
+\&{end};\6
+\4\&{othercases} \37\&{begin} \37$\\{link}(\|q)\K\\{link}(\|p)$;\5
+$\\{character}(\\{nucleus}(\|q))\K\\{rem\_byte}(\\{cur\_i})$;\C{\.{=:}}\6
+$\\{mem}[\\{subscr}(\|q)]\K\\{mem}[\\{subscr}(\|p)]$;\5
+$\\{mem}[\\{supscr}(\|q)]\K\\{mem}[\\{supscr}(\|p)]$;\6
+$\\{free\_node}(\|p,\39\\{noad\_size})$;\6
+\&{end}\2\6
+\&{endcases};\6
+\&{if} $\\{op\_byte}(\\{cur\_i})>\\{qi}(3)$ \1\&{then}\5
+\&{return};\2\6
+$\\{math\_type}(\\{nucleus}(\|q))\K\\{math\_char}$;\5
+\&{goto} \37\\{restart};\6
+\&{end}\2\2\2\par
+\U763.\fi
+
+\M765. When we get to the following part of the program, we have ``fallen
+through''
+from cases that did not lead to \\{check\_dimensions} or \\{done\_with\_noad}
+or
+\\{done\_with\_node}. Thus, \|q~points to a noad whose nucleus may need to be
+converted to an hlist, and whose subscripts and superscripts need to be
+appended if they are present.
+
+If $\\{nucleus}(\|q)$ is not a \\{math\_char}, the variable \\{delta} is the
+amount
+by which a superscript should be moved right with respect to a subscript
+when both are present.
+
+\Y\P$\4\X765:Convert \(n)$\\{nucleus}(\|q)$ to an hlist and attach the
+sub/superscripts\X\S$\6
+\&{case} $\\{math\_type}(\\{nucleus}(\|q))$ \1\&{of}\6
+\4$\\{math\_char},\39\\{math\_text\_char},\39\\{math\_jchar},\39\\{math\_text%
+\_jchar}$: \37\X766:Create a character node \|p for $\\{nucleus}(\|q)$,
+possibly followed by a kern node for the italic correction, and set \\{delta}
+to the italic correction if a subscript is present\X;\6
+\4\\{empty}: \37$\|p\K\\{null}$;\6
+\4\\{sub\_box}: \37$\|p\K\\{info}(\\{nucleus}(\|q))$;\6
+\4\\{sub\_mlist}: \37\&{begin} \37$\\{cur\_mlist}\K\\{info}(\\{nucleus}(\|q))$;%
+\5
+$\\{save\_style}\K\\{cur\_style}$;\5
+$\\{mlist\_penalties}\K\\{false}$;\5
+\\{mlist\_to\_hlist};\C{recursive call}\6
+$\\{cur\_style}\K\\{save\_style}$;\5
+\X714:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur%
+\_style}\X;\6
+$\|p\K\\{hpack}(\\{link}(\\{temp\_head}),\39\\{natural})$;\6
+\&{end};\6
+\4\&{othercases} \37$\\{confusion}(\.{"mlist2"})$\2\6
+\&{endcases};\6
+$\\{new\_hlist}(\|q)\K\|p$;\6
+\&{if} $(\\{math\_type}(\\{subscr}(\|q))=\\{empty})\W(\\{math\_type}(%
+\\{supscr}(\|q))=\\{empty})$ \1\&{then}\5
+\&{goto} \37\\{check\_dimensions};\2\6
+$\\{make\_scripts}(\|q,\39\\{delta})$\par
+\U739.\fi
+
+\M766. \P$\X766:Create a character node \|p for $\\{nucleus}(\|q)$, possibly
+followed by a kern node for the italic correction, and set \\{delta} to the
+italic correction if a subscript is present\X\S$\6
+\&{begin} \37$\\{fetch}(\\{nucleus}(\|q))$;\6
+\&{if} $\\{char\_exists}(\\{cur\_i})$ \1\&{then}\6
+\&{begin} \37$\\{delta}\K\\{char\_italic}(\\{cur\_f})(\\{cur\_i})$;\5
+$\|p\K\\{new\_character}(\\{cur\_f},\39\\{qo}(\\{cur\_c}))$;\5
+$\|u\K\|p$;\6
+\&{if} $\\{font\_dir}[\\{cur\_f}]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|u)\K\\{get\_avail}$;\5
+$\|u\K\\{link}(\|u)$;\5
+$\\{info}(\|u)\K\\{math\_kcode}(\|q)$;\6
+\&{end};\2\6
+\&{if} $((\\{math\_type}(\\{nucleus}(\|q))=\\{math\_text\_char})\V(\\{math%
+\_type}(\\{nucleus}(\|q))=\\{math\_text\_jchar}))\W(\\{space}(\\{cur\_f})\I0)$ %
+\1\&{then}\5
+$\\{delta}\K0$;\C{no italic correction in mid-word of text font}\2\6
+\&{if} $(\\{math\_type}(\\{subscr}(\|q))=\\{empty})\W(\\{delta}\I0)$ \1\&{then}%
+\6
+\&{begin} \37$\\{link}(\|u)\K\\{new\_kern}(\\{delta})$;\5
+$\\{delta}\K0$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} $\|p\K\\{null}$;\2\6
+\&{end}\par
+\U765.\fi
+
+\M767. The purpose of $\\{make\_scripts}(\|q,\\{delta})$ is to attach the
+subscript and/or
+superscript of noad \|q to the list that starts at $\\{new\_hlist}(\|q)$,
+given that subscript and superscript aren't both empty. The superscript
+will appear to the right of the subscript by a given distance \\{delta}.
+
+We set \\{shift\_down} and \\{shift\_up} to the minimum amounts to shift the
+baseline of subscripts and superscripts based on the given nucleus.
+
+\Y\P$\4\X745:Declare math construction procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{make\_scripts}(\|q:\\{pointer};\,\35\\{delta}:%
+\\{scaled})$;\6
+\4\&{var} \37$\|p,\39\|x,\39\|y,\39\|z$: \37\\{pointer};\C{temporary registers
+for box construction}\6
+$\\{shift\_up},\39\\{shift\_down},\39\\{clr}$: \37\\{scaled};\C{dimensions in
+the calculation}\6
+\|t: \37\\{small\_number};\C{subsidiary size code}\2\6
+\&{begin} \37$\|p\K\\{new\_hlist}(\|q)$;\6
+\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{begin} \37$\\{shift\_up}\K0$;\5
+$\\{shift\_down}\K0$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|z\K\\{hpack}(\|p,\39\\{natural})$;\6
+\&{if} $\\{cur\_style}<\\{script\_style}$ \1\&{then}\5
+$\|t\K\\{script\_size}$\ \&{else} $\|t\K\\{script\_script\_size}$;\2\6
+$\\{shift\_up}\K\\{height}(\|z)-\\{sup\_drop}(\|t)$;\5
+$\\{shift\_down}\K\\{depth}(\|z)+\\{sub\_drop}(\|t)$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|z))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|z))$;\5
+$\\{free\_node}(\|z,\39\\{box\_node\_size})$;\6
+\&{end};\2\6
+\&{if} $\\{math\_type}(\\{supscr}(\|q))=\\{empty}$ \1\&{then}\5
+\X768:Construct a subscript box \|x when there is no superscript\X\6
+\4\&{else} \&{begin} \37\X769:Construct a superscript box \|x\X;\6
+\&{if} $\\{math\_type}(\\{subscr}(\|q))=\\{empty}$ \1\&{then}\5
+$\\{shift\_amount}(\|x)\K-\\{shift\_up}$\6
+\4\&{else} \X770:Construct a sub/superscript combination box \|x, with the
+superscript offset by \\{delta}\X;\2\6
+\&{end};\2\6
+\&{if} $\\{new\_hlist}(\|q)=\\{null}$ \1\&{then}\5
+$\\{new\_hlist}(\|q)\K\|x$\6
+\4\&{else} \&{begin} \37$\|p\K\\{new\_hlist}(\|q)$;\6
+\&{while} $\\{link}(\|p)\I\\{null}$ \1\&{do}\5
+$\|p\K\\{link}(\|p)$;\2\6
+$\\{link}(\|p)\K\|x$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M768. When there is a subscript without a superscript, the top of the
+subscript
+should not exceed the baseline plus four-fifths of the x-height.
+
+\Y\P$\4\X768:Construct a subscript box \|x when there is no superscript\X\S$\6
+\&{begin} \37$\|x\K\\{clean\_box}(\\{subscr}(\|q),\39\\{sub\_style}(\\{cur%
+\_style}),\39\\{math\_kcode}(\|q))$;\5
+$\\{width}(\|x)\K\\{width}(\|x)+\\{script\_space}$;\6
+\&{if} $\\{shift\_down}<\\{sub1}(\\{cur\_size})$ \1\&{then}\5
+$\\{shift\_down}\K\\{sub1}(\\{cur\_size})$;\2\6
+$\\{clr}\K\\{height}(\|x)-(\\{abs}(\\{math\_x\_height}(\\{cur\_size})\ast4)%
+\mathbin{\&{div}}5)$;\6
+\&{if} $\\{shift\_down}<\\{clr}$ \1\&{then}\5
+$\\{shift\_down}\K\\{clr}$;\2\6
+$\\{shift\_amount}(\|x)\K\\{shift\_down}$;\6
+\&{end}\par
+\U767.\fi
+
+\M769. The bottom of a superscript should never descend below the baseline plus
+one-fourth of the x-height.
+
+\Y\P$\4\X769:Construct a superscript box \|x\X\S$\6
+\&{begin} \37$\|x\K\\{clean\_box}(\\{supscr}(\|q),\39\\{sup\_style}(\\{cur%
+\_style}),\39\\{math\_kcode}(\|q))$;\5
+$\\{width}(\|x)\K\\{width}(\|x)+\\{script\_space}$;\6
+\&{if} $\\{odd}(\\{cur\_style})$ \1\&{then}\5
+$\\{clr}\K\\{sup3}(\\{cur\_size})$\6
+\4\&{else} \&{if} $\\{cur\_style}<\\{text\_style}$ \1\&{then}\5
+$\\{clr}\K\\{sup1}(\\{cur\_size})$\6
+\4\&{else} $\\{clr}\K\\{sup2}(\\{cur\_size})$;\2\2\6
+\&{if} $\\{shift\_up}<\\{clr}$ \1\&{then}\5
+$\\{shift\_up}\K\\{clr}$;\2\6
+$\\{clr}\K\\{depth}(\|x)+(\\{abs}(\\{math\_x\_height}(\\{cur\_size}))\mathbin{%
+\&{div}}4)$;\6
+\&{if} $\\{shift\_up}<\\{clr}$ \1\&{then}\5
+$\\{shift\_up}\K\\{clr}$;\2\6
+\&{end}\par
+\U767.\fi
+
+\M770. When both subscript and superscript are present, the subscript must be
+separated from the superscript by at least four times \\{default\_rule%
+\_thickness}.
+If this condition would be violated, the subscript moves down, after which
+both subscript and superscript move up so that the bottom of the superscript
+is at least as high as the baseline plus four-fifths of the x-height.
+
+\Y\P$\4\X770:Construct a sub/superscript combination box \|x, with the
+superscript offset by \\{delta}\X\S$\6
+\&{begin} \37$\|y\K\\{clean\_box}(\\{subscr}(\|q),\39\\{sub\_style}(\\{cur%
+\_style}),\39\\{math\_kcode}(\|q))$;\5
+$\\{width}(\|y)\K\\{width}(\|y)+\\{script\_space}$;\6
+\&{if} $\\{shift\_down}<\\{sub2}(\\{cur\_size})$ \1\&{then}\5
+$\\{shift\_down}\K\\{sub2}(\\{cur\_size})$;\2\6
+$\\{clr}\K4\ast\\{default\_rule\_thickness}-((\\{shift\_up}-\\{depth}(\|x))-(%
+\\{height}(\|y)-\\{shift\_down}))$;\6
+\&{if} $\\{clr}>0$ \1\&{then}\6
+\&{begin} \37$\\{shift\_down}\K\\{shift\_down}+\\{clr}$;\5
+$\\{clr}\K(\\{abs}(\\{math\_x\_height}(\\{cur\_size})\ast4)\mathbin{%
+\&{div}}5)-(\\{shift\_up}-\\{depth}(\|x))$;\6
+\&{if} $\\{clr}>0$ \1\&{then}\6
+\&{begin} \37$\\{shift\_up}\K\\{shift\_up}+\\{clr}$;\5
+$\\{shift\_down}\K\\{shift\_down}-\\{clr}$;\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{shift\_amount}(\|x)\K\\{delta}$;\C{superscript is \\{delta} to the right of
+the subscript}\6
+$\|p\K\\{new\_kern}((\\{shift\_up}-\\{depth}(\|x))-(\\{height}(\|y)-\\{shift%
+\_down}))$;\5
+$\\{link}(\|x)\K\|p$;\5
+$\\{link}(\|p)\K\|y$;\5
+$\|x\K\\{vpack}(\|x,\39\\{natural})$;\5
+$\\{shift\_amount}(\|x)\K\\{shift\_down}$;\6
+\&{end}\par
+\U767.\fi
+
+\M771. We have now tied up all the loose ends of the first pass of \\{mlist\_to%
+\_hlist}.
+The second pass simply goes through and hooks everything together with the
+proper glue and penalties. It also handles the \\{left\_noad} and \\{right%
+\_noad} that
+might be present, since \\{max\_h} and \\{max\_d} are now known. Variable \|p
+points
+to a node at the current end of the final hlist.
+
+\Y\P$\4\X771:Make a second pass over the mlist, removing all noads and
+inserting the proper spacing and penalties\X\S$\6
+$\|p\K\\{temp\_head}$;\5
+$\\{link}(\|p)\K\\{null}$;\5
+$\|q\K\\{mlist}$;\5
+$\\{r\_type}\K0$;\5
+$\\{cur\_style}\K\\{style}$;\5
+\X714:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur%
+\_style}\X;\6
+\&{while} $\|q\I\\{null}$ \1\&{do}\6
+\&{begin} \37\X772:If node \|q is a style node, change the style and \&{goto} %
+\\{delete\_q}; otherwise if it is not a noad, put it into the hlist, advance %
+\|q, and \&{goto} \\{done}; otherwise set \|s to the size of noad \|q, set \|t
+to the associated type ($\\{ord\_noad}\to\\{inner\_noad}$), and set \\{pen} to
+the associated penalty\X;\6
+\X777:Append inter-element spacing based on \\{r\_type} and \|t\X;\6
+\X778:Append any \\{new\_hlist} entries for \|q, and any appropriate penalties%
+\X;\6
+$\\{r\_type}\K\|t$;\6
+\4\\{delete\_q}: \37$\|r\K\|q$;\5
+$\|q\K\\{link}(\|q)$;\5
+$\\{free\_node}(\|r,\39\|s)$;\6
+\4\\{done}: \37\&{end}\2\par
+\U737.\fi
+
+\M772. Just before doing the big   \&{case}  switch in the second pass, the
+program
+sets up default values so that most of the branches are short.
+
+\Y\P$\4\X772:If node \|q is a style node, change the style and \&{goto} %
+\\{delete\_q}; otherwise if it is not a noad, put it into the hlist, advance %
+\|q, and \&{goto} \\{done}; otherwise set \|s to the size of noad \|q, set \|t
+to the associated type ($\\{ord\_noad}\to\\{inner\_noad}$), and set \\{pen} to
+the associated penalty\X\S$\6
+$\|t\K\\{ord\_noad}$;\5
+$\|s\K\\{noad\_size}$;\5
+$\\{pen}\K\\{inf\_penalty}$;\6
+\&{case} $\\{type}(\|q)$ \1\&{of}\6
+\4$\\{op\_noad},\39\\{open\_noad},\39\\{close\_noad},\39\\{punct\_noad},\39%
+\\{inner\_noad}$: \37$\|t\K\\{type}(\|q)$;\6
+\4\\{bin\_noad}: \37\&{begin} \37$\|t\K\\{bin\_noad}$;\5
+$\\{pen}\K\\{bin\_op\_penalty}$;\6
+\&{end};\6
+\4\\{rel\_noad}: \37\&{begin} \37$\|t\K\\{rel\_noad}$;\5
+$\\{pen}\K\\{rel\_penalty}$;\6
+\&{end};\6
+\4$\\{ord\_noad},\39\\{vcenter\_noad},\39\\{over\_noad},\39\\{under\_noad}$: %
+\37\\{do\_nothing};\6
+\4\\{radical\_noad}: \37$\|s\K\\{radical\_noad\_size}$;\6
+\4\\{accent\_noad}: \37$\|s\K\\{accent\_noad\_size}$;\6
+\4\\{fraction\_noad}: \37\&{begin} \37$\|t\K\\{inner\_noad}$;\5
+$\|s\K\\{fraction\_noad\_size}$;\6
+\&{end};\6
+\4$\\{left\_noad},\39\\{right\_noad}$: \37$\|t\K\\{make\_left\_right}(\|q,\39%
+\\{style},\39\\{max\_d},\39\\{max\_h})$;\6
+\4\\{style\_node}: \37\X774:Change the current style and \&{goto} \\{delete\_q}%
+\X;\6
+\4$\\{whatsit\_node},\39\\{penalty\_node},\39\\{rule\_node},\39\\{disc\_node},%
+\39\\{adjust\_node},\39\\{ins\_node},\39\\{mark\_node},\39\\{glue\_node},\39%
+\\{kern\_node}$: \37\hbox{}\6
+\&{begin} \37$\\{link}(\|p)\K\|q$;\5
+$\|p\K\|q$;\5
+$\|q\K\\{link}(\|q)$;\5
+$\\{link}(\|p)\K\\{null}$;\5
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4\\{disp\_node}: \37\&{begin} \37$\\{link}(\|p)\K\|q$;\5
+$\|p\K\|q$;\5
+$\|q\K\\{link}(\|q)$;\5
+$\\{link}(\|p)\K\\{null}$;\5
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4\&{othercases} \37$\\{confusion}(\.{"mlist3"})$\2\6
+\&{endcases}\par
+\U771.\fi
+
+\M773. The \\{make\_left\_right} function constructs a left or right delimiter
+of
+the required size and returns the value \\{open\_noad} or \\{close\_noad}. The
+\\{right\_noad} and \\{left\_noad} will both be based on the original %
+\\{style},
+so they will have consistent sizes.
+
+We use the fact that $\\{right\_noad}-\\{left\_noad}=\\{close\_noad}-\\{open%
+\_noad}$.
+
+\Y\P$\4\X745:Declare math construction procedures\X\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{make\_left\_right}(\|q:\\{pointer};\,\35\\{style}:%
+\\{small\_number};\,\35\\{max\_d},\39\\{max\_h}:\\{scaled})$: \37\\{small%
+\_number};\6
+\4\&{var} \37$\\{delta},\39\\{delta1},\39\\{delta2}$: \37\\{scaled};%
+\C{dimensions used in the calculation}\2\6
+\&{begin} \37\&{if} $\\{style}<\\{script\_style}$ \1\&{then}\5
+$\\{cur\_size}\K\\{text\_size}$\6
+\4\&{else} $\\{cur\_size}\K16\ast((\\{style}-\\{text\_style})\mathbin{%
+\&{div}}2)$;\2\6
+$\\{delta2}\K\\{max\_d}+\\{axis\_height}(\\{cur\_size})$;\5
+$\\{delta1}\K\\{max\_h}+\\{max\_d}-\\{delta2}$;\6
+\&{if} $\\{delta2}>\\{delta1}$ \1\&{then}\5
+$\\{delta1}\K\\{delta2}$;\C{\\{delta1} is max distance from axis}\2\6
+$\\{delta}\K(\\{delta1}\mathbin{\&{div}}500)\ast\\{delimiter\_factor}$;\5
+$\\{delta2}\K\\{delta1}+\\{delta1}-\\{delimiter\_shortfall}$;\6
+\&{if} $\\{delta}<\\{delta2}$ \1\&{then}\5
+$\\{delta}\K\\{delta2}$;\2\6
+$\\{new\_hlist}(\|q)\K\\{var\_delimiter}(\\{delimiter}(\|q),\39\\{cur\_size},%
+\39\\{delta})$;\5
+$\\{make\_left\_right}\K\\{type}(\|q)-(\\{left\_noad}-\\{open\_noad})$;\C{%
+\\{open\_noad} or \\{close\_noad}}\6
+\&{end};\par
+\fi
+
+\M774. \P$\X774:Change the current style and \&{goto} \\{delete\_q}\X\S$\6
+\&{begin} \37$\\{cur\_style}\K\\{subtype}(\|q)$;\5
+$\|s\K\\{style\_node\_size}$;\5
+\X714:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur%
+\_style}\X;\6
+\&{goto} \37\\{delete\_q};\6
+\&{end}\par
+\U772.\fi
+
+\M775. The inter-element spacing in math formulas depends on a $8\times8$ table
+that
+\TeX\ preloads as a 64-digit string. The elements of this string have the
+following significance:
+$$\vbox{\halign{#\hfil\cr
+\.0 means no space;\cr
+\.1 means a conditional thin space (\.{\\nonscript\\mskip\\thinmuskip});\cr
+\.2 means a thin space (\.{\\mskip\\thinmuskip});\cr
+\.3 means a conditional medium space
+(\.{\\nonscript\\mskip\\medmuskip});\cr
+\.4 means a conditional thick space
+(\.{\\nonscript\\mskip\\thickmuskip});\cr
+\.* means an impossible case.\cr}}$$
+This is all pretty cryptic, but {\sl The \TeX book\/} explains what is
+supposed to happen, and the string makes it happen.
+
+A global variable \\{magic\_offset} is computed so that if \|a and \|b are
+in the range $\\{ord\_noad}\to\\{inner\_noad}$, then $\\{str\_pool}[\|a\ast8+%
+\|b+\\{magic\_offset}]$
+is the digit for spacing between noad types \|a and \|b.
+
+If \PASCAL\ had provided a good way to preload constant arrays, this part of
+the program would not have been so strange.
+
+\Y\P\D \37$\\{math\_spacing}=$\6
+\hbox{\hskip-35pt}%
+\.{"0234000122*4000133**3**344*0400400*000000234000111*1111112341011"}\hbox{$ %
+\hskip-35pt$}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{magic\_offset}: \37\\{integer};\C{used to find inter-element spacing}\par
+\fi
+
+\M776. \P$\X776:Compute the magic offset\X\S$\6
+$\\{magic\_offset}\K\\{str\_start}[\\{math\_spacing}]-9\ast\\{ord\_noad}$\par
+\U1350.\fi
+
+\M777. \P$\X777:Append inter-element spacing based on \\{r\_type} and \|t\X\S$\6
+\&{if} $\\{r\_type}>0$ \1\&{then}\C{not the first noad}\6
+\&{begin} \37\&{case} $\\{so}(\\{str\_pool}[\\{r\_type}\ast8+\|t+\\{magic%
+\_offset}])$ \1\&{of}\6
+\4\.{"0"}: \37$\|x\K0$;\6
+\4\.{"1"}: \37\&{if} $\\{cur\_style}<\\{script\_style}$ \1\&{then}\5
+$\|x\K\\{thin\_mu\_skip\_code}$\ \&{else} $\|x\K0$;\2\6
+\4\.{"2"}: \37$\|x\K\\{thin\_mu\_skip\_code}$;\6
+\4\.{"3"}: \37\&{if} $\\{cur\_style}<\\{script\_style}$ \1\&{then}\5
+$\|x\K\\{med\_mu\_skip\_code}$\ \&{else} $\|x\K0$;\2\6
+\4\.{"4"}: \37\&{if} $\\{cur\_style}<\\{script\_style}$ \1\&{then}\5
+$\|x\K\\{thick\_mu\_skip\_code}$\ \&{else} $\|x\K0$;\2\6
+\4\&{othercases} \37$\\{confusion}(\.{"mlist4"})$\2\6
+\&{endcases};\6
+\&{if} $\|x\I0$ \1\&{then}\6
+\&{begin} \37$\|y\K\\{math\_glue}(\\{glue\_par}(\|x),\39\\{cur\_mu})$;\5
+$\|z\K\\{new\_glue}(\|y)$;\5
+$\\{glue\_ref\_count}(\|y)\K\\{null}$;\5
+$\\{link}(\|p)\K\|z$;\5
+$\|p\K\|z$;\6
+$\\{subtype}(\|z)\K\|x+1$;\C{store a symbolic subtype}\6
+\&{end};\2\6
+\&{end}\2\par
+\U771.\fi
+
+\M778. We insert a penalty node after the hlist entries of noad \|q if \\{pen}
+is not an ``infinite'' penalty, and if the node immediately following \|q
+is not a penalty node or a \\{rel\_noad} or absent entirely.
+
+\Y\P$\4\X778:Append any \\{new\_hlist} entries for \|q, and any appropriate
+penalties\X\S$\6
+\&{if} $\\{new\_hlist}(\|q)\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|p)\K\\{new\_hlist}(\|q)$;\6
+\1\&{repeat} \37$\|p\K\\{link}(\|p)$;\6
+\4\&{until}\5
+$\\{link}(\|p)=\\{null}$;\2\6
+\&{end};\2\6
+\&{if} $\\{penalties}$ \1\&{then}\6
+\&{if} $\\{link}(\|q)\I\\{null}$ \1\&{then}\6
+\&{if} $\\{pen}<\\{inf\_penalty}$ \1\&{then}\6
+\&{begin} \37$\\{r\_type}\K\\{type}(\\{link}(\|q))$;\6
+\&{if} $\\{r\_type}\I\\{penalty\_node}$ \1\&{then}\6
+\&{if} $\\{r\_type}\I\\{rel\_noad}$ \1\&{then}\6
+\&{begin} \37$\|z\K\\{new\_penalty}(\\{pen})$;\5
+$\\{link}(\|p)\K\|z$;\5
+$\|p\K\|z$;\6
+\&{end};\2\2\6
+\&{end}\2\2\2\par
+\U771.\fi
+
+\N779.  \[37] Alignment.
+It's sort of a miracle whenever \.{\\halign} and \.{\\valign} work, because
+they cut across so many of the control structures of \TeX.
+
+Therefore the
+present page is probably not the best place for a beginner to start reading
+this program; it is better to master everything else first.
+
+Let us focus our thoughts on an example of what the input might be, in order
+to get some idea about how the alignment miracle happens. The example doesn't
+do anything useful, but it is sufficiently general to indicate all of the
+special cases that must be dealt with; please do not be disturbed by its
+apparent complexity and meaninglessness.
+$$\vbox{\halign{\.{#}\hfil\cr
+{}\\tabskip 2pt plus 3pt\cr
+{}\\halign to 300pt\{u1\#v1\&\cr
+\hskip 50pt\\tabskip 1pt plus 1fil u2\#v2\&\cr
+\hskip 50pt u3\#v3\\cr\cr
+\hskip 25pt a1\&\\omit a2\&\\vrule\\cr\cr
+\hskip 25pt \\noalign\{\\vskip 3pt\}\cr
+\hskip 25pt b1\\span b2\\cr\cr
+\hskip 25pt \\omit\&c2\\span\\omit\\cr\}\cr}}$$
+Here's what happens:
+
+\yskip
+(0) When `\.{\\halign to 300pt\{}' is scanned, the \\{scan\_spec} routine
+places the 300pt dimension onto the \\{save\_stack}, and an \\{align\_group}
+code is placed above it. This will make it possible to complete the alignment
+when the matching `\.\}' is found.
+
+(1) The preamble is scanned next. Macros in the preamble are not expanded,
+except as part of a tabskip specification. For example, if \.{u2} had been
+a macro in the preamble above, it would have been expanded, since \TeX\
+must look for `\.{minus...}' as part of the tabskip glue. A ``preamble list''
+is constructed based on the user's preamble; in our case it contains the
+following seven items:
+$$\vbox{\halign{\.{#}\hfil\qquad&(#)\hfil\cr
+{}\\glue 2pt plus 3pt&the tabskip preceding column 1\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 1\cr
+{}\\glue 2pt plus 3pt&the tabskip between columns 1 and 2\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 2\cr
+{}\\glue 1pt plus 1fil&the tabskip between columns 2 and 3\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 3\cr
+{}\\glue 1pt plus 1fil&the tabskip following column 3\cr}}$$
+These ``alignrecord'' entries have the same size as an \\{unset\_node},
+since they will later be converted into such nodes. However, at the
+moment they have no \\{type} or \\{subtype} fields; they have \\{info} fields
+instead, and these \\{info} fields are initially set to the value \\{end%
+\_span},
+for reasons explained below. Furthermore, the alignrecord nodes have no
+\\{height} or \\{depth} fields; these are renamed \\{u\_part} and \\{v\_part},
+and they point to token lists for the templates of the alignment.
+For example, the \\{u\_part} field in the first alignrecord points to the
+token list `\.{u1}', i.e., the template preceding the `\.\#' for column~1.
+
+(2) \TeX\ now looks at what follows the \.{\\cr} that ended the preamble.
+It is not `\.{\\noalign}' or `\.{\\omit}', so this input is put back to
+be read again, and the template `\.{u1}' is fed to the scanner. Just
+before reading `\.{u1}', \TeX\ goes into restricted horizontal mode.
+Just after reading `\.{u1}', \TeX\ will see `\.{a1}', and then (when the
+{\.\&} is sensed) \TeX\ will see `\.{v1}'. Then \TeX\ scans an \\{endv}
+token, indicating the end of a column. At this point an \\{unset\_node} is
+created, containing the contents of the current hlist (i.e., `\.{u1a1v1}').
+The natural width of this unset node replaces the \\{width} field of the
+alignrecord for column~1; in general, the alignrecords will record the
+maximum natural width that has occurred so far in a given column.
+
+(3) Since `\.{\\omit}' follows the `\.\&', the templates for column~2
+are now bypassed. Again \TeX\ goes into restricted horizontal mode and
+makes an \\{unset\_node} from the resulting hlist; but this time the
+hlist contains simply `\.{a2}'. The natural width of the new unset box
+is remembered in the \\{width} field of the alignrecord for column~2.
+
+(4) A third \\{unset\_node} is created for column 3, using essentially the
+mechanism that worked for column~1; this unset box contains `\.{u3\\vrule
+v3}'. The vertical rule in this case has running dimensions that will later
+extend to the height and depth of the whole first row, since each \\{unset%
+\_node}
+in a row will eventually inherit the height and depth of its enclosing box.
+
+(5) The first row has now ended; it is made into a single unset box
+comprising the following seven items:
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: u1a1v1\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: a2\cr
+{}\\glue 1pt plus 1fil\cr
+{}\\unsetbox for 1 column: u3\\vrule v3\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+The width of this unset row is unimportant, but it has the correct height
+and depth, so the correct baselineskip glue will be computed as the row
+is inserted into a vertical list.
+
+(6) Since `\.{\\noalign}' follows the current \.{\\cr}, \TeX\ appends
+additional material (in this case \.{\\vskip 3pt}) to the vertical list.
+While processing this material, \TeX\ will be in internal vertical
+mode, and \\{no\_align\_group} will be on \\{save\_stack}.
+
+(7) The next row produces an unset box that looks like this:
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 2 columns: u1b1v1u2b2v2\cr
+{}\\glue 1pt plus 1fil\cr
+{}\\unsetbox for 1 column: {\rm(empty)}\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+The natural width of the unset box that spans columns 1~and~2 is stored
+in a ``span node,'' which we will explain later; the \\{info} field of the
+alignrecord for column~1 now points to the new span node, and the \\{info}
+of the span node points to \\{end\_span}.
+
+(8) The final row produces the unset box
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: {\rm(empty)}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 2 columns: u2c2v2\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+A new span node is attached to the alignrecord for column 2.
+
+(9) The last step is to compute the true column widths and to change all the
+unset boxes to hboxes, appending the whole works to the vertical list that
+encloses the \.{\\halign}. The rules for deciding on the final widths of
+each unset column box will be explained below.
+
+\yskip\noindent
+Note that as \.{\\halign} is being processed, we fearlessly give up control
+to the rest of \TeX. At critical junctures, an alignment routine is
+called upon to step in and do some little action, but most of the time
+these routines just lurk in the background. It's something like
+post-hypnotic suggestion.
+
+\fi
+
+\M780. We have mentioned that alignrecords contain no \\{height} or \\{depth}
+fields.
+Their \\{glue\_sign} and \\{glue\_order} are pre-empted as well, since it
+is necessary to store information about what to do when a template ends.
+This information is called the \\{extra\_info} field.
+
+\Y\P\D \37$\\{u\_part}(\#)\S\\{mem}[\#+\\{height\_offset}].\\{int}$\C{pointer
+to \<u_j> token list}\par
+\P\D \37$\\{v\_part}(\#)\S\\{mem}[\#+\\{depth\_offset}].\\{int}$\C{pointer to %
+\<v_j> token list}\par
+\P\D \37$\\{extra\_info}(\#)\S\\{info}(\#+\\{list\_offset})$\C{info to remember
+during template}\par
+\fi
+
+\M781. Alignments can occur within alignments, so a small stack is used to
+access
+the alignrecord information. At each level we have a \\{preamble} pointer,
+indicating the beginning of the preamble list; a \\{cur\_align} pointer,
+indicating the current position in the preamble list; a \\{cur\_span} pointer,
+indicating the value of \\{cur\_align} at the beginning of a sequence of
+spanned columns; a \\{cur\_loop} pointer, indicating the tabskip glue before
+an alignrecord that should be copied next if the current list is extended;
+and the \\{align\_state} variable, which indicates the nesting of braces so
+that \.{\\cr} and \.{\\span} and tab marks are properly intercepted.
+There also are pointers \\{cur\_head} and \\{cur\_tail} to the head and tail
+of a list of adjustments being moved out from horizontal mode to
+vertical~mode.
+
+The current values of these seven quantities appear in global variables;
+when they have to be pushed down, they are stored in 5-word nodes, and
+\\{align\_ptr} points to the topmost such node.
+
+\Y\P\D \37$\\{preamble}\S\\{link}(\\{align\_head})$\C{the current preamble
+list}\par
+\P\D \37$\\{align\_stack\_node\_size}=5$\C{number of \\{mem} words to save
+alignment states}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_align}: \37\\{pointer};\C{current position in preamble list}\6
+\4\\{cur\_span}: \37\\{pointer};\C{start of currently spanned columns in
+preamble list}\6
+\4\\{cur\_loop}: \37\\{pointer};\C{place to copy when extending a periodic
+preamble}\6
+\4\\{align\_ptr}: \37\\{pointer};\C{most recently pushed-down alignment stack
+node}\6
+\4$\\{cur\_head},\39\\{cur\_tail}$: \37\\{pointer};\C{adjustment list pointers}%
+\par
+\fi
+
+\M782. The \\{align\_state} and \\{preamble} variables are initialized
+elsewhere.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{align\_ptr}\K\\{null}$;\5
+$\\{cur\_align}\K\\{null}$;\5
+$\\{cur\_span}\K\\{null}$;\5
+$\\{cur\_loop}\K\\{null}$;\5
+$\\{cur\_head}\K\\{null}$;\5
+$\\{cur\_tail}\K\\{null}$;\par
+\fi
+
+\M783. Alignment stack maintenance is handled by a pair of trivial routines
+called \\{push\_alignment} and \\{pop\_alignment}.
+
+\Y\P\4\&{procedure}\1\  \37\\{push\_alignment};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new alignment stack node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\\{align\_stack\_node\_size})$;\5
+$\\{link}(\|p)\K\\{align\_ptr}$;\5
+$\\{info}(\|p)\K\\{cur\_align}$;\5
+$\\{llink}(\|p)\K\\{preamble}$;\5
+$\\{rlink}(\|p)\K\\{cur\_span}$;\5
+$\\{mem}[\|p+2].\\{int}\K\\{cur\_loop}$;\5
+$\\{mem}[\|p+3].\\{int}\K\\{align\_state}$;\5
+$\\{info}(\|p+4)\K\\{cur\_head}$;\5
+$\\{link}(\|p+4)\K\\{cur\_tail}$;\5
+$\\{align\_ptr}\K\|p$;\5
+$\\{cur\_head}\K\\{get\_avail}$;\6
+\&{end};\7
+\4\&{procedure}\1\  \37\\{pop\_alignment};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the top alignment stack node}\2\6
+\&{begin} \37$\\{free\_avail}(\\{cur\_head})$;\5
+$\|p\K\\{align\_ptr}$;\5
+$\\{cur\_tail}\K\\{link}(\|p+4)$;\5
+$\\{cur\_head}\K\\{info}(\|p+4)$;\5
+$\\{align\_state}\K\\{mem}[\|p+3].\\{int}$;\5
+$\\{cur\_loop}\K\\{mem}[\|p+2].\\{int}$;\5
+$\\{cur\_span}\K\\{rlink}(\|p)$;\5
+$\\{preamble}\K\\{llink}(\|p)$;\5
+$\\{cur\_align}\K\\{info}(\|p)$;\5
+$\\{align\_ptr}\K\\{link}(\|p)$;\5
+$\\{free\_node}(\|p,\39\\{align\_stack\_node\_size})$;\6
+\&{end};\par
+\fi
+
+\M784. \TeX\ has eight procedures that govern alignments: \\{init\_align} and
+\\{fin\_align} are used at the very beginning and the very end; \\{init\_row}
+and
+\\{fin\_row} are used at the beginning and end of individual rows; \\{init%
+\_span}
+is used at the beginning of a sequence of spanned columns (possibly involving
+only one column); \\{init\_col} and \\{fin\_col} are used at the beginning and
+end of individual columns; and \\{align\_peek} is used after \.{\\cr} to see
+whether the next item is \.{\\noalign}.
+
+We shall consider these routines in the order they are first used during
+the course of a complete \.{\\halign}, namely \\{init\_align}, \\{align\_peek},
+\\{init\_row}, \\{init\_span}, \\{init\_col}, \\{fin\_col}, \\{fin\_row}, %
+\\{fin\_align}.
+
+\fi
+
+\M785. When \.{\\halign} or \.{\\valign} has been scanned in an appropriate
+mode, \TeX\ calls \\{init\_align}, whose task is to get everything off to a
+good start. This mostly involves scanning the preamble and putting its
+information into the preamble list.
+
+\Y\P\hbox{\4}\X793:Declare the procedure called \\{get\_preamble\_token}\X%
+\hbox{}\6
+\4\&{procedure}\1\  \37\\{align\_peek};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{normal\_paragraph};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{init\_align};\6
+\4\&{label} \37$\\{done},\39\\{done1},\39\\{done2},\39\\{continue}$;\6
+\4\&{var} \37\\{save\_cs\_ptr}: \37\\{pointer};\C{\\{warning\_index} value for
+error messages}\6
+\|p: \37\\{pointer};\C{for short-term temporary use}\2\6
+\&{begin} \37$\\{save\_cs\_ptr}\K\\{cur\_cs}$;\C{\.{\\halign} or \.{\\valign},
+usually}\6
+\\{push\_alignment};\5
+$\\{align\_state}\K-1000000$;\C{enter a new alignment level}\6
+\X787:Check for improper alignment in displayed math\X;\6
+\\{push\_nest};\C{enter a new semantic level}\6
+\X786:Change current mode to $-\\{vmode}$ for \.{\\halign}, $-\\{hmode}$ for %
+\.{\\valign}\X;\6
+$\\{scan\_spec}(\\{align\_group},\39\\{false})$;\6
+\X788:Scan the preamble and record it in the \\{preamble} list\X;\6
+$\\{new\_save\_level}(\\{align\_group})$;\6
+\&{if} $\\{every\_cr}\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{every\_cr},\39\\{every\_cr\_text})$;\2\6
+\\{align\_peek};\C{look for \.{\\noalign} or \.{\\omit}}\6
+\&{end};\par
+\fi
+
+\M786. In vertical modes, \\{prev\_depth} already has the correct value. But
+if we are in \\{mmode} (displayed formula mode), we reach out to the
+enclosing vertical mode for the \\{prev\_depth} value that produces the
+correct baseline calculations.
+
+\Y\P$\4\X786:Change current mode to $-\\{vmode}$ for \.{\\halign}, $-\\{hmode}$
+for \.{\\valign}\X\S$\6
+\&{if} $\\{mode}=\\{mmode}$ \1\&{then}\6
+\&{begin} \37$\\{mode}\K-\\{vmode}$;\5
+$\\{prev\_depth}\K\\{nest}[\\{nest\_ptr}-2].\\{aux\_field}.\\{sc}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{mode}>0$ \1\&{then}\5
+$\\{negate}(\\{mode})$\2\2\par
+\U785.\fi
+
+\M787. When \.{\\halign} is used as a displayed formula, there should be
+no other pieces of mlists present.
+
+\Y\P$\4\X787:Check for improper alignment in displayed math\X\S$\6
+\&{if} $(\\{mode}=\\{mmode})\W((\\{tail}\I\\{head})\V(\\{incompleat\_noad}\I%
+\\{null}))$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Improper\ "})$;\5
+$\\{print\_esc}(\.{"halign"})$;\5
+$\\{print}(\.{"\ inside\ \$\$\'s"})$;\5
+$\\{help3}(\.{"Displays\ can\ use\ special\ alignments\ (like\ \\eqalignno)"})$%
+\6
+$(\.{"only\ if\ nothing\ but\ the\ alignment\ itself\ is\ between\ \$\$\'s."})$%
+\6
+$(\.{"So\ I\'ve\ deleted\ the\ formulas\ that\ preceded\ this\ alignment."})$;\5
+\\{error};\5
+\\{flush\_math};\6
+\&{end}\2\par
+\U785.\fi
+
+\M788. \P$\X788:Scan the preamble and record it in the \\{preamble} list\X\S$\6
+$\\{preamble}\K\\{null}$;\5
+$\\{cur\_align}\K\\{align\_head}$;\5
+$\\{cur\_loop}\K\\{null}$;\5
+$\\{scanner\_status}\K\\{aligning}$;\5
+$\\{warning\_index}\K\\{save\_cs\_ptr}$;\5
+$\\{align\_state}\K-1000000$;\C{at this point, $\\{cur\_cmd}=\\{left\_brace}$}\6
+\~ \1\&{loop}\ \&{begin} \37\X789:Append the current tabskip glue to the
+preamble list\X;\6
+\&{if} $\\{cur\_cmd}=\\{car\_ret}$ \1\&{then}\5
+\&{goto} \37\\{done};\C{\.{\\cr} ends the preamble}\2\6
+\X790:Scan preamble text until \\{cur\_cmd} is \\{tab\_mark} or \\{car\_ret},
+looking for changes in the tabskip glue; append an alignrecord to the preamble
+list\X;\6
+\&{end};\2\6
+\4\\{done}: \37$\\{scanner\_status}\K\\{normal}$\par
+\U785.\fi
+
+\M789. \P$\X789:Append the current tabskip glue to the preamble list\X\S$\6
+$\\{link}(\\{cur\_align})\K\\{new\_param\_glue}(\\{tab\_skip\_code})$;\5
+$\\{cur\_align}\K\\{link}(\\{cur\_align})$\par
+\U788.\fi
+
+\M790. \P$\X790:Scan preamble text until \\{cur\_cmd} is \\{tab\_mark} or %
+\\{car\_ret}, looking for changes in the tabskip glue; append an alignrecord to
+the preamble list\X\S$\6
+\X794:Scan the template \<u_j>, putting the resulting token list in \\{hold%
+\_head}\X;\6
+$\\{link}(\\{cur\_align})\K\\{new\_null\_box}$;\5
+$\\{cur\_align}\K\\{link}(\\{cur\_align})$;\C{a new alignrecord}\6
+$\\{info}(\\{cur\_align})\K\\{end\_span}$;\5
+$\\{width}(\\{cur\_align})\K\\{null\_flag}$;\5
+$\\{u\_part}(\\{cur\_align})\K\\{link}(\\{hold\_head})$;\5
+\X795:Scan the template \<v_j>, putting the resulting token list in \\{hold%
+\_head}\X;\6
+$\\{v\_part}(\\{cur\_align})\K\\{link}(\\{hold\_head})$\par
+\U788.\fi
+
+\M791. We enter `\.{\\span}' into \\{eqtb} with \\{tab\_mark} as its command
+code,
+and with \\{span\_code} as the command modifier. This makes \TeX\ interpret it
+essentially the same as an alignment delimiter like `\.\&', yet it is
+recognizably different when we need to distinguish it from a normal delimiter.
+It also turns out to be useful to give a special \\{cr\_code} to `\.{\\cr}',
+and an even larger \\{cr\_cr\_code} to `\.{\\crcr}'.
+
+The end of a template is represented by two ``frozen'' control sequences
+called \.{\\endtemplate}. The first has the command code \\{end\_template},
+which
+is $>\\{outer\_call}$, so it will not easily disappear in the presence of
+errors.
+The \\{get\_x\_token} routine converts the first into the second, which has %
+\\{endv}
+as its command code.
+
+\Y\P\D \37$\\{span\_code}=256$\C{distinct from any character}\par
+\P\D \37$\\{cr\_code}=257$\C{distinct from \\{span\_code} and from any
+character}\par
+\P\D \37$\\{cr\_cr\_code}=\\{cr\_code}+1$\C{this distinguishes \.{\\crcr} from %
+\.{\\cr}}\par
+\P\D \37$\\{end\_template\_token}\S\\{cs\_token\_flag}+\\{frozen\_end%
+\_template}$\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"span"},\39\\{tab\_mark},\39\\{span\_code})$;\6
+$\\{primitive}(\.{"cr"},\39\\{car\_ret},\39\\{cr\_code})$;\5
+$\\{text}(\\{frozen\_cr})\K\.{"cr"}$;\5
+$\\{eqtb}[\\{frozen\_cr}]\K\\{eqtb}[\\{cur\_val}]$;\6
+$\\{primitive}(\.{"crcr"},\39\\{car\_ret},\39\\{cr\_cr\_code})$;\5
+$\\{text}(\\{frozen\_end\_template})\K\.{"endtemplate"}$;\5
+$\\{text}(\\{frozen\_endv})\K\.{"endtemplate"}$;\5
+$\\{eq\_type}(\\{frozen\_endv})\K\\{endv}$;\5
+$\\{equiv}(\\{frozen\_endv})\K\\{null\_list}$;\5
+$\\{eq\_level}(\\{frozen\_endv})\K\\{level\_one}$;\6
+$\\{eqtb}[\\{frozen\_end\_template}]\K\\{eqtb}[\\{frozen\_endv}]$;\5
+$\\{eq\_type}(\\{frozen\_end\_template})\K\\{end\_template}$;\par
+\fi
+
+\M792. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{tab\_mark}: \37\&{if} $\\{chr\_code}=\\{span\_code}$ \1\&{then}\5
+$\\{print\_esc}(\.{"span"})$\6
+\4\&{else} $\\{chr\_cmd}(\.{"alignment\ tab\ character\ "})$;\2\6
+\4\\{car\_ret}: \37\&{if} $\\{chr\_code}=\\{cr\_code}$ \1\&{then}\5
+$\\{print\_esc}(\.{"cr"})$\6
+\4\&{else} $\\{print\_esc}(\.{"crcr"})$;\2\par
+\fi
+
+\M793. The preamble is copied directly, except that \.{\\tabskip} causes a
+change
+to the tabskip glue, thereby possibly expanding macros that immediately
+follow it. An appearance of \.{\\span} also causes such an expansion.
+
+Note that if the preamble contains `\.{\\global\\tabskip}', the `\.{\\global}'
+token survives in the preamble and the `\.{\\tabskip}' defines new
+tabskip glue (locally).
+
+\Y\P$\4\X793:Declare the procedure called \\{get\_preamble\_token}\X\S$\6
+\4\&{procedure}\1\  \37\\{get\_preamble\_token};\6
+\4\&{label} \37\\{restart};\2\6
+\&{begin} \37\\{restart}: \37\\{get\_token};\6
+\&{while} $(\\{cur\_chr}=\\{span\_code})\W(\\{cur\_cmd}=\\{tab\_mark})$ \1%
+\&{do}\6
+\&{begin} \37\\{get\_token};\C{this token will be expanded once}\6
+\&{if} $\\{cur\_cmd}>\\{max\_command}$ \1\&{then}\6
+\&{begin} \37\\{expand};\5
+\\{get\_token};\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{cur\_cmd}=\\{endv}$ \1\&{then}\5
+$\\{fatal\_error}(\.{"(interwoven\ alignment\ preambles\ are\ not\
+allowed)"})$;\2\6
+\&{if} $(\\{cur\_cmd}=\\{assign\_glue})\W(\\{cur\_chr}=\\{glue\_base}+\\{tab%
+\_skip\_code})$ \1\&{then}\6
+\&{begin} \37\\{scan\_optional\_equals};\5
+$\\{scan\_glue}(\\{glue\_val})$;\6
+\&{if} $\\{global\_defs}>0$ \1\&{then}\5
+$\\{geq\_define}(\\{glue\_base}+\\{tab\_skip\_code},\39\\{glue\_ref},\39\\{cur%
+\_val})$\6
+\4\&{else} $\\{eq\_define}(\\{glue\_base}+\\{tab\_skip\_code},\39\\{glue\_ref},%
+\39\\{cur\_val})$;\2\6
+\&{goto} \37\\{restart};\6
+\&{end};\2\6
+\&{end};\par
+\U785.\fi
+
+\M794. Spaces are eliminated from the beginning of a template.
+
+\Y\P$\4\X794:Scan the template \<u_j>, putting the resulting token list in %
+\\{hold\_head}\X\S$\6
+$\|p\K\\{hold\_head}$;\5
+$\\{link}(\|p)\K\\{null}$;\6
+\~ \1\&{loop}\ \&{begin} \37\\{get\_preamble\_token};\6
+\&{if} $\\{cur\_cmd}=\\{mac\_param}$ \1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\&{if} $(\\{cur\_cmd}\L\\{car\_ret})\W(\\{cur\_cmd}\G\\{tab\_mark})\W(\\{align%
+\_state}=-1000000)$ \1\&{then}\6
+\&{if} $(\|p=\\{hold\_head})\W(\\{cur\_loop}=\\{null})\W(\\{cur\_cmd}=\\{tab%
+\_mark})$ \1\&{then}\5
+$\\{cur\_loop}\K\\{cur\_align}$\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Missing\ \#\ inserted\ in\
+alignment\ preamble"})$;\5
+$\\{help3}(\.{"There\ should\ be\ exactly\ one\ \#\ between\ \&\'s,\ when\
+an"})$\6
+$(\.{"\\halign\ or\ \\valign\ is\ being\ set\ up.\ In\ this\ case\ you\ had"})$%
+\6
+$(\.{"none,\ so\ I\'ve\ put\ one\ in;\ maybe\ that\ will\ work."})$;\5
+\\{back\_error};\5
+\&{goto} \37\\{done1};\6
+\&{end}\2\6
+\4\&{else} \&{if} $(\\{cur\_cmd}\I\\{spacer})\V(\|p\I\\{hold\_head})$ \1%
+\&{then}\6
+\&{begin} \37$\\{link}(\|p)\K\\{get\_avail}$;\5
+$\|p\K\\{link}(\|p)$;\5
+$\\{info}(\|p)\K\\{cur\_tok}$;\6
+\&{end};\2\2\6
+\&{end};\2\6
+\4\\{done1}: \37\par
+\U790.\fi
+
+\M795. \P$\X795:Scan the template \<v_j>, putting the resulting token list in %
+\\{hold\_head}\X\S$\6
+$\|p\K\\{hold\_head}$;\5
+$\\{link}(\|p)\K\\{null}$;\6
+\~ \1\&{loop}\ \&{begin} \37\\{continue}: \37\\{get\_preamble\_token};\6
+\&{if} $(\\{cur\_cmd}\L\\{car\_ret})\W(\\{cur\_cmd}\G\\{tab\_mark})\W(\\{align%
+\_state}=-1000000)$ \1\&{then}\5
+\&{goto} \37\\{done2};\2\6
+\&{if} $\\{cur\_cmd}=\\{mac\_param}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Only\ one\ \#\ is\ allowed\ per\ tab"})$;\5
+$\\{help3}(\.{"There\ should\ be\ exactly\ one\ \#\ between\ \&\'s,\ when\
+an"})$\6
+$(\.{"\\halign\ or\ \\valign\ is\ being\ set\ up.\ In\ this\ case\ you\ had"})$%
+\6
+$(\.{"more\ than\ one,\ so\ I\'m\ ignoring\ all\ but\ the\ first."})$;\5
+\\{error};\5
+\&{goto} \37\\{continue};\6
+\&{end};\2\6
+$\\{link}(\|p)\K\\{get\_avail}$;\5
+$\|p\K\\{link}(\|p)$;\5
+$\\{info}(\|p)\K\\{cur\_tok}$;\6
+\&{end};\2\6
+\4\\{done2}: \37$\\{link}(\|p)\K\\{get\_avail}$;\5
+$\|p\K\\{link}(\|p)$;\5
+$\\{info}(\|p)\K\\{end\_template\_token}$\C{put \.{\\endtemplate} at the end}%
+\par
+\U790.\fi
+
+\M796. The tricky part about alignments is getting the templates into the
+scanner at the right time, and recovering control when a row or column
+is finished.
+
+We usually begin a row after each \.{\\cr} has been sensed, unless that
+\.{\\cr} is followed by \.{\\noalign} or by the right brace that terminates
+the alignment. The \\{align\_peek} routine is used to look ahead and do
+the right thing; it either gets a new row started, or gets a \.{\\noalign}
+started, or finishes off the alignment.
+
+\Y\P$\4\X796:Declare the procedure called \\{align\_peek}\X\S$\6
+\4\&{procedure}\1\  \37\\{align\_peek};\6
+\4\&{label} \37\\{restart};\2\6
+\&{begin} \37\\{restart}: \37$\\{align\_state}\K1000000$;\5
+\X417:Get the next non-blank non-call token\X;\6
+\&{if} $\\{cur\_cmd}=\\{no\_align}$ \1\&{then}\6
+\&{begin} \37\\{scan\_left\_brace};\5
+$\\{new\_save\_level}(\\{no\_align\_group})$;\6
+\&{if} $\\{mode}=-\\{vmode}$ \1\&{then}\5
+\\{normal\_paragraph};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{right\_brace}$ \1\&{then}\5
+\\{fin\_align}\6
+\4\&{else} \&{if} $(\\{cur\_cmd}=\\{car\_ret})\W(\\{cur\_chr}=\\{cr\_cr%
+\_code})$ \1\&{then}\5
+\&{goto} \37\\{restart}\C{ignore \.{\\crcr}}\6
+\4\&{else} \&{begin} \37\\{init\_row};\C{start a new row}\6
+\\{init\_col};\C{start a new column and replace what we peeked at}\6
+\&{end};\2\2\2\6
+\&{end};\par
+\U811.\fi
+
+\M797. To start a row (i.e., a `row' that rhymes with `dough' but not with
+`bough'),
+we enter a new semantic level, copy the first tabskip glue, and change
+from internal vertical mode to restricted horizontal mode or vice versa.
+The \\{space\_factor} and \\{prev\_depth} are not used on this semantic level,
+but we clear them to zero just to be tidy.
+
+\Y\P\hbox{\4}\X798:Declare the procedure called \\{init\_span}\X\hbox{}\6
+\4\&{procedure}\1\  \37\\{init\_row};\2\6
+\&{begin} \37\\{push\_nest};\5
+$\\{mode}\K(-\\{hmode}-\\{vmode})-\\{mode}$;\6
+\&{if} $\\{mode}=-\\{hmode}$ \1\&{then}\5
+$\\{space\_factor}\K0$\ \&{else} $\\{prev\_depth}\K0$;\2\6
+$\\{tail\_append}(\\{new\_glue}(\\{glue\_ptr}(\\{preamble})))$;\5
+$\\{subtype}(\\{tail})\K\\{tab\_skip\_code}+1$;\6
+$\\{cur\_align}\K\\{link}(\\{preamble})$;\5
+$\\{cur\_tail}\K\\{cur\_head}$;\5
+$\\{init\_span}(\\{cur\_align})$;\6
+\&{end};\par
+\fi
+
+\M798. The parameter to \\{init\_span} is a pointer to the alignrecord where
+the
+next column or group of columns will begin. A new semantic level is
+entered, so that the columns will generate a list for subsequent packaging.
+
+\Y\P$\4\X798:Declare the procedure called \\{init\_span}\X\S$\6
+\4\&{procedure}\1\  \37$\\{init\_span}(\|p:\\{pointer})$;\2\6
+\&{begin} \37\\{push\_nest};\6
+\&{if} $\\{mode}=-\\{hmode}$ \1\&{then}\5
+$\\{space\_factor}\K1000$\6
+\4\&{else} \&{begin} \37$\\{prev\_depth}\K\\{ignore\_depth}$;\5
+\\{normal\_paragraph};\6
+\&{end};\2\6
+$\\{cur\_span}\K\|p$;\6
+\&{end};\par
+\U797.\fi
+
+\M799. When a column begins, we assume that \\{cur\_cmd} is either \\{omit} or
+else
+the current token should be put back into the input until the \<u_j>
+template has been scanned.  (Note that \\{cur\_cmd} might be \\{tab\_mark} or
+\\{car\_ret}.)  We also assume that \\{align\_state} is approximately 1000000
+at
+this time.  We remain in the same mode, and start the template if it is
+called for.
+
+\Y\P\4\&{procedure}\1\  \37\\{init\_col};\2\6
+\&{begin} \37$\\{extra\_info}(\\{cur\_align})\K\\{cur\_cmd}$;\6
+\&{if} $\\{cur\_cmd}=\\{omit}$ \1\&{then}\5
+$\\{align\_state}\K0$\6
+\4\&{else} \&{begin} \37\\{back\_input};\5
+$\\{begin\_token\_list}(\\{u\_part}(\\{cur\_align}),\39\\{u\_template})$;\6
+\&{end};\C{now $\\{align\_state}=1000000$}\2\6
+\&{end};\par
+\fi
+
+\M800. The scanner sets \\{align\_state} to zero when the \<u_j> template ends.
+When
+a subsequent \.{\\cr} or \.{\\span} or tab mark occurs with $\\{align%
+\_state}=0$,
+the scanner activates the following code, which fires up the \<v_j> template.
+We need to remember the \\{cur\_chr}, which is either \\{cr\_cr\_code}, \\{cr%
+\_code},
+\\{span\_code}, or a character code, depending on how the column text has
+ended.
+
+This part of the program had better not be activated when the preamble
+to another alignment is being scanned, or when no alignment preamble is active.
+
+\Y\P$\4\X800:Insert the \(v)\<v_j> template and \&{goto} \\{restart}\X\S$\6
+\&{begin} \37\&{if} $(\\{scanner\_status}=\\{aligning})\V(\\{cur\_align}=%
+\\{null})$ \1\&{then}\5
+$\\{fatal\_error}(\.{"(interwoven\ alignment\ preambles\ are\ not\
+allowed)"})$;\2\6
+$\\{cur\_cmd}\K\\{extra\_info}(\\{cur\_align})$;\5
+$\\{extra\_info}(\\{cur\_align})\K\\{cur\_chr}$;\6
+\&{if} $\\{cur\_cmd}=\\{omit}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{omit\_template},\39\\{v\_template})$\6
+\4\&{else} $\\{begin\_token\_list}(\\{v\_part}(\\{cur\_align}),\39\\{v%
+\_template})$;\2\6
+$\\{align\_state}\K1000000$;\5
+\&{goto} \37\\{restart};\6
+\&{end}\par
+\U348.\fi
+
+\M801. The token list \\{omit\_template} just referred to is a constant token
+list that contains the special control sequence \.{\\endtemplate} only.
+
+\Y\P$\4\X801:Initialize the special list heads and constant nodes\X\S$\6
+$\\{info}(\\{omit\_template})\K\\{end\_template\_token}$;\C{$\\{link}(\\{omit%
+\_template})=\\{null}$}\par
+\As808, 831, 992\ETs999.
+\U170.\fi
+
+\M802. When the \\{endv} command at the end of a \<v_j> template comes through
+the
+scanner, things really start to happen; and it is the \\{fin\_col} routine
+that makes them happen. This routine returns \\{true} if a row as well as a
+column has been finished.
+
+\Y\P\4\&{function}\1\  \37\\{fin\_col}: \37\\{boolean};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the alignrecord after the current one}\6
+$\|q,\39\|r$: \37\\{pointer};\C{temporary pointers for list manipulation}\6
+\|s: \37\\{pointer};\C{a new span node}\6
+\|u: \37\\{pointer};\C{a new unset box}\6
+\|w: \37\\{scaled};\C{natural width}\6
+\|o: \37\\{glue\_ord};\C{order of infinity}\6
+\|n: \37\\{halfword};\C{span counter}\2\6
+\&{begin} \37\&{if} $\\{cur\_align}=\\{null}$ \1\&{then}\5
+$\\{confusion}(\.{"endv"})$;\2\6
+$\|q\K\\{link}(\\{cur\_align})$;\ \&{if} $\|q=\\{null}$ \1\&{then}\5
+$\\{confusion}(\.{"endv"})$;\2\6
+\&{if} $\\{align\_state}<500000$ \1\&{then}\5
+$\\{fatal\_error}(\.{"(interwoven\ alignment\ preambles\ are\ not\
+allowed)"})$;\2\6
+$\|p\K\\{link}(\|q)$;\5
+\X803:If the preamble list has been traversed, check that the row has ended\X;\6
+\&{if} $\\{extra\_info}(\\{cur\_align})\I\\{span\_code}$ \1\&{then}\6
+\&{begin} \37\\{unsave};\5
+$\\{new\_save\_level}(\\{align\_group})$;\6
+\X807:Package an unset box for the current column and record its width\X;\6
+\X806:Copy the tabskip glue between columns\X;\6
+\&{if} $\\{extra\_info}(\\{cur\_align})\G\\{cr\_code}$ \1\&{then}\6
+\&{begin} \37$\\{fin\_col}\K\\{true}$;\5
+\&{return};\6
+\&{end};\2\6
+$\\{init\_span}(\|p)$;\6
+\&{end};\2\6
+$\\{align\_state}\K1000000$;\5
+\X417:Get the next non-blank non-call token\X;\6
+$\\{cur\_align}\K\|p$;\5
+\\{init\_col};\5
+$\\{fin\_col}\K\\{false}$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M803. \P$\X803:If the preamble list has been traversed, check that the row has
+ended\X\S$\6
+\&{if} $(\|p=\\{null})\W(\\{extra\_info}(\\{cur\_align})<\\{cr\_code})$ \1%
+\&{then}\6
+\&{if} $\\{cur\_loop}\I\\{null}$ \1\&{then}\5
+\X804:Lengthen the preamble periodically\X\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Extra\ alignment\ tab\ has\ been\
+changed\ to\ "})$;\5
+$\\{print\_esc}(\.{"cr"})$;\5
+$\\{help3}(\.{"You\ have\ given\ more\ \\span\ or\ \&\ marks\ than\ there\
+were"})$\6
+$(\.{"in\ the\ preamble\ to\ the\ \\halign\ or\ \\valign\ now\ in\
+progress."})$\6
+$(\.{"So\ I\'ll\ assume\ that\ you\ meant\ to\ type\ \\cr\ instead."})$;\5
+$\\{extra\_info}(\\{cur\_align})\K\\{cr\_code}$;\5
+\\{error};\6
+\&{end}\2\2\par
+\U802.\fi
+
+\M804. \P$\X804:Lengthen the preamble periodically\X\S$\6
+\&{begin} \37$\\{link}(\|q)\K\\{new\_null\_box}$;\5
+$\|p\K\\{link}(\|q)$;\C{a new alignrecord}\6
+$\\{info}(\|p)\K\\{end\_span}$;\5
+$\\{width}(\|p)\K\\{null\_flag}$;\5
+$\\{cur\_loop}\K\\{link}(\\{cur\_loop})$;\5
+\X805:Copy the templates from node \\{cur\_loop} into node \|p\X;\6
+$\\{cur\_loop}\K\\{link}(\\{cur\_loop})$;\5
+$\\{link}(\|p)\K\\{new\_glue}(\\{glue\_ptr}(\\{cur\_loop}))$;\6
+\&{end}\par
+\U803.\fi
+
+\M805. \P$\X805:Copy the templates from node \\{cur\_loop} into node \|p\X\S$\6
+$\|q\K\\{hold\_head}$;\5
+$\|r\K\\{u\_part}(\\{cur\_loop})$;\6
+\&{while} $\|r\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\\{link}(\|q)\K\\{get\_avail}$;\5
+$\|q\K\\{link}(\|q)$;\5
+$\\{info}(\|q)\K\\{info}(\|r)$;\5
+$\|r\K\\{link}(\|r)$;\6
+\&{end};\2\6
+$\\{link}(\|q)\K\\{null}$;\5
+$\\{u\_part}(\|p)\K\\{link}(\\{hold\_head})$;\5
+$\|q\K\\{hold\_head}$;\5
+$\|r\K\\{v\_part}(\\{cur\_loop})$;\6
+\&{while} $\|r\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\\{link}(\|q)\K\\{get\_avail}$;\5
+$\|q\K\\{link}(\|q)$;\5
+$\\{info}(\|q)\K\\{info}(\|r)$;\5
+$\|r\K\\{link}(\|r)$;\6
+\&{end};\2\6
+$\\{link}(\|q)\K\\{null}$;\5
+$\\{v\_part}(\|p)\K\\{link}(\\{hold\_head})$\par
+\U804.\fi
+
+\M806. \P$\X806:Copy the tabskip glue between columns\X\S$\6
+$\\{tail\_append}(\\{new\_glue}(\\{glue\_ptr}(\\{link}(\\{cur\_align}))))$;\5
+$\\{subtype}(\\{tail})\K\\{tab\_skip\_code}+1$\par
+\U802.\fi
+
+\M807. \P$\X807:Package an unset box for the current column and record its
+width\X\S$\6
+\&{begin} \37\&{if} $\\{mode}=-\\{hmode}$ \1\&{then}\6
+\&{begin} \37$\\{adjust\_tail}\K\\{cur\_tail}$;\5
+$\\{adjust\_hlist}(\\{head},\39\\{false})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\\{cur\_kanji\_skip}\K\\{space\_ptr}(\\{head})$;\5
+$\\{cur\_xkanji\_skip}\K\\{xspace\_ptr}(\\{head})$;\5
+$\\{add\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{add\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\|u\K\\{hpack}(\\{link}(\\{head}),\39\\{natural})$;\5
+$\|w\K\\{width}(\|u)$;\5
+$\\{cur\_tail}\K\\{adjust\_tail}$;\5
+$\\{adjust\_tail}\K\\{null}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|u\K\\{vpackage}(\\{link}(\\{head}),\39\\{natural},%
+\390)$;\5
+$\|w\K\\{height}(\|u)$;\6
+\&{end};\2\6
+$\|n\K\\{min\_quarterword}$;\C{this represents a span count of 1}\6
+\&{if} $\\{cur\_span}\I\\{cur\_align}$ \1\&{then}\5
+\X809:Update width entry for spanned columns\X\6
+\4\&{else} \&{if} $\|w>\\{width}(\\{cur\_align})$ \1\&{then}\5
+$\\{width}(\\{cur\_align})\K\|w$;\2\2\6
+$\\{type}(\|u)\K\\{unset\_node}$;\5
+$\\{span\_count}(\|u)\K\|n$;\6
+\X670:Determine the stretch order\X;\6
+$\\{glue\_order}(\|u)\K\|o$;\5
+$\\{glue\_stretch}(\|u)\K\\{total\_stretch}[\|o]$;\6
+\X676:Determine the shrink order\X;\6
+$\\{glue\_sign}(\|u)\K\|o$;\5
+$\\{glue\_shrink}(\|u)\K\\{total\_shrink}[\|o]$;\6
+\\{pop\_nest};\5
+$\\{link}(\\{tail})\K\|u$;\5
+$\\{tail}\K\|u$;\6
+\&{end}\par
+\U802.\fi
+
+\M808. A span node is a 2-word record containing \\{width}, \\{info}, and %
+\\{link}
+fields. The \\{link} field is not really a link, it indicates the number of
+spanned columns; the \\{info} field points to a span node for the same
+starting column, having a greater extent of spanning, or to \\{end\_span},
+which has the largest possible \\{link} field; the \\{width} field holds the
+largest natural width corresponding to a particular set of spanned columns.
+
+A list of the maximum widths so far, for spanned columns starting at a
+given column, begins with the \\{info} field of the alignrecord for that
+column.
+
+\Y\P\D \37$\\{span\_node\_size}=2$\C{number of \\{mem} words for a span node}%
+\par
+\Y\P$\4\X801:Initialize the special list heads and constant nodes\X\mathrel{+}%
+\S$\6
+$\\{link}(\\{end\_span})\K\\{max\_quarterword}+1$;\5
+$\\{info}(\\{end\_span})\K\\{null}$;\par
+\fi
+
+\M809. \P$\X809:Update width entry for spanned columns\X\S$\6
+\&{begin} \37$\|q\K\\{cur\_span}$;\6
+\1\&{repeat} \37$\\{incr}(\|n)$;\5
+$\|q\K\\{link}(\\{link}(\|q))$;\6
+\4\&{until}\5
+$\|q=\\{cur\_align}$;\2\6
+\&{if} $\|n>\\{max\_quarterword}$ \1\&{then}\5
+$\\{confusion}(\.{"256\ spans"})$;\C{this can happen, but won't}\2\6
+$\|q\K\\{cur\_span}$;\6
+\&{while} $\\{link}(\\{info}(\|q))<\|n$ \1\&{do}\5
+$\|q\K\\{info}(\|q)$;\2\6
+\&{if} $\\{link}(\\{info}(\|q))>\|n$ \1\&{then}\6
+\&{begin} \37$\|s\K\\{get\_node}(\\{span\_node\_size})$;\5
+$\\{info}(\|s)\K\\{info}(\|q)$;\5
+$\\{link}(\|s)\K\|n$;\5
+$\\{info}(\|q)\K\|s$;\5
+$\\{width}(\|s)\K\|w$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{width}(\\{info}(\|q))<\|w$ \1\&{then}\5
+$\\{width}(\\{info}(\|q))\K\|w$;\2\2\6
+\&{end}\par
+\U807.\fi
+
+\M810. At the end of a row, we append an unset box to the current vlist (for
+\.{\\halign}) or the current hlist (for \.{\\valign}). This unset box
+contains the unset boxes for the columns, separated by the tabskip glue.
+Everything will be set later.
+
+\Y\P\4\&{procedure}\1\  \37\\{fin\_row};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new unset box}\2\6
+\&{begin} \37\&{if} $\\{mode}=-\\{hmode}$ \1\&{then}\6
+\&{begin} \37$\\{adjust\_hlist}(\\{head},\39\\{false})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\\{cur\_kanji\_skip}\K\\{space\_ptr}(\\{head})$;\5
+$\\{cur\_xkanji\_skip}\K\\{xspace\_ptr}(\\{head})$;\5
+$\\{add\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{add\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\|p\K\\{hpack}(\\{link}(\\{head}),\39\\{natural})$;\5
+\\{pop\_nest};\5
+$\\{append\_to\_vlist}(\|p)$;\6
+\&{if} $\\{cur\_head}\I\\{cur\_tail}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\\{tail})\K\\{link}(\\{cur\_head})$;\5
+$\\{tail}\K\\{cur\_tail}$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|p\K\\{vpack}(\\{link}(\\{head}),\39\\{natural})$;\5
+\\{pop\_nest};\5
+$\\{link}(\\{tail})\K\|p$;\5
+$\\{tail}\K\|p$;\5
+$\\{space\_factor}\K1000$;\6
+\&{end};\2\6
+$\\{type}(\|p)\K\\{unset\_node}$;\5
+$\\{glue\_stretch}(\|p)\K0$;\6
+\&{if} $\\{every\_cr}\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{every\_cr},\39\\{every\_cr\_text})$;\2\6
+\\{align\_peek};\6
+\&{end};\C{note that $\\{glue\_shrink}(\|p)=0$ since $\\{glue\_shrink}\S%
+\\{shift\_amount}$}\par
+\fi
+
+\M811. Finally, we will reach the end of the alignment, and we can breathe a
+sigh of relief that memory hasn't overflowed. All the unset boxes will now be
+set so that the columns line up, taking due account of spanned columns.
+
+\Y\P\4\&{procedure}\1\  \37\\{do\_assignments};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{resume\_after\_display};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{build\_page};\5
+\\{forward};\5
+\hbox{\2}\6
+\4\&{procedure}\1\  \37\\{fin\_align};\6
+\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s,\39\|u,\39\|v,\39\|z$: \37\\{pointer};%
+\C{registers for the list operations}\6
+$\|t,\39\|w$: \37\\{scaled};\C{width of column}\6
+\|o: \37\\{scaled};\C{shift offset for unset boxes}\6
+\|n: \37\\{halfword};\C{matching span amount}\6
+\\{rule\_save}: \37\\{scaled};\C{temporary storage for \\{overfull\_rule}}\6
+\\{aux\_save}: \37\\{memory\_word};\C{temporary storage for \\{aux}}\2\6
+\&{begin} \37\&{if} $\\{cur\_group}\I\\{align\_group}$ \1\&{then}\5
+$\\{confusion}(\.{"align1"})$;\2\6
+\\{unsave};\C{that \\{align\_group} was for individual entries}\6
+\&{if} $\\{cur\_group}\I\\{align\_group}$ \1\&{then}\5
+$\\{confusion}(\.{"align0"})$;\2\6
+\\{unsave};\C{that \\{align\_group} was for the whole alignment}\6
+\&{if} $\\{nest}[\\{nest\_ptr}-1].\\{mode\_field}=\\{mmode}$ \1\&{then}\5
+$\|o\K\\{display\_indent}$\6
+\4\&{else} $\|o\K0$;\2\6
+\X812:Go through the preamble list, determining the column widths and changing
+the alignrecords to dummy unset boxes\X;\6
+\X815:Package the preamble list, to determine the actual tabskip glue amounts,
+and let \|p point to this prototype box\X;\6
+\X816:Set the glue in all the unset boxes of the current list\X;\6
+$\\{flush\_node\_list}(\|p)$;\5
+\\{pop\_alignment};\5
+\X823:Insert the \(c)current list into its environment\X;\6
+\&{end};\6
+\hbox{\4}\X796:Declare the procedure called \\{align\_peek}\X\par
+\fi
+
+\M812. It's time now to dismantle the preamble list and to compute the column
+widths. Let $w_{ij}$ be the maximum of the natural widths of all entries
+that span columns $i$ through $j$, inclusive. The alignrecord for column~$i$
+contains $w_{ii}$ in its \\{width} field, and there is also a linked list of
+the nonzero $w_{ij}$ for increasing $j$, accessible via the \\{info} field;
+these span nodes contain the value $j-i+\\{min\_quarterword}$ in their
+\\{link} fields. The values of $w_{ii}$ were initialized to \\{null\_flag},
+which
+we regard as $-\infty$.
+
+The final column widths are defined by the formula
+$$w_j=\max_{1\L i\L j}\biggl( w_{ij}-\sum_{i\L k<j}(t_k+w_k)\biggr),$$
+where $t_k$ is the natural width of the tabskip glue between columns
+$k$ and~$k+1$. However, if $w_{ij}=-\infty$ for all \|i in the range
+$1\L\|i\L\|j$ (i.e., if every entry that involved column~\|j also involved
+column~$\|j+1$), we let $w_j=0$, and we zero out the tabskip glue after
+column~\|j.
+
+\TeX\ computes these values by using the following scheme: First $w_1=w_{11}$.
+Then replace $w_{2j}$ by $\max(w_{2j},w_{1j}-t_1-w_1)$, for all $j>1$.
+Then $w_2=w_{22}$. Then replace $w_{3j}$ by $\max(w_{3j},w_{2j}-t_2-w_2)$
+for all $j>2$; and so on. If any $w_j$ turns out to be $-\infty$, its
+value is changed to zero and so is the next tabskip.
+
+\Y\P$\4\X812:Go through the preamble list, determining the column widths and
+changing the alignrecords to dummy unset boxes\X\S$\6
+$\|q\K\\{link}(\\{preamble})$;\6
+\1\&{repeat} \37$\\{flush\_list}(\\{u\_part}(\|q))$;\5
+$\\{flush\_list}(\\{v\_part}(\|q))$;\5
+$\|p\K\\{link}(\\{link}(\|q))$;\6
+\&{if} $\\{width}(\|q)=\\{null\_flag}$ \1\&{then}\5
+\X813:Nullify $\\{width}(\|q)$ and the tabskip glue following this column\X;\2\6
+\&{if} $\\{info}(\|q)\I\\{end\_span}$ \1\&{then}\5
+\X814:Merge the widths in the span nodes of \|q with those of \|p, destroying
+the span nodes of \|q\X;\2\6
+$\\{type}(\|q)\K\\{unset\_node}$;\5
+$\\{span\_count}(\|q)\K\\{min\_quarterword}$;\5
+$\\{height}(\|q)\K0$;\5
+$\\{depth}(\|q)\K0$;\5
+$\\{glue\_order}(\|q)\K\\{normal}$;\5
+$\\{glue\_sign}(\|q)\K\\{normal}$;\5
+$\\{glue\_stretch}(\|q)\K0$;\5
+$\\{glue\_shrink}(\|q)\K0$;\5
+$\|q\K\|p$;\6
+\4\&{until}\5
+$\|q=\\{null}$\2\par
+\U811.\fi
+
+\M813. \P$\X813:Nullify $\\{width}(\|q)$ and the tabskip glue following this
+column\X\S$\6
+\&{begin} \37$\\{width}(\|q)\K0$;\5
+$\|r\K\\{link}(\|q)$;\5
+$\|s\K\\{glue\_ptr}(\|r)$;\6
+\&{if} $\|s\I\\{zero\_glue}$ \1\&{then}\6
+\&{begin} \37$\\{add\_glue\_ref}(\\{zero\_glue})$;\5
+$\\{delete\_glue\_ref}(\|s)$;\5
+$\\{glue\_ptr}(\|r)\K\\{zero\_glue}$;\6
+\&{end};\2\6
+\&{end}\par
+\U812.\fi
+
+\M814. Merging of two span-node lists is a typical exercise in the manipulation
+of
+linearly linked data structures. The essential invariant in the following
+ \&{repeat}  loop is that we want to dispense with node \|r, in \|q's list,
+and \|u is its successor; all nodes of \|p's list up to and including \|s
+have been processed, and the successor of \|s matches \|r or precedes \|r
+or follows \|r, according as $\\{link}(\|r)=\|n$ or $\\{link}(\|r)>\|n$ or $%
+\\{link}(\|r)<\|n$.
+
+\Y\P$\4\X814:Merge the widths in the span nodes of \|q with those of \|p,
+destroying the span nodes of \|q\X\S$\6
+\&{begin} \37$\|t\K\\{width}(\|q)+\\{width}(\\{glue\_ptr}(\\{link}(\|q)))$;\5
+$\|r\K\\{info}(\|q)$;\5
+$\|s\K\\{end\_span}$;\5
+$\\{info}(\|s)\K\|p$;\5
+$\|n\K\\{min\_quarterword}+1$;\6
+\1\&{repeat} \37$\\{width}(\|r)\K\\{width}(\|r)-\|t$;\5
+$\|u\K\\{info}(\|r)$;\6
+\&{while} $\\{link}(\|r)>\|n$ \1\&{do}\6
+\&{begin} \37$\|s\K\\{info}(\|s)$;\5
+$\|n\K\\{link}(\\{info}(\|s))+1$;\6
+\&{end};\2\6
+\&{if} $\\{link}(\|r)<\|n$ \1\&{then}\6
+\&{begin} \37$\\{info}(\|r)\K\\{info}(\|s)$;\5
+$\\{info}(\|s)\K\|r$;\5
+$\\{decr}(\\{link}(\|r))$;\5
+$\|s\K\|r$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{width}(\|r)>\\{width}(\\{info}(\|s))$ \1%
+\&{then}\5
+$\\{width}(\\{info}(\|s))\K\\{width}(\|r)$;\2\6
+$\\{free\_node}(\|r,\39\\{span\_node\_size})$;\6
+\&{end};\2\6
+$\|r\K\|u$;\6
+\4\&{until}\5
+$\|r=\\{end\_span}$;\2\6
+\&{end}\par
+\U812.\fi
+
+\M815. Now the preamble list has been converted to a list of alternating unset
+boxes and tabskip glue, where the box widths are equal to the final
+column sizes. In case of \.{\\valign}, we change the widths to heights,
+so that a correct error message will be produced if the alignment is
+overfull or underfull.
+
+\Y\P$\4\X815:Package the preamble list, to determine the actual tabskip glue
+amounts, and let \|p point to this prototype box\X\S$\6
+$\\{save\_ptr}\K\\{save\_ptr}-2$;\5
+$\\{pack\_begin\_line}\K-\\{mode\_line}$;\6
+\&{if} $\\{mode}=-\\{vmode}$ \1\&{then}\6
+\&{begin} \37$\\{rule\_save}\K\\{overfull\_rule}$;\5
+$\\{overfull\_rule}\K0$;\C{prevent rule from being packaged}\6
+$\|z\K\\{new\_null\_box}$;\5
+$\\{link}(\|z)\K\\{preamble}$;\5
+$\\{adjust\_hlist}(\|z,\39\\{false})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\\{cur\_kanji\_skip}\K\\{space\_ptr}(\|z)$;\5
+$\\{cur\_xkanji\_skip}\K\\{xspace\_ptr}(\|z)$;\5
+$\\{add\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{add\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\|p\K\\{hpack}(\\{preamble},\39\\{saved}(1),\39\\{saved}(0))$;\5
+$\\{overfull\_rule}\K\\{rule\_save}$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|z))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|z))$;\5
+$\\{free\_node}(\|z,\39\\{box\_node\_size})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|q\K\\{link}(\\{preamble})$;\6
+\1\&{repeat} \37$\\{height}(\|q)\K\\{width}(\|q)$;\5
+$\\{width}(\|q)\K0$;\5
+$\|q\K\\{link}(\\{link}(\|q))$;\6
+\4\&{until}\5
+$\|q=\\{null}$;\2\6
+$\|p\K\\{vpack}(\\{preamble},\39\\{saved}(1),\39\\{saved}(0))$;\5
+$\|q\K\\{link}(\\{preamble})$;\6
+\1\&{repeat} \37$\\{width}(\|q)\K\\{height}(\|q)$;\5
+$\\{height}(\|q)\K0$;\5
+$\|q\K\\{link}(\\{link}(\|q))$;\6
+\4\&{until}\5
+$\|q=\\{null}$;\2\6
+\&{end};\2\6
+$\\{pack\_begin\_line}\K0$\par
+\U811.\fi
+
+\M816. \P$\X816:Set the glue in all the unset boxes of the current list\X\S$\6
+$\|q\K\\{link}(\\{head})$;\5
+$\|s\K\\{head}$;\6
+\&{while} $\|q\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\R\\{is\_char\_node}(\|q)$ \1\&{then}\6
+\&{if} $\\{type}(\|q)=\\{unset\_node}$ \1\&{then}\5
+\X818:Set the unset box \|q and the unset boxes in it\X\6
+\4\&{else} \&{if} $\\{type}(\|q)=\\{rule\_node}$ \1\&{then}\5
+\X817:Make the running dimensions in rule \|q extend to the boundaries of the
+alignment\X;\2\2\2\6
+$\|s\K\|q$;\5
+$\|q\K\\{link}(\|q)$;\6
+\&{end}\2\par
+\U811.\fi
+
+\M817. \P$\X817:Make the running dimensions in rule \|q extend to the
+boundaries of the alignment\X\S$\6
+\&{begin} \37\&{if} $\\{is\_running}(\\{width}(\|q))$ \1\&{then}\5
+$\\{width}(\|q)\K\\{width}(\|p)$;\2\6
+\&{if} $\\{is\_running}(\\{height}(\|q))$ \1\&{then}\5
+$\\{height}(\|q)\K\\{height}(\|p)$;\2\6
+\&{if} $\\{is\_running}(\\{depth}(\|q))$ \1\&{then}\5
+$\\{depth}(\|q)\K\\{depth}(\|p)$;\2\6
+\&{if} $\|o\I0$ \1\&{then}\6
+\&{begin} \37$\|r\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\\{null}$;\5
+$\|q\K\\{hpack}(\|q,\39\\{natural})$;\5
+$\\{shift\_amount}(\|q)\K\|o$;\5
+$\\{link}(\|q)\K\|r$;\5
+$\\{link}(\|s)\K\|q$;\6
+\&{end};\2\6
+\&{end}\par
+\U816.\fi
+
+\M818. The unset box \|q represents a row that contains one or more unset
+boxes,
+depending on how soon \.{\\cr} occurred in that row.
+
+\Y\P$\4\X818:Set the unset box \|q and the unset boxes in it\X\S$\6
+\&{begin} \37\&{if} $\\{mode}=-\\{vmode}$ \1\&{then}\6
+\&{begin} \37$\\{type}(\|q)\K\\{hlist\_node}$;\5
+$\\{width}(\|q)\K\\{width}(\|p)$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{type}(\|q)\K\\{vlist\_node}$;\5
+$\\{height}(\|q)\K\\{height}(\|p)$;\6
+\&{end};\2\6
+$\\{set\_box\_dir}(\|q)(\\{abs}(\\{direction}))$;\5
+$\\{glue\_order}(\|q)\K\\{glue\_order}(\|p)$;\5
+$\\{glue\_sign}(\|q)\K\\{glue\_sign}(\|p)$;\5
+$\\{glue\_set}(\|q)\K\\{glue\_set}(\|p)$;\5
+$\\{shift\_amount}(\|q)\K\|o$;\5
+$\|r\K\\{link}(\\{list\_ptr}(\|q))$;\5
+$\|s\K\\{link}(\\{list\_ptr}(\|p))$;\6
+\1\&{repeat} \37\X819:Set the glue in node \|r and change it from an unset node%
+\X;\6
+$\|r\K\\{link}(\\{link}(\|r))$;\5
+$\|s\K\\{link}(\\{link}(\|s))$;\6
+\4\&{until}\5
+$\|r=\\{null}$;\2\6
+\&{end}\par
+\U816.\fi
+
+\M819. A box made from spanned columns will be followed by tabskip glue nodes
+and
+by empty boxes as if there were no spanning. This permits perfect alignment
+of subsequent entries, and it prevents values that depend on floating point
+arithmetic from entering into the dimensions of any boxes.
+
+\Y\P$\4\X819:Set the glue in node \|r and change it from an unset node\X\S$\6
+$\|n\K\\{span\_count}(\|r)$;\5
+$\|t\K\\{width}(\|s)$;\5
+$\|w\K\|t$;\5
+$\|u\K\\{hold\_head}$;\6
+\&{while} $\|n>\\{min\_quarterword}$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\|n)$;\5
+\X820:Append tabskip glue and an empty box to list \|u, and update \|s and \|t
+as the prototype nodes are passed\X;\6
+\&{end};\2\6
+\&{if} $\\{mode}=-\\{vmode}$ \1\&{then}\5
+\X821:Make the unset node \|r into an \\{hlist\_node} of width \|w, setting the
+glue as if the width were \|t\X\6
+\4\&{else} \X822:Make the unset node \|r into a \\{vlist\_node} of height \|w,
+setting the glue as if the height were \|t\X;\2\6
+$\\{shift\_amount}(\|r)\K0$;\6
+\&{if} $\|u\I\\{hold\_head}$ \1\&{then}\C{append blank boxes to account for
+spanned nodes}\6
+\&{begin} \37$\\{link}(\|u)\K\\{link}(\|r)$;\5
+$\\{link}(\|r)\K\\{link}(\\{hold\_head})$;\5
+$\|r\K\|u$;\6
+\&{end}\2\par
+\U818.\fi
+
+\M820. \P$\X820:Append tabskip glue and an empty box to list \|u, and update %
+\|s and \|t as the prototype nodes are passed\X\S$\6
+$\|s\K\\{link}(\|s)$;\5
+$\|v\K\\{glue\_ptr}(\|s)$;\5
+$\\{link}(\|u)\K\\{new\_glue}(\|v)$;\5
+$\|u\K\\{link}(\|u)$;\5
+$\\{subtype}(\|u)\K\\{tab\_skip\_code}+1$;\5
+$\|t\K\|t+\\{width}(\|v)$;\6
+\&{if} $\\{glue\_sign}(\|p)=\\{stretching}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{stretch\_order}(\|v)=\\{glue\_order}(\|p)$ \1\&{then}\5
+$\|t\K\|t+\\{round}(\\{float}(\\{glue\_set}(\|p))\ast\\{stretch}(\|v))$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{glue\_sign}(\|p)=\\{shrinking}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{shrink\_order}(\|v)=\\{glue\_order}(\|p)$ \1\&{then}\5
+$\|t\K\|t-\\{round}(\\{float}(\\{glue\_set}(\|p))\ast\\{shrink}(\|v))$;\2\6
+\&{end};\2\2\6
+$\|s\K\\{link}(\|s)$;\5
+$\\{link}(\|u)\K\\{new\_null\_box}$;\5
+$\|u\K\\{link}(\|u)$;\5
+$\|t\K\|t+\\{width}(\|s)$;\6
+\&{if} $\\{mode}=-\\{vmode}$ \1\&{then}\5
+$\\{width}(\|u)\K\\{width}(\|s)$\ \&{else} \&{begin} \37$\\{type}(\|u)\K%
+\\{vlist\_node}$;\5
+$\\{height}(\|u)\K\\{width}(\|s)$;\6
+\&{end};\2\6
+$\\{set\_box\_dir}(\|u)(\\{abs}(\\{direction}))$\par
+\U819.\fi
+
+\M821. \P$\X821:Make the unset node \|r into an \\{hlist\_node} of width \|w,
+setting the glue as if the width were \|t\X\S$\6
+\&{begin} \37$\\{height}(\|r)\K\\{height}(\|q)$;\5
+$\\{depth}(\|r)\K\\{depth}(\|q)$;\6
+\&{if} $\|t=\\{width}(\|r)$ \1\&{then}\6
+\&{begin} \37$\\{glue\_sign}(\|r)\K\\{normal}$;\5
+$\\{glue\_order}(\|r)\K\\{normal}$;\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|t>\\{width}(\|r)$ \1\&{then}\6
+\&{begin} \37$\\{glue\_sign}(\|r)\K\\{stretching}$;\6
+\&{if} $\\{glue\_stretch}(\|r)=0$ \1\&{then}\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$\6
+\4\&{else} $\\{glue\_set}(\|r)\K\\{unfloat}((\|t-\\{width}(\|r))/\\{glue%
+\_stretch}(\|r))$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{glue\_order}(\|r)\K\\{glue\_sign}(\|r)$;\5
+$\\{glue\_sign}(\|r)\K\\{shrinking}$;\6
+\&{if} $\\{glue\_shrink}(\|r)=0$ \1\&{then}\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$\6
+\4\&{else} \&{if} $(\\{glue\_order}(\|r)=\\{normal})\W(\\{width}(\|r)-\|t>%
+\\{glue\_shrink}(\|r))$ \1\&{then}\5
+$\\{set\_glue\_ratio\_one}(\\{glue\_set}(\|r))$\6
+\4\&{else} $\\{glue\_set}(\|r)\K\\{unfloat}((\\{width}(\|r)-\|t)/\\{glue%
+\_shrink}(\|r))$;\2\2\6
+\&{end};\2\2\6
+$\\{width}(\|r)\K\|w$;\5
+$\\{type}(\|r)\K\\{hlist\_node}$;\5
+$\\{set\_box\_dir}(\|r)(\\{abs}(\\{direction}))$;\6
+\&{end}\par
+\U819.\fi
+
+\M822. \P$\X822:Make the unset node \|r into a \\{vlist\_node} of height \|w,
+setting the glue as if the height were \|t\X\S$\6
+\&{begin} \37$\\{width}(\|r)\K\\{width}(\|q)$;\6
+\&{if} $\|t=\\{height}(\|r)$ \1\&{then}\6
+\&{begin} \37$\\{glue\_sign}(\|r)\K\\{normal}$;\5
+$\\{glue\_order}(\|r)\K\\{normal}$;\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$;\6
+\&{end}\6
+\4\&{else} \&{if} $\|t>\\{height}(\|r)$ \1\&{then}\6
+\&{begin} \37$\\{glue\_sign}(\|r)\K\\{stretching}$;\6
+\&{if} $\\{glue\_stretch}(\|r)=0$ \1\&{then}\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$\6
+\4\&{else} $\\{glue\_set}(\|r)\K\\{unfloat}((\|t-\\{height}(\|r))/\\{glue%
+\_stretch}(\|r))$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{glue\_order}(\|r)\K\\{glue\_sign}(\|r)$;\5
+$\\{glue\_sign}(\|r)\K\\{shrinking}$;\6
+\&{if} $\\{glue\_shrink}(\|r)=0$ \1\&{then}\5
+$\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r))$\6
+\4\&{else} \&{if} $(\\{glue\_order}(\|r)=\\{normal})\W(\\{height}(\|r)-\|t>%
+\\{glue\_shrink}(\|r))$ \1\&{then}\5
+$\\{set\_glue\_ratio\_one}(\\{glue\_set}(\|r))$\6
+\4\&{else} $\\{glue\_set}(\|r)\K\\{unfloat}((\\{height}(\|r)-\|t)/\\{glue%
+\_shrink}(\|r))$;\2\2\6
+\&{end};\2\2\6
+$\\{height}(\|r)\K\|w$;\5
+$\\{type}(\|r)\K\\{vlist\_node}$;\5
+$\\{set\_box\_dir}(\|r)(\\{abs}(\\{direction}))$;\6
+\&{end}\par
+\U819.\fi
+
+\M823. We now have a completed alignment, in the list that starts at \\{head}
+and ends at \\{tail}. This list will be merged with the one that encloses
+it. (In case the enclosing mode is \\{mmode}, for displayed formulas,
+we will need to insert glue before and after the display; that part of the
+program will be deferred until we're more familiar with such operations.)
+
+In restricted horizontal mode, the \\{clang} part of \\{aux} is undefined;
+an over-cautious \PASCAL\ runtime system may complain about this.
+
+\Y\P$\4\X823:Insert the \(c)current list into its environment\X\S$\6
+$\\{aux\_save}\K\\{aux}$;\5
+$\|p\K\\{link}(\\{head})$;\5
+$\|q\K\\{tail}$;\5
+\\{pop\_nest};\6
+\&{if} $\\{mode}=\\{mmode}$ \1\&{then}\5
+\X1218:Finish an alignment in a display\X\6
+\4\&{else} \&{begin} \37$\\{aux}\K\\{aux\_save}$;\5
+$\\{link}(\\{tail})\K\|p$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\5
+$\\{tail}\K\|q$;\2\6
+\&{if} $\\{mode}=\\{vmode}$ \1\&{then}\5
+\\{build\_page};\2\6
+\&{end}\2\par
+\U811.\fi
+
+\N824.  \[38] Breaking paragraphs into lines.
+We come now to what is probably the most interesting algorithm of \TeX:
+the mechanism for choosing the ``best possible'' breakpoints that yield
+the individual lines of a paragraph. \TeX's line-breaking algorithm takes
+a given horizontal list and converts it to a sequence of boxes that are
+appended to the current vertical list. In the course of doing this, it
+creates a special data structure containing three kinds of records that are
+not used elsewhere in \TeX. Such nodes are created while a paragraph is
+being processed, and they are destroyed afterwards; thus, the other parts
+of \TeX\ do not need to know anything about how line-breaking is done.
+
+The method used here is based on an approach devised by Michael F. Plass and
+the author in 1977, subsequently generalized and improved by the same two
+people in 1980. A detailed discussion appears in {\sl SOFTWARE---Practice
+\AM\ Experience \bf11} (1981), 1119--1184, where it is shown that the
+line-breaking problem can be regarded as a special case of the problem of
+computing the shortest path in an acyclic network. The cited paper includes
+numerous examples and describes the history of line breaking as it has been
+practiced by printers through the ages. The present implementation adds two
+new ideas to the algorithm of 1980: Memory space requirements are considerably
+reduced by using smaller records for inactive nodes than for active ones,
+and arithmetic overflow is avoided by using ``delta distances'' instead of
+keeping track of the total distance from the beginning of the paragraph to the
+current point.
+
+\fi
+
+\M825. The \\{line\_break} procedure should be invoked only in horizontal mode;
+it
+leaves that mode and places its output into the current vlist of the
+enclosing vertical mode (or internal vertical mode).
+There is one explicit parameter:  \\{final\_widow\_penalty} is the amount of
+additional penalty to be inserted before the final line of the paragraph.
+
+There are also a number of implicit parameters: The hlist to be broken
+starts at $\\{link}(\\{head})$, and it is nonempty. The value of \\{prev\_graf}
+in the
+enclosing semantic level tells where the paragraph should begin in the
+sequence of line numbers, in case hanging indentation or \.{\\parshape}
+are in use; \\{prev\_graf} is zero unless this paragraph is being continued
+after a displayed formula.  Other implicit parameters, such as the
+\\{par\_shape\_ptr} and various penalties to use for hyphenation, etc., appear
+in \\{eqtb}.
+
+After \\{line\_break} has acted, it will have updated the current vlist and the
+value of \\{prev\_graf}. Furthermore, the global variable \\{just\_box} will
+point to the final box created by \\{line\_break}, so that the width of this
+line can be ascertained when it is necessary to decide whether to use
+\\{above\_display\_skip} or \\{above\_display\_short\_skip} before a displayed
+formula.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{just\_box}: \37\\{pointer};\C{the \\{hlist\_node} for the last line of the
+new paragraph}\par
+\fi
+
+\M826. Since \\{line\_break} is a rather lengthy procedure---sort of a small
+world unto
+itself---we must build it up little by little, somewhat more cautiously
+than we have done with the simpler procedures of \TeX. Here is the
+general outline.
+
+\Y\P\hbox{\4}\X837:Declare subprocedures for \\{line\_break}\X \6
+\4\&{procedure}\1\  \37$\\{line\_break}(\\{final\_widow\_penalty}:%
+\\{integer})$;\6
+\4\&{label} \37$\\{done},\39\\{done1},\39\\{done2},\39\\{done3},\39\\{done4},%
+\39\\{done5},\39\\{continue}$;\6
+\4\&{var} \37\X873:Local variables for line breaking\X\2\6
+\&{begin} \37$\\{pack\_begin\_line}\K\\{mode\_line}$;\C{this is for
+over/underfull box messages}\6
+\X827:Get ready to start line breaking\X;\6
+\X874:Find optimal breakpoints\X;\6
+\X887:Break the paragraph at the chosen breakpoints, justify the resulting
+lines to the correct widths, and append them to the current vertical list\X;\6
+\X876:Clean up the memory by removing the break nodes\X;\6
+$\\{pack\_begin\_line}\K0$;\6
+\&{end};\par
+\fi
+
+\M827. The first task is to move the list from \\{head} to \\{temp\_head} and
+go
+into the enclosing semantic level. We also append the \.{\\parfillskip}
+glue to the end of the paragraph, removing a space (or other glue node) if
+it was there, since spaces usually precede blank lines and instances of
+`\.{\$\$}'. The \\{par\_fill\_skip} is preceded by an infinite penalty, so
+it will never be considered as a potential breakpoint.
+
+This code assumes that a \\{glue\_node} and a \\{penalty\_node} occupy the
+same number of \\{mem}~words.
+
+\Y\P$\4\X827:Get ready to start line breaking\X\S$\6
+$\\{first\_use}\K\\{true}$;\5
+$\\{chain}\K\\{false}$;\5
+$\\{delete\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\\{cur\_kanji\_skip}\K\\{space\_ptr}(\\{head})$;\5
+$\\{cur\_xkanji\_skip}\K\\{xspace\_ptr}(\\{head})$;\5
+$\\{add\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{add\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\\{link}(\\{temp\_head})\K\\{link}(\\{head})$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=\\{disp\_node})$ \1%
+\&{then}\6
+\&{begin} \37$\\{free\_node}(\\{tail},\39\\{small\_node\_size})$;\5
+$\\{tail}\K\\{prev\_node}$;\5
+$\\{link}(\\{tail})\K\\{null}$\6
+\&{end};\2\6
+\&{if} $\\{is\_char\_node}(\\{tail})$ \1\&{then}\5
+$\\{tail\_append}(\\{new\_penalty}(\\{inf\_penalty}))$\6
+\4\&{else} \&{if} $\\{type}(\\{tail})\I\\{glue\_node}$ \1\&{then}\5
+$\\{tail\_append}(\\{new\_penalty}(\\{inf\_penalty}))$\6
+\4\&{else} \&{begin} \37$\\{type}(\\{tail})\K\\{penalty\_node}$;\5
+$\\{delete\_glue\_ref}(\\{glue\_ptr}(\\{tail}))$;\5
+$\\{flush\_node\_list}(\\{leader\_ptr}(\\{tail}))$;\5
+$\\{penalty}(\\{tail})\K\\{inf\_penalty}$;\6
+\&{end};\2\2\6
+$\\{link}(\\{tail})\K\\{new\_param\_glue}(\\{par\_fill\_skip\_code})$;\5
+$\\{init\_cur\_lang}\K\\{prev\_graf}\mathbin{\&{mod}}\O{200000}$;\5
+$\\{init\_l\_hyf}\K\\{prev\_graf}\mathbin{\&{div}}\O{20000000}$;\5
+$\\{init\_r\_hyf}\K(\\{prev\_graf}\mathbin{\&{div}}\O{200000})\mathbin{\&{mod}}%
+\O{100}$;\5
+\\{pop\_nest};\par
+\As838, 845\ETs859.
+\U826.\fi
+
+\M828. When looking for optimal line breaks, \TeX\ creates a ``break node'' for
+each break that is {\sl feasible}, in the sense that there is a way to end
+a line at the given place without requiring any line to stretch more than
+a given tolerance. A break node is characterized by three things: the position
+of the break (which is a pointer to a \\{glue\_node}, \\{math\_node}, %
+\\{penalty\_node},
+or \\{disc\_node}); the ordinal number of the line that will follow this
+breakpoint; and the fitness classification of the line that has just
+ended, i.e., \\{tight\_fit}, \\{decent\_fit}, \\{loose\_fit}, or \\{very\_loose%
+\_fit}.
+
+\Y\P\D \37$\\{tight\_fit}=3$\C{fitness classification for lines shrinking 0.5
+to 1.0 of their   shrinkability}\par
+\P\D \37$\\{loose\_fit}=1$\C{fitness classification for lines stretching 0.5 to
+1.0 of their   stretchability}\par
+\P\D \37$\\{very\_loose\_fit}=0$\C{fitness classification for lines stretching
+more than   their stretchability}\par
+\P\D \37$\\{decent\_fit}=2$\C{fitness classification for all other lines}\par
+\fi
+
+\M829. The algorithm essentially determines the best possible way to achieve
+each feasible combination of position, line, and fitness. Thus, it answers
+questions like, ``What is the best way to break the opening part of the
+paragraph so that the fourth line is a tight line ending at such-and-such
+a place?'' However, the fact that all lines are to be the same length
+after a certain point makes it possible to regard all sufficiently large
+line numbers as equivalent, when the looseness parameter is zero, and this
+makes it possible for the algorithm to save space and time.
+
+An ``active node'' and a ``passive node'' are created in \\{mem} for each
+feasible breakpoint that needs to be considered. Active nodes are three
+words long and passive nodes are two words long. We need active nodes only
+for breakpoints near the place in the paragraph that is currently being
+examined, so they are recycled within a comparatively short time after
+they are created.
+
+\fi
+
+\M830. An active node for a given breakpoint contains six fields:
+
+\yskip\hang\\{link} points to the next node in the list of active nodes; the
+last active node has $\\{link}=\\{last\_active}$.
+
+\yskip\hang\\{break\_node} points to the passive node associated with this
+breakpoint.
+
+\yskip\hang\\{line\_number} is the number of the line that follows this
+breakpoint.
+
+\yskip\hang\\{fitness} is the fitness classification of the line ending at this
+breakpoint.
+
+\yskip\hang\\{type} is either \\{hyphenated} or \\{unhyphenated}, depending on
+whether this breakpoint is a \\{disc\_node}.
+
+\yskip\hang\\{total\_demerits} is the minimum possible sum of demerits over all
+lines leading from the beginning of the paragraph to this breakpoint.
+
+\yskip\noindent
+The value of $\\{link}(\\{active})$ points to the first active node on a linked
+list
+of all currently active nodes. This list is in order by \\{line\_number},
+except that nodes with $\\{line\_number}>\\{easy\_line}$ may be in any order
+relative
+to each other.
+
+\Y\P\D \37$\\{active\_node\_size}=3$\C{number of words in active nodes}\par
+\P\D \37$\\{fitness}\S\\{subtype}$\C{$\\{very\_loose\_fit}\to\\{tight\_fit}$ on
+final line for this break}\par
+\P\D \37$\\{break\_node}\S\\{rlink}$\C{pointer to the corresponding passive
+node}\par
+\P\D \37$\\{line\_number}\S\\{llink}$\C{line that begins at this breakpoint}\par
+\P\D \37$\\{total\_demerits}(\#)\S\\{mem}[\#+2].\\{int}$\C{the quantity that %
+\TeX\ minimizes}\par
+\P\D \37$\\{unhyphenated}=0$\C{the \\{type} of a normal active break node}\par
+\P\D \37$\\{hyphenated}=1$\C{the \\{type} of an active node that breaks at a %
+\\{disc\_node}}\par
+\P\D \37$\\{last\_active}\S\\{active}$\C{the active list ends where it begins}%
+\par
+\fi
+
+\M831. \P$\X801:Initialize the special list heads and constant nodes\X%
+\mathrel{+}\S$\6
+$\\{type}(\\{last\_active})\K\\{hyphenated}$;\5
+$\\{line\_number}(\\{last\_active})\K\\{max\_halfword}$;\5
+$\\{subtype}(\\{last\_active})\K0$;\C{the \\{subtype} is never examined by the
+algorithm}\par
+\fi
+
+\M832. The passive node for a given breakpoint contains only four fields:
+
+\yskip\hang\\{link} points to the passive node created just before this one,
+if any, otherwise it is \\{null}.
+
+\yskip\hang\\{cur\_break} points to the position of this breakpoint in the
+horizontal list for the paragraph being broken.
+
+\yskip\hang\\{prev\_break} points to the passive node that should precede this
+one in an optimal path to this breakpoint.
+
+\yskip\hang\\{serial} is equal to \|n if this passive node is the \|nth
+one created during the current pass. (This field is used only when
+printing out detailed statistics about the line-breaking calculations.)
+
+\yskip\noindent
+There is a global variable called \\{passive} that points to the most
+recently created passive node. Another global variable, \\{printed\_node},
+is used to help print out the paragraph when detailed information about
+the line-breaking computation is being displayed.
+
+\Y\P\D \37$\\{passive\_node\_size}=2$\C{number of words in passive nodes}\par
+\P\D \37$\\{cur\_break}\S\\{rlink}$\C{in passive node, points to position of
+this breakpoint}\par
+\P\D \37$\\{prev\_break}\S\\{llink}$\C{points to passive node that should
+precede this one}\par
+\P\D \37$\\{serial}\S\\{info}$\C{serial number for symbolic identification}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{passive}: \37\\{pointer};\C{most recent node on passive list}\6
+\4\\{printed\_node}: \37\\{pointer};\C{most recent node that has been printed}\6
+\4\\{pass\_number}: \37\\{halfword};\C{the number of passive nodes allocated on
+this pass}\par
+\fi
+
+\M833. The active list also contains ``delta'' nodes that help the algorithm
+compute the badness of individual lines. Such nodes appear only between two
+active nodes, and they have $\\{type}=\\{delta\_node}$. If \|p and \|r are
+active nodes
+and if \|q is a delta node between them, so that $\\{link}(\|p)=\|q$ and $%
+\\{link}(\|q)=\|r$,
+then \|q tells the space difference between lines in the horizontal list that
+start after breakpoint \|p and lines that start after breakpoint \|r. In
+other words, if we know the length of the line that starts after \|p and
+ends at our current position, then the corresponding length of the line that
+starts after \|r is obtained by adding the amounts in node~\|q. A delta node
+contains six scaled numbers, since it must record the net change in glue
+stretchability with respect to all orders of infinity. The natural width
+difference appears in $\\{mem}[\|q+1].\\{sc}$; the stretch differences in units
+of
+pt, fil, fill, and filll appear in $\\{mem}[\|q+2\to\|q+5].\\{sc}$; and the
+shrink difference
+appears in $\\{mem}[\|q+6].\\{sc}$. The \\{subtype} field of a delta node is
+not used.
+
+\Y\P\D \37$\\{delta\_node\_size}=7$\C{number of words in a delta node}\par
+\P\D \37$\\{delta\_node}=2$\C{\\{type} field in a delta node}\par
+\fi
+
+\M834. As the algorithm runs, it maintains a set of six delta-like registers
+for the length of the line following the first active breakpoint to the
+current position in the given hlist. When it makes a pass through the
+active list, it also maintains a similar set of six registers for the
+length following the active breakpoint of current interest. A third set
+holds the length of an empty line (namely, the sum of \.{\\leftskip} and
+\.{\\rightskip}); and a fourth set is used to create new delta nodes.
+
+When we pass a delta node we want to do operations like
+$$\hbox{\ignorespaces \&{for} $\|k\K1\mathrel{\&{to}}6$ \&{do} $\\{cur\_active%
+\_width}[\|k]\K\\{cur\_active\_width}[\|k]+\\{mem}[\|q+\|k].\\{sc}$};$$ and we
+want to do this without the overhead of  \&{for}  loops. The \\{do\_all\_six}
+macro makes such six-tuples convenient.
+
+\Y\P\D \37$\\{do\_all\_six}(\#)\S\#(1)$;\5
+$\#(2)$;\5
+$\#(3)$;\5
+$\#(4)$;\5
+$\#(5)$;\5
+$\#(6)$\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{active\_width}: \37\&{array} $[1\to6]$ \1\&{of}\5
+\\{scaled};\C{distance from first active node to~\\{cur\_p}}\2\6
+\4\\{cur\_active\_width}: \37\&{array} $[1\to6]$ \1\&{of}\5
+\\{scaled};\C{distance from current active node}\2\6
+\4\\{background}: \37\&{array} $[1\to6]$ \1\&{of}\5
+\\{scaled};\C{length of an ``empty'' line}\2\6
+\4\\{break\_width}: \37\&{array} $[1\to6]$ \1\&{of}\5
+\\{scaled};\C{length being computed after current break}\2\par
+\fi
+
+\M835. Let's state the principles of the delta nodes more precisely and
+concisely,
+so that the following programs will be less obscure. For each legal
+breakpoint~\|p in the paragraph, we define two quantities $\alpha(p)$ and
+$\beta(p)$ such that the length of material in a line from breakpoint~\|p
+to breakpoint~\|q is $\gamma+\beta(q)-\alpha(p)$, for some fixed $\gamma$.
+Intuitively, $\alpha(p)$ and $\beta(q)$ are the total length of material from
+the beginning of the paragraph to a point ``after'' a break at \|p and to a
+point ``before'' a break at \|q; and $\gamma$ is the width of an empty line,
+namely the length contributed by \.{\\leftskip} and \.{\\rightskip}.
+
+Suppose, for example, that the paragraph consists entirely of alternating
+boxes and glue skips; let the boxes have widths $x_1\ldots x_n$ and
+let the skips have widths $y_1\ldots y_n$, so that the paragraph can be
+represented by $x_1y_1\ldots x_ny_n$. Let $p_i$ be the legal breakpoint
+at $y_i$; then $\alpha(p_i)=x_1+y_1+\cdots+x_i+y_i$, and $\beta(p_i)=
+x_1+y_1+\cdots+x_i$. To check this, note that the length of material from
+$p_2$ to $p_5$, say, is $\gamma+x_3+y_3+x_4+y_4+x_5=\gamma+\beta(p_5)
+-\alpha(p_2)$.
+
+The quantities $\alpha$, $\beta$, $\gamma$ involve glue stretchability and
+shrinkability as well as a natural width. If we were to compute $\alpha(p)$
+and $\beta(p)$ for each \|p, we would need multiple precision arithmetic, and
+the multiprecise numbers would have to be kept in the active nodes.
+\TeX\ avoids this problem by working entirely with relative differences
+or ``deltas.'' Suppose, for example, that the active list contains
+$a_1\,\delta_1\,a_2\,\delta_2\,a_3$, where the \|a's are active breakpoints
+and the $\delta$'s are delta nodes. Then $\delta_1=\alpha(a_1)-\alpha(a_2)$
+and $\delta_2=\alpha(a_2)-\alpha(a_3)$. If the line breaking algorithm is
+currently positioned at some other breakpoint \|p, the \\{active\_width} array
+contains the value $\gamma+\beta(p)-\alpha(a_1)$. If we are scanning through
+the list of active nodes and considering a tentative line that runs from
+$a_2$ to~\|p, say, the \\{cur\_active\_width} array will contain the value
+$\gamma+\beta(p)-\alpha(a_2)$. Thus, when we move from $a_2$ to $a_3$,
+we want to add $\alpha(a_2)-\alpha(a_3)$ to \\{cur\_active\_width}; and this
+is just $\delta_2$, which appears in the active list between $a_2$ and
+$a_3$. The \\{background} array contains $\gamma$. The \\{break\_width} array
+will be used to calculate values of new delta nodes when the active
+list is being updated.
+
+\fi
+
+\M836. Glue nodes in a horizontal list that is being paragraphed are not
+supposed to
+include ``infinite'' shrinkability; that is why the algorithm maintains
+four registers for stretching but only one for shrinking. If the user tries to
+introduce infinite shrinkability, the shrinkability will be reset to finite
+and an error message will be issued. A boolean variable \\{no\_shrink\_error%
+\_yet}
+prevents this error message from appearing more than once per paragraph.
+
+\Y\P\D \37$\\{check\_shrinkage}(\#)\S$\1\6
+\&{if} $(\\{shrink\_order}(\#)\I\\{normal})\W(\\{shrink}(\#)\I0)$ \1\&{then}\6
+\&{begin} \37$\#\K\\{finite\_shrink}(\#)$;\6
+\&{end}\2\2\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{no\_shrink\_error\_yet}: \37\\{boolean};\C{have we complained about
+infinite shrinkage?}\par
+\fi
+
+\M837. \P$\X837:Declare subprocedures for \\{line\_break}\X\S$\6
+\4\&{function}\1\  \37$\\{finite\_shrink}(\|p:\\{pointer})$: \37\\{pointer};%
+\C{recovers from infinite shrinkage}\6
+\4\&{var} \37\|q: \37\\{pointer};\C{new glue specification}\2\6
+\&{begin} \37\&{if} $\\{no\_shrink\_error\_yet}$ \1\&{then}\6
+\&{begin} \37$\\{no\_shrink\_error\_yet}\K\\{false}$;\5
+$\\{print\_err}(\.{"Infinite\ glue\ shrinkage\ found\ in\ a\ paragraph"})$;\5
+$\\{help5}(\.{"The\ paragraph\ just\ ended\ includes\ some\ glue\ that\ has"})$%
+\6
+$(\.{"infinite\ shrinkability,\ e.g.,\ \`\\hskip\ 0pt\ minus\ 1fil\'."})$\6
+$(\.{"Such\ glue\ doesn\'t\ belong\ there---it\ allows\ a\ paragraph"})$\6
+$(\.{"of\ any\ length\ to\ fit\ on\ one\ line.\ But\ it\'s\ safe\ to\
+proceed,"})$\6
+$(\.{"since\ the\ offensive\ shrinkability\ has\ been\ made\ finite."})$;\5
+\\{error};\6
+\&{end};\2\6
+$\|q\K\\{new\_spec}(\|p)$;\5
+$\\{shrink\_order}(\|q)\K\\{normal}$;\5
+$\\{delete\_glue\_ref}(\|p)$;\5
+$\\{finite\_shrink}\K\|q$;\6
+\&{end};\par
+\As840, 888, 906\ETs953.
+\U826.\fi
+
+\M838. \P$\X827:Get ready to start line breaking\X\mathrel{+}\S$\6
+$\\{no\_shrink\_error\_yet}\K\\{true}$;\6
+$\\{check\_shrinkage}(\\{left\_skip})$;\5
+$\\{check\_shrinkage}(\\{right\_skip})$;\6
+$\|q\K\\{left\_skip}$;\5
+$\|r\K\\{right\_skip}$;\5
+$\\{background}[1]\K\\{width}(\|q)+\\{width}(\|r)$;\6
+$\\{background}[2]\K0$;\5
+$\\{background}[3]\K0$;\5
+$\\{background}[4]\K0$;\5
+$\\{background}[5]\K0$;\6
+$\\{background}[2+\\{stretch\_order}(\|q)]\K\\{stretch}(\|q)$;\6
+$\\{background}[2+\\{stretch\_order}(\|r)]\K\30\\{background}[2+\\{stretch%
+\_order}(\|r)]+\\{stretch}(\|r)$;\6
+$\\{background}[6]\K\\{shrink}(\|q)+\\{shrink}(\|r)$;\par
+\fi
+
+\M839. A pointer variable \\{cur\_p} runs through the given horizontal list as
+we look
+for breakpoints. This variable is global, since it is used both by \\{line%
+\_break}
+and by its subprocedure \\{try\_break}.
+
+Another global variable called \\{threshold} is used to determine the
+feasibility
+of individual lines: Breakpoints are feasible if there is a way to reach
+them without creating lines whose badness exceeds \\{threshold}.  (The
+badness is compared to \\{threshold} before penalties are added, so that
+penalty values do not affect the feasibility of breakpoints, except that
+no break is allowed when the penalty is 10000 or more.) If \\{threshold}
+is 10000 or more, all legal breaks are considered feasible, since the
+\\{badness} function specified above never returns a value greater than~10000.
+
+Up to three passes might be made through the paragraph in an attempt to find at
+least one set of feasible breakpoints. On the first pass, we have
+$\\{threshold}=\\{pretolerance}$ and $\\{second\_pass}=\\{final\_pass}=%
+\\{false}$.
+If this pass fails to find a
+feasible solution, \\{threshold} is set to \\{tolerance}, \\{second\_pass} is
+set
+\\{true}, and an attempt is made to hyphenate as many words as possible.
+If that fails too, we add \\{emergency\_stretch} to the background
+stretchability and set $\\{final\_pass}=\\{true}$.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_p}: \37\\{pointer};\C{the current breakpoint under consideration}\6
+\4\\{chain}: \37\\{boolean};\C{chain current line and next line?}\6
+\4\\{second\_pass}: \37\\{boolean};\C{is this our second attempt to break this
+paragraph?}\6
+\4\\{final\_pass}: \37\\{boolean};\C{is this our final attempt to break this
+paragraph?}\6
+\4\\{threshold}: \37\\{integer};\C{maximum badness on feasible lines}\par
+\fi
+
+\M840. The heart of the line-breaking procedure is `\\{try\_break}', a
+subroutine
+that tests if the current breakpoint \\{cur\_p} is feasible, by running
+through the active list to see what lines of text can be made from active
+nodes to~\\{cur\_p}.  If feasible breaks are possible, new break nodes are
+created.  If \\{cur\_p} is too far from an active node, that node is
+deactivated.
+
+The parameter \\{pi} to \\{try\_break} is the penalty associated
+with a break at \\{cur\_p}; we have $\\{pi}=\\{eject\_penalty}$ if the break is
+forced,
+and $\\{pi}=\\{inf\_penalty}$ if the break is illegal.
+
+The other parameter, \\{break\_type}, is set to \\{hyphenated} or %
+\\{unhyphenated},
+depending on whether or not the current break is at a \\{disc\_node}. The
+end of a paragraph is also regarded as `\\{hyphenated}'; this case is
+distinguishable by the condition $\\{cur\_p}=\\{null}$.
+
+\Y\P\D \37$\\{copy\_to\_cur\_active}(\#)\S\\{cur\_active\_width}[\#]\K\\{active%
+\_width}[\#]$\par
+\P\D \37$\\{deactivate}=60$\C{go here when node \|r should be deactivated}\par
+\Y\P$\4\X837:Declare subprocedures for \\{line\_break}\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{try\_break}(\\{pi}:\\{integer};\,\35\\{break\_type}:%
+\\{small\_number})$;\6
+\4\&{label} \37$\\{exit},\39\\{done},\39\\{done1},\39\\{continue},\39%
+\\{deactivate}$;\6
+\4\&{var} \37\|r: \37\\{pointer};\C{runs through the active list}\6
+\\{prev\_r}: \37\\{pointer};\C{stays a step behind \|r}\6
+\\{old\_l}: \37\\{halfword};\C{maximum line number in current equivalence class
+of lines}\6
+\\{no\_break\_yet}: \37\\{boolean};\C{have we found a feasible break at \\{cur%
+\_p}?}\6
+\X841:Other local variables for \\{try\_break}\X\2\6
+\&{begin} \37\X842:Make sure that \\{pi} is in the proper range\X;\6
+$\\{no\_break\_yet}\K\\{true}$;\5
+$\\{prev\_r}\K\\{active}$;\5
+$\\{old\_l}\K0$;\5
+$\\{do\_all\_six}(\\{copy\_to\_cur\_active})$;\6
+\~ \1\&{loop}\ \&{begin} \37\\{continue}: \37$\|r\K\\{link}(\\{prev\_r})$;\5
+\X843:If node \|r is of type \\{delta\_node}, update \\{cur\_active\_width},
+set \\{prev\_r} and \\{prev\_prev\_r}, then \&{goto} \\{continue}\X;\6
+\X846:If a line number class has ended, create new active nodes for the best
+feasible breaks in that class; then \&{return} if $\|r=\\{last\_active}$,
+otherwise compute the new \\{line\_width}\X;\6
+\X862:Consider the demerits for a line from \|r to \\{cur\_p}; deactivate node %
+\|r if it should no longer be active; then \&{goto} \\{continue} if a line from
+\|r to \\{cur\_p} is infeasible, otherwise record a new feasible break\X;\6
+\&{end};\2\6
+\4\\{exit}: \37\&{stat} \37\X869:Update the value of \\{printed\_node} for
+symbolic displays\X\ \&{tats}\6
+\&{end};\par
+\fi
+
+\M841. \P$\X841:Other local variables for \\{try\_break}\X\S$\6
+\4\\{prev\_prev\_r}: \37\\{pointer};\C{a step behind \\{prev\_r}, if $\\{type}(%
+\\{prev\_r})=\\{delta\_node}$}\6
+\4\|s: \37\\{pointer};\C{runs through nodes ahead of \\{cur\_p}}\6
+\4\|q: \37\\{pointer};\C{points to a new node being created}\6
+\4\|v: \37\\{pointer};\C{points to a glue specification or a node ahead of %
+\\{cur\_p}}\6
+\4\|t: \37\\{integer};\C{node count, if \\{cur\_p} is a discretionary node}\6
+\4\|f: \37\\{internal\_font\_number};\C{used in character width calculation}\6
+\4\|l: \37\\{halfword};\C{line number of current active node}\6
+\4\\{node\_r\_stays\_active}: \37\\{boolean};\C{should node \|r remain in the
+active list?}\6
+\4\\{line\_width}: \37\\{scaled};\C{the current line will be justified to this
+width}\6
+\4\\{fit\_class}: \37$\\{very\_loose\_fit}\to\\{tight\_fit}$;\C{possible
+fitness class of test line}\6
+\4\|b: \37\\{halfword};\C{badness of test line}\6
+\4\|d: \37\\{integer};\C{demerits of test line}\6
+\4\\{artificial\_demerits}: \37\\{boolean};\C{has \|d been forced to zero?}\6
+\4\\{save\_link}: \37\\{pointer};\C{temporarily holds value of $\\{link}(\\{cur%
+\_p})$}\6
+\4\\{shortfall}: \37\\{scaled};\C{used in badness calculations}\par
+\U840.\fi
+
+\M842. \P$\X842:Make sure that \\{pi} is in the proper range\X\S$\6
+\&{if} $\\{abs}(\\{pi})\G\\{inf\_penalty}$ \1\&{then}\6
+\&{if} $\\{pi}>0$ \1\&{then}\5
+\&{return}\C{this breakpoint is inhibited by infinite penalty}\6
+\4\&{else} $\\{pi}\K\\{eject\_penalty}$\C{this breakpoint will be forced}\2\2%
+\par
+\U840.\fi
+
+\M843. The following code uses the fact that $\\{type}(\\{last\_active})\I%
+\\{delta\_node}$.
+
+\Y\P\D \37$\\{update\_width}(\#)\S\30\\{cur\_active\_width}[\#]\K\\{cur\_active%
+\_width}[\#]+\\{mem}[\|r+\#].\\{sc}$\par
+\Y\P$\4\X843:If node \|r is of type \\{delta\_node}, update \\{cur\_active%
+\_width}, set \\{prev\_r} and \\{prev\_prev\_r}, then \&{goto} \\{continue}\X%
+\S$\6
+\&{if} $\\{type}(\|r)=\\{delta\_node}$ \1\&{then}\6
+\&{begin} \37$\\{do\_all\_six}(\\{update\_width})$;\5
+$\\{prev\_prev\_r}\K\\{prev\_r}$;\5
+$\\{prev\_r}\K\|r$;\5
+\&{goto} \37\\{continue};\6
+\&{end}\2\par
+\U840.\fi
+
+\M844. As we consider various ways to end a line at \\{cur\_p}, in a given line
+number
+class, we keep track of the best total demerits known, in an array with
+one entry for each of the fitness classifications. For example,
+$\\{minimal\_demerits}[\\{tight\_fit}]$ contains the fewest total demerits of
+feasible
+line breaks ending at \\{cur\_p} with a \\{tight\_fit} line; $\\{best\_place}[%
+\\{tight\_fit}]$
+points to the passive node for the break before~\\{cur\_p} that achieves such
+an optimum; and $\\{best\_pl\_line}[\\{tight\_fit}]$ is the \\{line\_number}
+field in the
+active node corresponding to $\\{best\_place}[\\{tight\_fit}]$. When no
+feasible break
+sequence is known, the \\{minimal\_demerits} entries will be equal to
+\\{awful\_bad}, which is $2^{30}-1$. Another variable, \\{minimum\_demerits},
+keeps track of the smallest value in the \\{minimal\_demerits} array.
+
+\Y\P\D \37$\\{awful\_bad}\S\O{7777777777}$\C{more than a billion demerits}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{minimal\_demerits}: \37\&{array} $[\\{very\_loose\_fit}\to\\{tight\_fit}]$
+\1\&{of}\5
+\\{integer};\C{best total   demerits known for current line class and position,
+given the fitness}\2\6
+\4\\{minimum\_demerits}: \37\\{integer};\C{best total demerits known for
+current line class   and position}\6
+\4\\{best\_place}: \37\&{array} $[\\{very\_loose\_fit}\to\\{tight\_fit}]$ \1%
+\&{of}\5
+\\{pointer};\C{how to achieve   \\{minimal\_demerits}}\2\6
+\4\\{best\_pl\_line}: \37\&{array} $[\\{very\_loose\_fit}\to\\{tight\_fit}]$ \1%
+\&{of}\5
+\\{halfword};\C{corresponding   line number}\2\par
+\fi
+
+\M845. \P$\X827:Get ready to start line breaking\X\mathrel{+}\S$\6
+$\\{minimum\_demerits}\K\\{awful\_bad}$;\5
+$\\{minimal\_demerits}[\\{tight\_fit}]\K\\{awful\_bad}$;\5
+$\\{minimal\_demerits}[\\{decent\_fit}]\K\\{awful\_bad}$;\5
+$\\{minimal\_demerits}[\\{loose\_fit}]\K\\{awful\_bad}$;\5
+$\\{minimal\_demerits}[\\{very\_loose\_fit}]\K\\{awful\_bad}$;\par
+\fi
+
+\M846. The first part of the following code is part of \TeX's inner loop, so
+we don't want to waste any time. The current active node, namely node \|r,
+contains the line number that will be considered next. At the end of the
+list we have arranged the data structure so that $\|r=\\{last\_active}$ and
+$\\{line\_number}(\\{last\_active})>\\{old\_l}$.
+
+\Y\P$\4\X846:If a line number class has ended, create new active nodes for the
+best feasible breaks in that class; then \&{return} if $\|r=\\{last\_active}$,
+otherwise compute the new \\{line\_width}\X\S$\6
+\&{begin} \37$\|l\K\\{line\_number}(\|r)$;\6
+\&{if} $\|l>\\{old\_l}$ \1\&{then}\6
+\&{begin} \37\C{now we are no longer in the inner loop}\6
+\&{if} $(\\{minimum\_demerits}<\\{awful\_bad})\W\30((\\{old\_l}\I\\{easy%
+\_line})\V(\|r=\\{last\_active}))$ \1\&{then}\5
+\X847:Create new active nodes for the best feasible breaks just found\X;\2\6
+\&{if} $\|r=\\{last\_active}$ \1\&{then}\5
+\&{return};\2\6
+\X861:Compute the new line width\X;\6
+\&{end};\2\6
+\&{end}\par
+\U840.\fi
+
+\M847. It is not necessary to create new active nodes having \\{minimal%
+\_demerits}
+greater than
+$\\{minimum\_demerits}+\\{abs}(\\{adj\_demerits})$, since such active nodes
+will never
+be chosen in the final paragraph breaks. This observation allows us to
+omit a substantial number of feasible breakpoints from further consideration.
+
+\Y\P$\4\X847:Create new active nodes for the best feasible breaks just found\X%
+\S$\6
+\&{begin} \37\&{if} $\\{no\_break\_yet}$ \1\&{then}\5
+\X848:Compute the values of \\{break\_width}\X;\2\6
+\X854:Insert a delta node to prepare for breaks at \\{cur\_p}\X;\6
+\&{if} $\\{abs}(\\{adj\_demerits})\G\\{awful\_bad}-\\{minimum\_demerits}$ \1%
+\&{then}\5
+$\\{minimum\_demerits}\K\\{awful\_bad}-1$\6
+\4\&{else} $\\{minimum\_demerits}\K\\{minimum\_demerits}+\\{abs}(\\{adj%
+\_demerits})$;\2\6
+\&{for} $\\{fit\_class}\K\\{very\_loose\_fit}\mathrel{\&{to}}\\{tight\_fit}$ \1%
+\&{do}\6
+\&{begin} \37\&{if} $\\{minimal\_demerits}[\\{fit\_class}]\L\\{minimum%
+\_demerits}$ \1\&{then}\5
+\X856:Insert a new active node from $\\{best\_place}[\\{fit\_class}]$ to \\{cur%
+\_p}\X;\2\6
+$\\{minimal\_demerits}[\\{fit\_class}]\K\\{awful\_bad}$;\6
+\&{end};\2\6
+$\\{minimum\_demerits}\K\\{awful\_bad}$;\5
+\X855:Insert a delta node to prepare for the next active node\X;\6
+\&{end}\par
+\U846.\fi
+
+\M848. When we insert a new active node for a break at \\{cur\_p}, suppose this
+new node is to be placed just before active node \|a; then we essentially
+want to insert `$\delta\,\\{cur\_p}\,\delta^\prime$' before \|a, where
+$\delta=\alpha(a)-\alpha(\\{cur\_p})$ and $\delta^\prime=\alpha(\\{cur\_p})-%
+\alpha(a)$
+in the notation explained above.  The \\{cur\_active\_width} array now holds
+$\gamma+\beta(\\{cur\_p})-\alpha(a)$; so $\delta$ can be obtained by
+subtracting \\{cur\_active\_width} from the quantity $\gamma+\beta(\\{cur\_p})-
+\alpha(\\{cur\_p})$. The latter quantity can be regarded as the length of a
+line ``from \\{cur\_p} to \\{cur\_p}''; we call it the \\{break\_width} at %
+\\{cur\_p}.
+
+The \\{break\_width} is usually negative, since it consists of the background
+(which is normally zero) minus the width of nodes following~\\{cur\_p} that are
+eliminated after a break. If, for example, node \\{cur\_p} is a glue node, the
+width of this glue is subtracted from the background; and we also look
+ahead to eliminate all subsequent glue and penalty and kern and math
+nodes, subtracting their widths as well.
+
+Kern nodes do not disappear at a line break unless they are \\{explicit}.
+
+\Y\P\D \37$\\{set\_break\_width\_to\_background}(\#)\S\\{break\_width}[\#]\K%
+\\{background}[\#]$\par
+\Y\P$\4\X848:Compute the values of \\{break\_width}\X\S$\6
+\&{begin} \37$\\{no\_break\_yet}\K\\{false}$;\5
+$\\{do\_all\_six}(\\{set\_break\_width\_to\_background})$;\5
+$\|s\K\\{cur\_p}$;\6
+\&{if} $\\{break\_type}>\\{unhyphenated}$ \1\&{then}\6
+\&{if} $\\{cur\_p}\I\\{null}$ \1\&{then}\5
+\X851:Compute the discretionary \\{break\_width} values\X;\2\2\6
+\&{while} $\|s\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|s)$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{chain}$ \1\&{then}\6
+\&{begin} \37$\\{break\_width}[1]\K\\{break\_width}[1]-\\{width}(\\{cur\_kanji%
+\_skip})$;\5
+$\\{break\_width}[2+\\{stretch\_order}(\\{cur\_kanji\_skip})]\K\\{break%
+\_width}[2+\\{stretch\_order}(\\{cur\_kanji\_skip})]-\\{stretch}(\\{cur\_kanji%
+\_skip})$;\5
+$\\{break\_width}[6]\K\\{break\_width}[6]-\\{shrink}(\\{cur\_kanji\_skip})$;\6
+\&{end};\2\6
+\&{goto} \37\\{done}\6
+\&{end};\2\6
+\&{case} $\\{type}(\|s)$ \1\&{of}\6
+\4\\{glue\_node}: \37\X849:Subtract glue from \\{break\_width}\X;\6
+\4\\{penalty\_node}: \37\\{do\_nothing};\6
+\4\\{math\_node}: \37$\\{break\_width}[1]\K\\{break\_width}[1]-\\{width}(\|s)$;%
+\6
+\4\\{kern\_node}: \37\&{if} $(\\{subtype}(\|s)\I\\{explicit})\W(\\{subtype}(%
+\|s)\I\\{ita\_kern})$ \1\&{then}\5
+\&{goto} \37\\{done}\6
+\4\&{else} $\\{break\_width}[1]\K\\{break\_width}[1]-\\{width}(\|s)$;\2\6
+\4\&{othercases} \37\&{goto} \37\\{done}\2\6
+\&{endcases};\6
+$\|s\K\\{link}(\|s)$;\6
+\&{end};\2\6
+\4\\{done}: \37\&{end}\par
+\U847.\fi
+
+\M849. \P$\X849:Subtract glue from \\{break\_width}\X\S$\6
+\&{begin} \37$\|v\K\\{glue\_ptr}(\|s)$;\5
+$\\{break\_width}[1]\K\\{break\_width}[1]-\\{width}(\|v)$;\5
+$\\{break\_width}[2+\\{stretch\_order}(\|v)]\K\\{break\_width}[2+\\{stretch%
+\_order}(\|v)]-\\{stretch}(\|v)$;\5
+$\\{break\_width}[6]\K\\{break\_width}[6]-\\{shrink}(\|v)$;\6
+\&{end}\par
+\U848.\fi
+
+\M850. When \\{cur\_p} is a discretionary break, the length of a line ``from %
+\\{cur\_p} to
+\\{cur\_p}'' has to be defined properly so that the other calculations work
+out.
+Suppose that the pre-break text at \\{cur\_p} has length $l_0$, the post-break
+text has length $l_1$, and the replacement text has length \|l. Suppose
+also that \|q is the node following the replacement text. Then length of a
+line from \\{cur\_p} to \|q will be computed as $\gamma+\beta(q)-\alpha(\\{cur%
+\_p})$,
+where $\beta(q)=\beta(\\{cur\_p})-l_0+l$. The actual length will be the
+background
+plus $l_1$, so the length from \\{cur\_p} to \\{cur\_p} should be $%
+\gamma+l_0+l_1-l$.
+If the post-break text of the discretionary is empty, a break may also
+discard~\|q; in that unusual case we subtract the length of~\|q and any
+other nodes that will be discarded after the discretionary break.
+
+The value of $l_0$ need not be computed, since \\{line\_break} will put
+it into the global variable \\{disc\_width} before calling \\{try\_break}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{disc\_width}: \37\\{scaled};\C{the length of discretionary material
+preceding a break}\par
+\fi
+
+\M851. \P$\X851:Compute the discretionary \\{break\_width} values\X\S$\6
+\&{begin} \37$\|t\K\\{replace\_count}(\\{cur\_p})$;\5
+$\|v\K\\{cur\_p}$;\5
+$\|s\K\\{post\_break}(\\{cur\_p})$;\6
+\&{while} $\|t>0$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\|t)$;\5
+$\|v\K\\{link}(\|v)$;\5
+\X852:Subtract the width of node \|v from \\{break\_width}\X;\6
+\&{end};\2\6
+\&{while} $\|s\I\\{null}$ \1\&{do}\6
+\&{begin} \37\X853:Add the width of node \|s to \\{break\_width}\X;\6
+$\|s\K\\{link}(\|s)$;\6
+\&{end};\2\6
+$\\{break\_width}[1]\K\\{break\_width}[1]+\\{disc\_width}$;\6
+\&{if} $\\{post\_break}(\\{cur\_p})=\\{null}$ \1\&{then}\5
+$\|s\K\\{link}(\|v)$;\C{nodes may be discardable after the break}\2\6
+\&{end}\par
+\U848.\fi
+
+\M852. Replacement texts and discretionary texts are supposed to contain
+only character nodes, kern nodes, ligature nodes, and box or rule nodes.
+
+\Y\P$\4\X852:Subtract the width of node \|v from \\{break\_width}\X\S$\6
+\&{if} $\\{is\_char\_node}(\|v)$ \1\&{then}\6
+\&{begin} \37$\|f\K\\{font}(\|v)$;\5
+$\\{break\_width}[1]\K\\{break\_width}[1]-\\{char\_width}(\|f)(\\{orig\_char%
+\_info}(\|f)(\\{character}(\|v)))$;\6
+\&{if} $\\{font\_dir}[\|f]\I\\{dir\_default}$ \1\&{then}\5
+$\|v\K\\{link}(\|v)$;\2\6
+\&{end}\6
+\4\&{else} \&{case} $\\{type}(\|v)$ \1\&{of}\6
+\4\\{ligature\_node}: \37\&{begin} \37$\|f\K\\{font}(\\{lig\_char}(\|v))$;\6
+$\\{break\_width}[1]\K\30\\{break\_width}[1]-\\{char\_width}(\|f)(\\{orig\_char%
+\_info}(\|f)(\\{character}(\\{lig\_char}(\|v))))$;\6
+\&{end};\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node},\39%
+\\{kern\_node}$: \37$\\{break\_width}[1]\K\\{break\_width}[1]-\\{width}(\|v)$;\6
+\4\\{disp\_node}: \37\\{do\_nothing};\6
+\4\&{othercases} \37$\\{confusion}(\.{"disc1"})$\2\6
+\&{endcases}\2\par
+\U851.\fi
+
+\M853. \P$\X853:Add the width of node \|s to \\{break\_width}\X\S$\6
+\&{if} $\\{is\_char\_node}(\|s)$ \1\&{then}\6
+\&{begin} \37$\|f\K\\{font}(\|s)$;\5
+$\\{break\_width}[1]\K\30\\{break\_width}[1]+\\{char\_width}(\|f)(\\{orig\_char%
+\_info}(\|f)(\\{character}(\|s)))$;\6
+\&{if} $\\{font\_dir}[\|f]\I\\{dir\_default}$ \1\&{then}\5
+$\|s\K\\{link}(\|s)$;\2\6
+\&{end}\6
+\4\&{else} \&{case} $\\{type}(\|s)$ \1\&{of}\6
+\4\\{ligature\_node}: \37\&{begin} \37$\|f\K\\{font}(\\{lig\_char}(\|s))$;\5
+$\\{break\_width}[1]\K\\{break\_width}[1]+\\{char\_width}(\|f)(\\{orig\_char%
+\_info}(\|f)(\\{character}(\\{lig\_char}(\|s))))$;\6
+\&{end};\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node},\39%
+\\{kern\_node}$: \37$\\{break\_width}[1]\K\\{break\_width}[1]+\\{width}(\|s)$;\6
+\4\\{disp\_node}: \37\\{do\_nothing};\6
+\4\&{othercases} \37$\\{confusion}(\.{"disc2"})$\2\6
+\&{endcases}\2\par
+\U851.\fi
+
+\M854. We use the fact that $\\{type}(\\{active})\I\\{delta\_node}$.
+
+\Y\P\D \37$\\{convert\_to\_break\_width}(\#)\S\30\\{mem}[\\{prev\_r}+\#].\\{sc}%
+\K\30\hbox{\hskip10pt}\\{mem}[\\{prev\_r}+\#].\\{sc}-\\{cur\_active\_width}[%
+\#]+\\{break\_width}[\#]$\par
+\P\D \37$\\{store\_break\_width}(\#)\S\\{active\_width}[\#]\K\\{break\_width}[%
+\#]$\par
+\P\D \37$\\{new\_delta\_to\_break\_width}(\#)\S\30\\{mem}[\|q+\#].\\{sc}\K%
+\\{break\_width}[\#]-\\{cur\_active\_width}[\#]$\par
+\Y\P$\4\X854:Insert a delta node to prepare for breaks at \\{cur\_p}\X\S$\6
+\&{if} $\\{type}(\\{prev\_r})=\\{delta\_node}$ \1\&{then}\C{modify an existing
+delta node}\6
+\&{begin} \37$\\{do\_all\_six}(\\{convert\_to\_break\_width})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{prev\_r}=\\{active}$ \1\&{then}\C{no delta node needed at
+the beginning}\6
+\&{begin} \37$\\{do\_all\_six}(\\{store\_break\_width})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|q\K\\{get\_node}(\\{delta\_node\_size})$;\5
+$\\{link}(\|q)\K\|r$;\5
+$\\{type}(\|q)\K\\{delta\_node}$;\6
+$\\{subtype}(\|q)\K0$;\C{the \\{subtype} is not used}\6
+$\\{do\_all\_six}(\\{new\_delta\_to\_break\_width})$;\5
+$\\{link}(\\{prev\_r})\K\|q$;\5
+$\\{prev\_prev\_r}\K\\{prev\_r}$;\5
+$\\{prev\_r}\K\|q$;\6
+\&{end}\2\2\par
+\U847.\fi
+
+\M855. When the following code is performed, we will have just inserted at
+least one active node before \|r, so $\\{type}(\\{prev\_r})\I\\{delta\_node}$.
+
+\Y\P\D \37$\\{new\_delta\_from\_break\_width}(\#)\S\30\\{mem}[\|q+\#].\\{sc}\K%
+\\{cur\_active\_width}[\#]-\\{break\_width}[\#]$\par
+\Y\P$\4\X855:Insert a delta node to prepare for the next active node\X\S$\6
+\&{if} $\|r\I\\{last\_active}$ \1\&{then}\6
+\&{begin} \37$\|q\K\\{get\_node}(\\{delta\_node\_size})$;\5
+$\\{link}(\|q)\K\|r$;\5
+$\\{type}(\|q)\K\\{delta\_node}$;\6
+$\\{subtype}(\|q)\K0$;\C{the \\{subtype} is not used}\6
+$\\{do\_all\_six}(\\{new\_delta\_from\_break\_width})$;\5
+$\\{link}(\\{prev\_r})\K\|q$;\5
+$\\{prev\_prev\_r}\K\\{prev\_r}$;\5
+$\\{prev\_r}\K\|q$;\6
+\&{end}\2\par
+\U847.\fi
+
+\M856. When we create an active node, we also create the corresponding
+passive node.
+
+\Y\P$\4\X856:Insert a new active node from $\\{best\_place}[\\{fit\_class}]$ to
+\\{cur\_p}\X\S$\6
+\&{begin} \37$\|q\K\\{get\_node}(\\{passive\_node\_size})$;\5
+$\\{link}(\|q)\K\\{passive}$;\5
+$\\{passive}\K\|q$;\5
+$\\{cur\_break}(\|q)\K\\{cur\_p}$;\6
+\&{stat} \37$\\{incr}(\\{pass\_number})$;\5
+$\\{serial}(\|q)\K\\{pass\_number}$;\ \&{tats}\6
+$\\{prev\_break}(\|q)\K\\{best\_place}[\\{fit\_class}]$;\6
+$\|q\K\\{get\_node}(\\{active\_node\_size})$;\5
+$\\{break\_node}(\|q)\K\\{passive}$;\5
+$\\{line\_number}(\|q)\K\\{best\_pl\_line}[\\{fit\_class}]+1$;\5
+$\\{fitness}(\|q)\K\\{fit\_class}$;\5
+$\\{type}(\|q)\K\\{break\_type}$;\5
+$\\{total\_demerits}(\|q)\K\\{minimal\_demerits}[\\{fit\_class}]$;\5
+$\\{link}(\|q)\K\|r$;\5
+$\\{link}(\\{prev\_r})\K\|q$;\5
+$\\{prev\_r}\K\|q$;\6
+\&{stat} \37\&{if} $\\{tracing\_paragraphs}>0$ \1\&{then}\5
+\X857:Print a symbolic description of the new break node\X;\2\6
+\&{tats}\6
+\&{end}\par
+\U847.\fi
+
+\M857. \P$\X857:Print a symbolic description of the new break node\X\S$\6
+\&{begin} \37$\\{print\_nl}(\.{"@@"})$;\5
+$\\{print\_int}(\\{serial}(\\{passive}))$;\5
+$\\{print}(\.{":\ line\ "})$;\5
+$\\{print\_int}(\\{line\_number}(\|q)-1)$;\5
+$\\{print\_char}(\.{"."})$;\5
+$\\{print\_int}(\\{fit\_class})$;\6
+\&{if} $\\{break\_type}=\\{hyphenated}$ \1\&{then}\5
+$\\{print\_char}(\.{"-"})$;\2\6
+$\\{print}(\.{"\ t="})$;\5
+$\\{print\_int}(\\{total\_demerits}(\|q))$;\5
+$\\{print}(\.{"\ ->\ @@"})$;\6
+\&{if} $\\{prev\_break}(\\{passive})=\\{null}$ \1\&{then}\5
+$\\{print\_char}(\.{"0"})$\6
+\4\&{else} $\\{print\_int}(\\{serial}(\\{prev\_break}(\\{passive})))$;\2\6
+\&{end}\par
+\U856.\fi
+
+\M858. The length of lines depends on whether the user has specified
+\.{\\parshape} or \.{\\hangindent}. If \\{par\_shape\_ptr} is not null, it
+points to a $(2n+1)$-word record in \\{mem}, where the \\{info} in the first
+word contains the value of \|n, and the other $2n$ words contain the left
+margins and line lengths for the first \|n lines of the paragraph; the
+specifications for line \|n apply to all subsequent lines. If
+$\\{par\_shape\_ptr}=\\{null}$, the shape of the paragraph depends on the value
+of
+$\|n=\\{hang\_after}$; if $\|n\G0$, hanging indentation takes place on lines $%
+\|n+1$,
+$\|n+2$, \dots, otherwise it takes place on lines 1, \dots, $\vert
+n\vert$. When hanging indentation is active, the left margin is
+\\{hang\_indent}, if $\\{hang\_indent}\G0$, else it is 0; the line length is
+$\\{hsize}-\vert\\{hang\_indent}\vert$. The normal setting is
+$\\{par\_shape\_ptr}=\\{null}$, $\\{hang\_after}=1$, and $\\{hang\_indent}=0$.
+Note that if $\\{hang\_indent}=0$, the value of \\{hang\_after} is irrelevant.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{easy\_line}: \37\\{halfword};\C{line numbers $>\\{easy\_line}$ are
+equivalent in break nodes}\6
+\4\\{last\_special\_line}: \37\\{halfword};\C{line numbers $>\\{last\_special%
+\_line}$ all have   the same width}\6
+\4\\{first\_width}: \37\\{scaled};\C{the width of all lines $\L\\{last\_special%
+\_line}$, if   no \.{\\parshape} has been specified}\6
+\4\\{second\_width}: \37\\{scaled};\C{the width of all lines $>\\{last\_special%
+\_line}$}\6
+\4\\{first\_indent}: \37\\{scaled};\C{left margin to go with \\{first\_width}}\6
+\4\\{second\_indent}: \37\\{scaled};\C{left margin to go with \\{second%
+\_width}}\par
+\fi
+
+\M859. We compute the values of \\{easy\_line} and the other local variables
+relating
+to line length when the \\{line\_break} procedure is initializing itself.
+
+\Y\P$\4\X827:Get ready to start line breaking\X\mathrel{+}\S$\6
+\&{if} $\\{par\_shape\_ptr}=\\{null}$ \1\&{then}\6
+\&{if} $\\{hang\_indent}=0$ \1\&{then}\6
+\&{begin} \37$\\{last\_special\_line}\K0$;\5
+$\\{second\_width}\K\\{hsize}$;\5
+$\\{second\_indent}\K0$;\6
+\&{end}\6
+\4\&{else} \X860:Set line length parameters in preparation for hanging
+indentation\X\2\6
+\4\&{else} \&{begin} \37$\\{last\_special\_line}\K\\{info}(\\{par\_shape%
+\_ptr})-1$;\5
+$\\{second\_width}\K\\{mem}[\\{par\_shape\_ptr}+2\ast(\\{last\_special%
+\_line}+1)].\\{sc}$;\5
+$\\{second\_indent}\K\\{mem}[\\{par\_shape\_ptr}+2\ast\\{last\_special%
+\_line}+1].\\{sc}$;\6
+\&{end};\2\6
+\&{if} $\\{looseness}=0$ \1\&{then}\5
+$\\{easy\_line}\K\\{last\_special\_line}$\6
+\4\&{else} $\\{easy\_line}\K\\{max\_halfword}$\2\par
+\fi
+
+\M860. \P$\X860:Set line length parameters in preparation for hanging
+indentation\X\S$\6
+\&{begin} \37$\\{last\_special\_line}\K\\{abs}(\\{hang\_after})$;\6
+\&{if} $\\{hang\_after}<0$ \1\&{then}\6
+\&{begin} \37$\\{first\_width}\K\\{hsize}-\\{abs}(\\{hang\_indent})$;\6
+\&{if} $\\{hang\_indent}\G0$ \1\&{then}\5
+$\\{first\_indent}\K\\{hang\_indent}$\6
+\4\&{else} $\\{first\_indent}\K0$;\2\6
+$\\{second\_width}\K\\{hsize}$;\5
+$\\{second\_indent}\K0$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{first\_width}\K\\{hsize}$;\5
+$\\{first\_indent}\K0$;\5
+$\\{second\_width}\K\\{hsize}-\\{abs}(\\{hang\_indent})$;\6
+\&{if} $\\{hang\_indent}\G0$ \1\&{then}\5
+$\\{second\_indent}\K\\{hang\_indent}$\6
+\4\&{else} $\\{second\_indent}\K0$;\2\6
+\&{end};\2\6
+\&{end}\par
+\U859.\fi
+
+\M861. When we come to the following code, we have just encountered the first
+active node~\|r whose \\{line\_number} field contains \|l. Thus we want to
+compute the length of the $l\mskip1mu$th line of the current paragraph.
+Furthermore,
+we want to set \\{old\_l} to the last number in the class of line numbers
+equivalent to~\|l.
+
+\Y\P$\4\X861:Compute the new line width\X\S$\6
+\&{if} $\|l>\\{easy\_line}$ \1\&{then}\6
+\&{begin} \37$\\{line\_width}\K\\{second\_width}$;\5
+$\\{old\_l}\K\\{max\_halfword}-1$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{old\_l}\K\|l$;\6
+\&{if} $\|l>\\{last\_special\_line}$ \1\&{then}\5
+$\\{line\_width}\K\\{second\_width}$\6
+\4\&{else} \&{if} $\\{par\_shape\_ptr}=\\{null}$ \1\&{then}\5
+$\\{line\_width}\K\\{first\_width}$\6
+\4\&{else} $\\{line\_width}\K\\{mem}[\\{par\_shape\_ptr}+2\ast\|l\,].\\{sc}$;\2%
+\2\6
+\&{end}\2\par
+\U846.\fi
+
+\M862. The remaining part of \\{try\_break} deals with the calculation of
+demerits for a break from \|r to \\{cur\_p}.
+
+The first thing to do is calculate the badness, \|b. This value will always
+be between zero and $\\{inf\_bad}+1$; the latter value occurs only in the
+case of lines from \|r to \\{cur\_p} that cannot shrink enough to fit the
+necessary
+width. In such cases, node \|r will be deactivated.
+We also deactivate node~\|r when a break at~\\{cur\_p} is forced, since future
+breaks must go through a forced break.
+
+\Y\P$\4\X862:Consider the demerits for a line from \|r to \\{cur\_p};
+deactivate node \|r if it should no longer be active; then \&{goto} %
+\\{continue} if a line from \|r to \\{cur\_p} is infeasible, otherwise record a
+new feasible break\X\S$\6
+\&{begin} \37$\\{artificial\_demerits}\K\\{false}$;\6
+$\\{shortfall}\K\\{line\_width}-\\{cur\_active\_width}[1]$;\C{we're this much
+too short}\6
+\&{if} $\\{shortfall}>0$ \1\&{then}\5
+\X863:Set the value of \|b to the badness for stretching the line, and compute
+the corresponding \\{fit\_class}\X\6
+\4\&{else} \X864:Set the value of \|b to the badness for shrinking the line,
+and compute the corresponding \\{fit\_class}\X;\2\6
+\&{if} $(\|b>\\{inf\_bad})\V(\\{pi}=\\{eject\_penalty})$ \1\&{then}\5
+\X865:Prepare to deactivate node~\|r, and \&{goto} \\{deactivate} unless there
+is a reason to consider lines of text from \|r to \\{cur\_p}\X\6
+\4\&{else} \&{begin} \37$\\{prev\_r}\K\|r$;\6
+\&{if} $\|b>\\{threshold}$ \1\&{then}\5
+\&{goto} \37\\{continue};\2\6
+$\\{node\_r\_stays\_active}\K\\{true}$;\6
+\&{end};\2\6
+\X866:Record a new feasible break\X;\6
+\&{if} $\\{node\_r\_stays\_active}$ \1\&{then}\5
+\&{goto} \37\\{continue};\C{\\{prev\_r} has been set to \|r}\2\6
+\4\\{deactivate}: \37\X871:Deactivate node \|r\X;\6
+\&{end}\par
+\U840.\fi
+
+\M863. When a line must stretch, the available stretchability can be found in
+the
+subarray $\\{cur\_active\_width}[2\to5]$, in units of points, fil, fill, and
+filll.
+
+The present section is part of \TeX's inner loop, and it is most often
+performed
+when the badness is infinite; therefore it is worth while to make a quick
+test for large width excess and small stretchability, before calling the
+\\{badness} subroutine.
+
+\Y\P$\4\X863:Set the value of \|b to the badness for stretching the line, and
+compute the corresponding \\{fit\_class}\X\S$\6
+\&{if} $(\\{cur\_active\_width}[3]\I0)\V(\\{cur\_active\_width}[4]\I0)\V\30(%
+\\{cur\_active\_width}[5]\I0)$ \1\&{then}\6
+\&{begin} \37$\|b\K0$;\5
+$\\{fit\_class}\K\\{decent\_fit}$;\C{infinite stretch}\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{shortfall}>7230584$ \1\&{then}\6
+\&{if} $\\{cur\_active\_width}[2]<1663497$ \1\&{then}\6
+\&{begin} \37$\|b\K\\{inf\_bad}$;\5
+$\\{fit\_class}\K\\{very\_loose\_fit}$;\5
+\&{goto} \37\\{done1};\6
+\&{end};\2\2\6
+$\|b\K\\{badness}(\\{shortfall},\39\\{cur\_active\_width}[2])$;\6
+\&{if} $\|b>12$ \1\&{then}\6
+\&{if} $\|b>99$ \1\&{then}\5
+$\\{fit\_class}\K\\{very\_loose\_fit}$\6
+\4\&{else} $\\{fit\_class}\K\\{loose\_fit}$\2\6
+\4\&{else} $\\{fit\_class}\K\\{decent\_fit}$;\2\6
+\4\\{done1}: \37\&{end}\2\par
+\U862.\fi
+
+\M864. Shrinkability is never infinite in a paragraph;
+we can shrink the line from \|r to \\{cur\_p} by at most $\\{cur\_active%
+\_width}[6]$.
+
+\Y\P$\4\X864:Set the value of \|b to the badness for shrinking the line, and
+compute the corresponding \\{fit\_class}\X\S$\6
+\&{begin} \37\&{if} $-\\{shortfall}>\\{cur\_active\_width}[6]$ \1\&{then}\5
+$\|b\K\\{inf\_bad}+1$\6
+\4\&{else} $\|b\K\\{badness}(-\\{shortfall},\39\\{cur\_active\_width}[6])$;\2\6
+\&{if} $\|b>12$ \1\&{then}\5
+$\\{fit\_class}\K\\{tight\_fit}$\ \&{else} $\\{fit\_class}\K\\{decent\_fit}$;\2%
+\6
+\&{end}\par
+\U862.\fi
+
+\M865. During the final pass, we dare not lose all active nodes, lest we lose
+touch with the line breaks already found. The code shown here makes sure
+that such a catastrophe does not happen, by permitting overfull boxes as
+a last resort. This particular part of \TeX\ was a source of several subtle
+bugs before the correct program logic was finally discovered; readers
+who seek to ``improve'' \TeX\ should therefore think thrice before daring
+to make any changes here.
+
+\Y\P$\4\X865:Prepare to deactivate node~\|r, and \&{goto} \\{deactivate} unless
+there is a reason to consider lines of text from \|r to \\{cur\_p}\X\S$\6
+\&{begin} \37\&{if} $\\{final\_pass}\W(\\{minimum\_demerits}=\\{awful\_bad})\W%
+\30(\\{link}(\|r)=\\{last\_active})\W(\\{prev\_r}=\\{active})$ \1\&{then}\5
+$\\{artificial\_demerits}\K\\{true}$\C{set demerits zero, this break is forced}%
+\6
+\4\&{else} \&{if} $\|b>\\{threshold}$ \1\&{then}\5
+\&{goto} \37\\{deactivate};\2\2\6
+$\\{node\_r\_stays\_active}\K\\{false}$;\6
+\&{end}\par
+\U862.\fi
+
+\M866. When we get to this part of the code, the line from \|r to \\{cur\_p} is
+feasible, its badness is~\|b, and its fitness classification is \\{fit\_class}.
+We don't want to make an active node for this break yet, but we will
+compute the total demerits and record them in the \\{minimal\_demerits} array,
+if such a break is the current champion among all ways to get to \\{cur\_p}
+in a given line-number class and fitness class.
+
+\Y\P$\4\X866:Record a new feasible break\X\S$\6
+\&{if} $\\{artificial\_demerits}$ \1\&{then}\5
+$\|d\K0$\6
+\4\&{else} \X870:Compute the demerits, \|d, from \|r to \\{cur\_p}\X;\2\6
+\&{stat} \37\&{if} $\\{tracing\_paragraphs}>0$ \1\&{then}\5
+\X867:Print a symbolic description of this feasible break\X;\2\6
+\&{tats}\6
+$\|d\K\|d+\\{total\_demerits}(\|r)$;\C{this is the minimum total demerits
+from the beginning to \\{cur\_p} via \|r}\6
+\&{if} $\|d\L\\{minimal\_demerits}[\\{fit\_class}]$ \1\&{then}\6
+\&{begin} \37$\\{minimal\_demerits}[\\{fit\_class}]\K\|d$;\5
+$\\{best\_place}[\\{fit\_class}]\K\\{break\_node}(\|r)$;\5
+$\\{best\_pl\_line}[\\{fit\_class}]\K\|l$;\6
+\&{if} $\|d<\\{minimum\_demerits}$ \1\&{then}\5
+$\\{minimum\_demerits}\K\|d$;\2\6
+\&{end}\2\par
+\U862.\fi
+
+\M867. \P$\X867:Print a symbolic description of this feasible break\X\S$\6
+\&{begin} \37\&{if} $\\{printed\_node}\I\\{cur\_p}$ \1\&{then}\5
+\X868:Print the list between \\{printed\_node} and \\{cur\_p}, then set $%
+\\{printed\_node}\K\\{cur\_p}$\X;\2\6
+$\\{print\_nl}(\.{"@"})$;\6
+\&{if} $\\{cur\_p}=\\{null}$ \1\&{then}\5
+$\\{print\_esc}(\.{"par"})$\6
+\4\&{else} \&{if} $(\\{type}(\\{cur\_p})\I\\{glue\_node})\W(\R\\{is\_char%
+\_node}(\\{cur\_p}))$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{type}(\\{cur\_p})=\\{penalty\_node}$ \1\&{then}\5
+$\\{print\_esc}(\.{"penalty"})$\6
+\4\&{else} \&{if} $\\{type}(\\{cur\_p})=\\{disc\_node}$ \1\&{then}\5
+$\\{print\_esc}(\.{"discretionary"})$\6
+\4\&{else} \&{if} $\\{type}(\\{cur\_p})=\\{kern\_node}$ \1\&{then}\5
+$\\{print\_esc}(\.{"kern"})$\6
+\4\&{else} $\\{print\_esc}(\.{"math"})$;\2\2\2\6
+\&{end};\2\2\6
+$\\{print}(\.{"\ via\ @@"})$;\6
+\&{if} $\\{break\_node}(\|r)=\\{null}$ \1\&{then}\5
+$\\{print\_char}(\.{"0"})$\6
+\4\&{else} $\\{print\_int}(\\{serial}(\\{break\_node}(\|r)))$;\2\6
+$\\{print}(\.{"\ b="})$;\6
+\&{if} $\|b>\\{inf\_bad}$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\ \&{else} $\\{print\_int}(\|b)$;\2\6
+$\\{print}(\.{"\ p="})$;\5
+$\\{print\_int}(\\{pi})$;\5
+$\\{print}(\.{"\ d="})$;\6
+\&{if} $\\{artificial\_demerits}$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\ \&{else} $\\{print\_int}(\|d)$;\2\6
+\&{end}\par
+\U866.\fi
+
+\M868. \P$\X868:Print the list between \\{printed\_node} and \\{cur\_p}, then
+set $\\{printed\_node}\K\\{cur\_p}$\X\S$\6
+\&{begin} \37$\\{print\_nl}(\.{""})$;\6
+\&{if} $\\{cur\_p}=\\{null}$ \1\&{then}\5
+$\\{short\_display}(\\{link}(\\{printed\_node}))$\6
+\4\&{else} \&{begin} \37$\\{save\_link}\K\\{link}(\\{cur\_p})$;\5
+$\\{link}(\\{cur\_p})\K\\{null}$;\5
+$\\{print\_nl}(\.{""})$;\5
+$\\{short\_display}(\\{link}(\\{printed\_node}))$;\5
+$\\{link}(\\{cur\_p})\K\\{save\_link}$;\6
+\&{end};\2\6
+$\\{printed\_node}\K\\{cur\_p}$;\6
+\&{end}\par
+\U867.\fi
+
+\M869. When the data for a discretionary break is being displayed, we will have
+printed the \\{pre\_break} and \\{post\_break} lists; we want to skip over the
+third list, so that the discretionary data will not appear twice.  The
+following code is performed at the very end of \\{try\_break}.
+
+\Y\P$\4\X869:Update the value of \\{printed\_node} for symbolic displays\X\S$\6
+\&{if} $\\{cur\_p}=\\{printed\_node}$ \1\&{then}\6
+\&{if} $\\{cur\_p}\I\\{null}$ \1\&{then}\6
+\&{if} $\\{type}(\\{cur\_p})=\\{disc\_node}$ \1\&{then}\6
+\&{begin} \37$\|t\K\\{replace\_count}(\\{cur\_p})$;\6
+\&{while} $\|t>0$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\|t)$;\5
+$\\{printed\_node}\K\\{link}(\\{printed\_node})$;\6
+\&{end};\2\6
+\&{end}\2\2\2\par
+\U840.\fi
+
+\M870. \P$\X870:Compute the demerits, \|d, from \|r to \\{cur\_p}\X\S$\6
+\&{begin} \37$\|d\K\\{line\_penalty}+\|b$;\6
+\&{if} $\\{abs}(\|d)\G10000$ \1\&{then}\5
+$\|d\K100000000$\ \&{else} $\|d\K\|d\ast\|d$;\2\6
+\&{if} $\\{pi}\I0$ \1\&{then}\6
+\&{if} $\\{pi}>0$ \1\&{then}\5
+$\|d\K\|d+\\{pi}\ast\\{pi}$\6
+\4\&{else} \&{if} $\\{pi}>\\{eject\_penalty}$ \1\&{then}\5
+$\|d\K\|d-\\{pi}\ast\\{pi}$;\2\2\2\6
+\&{if} $(\\{break\_type}=\\{hyphenated})\W(\\{type}(\|r)=\\{hyphenated})$ \1%
+\&{then}\6
+\&{if} $\\{cur\_p}\I\\{null}$ \1\&{then}\5
+$\|d\K\|d+\\{double\_hyphen\_demerits}$\6
+\4\&{else} $\|d\K\|d+\\{final\_hyphen\_demerits}$;\2\2\6
+\&{if} $\\{abs}(\\{intcast}(\\{fit\_class})-\\{intcast}(\\{fitness}(\|r)))>1$ %
+\1\&{then}\5
+$\|d\K\|d+\\{adj\_demerits}$;\2\6
+\&{end}\par
+\U866.\fi
+
+\M871. When an active node disappears, we must delete an adjacent delta node if
+the
+active node was at the beginning or the end of the active list, or if it
+was surrounded by delta nodes. We also must preserve the property that
+\\{cur\_active\_width} represents the length of material from $\\{link}(\\{prev%
+\_r})$
+to~\\{cur\_p}.
+
+\Y\P\D \37$\\{combine\_two\_deltas}(\#)\S\30\\{mem}[\\{prev\_r}+\#].\\{sc}\K%
+\\{mem}[\\{prev\_r}+\#].\\{sc}+\\{mem}[\|r+\#].\\{sc}$\par
+\P\D \37$\\{downdate\_width}(\#)\S\30\\{cur\_active\_width}[\#]\K\\{cur\_active%
+\_width}[\#]-\\{mem}[\\{prev\_r}+\#].\\{sc}$\par
+\Y\P$\4\X871:Deactivate node \|r\X\S$\6
+$\\{link}(\\{prev\_r})\K\\{link}(\|r)$;\5
+$\\{free\_node}(\|r,\39\\{active\_node\_size})$;\6
+\&{if} $\\{prev\_r}=\\{active}$ \1\&{then}\5
+\X872:Update the active widths, since the first active node has been deleted\X\6
+\4\&{else} \&{if} $\\{type}(\\{prev\_r})=\\{delta\_node}$ \1\&{then}\6
+\&{begin} \37$\|r\K\\{link}(\\{prev\_r})$;\6
+\&{if} $\|r=\\{last\_active}$ \1\&{then}\6
+\&{begin} \37$\\{do\_all\_six}(\\{downdate\_width})$;\5
+$\\{link}(\\{prev\_prev\_r})\K\\{last\_active}$;\5
+$\\{free\_node}(\\{prev\_r},\39\\{delta\_node\_size})$;\5
+$\\{prev\_r}\K\\{prev\_prev\_r}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{type}(\|r)=\\{delta\_node}$ \1\&{then}\6
+\&{begin} \37$\\{do\_all\_six}(\\{update\_width})$;\5
+$\\{do\_all\_six}(\\{combine\_two\_deltas})$;\5
+$\\{link}(\\{prev\_r})\K\\{link}(\|r)$;\5
+$\\{free\_node}(\|r,\39\\{delta\_node\_size})$;\6
+\&{end};\2\2\6
+\&{end}\2\2\par
+\U862.\fi
+
+\M872. The following code uses the fact that $\\{type}(\\{last\_active})\I%
+\\{delta\_node}$. If the
+active list has just become empty, we do not need to update the
+\\{active\_width} array, since it will be initialized when an active
+node is next inserted.
+
+\Y\P\D \37$\\{update\_active}(\#)\S\\{active\_width}[\#]\K\\{active\_width}[%
+\#]+\\{mem}[\|r+\#].\\{sc}$\par
+\Y\P$\4\X872:Update the active widths, since the first active node has been
+deleted\X\S$\6
+\&{begin} \37$\|r\K\\{link}(\\{active})$;\6
+\&{if} $\\{type}(\|r)=\\{delta\_node}$ \1\&{then}\6
+\&{begin} \37$\\{do\_all\_six}(\\{update\_active})$;\5
+$\\{do\_all\_six}(\\{copy\_to\_cur\_active})$;\5
+$\\{link}(\\{active})\K\\{link}(\|r)$;\5
+$\\{free\_node}(\|r,\39\\{delta\_node\_size})$;\6
+\&{end};\2\6
+\&{end}\par
+\U871.\fi
+
+\N873.  \[39] Breaking paragraphs into lines, continued.
+So far we have gotten a little way into the \\{line\_break} routine, having
+covered its important \\{try\_break} subroutine. Now let's consider the
+rest of the process.
+
+The main loop of \\{line\_break} traverses the given hlist,
+starting at $\\{link}(\\{temp\_head})$, and calls \\{try\_break} at each legal
+breakpoint. A variable called \\{auto\_breaking} is set to true except
+within math formulas, since glue nodes are not legal breakpoints when
+they appear in formulas.
+
+The current node of interest in the hlist is pointed to by \\{cur\_p}. Another
+variable, \\{prev\_p}, is usually one step behind \\{cur\_p}, but the real
+meaning of \\{prev\_p} is this: If $\\{type}(\\{cur\_p})=\\{glue\_node}$ then %
+\\{cur\_p} is a legal
+breakpoint if and only if \\{auto\_breaking} is true and \\{prev\_p} does not
+point to a glue node, penalty node, explicit kern node, or math node.
+
+The following declarations provide for a few other local variables that are
+used in special calculations.
+
+\Y\P$\4\X873:Local variables for line breaking\X\S$\6
+\4\\{auto\_breaking}: \37\\{boolean};\C{is node \\{cur\_p} outside a formula?}\6
+\4\\{prev\_p}: \37\\{pointer};\C{helps to determine when glue nodes are
+breakpoints}\6
+\4$\|q,\39\|r,\39\|s,\39\\{prev\_s}$: \37\\{pointer};\C{miscellaneous nodes of
+temporary interest}\6
+\4$\|f,\39\\{post\_f}$: \37\\{internal\_font\_number};\C{used when calculating
+character widths}\6
+\4\\{post\_p}: \37\\{pointer};\6
+\4\\{cc}: \37\\{ASCII\_code};\6
+\4\\{first\_use}: \37\\{boolean};\par
+\A904.
+\U826.\fi
+
+\M874. The `\ignorespaces \~ \&{loop}\unskip' in the following code is
+performed at most
+thrice per call of \\{line\_break}, since it is actually a pass over the
+entire paragraph.
+
+\Y\P$\4\X874:Find optimal breakpoints\X\S$\6
+$\\{threshold}\K\\{pretolerance}$;\6
+\&{if} $\\{threshold}\G0$ \1\&{then}\6
+\&{begin} \37\&{stat} \37\&{if} $\\{tracing\_paragraphs}>0$ \1\&{then}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"@firstpass"})$;\ \&{end};\2\ \&{tats}\6
+$\\{second\_pass}\K\\{false}$;\5
+$\\{final\_pass}\K\\{false}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{threshold}\K\\{tolerance}$;\5
+$\\{second\_pass}\K\\{true}$;\5
+$\\{final\_pass}\K(\\{emergency\_stretch}\L0)$;\6
+\&{stat} \37\&{if} $\\{tracing\_paragraphs}>0$ \1\&{then}\5
+\\{begin\_diagnostic};\ \2\6
+\&{tats}\6
+\&{end};\2\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{threshold}>\\{inf\_bad}$ \1\&{then}\5
+$\\{threshold}\K\\{inf\_bad}$;\2\6
+\&{if} $\\{second\_pass}$ \1\&{then}\5
+\X902:Initialize for hyphenating a paragraph\X;\2\6
+\X875:Create an active breakpoint representing the beginning of the paragraph%
+\X;\6
+$\\{cur\_p}\K\\{link}(\\{temp\_head})$;\5
+$\\{auto\_breaking}\K\\{true}$;\6
+$\\{prev\_p}\K\\{cur\_p}$;\C{glue at beginning is not a legal breakpoint}\6
+\&{while} $(\\{cur\_p}\I\\{null})\W(\\{link}(\\{active})\I\\{last\_active})$ \1%
+\&{do}\5
+\X877:Call \\{try\_break} if \\{cur\_p} is a legal breakpoint; on the second
+pass, also try to hyphenate the next word, if \\{cur\_p} is a glue node; then
+advance \\{cur\_p} to the next node of the paragraph that could possibly be a
+legal breakpoint\X;\2\6
+\&{if} $\\{cur\_p}=\\{null}$ \1\&{then}\5
+\X884:Try the final line break at the end of the paragraph, and \&{goto} %
+\\{done} if the desired breakpoints have been found\X;\2\6
+\X876:Clean up the memory by removing the break nodes\X;\6
+\&{if} $\R\\{second\_pass}$ \1\&{then}\6
+\&{begin} \37\&{stat} \37\&{if} $\\{tracing\_paragraphs}>0$ \1\&{then}\5
+$\\{print\_nl}(\.{"@secondpass"})$;\2\ \&{tats}\6
+$\\{threshold}\K\\{tolerance}$;\5
+$\\{second\_pass}\K\\{true}$;\5
+$\\{final\_pass}\K(\\{emergency\_stretch}\L0)$;\6
+\&{end}\C{if at first you don't succeed, \dots}\6
+\4\&{else} \&{begin} \37\&{stat} \37\&{if} $\\{tracing\_paragraphs}>0$ \1%
+\&{then}\5
+$\\{print\_nl}(\.{"@emergencypass"})$;\2\ \&{tats}\6
+$\\{background}[2]\K\\{background}[2]+\\{emergency\_stretch}$;\5
+$\\{final\_pass}\K\\{true}$;\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{done}: \37\&{stat} \37\&{if} $\\{tracing\_paragraphs}>0$ \1\&{then}\6
+\&{begin} \37$\\{end\_diagnostic}(\\{true})$;\5
+\\{normalize\_selector};\6
+\&{end};\ \2\6
+\&{tats}\par
+\U826.\fi
+
+\M875. The active node that represents the starting point does not need a
+corresponding passive node.
+
+\Y\P\D \37$\\{store\_background}(\#)\S\\{active\_width}[\#]\K\\{background}[%
+\#]$\par
+\Y\P$\4\X875:Create an active breakpoint representing the beginning of the
+paragraph\X\S$\6
+$\|q\K\\{get\_node}(\\{active\_node\_size})$;\5
+$\\{type}(\|q)\K\\{unhyphenated}$;\5
+$\\{fitness}(\|q)\K\\{decent\_fit}$;\5
+$\\{link}(\|q)\K\\{last\_active}$;\5
+$\\{break\_node}(\|q)\K\\{null}$;\5
+$\\{line\_number}(\|q)\K\\{prev\_graf}+1$;\5
+$\\{total\_demerits}(\|q)\K0$;\5
+$\\{link}(\\{active})\K\|q$;\5
+$\\{do\_all\_six}(\\{store\_background})$;\6
+$\\{passive}\K\\{null}$;\5
+$\\{printed\_node}\K\\{temp\_head}$;\5
+$\\{pass\_number}\K0$;\5
+$\\{font\_in\_short\_display}\K\\{null\_font}$\par
+\U874.\fi
+
+\M876. \P$\X876:Clean up the memory by removing the break nodes\X\S$\6
+$\|q\K\\{link}(\\{active})$;\6
+\&{while} $\|q\I\\{last\_active}$ \1\&{do}\6
+\&{begin} \37$\\{cur\_p}\K\\{link}(\|q)$;\6
+\&{if} $\\{type}(\|q)=\\{delta\_node}$ \1\&{then}\5
+$\\{free\_node}(\|q,\39\\{delta\_node\_size})$\6
+\4\&{else} $\\{free\_node}(\|q,\39\\{active\_node\_size})$;\2\6
+$\|q\K\\{cur\_p}$;\6
+\&{end};\2\6
+$\|q\K\\{passive}$;\6
+\&{while} $\|q\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\\{cur\_p}\K\\{link}(\|q)$;\5
+$\\{free\_node}(\|q,\39\\{passive\_node\_size})$;\5
+$\|q\K\\{cur\_p}$;\6
+\&{end}\2\par
+\Us826\ET874.\fi
+
+\M877. Here is the main switch in the \\{line\_break} routine, where legal
+breaks
+are determined. As we move through the hlist, we need to keep the \\{active%
+\_width}
+array up to date, so that the badness of individual lines is readily calculated
+by \\{try\_break}. It is convenient to use the short name \\{act\_width} for
+the component of active width that represents real width as opposed to glue.
+
+\Y\P\D \37$\\{act\_width}\S\\{active\_width}[1]$\C{length from first active
+node to current node}\par
+\P\D \37$\\{kern\_break}\S$\1\6
+\&{begin} \37\&{if} $\R\\{is\_char\_node}(\\{link}(\\{cur\_p}))\W\\{auto%
+\_breaking}$ \1\&{then}\6
+\&{if} $\\{type}(\\{link}(\\{cur\_p}))=\\{glue\_node}$ \1\&{then}\5
+$\\{try\_break}(0,\39\\{unhyphenated})$;\2\2\6
+$\\{act\_width}\K\\{act\_width}+\\{width}(\\{cur\_p})$;\6
+\&{end}\2\par
+\Y\P$\4\X877:Call \\{try\_break} if \\{cur\_p} is a legal breakpoint; on the
+second pass, also try to hyphenate the next word, if \\{cur\_p} is a glue node;
+then advance \\{cur\_p} to the next node of the paragraph that could possibly
+be a legal breakpoint\X\S$\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\\{cur\_p})$ \1\&{then}\5
+\X878:Advance \(c)\\{cur\_p} to the node following the present string of
+characters\X;\2\6
+\&{case} $\\{type}(\\{cur\_p})$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node}$: \37$%
+\\{act\_width}\K\\{act\_width}+\\{width}(\\{cur\_p})$;\6
+\4\\{whatsit\_node}: \37\X1375:Advance \(p)past a whatsit node in the \(l)%
+\\{line\_break} loop\X;\6
+\4\\{glue\_node}: \37\&{begin} \37\X879:If node \\{cur\_p} is a legal
+breakpoint, call \\{try\_break}; then update the active widths by including the
+glue in $\\{glue\_ptr}(\\{cur\_p})$\X;\6
+\&{if} $\\{second\_pass}\W\\{auto\_breaking}$ \1\&{then}\5
+\X905:Try to hyphenate the following word\X;\2\6
+\&{end};\6
+\4\\{kern\_node}: \37\&{if} $(\\{subtype}(\\{cur\_p})=\\{explicit})\V(%
+\\{subtype}(\\{cur\_p})=\\{ita\_kern})$ \1\&{then}\5
+\\{kern\_break}\6
+\4\&{else} $\\{act\_width}\K\\{act\_width}+\\{width}(\\{cur\_p})$;\2\6
+\4\\{ligature\_node}: \37\&{begin} \37$\|f\K\\{font}(\\{lig\_char}(\\{cur%
+\_p}))$;\5
+$\\{act\_width}\K\\{act\_width}+\\{char\_width}(\|f)(\\{char\_info}(\|f)(%
+\\{character}(\\{lig\_char}(\\{cur\_p}))))$;\6
+\&{end};\6
+\4\\{disc\_node}: \37\X880:Try to break after a discretionary fragment, then %
+\&{goto} \\{done5}\X;\6
+\4\\{math\_node}: \37\&{begin} \37$\\{auto\_breaking}\K(\\{subtype}(\\{cur%
+\_p})=\\{after})$;\5
+\\{kern\_break};\6
+\&{end};\6
+\4\\{penalty\_node}: \37$\\{try\_break}(\\{penalty}(\\{cur\_p}),\39%
+\\{unhyphenated})$;\6
+\4$\\{disp\_node},\39\\{mark\_node},\39\\{ins\_node},\39\\{adjust\_node}$: \37%
+\\{do\_nothing};\6
+\4\&{othercases} \37$\\{confusion}(\.{"paragraph"})$\2\6
+\&{endcases};\6
+$\\{prev\_p}\K\\{cur\_p}$;\5
+$\\{cur\_p}\K\\{link}(\\{cur\_p})$;\6
+\4\\{done5}: \37\&{end}\par
+\U874.\fi
+
+\M878. The code that passes over the characters of words in a paragraph is
+part of \TeX's inner loop, so it has been streamlined for speed. We use
+the fact that `\.{\\parfillskip}' glue appears at the end of each paragraph;
+it is therefore unnecessary to check if $\\{link}(\\{cur\_p})=\\{null}$ when %
+\\{cur\_p} is a
+character node.
+
+\Y\P$\4\X878:Advance \(c)\\{cur\_p} to the node following the present string of
+characters\X\S$\6
+\&{begin} \37$\\{chain}\K\\{false}$;\6
+\&{if} $\\{is\_char\_node}(\\{cur\_p})$ \1\&{then}\6
+\&{if} $\\{font\_dir}[\\{font}(\\{cur\_p})]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37\&{case} $\\{type}(\\{prev\_p})$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node},\39%
+\\{ligature\_node},\39\\{disc\_node},\39\\{math\_node}$: \37\&{begin} \37$%
+\\{cur\_p}\K\\{prev\_p}$;\5
+$\\{try\_break}(0,\39\\{unhyphenated})$;\5
+$\\{cur\_p}\K\\{link}(\\{cur\_p})$;\6
+\&{end};\6
+\4\&{othercases} \37\\{do\_nothing};\2\6
+\&{endcases};\6
+\&{end};\2\2\6
+$\\{prev\_p}\K\\{cur\_p}$;\5
+$\\{post\_p}\K\\{cur\_p}$;\5
+$\\{post\_f}\K\\{font}(\\{post\_p})$;\6
+\1\&{repeat} \37$\|f\K\\{post\_f}$;\5
+$\\{cc}\K\\{character}(\\{cur\_p})$;\5
+$\\{act\_width}\K\\{act\_width}+\\{char\_width}(\|f)(\\{orig\_char\_info}(\|f)(%
+\\{cc}))$;\5
+$\\{post\_p}\K\\{link}(\\{cur\_p})$;\6
+\&{if} $\\{font\_dir}[\|f]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\\{prev\_p}\K\\{cur\_p}$;\5
+$\\{cur\_p}\K\\{post\_p}$;\5
+$\\{post\_p}\K\\{link}(\\{post\_p})$;\6
+\&{if} $\\{is\_char\_node}(\\{post\_p})$ \1\&{then}\6
+\&{begin} \37$\\{post\_f}\K\\{font}(\\{post\_p})$;\6
+\&{if} $\\{font\_dir}[\\{post\_f}]\I\\{dir\_default}$ \1\&{then}\5
+$\\{chain}\K\\{true}$\6
+\4\&{else} $\\{chain}\K\\{false}$;\2\6
+$\\{try\_break}(0,\39\\{unhyphenated})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{chain}\K\\{false}$;\6
+\&{case} $\\{type}(\\{post\_p})$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node},\39%
+\\{ligature\_node},\39\\{disc\_node},\39\\{math\_node}$: \37$\\{try\_break}(0,%
+\39\\{unhyphenated})$;\6
+\4\&{othercases} \37\\{do\_nothing};\2\6
+\&{endcases};\6
+\&{end};\2\6
+\&{if} $\\{chain}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{first\_use}$ \1\&{then}\6
+\&{begin} \37$\\{check\_shrinkage}(\\{cur\_kanji\_skip})$;\5
+$\\{first\_use}\K\\{false}$;\6
+\&{end};\2\6
+$\\{act\_width}\K\\{act\_width}+\\{width}(\\{cur\_kanji\_skip})$;\5
+$\30\\{active\_width}[2+\\{stretch\_order}(\\{cur\_kanji\_skip})]\K\30\\{active%
+\_width}[2+\\{stretch\_order}(\\{cur\_kanji\_skip})]+\\{stretch}(\\{cur\_kanji%
+\_skip})$;\6
+$\\{active\_width}[6]\K\\{active\_width}[6]+\\{shrink}(\\{cur\_kanji\_skip})$;\6
+\&{end};\2\6
+$\\{prev\_p}\K\\{cur\_p}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{is\_char\_node}(\\{post\_p})$ \1\&{then}\6
+\&{begin} \37$\\{post\_f}\K\\{font}(\\{post\_p})$;\5
+$\\{chain}\K\\{false}$;\6
+\&{if} $\\{font\_dir}[\\{post\_f}]\I\\{dir\_default}$ \1\&{then}\5
+$\\{try\_break}(0,\39\\{unhyphenated})$;\2\6
+\&{end};\2\2\6
+$\\{cur\_p}\K\\{post\_p}$;\6
+\4\&{until}\5
+$\R\\{is\_char\_node}(\\{cur\_p})$;\2\6
+$\\{chain}\K\\{false}$;\6
+\&{end}\par
+\U877.\fi
+
+\M879. When node \\{cur\_p} is a glue node, we look at \\{prev\_p} to see
+whether or not
+a breakpoint is legal at \\{cur\_p}, as explained above.
+
+\Y\P$\4\X879:If node \\{cur\_p} is a legal breakpoint, call \\{try\_break};
+then update the active widths by including the glue in $\\{glue\_ptr}(\\{cur%
+\_p})$\X\S$\6
+\&{if} $\\{auto\_breaking}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\\{prev\_p})$ \1\&{then}\5
+$\\{try\_break}(0,\39\\{unhyphenated})$\6
+\4\&{else} \&{if} $\\{precedes\_break}(\\{prev\_p})$ \1\&{then}\5
+$\\{try\_break}(0,\39\\{unhyphenated})$\6
+\4\&{else} \&{if} $\\{type}(\\{prev\_p})=\\{kern\_node}$ \1\&{then}\6
+\&{if} $(\\{subtype}(\\{prev\_p})\I\\{explicit})\W(\\{subtype}(\\{prev\_p})\I%
+\\{ita\_kern})$ \1\&{then}\5
+$\\{try\_break}(0,\39\\{unhyphenated})$;\2\2\2\2\6
+\&{end};\2\6
+$\\{check\_shrinkage}(\\{glue\_ptr}(\\{cur\_p}))$;\5
+$\|q\K\\{glue\_ptr}(\\{cur\_p})$;\5
+$\\{act\_width}\K\\{act\_width}+\\{width}(\|q)$;\5
+$\30\\{active\_width}[2+\\{stretch\_order}(\|q)]\K\30\\{active\_width}[2+%
+\\{stretch\_order}(\|q)]+\\{stretch}(\|q)$;\6
+$\\{active\_width}[6]\K\\{active\_width}[6]+\\{shrink}(\|q)$\par
+\U877.\fi
+
+\M880. The following code knows that discretionary texts contain
+only character nodes, kern nodes, box nodes, rule nodes, and ligature nodes.
+
+\Y\P$\4\X880:Try to break after a discretionary fragment, then \&{goto} %
+\\{done5}\X\S$\6
+\&{begin} \37$\|s\K\\{pre\_break}(\\{cur\_p})$;\5
+$\\{disc\_width}\K0$;\6
+\&{if} $\|s=\\{null}$ \1\&{then}\5
+$\\{try\_break}(\\{ex\_hyphen\_penalty},\39\\{hyphenated})$\6
+\4\&{else} \&{begin} \37\1\&{repeat} \37\X881:Add the width of node \|s to %
+\\{disc\_width}\X;\6
+$\|s\K\\{link}(\|s)$;\6
+\4\&{until}\5
+$\|s=\\{null}$;\2\6
+$\\{act\_width}\K\\{act\_width}+\\{disc\_width}$;\5
+$\\{try\_break}(\\{hyphen\_penalty},\39\\{hyphenated})$;\5
+$\\{act\_width}\K\\{act\_width}-\\{disc\_width}$;\6
+\&{end};\2\6
+$\|r\K\\{replace\_count}(\\{cur\_p})$;\5
+$\|s\K\\{link}(\\{cur\_p})$;\6
+\&{while} $\|r>0$ \1\&{do}\6
+\&{begin} \37\X882:Add the width of node \|s to \\{act\_width}\X;\6
+$\\{decr}(\|r)$;\5
+$\|s\K\\{link}(\|s)$;\6
+\&{end};\2\6
+$\\{prev\_p}\K\\{cur\_p}$;\5
+$\\{cur\_p}\K\|s$;\5
+\&{goto} \37\\{done5};\6
+\&{end}\par
+\U877.\fi
+
+\M881. \P$\X881:Add the width of node \|s to \\{disc\_width}\X\S$\6
+\&{if} $\\{is\_char\_node}(\|s)$ \1\&{then}\6
+\&{begin} \37$\|f\K\\{font}(\|s)$;\5
+$\\{disc\_width}\K\\{disc\_width}+\\{char\_width}(\|f)(\\{orig\_char\_info}(%
+\|f)(\\{character}(\|s)))$;\6
+\&{if} $\\{font\_dir}[\|f]\I\\{dir\_default}$ \1\&{then}\5
+$\|s\K\\{link}(\|s)$\2\6
+\&{end}\6
+\4\&{else} \&{case} $\\{type}(\|s)$ \1\&{of}\6
+\4\\{ligature\_node}: \37\&{begin} \37$\|f\K\\{font}(\\{lig\_char}(\|s))$;\5
+$\\{disc\_width}\K\\{disc\_width}+\\{char\_width}(\|f)(\\{orig\_char\_info}(%
+\|f)(\\{character}(\\{lig\_char}(\|s))))$;\6
+\&{end};\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node},\39%
+\\{kern\_node}$: \37$\\{disc\_width}\K\\{disc\_width}+\\{width}(\|s)$;\6
+\4\\{disp\_node}: \37\\{do\_nothing};\6
+\4\&{othercases} \37$\\{confusion}(\.{"disc3"})$\2\6
+\&{endcases}\2\par
+\U880.\fi
+
+\M882. \P$\X882:Add the width of node \|s to \\{act\_width}\X\S$\6
+\&{if} $\\{is\_char\_node}(\|s)$ \1\&{then}\6
+\&{begin} \37$\|f\K\\{font}(\|s)$;\5
+$\\{act\_width}\K\\{act\_width}+\\{char\_width}(\|f)(\\{orig\_char\_info}(\|f)(%
+\\{character}(\|s)))$;\6
+\&{if} $\\{font\_dir}[\|f]\I\\{dir\_default}$ \1\&{then}\5
+$\|s\K\\{link}(\|s)$\2\6
+\&{end}\6
+\4\&{else} \&{case} $\\{type}(\|s)$ \1\&{of}\6
+\4\\{ligature\_node}: \37\&{begin} \37$\|f\K\\{font}(\\{lig\_char}(\|s))$;\5
+$\\{act\_width}\K\\{act\_width}+\\{char\_width}(\|f)(\\{orig\_char\_info}(\|f)(%
+\\{character}(\\{lig\_char}(\|s))))$;\6
+\&{end};\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node},\39%
+\\{kern\_node}$: \37$\\{act\_width}\K\\{act\_width}+\\{width}(\|s)$;\6
+\4\\{disp\_node}: \37\\{do\_nothing};\6
+\4\&{othercases} \37$\\{confusion}(\.{"disc4"})$\2\6
+\&{endcases}\2\par
+\U880.\fi
+
+\M883. The forced line break at the paragraph's end will reduce the list of
+breakpoints so that all active nodes represent breaks at $\\{cur\_p}=\\{null}$.
+On the first pass, we insist on finding an active node that has the
+correct ``looseness.'' On the final pass, there will be at least one active
+node, and we will match the desired looseness as well as we can.
+
+The global variable \\{best\_bet} will be set to the active node for the best
+way to break the paragraph, and a few other variables are used to
+help determine what is best.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{best\_bet}: \37\\{pointer};\C{use this passive node and its predecessors}\6
+\4\\{fewest\_demerits}: \37\\{integer};\C{the demerits associated with \\{best%
+\_bet}}\6
+\4\\{best\_line}: \37\\{halfword};\C{line number following the last line of the
+new paragraph}\6
+\4\\{actual\_looseness}: \37\\{integer};\C{the difference between $\\{line%
+\_number}(\\{best\_bet})$   and the optimum \\{best\_line}}\6
+\4\\{line\_diff}: \37\\{integer};\C{the difference between the current line
+number and   the optimum \\{best\_line}}\par
+\fi
+
+\M884. \P$\X884:Try the final line break at the end of the paragraph, and %
+\&{goto} \\{done} if the desired breakpoints have been found\X\S$\6
+\&{begin} \37$\\{try\_break}(\\{eject\_penalty},\39\\{hyphenated})$;\6
+\&{if} $\\{link}(\\{active})\I\\{last\_active}$ \1\&{then}\6
+\&{begin} \37\X885:Find an active node with fewest demerits\X;\6
+\&{if} $\\{looseness}=0$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+\X886:Find the best active node for the desired looseness\X;\6
+\&{if} $(\\{actual\_looseness}=\\{looseness})\V\\{final\_pass}$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+\&{end};\2\6
+\&{end}\par
+\U874.\fi
+
+\M885. \P$\X885:Find an active node with fewest demerits\X\S$\6
+$\|r\K\\{link}(\\{active})$;\5
+$\\{fewest\_demerits}\K\\{awful\_bad}$;\6
+\1\&{repeat} \37\&{if} $\\{type}(\|r)\I\\{delta\_node}$ \1\&{then}\6
+\&{if} $\\{total\_demerits}(\|r)<\\{fewest\_demerits}$ \1\&{then}\6
+\&{begin} \37$\\{fewest\_demerits}\K\\{total\_demerits}(\|r)$;\5
+$\\{best\_bet}\K\|r$;\6
+\&{end};\2\2\6
+$\|r\K\\{link}(\|r)$;\6
+\4\&{until}\5
+$\|r=\\{last\_active}$;\2\6
+$\\{best\_line}\K\\{line\_number}(\\{best\_bet})$\par
+\U884.\fi
+
+\M886. The adjustment for a desired looseness is a slightly more complicated
+version of the loop just considered. Note that if a paragraph is broken
+into segments by displayed equations, each segment will be subject to the
+looseness calculation, independently of the other segments.
+
+\Y\P$\4\X886:Find the best active node for the desired looseness\X\S$\6
+\&{begin} \37$\|r\K\\{link}(\\{active})$;\5
+$\\{actual\_looseness}\K0$;\6
+\1\&{repeat} \37\&{if} $\\{type}(\|r)\I\\{delta\_node}$ \1\&{then}\6
+\&{begin} \37$\\{line\_diff}\K\\{intcast}(\\{line\_number}(\|r))-\\{intcast}(%
+\\{best\_line})$;\6
+\&{if} $((\\{line\_diff}<\\{actual\_looseness})\W(\\{looseness}\L\\{line%
+\_diff}))\V\30((\\{line\_diff}>\\{actual\_looseness})\W(\\{looseness}\G\\{line%
+\_diff}))$ \1\&{then}\6
+\&{begin} \37$\\{best\_bet}\K\|r$;\5
+$\\{actual\_looseness}\K\\{line\_diff}$;\5
+$\\{fewest\_demerits}\K\\{total\_demerits}(\|r)$;\6
+\&{end}\6
+\4\&{else} \&{if} $(\\{line\_diff}=\\{actual\_looseness})\W\30(\\{total%
+\_demerits}(\|r)<\\{fewest\_demerits})$ \1\&{then}\6
+\&{begin} \37$\\{best\_bet}\K\|r$;\5
+$\\{fewest\_demerits}\K\\{total\_demerits}(\|r)$;\6
+\&{end};\2\2\6
+\&{end};\2\6
+$\|r\K\\{link}(\|r)$;\6
+\4\&{until}\5
+$\|r=\\{last\_active}$;\2\6
+$\\{best\_line}\K\\{line\_number}(\\{best\_bet})$;\6
+\&{end}\par
+\U884.\fi
+
+\M887. Once the best sequence of breakpoints has been found (hurray), we call
+on the
+procedure \\{post\_line\_break} to finish the remainder of the work.
+(By introducing this subprocedure, we are able to keep \\{line\_break}
+from getting extremely long.)
+
+\Y\P$\4\X887:Break the paragraph at the chosen breakpoints, justify the
+resulting lines to the correct widths, and append them to the current vertical
+list\X\S$\6
+$\\{post\_line\_break}(\\{final\_widow\_penalty})$\par
+\U826.\fi
+
+\M888. The total number of lines that will be set by \\{post\_line\_break}
+is $\\{best\_line}-\\{prev\_graf}-1$. The last breakpoint is specified by
+$\\{break\_node}(\\{best\_bet})$, and this passive node points to the other
+breakpoints
+via the \\{prev\_break} links. The finishing-up phase starts by linking the
+relevant passive nodes in forward order, changing \\{prev\_break} to
+\\{next\_break}. (The \\{next\_break} fields actually reside in the same memory
+space as the \\{prev\_break} fields did, but we give them a new name because
+of their new significance.) Then the lines are justified, one by one.
+
+\Y\P\D \37$\\{next\_break}\S\\{prev\_break}$\C{new name for \\{prev\_break}
+after links are reversed}\par
+\Y\P$\4\X837:Declare subprocedures for \\{line\_break}\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{post\_line\_break}(\\{final\_widow\_penalty}:%
+\\{integer})$;\6
+\4\&{label} \37$\\{done},\39\\{done1}$;\6
+\4\&{var} \37$\|q,\39\|r,\39\|s$: \37\\{pointer};\C{temporary registers for
+list manipulation}\6
+\\{disc\_break}: \37\\{boolean};\C{was the current break at a discretionary
+node?}\6
+\\{post\_disc\_break}: \37\\{boolean};\C{and did it have a nonempty post-break
+part?}\6
+\\{cur\_width}: \37\\{scaled};\C{width of line number \\{cur\_line}}\6
+\\{cur\_indent}: \37\\{scaled};\C{left margin of line number \\{cur\_line}}\6
+\|t: \37\\{quarterword};\C{used for replacement counts in discretionary nodes}\6
+\\{pen}: \37\\{integer};\C{use when calculating penalties between lines}\6
+\\{cur\_line}: \37\\{halfword};\C{the current line number being justified}\2\6
+\&{begin} \37\X889:Reverse the links of the relevant passive nodes, setting %
+\\{cur\_p} to the first breakpoint\X;\6
+$\\{cur\_line}\K\\{prev\_graf}+1$;\5
+$\\{last\_disp}\K0$;\6
+\1\&{repeat} \37\X891:Justify the line ending at breakpoint \\{cur\_p}, and
+append it to the current vertical list, together with associated penalties and
+other insertions\X;\6
+$\\{incr}(\\{cur\_line})$;\5
+$\\{cur\_p}\K\\{next\_break}(\\{cur\_p})$;\6
+\&{if} $\\{cur\_p}\I\\{null}$ \1\&{then}\6
+\&{if} $\R\\{post\_disc\_break}$ \1\&{then}\5
+\X890:Prune unwanted nodes at the beginning of the next line\X;\2\2\6
+\4\&{until}\5
+$\\{cur\_p}=\\{null}$;\2\6
+\&{if} $(\\{cur\_line}\I\\{best\_line})\V(\\{link}(\\{temp\_head})\I\\{null})$ %
+\1\&{then}\5
+$\\{confusion}(\.{"line\ breaking"})$;\2\6
+$\\{prev\_graf}\K\\{best\_line}-1$;\6
+\&{end};\par
+\fi
+
+\M889. The job of reversing links in a list is conveniently regarded as the job
+of taking items off one stack and putting them on another. In this case we
+take them off a stack pointed to by \|q and having \\{prev\_break} fields;
+we put them on a stack pointed to by \\{cur\_p} and having \\{next\_break}
+fields.
+Node \|r is the passive node being moved from stack to stack.
+
+\Y\P$\4\X889:Reverse the links of the relevant passive nodes, setting \\{cur%
+\_p} to the first breakpoint\X\S$\6
+$\|q\K\\{break\_node}(\\{best\_bet})$;\5
+$\\{cur\_p}\K\\{null}$;\6
+\1\&{repeat} \37$\|r\K\|q$;\5
+$\|q\K\\{prev\_break}(\|q)$;\5
+$\\{next\_break}(\|r)\K\\{cur\_p}$;\5
+$\\{cur\_p}\K\|r$;\6
+\4\&{until}\5
+$\|q=\\{null}$\2\par
+\U888.\fi
+
+\M890. Glue and penalty and kern and math nodes are deleted at the beginning of
+a line, except in the anomalous case that the node to be deleted is actually
+one of the chosen breakpoints. Otherwise
+the pruning done here is designed to match
+the lookahead computation in \\{try\_break}, where the \\{break\_width} values
+are computed for non-discretionary breakpoints.
+
+\Y\P$\4\X890:Prune unwanted nodes at the beginning of the next line\X\S$\6
+\&{begin} \37$\|r\K\\{temp\_head}$;\6
+\~ \1\&{loop}\ \&{begin} \37$\|q\K\\{link}(\|r)$;\6
+\&{if} $\|q=\\{cur\_break}(\\{cur\_p})$ \1\&{then}\5
+\&{goto} \37\\{done1};\C{$\\{cur\_break}(\\{cur\_p})$ is the next breakpoint}\6
+\C{now \|q cannot be \\{null}}\2\6
+\&{if} $\\{is\_char\_node}(\|q)$ \1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\&{if} $\\{non\_discardable}(\|q)$ \1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\&{if} $\\{type}(\|q)=\\{kern\_node}$ \1\&{then}\6
+\&{if} $(\\{subtype}(\|q)\I\\{explicit})\W(\\{subtype}(\|q)\I\\{ita\_kern})$ \1%
+\&{then}\5
+\&{goto} \37\\{done1};\2\2\6
+$\|r\K\|q$;\C{now $\\{type}(\|q)=\\{glue\_node}$, \\{kern\_node}, \\{math%
+\_node} or \\{penalty\_node}}\6
+\&{end};\2\6
+\4\\{done1}: \37\&{if} $\|r\I\\{temp\_head}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|r)\K\\{null}$;\5
+$\\{flush\_node\_list}(\\{link}(\\{temp\_head}))$;\5
+$\\{link}(\\{temp\_head})\K\|q$;\6
+\&{end};\2\6
+\&{end}\par
+\U888.\fi
+
+\M891. The current line to be justified appears in a horizontal list starting
+at $\\{link}(\\{temp\_head})$ and ending at $\\{cur\_break}(\\{cur\_p})$. If $%
+\\{cur\_break}(\\{cur\_p})$ is
+a glue node, we reset the glue to equal the \\{right\_skip} glue; otherwise
+we append the \\{right\_skip} glue at the right. If $\\{cur\_break}(\\{cur%
+\_p})$ is a
+discretionary node, we modify the list so that the discretionary break
+is compulsory, and we set \\{disc\_break} to \\{true}. We also append
+the \\{left\_skip} glue at the left of the line, unless it is zero.
+
+\Y\P$\4\X891:Justify the line ending at breakpoint \\{cur\_p}, and append it to
+the current vertical list, together with associated penalties and other
+insertions\X\S$\6
+\X892:Modify the end of the line to reflect the nature of the break and to
+include \.{\\rightskip}; also set the proper value of \\{disc\_break}\X;\6
+\X898:Put the \(l)\.{\\leftskip} glue at the left and detach this line\X;\6
+\X900:Call the packaging subroutine, setting \\{just\_box} to the justified box%
+\X;\6
+\X899:Append the new box to the current vertical list, followed by the list of
+special nodes taken out of the box by the packager\X;\6
+\X901:Append a penalty node, if a nonzero penalty is appropriate\X\par
+\U888.\fi
+
+\M892. At the end of the following code, \|q will point to the final node on
+the
+list about to be justified.
+
+\Y\P$\4\X892:Modify the end of the line to reflect the nature of the break and
+to include \.{\\rightskip}; also set the proper value of \\{disc\_break}\X\S$\6
+$\|q\K\\{cur\_break}(\\{cur\_p})$;\5
+$\\{disc\_break}\K\\{false}$;\5
+$\\{post\_disc\_break}\K\\{false}$;\6
+\&{if} $\|q\I\\{null}$ \1\&{then}\C{\|q may be a \\{char\_node}}\6
+\&{begin} \37\&{if} $\R\\{is\_char\_node}(\|q)$ \1\&{then}\6
+\&{if} $\\{type}(\|q)=\\{glue\_node}$ \1\&{then}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{glue\_ptr}(\|q))$;\5
+$\\{glue\_ptr}(\|q)\K\\{right\_skip}$;\5
+$\\{subtype}(\|q)\K\\{right\_skip\_code}+1$;\5
+$\\{add\_glue\_ref}(\\{right\_skip})$;\5
+\&{goto} \37\\{done};\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{type}(\|q)=\\{disc\_node}$ \1\&{then}\5
+\X893:Change discretionary to compulsory and set $\\{disc\_break}\K\\{true}$\X\6
+\4\&{else} \&{if} $(\\{type}(\|q)=\\{math\_node})\V(\\{type}(\|q)=\\{kern%
+\_node})$ \1\&{then}\5
+$\\{width}(\|q)\K0$;\2\2\6
+\&{end}\2\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|q\K\\{temp\_head}$;\6
+\&{while} $\\{link}(\|q)\I\\{null}$ \1\&{do}\5
+$\|q\K\\{link}(\|q)$;\2\6
+\&{end};\2\6
+\X897:Put the \(r)\.{\\rightskip} glue after node \|q\X;\6
+\4\\{done}: \37\par
+\U891.\fi
+
+\M893. \P$\X893:Change discretionary to compulsory and set $\\{disc\_break}\K%
+\\{true}$\X\S$\6
+\&{begin} \37$\|t\K\\{replace\_count}(\|q)$;\5
+\X894:Destroy the \|t nodes following \|q, and make \|r point to the following
+node\X;\6
+\&{if} $\\{post\_break}(\|q)\I\\{null}$ \1\&{then}\5
+\X895:Transplant the post-break list\X;\2\6
+\&{if} $\\{pre\_break}(\|q)\I\\{null}$ \1\&{then}\5
+\X896:Transplant the pre-break list\X;\2\6
+$\\{link}(\|q)\K\|r$;\5
+$\\{disc\_break}\K\\{true}$;\6
+\&{end}\par
+\U892.\fi
+
+\M894. \P$\X894:Destroy the \|t nodes following \|q, and make \|r point to the
+following node\X\S$\6
+\&{if} $\|t=0$ \1\&{then}\5
+$\|r\K\\{link}(\|q)$\6
+\4\&{else} \&{begin} \37$\|r\K\|q$;\6
+\&{while} $\|t>1$ \1\&{do}\6
+\&{begin} \37$\|r\K\\{link}(\|r)$;\5
+$\\{decr}(\|t)$;\6
+\&{end};\2\6
+$\|s\K\\{link}(\|r)$;\5
+$\|r\K\\{link}(\|s)$;\5
+$\\{link}(\|s)\K\\{null}$;\5
+$\\{flush\_node\_list}(\\{link}(\|q))$;\5
+$\\{replace\_count}(\|q)\K0$;\6
+\&{end}\2\par
+\U893.\fi
+
+\M895. We move the post-break list from inside node \|q to the main list by
+re\-attaching it just before the present node \|r, then resetting \|r.
+
+\Y\P$\4\X895:Transplant the post-break list\X\S$\6
+\&{begin} \37$\|s\K\\{post\_break}(\|q)$;\6
+\&{while} $\\{link}(\|s)\I\\{null}$ \1\&{do}\5
+$\|s\K\\{link}(\|s)$;\2\6
+$\\{link}(\|s)\K\|r$;\5
+$\|r\K\\{post\_break}(\|q)$;\5
+$\\{post\_break}(\|q)\K\\{null}$;\5
+$\\{post\_disc\_break}\K\\{true}$;\6
+\&{end}\par
+\U893.\fi
+
+\M896. We move the pre-break list from inside node \|q to the main list by
+re\-attaching it just after the present node \|q, then resetting \|q.
+
+\Y\P$\4\X896:Transplant the pre-break list\X\S$\6
+\&{begin} \37$\|s\K\\{pre\_break}(\|q)$;\5
+$\\{link}(\|q)\K\|s$;\6
+\&{while} $\\{link}(\|s)\I\\{null}$ \1\&{do}\5
+$\|s\K\\{link}(\|s)$;\2\6
+$\\{pre\_break}(\|q)\K\\{null}$;\5
+$\|q\K\|s$;\6
+\&{end}\par
+\U893.\fi
+
+\M897. \P$\X897:Put the \(r)\.{\\rightskip} glue after node \|q\X\S$\6
+$\|r\K\\{new\_param\_glue}(\\{right\_skip\_code})$;\5
+$\\{link}(\|r)\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\|r$;\5
+$\|q\K\|r$\par
+\U892.\fi
+
+\M898. The following code begins with \|q at the end of the list to be
+justified. It ends with \|q at the beginning of that list, and with
+$\\{link}(\\{temp\_head})$ pointing to the remainder of the paragraph, if any.
+
+\Y\P$\4\X898:Put the \(l)\.{\\leftskip} glue at the left and detach this line\X%
+\S$\6
+$\|r\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\\{null}$;\5
+$\|q\K\\{link}(\\{temp\_head})$;\5
+$\\{link}(\\{temp\_head})\K\|r$;\6
+\&{if} $\\{last\_disp}\I0$ \1\&{then}\6
+\&{begin} \37$\|r\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|r)\K\\{disp\_node}$;\5
+$\\{disp\_dimen}(\|r)\K\\{last\_disp}$;\5
+$\\{link}(\|r)\K\|q$;\5
+$\|q\K\|r$;\6
+\&{end};\2\6
+\&{if} $\\{left\_skip}\I\\{zero\_glue}$ \1\&{then}\6
+\&{begin} \37$\|r\K\\{new\_param\_glue}(\\{left\_skip\_code})$;\5
+$\\{link}(\|r)\K\|q$;\5
+$\|q\K\|r$;\6
+\&{end}\2\par
+\U891.\fi
+
+\M899. \P$\X899:Append the new box to the current vertical list, followed by
+the list of special nodes taken out of the box by the packager\X\S$\6
+$\\{append\_to\_vlist}(\\{just\_box})$;\6
+\&{if} $\\{adjust\_head}\I\\{adjust\_tail}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\\{tail})\K\\{link}(\\{adjust\_head})$;\5
+$\\{tail}\K\\{adjust\_tail}$;\6
+\&{end};\2\6
+$\\{adjust\_tail}\K\\{null}$\par
+\U891.\fi
+
+\M900. Now \|q points to the hlist that represents the current line of the
+paragraph. We need to compute the appropriate line width, pack the
+line into a box of this size, and shift the box by the appropriate
+amount of indentation.
+
+\Y\P$\4\X900:Call the packaging subroutine, setting \\{just\_box} to the
+justified box\X\S$\6
+\&{if} $\\{cur\_line}>\\{last\_special\_line}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_width}\K\\{second\_width}$;\5
+$\\{cur\_indent}\K\\{second\_indent}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{par\_shape\_ptr}=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_width}\K\\{first\_width}$;\5
+$\\{cur\_indent}\K\\{first\_indent}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{cur\_width}\K\\{mem}[\\{par\_shape\_ptr}+2\ast%
+\\{cur\_line}].\\{sc}$;\5
+$\\{cur\_indent}\K\\{mem}[\\{par\_shape\_ptr}+2\ast\\{cur\_line}-1].\\{sc}$;\6
+\&{end};\2\2\6
+$\\{adjust\_tail}\K\\{adjust\_head}$;\5
+$\\{just\_box}\K\\{hpack}(\|q,\39\\{cur\_width},\39\\{exactly})$;\5
+$\\{shift\_amount}(\\{just\_box})\K\\{cur\_indent}$\par
+\U891.\fi
+
+\M901. Penalties between the lines of a paragraph come from club and widow
+lines,
+from the \\{inter\_line\_penalty} parameter, and from lines that end at
+discretionary breaks.  Breaking between lines of a two-line paragraph gets
+both club-line and widow-line penalties. The local variable \\{pen} will
+be set to the sum of all relevant penalties for the current line, except
+that the final line is never penalized.
+
+\Y\P$\4\X901:Append a penalty node, if a nonzero penalty is appropriate\X\S$\6
+\&{if} $\\{cur\_line}+1\I\\{best\_line}$ \1\&{then}\6
+\&{begin} \37$\\{pen}\K\\{inter\_line\_penalty}$;\6
+\&{if} $\\{cur\_line}=\\{prev\_graf}+1$ \1\&{then}\5
+$\\{pen}\K\\{pen}+\\{club\_penalty}$;\2\6
+\&{if} $\\{cur\_line}+2=\\{best\_line}$ \1\&{then}\5
+$\\{pen}\K\\{pen}+\\{final\_widow\_penalty}$;\2\6
+\&{if} $\\{disc\_break}$ \1\&{then}\5
+$\\{pen}\K\\{pen}+\\{broken\_penalty}$;\2\6
+\&{if} $\\{pen}\I0$ \1\&{then}\6
+\&{begin} \37$\|r\K\\{new\_penalty}(\\{pen})$;\5
+$\\{link}(\\{tail})\K\|r$;\5
+$\\{tail}\K\|r$;\6
+\&{end};\2\6
+\&{end}\2\par
+\U891.\fi
+
+\N902.  \[40] Pre-hyphenation.
+When the line-breaking routine is unable to find a feasible sequence of
+breakpoints, it makes a second pass over the paragraph, attempting to
+hyphenate the hyphenatable words. The goal of hyphenation is to insert
+discretionary material into the paragraph so that there are more
+potential places to break.
+
+The general rules for hyphenation are somewhat complex and technical,
+because we want to be able to hyphenate words that are preceded or
+followed by punctuation marks, and because we want the rules to work
+for languages other than English. We also must contend with the fact
+that hyphens might radically alter the ligature and kerning structure
+of a word.
+
+A sequence of characters will be considered for hyphenation only if it
+belongs to a ``potentially hyphenatable part'' of the current paragraph.
+This is a sequence of nodes $p_0p_1\ldots p_m$ where $p_0$ is a glue node,
+$p_1\ldots p_{m-1}$ are either character or ligature or whatsit or
+implicit kern nodes, and $p_m$ is a glue or penalty or insertion or adjust
+or mark or whatsit or explicit kern node.  (Therefore hyphenation is
+disabled by boxes, math formulas, and discretionary nodes already inserted
+by the user.) The ligature nodes among $p_1\ldots p_{m-1}$ are effectively
+expanded into the original non-ligature characters; the kern nodes and
+whatsits are ignored. Each character \|c is now classified as either a
+nonletter (if $\\{lc\_code}(\|c)=0$), a lowercase letter (if
+$\\{lc\_code}(\|c)=\|c$), or an uppercase letter (otherwise); an uppercase
+letter
+is treated as if it were $\\{lc\_code}(\|c)$ for purposes of hyphenation. The
+characters generated by $p_1\ldots p_{m-1}$ may begin with nonletters; let
+$c_1$ be the first letter that is not in the middle of a ligature. Whatsit
+nodes preceding $c_1$ are ignored; a whatsit found after $c_1$ will be the
+terminating node $p_m$. All characters that do not have the same font as
+$c_1$ will be treated as nonletters. The \\{hyphen\_char} for that font
+must be between 0 and 255, otherwise hyphenation will not be attempted.
+\TeX\ looks ahead for as many consecutive letters $c_1\ldots c_n$ as
+possible; however, \|n must be less than 64, so a character that would
+otherwise be $c_{64}$ is effectively not a letter. Furthermore $c_n$ must
+not be in the middle of a ligature.  In this way we obtain a string of
+letters $c_1\ldots c_n$ that are generated by nodes $p_a\ldots p_b$, where
+$1\L\|a\L\|b+1\L\|m$. If $\|n\G\\{l\_hyf}+\\{r\_hyf}$, this string qualifies
+for hyphenation;
+however, \\{uc\_hyph} must be positive, if $c_1$ is uppercase.
+
+The hyphenation process takes place in three stages. First, the candidate
+sequence $c_1\ldots c_n$ is found; then potential positions for hyphens
+are determined by referring to hyphenation tables; and finally, the nodes
+$p_a\ldots p_b$ are replaced by a new sequence of nodes that includes the
+discretionary breaks found.
+
+Fortunately, we do not have to do all this calculation very often, because
+of the way it has been taken out of \TeX's inner loop. For example, when
+the second edition of the author's 700-page book {\sl Seminumerical
+Algorithms} was typeset by \TeX, only about 1.2 hyphenations needed to be
+tried per paragraph, since the line breaking algorithm needed to use two
+passes on only about 5 per cent of the paragraphs.
+
+\Y\P$\4\X902:Initialize for hyphenating a paragraph\X\S$\6
+\&{begin} \37\&{init} \37\&{if} $\\{trie\_not\_ready}$ \1\&{then}\5
+\\{init\_trie};\ \2\6
+\&{tini}\6
+$\\{cur\_lang}\K\\{init\_cur\_lang}$;\5
+$\\{l\_hyf}\K\\{init\_l\_hyf}$;\5
+$\\{r\_hyf}\K\\{init\_r\_hyf}$;\6
+\&{end}\par
+\U874.\fi
+
+\M903. The letters $c_1\ldots c_n$ that are candidates for hyphenation are
+placed
+into an array called \\{hc}; the number \|n is placed into \\{hn}; pointers to
+nodes $p_{a-1}$ and~$p_b$ in the description above are placed into variables
+\\{ha} and \\{hb}; and the font number is placed into \\{hf}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{hc}: \37\&{array} $[0\to65]$ \1\&{of}\5
+$0\to256$;\C{word to be hyphenated}\2\6
+\4\\{hn}: \37\\{small\_number};\C{the number of positions occupied in \\{hc}}\6
+\4$\\{ha},\39\\{hb}$: \37\\{pointer};\C{nodes $\\{ha}\to\\{hb}$ should be
+replaced by the hyphenated result}\6
+\4\\{hf}: \37\\{internal\_font\_number};\C{font number of the letters in %
+\\{hc}}\6
+\4\\{hu}: \37\&{array} $[0\to63]$ \1\&{of}\5
+$0\to256$;\C{like \\{hc}, before conversion to lowercase}\2\6
+\4\\{hyf\_char}: \37\\{integer};\C{hyphen character of the relevant font}\6
+\4$\\{cur\_lang},\39\\{init\_cur\_lang}$: \37\\{ASCII\_code};\C{current
+hyphenation table of interest}\6
+\4$\\{l\_hyf},\39\\{r\_hyf},\39\\{init\_l\_hyf},\39\\{init\_r\_hyf}$: \37%
+\\{integer};\C{limits on fragment sizes}\6
+\4\\{hyf\_bchar}: \37\\{halfword};\C{boundary character after $c_n$}\par
+\fi
+
+\M904. Hyphenation routines need a few more local variables.
+
+\Y\P$\4\X873:Local variables for line breaking\X\mathrel{+}\S$\6
+\4\|j: \37\\{small\_number};\C{an index into \\{hc} or \\{hu}}\6
+\4\|c: \37$0\to255$;\C{character being considered for hyphenation}\par
+\fi
+
+\M905. When the following code is activated, the \\{line\_break} procedure is
+in its
+second pass, and \\{cur\_p} points to a glue node.
+
+\Y\P$\4\X905:Try to hyphenate the following word\X\S$\6
+\&{begin} \37$\\{prev\_s}\K\\{cur\_p}$;\5
+$\|s\K\\{link}(\\{prev\_s})$;\6
+\&{if} $\|s\I\\{null}$ \1\&{then}\6
+\&{begin} \37\X907:Skip to node \\{ha}, or \&{goto} \\{done1} if no hyphenation
+should be attempted\X;\6
+\&{if} $\\{l\_hyf}+\\{r\_hyf}>63$ \1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\X908:Skip to node \\{hb}, putting letters into \\{hu} and \\{hc}\X;\6
+\X910:Check that the nodes following \\{hb} permit hyphenation and that at
+least $\\{l\_hyf}+\\{r\_hyf}$ letters have been found, otherwise \&{goto} %
+\\{done1}\X;\6
+\\{hyphenate};\6
+\&{end};\2\6
+\4\\{done1}: \37\&{end}\par
+\U877.\fi
+
+\M906. \P$\X837:Declare subprocedures for \\{line\_break}\X\mathrel{+}\S$\6
+\hbox{\4}\X917:Declare the function called \\{reconstitute}\X \6
+\4\&{procedure}\1\  \37\\{hyphenate};\6
+\4\&{label} \37$\\{common\_ending},\39\\{done},\39\\{found},\39\\{found1},\39%
+\\{found2},\39\\{not\_found},\39\\{exit}$;\6
+\4\&{var} \37\X912:Local variables for hyphenation\X\2\6
+\&{begin} \37\X934:Find hyphen locations for the word in \\{hc}, or \&{return}%
+\X;\6
+\X913:If no hyphens were found, \&{return}\X;\6
+\X914:Replace nodes $\\{ha}\to\\{hb}$ by a sequence of nodes that includes the
+discretionary hyphens\X;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M907. The first thing we need to do is find the node \\{ha} just before the
+first letter.
+
+\Y\P$\4\X907:Skip to node \\{ha}, or \&{goto} \\{done1} if no hyphenation
+should be attempted\X\S$\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{is\_char\_node}(\|s)$ \1\&{then}\6
+\&{begin} \37$\\{hf}\K\\{font}(\|s)$;\6
+\&{if} $\\{font\_dir}[\\{hf}]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\\{prev\_s}\K\|s$;\5
+$\|s\K\\{link}(\\{prev\_s})$;\5
+$\|c\K\\{info}(\|s)$;\5
+\&{goto} \37\\{continue};\6
+\&{end}\6
+\4\&{else} $\|c\K\\{qo}(\\{character}(\|s))$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{type}(\|s)=\\{disp\_node}$ \1\&{then}\5
+\&{goto} \37\\{continue}\6
+\4\&{else} \&{if} $(\\{type}(\|s)=\\{penalty\_node})\W(\R\\{subtype}(\|s)=%
+\\{normal})$ \1\&{then}\5
+\&{goto} \37\\{continue}\6
+\4\&{else} \&{if} $\\{type}(\|s)=\\{ligature\_node}$ \1\&{then}\6
+\&{if} $\\{lig\_ptr}(\|s)=\\{null}$ \1\&{then}\5
+\&{goto} \37\\{continue}\6
+\4\&{else} \&{begin} \37$\|q\K\\{lig\_ptr}(\|s)$;\5
+$\|c\K\\{qo}(\\{character}(\|q))$;\5
+$\\{hf}\K\\{font}(\|q)$;\6
+\&{end}\2\6
+\4\&{else} \&{if} $(\\{type}(\|s)=\\{kern\_node})\W(\\{subtype}(\|s)=%
+\\{normal})$ \1\&{then}\5
+\&{goto} \37\\{continue}\6
+\4\&{else} \&{if} $\\{type}(\|s)=\\{whatsit\_node}$ \1\&{then}\6
+\&{begin} \37\X1376:Advance \(p)past a whatsit node in the \(p)pre-hyphenation
+loop\X;\6
+\&{goto} \37\\{continue};\6
+\&{end}\6
+\4\&{else} \&{goto} \37\\{done1};\2\2\2\2\2\2\6
+\&{if} $\\{lc\_code}(\|c)\I0$ \1\&{then}\6
+\&{if} $(\\{lc\_code}(\|c)=\|c)\V(\\{uc\_hyph}>0)$ \1\&{then}\5
+\&{goto} \37\\{done2}\6
+\4\&{else} \&{goto} \37\\{done1};\2\2\6
+\4\\{continue}: \37$\\{prev\_s}\K\|s$;\5
+$\|s\K\\{link}(\\{prev\_s})$;\6
+\&{end};\2\6
+\4\\{done2}: \37$\\{hyf\_char}\K\\{hyphen\_char}[\\{hf}]$;\6
+\&{if} $\\{hyf\_char}<0$ \1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\&{if} $\\{hyf\_char}>255$ \1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+$\\{ha}\K\\{prev\_s}$\par
+\U905.\fi
+
+\M908. The word to be hyphenated is now moved to the \\{hu} and \\{hc} arrays.
+
+\Y\P$\4\X908:Skip to node \\{hb}, putting letters into \\{hu} and \\{hc}\X\S$\6
+$\\{hn}\K0$;\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{is\_char\_node}(\|s)$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{font}(\|s)\I\\{hf}$ \1\&{then}\5
+\&{goto} \37\\{done3};\2\6
+$\\{hyf\_bchar}\K\\{character}(\|s)$;\5
+$\|c\K\\{qo}(\\{hyf\_bchar})$;\6
+\&{if} $\\{lc\_code}(\|c)=0$ \1\&{then}\5
+\&{goto} \37\\{done3};\2\6
+\&{if} $\\{hn}=63$ \1\&{then}\5
+\&{goto} \37\\{done3};\2\6
+$\\{hb}\K\|s$;\5
+$\\{incr}(\\{hn})$;\5
+$\\{hu}[\\{hn}]\K\|c$;\5
+$\\{hc}[\\{hn}]\K\\{lc\_code}(\|c)$;\5
+$\\{hyf\_bchar}\K\\{non\_char}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{type}(\|s)=\\{ligature\_node}$ \1\&{then}\5
+\X909:Move the characters of a ligature node to \\{hu} and \\{hc}; but \&{goto}
+\\{done3} if they are not all letters\X\6
+\4\&{else} \&{if} $(\\{type}(\|s)=\\{kern\_node})\W(\\{subtype}(\|s)=%
+\\{normal})$ \1\&{then}\6
+\&{begin} \37$\\{hb}\K\|s$;\5
+$\\{hyf\_bchar}\K\\{font\_bchar}[\\{hf}]$;\6
+\&{end}\6
+\4\&{else} \&{goto} \37\\{done3};\2\2\2\6
+$\|s\K\\{link}(\|s)$;\6
+\&{end};\2\6
+\4\\{done3}: \37\par
+\U905.\fi
+
+\M909. We let \|j be the index of the character being stored when a ligature
+node
+is being expanded, since we do not want to advance \\{hn} until we are sure
+that the entire ligature consists of letters. Note that it is possible
+to get to \\{done3} with $\\{hn}=0$ and \\{hb} not set to any value.
+
+\Y\P$\4\X909:Move the characters of a ligature node to \\{hu} and \\{hc}; but %
+\&{goto} \\{done3} if they are not all letters\X\S$\6
+\&{begin} \37\&{if} $\\{font}(\\{lig\_char}(\|s))\I\\{hf}$ \1\&{then}\5
+\&{goto} \37\\{done3};\2\6
+$\|j\K\\{hn}$;\5
+$\|q\K\\{lig\_ptr}(\|s)$;\ \&{if} $\|q>\\{null}$ \1\&{then}\5
+$\\{hyf\_bchar}\K\\{character}(\|q)$;\2\6
+\&{while} $\|q>\\{null}$ \1\&{do}\6
+\&{begin} \37$\|c\K\\{qo}(\\{character}(\|q))$;\6
+\&{if} $\\{lc\_code}(\|c)=0$ \1\&{then}\5
+\&{goto} \37\\{done3};\2\6
+\&{if} $\|j=63$ \1\&{then}\5
+\&{goto} \37\\{done3};\2\6
+$\\{incr}(\|j)$;\5
+$\\{hu}[\|j]\K\|c$;\5
+$\\{hc}[\|j]\K\\{lc\_code}(\|c)$;\6
+$\|q\K\\{link}(\|q)$;\6
+\&{end};\2\6
+$\\{hb}\K\|s$;\5
+$\\{hn}\K\|j$;\6
+\&{if} $\\{odd}(\\{subtype}(\|s))$ \1\&{then}\5
+$\\{hyf\_bchar}\K\\{font\_bchar}[\\{hf}]$\ \&{else} $\\{hyf\_bchar}\K\\{non%
+\_char}$;\2\6
+\&{end}\par
+\U908.\fi
+
+\M910. \P$\X910:Check that the nodes following \\{hb} permit hyphenation and
+that at least $\\{l\_hyf}+\\{r\_hyf}$ letters have been found, otherwise %
+\&{goto} \\{done1}\X\S$\6
+\&{if} $\\{hn}<\\{l\_hyf}+\\{r\_hyf}$ \1\&{then}\5
+\&{goto} \37\\{done1};\C{\\{l\_hyf} and \\{r\_hyf} are $\G1$}\2\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\R(\\{is\_char\_node}(\|s))$ \1\&{then}\6
+\&{case} $\\{type}(\|s)$ \1\&{of}\6
+\4\\{ligature\_node}: \37\\{do\_nothing};\6
+\4\\{kern\_node}: \37\&{if} $\\{subtype}(\|s)\I\\{normal}$ \1\&{then}\5
+\&{goto} \37\\{done4};\2\6
+\4\\{disp\_node}: \37\\{do\_nothing};\6
+\4$\\{whatsit\_node},\39\\{glue\_node},\39\\{penalty\_node},\39\\{ins\_node},%
+\39\\{adjust\_node},\39\\{mark\_node}$: \37\&{goto} \37\\{done4};\6
+\4\&{othercases} \37\&{goto} \37\\{done1}\2\6
+\&{endcases};\2\6
+$\|s\K\\{link}(\|s)$;\6
+\&{end};\2\6
+\4\\{done4}: \37\par
+\U905.\fi
+
+\N911.  \[41] Post-hyphenation.
+If a hyphen may be inserted between $\\{hc}[\|j]$ and $\\{hc}[\|j+1]$, the
+hyphenation
+procedure will set $\\{hyf}[\|j]$ to some small odd number. But before we look
+at \TeX's hyphenation procedure, which is independent of the rest of the
+line-breaking algorithm, let us consider what we will do with the hyphens
+it finds, since it is better to work on this part of the program before
+forgetting what \\{ha} and \\{hb}, etc., are all about.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{hyf}: \37\&{array} $[0\to64]$ \1\&{of}\5
+$0\to9$;\C{odd values indicate discretionary hyphens}\2\6
+\4\\{init\_list}: \37\\{pointer};\C{list of punctuation characters preceding
+the word}\6
+\4\\{init\_lig}: \37\\{boolean};\C{does \\{init\_list} represent a ligature?}\6
+\4\\{init\_lft}: \37\\{boolean};\C{if so, did the ligature involve a left
+boundary?}\par
+\fi
+
+\M912. \P$\X912:Local variables for hyphenation\X\S$\6
+\4$\|i,\39\|j,\39\|l$: \37$0\to65$;\C{indices into \\{hc} or \\{hu}}\6
+\4$\|q,\39\|r,\39\|s$: \37\\{pointer};\C{temporary registers for list
+manipulation}\6
+\4\\{bchar}: \37\\{halfword};\C{right boundary character of hyphenated word, or
+\\{non\_char}}\par
+\As923, 933\ETs940.
+\U906.\fi
+
+\M913. \TeX\ will never insert a hyphen that has fewer than
+\.{\\lefthyphenmin} letters before it or fewer than
+\.{\\righthyphenmin} after it; hence, a short word has
+comparatively little chance of being hyphenated. If no hyphens have
+been found, we can save time by not having to make any changes to the
+paragraph.
+
+\Y\P$\4\X913:If no hyphens were found, \&{return}\X\S$\6
+\&{for} $\|j\K\\{l\_hyf}\mathrel{\&{to}}\\{hn}-\\{r\_hyf}$ \1\&{do}\6
+\&{if} $\\{odd}(\\{hyf}[\|j])$ \1\&{then}\5
+\&{goto} \37\\{found1};\2\2\6
+\&{return};\6
+\4\\{found1}: \37\par
+\U906.\fi
+
+\M914. If hyphens are in fact going to be inserted, \TeX\ first deletes the
+subsequence of nodes between \\{ha} and~\\{hb}. An attempt is made to
+preserve the effect that implicit boundary characters and punctuation marks
+had on ligatures inside the hyphenated word, by storing a left boundary or
+preceding character in $\\{hu}[0]$ and by storing a possible right boundary
+in \\{bchar}. We set $\|j\K0$ if $\\{hu}[0]$ is to be part of the
+reconstruction;
+otherwise $\|j\K1$.
+The variable \|s will point to the tail of the current hlist, and
+\|q will point to the node following \\{hb}, so that
+things can be hooked up after we reconstitute the hyphenated word.
+
+\Y\P$\4\X914:Replace nodes $\\{ha}\to\\{hb}$ by a sequence of nodes that
+includes the discretionary hyphens\X\S$\6
+$\|q\K\\{link}(\\{hb})$;\5
+$\\{link}(\\{hb})\K\\{null}$;\5
+$\|r\K\\{link}(\\{ha})$;\5
+$\\{link}(\\{ha})\K\\{null}$;\5
+$\\{bchar}\K\\{hyf\_bchar}$;\6
+\&{if} $\\{is\_char\_node}(\\{ha})$ \1\&{then}\6
+\&{if} $\\{font}(\\{ha})\I\\{hf}$ \1\&{then}\5
+\&{goto} \37\\{found2}\6
+\4\&{else} \&{begin} \37$\\{init\_list}\K\\{ha}$;\5
+$\\{init\_lig}\K\\{false}$;\5
+$\\{hu}[0]\K\\{qo}(\\{character}(\\{ha}))$;\6
+\&{end}\2\6
+\4\&{else} \&{if} $\\{type}(\\{ha})=\\{ligature\_node}$ \1\&{then}\6
+\&{if} $\\{font}(\\{lig\_char}(\\{ha}))\I\\{hf}$ \1\&{then}\5
+\&{goto} \37\\{found2}\6
+\4\&{else} \&{begin} \37$\\{init\_list}\K\\{lig\_ptr}(\\{ha})$;\5
+$\\{init\_lig}\K\\{true}$;\5
+$\\{init\_lft}\K(\\{subtype}(\\{ha})>1)$;\5
+$\\{hu}[0]\K\\{qo}(\\{character}(\\{lig\_char}(\\{ha})))$;\6
+\&{if} $\\{init\_list}=\\{null}$ \1\&{then}\6
+\&{if} $\\{init\_lft}$ \1\&{then}\6
+\&{begin} \37$\\{hu}[0]\K256$;\5
+$\\{init\_lig}\K\\{false}$;\6
+\&{end};\C{in this case a ligature will be reconstructed from scratch}\2\2\6
+$\\{free\_node}(\\{ha},\39\\{small\_node\_size})$;\6
+\&{end}\2\6
+\4\&{else} \&{begin} \37\C{no punctuation found; look for left boundary}\6
+\&{if} $\R\\{is\_char\_node}(\|r)$ \1\&{then}\6
+\&{if} $\\{type}(\|r)=\\{ligature\_node}$ \1\&{then}\6
+\&{if} $\\{subtype}(\|r)>1$ \1\&{then}\5
+\&{goto} \37\\{found2};\2\2\2\6
+$\|j\K1$;\5
+$\|s\K\\{ha}$;\5
+$\\{init\_list}\K\\{null}$;\5
+\&{goto} \37\\{common\_ending};\6
+\&{end};\2\2\6
+$\|s\K\\{cur\_p}$;\C{we have $\\{cur\_p}\I\\{ha}$ because $\\{type}(\\{cur%
+\_p})=\\{glue\_node}$}\6
+\&{while} $\\{link}(\|s)\I\\{ha}$ \1\&{do}\5
+$\|s\K\\{link}(\|s)$;\2\6
+$\|j\K0$;\5
+\&{goto} \37\\{common\_ending};\6
+\4\\{found2}: \37$\|s\K\\{ha}$;\5
+$\|j\K0$;\5
+$\\{hu}[0]\K256$;\5
+$\\{init\_lig}\K\\{false}$;\5
+$\\{init\_list}\K\\{null}$;\6
+\4\\{common\_ending}: \37$\\{flush\_node\_list}(\|r)$;\5
+\X924:Reconstitute nodes for the hyphenated word, inserting discretionary
+hyphens\X;\6
+$\\{flush\_list}(\\{init\_list})$\par
+\U906.\fi
+
+\M915. We must now face the fact that the battle is not over, even though the
+{\def\!{\kern-1pt}%
+hyphens have been found: The process of reconstituting a word can be nontrivial
+because ligatures might change when a hyphen is present. {\sl The \TeX book\/}
+discusses the difficulties of the word ``difficult'', and
+the discretionary material surrounding a
+hyphen can be considerably more complex than that. Suppose
+\.{abcdef} is a word in a font for which the only ligatures are \.{b\!c},
+\.{c\!d}, \.{d\!e}, and \.{e\!f}. If this word permits hyphenation
+between \.b and \.c, the two patterns with and without hyphenation are
+$\.a\,\.b\,\.-\,\.{c\!d}\,\.{e\!f}$ and $\.a\,\.{b\!c}\,\.{d\!e}\,\.f$.
+Thus the insertion of a hyphen might cause effects to ripple arbitrarily
+far into the rest of the word. A further complication arises if additional
+hyphens appear together with such rippling, e.g., if the word in the
+example just given could also be hyphenated between \.c and \.d; \TeX\
+avoids this by simply ignoring the additional hyphens in such weird cases.}
+
+Still further complications arise in the presence of ligatures that do not
+delete the original characters. When punctuation precedes the word being
+hyphenated, \TeX's method is not perfect under all possible scenarios,
+because punctuation marks and letters can propagate information back and forth.
+For example, suppose the original pre-hyphenation pair
+\.{*a} changes to \.{*y} via a \.{\?=:} ligature, which changes to \.{xy}
+via a \.{=:\?} ligature; if $p_{a-1}=\.x$ and $p_a=\.y$, the reconstitution
+procedure isn't smart enough to obtain \.{xy} again. In such cases the
+font designer should include a ligature that goes from \.{xa} to \.{xy}.
+
+\fi
+
+\M916. The processing is facilitated by a subroutine called \\{reconstitute}.
+Given
+a string of characters $x_j\ldots x_n$, there is a smallest index $m\ge j$
+such that the ``translation'' of $x_j\ldots x_n$ by ligatures and kerning
+has the form $y_1\ldots y_t$ followed by the translation of $x_{m+1}\ldots
+x_n$,
+where $y_1\ldots y_t$ is some nonempty sequence of character, ligature, and
+kern nodes. We call $x_j\ldots x_m$ a ``cut prefix'' of $x_j\ldots x_n$.
+For example, if $x_1x_2x_3=\.{fly}$, and if the font contains `fl' as a
+ligature and a kern between `fl' and `y', then $m=2$, $t=2$, and $y_1$ will
+be a ligature node for `fl' followed by an appropriate kern node~$y_2$.
+In the most common case, $x_j$~forms no ligature with $x_{j+1}$ and we
+simply have $m=j$, $y_1=x_j$. If $m<n$ we can repeat the procedure on
+$x_{m+1}\ldots x_n$ until the entire translation has been found.
+
+The \\{reconstitute} function returns the integer $m$ and puts the nodes
+$y_1\ldots y_t$ into a linked list starting at $\\{link}(\\{hold\_head})$,
+getting the input $x_j\ldots x_n$ from the \\{hu} array. If $x_j=256$,
+we consider $x_j$ to be an implicit left boundary character; in this
+case \|j must be strictly less than~\|n. There is a
+parameter \\{bchar}, which is either 256 or an implicit right boundary
+character
+assumed to be present just following~$x_n$. (The value $\\{hu}[\|n+1]$ is never
+explicitly examined, but the algorithm imagines that \\{bchar} is there.)
+
+If there exists an index \|k in the range $j\le k\le m$ such that $\\{hyf}[%
+\|k]$
+is odd and such that the result of \\{reconstitute} would have been different
+if $x_{k+1}$ had been \\{hchar}, then \\{reconstitute} sets \\{hyphen\_passed}
+to the smallest such~\|k. Otherwise it sets \\{hyphen\_passed} to zero.
+
+A special convention is used in the case $\|j=0$: Then we assume that the
+translation of $\\{hu}[0]$ appears in a special list of charnodes starting at
+\\{init\_list}; moreover, if \\{init\_lig} is \\{true}, then $\\{hu}[0]$ will
+be
+a ligature character, involving a left boundary if \\{init\_lft} is \\{true}.
+This facility is provided for cases when a hyphenated
+word is preceded by punctuation (like single or double quotes) that might
+affect the translation of the beginning of the word.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{hyphen\_passed}: \37\\{small\_number};\C{first hyphen in a ligature, if
+any}\par
+\fi
+
+\M917. \P$\X917:Declare the function called \\{reconstitute}\X\S$\6
+\4\&{function}\1\  \37$\\{reconstitute}(\|j,\39\|n:\\{small\_number};\,\35%
+\\{bchar},\39\\{hchar}:\\{halfword})$: \37\\{small\_number};\6
+\4\&{label} \37$\\{continue},\39\\{done}$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{temporary register for list manipulation}\6
+\|t: \37\\{pointer};\C{a node being appended to}\6
+\|q: \37\\{four\_quarters};\C{character information or a lig/kern instruction}\6
+\\{cur\_rh}: \37\\{halfword};\C{hyphen character for ligature testing}\6
+\\{test\_char}: \37\\{halfword};\C{hyphen or other character for ligature
+testing}\6
+\|w: \37\\{scaled};\C{amount of kerning}\6
+\|k: \37\\{font\_index};\C{position of current lig/kern instruction}\2\6
+\&{begin} \37$\\{hyphen\_passed}\K0$;\5
+$\|t\K\\{hold\_head}$;\5
+$\|w\K0$;\5
+$\\{link}(\\{hold\_head})\K\\{null}$;\C{at this point $\\{ligature\_present}=%
+\\{lft\_hit}=\\{rt\_hit}=\\{false}$}\6
+\X919:Set up data structures with the cursor following position \|j\X;\6
+\4\\{continue}: \37\X920:If there's a ligature or kern at the cursor position,
+update the data structures, possibly advancing~\|j; continue until the cursor
+moves\X;\6
+\X921:Append a ligature and/or kern to the translation; \&{goto} \\{continue}
+if the stack of inserted ligatures is nonempty\X;\6
+$\\{reconstitute}\K\|j$;\6
+\&{end};\par
+\U906.\fi
+
+\M918. The reconstitution procedure shares many of the global data structures
+by which \TeX\ has processed the words before they were hyphenated.
+There is an implied ``cursor'' between characters \\{cur\_l} and \\{cur\_r};
+these characters will be tested for possible ligature activity. If
+\\{ligature\_present} then \\{cur\_l} is a ligature character formed from the
+original characters following \\{cur\_q} in the current translation list.
+There is a ``ligature stack'' between the cursor and character $\|j+1$,
+consisting of pseudo-ligature nodes linked together by their \\{link} fields.
+This stack is normally empty unless a ligature command has created a new
+character that will need to be processed later. A pseudo-ligature is
+a special node having a \\{character} field that represents a potential
+ligature and a \\{lig\_ptr} field that points to a \\{char\_node} or is %
+\\{null}.
+We have
+$$\\{cur\_r}=\cases{$\\{character}(\\{lig\_stack})$,&if $\\{lig\_stack}>%
+\\{null}$;\cr
+$\\{qi}(\\{hu}[\|j+1])$,&if $\\{lig\_stack}=\\{null}$ and $\|j<\|n$;\cr
+bchar,&if $\\{lig\_stack}=\\{null}$ and $\|j=\|n$.\cr}$$
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4$\\{cur\_l},\39\\{cur\_r}$: \37\\{halfword};\C{characters before and after
+the cursor}\6
+\4\\{cur\_q}: \37\\{pointer};\C{where a ligature should be detached}\6
+\4\\{lig\_stack}: \37\\{pointer};\C{unfinished business to the right of the
+cursor}\6
+\4\\{ligature\_present}: \37\\{boolean};\C{should a ligature node be made for %
+\\{cur\_l}?}\6
+\4$\\{lft\_hit},\39\\{rt\_hit}$: \37\\{boolean};\C{did we hit a ligature with a
+boundary character?}\par
+\fi
+
+\M919. \P\D \37$\\{append\_charnode\_to\_t}(\#)\S$\1\6
+\&{begin} \37$\\{link}(\|t)\K\\{get\_avail}$;\5
+$\|t\K\\{link}(\|t)$;\5
+$\\{font}(\|t)\K\\{hf}$;\5
+$\\{character}(\|t)\K\#$;\6
+\&{end}\2\par
+\P\D \37$\\{set\_cur\_r}\S$\1\6
+\&{begin} \37\&{if} $\|j<\|n$ \1\&{then}\5
+$\\{cur\_r}\K\\{qi}(\\{hu}[\|j+1])$\ \&{else} $\\{cur\_r}\K\\{bchar}$;\2\6
+\&{if} $\\{odd}(\\{hyf}[\|j])$ \1\&{then}\5
+$\\{cur\_rh}\K\\{hchar}$\ \&{else} $\\{cur\_rh}\K\\{non\_char}$;\2\6
+\&{end}\2\par
+\Y\P$\4\X919:Set up data structures with the cursor following position \|j\X\S$%
+\6
+$\\{cur\_l}\K\\{qi}(\\{hu}[\|j])$;\5
+$\\{cur\_q}\K\|t$;\6
+\&{if} $\|j=0$ \1\&{then}\6
+\&{begin} \37$\\{ligature\_present}\K\\{init\_lig}$;\5
+$\|p\K\\{init\_list}$;\6
+\&{if} $\\{ligature\_present}$ \1\&{then}\5
+$\\{lft\_hit}\K\\{init\_lft}$;\2\6
+\&{while} $\|p>\\{null}$ \1\&{do}\6
+\&{begin} \37$\\{append\_charnode\_to\_t}(\\{character}(\|p))$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{cur\_l}<\\{non\_char}$ \1\&{then}\5
+$\\{append\_charnode\_to\_t}(\\{cur\_l})$;\2\2\6
+$\\{lig\_stack}\K\\{null}$;\5
+\\{set\_cur\_r}\par
+\U917.\fi
+
+\M920. We may want to look at the lig/kern program twice, once for a hyphen
+and once for a normal letter. (The hyphen might appear after the letter
+in the program, so we'd better not try to look for both at once.)
+
+\Y\P$\4\X920:If there's a ligature or kern at the cursor position, update the
+data structures, possibly advancing~\|j; continue until the cursor moves\X\S$\6
+\&{if} $\\{cur\_l}=\\{non\_char}$ \1\&{then}\6
+\&{begin} \37$\|k\K\\{bchar\_label}[\\{hf}]$;\6
+\&{if} $\|k=\\{non\_address}$ \1\&{then}\5
+\&{goto} \37\\{done}\ \&{else} $\|q\K\\{font\_info}[\|k].\\{qqqq}$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|q\K\\{char\_info}(\\{hf})(\\{cur\_l})$;\6
+\&{if} $\\{char\_tag}(\|q)\I\\{lig\_tag}$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\|k\K\\{lig\_kern\_start}(\\{hf})(\|q)$;\5
+$\|q\K\\{font\_info}[\|k].\\{qqqq}$;\6
+\&{if} $\\{skip\_byte}(\|q)>\\{stop\_flag}$ \1\&{then}\6
+\&{begin} \37$\|k\K\\{lig\_kern\_restart}(\\{hf})(\|q)$;\5
+$\|q\K\\{font\_info}[\|k].\\{qqqq}$;\6
+\&{end};\2\6
+\&{end};\C{now \|k is the starting address of the lig/kern program}\2\6
+\&{if} $\\{cur\_rh}<\\{non\_char}$ \1\&{then}\5
+$\\{test\_char}\K\\{cur\_rh}$\ \&{else} $\\{test\_char}\K\\{cur\_r}$;\2\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{next\_char}(\|q)=\\{test\_char}$ \1%
+\&{then}\6
+\&{if} $\\{skip\_byte}(\|q)\L\\{stop\_flag}$ \1\&{then}\6
+\&{if} $\\{cur\_rh}<\\{non\_char}$ \1\&{then}\6
+\&{begin} \37$\\{hyphen\_passed}\K\|j$;\5
+$\\{hchar}\K\\{non\_char}$;\5
+$\\{cur\_rh}\K\\{non\_char}$;\5
+\&{goto} \37\\{continue};\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{hchar}<\\{non\_char}$ \1\&{then}\6
+\&{if} $\\{odd}(\\{hyf}[\|j])$ \1\&{then}\6
+\&{begin} \37$\\{hyphen\_passed}\K\|j$;\5
+$\\{hchar}\K\\{non\_char}$;\6
+\&{end};\2\2\6
+\&{if} $\\{op\_byte}(\|q)<\\{kern\_flag}$ \1\&{then}\5
+\X922:Carry out a ligature replacement, updating the cursor structure and
+possibly advancing~\|j; \&{goto} \\{continue} if the cursor doesn't advance,
+otherwise \&{goto} \\{done}\X;\2\6
+$\|w\K\\{char\_kern}(\\{hf})(\|q)$;\5
+\&{goto} \37\\{done};\C{this kern will be inserted below}\6
+\&{end};\2\2\2\6
+\&{if} $\\{skip\_byte}(\|q)\G\\{stop\_flag}$ \1\&{then}\6
+\&{if} $\\{cur\_rh}=\\{non\_char}$ \1\&{then}\5
+\&{goto} \37\\{done}\6
+\4\&{else} \&{begin} \37$\\{cur\_rh}\K\\{non\_char}$;\5
+\&{goto} \37\\{continue};\6
+\&{end};\2\2\6
+$\|k\K\|k+\\{qo}(\\{skip\_byte}(\|q))+1$;\5
+$\|q\K\\{font\_info}[\|k].\\{qqqq}$;\6
+\&{end};\2\6
+\4\\{done}: \37\par
+\U917.\fi
+
+\M921. \P\D \37$\\{wrap\_lig}(\#)\S$\1\6
+\&{if} $\\{ligature\_present}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{new\_ligature}(\\{hf},\39\\{cur\_l},\39\\{link}(\\{cur%
+\_q}))$;\6
+\&{if} $\\{lft\_hit}$ \1\&{then}\6
+\&{begin} \37$\\{subtype}(\|p)\K2$;\5
+$\\{lft\_hit}\K\\{false}$;\6
+\&{end};\2\6
+\&{if} $\#$ \1\&{then}\6
+\&{if} $\\{lig\_stack}=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{incr}(\\{subtype}(\|p))$;\5
+$\\{rt\_hit}\K\\{false}$;\6
+\&{end};\2\2\6
+$\\{link}(\\{cur\_q})\K\|p$;\5
+$\|t\K\|p$;\5
+$\\{ligature\_present}\K\\{false}$;\6
+\&{end}\2\2\par
+\P\D \37$\\{pop\_lig\_stack}\S$\1\6
+\&{begin} \37\&{if} $\\{lig\_ptr}(\\{lig\_stack})>\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|t)\K\\{lig\_ptr}(\\{lig\_stack})$;\C{this is a
+charnode for $\\{hu}[\|j+1]$}\6
+$\|t\K\\{link}(\|t)$;\5
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+$\|p\K\\{lig\_stack}$;\5
+$\\{lig\_stack}\K\\{link}(\|p)$;\5
+$\\{free\_node}(\|p,\39\\{small\_node\_size})$;\6
+\&{if} $\\{lig\_stack}=\\{null}$ \1\&{then}\5
+\\{set\_cur\_r}\ \&{else} $\\{cur\_r}\K\\{character}(\\{lig\_stack})$;\2\6
+\&{end}\C{if \\{lig\_stack} isn't \\{null} we have $\\{cur\_rh}=\\{non\_char}$}%
+\2\par
+\Y\P$\4\X921:Append a ligature and/or kern to the translation; \&{goto} %
+\\{continue} if the stack of inserted ligatures is nonempty\X\S$\6
+$\\{wrap\_lig}(\\{rt\_hit})$;\6
+\&{if} $\|w\I0$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|t)\K\\{new\_kern}(\|w)$;\5
+$\|t\K\\{link}(\|t)$;\5
+$\|w\K0$;\6
+\&{end};\2\6
+\&{if} $\\{lig\_stack}>\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_q}\K\|t$;\5
+$\\{cur\_l}\K\\{character}(\\{lig\_stack})$;\5
+$\\{ligature\_present}\K\\{true}$;\5
+\\{pop\_lig\_stack};\5
+\&{goto} \37\\{continue};\6
+\&{end}\2\par
+\U917.\fi
+
+\M922. \P$\X922:Carry out a ligature replacement, updating the cursor structure
+and possibly advancing~\|j; \&{goto} \\{continue} if the cursor doesn't
+advance, otherwise \&{goto} \\{done}\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_l}=\\{non\_char}$ \1\&{then}\5
+$\\{lft\_hit}\K\\{true}$;\2\6
+\&{if} $\|j=\|n$ \1\&{then}\6
+\&{if} $\\{lig\_stack}=\\{null}$ \1\&{then}\5
+$\\{rt\_hit}\K\\{true}$;\2\2\6
+\\{check\_interrupt};\C{allow a way out in case there's an infinite ligature
+loop}\6
+\&{case} $\\{op\_byte}(\|q)$ \1\&{of}\6
+\4$\\{qi}(1),\39\\{qi}(5)$: \37\&{begin} \37$\\{cur\_l}\K\\{rem\_byte}(\|q)$;%
+\C{\.{=:\?}, \.{=:\?>}}\6
+$\\{ligature\_present}\K\\{true}$;\6
+\&{end};\6
+\4$\\{qi}(2),\39\\{qi}(6)$: \37\&{begin} \37$\\{cur\_r}\K\\{rem\_byte}(\|q)$;%
+\C{\.{\?=:}, \.{\?=:>}}\6
+\&{if} $\\{lig\_stack}>\\{null}$ \1\&{then}\5
+$\\{character}(\\{lig\_stack})\K\\{cur\_r}$\6
+\4\&{else} \&{begin} \37$\\{lig\_stack}\K\\{new\_lig\_item}(\\{cur\_r})$;\6
+\&{if} $\|j=\|n$ \1\&{then}\5
+$\\{bchar}\K\\{non\_char}$\6
+\4\&{else} \&{begin} \37$\|p\K\\{get\_avail}$;\5
+$\\{lig\_ptr}(\\{lig\_stack})\K\|p$;\5
+$\\{character}(\|p)\K\\{qi}(\\{hu}[\|j+1])$;\5
+$\\{font}(\|p)\K\\{hf}$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\6
+\4$\\{qi}(3)$: \37\&{begin} \37$\\{cur\_r}\K\\{rem\_byte}(\|q)$;\C{\.{\?=:\?}}\6
+$\|p\K\\{lig\_stack}$;\5
+$\\{lig\_stack}\K\\{new\_lig\_item}(\\{cur\_r})$;\5
+$\\{link}(\\{lig\_stack})\K\|p$;\6
+\&{end};\6
+\4$\\{qi}(7),\39\\{qi}(11)$: \37\&{begin} \37$\\{wrap\_lig}(\\{false})$;\C{\.{%
+\?=:\?>}, \.{\?=:\?>>}}\6
+$\\{cur\_q}\K\|t$;\5
+$\\{cur\_l}\K\\{rem\_byte}(\|q)$;\5
+$\\{ligature\_present}\K\\{true}$;\6
+\&{end};\6
+\4\&{othercases} \37\&{begin} \37$\\{cur\_l}\K\\{rem\_byte}(\|q)$;\5
+$\\{ligature\_present}\K\\{true}$;\C{\.{=:}}\6
+\&{if} $\\{lig\_stack}>\\{null}$ \1\&{then}\5
+\\{pop\_lig\_stack}\6
+\4\&{else} \&{if} $\|j=\|n$ \1\&{then}\5
+\&{goto} \37\\{done}\6
+\4\&{else} \&{begin} \37$\\{append\_charnode\_to\_t}(\\{cur\_r})$;\5
+$\\{incr}(\|j)$;\5
+\\{set\_cur\_r};\6
+\&{end};\2\2\6
+\&{end}\2\6
+\&{endcases};\6
+\&{if} $\\{op\_byte}(\|q)>\\{qi}(4)$ \1\&{then}\6
+\&{if} $\\{op\_byte}(\|q)\I\\{qi}(7)$ \1\&{then}\5
+\&{goto} \37\\{done};\2\2\6
+\&{goto} \37\\{continue};\6
+\&{end}\par
+\U920.\fi
+
+\M923. Okay, we're ready to insert the potential hyphenations that were found.
+When the following program is executed, we want to append the word
+$\\{hu}[1\to\\{hn}]$ after node \\{ha}, and node \|q should be appended to the
+result.
+During this process, the variable \|i will be a temporary
+index into \\{hu}; the variable \|j will be an index to our current position
+in \\{hu}; the variable \|l will be the counterpart of \|j, in a discretionary
+branch; the variable \|r will point to new nodes being created; and
+we need a few new local variables:
+
+\Y\P$\4\X912:Local variables for hyphenation\X\mathrel{+}\S$\6
+\4$\\{major\_tail},\39\\{minor\_tail}$: \37\\{pointer};\C{the end of lists in
+the main and   discretionary branches being reconstructed}\6
+\4\|c: \37\\{ASCII\_code};\C{character temporarily replaced by a hyphen}\6
+\4\\{c\_loc}: \37$0\to63$;\C{where that character came from}\6
+\4\\{r\_count}: \37\\{integer};\C{replacement count for discretionary}\6
+\4\\{hyf\_node}: \37\\{pointer};\C{the hyphen, if it exists}\par
+\fi
+
+\M924. When the following code is performed, $\\{hyf}[0]$ and $\\{hyf}[\\{hn}]$
+will be zero.
+
+\Y\P$\4\X924:Reconstitute nodes for the hyphenated word, inserting
+discretionary hyphens\X\S$\6
+\1\&{repeat} \37$\|l\K\|j$;\5
+$\|j\K\\{reconstitute}(\|j,\39\\{hn},\39\\{bchar},\39\\{qi}(\\{hyf\_char}))+1$;%
+\6
+\&{if} $\\{hyphen\_passed}=0$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|s)\K\\{link}(\\{hold\_head})$;\6
+\&{while} $\\{link}(\|s)>\\{null}$ \1\&{do}\5
+$\|s\K\\{link}(\|s)$;\2\6
+\&{if} $\\{odd}(\\{hyf}[\|j-1])$ \1\&{then}\6
+\&{begin} \37$\|l\K\|j$;\5
+$\\{hyphen\_passed}\K\|j-1$;\5
+$\\{link}(\\{hold\_head})\K\\{null}$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{hyphen\_passed}>0$ \1\&{then}\5
+\X925:Create and append a discretionary node as an alternative to the
+unhyphenated word, and continue to develop both branches until they become
+equivalent\X;\2\6
+\4\&{until}\5
+$\|j>\\{hn}$;\2\6
+$\\{link}(\|s)\K\|q$\par
+\U914.\fi
+
+\M925. In this repeat loop we will insert another discretionary if $\\{hyf}[%
+\|j-1]$ is
+odd, when both branches of the previous discretionary end at position $\|j-1$.
+Strictly speaking, we aren't justified in doing this, because we don't know
+that a hyphen after $\|j-1$ is truly independent of those branches. But in
+almost
+all applications we would rather not lose a potentially valuable hyphenation
+point. (Consider the word `difficult', where the letter `c' is in position %
+\|j.)
+
+\Y\P\D \37$\\{advance\_major\_tail}\S$\1\6
+\&{begin} \37$\\{major\_tail}\K\\{link}(\\{major\_tail})$;\5
+$\\{incr}(\\{r\_count})$;\6
+\&{end}\2\par
+\Y\P$\4\X925:Create and append a discretionary node as an alternative to the
+unhyphenated word, and continue to develop both branches until they become
+equivalent\X\S$\6
+\1\&{repeat} \37$\|r\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{link}(\|r)\K\\{link}(\\{hold\_head})$;\5
+$\\{type}(\|r)\K\\{disc\_node}$;\5
+$\\{major\_tail}\K\|r$;\5
+$\\{r\_count}\K0$;\6
+\&{while} $\\{link}(\\{major\_tail})>\\{null}$ \1\&{do}\5
+\\{advance\_major\_tail};\2\6
+$\|i\K\\{hyphen\_passed}$;\5
+$\\{hyf}[\|i]\K0$;\5
+\X926:Put the \(c)characters $\\{hu}[\|l\to\|i]$ and a hyphen into $\\{pre%
+\_break}(\|r)$\X;\6
+\X927:Put the \(c)characters $\\{hu}[\|i+1\to\,]$ into $\\{post\_break}(\|r)$,
+appending to this list and to \\{major\_tail} until synchronization has been
+achieved\X;\6
+\X929:Move pointer \|s to the end of the current list, and set $\\{replace%
+\_count}(\|r)$ appropriately\X;\6
+$\\{hyphen\_passed}\K\|j-1$;\5
+$\\{link}(\\{hold\_head})\K\\{null}$;\6
+\4\&{until}\5
+$\R\\{odd}(\\{hyf}[\|j-1])$\2\par
+\U924.\fi
+
+\M926. The new hyphen might combine with the previous character via ligature
+or kern. At this point we have $\|l-1\L\|i<\|j$ and $\|i<\\{hn}$.
+
+\Y\P$\4\X926:Put the \(c)characters $\\{hu}[\|l\to\|i]$ and a hyphen into $%
+\\{pre\_break}(\|r)$\X\S$\6
+$\\{minor\_tail}\K\\{null}$;\5
+$\\{pre\_break}(\|r)\K\\{null}$;\5
+$\\{hyf\_node}\K\\{new\_character}(\\{hf},\39\\{hyf\_char})$;\6
+\&{if} $\\{hyf\_node}\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{incr}(\|i)$;\5
+$\|c\K\\{hu}[\|i]$;\5
+$\\{hu}[\|i]\K\\{hyf\_char}$;\5
+$\\{free\_avail}(\\{hyf\_node})$;\6
+\&{end};\2\6
+\&{while} $\|l\L\|i$ \1\&{do}\6
+\&{begin} \37$\|l\K\\{reconstitute}(\|l,\39\|i,\39\\{font\_bchar}[\\{hf}],\39%
+\\{non\_char})+1$;\6
+\&{if} $\\{link}(\\{hold\_head})>\\{null}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{minor\_tail}=\\{null}$ \1\&{then}\5
+$\\{pre\_break}(\|r)\K\\{link}(\\{hold\_head})$\6
+\4\&{else} $\\{link}(\\{minor\_tail})\K\\{link}(\\{hold\_head})$;\2\6
+$\\{minor\_tail}\K\\{link}(\\{hold\_head})$;\6
+\&{while} $\\{link}(\\{minor\_tail})>\\{null}$ \1\&{do}\5
+$\\{minor\_tail}\K\\{link}(\\{minor\_tail})$;\2\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{hyf\_node}\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{hu}[\|i]\K\|c$;\C{restore the character in the hyphen
+position}\6
+$\|l\K\|i$;\5
+$\\{decr}(\|i)$;\6
+\&{end}\2\par
+\U925.\fi
+
+\M927. The synchronization algorithm begins with $\|l=\|i+1\L\|j$.
+
+\Y\P$\4\X927:Put the \(c)characters $\\{hu}[\|i+1\to\,]$ into $\\{post\_break}(%
+\|r)$, appending to this list and to \\{major\_tail} until synchronization has
+been achieved\X\S$\6
+$\\{minor\_tail}\K\\{null}$;\5
+$\\{post\_break}(\|r)\K\\{null}$;\5
+$\\{c\_loc}\K0$;\6
+\&{if} $\\{bchar\_label}[\\{hf}]\I\\{non\_address}$ \1\&{then}\C{put left
+boundary at beginning of new line}\6
+\&{begin} \37$\\{decr}(\|l)$;\5
+$\|c\K\\{hu}[\|l]$;\5
+$\\{c\_loc}\K\|l$;\5
+$\\{hu}[\|l]\K256$;\6
+\&{end};\2\6
+\&{while} $\|l<\|j$ \1\&{do}\6
+\&{begin} \37\1\&{repeat} \37$\|l\K\\{reconstitute}(\|l,\39\\{hn},\39\\{bchar},%
+\39\\{non\_char})+1$;\6
+\&{if} $\\{c\_loc}>0$ \1\&{then}\6
+\&{begin} \37$\\{hu}[\\{c\_loc}]\K\|c$;\5
+$\\{c\_loc}\K0$;\6
+\&{end};\2\6
+\&{if} $\\{link}(\\{hold\_head})>\\{null}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{minor\_tail}=\\{null}$ \1\&{then}\5
+$\\{post\_break}(\|r)\K\\{link}(\\{hold\_head})$\6
+\4\&{else} $\\{link}(\\{minor\_tail})\K\\{link}(\\{hold\_head})$;\2\6
+$\\{minor\_tail}\K\\{link}(\\{hold\_head})$;\6
+\&{while} $\\{link}(\\{minor\_tail})>\\{null}$ \1\&{do}\5
+$\\{minor\_tail}\K\\{link}(\\{minor\_tail})$;\2\6
+\&{end};\2\6
+\4\&{until}\5
+$\|l\G\|j$;\2\6
+\&{while} $\|l>\|j$ \1\&{do}\5
+\X928:Append characters of $\\{hu}[\|j\to\,]$ to \\{major\_tail}, advancing~\|j%
+\X;\2\6
+\&{end}\2\par
+\U925.\fi
+
+\M928. \P$\X928:Append characters of $\\{hu}[\|j\to\,]$ to \\{major\_tail},
+advancing~\|j\X\S$\6
+\&{begin} \37$\|j\K\\{reconstitute}(\|j,\39\\{hn},\39\\{bchar},\39\\{non%
+\_char})+1$;\5
+$\\{link}(\\{major\_tail})\K\\{link}(\\{hold\_head})$;\6
+\&{while} $\\{link}(\\{major\_tail})>\\{null}$ \1\&{do}\5
+\\{advance\_major\_tail};\2\6
+\&{end}\par
+\U927.\fi
+
+\M929. Ligature insertion can cause a word to grow exponentially in size.
+Therefore
+we must test the size of \\{r\_count} here, even though the hyphenated text
+was at most 63 characters long.
+
+\Y\P$\4\X929:Move pointer \|s to the end of the current list, and set $%
+\\{replace\_count}(\|r)$ appropriately\X\S$\6
+\&{if} $\\{r\_count}>127$ \1\&{then}\C{we have to forget the discretionary
+hyphen}\6
+\&{begin} \37$\\{link}(\|s)\K\\{link}(\|r)$;\5
+$\\{link}(\|r)\K\\{null}$;\5
+$\\{flush\_node\_list}(\|r)$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{link}(\|s)\K\|r$;\5
+$\\{replace\_count}(\|r)\K\\{r\_count}$;\6
+\&{end};\2\6
+$\|s\K\\{major\_tail}$\par
+\U925.\fi
+
+\N930.  \[42] Hyphenation.
+When a word $\\{hc}[1\to\\{hn}]$ has been set up to contain a candidate for
+hyphenation,
+\TeX\ first looks to see if it is in the user's exception dictionary. If not,
+hyphens are inserted based on patterns that appear within the given word,
+using an algorithm due to Frank~M. Liang.
+
+Let's consider Liang's method first, since it is much more interesting than the
+exception-lookup routine.  The algorithm begins by setting $\\{hyf}[\|j]$ to
+zero
+for all \|j, and invalid characters are inserted into $\\{hc}[0]$
+and $\\{hc}[\\{hn}+1]$ to serve as delimiters. Then a reasonably fast method is
+used to see which of a given set of patterns occurs in the word
+$\\{hc}[0\to(\\{hn}+1)]$. Each pattern $p_1\ldots p_k$ of length \|k has an
+associated
+sequence of $\|k+1$ numbers $n_0\ldots n_k$; and if the pattern occurs in
+$\\{hc}[(\|j+1)\to(\|j+\|k)]$, \TeX\ will set $\\{hyf}[\|j+\|i]\K\hbox{max}(%
+\\{hyf}[\|j+\|i],\hbox{$n_i$})$ for
+$0\L\|i\L\|k$. After this has been done for each pattern that occurs, a
+discretionary hyphen will be inserted between $\\{hc}[\|j]$ and $\\{hc}[\|j+1]$
+when
+$\\{hyf}[\|j]$ is odd, as we have already seen.
+
+The set of patterns $p_1\ldots p_k$ and associated numbers $n_0\ldots n_k$
+depends, of course, on the language whose words are being hyphenated, and
+on the degree of hyphenation that is desired. A method for finding
+appropriate \|p's and \|n's, from a given dictionary of words and acceptable
+hyphenations, is discussed in Liang's Ph.D. thesis (Stanford University,
+1983); \TeX\ simply starts with the patterns and works from there.
+
+\fi
+
+\M931. The patterns are stored in a compact table that is also efficient for
+retrieval, using a variant of ``trie memory'' [cf.\ {\sl The Art of
+Computer Programming \bf3} (1973), 481--505]. We can find each pattern
+$p_1\ldots p_k$ by letting $z_0$ be one greater than the relevant language
+index and then, for $1\L\|i\L\|k$,
+setting $\hbox{$z_i$}\K\\{trie\_link}\hbox{$(z_{i-1})+p_i$}$; the pattern will
+be
+identified by the number $z_k$. Since all the pattern information is
+packed together into a single \\{trie\_link} array, it is necessary to
+prevent confusion between the data from inequivalent patterns, so another
+table is provided such that \\{trie\_char}\hbox{$(z_i)=p_i$} for all \|i. There
+is also a table \\{trie\_op}$(z_k)$ to identify the numbers $n_0\ldots n_k$
+associated with $p_1\ldots p_k$.
+
+The theory that comparatively few different number sequences $n_0\ldots n_k$
+actually occur, since most of the \|n's are generally zero, seems to fail
+at least for the large German hyphenation patterns.
+Therefore the number sequences cannot any longer be encoded in such a way
+that \\{trie\_op}$(z_k)$ is only one byte long.
+We have introduced a new constant \\{max\_trie\_op} for the maximum allowable
+hyphenation operation code value; \\{max\_trie\_op} might be different for
+\TeX\ and \.{INITEX} and must not exceed \\{max\_halfword}.
+An opcode will occupy a halfword if \\{max\_trie\_op} exceeds \\{max%
+\_quarterword}
+or a quarterword otherwise.
+If $\\{trie\_op}(\hbox{$z_k$})\I\\{min\_trie\_op}$, when $p_1\ldots p_k$ has
+matched
+the letters in $\\{hc}[(\|l-\|k+1)\to\|l\,]$ of language \|t,
+we perform all of the required operations
+for this pattern by carrying out the following little program: Set
+$\|v\K\\{trie\_op}(\hbox{$z_k$})$. Then set $\|v\K\|v+\\{op\_start}[\|t]$,
+$\\{hyf}[\|l-\\{hyf\_distance}[\|v]]\K\hbox{max}(\\{hyf}[\|l-\\{hyf\_distance}[%
+\|v]],\\{hyf\_num}[\|v])$,
+and $\|v\K\\{hyf\_next}[\|v]$; repeat, if necessary, until $\|v=\\{min\_trie%
+\_op}$.
+
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{trie\_pointer}=0\to\\{ssup\_trie\_size}$;\C{an index into \\{trie}}\6
+$\\{trie\_opcode}=0\to\\{ssup\_trie\_opcode}$;\C{a trie opcode}\par
+\fi
+
+\M932. For more than 255 trie op codes, the three fields \\{trie\_link}, %
+\\{trie\_char},
+and \\{trie\_op} will no longer fit into one memory word; thus using web2c
+we define \\{trie} as three array instead of an array of records.
+The variant will be implented by reusing the opcode field later on with
+another macro.
+
+\Y\P\D \37$\\{trie\_link}(\#)\S\\{trie\_trl}[\#]$\C{``downward'' link in a
+trie}\par
+\P\D \37$\\{trie\_char}(\#)\S\\{trie\_trc}[\#]$\C{character matched at this
+trie location}\par
+\P\D \37$\\{trie\_op}(\#)\S\\{trie\_tro}[\#]$\C{program for hyphenation at this
+trie location}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\C{We will dynamically allocate these arrays.}\6
+\4\\{trie\_trl}: \37$\^\\{trie\_pointer}$;\C{\\{trie\_link}}\6
+\4\\{trie\_tro}: \37$\^\\{trie\_pointer}$;\C{\\{trie\_op}}\6
+\4\\{trie\_trc}: \37$\^\\{quarterword}$;\C{\\{trie\_char}}\6
+\4\\{hyf\_distance}: \37\&{array} $[1\to\\{trie\_op\_size}]$ \1\&{of}\5
+\\{small\_number};\C{position $\|k-\|j$ of $n_j$}\2\6
+\4\\{hyf\_num}: \37\&{array} $[1\to\\{trie\_op\_size}]$ \1\&{of}\5
+\\{small\_number};\C{value of $n_j$}\2\6
+\4\\{hyf\_next}: \37\&{array} $[1\to\\{trie\_op\_size}]$ \1\&{of}\5
+\\{trie\_opcode};\C{continuation code}\2\6
+\4\\{op\_start}: \37\&{array} $[\\{ASCII\_code}]$ \1\&{of}\5
+$0\to\\{trie\_op\_size}$;\C{offset for current language}\2\par
+\fi
+
+\M933. \P$\X912:Local variables for hyphenation\X\mathrel{+}\S$\6
+\4\|z: \37\\{trie\_pointer};\C{an index into \\{trie}}\6
+\4\|v: \37\\{integer};\C{an index into \\{hyf\_distance}, etc.}\par
+\fi
+
+\M934. Assuming that these auxiliary tables have been set up properly, the
+hyphenation algorithm is quite short. In the following code we set $\\{hc}[%
+\\{hn}+2]$
+to the impossible value 256, in order to guarantee that $\\{hc}[\\{hn}+3]$ will
+never be fetched.
+
+\Y\P$\4\X934:Find hyphen locations for the word in \\{hc}, or \&{return}\X\S$\6
+\&{for} $\|j\K0\mathrel{\&{to}}\\{hn}$ \1\&{do}\5
+$\\{hyf}[\|j]\K0$;\2\6
+\X941:Look for the word $\\{hc}[1\to\\{hn}]$ in the exception table, and %
+\&{goto} \\{found} (with \\{hyf} containing the hyphens) if an entry is found%
+\X;\6
+\&{if} $\\{trie\_char}(\\{cur\_lang}+1)\I\\{qi}(\\{cur\_lang})$ \1\&{then}\5
+\&{return};\C{no patterns for \\{cur\_lang}}\2\6
+$\\{hc}[0]\K0$;\5
+$\\{hc}[\\{hn}+1]\K0$;\5
+$\\{hc}[\\{hn}+2]\K256$;\C{insert delimiters}\6
+\&{for} $\|j\K0\mathrel{\&{to}}\\{hn}-\\{r\_hyf}+1$ \1\&{do}\6
+\&{begin} \37$\|z\K\\{trie\_link}(\\{cur\_lang}+1)+\\{hc}[\|j]$;\5
+$\|l\K\|j$;\6
+\&{while} $\\{hc}[\|l]=\\{qo}(\\{trie\_char}(\|z))$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{trie\_op}(\|z)\I\\{min\_trie\_op}$ \1\&{then}\5
+\X935:Store \(m)maximum values in the \\{hyf} table\X;\2\6
+$\\{incr}(\|l)$;\5
+$\|z\K\\{trie\_link}(\|z)+\\{hc}[\|l]$;\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{found}: \37\&{for} $\|j\K0\mathrel{\&{to}}\\{l\_hyf}-1$ \1\&{do}\5
+$\\{hyf}[\|j]\K0$;\2\6
+\&{for} $\|j\K0\mathrel{\&{to}}\\{r\_hyf}-1$ \1\&{do}\5
+$\\{hyf}[\\{hn}-\|j]\K0$\2\par
+\U906.\fi
+
+\M935. \P$\X935:Store \(m)maximum values in the \\{hyf} table\X\S$\6
+\&{begin} \37$\|v\K\\{trie\_op}(\|z)$;\6
+\1\&{repeat} \37$\|v\K\|v+\\{op\_start}[\\{cur\_lang}]$;\5
+$\|i\K\|l-\\{hyf\_distance}[\|v]$;\6
+\&{if} $\\{hyf\_num}[\|v]>\\{hyf}[\|i]$ \1\&{then}\5
+$\\{hyf}[\|i]\K\\{hyf\_num}[\|v]$;\2\6
+$\|v\K\\{hyf\_next}[\|v]$;\6
+\4\&{until}\5
+$\|v=\\{min\_trie\_op}$;\2\6
+\&{end}\par
+\U934.\fi
+
+\M936. The exception table that is built by \TeX's \.{\\hyphenation} primitive
+is
+organized as an ordered hash table [cf.\ Amble and Knuth, {\sl The Computer
+Journal\/ \bf17} (1974), 135--142] using linear probing. If $\alpha$ and
+$\beta$ are words, we will say that $\alpha<\beta$ if $\vert\alpha\vert<
+\vert\beta\vert$ or if $\vert\alpha\vert=\vert\beta\vert$ and
+$\alpha$ is lexicographically smaller than $\beta$. (The notation $\vert
+\alpha\vert$ stands for the length of $\alpha$.) The idea of ordered hashing
+is to arrange the table so that a given word $\alpha$ can be sought by
+computing
+a hash address $h=h(\alpha)$ and then looking in table positions \|h, $\|h-1$,
+\dots, until encountering the first word $\L\alpha$. If this word is
+different from $\alpha$, we can conclude that $\alpha$ is not in the table.
+This is a clever scheme which saves the need for a hash link array.
+However, it is difficult to increase the size of the hyphen exception
+arrays. To make this easier, the ordered hash has been replaced by
+a simple hash, using an additional array \\{hyph\_link}. The value
+0 in $\\{hyph\_link}[\|k]$ means that there are no more entries corresponding
+to the specific hash chain. When $\\{hyph\_link}[\|k]>0$, the next entry in
+the hash chain is $\\{hyph\_link}[\|k]-1$. This value is used because the
+arrays start at 0.
+
+The words in the table point to lists in \\{mem} that specify hyphen positions
+in their \\{info} fields. The list for $c_1\ldots c_n$ contains the number \|k
+if
+the word $c_1\ldots c_n$ has a discretionary hyphen between $c_k$ and
+$c_{k+1}$.
+
+\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6
+$\\{hyph\_pointer}=0\to\\{ssup\_hyph\_size}$;\C{index into hyphen exceptions
+hash table;                      enlarging this requires changing (un)dump
+code}\par
+\fi
+
+\M937. \P$\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{hyph\_word}: \37$\^\\{str\_number}$;\C{exception words}\6
+\4\\{hyph\_list}: \37$\^\\{pointer}$;\C{lists of hyphen positions}\6
+\4\\{hyph\_link}: \37$\^\\{hyph\_pointer}$;\C{link array for hyphen exceptions
+hash table}\6
+\4\\{hyph\_count}: \37\\{integer};\C{the number of words in the exception
+dictionary}\6
+\4\\{hyph\_next}: \37\\{integer};\C{next free slot in hyphen exceptions hash
+table}\par
+\fi
+
+\M938. \P$\X19:Local variables for initialization\X\mathrel{+}\S$\6
+\4\|z: \37\\{hyph\_pointer};\C{runs through the exception dictionary}\par
+\fi
+
+\M939. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+\&{for} $\|z\K0\mathrel{\&{to}}\\{hyph\_size}$ \1\&{do}\6
+\&{begin} \37$\\{hyph\_word}[\|z]\K0$;\5
+$\\{hyph\_list}[\|z]\K\\{null}$;\5
+$\\{hyph\_link}[\|z]\K0$;\6
+\&{end};\2\6
+$\\{hyph\_count}\K0$;\5
+$\\{hyph\_next}\K\\{hyph\_prime}+1$;\6
+\&{if} $\\{hyph\_next}>\\{hyph\_size}$ \1\&{then}\5
+$\\{hyph\_next}\K\\{hyph\_prime}$;\2\par
+\fi
+
+\M940. The algorithm for exception lookup is quite simple, as soon as we have
+a few more local variables to work with.
+
+\Y\P$\4\X912:Local variables for hyphenation\X\mathrel{+}\S$\6
+\4\|h: \37\\{hyph\_pointer};\C{an index into \\{hyph\_word} and \\{hyph\_list}}%
+\6
+\4\|k: \37\\{str\_number};\C{an index into \\{str\_start}}\6
+\4\|u: \37\\{pool\_pointer};\C{an index into \\{str\_pool}}\par
+\fi
+
+\M941. First we compute the hash code \|h, then we search until we either
+find the word or we don't. Words from different languages are kept
+separate by appending the language code to the string.
+
+\Y\P$\4\X941:Look for the word $\\{hc}[1\to\\{hn}]$ in the exception table, and
+\&{goto} \\{found} (with \\{hyf} containing the hyphens) if an entry is found\X%
+\S$\6
+$\|h\K\\{hc}[1]$;\5
+$\\{incr}(\\{hn})$;\5
+$\\{hc}[\\{hn}]\K\\{cur\_lang}$;\6
+\&{for} $\|j\K2\mathrel{\&{to}}\\{hn}$ \1\&{do}\5
+$\|h\K(\|h+\|h+\\{hc}[\|j])\mathbin{\&{mod}}\\{hyph\_prime}$;\2\6
+\~ \1\&{loop}\ \&{begin} \37\X942:If the string $\\{hyph\_word}[\|h]$ is less
+than \(hc)$\\{hc}[1\to\\{hn}]$, \&{goto} \\{not\_found}; but if the two strings
+are equal, set \\{hyf} to the hyphen positions and \&{goto} \\{found}\X;\6
+$\|h\K\\{hyph\_link}[\|h]$;\6
+\&{if} $\|h=0$ \1\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+$\\{decr}(\|h)$;\6
+\&{end};\2\6
+\4\\{not\_found}: \37$\\{decr}(\\{hn})$\par
+\U934.\fi
+
+\M942. \P$\X942:If the string $\\{hyph\_word}[\|h]$ is less than \(hc)$\\{hc}[1%
+\to\\{hn}]$, \&{goto} \\{not\_found}; but if the two strings are equal, set %
+\\{hyf} to the hyphen positions and \&{goto} \\{found}\X\S$\6
+\C{This is now a simple hash list, not an ordered one, so the module title is
+no longer descriptive.}\6
+$\|k\K\\{hyph\_word}[\|h]$;\6
+\&{if} $\|k=0$ \1\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+\&{if} $\\{length}(\|k)=\\{hn}$ \1\&{then}\6
+\&{begin} \37$\|j\K1$;\5
+$\|u\K\\{str\_start}[\|k]$;\6
+\1\&{repeat} \37\&{if} $\\{so}(\\{str\_pool}[\|u])\I\\{hc}[\|j]$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\\{incr}(\|j)$;\5
+$\\{incr}(\|u)$;\6
+\4\&{until}\5
+$\|j>\\{hn}$;\2\6
+\X943:Insert hyphens as specified in $\\{hyph\_list}[\|h]$\X;\6
+$\\{decr}(\\{hn})$;\5
+\&{goto} \37\\{found};\6
+\&{end};\2\6
+\4\\{done}: \37\par
+\U941.\fi
+
+\M943. \P$\X943:Insert hyphens as specified in $\\{hyph\_list}[\|h]$\X\S$\6
+$\|s\K\\{hyph\_list}[\|h]$;\6
+\&{while} $\|s\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\\{hyf}[\\{info}(\|s)]\K1$;\5
+$\|s\K\\{link}(\|s)$;\6
+\&{end}\2\par
+\U942.\fi
+
+\M944. \P$\X944:Search \\{hyph\_list} for pointers to \|p\X\S$\6
+\&{for} $\|q\K0\mathrel{\&{to}}\\{hyph\_size}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{hyph\_list}[\|q]=\|p$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"HYPH("})$;\5
+$\\{print\_int}(\|q)$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\6
+\&{end}\2\par
+\U178.\fi
+
+\M945. We have now completed the hyphenation routine, so the \\{line\_break}
+procedure
+is finished at last. Since the hyphenation exception table is fresh in our
+minds, it's a good time to deal with the routine that adds new entries to it.
+
+When \TeX\ has scanned `\.{\\hyphenation}', it calls on a procedure named
+\\{new\_hyph\_exceptions} to do the right thing.
+
+\Y\P\D \37$\\{set\_cur\_lang}\S$\1\6
+\&{if} $\\{language}\L0$ \1\&{then}\5
+$\\{cur\_lang}\K0$\6
+\4\&{else} \&{if} $\\{language}>255$ \1\&{then}\5
+$\\{cur\_lang}\K0$\6
+\4\&{else} $\\{cur\_lang}\K\\{language}$\2\2\2\par
+\Y\P\4\&{procedure}\1\  \37\\{new\_hyph\_exceptions};\C{enters new exceptions}\6
+\4\&{label} \37$\\{reswitch},\39\\{exit},\39\\{found},\39\\{not\_found}$;\6
+\4\&{var} \37\|n: \37$0\to64$;\C{length of current word; not always a \\{small%
+\_number}}\6
+\|j: \37$0\to64$;\C{an index into \\{hc}}\6
+\|h: \37\\{hyph\_pointer};\C{an index into \\{hyph\_word} and \\{hyph\_list}}\6
+\|k: \37\\{str\_number};\C{an index into \\{str\_start}}\6
+\|p: \37\\{pointer};\C{head of a list of hyphen positions}\6
+\|q: \37\\{pointer};\C{used when creating a new node for list \|p}\6
+\|s: \37\\{str\_number};\C{strings being compared or stored}\6
+$\|u,\39\|v$: \37\\{pool\_pointer};\C{indices into \\{str\_pool}}\2\6
+\&{begin} \37\\{scan\_left\_brace};\C{a left brace must follow \.{%
+\\hyphenation}}\6
+\\{set\_cur\_lang};\5
+\X946:Enter as many hyphenation exceptions as are listed, until coming to a
+right brace; then \&{return}\X;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M946. \P$\X946:Enter as many hyphenation exceptions as are listed, until
+coming to a right brace; then \&{return}\X\S$\6
+$\|n\K0$;\5
+$\|p\K\\{null}$;\6
+\~ \1\&{loop}\ \&{begin} \37\\{get\_x\_token};\6
+\4\\{reswitch}: \37\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\4$\\{letter},\39\\{other\_char},\39\\{char\_given}$: \37\X948:Append a new
+letter or hyphen\X;\6
+\4\\{char\_num}: \37\&{begin} \37\\{scan\_char\_num};\5
+$\\{cur\_chr}\K\\{cur\_val}$;\5
+$\\{cur\_cmd}\K\\{char\_given}$;\5
+\&{goto} \37\\{reswitch};\6
+\&{end};\6
+\4$\\{spacer},\39\\{right\_brace}$: \37\&{begin} \37\&{if} $\|n>1$ \1\&{then}\5
+\X950:Enter a hyphenation exception\X;\2\6
+\&{if} $\\{cur\_cmd}=\\{right\_brace}$ \1\&{then}\5
+\&{return};\2\6
+$\|n\K0$;\5
+$\|p\K\\{null}$;\6
+\&{end};\6
+\4\&{othercases} \37\X947:Give improper \.{\\hyphenation} error\X\2\6
+\&{endcases};\6
+\&{end}\2\par
+\U945.\fi
+
+\M947. \P$\X947:Give improper \.{\\hyphenation} error\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Improper\ "})$;\5
+$\\{print\_esc}(\.{"hyphenation"})$;\5
+$\\{print}(\.{"\ will\ be\ flushed"})$;\5
+$\\{help2}(\.{"Hyphenation\ exceptions\ must\ contain\ only\ letters"})$\6
+$(\.{"and\ hyphens.\ But\ continue;\ I\'ll\ forgive\ and\ forget."})$;\5
+\\{error};\6
+\&{end}\par
+\U946.\fi
+
+\M948. \P$\X948:Append a new letter or hyphen\X\S$\6
+\&{if} $\\{cur\_chr}=\.{"-"}$ \1\&{then}\5
+\X949:Append the value \|n to list \|p\X\6
+\4\&{else} \&{begin} \37\&{if} $\\{lc\_code}(\\{cur\_chr})=0$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Not\ a\ letter"})$;\5
+$\\{help2}(\.{"Letters\ in\ \\hyphenation\ words\ must\ have\ \\lccode>0."})$\6
+$(\.{"Proceed;\ I\'ll\ ignore\ the\ character\ I\ just\ read."})$;\5
+\\{error};\6
+\&{end}\6
+\4\&{else} \&{if} $\|n<63$ \1\&{then}\6
+\&{begin} \37$\\{incr}(\|n)$;\5
+$\\{hc}[\|n]\K\\{lc\_code}(\\{cur\_chr})$;\6
+\&{end};\2\2\6
+\&{end}\2\par
+\U946.\fi
+
+\M949. \P$\X949:Append the value \|n to list \|p\X\S$\6
+\&{begin} \37\&{if} $\|n<63$ \1\&{then}\6
+\&{begin} \37$\|q\K\\{get\_avail}$;\5
+$\\{link}(\|q)\K\|p$;\5
+$\\{info}(\|q)\K\|n$;\5
+$\|p\K\|q$;\6
+\&{end};\2\6
+\&{end}\par
+\U948.\fi
+
+\M950. \P$\X950:Enter a hyphenation exception\X\S$\6
+\&{begin} \37$\\{incr}(\|n)$;\5
+$\\{hc}[\|n]\K\\{cur\_lang}$;\5
+$\\{str\_room}(\|n)$;\5
+$\|h\K0$;\6
+\&{for} $\|j\K1\mathrel{\&{to}}\|n$ \1\&{do}\6
+\&{begin} \37$\|h\K(\|h+\|h+\\{hc}[\|j])\mathbin{\&{mod}}\\{hyph\_prime}$;\5
+$\\{append\_char}(\\{hc}[\|j])$;\6
+\&{end};\2\6
+$\|s\K\\{make\_string}$;\5
+\X951:Insert the \(p)pair $(\|s,\|p)$ into the exception table\X;\6
+\&{end}\par
+\U946.\fi
+
+\M951. \P$\X951:Insert the \(p)pair $(\|s,\|p)$ into the exception table\X\S$\6
+\&{if} $\\{hyph\_next}\L\\{hyph\_prime}$ \1\&{then}\6
+\&{while} $(\\{hyph\_next}>0)\W(\\{hyph\_word}[\\{hyph\_next}-1]>0)$ \1\&{do}\5
+$\\{decr}(\\{hyph\_next})$;\2\2\6
+\&{if} $(\\{hyph\_count}=\\{hyph\_size})\V(\\{hyph\_next}=0)$ \1\&{then}\5
+$\\{overflow}(\.{"exception\ dictionary"},\39\\{hyph\_size})$;\2\6
+$\\{incr}(\\{hyph\_count})$;\6
+\&{while} $\\{hyph\_word}[\|h]\I0$ \1\&{do}\6
+\&{begin} \37\X952:If the string $\\{hyph\_word}[\|h]$ is less than \(or)or
+equal to \|s, interchange $(\\{hyph\_word}[\|h],\\{hyph\_list}[\|h])$ with $(%
+\|s,\|p)$\X;\6
+\&{if} $\\{hyph\_link}[\|h]=0$ \1\&{then}\6
+\&{begin} \37$\\{hyph\_link}[\|h]\K\\{hyph\_next}$;\6
+\&{if} $\\{hyph\_next}\G\\{hyph\_size}$ \1\&{then}\5
+$\\{hyph\_next}\K\\{hyph\_prime}$;\2\6
+\&{if} $\\{hyph\_next}>\\{hyph\_prime}$ \1\&{then}\5
+$\\{incr}(\\{hyph\_next})$;\2\6
+\&{end};\2\6
+$\|h\K\\{hyph\_link}[\|h]-1$;\6
+\&{end};\2\6
+\4\\{found}: \37$\\{hyph\_word}[\|h]\K\|s$;\5
+$\\{hyph\_list}[\|h]\K\|p$\par
+\U950.\fi
+
+\M952. \P$\X952:If the string $\\{hyph\_word}[\|h]$ is less than \(or)or equal
+to \|s, interchange $(\\{hyph\_word}[\|h],\\{hyph\_list}[\|h])$ with $(\|s,%
+\|p)$\X\S$\6
+\C{This is now a simple hash list, not an ordered one, so the module title is
+no longer descriptive.}\6
+$\|k\K\\{hyph\_word}[\|h]$;\6
+\&{if} $\\{length}(\|k)\I\\{length}(\|s)$ \1\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+$\|u\K\\{str\_start}[\|k]$;\5
+$\|v\K\\{str\_start}[\|s]$;\6
+\1\&{repeat} \37\&{if} $\\{str\_pool}[\|u]\I\\{str\_pool}[\|v]$ \1\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+$\\{incr}(\|u)$;\5
+$\\{incr}(\|v)$;\6
+\4\&{until}\5
+$\|u=\\{str\_start}[\|k+1]$;\C{repeat hyphenation exception; flushing old data}%
+\2\6
+\\{flush\_string};\5
+$\|s\K\\{hyph\_word}[\|h]$;\C{avoid \\{slow\_make\_string}!}\6
+$\\{decr}(\\{hyph\_count})$;\C{ We could also $\\{flush\_list}(\\{hyph\_list}[%
+\|h])$;, but it interferes   with \.{trip.log}. }\6
+\&{goto} \37\\{found};\6
+\4\\{not\_found}: \37\par
+\U951.\fi
+
+\N953.  \[43] Initializing the hyphenation tables.
+The trie for \TeX's hyphenation algorithm is built from a sequence of
+patterns following a \.{\\patterns} specification. Such a specification
+is allowed only in \.{INITEX}, since the extra memory for auxiliary tables
+and for the initialization program itself would only clutter up the
+production version of \TeX\ with a lot of deadwood.
+
+The first step is to build a trie that is linked, instead of packed
+into sequential storage, so that insertions are readily made.
+After all patterns have been processed, \.{INITEX}
+compresses the linked trie by identifying common subtries. Finally the
+trie is packed into the efficient sequential form that the hyphenation
+algorithm actually uses.
+
+\Y\P$\4\X837:Declare subprocedures for \\{line\_break}\X\mathrel{+}\S$\6
+\&{init} \37\X955:Declare procedures for preprocessing hyphenation patterns\X\6
+\&{tini}\par
+\fi
+
+\M954. Before we discuss trie building in detail, let's consider the simpler
+problem of creating the \\{hyf\_distance}, \\{hyf\_num}, and \\{hyf\_next}
+arrays.
+
+Suppose, for example, that \TeX\ reads the pattern `\.{ab2cde1}'. This is
+a pattern of length 5, with $n_0\ldots n_5=0\,0\,2\,0\,0\,1$ in the
+notation above. We want the corresponding \\{trie\_op} code \|v to have
+$\\{hyf\_distance}[\|v]=3$, $\\{hyf\_num}[\|v]=2$, and $\\{hyf\_next}[\|v]=%
+\hbox{$v^\prime$}$,
+where the auxiliary \\{trie\_op} code $v^\prime$ has
+$\\{hyf\_distance}[\hbox{$v^\prime$}]=0$, $\\{hyf\_num}[\hbox{$v^\prime$}]=1$,
+and
+$\\{hyf\_next}[\hbox{$v^\prime$}]=\\{min\_trie\_op}$.
+
+\TeX\ computes an appropriate value \|v with the \\{new\_trie\_op} subroutine
+below, by setting
+$$\hbox{$\hbox{$v^\prime$}\K\\{new\_trie\_op}(0,1,\\{min\_trie\_op})$,\qquad
+$\|v\K\\{new\_trie\_op}(3,2,\hbox{$v^\prime$})$.}$$
+This subroutine looks up its three
+parameters in a special hash table, assigning a new value only if these
+three have not appeared before for the current language.
+
+The hash table is called \\{trie\_op\_hash}, and the number of entries it
+contains
+is \\{trie\_op\_ptr}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\&{init} \37\\{trie\_op\_hash}: \37\&{array} $[\\{neg\_trie\_op\_size}\to%
+\\{trie\_op\_size}]$ \1\&{of}\5
+$0\to\\{trie\_op\_size}$;\C{trie op codes for quadruples}\2\6
+\4\\{trie\_used}: \37\&{array} $[\\{ASCII\_code}]$ \1\&{of}\5
+\\{trie\_opcode};\C{largest opcode used so far for this language}\2\6
+\4\\{trie\_op\_lang}: \37\&{array} $[1\to\\{trie\_op\_size}]$ \1\&{of}\5
+\\{ASCII\_code};\C{language part of a hashed quadruple}\2\6
+\4\\{trie\_op\_val}: \37\&{array} $[1\to\\{trie\_op\_size}]$ \1\&{of}\5
+\\{trie\_opcode};\C{opcode corresponding to a hashed quadruple}\2\6
+\4\\{trie\_op\_ptr}: \37$0\to\\{trie\_op\_size}$;\C{number of stored ops so
+far}\6
+\&{tini}\6
+\4\\{max\_op\_used}: \37\\{trie\_opcode};\C{largest opcode used for any
+language}\6
+\4\\{small\_op}: \37\\{boolean};\C{flag used while dumping or undumping}\par
+\fi
+
+\M955. It's tempting to remove the \\{overflow} stops in the following
+procedure;
+\\{new\_trie\_op} could return \\{min\_trie\_op} (thereby simply ignoring
+part of a hyphenation pattern) instead of aborting the job. However, that would
+lead to different hyphenation results on different installations of \TeX\
+using the same patterns. The \\{overflow} stops are necessary for portability
+of patterns.
+
+\Y\P$\4\X955:Declare procedures for preprocessing hyphenation patterns\X\S$\6
+\4\&{function}\1\  \37$\\{new\_trie\_op}(\|d,\39\|n:\\{small\_number};\,\35\|v:%
+\\{trie\_opcode})$: \37\\{trie\_opcode};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|h: \37$\\{neg\_trie\_op\_size}\to\\{trie\_op\_size}$;\C{trial
+hash location}\6
+\|u: \37\\{trie\_opcode};\C{trial op code}\6
+\|l: \37$0\to\\{trie\_op\_size}$;\C{pointer to stored data}\2\6
+\&{begin} \37$\|h\K\\{abs}(\\{intcast}(\|n)+313\ast\\{intcast}(\|d)+361\ast%
+\\{intcast}(\|v)+1009\ast\\{intcast}(\\{cur\_lang}))\mathbin{\&{mod}}(\\{trie%
+\_op\_size}-\\{neg\_trie\_op\_size})+\\{neg\_trie\_op\_size}$;\6
+\~ \1\&{loop}\ \&{begin} \37$\|l\K\\{trie\_op\_hash}[\|h]$;\6
+\&{if} $\|l=0$ \1\&{then}\C{empty position found for a new op}\6
+\&{begin} \37\&{if} $\\{trie\_op\_ptr}=\\{trie\_op\_size}$ \1\&{then}\5
+$\\{overflow}(\.{"pattern\ memory\ ops"},\39\\{trie\_op\_size})$;\2\6
+$\|u\K\\{trie\_used}[\\{cur\_lang}]$;\6
+\&{if} $\|u=\\{max\_trie\_op}$ \1\&{then}\5
+$\\{overflow}(\.{"pattern\ memory\ ops\ per\ language"},\39\\{max\_trie\_op}-%
+\\{min\_trie\_op})$;\2\6
+$\\{incr}(\\{trie\_op\_ptr})$;\5
+$\\{incr}(\|u)$;\5
+$\\{trie\_used}[\\{cur\_lang}]\K\|u$;\6
+\&{if} $\|u>\\{max\_op\_used}$ \1\&{then}\5
+$\\{max\_op\_used}\K\|u$;\2\6
+$\\{hyf\_distance}[\\{trie\_op\_ptr}]\K\|d$;\5
+$\\{hyf\_num}[\\{trie\_op\_ptr}]\K\|n$;\5
+$\\{hyf\_next}[\\{trie\_op\_ptr}]\K\|v$;\5
+$\\{trie\_op\_lang}[\\{trie\_op\_ptr}]\K\\{cur\_lang}$;\5
+$\\{trie\_op\_hash}[\|h]\K\\{trie\_op\_ptr}$;\5
+$\\{trie\_op\_val}[\\{trie\_op\_ptr}]\K\|u$;\5
+$\\{new\_trie\_op}\K\|u$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $(\\{hyf\_distance}[\|l]=\|d)\W(\\{hyf\_num}[\|l]=\|n)\W(\\{hyf\_next}[%
+\|l]=\|v)\W(\\{trie\_op\_lang}[\|l]=\\{cur\_lang})$ \1\&{then}\6
+\&{begin} \37$\\{new\_trie\_op}\K\\{trie\_op\_val}[\|l]$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $\|h>-\\{trie\_op\_size}$ \1\&{then}\5
+$\\{decr}(\|h)$\ \&{else} $\|h\K\\{trie\_op\_size}$;\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\As959, 960, 964, 968, 970, 971\ETs977.
+\U953.\fi
+
+\M956. After \\{new\_trie\_op} has compressed the necessary opcode information,
+plenty of information is available to unscramble the data into the
+final form needed by our hyphenation algorithm.
+
+\Y\P$\4\X956:Sort \(t)the hyphenation op tables into proper order\X\S$\6
+$\\{op\_start}[0]\K-\\{min\_trie\_op}$;\6
+\&{for} $\|j\K1\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{op\_start}[\|j]\K\\{op\_start}[\|j-1]+\\{qo}(\\{trie\_used}[\|j-1])$;\2\6
+\&{for} $\|j\K1\mathrel{\&{to}}\\{trie\_op\_ptr}$ \1\&{do}\5
+$\\{trie\_op\_hash}[\|j]\K\\{op\_start}[\\{trie\_op\_lang}[\|j]]+\\{trie\_op%
+\_val}[\|j]$;\C{destination}\2\6
+\&{for} $\|j\K1\mathrel{\&{to}}\\{trie\_op\_ptr}$ \1\&{do}\6
+\&{while} $\\{trie\_op\_hash}[\|j]>\|j$ \1\&{do}\6
+\&{begin} \37$\|k\K\\{trie\_op\_hash}[\|j]$;\6
+$\|t\K\\{hyf\_distance}[\|k]$;\5
+$\\{hyf\_distance}[\|k]\K\\{hyf\_distance}[\|j]$;\5
+$\\{hyf\_distance}[\|j]\K\|t$;\6
+$\|t\K\\{hyf\_num}[\|k]$;\5
+$\\{hyf\_num}[\|k]\K\\{hyf\_num}[\|j]$;\5
+$\\{hyf\_num}[\|j]\K\|t$;\6
+$\|t\K\\{hyf\_next}[\|k]$;\5
+$\\{hyf\_next}[\|k]\K\\{hyf\_next}[\|j]$;\5
+$\\{hyf\_next}[\|j]\K\|t$;\6
+$\\{trie\_op\_hash}[\|j]\K\\{trie\_op\_hash}[\|k]$;\5
+$\\{trie\_op\_hash}[\|k]\K\|k$;\6
+\&{end}\2\2\par
+\U963.\fi
+
+\M957. Before we forget how to initialize the data structures that have been
+mentioned so far, let's write down the code that gets them started.
+
+\Y\P$\4\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}\S$%
+\6
+\&{for} $\|k\K-\\{trie\_op\_size}\mathrel{\&{to}}\\{trie\_op\_size}$ \1\&{do}\5
+$\\{trie\_op\_hash}[\|k]\K0$;\2\6
+\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{trie\_used}[\|k]\K\\{min\_trie\_op}$;\2\6
+$\\{max\_op\_used}\K\\{min\_trie\_op}$;\5
+$\\{trie\_op\_ptr}\K0$;\par
+\fi
+
+\M958. The linked trie that is used to preprocess hyphenation patterns appears
+in several global arrays. Each node represents an instruction of the form
+``if you see character \|c, then perform operation \|o, move to the
+next character, and go to node \|l; otherwise go to node \|r.''
+The four quantities \|c, \|o, \|l, and \|r are stored in four arrays
+\\{trie\_c}, \\{trie\_o}, \\{trie\_l}, and \\{trie\_r}. The root of the trie
+is $\\{trie\_l}[0]$, and the number of nodes is \\{trie\_ptr}. Null trie
+pointers are represented by zero. To initialize the trie, we simply
+set $\\{trie\_l}[0]$ and \\{trie\_ptr} to zero. We also set $\\{trie\_c}[0]$ to
+some
+arbitrary value, since the algorithm may access it.
+
+The algorithms maintain the condition
+$$\hbox{$\\{trie\_c}[\\{trie\_r}[\|z]]>\\{trie\_c}[\|z]$\qquad
+whenever $\|z\I0$ and $\\{trie\_r}[\|z]\I0$};$$ in other words, sibling nodes
+are
+ordered by their \|c fields.
+
+\Y\P\D \37$\\{trie\_root}\S\\{trie\_l}[0]$\C{root of the linked trie}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\&{init} \37\\{trie\_c}: \37$\^\\{packed\_ASCII\_code}$;\C{characters to match}%
+\6
+\4\hbox{\hskip10pt}\\{trie\_o}: \37$\^\\{trie\_opcode}$;\C{operations to
+perform}\6
+\4\hbox{\hskip10pt}\\{trie\_l}: \37$\^\\{trie\_pointer}$;\C{left subtrie links}%
+\6
+\4\hbox{\hskip10pt}\\{trie\_r}: \37$\^\\{trie\_pointer}$;\C{right subtrie
+links}\6
+\4\hbox{\hskip10pt}\\{trie\_ptr}: \37\\{trie\_pointer};\C{the number of nodes
+in the trie}\6
+\4\hbox{\hskip10pt}\\{trie\_hash}: \37$\^\\{trie\_pointer}$;\C{used to identify
+equivalent subtries}\6
+\&{tini}\par
+\fi
+
+\M959. Let us suppose that a linked trie has already been constructed.
+Experience shows that we can often reduce its size by recognizing common
+subtries; therefore another hash table is introduced for this purpose,
+somewhat similar to \\{trie\_op\_hash}. The new hash table will be
+initialized to zero.
+
+The function $\\{trie\_node}(\|p)$ returns \|p if \|p is distinct from other
+nodes
+that it has seen, otherwise it returns the number of the first equivalent
+node that it has seen.
+
+Notice that we might make subtries equivalent even if they correspond to
+patterns for different languages, in which the trie ops might mean quite
+different things. That's perfectly all right.
+
+\Y\P$\4\X955:Declare procedures for preprocessing hyphenation patterns\X%
+\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{trie\_node}(\|p:\\{trie\_pointer})$: \37\\{trie%
+\_pointer};\C{converts   to a canonical form}\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|h: \37\\{trie\_pointer};\C{trial hash location}\6
+\|q: \37\\{trie\_pointer};\C{trial trie node}\2\6
+\&{begin} \37$\|h\K\\{abs}(\\{intcast}(\\{trie\_c}[\|p])+1009\ast\\{intcast}(%
+\\{trie\_o}[\|p])+\302718\ast\\{intcast}(\\{trie\_l}[\|p])+3142\ast\\{intcast}(%
+\\{trie\_r}[\|p]))\mathbin{\&{mod}}\\{trie\_size}$;\6
+\~ \1\&{loop}\ \&{begin} \37$\|q\K\\{trie\_hash}[\|h]$;\6
+\&{if} $\|q=0$ \1\&{then}\6
+\&{begin} \37$\\{trie\_hash}[\|h]\K\|p$;\5
+$\\{trie\_node}\K\|p$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $(\\{trie\_c}[\|q]=\\{trie\_c}[\|p])\W(\\{trie\_o}[\|q]=\\{trie\_o}[%
+\|p])\W\30(\\{trie\_l}[\|q]=\\{trie\_l}[\|p])\W(\\{trie\_r}[\|q]=\\{trie\_r}[%
+\|p])$ \1\&{then}\6
+\&{begin} \37$\\{trie\_node}\K\|q$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $\|h>0$ \1\&{then}\5
+$\\{decr}(\|h)$\ \&{else} $\|h\K\\{trie\_size}$;\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M960. A neat recursive procedure is now able to compress a trie by
+traversing it and applying \\{trie\_node} to its nodes in ``bottom up''
+fashion. We will compress the entire trie by clearing \\{trie\_hash} to
+zero and then saying `$\\{trie\_root}\K\\{compress\_trie}(\\{trie\_root})$'.
+
+\Y\P$\4\X955:Declare procedures for preprocessing hyphenation patterns\X%
+\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{compress\_trie}(\|p:\\{trie\_pointer})$: \37\\{trie%
+\_pointer};\2\6
+\&{begin} \37\&{if} $\|p=0$ \1\&{then}\5
+$\\{compress\_trie}\K0$\6
+\4\&{else} \&{begin} \37$\\{trie\_l}[\|p]\K\\{compress\_trie}(\\{trie\_l}[%
+\|p])$;\5
+$\\{trie\_r}[\|p]\K\\{compress\_trie}(\\{trie\_r}[\|p])$;\5
+$\\{compress\_trie}\K\\{trie\_node}(\|p)$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M961. The compressed trie will be packed into the \\{trie} array using a
+``top-down first-fit'' procedure. This is a little tricky, so the reader
+should pay close attention: The \\{trie\_hash} array is cleared to zero
+again and renamed \\{trie\_ref} for this phase of the operation; later on,
+$\\{trie\_ref}[\|p]$ will be nonzero only if the linked trie node \|p is the
+smallest character
+in a family and if the characters \|c of that family have been allocated to
+locations $\\{trie\_ref}[\|p]+\|c$ in the \\{trie} array. Locations of \\{trie}
+that
+are in use will have $\\{trie\_link}=0$, while the unused holes in \\{trie}
+will be doubly linked with \\{trie\_link} pointing to the next larger vacant
+location and \\{trie\_back} pointing to the next smaller one. This double
+linking will have been carried out only as far as \\{trie\_max}, where
+\\{trie\_max} is the largest index of \\{trie} that will be needed.
+To save time at the low end of the trie, we maintain array entries
+$\\{trie\_min}[\|c]$ pointing to the smallest hole that is greater than~\|c.
+Another array \\{trie\_taken} tells whether or not a given location is
+equal to $\\{trie\_ref}[\|p]$ for some \|p; this array is used to ensure that
+distinct nodes in the compressed trie will have distinct \\{trie\_ref}
+entries.
+
+\Y\P\D \37$\\{trie\_ref}\S\\{trie\_hash}$\C{where linked trie families go into %
+\\{trie}}\par
+\P\D \37$\\{trie\_back}(\#)\S\\{trie\_tro}[\#]$\C{use the opcode field now for
+backward links}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\&{init} \37\\{trie\_taken}: \37$\^\\{boolean}$;\C{does a family start here?}\6
+\4\hbox{\hskip10pt}\\{trie\_min}: \37\&{array} $[\\{ASCII\_code}]$ \1\&{of}\5
+\\{trie\_pointer};\C{the first possible slot for each character}\2\6
+\4\hbox{\hskip10pt}\\{trie\_max}: \37\\{trie\_pointer};\C{largest location used
+in \\{trie}}\6
+\4\hbox{\hskip10pt}\\{trie\_not\_ready}: \37\\{boolean};\C{is the trie still in
+linked form?}\6
+\&{tini}\par
+\fi
+
+\M962. Each time \.{\\patterns} appears, it contributes further patterns to
+the future trie, which will be built only when hyphenation is attempted or
+when a format file is dumped. The boolean variable \\{trie\_not\_ready}
+will change to \\{false} when the trie is compressed; this will disable
+further patterns.
+
+\Y\P$\4\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}\S$%
+\6
+$\\{trie\_not\_ready}\K\\{true}$;\par
+\fi
+
+\M963. Here is how the trie-compression data structures are initialized.
+If storage is tight, it would be possible to overlap \\{trie\_op\_hash},
+\\{trie\_op\_lang}, and \\{trie\_op\_val} with \\{trie}, \\{trie\_hash}, and %
+\\{trie\_taken},
+because we finish with the former just before we need the latter.
+
+\Y\P$\4\X963:Get ready to compress the trie\X\S$\6
+\X956:Sort \(t)the hyphenation op tables into proper order\X;\6
+\&{for} $\|p\K0\mathrel{\&{to}}\\{trie\_size}$ \1\&{do}\5
+$\\{trie\_hash}[\|p]\K0$;\2\6
+$\\{trie\_root}\K\\{compress\_trie}(\\{trie\_root})$;\C{identify equivalent
+subtries}\6
+\&{for} $\|p\K0\mathrel{\&{to}}\\{trie\_ptr}$ \1\&{do}\5
+$\\{trie\_ref}[\|p]\K0$;\2\6
+\&{for} $\|p\K0\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{trie\_min}[\|p]\K\|p+1$;\2\6
+$\\{trie\_link}(0)\K1$;\5
+$\\{trie\_max}\K0$\par
+\U977.\fi
+
+\M964. The \\{first\_fit} procedure finds the smallest hole \|z in \\{trie}
+such that
+a trie family starting at a given node \|p will fit into vacant positions
+starting at \|z. If $\|c=\\{trie\_c}[\|p]$, this means that location $\|z-\|c$
+must
+not already be taken by some other family, and that $\|z-\|c+\hbox{$c^\prime$}$
+must be vacant for all characters $c^\prime$ in the family. The procedure
+sets $\\{trie\_ref}[\|p]$ to $\|z-\|c$ when the first fit has been found.
+
+\Y\P$\4\X955:Declare procedures for preprocessing hyphenation patterns\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{first\_fit}(\|p:\\{trie\_pointer})$;\C{packs a
+family into \\{trie}}\6
+\4\&{label} \37$\\{not\_found},\39\\{found}$;\6
+\4\&{var} \37\|h: \37\\{trie\_pointer};\C{candidate for $\\{trie\_ref}[\|p]$}\6
+\|z: \37\\{trie\_pointer};\C{runs through holes}\6
+\|q: \37\\{trie\_pointer};\C{runs through the family starting at \|p}\6
+\|c: \37\\{ASCII\_code};\C{smallest character in the family}\6
+$\|l,\39\|r$: \37\\{trie\_pointer};\C{left and right neighbors}\6
+\\{ll}: \37$1\to256$;\C{upper limit of \\{trie\_min} updating}\2\6
+\&{begin} \37$\|c\K\\{so}(\\{trie\_c}[\|p])$;\5
+$\|z\K\\{trie\_min}[\|c]$;\C{get the first conceivably good hole}\6
+\~ \1\&{loop}\ \&{begin} \37$\|h\K\|z-\|c$;\6
+\X965:Ensure that $\\{trie\_max}\G\|h+256$\X;\6
+\&{if} $\\{trie\_taken}[\|h]$ \1\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+\X966:If all characters of the family fit relative to \|h, then \&{goto} %
+\\{found},\30\ otherwise \&{goto} \\{not\_found}\X;\6
+\4\\{not\_found}: \37$\|z\K\\{trie\_link}(\|z)$;\C{move to the next hole}\6
+\&{end};\2\6
+\4\\{found}: \37\X967:Pack the family into \\{trie} relative to \|h\X;\6
+\&{end};\par
+\fi
+
+\M965. By making sure that \\{trie\_max} is at least $\|h+256$, we can be sure
+that
+$\\{trie\_max}>\|z$, since $\|h=\|z-\|c$. It follows that location \\{trie%
+\_max} will
+never be occupied in \\{trie}, and we will have $\\{trie\_max}\G\\{trie\_link}(%
+\|z)$.
+
+\Y\P$\4\X965:Ensure that $\\{trie\_max}\G\|h+256$\X\S$\6
+\&{if} $\\{trie\_max}<\|h+256$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{trie\_size}\L\|h+256$ \1\&{then}\5
+$\\{overflow}(\.{"pattern\ memory"},\39\\{trie\_size})$;\2\6
+\1\&{repeat} \37$\\{incr}(\\{trie\_max})$;\5
+$\\{trie\_taken}[\\{trie\_max}]\K\\{false}$;\5
+$\\{trie\_link}(\\{trie\_max})\K\\{trie\_max}+1$;\5
+$\\{trie\_back}(\\{trie\_max})\K\\{trie\_max}-1$;\6
+\4\&{until}\5
+$\\{trie\_max}=\|h+256$;\2\6
+\&{end}\2\par
+\U964.\fi
+
+\M966. \P$\X966:If all characters of the family fit relative to \|h, then %
+\&{goto} \\{found},\30\ otherwise \&{goto} \\{not\_found}\X\S$\6
+$\|q\K\\{trie\_r}[\|p]$;\6
+\&{while} $\|q>0$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{trie\_link}(\|h+\\{so}(\\{trie\_c}[\|q]))=0$ \1\&{then}%
+\5
+\&{goto} \37\\{not\_found};\2\6
+$\|q\K\\{trie\_r}[\|q]$;\6
+\&{end};\2\6
+\&{goto} \37\\{found}\par
+\U964.\fi
+
+\M967. \P$\X967:Pack the family into \\{trie} relative to \|h\X\S$\6
+$\\{trie\_taken}[\|h]\K\\{true}$;\5
+$\\{trie\_ref}[\|p]\K\|h$;\5
+$\|q\K\|p$;\6
+\1\&{repeat} \37$\|z\K\|h+\\{so}(\\{trie\_c}[\|q])$;\5
+$\|l\K\\{trie\_back}(\|z)$;\5
+$\|r\K\\{trie\_link}(\|z)$;\5
+$\\{trie\_back}(\|r)\K\|l$;\5
+$\\{trie\_link}(\|l)\K\|r$;\5
+$\\{trie\_link}(\|z)\K0$;\6
+\&{if} $\|l<256$ \1\&{then}\6
+\&{begin} \37\&{if} $\|z<256$ \1\&{then}\5
+$\\{ll}\K\|z$\ \&{else} $\\{ll}\K256$;\2\6
+\1\&{repeat} \37$\\{trie\_min}[\|l]\K\|r$;\5
+$\\{incr}(\|l)$;\6
+\4\&{until}\5
+$\|l=\\{ll}$;\2\6
+\&{end};\2\6
+$\|q\K\\{trie\_r}[\|q]$;\6
+\4\&{until}\5
+$\|q=0$\2\par
+\U964.\fi
+
+\M968. To pack the entire linked trie, we use the following recursive
+procedure.
+
+\Y\P$\4\X955:Declare procedures for preprocessing hyphenation patterns\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{trie\_pack}(\|p:\\{trie\_pointer})$;\C{pack subtries
+of a family}\6
+\4\&{var} \37\|q: \37\\{trie\_pointer};\C{a local variable that need not be
+saved on recursive calls}\2\6
+\&{begin} \37\1\&{repeat} \37$\|q\K\\{trie\_l}[\|p]$;\6
+\&{if} $(\|q>0)\W(\\{trie\_ref}[\|q]=0)$ \1\&{then}\6
+\&{begin} \37$\\{first\_fit}(\|q)$;\5
+$\\{trie\_pack}(\|q)$;\6
+\&{end};\2\6
+$\|p\K\\{trie\_r}[\|p]$;\6
+\4\&{until}\5
+$\|p=0$;\2\6
+\&{end};\par
+\fi
+
+\M969. When the whole trie has been allocated into the sequential table, we
+must go through it once again so that \\{trie} contains the correct
+information. Null pointers in the linked trie will be represented by the
+value~0, which properly implements an ``empty'' family.
+
+\Y\P\D \37$\\{clear\_trie}\S$\C{clear $\\{trie}[\|r]$}\6
+\&{begin} \37$\\{trie\_link}(\|r)\K0$;\5
+$\\{trie\_op}(\|r)\K\\{min\_trie\_op}$;\5
+$\\{trie\_char}(\|r)\K\\{min\_quarterword}$;\C{$\\{trie\_char}\K\\{qi}(0)$}\6
+\&{end}\par
+\Y\P$\4\X969:Move the data into \\{trie}\X\S$\6
+\&{if} $\\{trie\_root}=0$ \1\&{then}\C{no patterns were given}\6
+\&{begin} \37\&{for} $\|r\K0\mathrel{\&{to}}256$ \1\&{do}\5
+\\{clear\_trie};\2\6
+$\\{trie\_max}\K256$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{trie\_fix}(\\{trie\_root})$;\C{this fixes the
+non-holes in \\{trie}}\6
+$\|r\K0$;\C{now we will zero out all the holes}\6
+\1\&{repeat} \37$\|s\K\\{trie\_link}(\|r)$;\5
+\\{clear\_trie};\5
+$\|r\K\|s$;\6
+\4\&{until}\5
+$\|r>\\{trie\_max}$;\2\6
+\&{end};\2\6
+$\\{trie\_char}(0)\K\\{qi}(\.{"?"})$;\C{make $\\{trie\_char}(\|c)\I\|c$ for all
+\|c}\par
+\U977.\fi
+
+\M970. The fixing-up procedure is, of course, recursive. Since the linked trie
+usually has overlapping subtries, the same data may be moved several
+times; but that causes no harm, and at most as much work is done as it
+took to build the uncompressed trie.
+
+\Y\P$\4\X955:Declare procedures for preprocessing hyphenation patterns\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{trie\_fix}(\|p:\\{trie\_pointer})$;\C{moves \|p and
+its siblings into \\{trie}}\6
+\4\&{var} \37\|q: \37\\{trie\_pointer};\C{a local variable that need not be
+saved on recursive calls}\6
+\|c: \37\\{ASCII\_code};\C{another one that need not be saved}\6
+\|z: \37\\{trie\_pointer};\C{\\{trie} reference; this local variable must be
+saved}\2\6
+\&{begin} \37$\|z\K\\{trie\_ref}[\|p]$;\6
+\1\&{repeat} \37$\|q\K\\{trie\_l}[\|p]$;\5
+$\|c\K\\{so}(\\{trie\_c}[\|p])$;\5
+$\\{trie\_link}(\|z+\|c)\K\\{trie\_ref}[\|q]$;\5
+$\\{trie\_char}(\|z+\|c)\K\\{qi}(\|c)$;\5
+$\\{trie\_op}(\|z+\|c)\K\\{trie\_o}[\|p]$;\6
+\&{if} $\|q>0$ \1\&{then}\5
+$\\{trie\_fix}(\|q)$;\2\6
+$\|p\K\\{trie\_r}[\|p]$;\6
+\4\&{until}\5
+$\|p=0$;\2\6
+\&{end};\par
+\fi
+
+\M971. Now let's go back to the easier problem, of building the linked
+trie.  When \.{INITEX} has scanned the `\.{\\patterns}' control
+sequence, it calls on \\{new\_patterns} to do the right thing.
+
+\Y\P$\4\X955:Declare procedures for preprocessing hyphenation patterns\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{new\_patterns};\C{initializes the hyphenation pattern
+data}\6
+\4\&{label} \37$\\{done},\39\\{done1}$;\6
+\4\&{var} \37$\|k,\39\|l$: \37$0\to64$;\C{indices into \\{hc} and \\{hyf};
+             not always in \\{small\_number} range}\6
+\\{digit\_sensed}: \37\\{boolean};\C{should the next digit be treated as a
+letter?}\6
+\|v: \37\\{trie\_opcode};\C{trie op code}\6
+$\|p,\39\|q$: \37\\{trie\_pointer};\C{nodes of trie traversed during insertion}%
+\6
+\\{first\_child}: \37\\{boolean};\C{is $\|p=\\{trie\_l}[\|q]$?}\6
+\|c: \37\\{ASCII\_code};\C{character being inserted}\2\6
+\&{begin} \37\&{if} $\\{trie\_not\_ready}$ \1\&{then}\6
+\&{begin} \37\\{set\_cur\_lang};\5
+\\{scan\_left\_brace};\C{a left brace must follow \.{\\patterns}}\6
+\X972:Enter all of the patterns into a linked trie, until coming to a right
+brace\X;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Too\ late\ for\ "})$;\5
+$\\{print\_esc}(\.{"patterns"})$;\5
+$\\{help1}(\.{"All\ patterns\ must\ be\ given\ before\ typesetting\
+begins."})$;\5
+\\{error};\5
+$\\{link}(\\{garbage})\K\\{scan\_toks}(\\{false},\39\\{false})$;\5
+$\\{flush\_list}(\\{def\_ref})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M972. Novices are not supposed to be using \.{\\patterns}, so the error
+messages are terse. (Note that all error messages appear in \TeX's string
+pool, even if they are used only by \.{INITEX}.)
+
+\Y\P$\4\X972:Enter all of the patterns into a linked trie, until coming to a
+right brace\X\S$\6
+$\|k\K0$;\5
+$\\{hyf}[0]\K0$;\5
+$\\{digit\_sensed}\K\\{false}$;\6
+\~ \1\&{loop}\ \&{begin} \37\\{get\_x\_token};\6
+\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\4$\\{letter},\39\\{other\_char}$: \37\X973:Append a new letter or a hyphen
+level\X;\6
+\4$\\{spacer},\39\\{right\_brace}$: \37\&{begin} \37\&{if} $\|k>0$ \1\&{then}\5
+\X974:Insert a new pattern into the linked trie\X;\2\6
+\&{if} $\\{cur\_cmd}=\\{right\_brace}$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\|k\K0$;\5
+$\\{hyf}[0]\K0$;\5
+$\\{digit\_sensed}\K\\{false}$;\6
+\&{end};\6
+\4\&{othercases} \37\&{begin} \37$\\{print\_err}(\.{"Bad\ "})$;\5
+$\\{print\_esc}(\.{"patterns"})$;\5
+$\\{help1}(\.{"(See\ Appendix\ H.)"})$;\5
+\\{error};\6
+\&{end}\2\6
+\&{endcases};\6
+\&{end};\2\6
+\4\\{done}: \37\par
+\U971.\fi
+
+\M973. \P$\X973:Append a new letter or a hyphen level\X\S$\6
+\&{if} $\\{digit\_sensed}\V(\\{cur\_chr}<\.{"0"})\V(\\{cur\_chr}>\.{"9"})$ \1%
+\&{then}\6
+\&{begin} \37\&{if} $\\{cur\_chr}=\.{"."}$ \1\&{then}\5
+$\\{cur\_chr}\K0$\C{edge-of-word delimiter}\6
+\4\&{else} \&{begin} \37$\\{cur\_chr}\K\\{lc\_code}(\\{cur\_chr})$;\6
+\&{if} $\\{cur\_chr}=0$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Nonletter"})$;\5
+$\\{help1}(\.{"(See\ Appendix\ H.)"})$;\5
+\\{error};\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\|k<63$ \1\&{then}\6
+\&{begin} \37$\\{incr}(\|k)$;\5
+$\\{hc}[\|k]\K\\{cur\_chr}$;\5
+$\\{hyf}[\|k]\K0$;\5
+$\\{digit\_sensed}\K\\{false}$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\|k<63$ \1\&{then}\6
+\&{begin} \37$\\{hyf}[\|k]\K\\{cur\_chr}-\.{"0"}$;\5
+$\\{digit\_sensed}\K\\{true}$;\6
+\&{end}\2\2\par
+\U972.\fi
+
+\M974. When the following code comes into play, the pattern $p_1\ldots p_k$
+appears in $\\{hc}[1\to\|k]$, and the corresponding sequence of numbers $n_0%
+\ldots
+n_k$ appears in $\\{hyf}[0\to\|k]$.
+
+\Y\P$\4\X974:Insert a new pattern into the linked trie\X\S$\6
+\&{begin} \37\X976:Compute the trie op code, \|v, and set $\|l\K0$\X;\6
+$\|q\K0$;\5
+$\\{hc}[0]\K\\{cur\_lang}$;\6
+\&{while} $\|l\L\|k$ \1\&{do}\6
+\&{begin} \37$\|c\K\\{hc}[\|l]$;\5
+$\\{incr}(\|l)$;\5
+$\|p\K\\{trie\_l}[\|q]$;\5
+$\\{first\_child}\K\\{true}$;\6
+\&{while} $(\|p>0)\W(\|c>\\{so}(\\{trie\_c}[\|p]))$ \1\&{do}\6
+\&{begin} \37$\|q\K\|p$;\5
+$\|p\K\\{trie\_r}[\|q]$;\5
+$\\{first\_child}\K\\{false}$;\6
+\&{end};\2\6
+\&{if} $(\|p=0)\V(\|c<\\{so}(\\{trie\_c}[\|p]))$ \1\&{then}\5
+\X975:Insert a new trie node between \|q and \|p, and make \|p point to it\X;\2%
+\6
+$\|q\K\|p$;\C{now node \|q represents $p_1\ldots p_{l-1}$}\6
+\&{end};\2\6
+\&{if} $\\{trie\_o}[\|q]\I\\{min\_trie\_op}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Duplicate\ pattern"})$;\5
+$\\{help1}(\.{"(See\ Appendix\ H.)"})$;\5
+\\{error};\6
+\&{end};\2\6
+$\\{trie\_o}[\|q]\K\|v$;\6
+\&{end}\par
+\U972.\fi
+
+\M975. \P$\X975:Insert a new trie node between \|q and \|p, and make \|p point
+to it\X\S$\6
+\&{begin} \37\&{if} $\\{trie\_ptr}=\\{trie\_size}$ \1\&{then}\5
+$\\{overflow}(\.{"pattern\ memory"},\39\\{trie\_size})$;\2\6
+$\\{incr}(\\{trie\_ptr})$;\5
+$\\{trie\_r}[\\{trie\_ptr}]\K\|p$;\5
+$\|p\K\\{trie\_ptr}$;\5
+$\\{trie\_l}[\|p]\K0$;\6
+\&{if} $\\{first\_child}$ \1\&{then}\5
+$\\{trie\_l}[\|q]\K\|p$\ \&{else} $\\{trie\_r}[\|q]\K\|p$;\2\6
+$\\{trie\_c}[\|p]\K\\{si}(\|c)$;\5
+$\\{trie\_o}[\|p]\K\\{min\_trie\_op}$;\6
+\&{end}\par
+\U974.\fi
+
+\M976. \P$\X976:Compute the trie op code, \|v, and set $\|l\K0$\X\S$\6
+\&{if} $\\{hc}[1]=0$ \1\&{then}\5
+$\\{hyf}[0]\K0$;\2\6
+\&{if} $\\{hc}[\|k]=0$ \1\&{then}\5
+$\\{hyf}[\|k]\K0$;\2\6
+$\|l\K\|k$;\5
+$\|v\K\\{min\_trie\_op}$;\6
+\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{hyf}[\|l]\I0$ \1\&{then}\5
+$\|v\K\\{new\_trie\_op}(\|k-\|l,\39\\{hyf}[\|l],\39\|v)$;\2\6
+\&{if} $\|l>0$ \1\&{then}\5
+$\\{decr}(\|l)$\ \&{else} \&{goto} \37\\{done1};\2\6
+\&{end};\2\6
+\4\\{done1}: \37\par
+\U974.\fi
+
+\M977. Finally we put everything together: Here is how the trie gets to its
+final, efficient form.
+The following packing routine is rigged so that the root of the linked
+tree gets mapped into location 1 of \\{trie}, as required by the hyphenation
+algorithm. This happens because the first call of \\{first\_fit} will
+``take'' location~1.
+
+\Y\P$\4\X955:Declare procedures for preprocessing hyphenation patterns\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{init\_trie};\6
+\4\&{var} \37\|p: \37\\{trie\_pointer};\C{pointer for initialization}\6
+$\|j,\39\|k,\39\|t$: \37\\{integer};\C{all-purpose registers for
+initialization}\6
+$\|r,\39\|s$: \37\\{trie\_pointer};\C{used to clean up the packed \\{trie}}\2\6
+\&{begin} \37\X963:Get ready to compress the trie\X;\6
+\&{if} $\\{trie\_root}\I0$ \1\&{then}\6
+\&{begin} \37$\\{first\_fit}(\\{trie\_root})$;\5
+$\\{trie\_pack}(\\{trie\_root})$;\6
+\&{end};\2\6
+\X969:Move the data into \\{trie}\X;\6
+$\\{trie\_not\_ready}\K\\{false}$;\6
+\&{end};\par
+\fi
+
+\N978.  \[44] Breaking vertical lists into pages.
+The \\{vsplit} procedure, which implements \TeX's \.{\\vsplit} operation,
+is considerably simpler than \\{line\_break} because it doesn't have to
+worry about hyphenation, and because its mission is to discover a single
+break instead of an optimum sequence of breakpoints.  But before we get
+into the details of \\{vsplit}, we need to consider a few more basic things.
+
+\fi
+
+\M979. A subroutine called \\{prune\_page\_top} takes a pointer to a vlist and
+returns a pointer to a modified vlist in which all glue, kern, and penalty
+nodes
+have been deleted before the first box or rule node. However, the first
+box or rule is actually preceded by a newly created glue node designed so that
+the topmost baseline will be at distance \\{split\_top\_skip} from the top,
+whenever this is possible without backspacing.
+
+In this routine and those that follow, we make use of the fact that a
+vertical list contains no character nodes, hence the \\{type} field exists
+for each node in the list.
+
+\Y\P\4\&{function}\1\  \37$\\{prune\_page\_top}(\|p:\\{pointer})$: \37%
+\\{pointer};\C{adjust top after page break}\6
+\4\&{var} \37\\{prev\_p}: \37\\{pointer};\C{lags one step behind \|p}\6
+\|q: \37\\{pointer};\C{temporary variable for list manipulation}\2\6
+\&{begin} \37$\\{prev\_p}\K\\{temp\_head}$;\5
+$\\{link}(\\{temp\_head})\K\|p$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{dir\_node},\39\\{hlist\_node},\39\\{vlist\_node},\39\\{rule\_node}$: \37%
+\X980:Insert glue for \\{split\_top\_skip} and set~$\|p\K\\{null}$\X;\6
+\4$\\{whatsit\_node},\39\\{mark\_node},\39\\{ins\_node}$: \37\&{begin} \37$%
+\\{prev\_p}\K\|p$;\5
+$\|p\K\\{link}(\\{prev\_p})$;\6
+\&{end};\6
+\4$\\{glue\_node},\39\\{kern\_node},\39\\{penalty\_node}$: \37\&{begin} \37$\|q%
+\K\|p$;\5
+$\|p\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\\{null}$;\5
+$\\{link}(\\{prev\_p})\K\|p$;\5
+$\\{flush\_node\_list}(\|q)$;\6
+\&{end};\6
+\4\&{othercases} \37$\\{confusion}(\.{"pruning"})$\2\6
+\&{endcases};\2\6
+$\\{prune\_page\_top}\K\\{link}(\\{temp\_head})$;\6
+\&{end};\par
+\fi
+
+\M980. \P$\X980:Insert glue for \\{split\_top\_skip} and set~$\|p\K\\{null}$\X%
+\S$\6
+\&{begin} \37$\|q\K\\{new\_skip\_param}(\\{split\_top\_skip\_code})$;\5
+$\\{link}(\\{prev\_p})\K\|q$;\5
+$\\{link}(\|q)\K\|p$;\C{now $\\{temp\_ptr}=\\{glue\_ptr}(\|q)$}\6
+\&{if} $\\{width}(\\{temp\_ptr})>\\{height}(\|p)$ \1\&{then}\5
+$\\{width}(\\{temp\_ptr})\K\\{width}(\\{temp\_ptr})-\\{height}(\|p)$\6
+\4\&{else} $\\{width}(\\{temp\_ptr})\K0$;\2\6
+$\|p\K\\{null}$;\6
+\&{end}\par
+\U979.\fi
+
+\M981. The next subroutine finds the best place to break a given vertical list
+so as to obtain a box of height~\|h, with maximum depth~\|d.
+A pointer to the beginning of the vertical list is given,
+and a pointer to the optimum breakpoint is returned. The list is effectively
+followed by a forced break, i.e., a penalty node with the \\{eject\_penalty};
+if the best break occurs at this artificial node, the value \\{null} is
+returned.
+
+An array of six \\{scaled} distances is used to keep track of the height
+from the beginning of the list to the current place, just as in \\{line%
+\_break}.
+In fact, we use one of the same arrays, only changing its name to reflect
+its new significance.
+
+\Y\P\D \37$\\{active\_height}\S\\{active\_width}$\C{new name for the six
+distance variables}\par
+\P\D \37$\\{cur\_height}\S\\{active\_height}[1]$\C{the natural height}\par
+\P\D \37$\\{set\_height\_zero}(\#)\S\\{active\_height}[\#]\K0$\C{initialize the
+height to zero}\Y\par
+\P\D \37$\\{update\_heights}=90$\C{go here to record glue in the \\{active%
+\_height} table}\par
+\Y\P\4\&{function}\1\  \37$\\{vert\_break}(\|p:\\{pointer};\,\35\|h,\39\|d:%
+\\{scaled})$: \37\\{pointer};\C{finds optimum page break}\6
+\4\&{label} \37$\\{done},\39\\{not\_found},\39\\{update\_heights}$;\6
+\4\&{var} \37\\{prev\_p}: \37\\{pointer};\C{if \|p is a glue node, $\\{type}(%
+\\{prev\_p})$ determines   whether \|p is a legal breakpoint}\6
+$\|q,\39\|r$: \37\\{pointer};\C{glue specifications}\6
+\\{pi}: \37\\{integer};\C{penalty value}\6
+\|b: \37\\{integer};\C{badness at a trial breakpoint}\6
+\\{least\_cost}: \37\\{integer};\C{the smallest badness plus penalties found so
+far}\6
+\\{best\_place}: \37\\{pointer};\C{the most recent break that leads to \\{least%
+\_cost}}\6
+\\{prev\_dp}: \37\\{scaled};\C{depth of previous box in the list}\6
+\|t: \37\\{small\_number};\C{\\{type} of the node following a kern}\2\6
+\&{begin} \37$\\{prev\_p}\K\|p$;\C{an initial glue node is not a legal
+breakpoint}\6
+$\\{least\_cost}\K\\{awful\_bad}$;\5
+$\\{do\_all\_six}(\\{set\_height\_zero})$;\5
+$\\{prev\_dp}\K0$;\6
+\~ \1\&{loop}\ \&{begin} \37\X983:If node \|p is a legal breakpoint, check if
+this break is the best known, and \&{goto} \\{done} if \|p is null or if the
+page-so-far is already too full to accept more stuff\X;\6
+$\\{prev\_p}\K\|p$;\5
+$\|p\K\\{link}(\\{prev\_p})$;\6
+\&{end};\2\6
+\4\\{done}: \37$\\{vert\_break}\K\\{best\_place}$;\6
+\&{end};\par
+\fi
+
+\M982. A global variable \\{best\_height\_plus\_depth} will be set to the
+natural size
+of the box that corresponds to the optimum breakpoint found by \\{vert\_break}.
+(This value is used by the insertion-splitting algorithm of the page builder.)
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{best\_height\_plus\_depth}: \37\\{scaled};\C{height of the best box,
+without stretching or   shrinking}\par
+\fi
+
+\M983. A subtle point to be noted here is that the maximum depth~\|d might be
+negative, so \\{cur\_height} and \\{prev\_dp} might need to be corrected even
+after a glue or kern node.
+
+\Y\P$\4\X983:If node \|p is a legal breakpoint, check if this break is the best
+known, and \&{goto} \\{done} if \|p is null or if the page-so-far is already
+too full to accept more stuff\X\S$\6
+\&{if} $\|p=\\{null}$ \1\&{then}\5
+$\\{pi}\K\\{eject\_penalty}$\6
+\4\&{else} \X984:Use node \|p to update the current height and depth
+measurements; if this node is not a legal breakpoint, \&{goto} \\{not\_found}
+or \\{update\_heights}, otherwise set \\{pi} to the associated penalty at the
+break\X;\2\6
+\X985:Check if node \|p is a new champion breakpoint; then \(go)\&{goto} %
+\\{done} if \|p is a forced break or if the page-so-far is already too full\X;\6
+\&{if} $(\\{type}(\|p)<\\{glue\_node})\V(\\{type}(\|p)>\\{kern\_node})$ \1%
+\&{then}\5
+\&{goto} \37\\{not\_found};\2\6
+\4\\{update\_heights}: \37\X987:Update the current height and depth
+measurements with respect to a glue or kern node~\|p\X;\6
+\4\\{not\_found}: \37\&{if} $\\{prev\_dp}>\|d$ \1\&{then}\6
+\&{begin} \37$\\{cur\_height}\K\\{cur\_height}+\\{prev\_dp}-\|d$;\5
+$\\{prev\_dp}\K\|d$;\6
+\&{end};\2\par
+\U981.\fi
+
+\M984. \P$\X984:Use node \|p to update the current height and depth
+measurements; if this node is not a legal breakpoint, \&{goto} \\{not\_found}
+or \\{update\_heights}, otherwise set \\{pi} to the associated penalty at the
+break\X\S$\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{dir\_node},\39\\{hlist\_node},\39\\{vlist\_node},\39\\{rule\_node}$: \37%
+\&{begin} \37\hbox{}\6
+$\\{cur\_height}\K\\{cur\_height}+\\{prev\_dp}+\\{height}(\|p)$;\5
+$\\{prev\_dp}\K\\{depth}(\|p)$;\5
+\&{goto} \37\\{not\_found};\6
+\&{end};\6
+\4\\{whatsit\_node}: \37\X1378:Process whatsit \|p in \\{vert\_break} loop, %
+\&{goto} \\{not\_found}\X;\6
+\4\\{glue\_node}: \37\&{if} $\\{precedes\_break}(\\{prev\_p})$ \1\&{then}\5
+$\\{pi}\K0$\6
+\4\&{else} \&{goto} \37\\{update\_heights};\2\6
+\4\\{kern\_node}: \37\&{begin} \37\&{if} $\\{link}(\|p)=\\{null}$ \1\&{then}\5
+$\|t\K\\{penalty\_node}$\6
+\4\&{else} $\|t\K\\{type}(\\{link}(\|p))$;\2\6
+\&{if} $\|t=\\{glue\_node}$ \1\&{then}\5
+$\\{pi}\K0$\ \&{else} \&{goto} \37\\{update\_heights};\2\6
+\&{end};\6
+\4\\{penalty\_node}: \37$\\{pi}\K\\{penalty}(\|p)$;\6
+\4$\\{mark\_node},\39\\{ins\_node}$: \37\&{goto} \37\\{not\_found};\6
+\4\&{othercases} \37$\\{confusion}(\.{"vertbreak"})$\2\6
+\&{endcases}\par
+\U983.\fi
+
+\M985. \P\D \37$\\{deplorable}\S100000$\C{more than \\{inf\_bad}, but less than
+\\{awful\_bad}}\par
+\Y\P$\4\X985:Check if node \|p is a new champion breakpoint; then \(go)\&{goto}
+\\{done} if \|p is a forced break or if the page-so-far is already too full\X%
+\S$\6
+\&{if} $\\{pi}<\\{inf\_penalty}$ \1\&{then}\6
+\&{begin} \37\X986:Compute the badness, \|b, using \\{awful\_bad} if the box is
+too full\X;\6
+\&{if} $\|b<\\{awful\_bad}$ \1\&{then}\6
+\&{if} $\\{pi}\L\\{eject\_penalty}$ \1\&{then}\5
+$\|b\K\\{pi}$\6
+\4\&{else} \&{if} $\|b<\\{inf\_bad}$ \1\&{then}\5
+$\|b\K\|b+\\{pi}$\6
+\4\&{else} $\|b\K\\{deplorable}$;\2\2\2\6
+\&{if} $\|b\L\\{least\_cost}$ \1\&{then}\6
+\&{begin} \37$\\{best\_place}\K\|p$;\5
+$\\{least\_cost}\K\|b$;\5
+$\\{best\_height\_plus\_depth}\K\\{cur\_height}+\\{prev\_dp}$;\6
+\&{end};\2\6
+\&{if} $(\|b=\\{awful\_bad})\V(\\{pi}\L\\{eject\_penalty})$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+\&{end}\2\par
+\U983.\fi
+
+\M986. \P$\X986:Compute the badness, \|b, using \\{awful\_bad} if the box is
+too full\X\S$\6
+\&{if} $\\{cur\_height}<\|h$ \1\&{then}\6
+\&{if} $(\\{active\_height}[3]\I0)\V(\\{active\_height}[4]\I0)\V(\\{active%
+\_height}[5]\I0)$ \1\&{then}\5
+$\|b\K0$\6
+\4\&{else} $\|b\K\\{badness}(\|h-\\{cur\_height},\39\\{active\_height}[2])$\2\6
+\4\&{else} \&{if} $\\{cur\_height}-\|h>\\{active\_height}[6]$ \1\&{then}\5
+$\|b\K\\{awful\_bad}$\6
+\4\&{else} $\|b\K\\{badness}(\\{cur\_height}-\|h,\39\\{active\_height}[6])$\2\2%
+\par
+\U985.\fi
+
+\M987. Vertical lists that are subject to the \\{vert\_break} procedure should
+not
+contain infinite shrinkability, since that would permit any amount of
+information to ``fit'' on one page.
+
+\Y\P$\4\X987:Update the current height and depth measurements with respect to a
+glue or kern node~\|p\X\S$\6
+\&{if} $\\{type}(\|p)=\\{kern\_node}$ \1\&{then}\5
+$\|q\K\|p$\6
+\4\&{else} \&{begin} \37$\|q\K\\{glue\_ptr}(\|p)$;\5
+$\\{active\_height}[2+\\{stretch\_order}(\|q)]\K\30\\{active\_height}[2+%
+\\{stretch\_order}(\|q)]+\\{stretch}(\|q)$;\6
+$\\{active\_height}[6]\K\\{active\_height}[6]+\\{shrink}(\|q)$;\6
+\&{if} $(\\{shrink\_order}(\|q)\I\\{normal})\W(\\{shrink}(\|q)\I0)$ \1\&{then}\6
+\&{begin} \37\hbox{}\6
+$\\{print\_err}(\.{"Infinite\ glue\ shrinkage\ found\ in\ box\ being\
+split"})$;\6
+$\\{help4}(\.{"The\ box\ you\ are\ \\vsplitting\ contains\ some\ infinitely"})$%
+\6
+$(\.{"shrinkable\ glue,\ e.g.,\ \`\\vss\'\ or\ \`\\vskip\ 0pt\ minus\ 1fil%
+\'."})$\6
+$(\.{"Such\ glue\ doesn\'t\ belong\ there;\ but\ you\ can\ safely\ proceed,"})$%
+\6
+$(\.{"since\ the\ offensive\ shrinkability\ has\ been\ made\ finite."})$;\5
+\\{error};\5
+$\|r\K\\{new\_spec}(\|q)$;\5
+$\\{shrink\_order}(\|r)\K\\{normal}$;\5
+$\\{delete\_glue\_ref}(\|q)$;\5
+$\\{glue\_ptr}(\|p)\K\|r$;\5
+$\|q\K\|r$;\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{cur\_height}\K\\{cur\_height}+\\{prev\_dp}+\\{width}(\|q)$;\5
+$\\{prev\_dp}\K0$\par
+\U983.\fi
+
+\M988. Now we are ready to consider \\{vsplit} itself. Most of
+its work is accomplished by the two subroutines that we have just considered.
+
+Given the number of a vlist box \|n, and given a desired page height \|h,
+the \\{vsplit} function finds the best initial segment of the vlist and
+returns a box for a page of height~\|h. The remainder of the vlist, if
+any, replaces the original box, after removing glue and penalties and
+adjusting for \\{split\_top\_skip}. Mark nodes in the split-off box are used to
+set the values of \\{split\_first\_mark} and \\{split\_bot\_mark}; we use the
+fact that $\\{split\_first\_mark}=\\{null}$ if and only if $\\{split\_bot%
+\_mark}=\\{null}$.
+
+The original box becomes ``void'' if and only if it has been entirely
+extracted.  The extracted box is ``void'' if and only if the original
+box was void (or if it was, erroneously, an hlist box).
+
+\Y\P\4\&{function}\1\  \37$\\{vsplit}(\|n:\\{eight\_bits};\,\35\|h:%
+\\{scaled})$: \37\\{pointer};\C{extracts a page of height \|h from box \|n}\6
+\4\&{label} \37$\\{exit},\39\\{done}$;\6
+\4\&{var} \37\|v: \37\\{pointer};\C{the box to be split}\6
+\|w: \37\\{pointer};\C{\\{dir\_node}}\6
+\|p: \37\\{pointer};\C{runs through the vlist}\6
+\|q: \37\\{pointer};\C{points to where the break occurs}\2\6
+\&{begin} \37$\|v\K\\{box}(\|n)$;\6
+\&{if} $\\{split\_first\_mark}\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{delete\_token\_ref}(\\{split\_first\_mark})$;\5
+$\\{split\_first\_mark}\K\\{null}$;\5
+$\\{delete\_token\_ref}(\\{split\_bot\_mark})$;\5
+$\\{split\_bot\_mark}\K\\{null}$;\6
+\&{end};\2\6
+\X989:Dispense with trivial cases of void or bad boxes\X;\6
+$\|q\K\\{vert\_break}(\\{list\_ptr}(\|v),\39\|h,\39\\{split\_max\_depth})$;\5
+\X990:Look at all the marks in nodes before the break, and set the final link
+to \\{null} at the break\X;\6
+$\|q\K\\{prune\_page\_top}(\|q)$;\5
+$\|p\K\\{list\_ptr}(\|v)$;\6
+\&{if} $\|q=\\{null}$ \1\&{then}\5
+$\\{box}(\|n)\K\\{null}$\C{the \\{eq\_level} of the box stays the same}\6
+\4\&{else} \&{begin} \37$\\{box}(\|n)\K\\{vpack}(\|q,\39\\{natural})$;\5
+$\\{set\_box\_dir}(\\{box}(\|n))(\\{box\_dir}(\|v))$;\6
+\&{end};\2\6
+$\|q\K\\{vpackage}(\|p,\39\|h,\39\\{exactly},\39\\{split\_max\_depth})$;\5
+$\\{set\_box\_dir}(\|q)(\\{box\_dir}(\|v))$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|v))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|v))$;\5
+$\\{free\_node}(\|v,\39\\{box\_node\_size})$;\5
+$\\{vsplit}\K\|q$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M989. \P$\X989:Dispense with trivial cases of void or bad boxes\X\S$\6
+\&{if} $\|v=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{vsplit}\K\\{null}$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $\\{type}(\|v)=\\{dir\_node}$ \1\&{then}\6
+\&{begin} \37$\|w\K\|v$;\5
+$\|v\K\\{list\_ptr}(\|v)$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|w))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|w))$;\5
+$\\{free\_node}(\|w,\39\\{box\_node\_size})$;\6
+\&{end};\2\6
+\&{if} $\\{type}(\|v)\I\\{vlist\_node}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{""})$;\5
+$\\{print\_esc}(\.{"vsplit"})$;\5
+$\\{print}(\.{"\ needs\ a\ "})$;\5
+$\\{print\_esc}(\.{"vbox"})$;\5
+$\\{help2}(\.{"The\ box\ you\ are\ trying\ to\ split\ is\ an\ \\hbox."})$\6
+$(\.{"I\ can\'t\ split\ such\ a\ box,\ so\ I\'ll\ leave\ it\ alone."})$;\5
+\\{error};\5
+$\\{vsplit}\K\\{null}$;\5
+\&{return};\6
+\&{end};\2\6
+$\\{flush\_node\_list}(\\{link}(\|v))$;\5
+$\\{link}(\|v)\K\\{null}$\par
+\U988.\fi
+
+\M990. It's possible that the box begins with a penalty node that is the
+``best'' break, so we must be careful to handle this special case correctly.
+
+\Y\P$\4\X990:Look at all the marks in nodes before the break, and set the final
+link to \\{null} at the break\X\S$\6
+$\|p\K\\{list\_ptr}(\|v)$;\6
+\&{if} $\|p=\|q$ \1\&{then}\5
+$\\{list\_ptr}(\|v)\K\\{null}$\6
+\4\&{else} \~ \1\&{loop}\ \&{begin} \37\&{if} $\\{type}(\|p)=\\{mark\_node}$ \1%
+\&{then}\6
+\&{if} $\\{split\_first\_mark}=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{split\_first\_mark}\K\\{mark\_ptr}(\|p)$;\5
+$\\{split\_bot\_mark}\K\\{split\_first\_mark}$;\5
+$\\{token\_ref\_count}(\\{split\_first\_mark})\K\30\\{token\_ref\_count}(%
+\\{split\_first\_mark})+2$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{delete\_token\_ref}(\\{split\_bot\_mark})$;\5
+$\\{split\_bot\_mark}\K\\{mark\_ptr}(\|p)$;\5
+$\\{add\_token\_ref}(\\{split\_bot\_mark})$;\6
+\&{end};\2\2\6
+\&{if} $\\{link}(\|p)=\|q$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|p)\K\\{null}$;\5
+\&{goto} \37\\{done};\6
+\&{end};\2\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\2\6
+\4\\{done}: \37\par
+\U988.\fi
+
+\N991.  \[45] The page builder.
+When \TeX\ appends new material to its main vlist in vertical mode, it uses
+a method something like \\{vsplit} to decide where a page ends, except that
+the calculations are done ``on line'' as new items come in.
+The main complication in this process is that insertions must be put
+into their boxes and removed from the vlist, in a more-or-less optimum manner.
+
+We shall use the term ``current page'' for that part of the main vlist that
+is being considered as a candidate for being broken off and sent to the
+user's output routine. The current page starts at $\\{link}(\\{page\_head})$,
+and
+it ends at \\{page\_tail}.  We have $\\{page\_head}=\\{page\_tail}$ if this
+list is empty.
+
+Utter chaos would reign if the user kept changing page specifications
+while a page is being constructed, so the page builder keeps the pertinent
+specifications frozen as soon as the page receives its first box or
+insertion.  The global variable \\{page\_contents} is \\{empty} when the
+current page contains only mark nodes and content-less whatsit nodes; it
+is \\{inserts\_only} if the page contains only insertion nodes in addition to
+marks and whatsits.  Glue nodes, kern nodes, and penalty nodes are
+discarded until a box or rule node appears, at which time \\{page\_contents}
+changes to \\{box\_there}.  As soon as \\{page\_contents} becomes non-%
+\\{empty},
+the current \\{vsize} and \\{max\_depth} are squirreled away into \\{page%
+\_goal}
+and \\{page\_max\_depth}; the latter values will be used until the page has
+been forwarded to the user's output routine. The \.{\\topskip} adjustment
+is made when \\{page\_contents} changes to \\{box\_there}.
+
+Although \\{page\_goal} starts out equal to \\{vsize}, it is decreased by the
+scaled natural height-plus-depth of the insertions considered so far, and by
+the \.{\\skip} corrections for those insertions. Therefore it represents
+the size into which the non-inserted material should fit, assuming that
+all insertions in the current page have been made.
+
+The global variables \\{best\_page\_break} and \\{least\_page\_cost} correspond
+respectively to the local variables \\{best\_place} and \\{least\_cost} in the
+\\{vert\_break} routine that we have already studied; i.e., they record the
+location and value of the best place currently known for breaking the
+current page. The value of \\{page\_goal} at the time of the best break is
+stored in \\{best\_size}.
+
+\Y\P\D \37$\\{inserts\_only}=1$\C{\\{page\_contents} when an insert node has
+been contributed, but no boxes}\par
+\P\D \37$\\{box\_there}=2$\C{\\{page\_contents} when a box or rule has been
+contributed}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{page\_tail}: \37\\{pointer};\C{the final node on the current page}\6
+\4\\{page\_contents}: \37$\\{empty}\to\\{box\_there}$;\C{what is on the current
+page so far?}\6
+\4\\{page\_max\_depth}: \37\\{scaled};\C{maximum box depth on page being built}%
+\6
+\4\\{best\_page\_break}: \37\\{pointer};\C{break here to get the best page
+known so far}\6
+\4\\{least\_page\_cost}: \37\\{integer};\C{the score for this currently best
+page}\6
+\4\\{best\_size}: \37\\{scaled};\C{its \\{page\_goal}}\par
+\fi
+
+\M992. The page builder has another data structure to keep track of insertions.
+This is a list of four-word nodes, starting and ending at \\{page\_ins\_head}.
+That is, the first element of the list is node $\|r\hbox{$_1$}=\\{link}(\\{page%
+\_ins\_head})$;
+node $r_j$ is followed by $\|r\hbox{$_{j+1}$}=\\{link}(\|r\hbox{$_j$})$; and if
+there are
+\|n items we have $\|r\hbox{$_{n+1}$}=\\{page\_ins\_head}$. The \\{subtype}
+field of
+each node in this list refers to an insertion number; for example, `\.{\\insert
+250}' would correspond to a node whose \\{subtype} is $\\{qi}(250)$
+(the same as the \\{subtype} field of the relevant \\{ins\_node}). These %
+\\{subtype}
+fields are in increasing order, and $\\{subtype}(\\{page\_ins\_head})=%
+\\{qi}(255)$, so \\{page\_ins\_head} serves as a convenient sentinel
+at the end of the list. A record is present for each insertion number that
+appears in the current page.
+
+The \\{type} field in these nodes distinguishes two possibilities that
+might occur as we look ahead before deciding on the optimum page break.
+If $\\{type}(\|r)=\\{inserting}$, then $\\{height}(\|r)$ contains the total of
+the
+height-plus-depth dimensions of the box and all its inserts seen so far.
+If $\\{type}(\|r)=\\{split\_up}$, then no more insertions will be made into
+this box,
+because at least one previous insertion was too big to fit on the current
+page; $\\{broken\_ptr}(\|r)$ points to the node where that insertion will be
+split, if \TeX\ decides to split it, $\\{broken\_ins}(\|r)$ points to the
+insertion node that was tentatively split, and $\\{height}(\|r)$ includes also
+the
+natural height plus depth of the part that would be split off.
+
+In both cases, $\\{last\_ins\_ptr}(\|r)$ points to the last \\{ins\_node}
+encountered for box $\\{qo}(\\{subtype}(\|r))$ that would be at least partially
+inserted on the next page; and $\\{best\_ins\_ptr}(\|r)$ points to the last
+such \\{ins\_node} that should actually be inserted, to get the page with
+minimum badness among all page breaks considered so far. We have
+$\\{best\_ins\_ptr}(\|r)=\\{null}$ if and only if no insertion for this box
+should
+be made to produce this optimum page.
+
+The data structure definitions here use the fact that the \\{height} field
+appears in the fourth word of a box node.
+
+\Y\P\D \37$\\{page\_ins\_node\_size}=4$\C{number of words for a page insertion
+node}\par
+\P\D \37$\\{inserting}=0$\C{an insertion class that has not yet overflowed}\par
+\P\D \37$\\{split\_up}=1$\C{an overflowed insertion class}\par
+\P\D \37$\\{broken\_ptr}(\#)\S\\{link}(\#+1)$\C{an insertion for this class
+will break here if anywhere}\par
+\P\D \37$\\{broken\_ins}(\#)\S\\{info}(\#+1)$\C{this insertion might break at %
+\\{broken\_ptr}}\par
+\P\D \37$\\{last\_ins\_ptr}(\#)\S\\{link}(\#+2)$\C{the most recent insertion
+for this \\{subtype}}\par
+\P\D \37$\\{best\_ins\_ptr}(\#)\S\\{info}(\#+2)$\C{the optimum most recent
+insertion}\par
+\Y\P$\4\X801:Initialize the special list heads and constant nodes\X\mathrel{+}%
+\S$\6
+$\\{subtype}(\\{page\_ins\_head})\K\\{qi}(255)$;\5
+$\\{type}(\\{page\_ins\_head})\K\\{split\_up}$;\5
+$\\{link}(\\{page\_ins\_head})\K\\{page\_ins\_head}$;\par
+\fi
+
+\M993. An array \\{page\_so\_far} records the heights and depths of everything
+on the current page. This array contains six \\{scaled} numbers, like the
+similar arrays already considered in \\{line\_break} and \\{vert\_break}; and
+it
+also contains \\{page\_goal} and \\{page\_depth}, since these values are
+all accessible to the user via \\{set\_page\_dimen} commands. The
+value of $\\{page\_so\_far}[1]$ is also called \\{page\_total}.  The stretch
+and shrink components of the \.{\\skip} corrections for each insertion are
+included in \\{page\_so\_far}, but the natural space components of these
+corrections are not, since they have been subtracted from \\{page\_goal}.
+
+The variable \\{page\_depth} records the depth of the current page; it has been
+adjusted so that it is at most \\{page\_max\_depth}. The variable
+\\{last\_glue} points to the glue specification of the most recent node
+contributed from the contribution list, if this was a glue node; otherwise
+$\\{last\_glue}=\\{max\_halfword}$. (If the contribution list is nonempty,
+however, the value of \\{last\_glue} is not necessarily accurate.)
+The variables \\{last\_penalty} and \\{last\_kern} are similar.  And
+finally, \\{insert\_penalties} holds the sum of the penalties associated with
+all split and floating insertions.
+
+\Y\P\D \37$\\{page\_goal}\S\\{page\_so\_far}[0]$\C{desired height of
+information on page being built}\par
+\P\D \37$\\{page\_total}\S\\{page\_so\_far}[1]$\C{height of the current page}%
+\par
+\P\D \37$\\{page\_shrink}\S\\{page\_so\_far}[6]$\C{shrinkability of the current
+page}\par
+\P\D \37$\\{page\_depth}\S\\{page\_so\_far}[7]$\C{depth of the current page}\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{page\_so\_far}: \37\&{array} $[0\to7]$ \1\&{of}\5
+\\{scaled};\C{height and glue of the current page}\2\6
+\4\\{last\_glue}: \37\\{pointer};\C{used to implement \.{\\lastskip}}\6
+\4\\{last\_penalty}: \37\\{integer};\C{used to implement \.{\\lastpenalty}}\6
+\4\\{last\_kern}: \37\\{scaled};\C{used to implement \.{\\lastkern}}\6
+\4\\{insert\_penalties}: \37\\{integer};\C{sum of the penalties for held-over
+insertions}\par
+\fi
+
+\M994. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"pagegoal"},\39\\{set\_page\_dimen},\390)$;\5
+$\\{primitive}(\.{"pagetotal"},\39\\{set\_page\_dimen},\391)$;\5
+$\\{primitive}(\.{"pagestretch"},\39\\{set\_page\_dimen},\392)$;\5
+$\\{primitive}(\.{"pagefilstretch"},\39\\{set\_page\_dimen},\393)$;\5
+$\\{primitive}(\.{"pagefillstretch"},\39\\{set\_page\_dimen},\394)$;\5
+$\\{primitive}(\.{"pagefilllstretch"},\39\\{set\_page\_dimen},\395)$;\5
+$\\{primitive}(\.{"pageshrink"},\39\\{set\_page\_dimen},\396)$;\5
+$\\{primitive}(\.{"pagedepth"},\39\\{set\_page\_dimen},\397)$;\par
+\fi
+
+\M995. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{set\_page\_dimen}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\40: \37$\\{print\_esc}(\.{"pagegoal"})$;\6
+\41: \37$\\{print\_esc}(\.{"pagetotal"})$;\6
+\42: \37$\\{print\_esc}(\.{"pagestretch"})$;\6
+\43: \37$\\{print\_esc}(\.{"pagefilstretch"})$;\6
+\44: \37$\\{print\_esc}(\.{"pagefillstretch"})$;\6
+\45: \37$\\{print\_esc}(\.{"pagefilllstretch"})$;\6
+\46: \37$\\{print\_esc}(\.{"pageshrink"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"pagedepth"})$\2\6
+\&{endcases};\par
+\fi
+
+\M996. \P\D \37$\\{print\_plus\_end}(\#)\S\\{print}(\#)$;\ \&{end} \par
+\P\D $\\{print\_plus}(\#)\S$  \6
+\&{if} $\\{page\_so\_far}[\#]\I0$ \1\&{then} \6
+\&{begin} \37$\\{print}(\.{"\ plus\ "})$;\5
+$\\{print\_scaled}(\\{page\_so\_far}[\#])$;\5
+\\{print\_plus\_end}\par
+\Y\P\4\&{procedure}\1\  \37\\{print\_totals};\2\6
+\&{begin} \37$\\{print\_scaled}(\\{page\_total})$;\5
+$\\{print\_plus}(2)(\.{""})$;\5
+$\\{print\_plus}(3)(\.{"fil"})$;\5
+$\\{print\_plus}(4)(\.{"fill"})$;\5
+$\\{print\_plus}(5)(\.{"filll"})$;\6
+\&{if} $\\{page\_shrink}\I0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ minus\ "})$;\5
+$\\{print\_scaled}(\\{page\_shrink})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M997. \P$\X997:Show the status of the current page\X\S$\6
+\&{if} $\\{page\_head}\I\\{page\_tail}$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"\#\#\#\ current\ page:"})$;\6
+\&{if} $\\{output\_active}$ \1\&{then}\5
+$\\{print}(\.{"\ (held\ over\ for\ next\ output)"})$;\2\6
+$\\{show\_box}(\\{link}(\\{page\_head}))$;\6
+\&{if} $\\{page\_contents}>\\{empty}$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"total\ height\ "})$;\5
+\\{print\_totals};\5
+$\\{print\_nl}(\.{"\ goal\ height\ "})$;\5
+$\\{print\_scaled}(\\{page\_goal})$;\5
+$\|r\K\\{link}(\\{page\_ins\_head})$;\6
+\&{while} $\|r\I\\{page\_ins\_head}$ \1\&{do}\6
+\&{begin} \37\\{print\_ln};\5
+$\\{print\_esc}(\.{"insert"})$;\5
+$\|t\K\\{qo}(\\{subtype}(\|r))$;\5
+$\\{print\_int}(\|t)$;\5
+$\\{print}(\.{"\ adds\ "})$;\6
+\&{if} $\\{count}(\|t)=1000$ \1\&{then}\5
+$\|t\K\\{height}(\|r)$\6
+\4\&{else} $\|t\K\\{x\_over\_n}(\\{height}(\|r),\391000)\ast\\{count}(\|t)$;\2\6
+$\\{print\_scaled}(\|t)$;\6
+\&{if} $\\{type}(\|r)=\\{split\_up}$ \1\&{then}\6
+\&{begin} \37$\|q\K\\{page\_head}$;\5
+$\|t\K0$;\6
+\1\&{repeat} \37$\|q\K\\{link}(\|q)$;\6
+\&{if} $(\\{type}(\|q)=\\{ins\_node})\W(\\{subtype}(\|q)=\\{subtype}(\|r))$ \1%
+\&{then}\5
+$\\{incr}(\|t)$;\2\6
+\4\&{until}\5
+$\|q=\\{broken\_ins}(\|r)$;\2\6
+$\\{print}(\.{",\ \#"})$;\5
+$\\{print\_int}(\|t)$;\5
+$\\{print}(\.{"\ might\ split"})$;\6
+\&{end};\2\6
+$\|r\K\\{link}(\|r)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end}\2\par
+\U224.\fi
+
+\M998. Here is a procedure that is called when the \\{page\_contents} is
+changing
+from \\{empty} to \\{inserts\_only} or \\{box\_there}.
+
+\Y\P\D \37$\\{set\_page\_so\_far\_zero}(\#)\S\\{page\_so\_far}[\#]\K0$\par
+\Y\P\4\&{procedure}\1\  \37$\\{freeze\_page\_specs}(\|s:\\{small\_number})$;\2\6
+\&{begin} \37$\\{page\_contents}\K\|s$;\5
+$\\{page\_goal}\K\\{vsize}$;\5
+$\\{page\_max\_depth}\K\\{max\_depth}$;\5
+$\\{page\_depth}\K0$;\5
+$\\{do\_all\_six}(\\{set\_page\_so\_far\_zero})$;\5
+$\\{least\_page\_cost}\K\\{awful\_bad}$;\6
+\&{stat} \37\&{if} $\\{tracing\_pages}>0$ \1\&{then}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"\%\%\ goal\ height="})$;\5
+$\\{print\_scaled}(\\{page\_goal})$;\5
+$\\{print}(\.{",\ max\ depth="})$;\5
+$\\{print\_scaled}(\\{page\_max\_depth})$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end};\2\ \&{tats}\6
+\&{end};\par
+\fi
+
+\M999. Pages are built by appending nodes to the current list in \TeX's
+vertical mode, which is at the outermost level of the semantic nest. This
+vlist is split into two parts; the ``current page'' that we have been
+talking so much about already, and the ``contribution list'' that receives
+new nodes as they are created.  The current page contains everything that
+the page builder has accounted for in its data structures, as described
+above, while the contribution list contains other things that have been
+generated by other parts of \TeX\ but have not yet been
+seen by the page builder.
+The contribution list starts at $\\{link}(\\{contrib\_head})$, and it ends at
+the
+current node in \TeX's vertical mode.
+
+When \TeX\ has appended new material in vertical mode, it calls the procedure
+\\{build\_page}, which tries to catch up by moving nodes from the contribution
+list to the current page. This procedure will succeed in its goal of
+emptying the contribution list, unless a page break is discovered, i.e.,
+unless the current page has grown to the point where the optimum next
+page break has been determined. In the latter case, the nodes after the
+optimum break will go back onto the contribution list, and control will
+effectively pass to the user's output routine.
+
+We make $\\{type}(\\{page\_head})=\\{glue\_node}$, so that an initial glue node
+on
+the current page will not be considered a valid breakpoint.
+
+\Y\P$\4\X801:Initialize the special list heads and constant nodes\X\mathrel{+}%
+\S$\6
+$\\{type}(\\{page\_head})\K\\{glue\_node}$;\5
+$\\{subtype}(\\{page\_head})\K\\{normal}$;\par
+\fi
+
+\M1000. The global variable \\{output\_active} is true during the time the
+user's output routine is driving \TeX.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{output\_active}: \37\\{boolean};\C{are we in the midst of an output
+routine?}\par
+\fi
+
+\M1001. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{output\_active}\K\\{false}$;\5
+$\\{insert\_penalties}\K0$;\par
+\fi
+
+\M1002. The page builder is ready to start a fresh page if we initialize
+the following state variables. (However, the page insertion list is initialized
+elsewhere.)
+
+\Y\P$\4\X1002:Start a new current page\X\S$\6
+$\\{page\_contents}\K\\{empty}$;\5
+$\\{page\_tail}\K\\{page\_head}$;\5
+$\\{link}(\\{page\_head})\K\\{null}$;\6
+$\\{last\_glue}\K\\{max\_halfword}$;\5
+$\\{last\_penalty}\K0$;\5
+$\\{last\_kern}\K0$;\5
+$\\{page\_depth}\K0$;\5
+$\\{page\_max\_depth}\K0$\par
+\U1028.\fi
+
+\M1003. At certain times box 255 is supposed to be void (i.e., \\{null}),
+or an insertion box is supposed to be ready to accept a vertical list.
+If not, an error message is printed, and the following subroutine
+flushes the unwanted contents, reporting them to the user.
+
+\Y\P\4\&{procedure}\1\  \37$\\{box\_error}(\|n:\\{eight\_bits})$;\2\6
+\&{begin} \37\\{error};\5
+\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"The\ following\ box\ has\ been\ deleted:"})$;\5
+$\\{show\_box}(\\{box}(\|n))$;\5
+$\\{end\_diagnostic}(\\{true})$;\5
+$\\{flush\_node\_list}(\\{box}(\|n))$;\5
+$\\{box}(\|n)\K\\{null}$;\6
+\&{end};\par
+\fi
+
+\M1004. The following procedure guarantees that a given box register
+does not contain an \.{\\hbox}.
+
+\Y\P\4\&{procedure}\1\  \37$\\{ensure\_vbox}(\|n:\\{eight\_bits})$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the box register contents}\2\6
+\&{begin} \37$\|p\K\\{box}(\|n)$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{if} $\\{type}(\|p)=\\{dir\_node}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{list\_ptr}(\|p)$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\\{box}(\|n)))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\\{box}(\|n)))$;\5
+$\\{free\_node}(\\{box}(\|n),\39\\{box\_node\_size})$;\5
+$\\{box}(\|n)\K\|p$\6
+\&{end};\2\2\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{if} $\\{type}(\|p)\I\\{vlist\_node}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Insertions\ can\ only\ be\ added\ to\ a\
+vbox"})$;\5
+$\\{help3}(\.{"Tut\ tut:\ You\'re\ trying\ to\ \\insert\ into\ a"})$\6
+$(\.{"\\box\ register\ that\ now\ contains\ an\ \\hbox."})$\6
+$(\.{"Proceed,\ and\ I\'ll\ discard\ its\ present\ contents."})$;\5
+$\\{box\_error}(\|n)$;\6
+\&{end};\2\2\6
+\&{end};\par
+\fi
+
+\M1005. \TeX\ is not always in vertical mode at the time \\{build\_page}
+is called; the current mode reflects what \TeX\ should return to, after
+the contribution list has been emptied. A call on \\{build\_page} should
+be immediately followed by `\&{goto} \\{big\_switch}', which is \TeX's central
+control point.
+
+\Y\P\D \37$\\{contribute}=80$\C{go here to link a node into the current page}%
+\par
+\Y\P\hbox{\4}\X1023:Declare the procedure called \\{fire\_up}\X\6
+\4\&{procedure}\1\  \37\\{build\_page};\C{append contributions to the current
+page}\6
+\4\&{label} \37$\\{exit},\39\\{done},\39\\{done1},\39\\{continue},\39%
+\\{contribute},\39\\{update\_heights}$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the node being appended}\6
+$\|q,\39\|r$: \37\\{pointer};\C{nodes being examined}\6
+$\|b,\39\|c$: \37\\{integer};\C{badness and cost of current page}\6
+\\{pi}: \37\\{integer};\C{penalty to be added to the badness}\6
+\|n: \37$\\{min\_quarterword}\to255$;\C{insertion box number}\6
+$\\{delta},\39\|h,\39\|w$: \37\\{scaled};\C{sizes used for insertion
+calculations}\2\6
+\&{begin} \37\&{if} $(\\{link}(\\{contrib\_head})=\\{null})\V\\{output%
+\_active}$ \1\&{then}\5
+\&{return};\2\6
+\1\&{repeat} \37\\{continue}: \37$\|p\K\\{link}(\\{contrib\_head})$;\6
+\X1007:Update the values of \\{last\_glue}, \\{last\_penalty}, and \\{last%
+\_kern}\X;\6
+\X1008:Move node \|p to the current page; if it is time for a page break, put
+the nodes following the break back onto the contribution list, and \&{return}
+to the user's output routine if there is one\X;\6
+\4\&{until}\5
+$\\{link}(\\{contrib\_head})=\\{null}$;\2\6
+\X1006:Make the contribution list empty by setting its tail to \\{contrib%
+\_head}\X;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1006. \P\D \37$\\{contrib\_tail}\S\\{nest}[0].\\{tail\_field}$\C{tail of the
+contribution list}\par
+\Y\P$\4\X1006:Make the contribution list empty by setting its tail to %
+\\{contrib\_head}\X\S$\6
+\&{if} $\\{nest\_ptr}=0$ \1\&{then}\5
+$\\{tail}\K\\{contrib\_head}$\C{vertical mode}\6
+\4\&{else} $\\{contrib\_tail}\K\\{contrib\_head}$\C{other modes}\2\par
+\U1005.\fi
+
+\M1007. \P$\X1007:Update the values of \\{last\_glue}, \\{last\_penalty}, and %
+\\{last\_kern}\X\S$\6
+\&{if} $\\{last\_glue}\I\\{max\_halfword}$ \1\&{then}\5
+$\\{delete\_glue\_ref}(\\{last\_glue})$;\2\6
+$\\{last\_penalty}\K0$;\5
+$\\{last\_kern}\K0$;\6
+\&{if} $\\{type}(\|p)=\\{glue\_node}$ \1\&{then}\6
+\&{begin} \37$\\{last\_glue}\K\\{glue\_ptr}(\|p)$;\5
+$\\{add\_glue\_ref}(\\{last\_glue})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{last\_glue}\K\\{max\_halfword}$;\6
+\&{if} $\\{type}(\|p)=\\{penalty\_node}$ \1\&{then}\5
+$\\{last\_penalty}\K\\{penalty}(\|p)$\6
+\4\&{else} \&{if} $\\{type}(\|p)=\\{kern\_node}$ \1\&{then}\5
+$\\{last\_kern}\K\\{width}(\|p)$;\2\2\6
+\&{end}\2\par
+\U1005.\fi
+
+\M1008. The code here is an example of a many-way switch into routines that
+merge together in different places. Some people call this unstructured
+programming, but the author doesn't see much wrong with it, as long as
+the various labels have a well-understood meaning.
+
+\Y\P$\4\X1008:Move node \|p to the current page; if it is time for a page
+break, put the nodes following the break back onto the contribution list, and %
+\&{return} to the user's output routine if there is one\X\S$\6
+\X1011:If the current page is empty and node \|p is to be deleted, \&{goto} %
+\\{done1}; otherwise use node \|p to update the state of the current page; if
+this node is an insertion, \&{goto} \\{contribute}; otherwise if this node is
+not a legal breakpoint, \&{goto} \\{contribute} or \\{update\_heights};
+otherwise set \\{pi} to the penalty associated with this breakpoint\X;\6
+\X1016:Check if node \|p is a new champion breakpoint; then \(if)if it is time
+for a page break, prepare for output, and either fire up the user's output
+routine and \&{return} or ship out the page and \&{goto} \\{done}\X;\6
+\&{if} $(\\{type}(\|p)<\\{glue\_node})\V(\\{type}(\|p)>\\{kern\_node})$ \1%
+\&{then}\5
+\&{goto} \37\\{contribute};\2\6
+\4\\{update\_heights}: \37\X1015:Update the current page measurements with
+respect to the glue or kern specified by node~\|p\X;\6
+\4\\{contribute}: \37\X1014:Make sure that \\{page\_max\_depth} is not exceeded%
+\X;\6
+\X1009:Link node \|p into the current page and \&{goto} \\{done}\X;\6
+\4\\{done1}: \37\X1010:Recycle node \|p\X;\6
+\4\\{done}: \37\par
+\U1005.\fi
+
+\M1009. \P$\X1009:Link node \|p into the current page and \&{goto} \\{done}\X%
+\S$\6
+$\\{link}(\\{page\_tail})\K\|p$;\5
+$\\{page\_tail}\K\|p$;\5
+$\\{link}(\\{contrib\_head})\K\\{link}(\|p)$;\5
+$\\{link}(\|p)\K\\{null}$;\5
+\&{goto} \37\\{done}\par
+\U1008.\fi
+
+\M1010. \P$\X1010:Recycle node \|p\X\S$\6
+$\\{link}(\\{contrib\_head})\K\\{link}(\|p)$;\5
+$\\{link}(\|p)\K\\{null}$;\5
+$\\{flush\_node\_list}(\|p)$\par
+\U1008.\fi
+
+\M1011. The title of this section is already so long, it seems best to avoid
+making it more accurate but still longer, by mentioning the fact that a
+kern node at the end of the contribution list will not be contributed until
+we know its successor.
+
+\Y\P$\4\X1011:If the current page is empty and node \|p is to be deleted, %
+\&{goto} \\{done1}; otherwise use node \|p to update the state of the current
+page; if this node is an insertion, \&{goto} \\{contribute}; otherwise if this
+node is not a legal breakpoint, \&{goto} \\{contribute} or \\{update\_heights};
+otherwise set \\{pi} to the penalty associated with this breakpoint\X\S$\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node}$: \37%
+\&{if} $\\{page\_contents}<\\{box\_there}$ \1\&{then}\5
+\X1012:Initialize the current page, insert the \.{\\topskip} glue ahead of \|p,
+and \&{goto} \\{continue}\X\6
+\4\&{else} \X1013:Prepare to move a box or rule node to the current page, then %
+\&{goto} \\{contribute}\X;\2\6
+\4\\{whatsit\_node}: \37\X1377:Prepare to move whatsit \|p to the current page,
+then \&{goto} \\{contribute}\X;\6
+\4\\{glue\_node}: \37\&{if} $\\{page\_contents}<\\{box\_there}$ \1\&{then}\5
+\&{goto} \37\\{done1}\6
+\4\&{else} \&{if} $\\{precedes\_break}(\\{page\_tail})$ \1\&{then}\5
+$\\{pi}\K0$\6
+\4\&{else} \&{goto} \37\\{update\_heights};\2\2\6
+\4\\{kern\_node}: \37\&{if} $\\{page\_contents}<\\{box\_there}$ \1\&{then}\5
+\&{goto} \37\\{done1}\6
+\4\&{else} \&{if} $\\{link}(\|p)=\\{null}$ \1\&{then}\5
+\&{return}\6
+\4\&{else} \&{if} $\\{type}(\\{link}(\|p))=\\{glue\_node}$ \1\&{then}\5
+$\\{pi}\K0$\6
+\4\&{else} \&{goto} \37\\{update\_heights};\2\2\2\6
+\4\\{penalty\_node}: \37\&{if} $\\{page\_contents}<\\{box\_there}$ \1\&{then}\5
+\&{goto} \37\\{done1}\ \&{else} $\\{pi}\K\\{penalty}(\|p)$;\2\6
+\4\\{mark\_node}: \37\&{goto} \37\\{contribute};\6
+\4\\{ins\_node}: \37\X1019:Append an insertion to the current page and \&{goto}
+\\{contribute}\X;\6
+\4\&{othercases} \37$\\{confusion}(\.{"page"})$\2\6
+\&{endcases}\par
+\U1008.\fi
+
+\M1012. \P$\X1012:Initialize the current page, insert the \.{\\topskip} glue
+ahead of \|p, and \&{goto} \\{continue}\X\S$\6
+\&{begin} \37\&{if} $\\{page\_contents}=\\{empty}$ \1\&{then}\5
+$\\{freeze\_page\_specs}(\\{box\_there})$\6
+\4\&{else} $\\{page\_contents}\K\\{box\_there}$;\2\6
+$\|q\K\\{new\_skip\_param}(\\{top\_skip\_code})$;\C{now $\\{temp\_ptr}=\\{glue%
+\_ptr}(\|q)$}\6
+\&{if} $\\{width}(\\{temp\_ptr})>\\{height}(\|p)$ \1\&{then}\5
+$\\{width}(\\{temp\_ptr})\K\\{width}(\\{temp\_ptr})-\\{height}(\|p)$\6
+\4\&{else} $\\{width}(\\{temp\_ptr})\K0$;\2\6
+$\\{link}(\|q)\K\|p$;\5
+$\\{link}(\\{contrib\_head})\K\|q$;\5
+\&{goto} \37\\{continue};\6
+\&{end}\par
+\U1011.\fi
+
+\M1013. \P$\X1013:Prepare to move a box or rule node to the current page, then %
+\&{goto} \\{contribute}\X\S$\6
+\&{begin} \37$\\{page\_total}\K\\{page\_total}+\\{page\_depth}+\\{height}(%
+\|p)$;\5
+$\\{page\_depth}\K\\{depth}(\|p)$;\5
+\&{goto} \37\\{contribute};\6
+\&{end}\par
+\U1011.\fi
+
+\M1014. \P$\X1014:Make sure that \\{page\_max\_depth} is not exceeded\X\S$\6
+\&{if} $\\{page\_depth}>\\{page\_max\_depth}$ \1\&{then}\6
+\&{begin} \37$\\{page\_total}\K\30\\{page\_total}+\\{page\_depth}-\\{page\_max%
+\_depth}$;\6
+$\\{page\_depth}\K\\{page\_max\_depth}$;\6
+\&{end};\2\par
+\U1008.\fi
+
+\M1015. \P$\X1015:Update the current page measurements with respect to the glue
+or kern specified by node~\|p\X\S$\6
+\&{if} $\\{type}(\|p)=\\{kern\_node}$ \1\&{then}\5
+$\|q\K\|p$\6
+\4\&{else} \&{begin} \37$\|q\K\\{glue\_ptr}(\|p)$;\5
+$\\{page\_so\_far}[2+\\{stretch\_order}(\|q)]\K\30\\{page\_so\_far}[2+%
+\\{stretch\_order}(\|q)]+\\{stretch}(\|q)$;\6
+$\\{page\_shrink}\K\\{page\_shrink}+\\{shrink}(\|q)$;\6
+\&{if} $(\\{shrink\_order}(\|q)\I\\{normal})\W(\\{shrink}(\|q)\I0)$ \1\&{then}\6
+\&{begin} \37\hbox{}\6
+$\\{print\_err}(\.{"Infinite\ glue\ shrinkage\ found\ on\ current\ page"})$;\6
+$\\{help4}(\.{"The\ page\ about\ to\ be\ output\ contains\ some\ infinitely"})$%
+\6
+$(\.{"shrinkable\ glue,\ e.g.,\ \`\\vss\'\ or\ \`\\vskip\ 0pt\ minus\ 1fil%
+\'."})$\6
+$(\.{"Such\ glue\ doesn\'t\ belong\ there;\ but\ you\ can\ safely\ proceed,"})$%
+\6
+$(\.{"since\ the\ offensive\ shrinkability\ has\ been\ made\ finite."})$;\5
+\\{error};\5
+$\|r\K\\{new\_spec}(\|q)$;\5
+$\\{shrink\_order}(\|r)\K\\{normal}$;\5
+$\\{delete\_glue\_ref}(\|q)$;\5
+$\\{glue\_ptr}(\|p)\K\|r$;\5
+$\|q\K\|r$;\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{page\_total}\K\\{page\_total}+\\{page\_depth}+\\{width}(\|q)$;\5
+$\\{page\_depth}\K0$\par
+\U1008.\fi
+
+\M1016. \P$\X1016:Check if node \|p is a new champion breakpoint; then \(if)if
+it is time for a page break, prepare for output, and either fire up the user's
+output routine and \&{return} or ship out the page and \&{goto} \\{done}\X\S$\6
+\&{if} $\\{pi}<\\{inf\_penalty}$ \1\&{then}\6
+\&{begin} \37\X1018:Compute the badness, \|b, of the current page, using %
+\\{awful\_bad} if the box is too full\X;\6
+\&{if} $\|b<\\{awful\_bad}$ \1\&{then}\6
+\&{if} $\\{pi}\L\\{eject\_penalty}$ \1\&{then}\5
+$\|c\K\\{pi}$\6
+\4\&{else} \&{if} $\|b<\\{inf\_bad}$ \1\&{then}\5
+$\|c\K\|b+\\{pi}+\\{insert\_penalties}$\6
+\4\&{else} $\|c\K\\{deplorable}$\2\2\6
+\4\&{else} $\|c\K\|b$;\2\6
+\&{if} $\\{insert\_penalties}\G10000$ \1\&{then}\5
+$\|c\K\\{awful\_bad}$;\2\6
+\&{stat} \37\&{if} $\\{tracing\_pages}>0$ \1\&{then}\5
+\X1017:Display the page break cost\X;\ \2\6
+\&{tats}\6
+\&{if} $\|c\L\\{least\_page\_cost}$ \1\&{then}\6
+\&{begin} \37$\\{best\_page\_break}\K\|p$;\5
+$\\{best\_size}\K\\{page\_goal}$;\5
+$\\{least\_page\_cost}\K\|c$;\5
+$\|r\K\\{link}(\\{page\_ins\_head})$;\6
+\&{while} $\|r\I\\{page\_ins\_head}$ \1\&{do}\6
+\&{begin} \37$\\{best\_ins\_ptr}(\|r)\K\\{last\_ins\_ptr}(\|r)$;\5
+$\|r\K\\{link}(\|r)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $(\|c=\\{awful\_bad})\V(\\{pi}\L\\{eject\_penalty})$ \1\&{then}\6
+\&{begin} \37$\\{fire\_up}(\|p)$;\C{output the current page at the best place}\6
+\&{if} $\\{output\_active}$ \1\&{then}\5
+\&{return};\C{user's output routine will act}\2\6
+\&{goto} \37\\{done};\C{the page has been shipped out by default output
+routine}\6
+\&{end};\2\6
+\&{end}\2\par
+\U1008.\fi
+
+\M1017. \P$\X1017:Display the page break cost\X\S$\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"\%"})$;\5
+$\\{print}(\.{"\ t="})$;\5
+\\{print\_totals};\6
+$\\{print}(\.{"\ g="})$;\5
+$\\{print\_scaled}(\\{page\_goal})$;\6
+$\\{print}(\.{"\ b="})$;\6
+\&{if} $\|b=\\{awful\_bad}$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\ \&{else} $\\{print\_int}(\|b)$;\2\6
+$\\{print}(\.{"\ p="})$;\5
+$\\{print\_int}(\\{pi})$;\5
+$\\{print}(\.{"\ c="})$;\6
+\&{if} $\|c=\\{awful\_bad}$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\ \&{else} $\\{print\_int}(\|c)$;\2\6
+\&{if} $\|c\L\\{least\_page\_cost}$ \1\&{then}\5
+$\\{print\_char}(\.{"\#"})$;\2\6
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end}\par
+\U1016.\fi
+
+\M1018. \P$\X1018:Compute the badness, \|b, of the current page, using \\{awful%
+\_bad} if the box is too full\X\S$\6
+\&{if} $\\{page\_total}<\\{page\_goal}$ \1\&{then}\6
+\&{if} $(\\{page\_so\_far}[3]\I0)\V(\\{page\_so\_far}[4]\I0)\V\30(\\{page\_so%
+\_far}[5]\I0)$ \1\&{then}\5
+$\|b\K0$\6
+\4\&{else} $\|b\K\\{badness}(\\{page\_goal}-\\{page\_total},\39\\{page\_so%
+\_far}[2])$\2\6
+\4\&{else} \&{if} $\\{page\_total}-\\{page\_goal}>\\{page\_shrink}$ \1\&{then}\5
+$\|b\K\\{awful\_bad}$\6
+\4\&{else} $\|b\K\\{badness}(\\{page\_total}-\\{page\_goal},\39\\{page%
+\_shrink})$\2\2\par
+\U1016.\fi
+
+\M1019. \P$\X1019:Append an insertion to the current page and \&{goto} %
+\\{contribute}\X\S$\6
+\&{begin} \37\&{if} $\\{page\_contents}=\\{empty}$ \1\&{then}\5
+$\\{freeze\_page\_specs}(\\{inserts\_only})$;\2\6
+$\|n\K\\{subtype}(\|p)$;\5
+$\|r\K\\{page\_ins\_head}$;\6
+\&{while} $\|n\G\\{subtype}(\\{link}(\|r))$ \1\&{do}\5
+$\|r\K\\{link}(\|r)$;\2\6
+$\|n\K\\{qo}(\|n)$;\6
+\&{if} $\\{subtype}(\|r)\I\\{qi}(\|n)$ \1\&{then}\5
+\X1020:Create a page insertion node with $\\{subtype}(\|r)=\\{qi}(\|n)$, and
+include the glue correction for box \|n in the current page state\X;\2\6
+\&{if} $\\{type}(\|r)=\\{split\_up}$ \1\&{then}\5
+$\\{insert\_penalties}\K\\{insert\_penalties}+\\{float\_cost}(\|p)$\6
+\4\&{else} \&{begin} \37$\\{last\_ins\_ptr}(\|r)\K\|p$;\5
+$\\{delta}\K\\{page\_goal}-\\{page\_total}-\\{page\_depth}+\\{page\_shrink}$;%
+\C{this much room is left if we shrink the maximum}\6
+\&{if} $\\{count}(\|n)=1000$ \1\&{then}\5
+$\|h\K\\{height}(\|p)$\6
+\4\&{else} $\|h\K\\{x\_over\_n}(\\{height}(\|p),\391000)\ast\\{count}(\|n)$;%
+\C{this much room is needed}\2\6
+\&{if} $((\|h\L0)\V(\|h\L\\{delta}))\W(\\{height}(\|p)+\\{height}(\|r)\L%
+\\{dimen}(\|n))$ \1\&{then}\6
+\&{begin} \37$\\{page\_goal}\K\\{page\_goal}-\|h$;\5
+$\\{height}(\|r)\K\\{height}(\|r)+\\{height}(\|p)$;\6
+\&{end}\6
+\4\&{else} \X1021:Find the best way to split the insertion, and change $%
+\\{type}(\|r)$ to \\{split\_up}\X;\2\6
+\&{end};\2\6
+\&{goto} \37\\{contribute};\6
+\&{end}\par
+\U1011.\fi
+
+\M1020. We take note of the value of \.{\\skip} \|n and the height plus depth
+of \.{\\box}~\|n only when the first \.{\\insert}~\|n node is
+encountered for a new page. A user who changes the contents of \.{\\box}~\|n
+after that first \.{\\insert}~\|n had better be either extremely careful
+or extremely lucky, or both.
+
+\Y\P$\4\X1020:Create a page insertion node with $\\{subtype}(\|r)=\\{qi}(\|n)$,
+and include the glue correction for box \|n in the current page state\X\S$\6
+\&{begin} \37$\|q\K\\{get\_node}(\\{page\_ins\_node\_size})$;\5
+$\\{link}(\|q)\K\\{link}(\|r)$;\5
+$\\{link}(\|r)\K\|q$;\5
+$\|r\K\|q$;\5
+$\\{subtype}(\|r)\K\\{qi}(\|n)$;\5
+$\\{type}(\|r)\K\\{inserting}$;\5
+$\\{ensure\_vbox}(\|n)$;\6
+\&{if} $\\{box}(\|n)=\\{null}$ \1\&{then}\5
+$\\{height}(\|r)\K0$\6
+\4\&{else} \&{begin} \37\&{if} $\\{ins\_dir}(\|p)\I\\{box\_dir}(\\{box}(\|n))$ %
+\1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Insertions\ can\ only\ be\ added\ to\ a\ same\
+direction\ vbox"})$;\5
+$\\{help3}(\.{"Tut\ tut:\ You\'re\ trying\ to\ \\insert\ into\ a"})$\6
+$(\.{"\\box\ register\ that\ now\ have\ a\ different\ direction."})$\6
+$(\.{"Proceed,\ and\ I\'ll\ discard\ its\ present\ contents."})$;\5
+$\\{box\_error}(\|n)$\6
+\&{end}\6
+\4\&{else} $\\{height}(\|r)\K\\{height}(\\{box}(\|n))+\\{depth}(\\{box}(\|n))$;%
+\2\6
+\&{end};\2\6
+$\\{best\_ins\_ptr}(\|r)\K\\{null}$;\6
+$\|q\K\\{skip}(\|n)$;\6
+\&{if} $\\{count}(\|n)=1000$ \1\&{then}\5
+$\|h\K\\{height}(\|r)$\6
+\4\&{else} $\|h\K\\{x\_over\_n}(\\{height}(\|r),\391000)\ast\\{count}(\|n)$;\2\6
+$\\{page\_goal}\K\\{page\_goal}-\|h-\\{width}(\|q)$;\6
+$\\{page\_so\_far}[2+\\{stretch\_order}(\|q)]\K\30\\{page\_so\_far}[2+%
+\\{stretch\_order}(\|q)]+\\{stretch}(\|q)$;\6
+$\\{page\_shrink}\K\\{page\_shrink}+\\{shrink}(\|q)$;\6
+\&{if} $(\\{shrink\_order}(\|q)\I\\{normal})\W(\\{shrink}(\|q)\I0)$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Infinite\ glue\ shrinkage\ inserted\ from\
+"})$;\5
+$\\{print\_esc}(\.{"skip"})$;\5
+$\\{print\_int}(\|n)$;\5
+$\\{help3}(\.{"The\ correction\ glue\ for\ page\ breaking\ with\ insertions"})$%
+\6
+$(\.{"must\ have\ finite\ shrinkability.\ But\ you\ may\ proceed,"})$\6
+$(\.{"since\ the\ offensive\ shrinkability\ has\ been\ made\ finite."})$;\5
+\\{error};\6
+\&{end};\2\6
+\&{end}\par
+\U1019.\fi
+
+\M1021. Here is the code that will split a long footnote between pages, in an
+emergency. The current situation deserves to be recapitulated: Node \|p
+is an insertion into box \|n; the insertion will not fit, in its entirety,
+either because it would make the total contents of box \|n greater than
+\.{\\dimen} \|n, or because it would make the incremental amount of growth
+\|h greater than the available space \\{delta}, or both. (This amount \|h has
+been weighted by the insertion scaling factor, i.e., by \.{\\count} \|n
+over 1000.) Now we will choose the best way to break the vlist of the
+insertion, using the same criteria as in the \.{\\vsplit} operation.
+
+\Y\P$\4\X1021:Find the best way to split the insertion, and change $\\{type}(%
+\|r)$ to \\{split\_up}\X\S$\6
+\&{begin} \37\&{if} $\\{count}(\|n)\L0$ \1\&{then}\5
+$\|w\K\\{max\_dimen}$\6
+\4\&{else} \&{begin} \37$\|w\K\\{page\_goal}-\\{page\_total}-\\{page\_depth}$;\6
+\&{if} $\\{count}(\|n)\I1000$ \1\&{then}\5
+$\|w\K\\{x\_over\_n}(\|w,\39\\{count}(\|n))\ast1000$;\2\6
+\&{end};\2\6
+\&{if} $\|w>\\{dimen}(\|n)-\\{height}(\|r)$ \1\&{then}\5
+$\|w\K\\{dimen}(\|n)-\\{height}(\|r)$;\2\6
+$\|q\K\\{vert\_break}(\\{ins\_ptr}(\|p),\39\|w,\39\\{depth}(\|p))$;\5
+$\\{height}(\|r)\K\\{height}(\|r)+\\{best\_height\_plus\_depth}$;\6
+\&{stat} \37\&{if} $\\{tracing\_pages}>0$ \1\&{then}\5
+\X1022:Display the insertion split cost\X;\ \2\6
+\&{tats}\6
+\&{if} $\\{count}(\|n)\I1000$ \1\&{then}\5
+$\\{best\_height\_plus\_depth}\K\\{x\_over\_n}(\\{best\_height\_plus\_depth},%
+\391000)\ast\\{count}(\|n)$;\2\6
+$\\{page\_goal}\K\\{page\_goal}-\\{best\_height\_plus\_depth}$;\5
+$\\{type}(\|r)\K\\{split\_up}$;\5
+$\\{broken\_ptr}(\|r)\K\|q$;\5
+$\\{broken\_ins}(\|r)\K\|p$;\6
+\&{if} $\|q=\\{null}$ \1\&{then}\5
+$\\{insert\_penalties}\K\\{insert\_penalties}+\\{eject\_penalty}$\6
+\4\&{else} \&{if} $\\{type}(\|q)=\\{penalty\_node}$ \1\&{then}\5
+$\\{insert\_penalties}\K\\{insert\_penalties}+\\{penalty}(\|q)$;\2\2\6
+\&{end}\par
+\U1019.\fi
+
+\M1022. \P$\X1022:Display the insertion split cost\X\S$\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"\%\ split"})$;\5
+$\\{print\_int}(\|n)$;\5
+$\\{print}(\.{"\ to\ "})$;\5
+$\\{print\_scaled}(\|w)$;\5
+$\\{print\_char}(\.{","})$;\5
+$\\{print\_scaled}(\\{best\_height\_plus\_depth})$;\6
+$\\{print}(\.{"\ p="})$;\6
+\&{if} $\|q=\\{null}$ \1\&{then}\5
+$\\{print\_int}(\\{eject\_penalty})$\6
+\4\&{else} \&{if} $\\{type}(\|q)=\\{penalty\_node}$ \1\&{then}\5
+$\\{print\_int}(\\{penalty}(\|q))$\6
+\4\&{else} $\\{print\_char}(\.{"0"})$;\2\2\6
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end}\par
+\U1021.\fi
+
+\M1023. When the page builder has looked at as much material as could appear
+before
+the next page break, it makes its decision. The break that gave minimum
+badness will be used to put a completed ``page'' into box 255, with insertions
+appended to their other boxes.
+
+We also set the values of \\{top\_mark}, \\{first\_mark}, and \\{bot\_mark}.
+The
+program uses the fact that $\\{bot\_mark}\I\\{null}$ implies $\\{first\_mark}\I%
+\\{null}$;
+it also knows that $\\{bot\_mark}=\\{null}$ implies $\\{top\_mark}=\\{first%
+\_mark}=\\{null}$.
+
+The \\{fire\_up} subroutine prepares to output the current page at the best
+place; then it fires up the user's output routine, if there is one,
+or it simply ships out the page. There is one parameter, \|c, which represents
+the node that was being contributed to the page when the decision to
+force an output was made.
+
+\Y\P$\4\X1023:Declare the procedure called \\{fire\_up}\X\S$\6
+\4\&{procedure}\1\  \37$\\{fire\_up}(\|c:\\{pointer})$;\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{nodes being examined
+and/or changed}\6
+\\{prev\_p}: \37\\{pointer};\C{predecessor of \|p}\6
+\|n: \37$\\{min\_quarterword}\to255$;\C{insertion box number}\6
+\\{wait}: \37\\{boolean};\C{should the present insertion be held over?}\6
+\\{save\_vbadness}: \37\\{integer};\C{saved value of \\{vbadness}}\6
+\\{save\_vfuzz}: \37\\{scaled};\C{saved value of \\{vfuzz}}\6
+\\{save\_split\_top\_skip}: \37\\{pointer};\C{saved value of \\{split\_top%
+\_skip}}\2\6
+\&{begin} \37\X1024:Set the value of \\{output\_penalty}\X;\6
+\&{if} $\\{bot\_mark}\I\\{null}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{top\_mark}\I\\{null}$ \1\&{then}\5
+$\\{delete\_token\_ref}(\\{top\_mark})$;\2\6
+$\\{top\_mark}\K\\{bot\_mark}$;\5
+$\\{add\_token\_ref}(\\{top\_mark})$;\5
+$\\{delete\_token\_ref}(\\{first\_mark})$;\5
+$\\{first\_mark}\K\\{null}$;\6
+\&{end};\2\6
+\X1025:Put the \(o)optimal current page into box 255, update \\{first\_mark}
+and \\{bot\_mark}, append insertions to their boxes, and put the remaining
+nodes back on the contribution list\X;\6
+\&{if} $(\\{top\_mark}\I\\{null})\W(\\{first\_mark}=\\{null})$ \1\&{then}\6
+\&{begin} \37$\\{first\_mark}\K\\{top\_mark}$;\5
+$\\{add\_token\_ref}(\\{top\_mark})$;\6
+\&{end};\2\6
+\&{if} $\\{output\_routine}\I\\{null}$ \1\&{then}\6
+\&{if} $\\{dead\_cycles}\G\\{max\_dead\_cycles}$ \1\&{then}\5
+\X1035:Explain that too many dead cycles have occurred in a row\X\6
+\4\&{else} \X1036:Fire up the user's output routine and \&{return}\X;\2\2\6
+\X1034:Perform the default output routine\X;\6
+\4\\{exit}: \37\&{end};\par
+\U1005.\fi
+
+\M1024. \P$\X1024:Set the value of \\{output\_penalty}\X\S$\6
+\&{if} $\\{type}(\\{best\_page\_break})=\\{penalty\_node}$ \1\&{then}\6
+\&{begin} \37$\\{geq\_word\_define}(\\{int\_base}+\\{output\_penalty\_code},\39%
+\\{penalty}(\\{best\_page\_break}))$;\5
+$\\{penalty}(\\{best\_page\_break})\K\\{inf\_penalty}$;\6
+\&{end}\6
+\4\&{else} $\\{geq\_word\_define}(\\{int\_base}+\\{output\_penalty\_code},\39%
+\\{inf\_penalty})$\2\par
+\U1023.\fi
+
+\M1025. As the page is finally being prepared for output,
+pointer \|p runs through the vlist, with \\{prev\_p} trailing behind;
+pointer \|q is the tail of a list of insertions that
+are being held over for a subsequent page.
+
+\Y\P$\4\X1025:Put the \(o)optimal current page into box 255, update \\{first%
+\_mark} and \\{bot\_mark}, append insertions to their boxes, and put the
+remaining nodes back on the contribution list\X\S$\6
+\&{if} $\|c=\\{best\_page\_break}$ \1\&{then}\5
+$\\{best\_page\_break}\K\\{null}$;\C{\|c not yet linked in}\2\6
+\X1026:Ensure that box 255 is empty before output\X;\6
+$\\{insert\_penalties}\K0$;\C{this will count the number of insertions held
+over}\6
+$\\{save\_split\_top\_skip}\K\\{split\_top\_skip}$;\6
+\&{if} $\\{holding\_inserts}\L0$ \1\&{then}\5
+\X1029:Prepare all the boxes involved in insertions to act as queues\X;\2\6
+$\|q\K\\{hold\_head}$;\5
+$\\{link}(\|q)\K\\{null}$;\5
+$\\{prev\_p}\K\\{page\_head}$;\5
+$\|p\K\\{link}(\\{prev\_p})$;\6
+\&{while} $\|p\I\\{best\_page\_break}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{type}(\|p)=\\{ins\_node}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{holding\_inserts}\L0$ \1\&{then}\5
+\X1031:Either insert the material specified by node \|p into the appropriate
+box, or hold it for the next page; also delete node \|p from the current page%
+\X;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{type}(\|p)=\\{mark\_node}$ \1\&{then}\5
+\X1027:Update the values of \\{first\_mark} and \\{bot\_mark}\X;\2\2\6
+$\\{prev\_p}\K\|p$;\5
+$\|p\K\\{link}(\\{prev\_p})$;\6
+\&{end};\2\6
+$\\{split\_top\_skip}\K\\{save\_split\_top\_skip}$;\5
+\X1028:Break the current page at node \|p, put it in box~255, and put the
+remaining nodes on the contribution list\X;\6
+\X1030:Delete \(t)the page-insertion nodes\X\par
+\U1023.\fi
+
+\M1026. \P$\X1026:Ensure that box 255 is empty before output\X\S$\6
+\&{if} $\\{box}(255)\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{""})$;\5
+$\\{print\_esc}(\.{"box"})$;\5
+$\\{print}(\.{"255\ is\ not\ void"})$;\5
+$\\{help2}(\.{"You\ shouldn\'t\ use\ \\box255\ except\ in\ \\output\
+routines."})$\6
+$(\.{"Proceed,\ and\ I\'ll\ discard\ its\ present\ contents."})$;\5
+$\\{box\_error}(255)$;\6
+\&{end}\2\par
+\U1025.\fi
+
+\M1027. \P$\X1027:Update the values of \\{first\_mark} and \\{bot\_mark}\X\S$\6
+\&{begin} \37\&{if} $\\{first\_mark}=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{first\_mark}\K\\{mark\_ptr}(\|p)$;\5
+$\\{add\_token\_ref}(\\{first\_mark})$;\6
+\&{end};\2\6
+\&{if} $\\{bot\_mark}\I\\{null}$ \1\&{then}\5
+$\\{delete\_token\_ref}(\\{bot\_mark})$;\2\6
+$\\{bot\_mark}\K\\{mark\_ptr}(\|p)$;\5
+$\\{add\_token\_ref}(\\{bot\_mark})$;\6
+\&{end}\par
+\U1025.\fi
+
+\M1028. When the following code is executed, the current page runs from node
+$\\{link}(\\{page\_head})$ to node \\{prev\_p}, and the nodes from \|p to %
+\\{page\_tail}
+are to be placed back at the front of the contribution list. Furthermore
+the heldover insertions appear in a list from $\\{link}(\\{hold\_head})$ to %
+\|q; we
+will put them into the current page list for safekeeping while the user's
+output routine is active.  We might have $\|q=\\{hold\_head}$; and $\|p=%
+\\{null}$ if
+and only if $\\{prev\_p}=\\{page\_tail}$. Error messages are suppressed within
+\\{vpackage}, since the box might appear to be overfull or underfull simply
+because the stretch and shrink from the \.{\\skip} registers for inserts
+are not actually present in the box.
+
+\Y\P$\4\X1028:Break the current page at node \|p, put it in box~255, and put
+the remaining nodes on the contribution list\X\S$\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{link}(\\{contrib\_head})=\\{null}$ \1\&{then}\6
+\&{if} $\\{nest\_ptr}=0$ \1\&{then}\5
+$\\{tail}\K\\{page\_tail}$\6
+\4\&{else} $\\{contrib\_tail}\K\\{page\_tail}$;\2\2\6
+$\\{link}(\\{page\_tail})\K\\{link}(\\{contrib\_head})$;\5
+$\\{link}(\\{contrib\_head})\K\|p$;\5
+$\\{link}(\\{prev\_p})\K\\{null}$;\6
+\&{end};\2\6
+$\\{save\_vbadness}\K\\{vbadness}$;\5
+$\\{vbadness}\K\\{inf\_bad}$;\5
+$\\{save\_vfuzz}\K\\{vfuzz}$;\5
+$\\{vfuzz}\K\\{max\_dimen}$;\C{inhibit error messages}\6
+$\\{box}(255)\K\\{vpackage}(\\{link}(\\{page\_head}),\39\\{best\_size},\39%
+\\{exactly},\39\\{page\_max\_depth})$;\5
+$\\{set\_box\_dir}(\\{box}(255))(\\{page\_dir})$;\5
+$\\{vbadness}\K\\{save\_vbadness}$;\5
+$\\{vfuzz}\K\\{save\_vfuzz}$;\6
+\&{if} $\\{last\_glue}\I\\{max\_halfword}$ \1\&{then}\5
+$\\{delete\_glue\_ref}(\\{last\_glue})$;\2\6
+\X1002:Start a new current page\X;\C{this sets $\\{last\_glue}\K\\{max%
+\_halfword}$}\6
+\&{if} $\|q\I\\{hold\_head}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\\{page\_head})\K\\{link}(\\{hold\_head})$;\5
+$\\{page\_tail}\K\|q$;\6
+\&{end}\2\par
+\U1025.\fi
+
+\M1029. If many insertions are supposed to go into the same box, we want to
+know
+the position of the last node in that box, so that we don't need to waste time
+when linking further information into it. The \\{last\_ins\_ptr} fields of the
+page insertion nodes are therefore used for this purpose during the
+packaging phase.
+
+\Y\P$\4\X1029:Prepare all the boxes involved in insertions to act as queues\X%
+\S$\6
+\&{begin} \37$\|r\K\\{link}(\\{page\_ins\_head})$;\6
+\&{while} $\|r\I\\{page\_ins\_head}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{best\_ins\_ptr}(\|r)\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\|n\K\\{qo}(\\{subtype}(\|r))$;\5
+$\\{ensure\_vbox}(\|n)$;\6
+\&{if} $\\{box}(\|n)=\\{null}$ \1\&{then}\5
+$\\{box}(\|n)\K\\{new\_null\_box}$;\2\6
+$\|p\K\\{box}(\|n)+\\{list\_offset}$;\6
+\&{while} $\\{link}(\|p)\I\\{null}$ \1\&{do}\5
+$\|p\K\\{link}(\|p)$;\2\6
+$\\{last\_ins\_ptr}(\|r)\K\|p$;\6
+\&{end};\2\6
+$\|r\K\\{link}(\|r)$;\6
+\&{end};\2\6
+\&{end}\par
+\U1025.\fi
+
+\M1030. \P$\X1030:Delete \(t)the page-insertion nodes\X\S$\6
+$\|r\K\\{link}(\\{page\_ins\_head})$;\6
+\&{while} $\|r\I\\{page\_ins\_head}$ \1\&{do}\6
+\&{begin} \37$\|q\K\\{link}(\|r)$;\5
+$\\{free\_node}(\|r,\39\\{page\_ins\_node\_size})$;\5
+$\|r\K\|q$;\6
+\&{end};\2\6
+$\\{link}(\\{page\_ins\_head})\K\\{page\_ins\_head}$\par
+\U1025.\fi
+
+\M1031. We will set $\\{best\_ins\_ptr}\K\\{null}$ and package the box
+corresponding to
+insertion node~\|r, just after making the final insertion into that box.
+If this final insertion is `\\{split\_up}', the remainder after splitting
+and pruning (if any) will be carried over to the next page.
+
+\Y\P$\4\X1031:Either insert the material specified by node \|p into the
+appropriate box, or hold it for the next page; also delete node \|p from the
+current page\X\S$\6
+\&{begin} \37$\|r\K\\{link}(\\{page\_ins\_head})$;\6
+\&{while} $\\{subtype}(\|r)\I\\{subtype}(\|p)$ \1\&{do}\5
+$\|r\K\\{link}(\|r)$;\2\6
+\&{if} $\\{best\_ins\_ptr}(\|r)=\\{null}$ \1\&{then}\5
+$\\{wait}\K\\{true}$\6
+\4\&{else} \&{begin} \37$\\{wait}\K\\{false}$;\5
+$\|n\K\\{qo}(\\{subtype}(\|p))$;\6
+\&{case} $\\{box\_dir}(\\{box}(\|n))$ \1\&{of}\6
+\4\\{any\_dir}: \37\&{if} $\\{ins\_dir}(\|p)\I\\{box\_dir}(\\{box}(\|n))$ \1%
+\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Insertions\ can\ only\ be\ added\ to\ a\ same\
+direction\ vbox"})$;\5
+$\\{help3}(\.{"Tut\ tut:\ You\'re\ trying\ to\ \\insert\ into\ a"})$\6
+$(\.{"\\box\ register\ that\ now\ have\ a\ different\ direction."})$\6
+$(\.{"Proceed,\ and\ I\'ll\ discard\ its\ present\ contents."})$;\5
+$\\{box\_error}(\|n)$;\5
+$\\{box}(\|n)\K\\{new\_null\_box}$;\5
+$\\{last\_ins\_ptr}(\|r)\K\\{box}(\|n)+\\{list\_offset}$;\6
+\&{end};\6
+\4\&{othercases} $\\{set\_box\_dir}(\\{box}(\|n))(\\{ins\_dir}(\|p))$;\2\2\6
+\&{endcases};\5
+$\|s\K\\{last\_ins\_ptr}(\|r)$;\5
+$\\{link}(\|s)\K\\{ins\_ptr}(\|p)$;\6
+\&{if} $\\{best\_ins\_ptr}(\|r)=\|p$ \1\&{then}\5
+\X1032:Wrap up the box specified by node \|r, splitting node \|p if called for;
+set $\\{wait}\K\\{true}$ if node \|p holds a remainder after splitting\X\6
+\4\&{else} \&{begin} \37\&{while} $\\{link}(\|s)\I\\{null}$ \1\&{do}\5
+$\|s\K\\{link}(\|s)$;\2\6
+$\\{last\_ins\_ptr}(\|r)\K\|s$;\6
+\&{end};\2\6
+\&{end};\2\6
+\X1033:Either append the insertion node \|p after node \|q, and remove it from
+the current page, or delete $\\{node}(\|p)$\X;\6
+\&{end}\par
+\U1025.\fi
+
+\M1032. \P$\X1032:Wrap up the box specified by node \|r, splitting node \|p if
+called for; set $\\{wait}\K\\{true}$ if node \|p holds a remainder after
+splitting\X\S$\6
+\&{begin} \37\&{if} $\\{type}(\|r)=\\{split\_up}$ \1\&{then}\6
+\&{if} $(\\{broken\_ins}(\|r)=\|p)\W(\\{broken\_ptr}(\|r)\I\\{null})$ \1%
+\&{then}\6
+\&{begin} \37\&{while} $\\{link}(\|s)\I\\{broken\_ptr}(\|r)$ \1\&{do}\5
+$\|s\K\\{link}(\|s)$;\2\6
+$\\{link}(\|s)\K\\{null}$;\5
+$\\{split\_top\_skip}\K\\{split\_top\_ptr}(\|p)$;\5
+$\\{ins\_ptr}(\|p)\K\\{prune\_page\_top}(\\{broken\_ptr}(\|r))$;\6
+\&{if} $\\{ins\_ptr}(\|p)\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{temp\_ptr}\K\\{vpack}(\\{ins\_ptr}(\|p),\39\\{natural})$;\5
+$\\{height}(\|p)\K\\{height}(\\{temp\_ptr})+\\{depth}(\\{temp\_ptr})$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\\{temp\_ptr}))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\\{temp\_ptr}))$;\5
+$\\{free\_node}(\\{temp\_ptr},\39\\{box\_node\_size})$;\5
+$\\{wait}\K\\{true}$;\6
+\&{end};\2\6
+\&{end};\2\2\6
+$\\{best\_ins\_ptr}(\|r)\K\\{null}$;\5
+$\|n\K\\{qo}(\\{subtype}(\|r))$;\5
+$\\{temp\_ptr}\K\\{list\_ptr}(\\{box}(\|n))$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\\{box}(\|n)))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\\{box}(\|n)))$;\5
+$\\{flush\_node\_list}(\\{link}(\\{box}(\|n)))$;\5
+$\\{free\_node}(\\{box}(\|n),\39\\{box\_node\_size})$;\5
+$\\{box}(\|n)\K\\{vpack}(\\{temp\_ptr},\39\\{natural})$;\5
+$\\{set\_box\_dir}(\\{box}(\|n))(\\{ins\_dir}(\|p))$;\6
+\&{end}\par
+\U1031.\fi
+
+\M1033. \P$\X1033:Either append the insertion node \|p after node \|q, and
+remove it from the current page, or delete $\\{node}(\|p)$\X\S$\6
+$\\{link}(\\{prev\_p})\K\\{link}(\|p)$;\5
+$\\{link}(\|p)\K\\{null}$;\6
+\&{if} $\\{wait}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|q)\K\|p$;\5
+$\|q\K\|p$;\5
+$\\{incr}(\\{insert\_penalties})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{delete\_glue\_ref}(\\{split\_top\_ptr}(\|p))$;\5
+$\\{free\_node}(\|p,\39\\{ins\_node\_size})$;\6
+\&{end};\2\6
+$\|p\K\\{prev\_p}$\par
+\U1031.\fi
+
+\M1034. The list of heldover insertions, running from $\\{link}(\\{page%
+\_head})$ to
+\\{page\_tail}, must be moved to the contribution list when the user has
+specified no output routine.
+
+\Y\P$\4\X1034:Perform the default output routine\X\S$\6
+\&{begin} \37\&{if} $\\{link}(\\{page\_head})\I\\{null}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{link}(\\{contrib\_head})=\\{null}$ \1\&{then}\6
+\&{if} $\\{nest\_ptr}=0$ \1\&{then}\5
+$\\{tail}\K\\{page\_tail}$\ \&{else} $\\{contrib\_tail}\K\\{page\_tail}$\2\6
+\4\&{else} $\\{link}(\\{page\_tail})\K\\{link}(\\{contrib\_head})$;\2\6
+$\\{link}(\\{contrib\_head})\K\\{link}(\\{page\_head})$;\5
+$\\{link}(\\{page\_head})\K\\{null}$;\5
+$\\{page\_tail}\K\\{page\_head}$;\6
+\&{end};\2\6
+$\\{ship\_out}(\\{box}(255))$;\5
+$\\{box}(255)\K\\{null}$;\6
+\&{end}\par
+\U1023.\fi
+
+\M1035. \P$\X1035:Explain that too many dead cycles have occurred in a row\X\S$%
+\6
+\&{begin} \37$\\{print\_err}(\.{"Output\ loop---"})$;\5
+$\\{print\_int}(\\{dead\_cycles})$;\5
+$\\{print}(\.{"\ consecutive\ dead\ cycles"})$;\5
+$\\{help3}(\.{"I\'ve\ concluded\ that\ your\ \\output\ is\ awry;\ it\ never\
+does\ a"})$\6
+$(\.{"\\shipout,\ so\ I\'m\ shipping\ \\box255\ out\ myself.\ Next\ time"})$\6
+$(\.{"increase\ \\maxdeadcycles\ if\ you\ want\ me\ to\ be\ more\ patient!"})$;%
+\5
+\\{error};\6
+\&{end}\par
+\U1023.\fi
+
+\M1036. \P$\X1036:Fire up the user's output routine and \&{return}\X\S$\6
+\&{begin} \37$\\{output\_active}\K\\{true}$;\5
+$\\{incr}(\\{dead\_cycles})$;\5
+\\{push\_nest};\5
+$\\{mode}\K-\\{vmode}$;\5
+$\\{prev\_depth}\K\\{ignore\_depth}$;\5
+$\\{mode\_line}\K-\\{line}$;\5
+$\\{begin\_token\_list}(\\{output\_routine},\39\\{output\_text})$;\5
+$\\{new\_save\_level}(\\{output\_group})$;\5
+\\{normal\_paragraph};\5
+\\{scan\_left\_brace};\5
+\&{return};\6
+\&{end}\par
+\U1023.\fi
+
+\M1037. When the user's output routine finishes, it has constructed a vlist
+in internal vertical mode, and \TeX\ will do the following:
+
+\Y\P$\4\X1037:Resume the page builder after an output routine has come to an
+end\X\S$\6
+\&{begin} \37\&{if} $(\\{loc}\I\\{null})\V((\\{token\_type}\I\\{output\_text})%
+\W(\\{token\_type}\I\\{backed\_up}))$ \1\&{then}\5
+\X1038:Recover from an unbalanced output routine\X;\2\6
+\\{end\_token\_list};\C{conserve stack space in case more outputs are
+triggered}\6
+\\{end\_graf};\5
+\\{unsave};\5
+$\\{output\_active}\K\\{false}$;\5
+$\\{insert\_penalties}\K0$;\6
+\X1039:Ensure that box 255 is empty after output\X;\6
+\&{if} $\\{tail}\I\\{head}$ \1\&{then}\C{current list goes after heldover
+insertions}\6
+\&{begin} \37$\\{link}(\\{page\_tail})\K\\{link}(\\{head})$;\5
+$\\{page\_tail}\K\\{tail}$;\6
+\&{end};\2\6
+\&{if} $\\{link}(\\{page\_head})\I\\{null}$ \1\&{then}\C{and both go before
+heldover contributions}\6
+\&{begin} \37\&{if} $\\{link}(\\{contrib\_head})=\\{null}$ \1\&{then}\5
+$\\{contrib\_tail}\K\\{page\_tail}$;\2\6
+$\\{link}(\\{page\_tail})\K\\{link}(\\{contrib\_head})$;\5
+$\\{link}(\\{contrib\_head})\K\\{link}(\\{page\_head})$;\5
+$\\{link}(\\{page\_head})\K\\{null}$;\5
+$\\{page\_tail}\K\\{page\_head}$;\6
+\&{end};\2\6
+\\{pop\_nest};\5
+\\{build\_page};\6
+\&{end}\par
+\U1112.\fi
+
+\M1038. \P$\X1038:Recover from an unbalanced output routine\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Unbalanced\ output\ routine"})$;\5
+$\\{help2}(\.{"Your\ sneaky\ output\ routine\ has\ problematic\ \{\'s\ and/or\ %
+\}\'s."})$\6
+$(\.{"I\ can\'t\ handle\ that\ very\ well;\ good\ luck."})$;\5
+\\{error};\6
+\1\&{repeat} \37\\{get\_token};\6
+\4\&{until}\5
+$\\{loc}=\\{null}$;\2\6
+\&{end}\C{loops forever if reading from a file, since $\\{null}=\\{min%
+\_halfword}\L0$}\par
+\U1037.\fi
+
+\M1039. \P$\X1039:Ensure that box 255 is empty after output\X\S$\6
+\&{if} $\\{box}(255)\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Output\ routine\ didn\'t\ use\ all\ of\ "})$;\5
+$\\{print\_esc}(\.{"box"})$;\5
+$\\{print\_int}(255)$;\5
+$\\{help3}(\.{"Your\ \\output\ commands\ should\ empty\ \\box255,"})$\6
+$(\.{"e.g.,\ by\ saying\ \`\\shipout\\box255\'."})$\6
+$(\.{"Proceed;\ I\'ll\ discard\ its\ present\ contents."})$;\5
+$\\{box\_error}(255)$;\6
+\&{end}\2\par
+\U1037.\fi
+
+\N1040.  \[46] The chief executive.
+We come now to the \\{main\_control} routine, which contains the master
+switch that causes all the various pieces of \TeX\ to do their things,
+in the right order.
+
+In a sense, this is the grand climax of the program: It applies all the
+tools that we have worked so hard to construct. In another sense, this is
+the messiest part of the program: It necessarily refers to other pieces
+of code all over the place, so that a person can't fully understand what is
+going on without paging back and forth to be reminded of conventions that
+are defined elsewhere. We are now at the hub of the web, the central nervous
+system that touches most of the other parts and ties them together.
+
+The structure of \\{main\_control} itself is quite simple. There's a label
+called \\{big\_switch}, at which point the next token of input is fetched
+using \\{get\_x\_token}. Then the program branches at high speed into one of
+about 100 possible directions, based on the value of the current
+mode and the newly fetched command code; the sum $\\{abs}(\\{mode})+\\{cur%
+\_cmd}$
+indicates what to do next. For example, the case `$\\{vmode}+\\{letter}$'
+arises
+when a letter occurs in vertical mode (or internal vertical mode); this
+case leads to instructions that initialize a new paragraph and enter
+horizontal mode.
+
+The big   \&{case}  statement that contains this multiway switch has been
+labeled
+\\{reswitch}, so that the program can \&{goto} \\{reswitch} when the next token
+has already been fetched. Most of the cases are quite short; they call
+an ``action procedure'' that does the work for that case, and then they
+either \&{goto} \\{reswitch} or they ``fall through'' to the end of the   %
+\&{case}
+statement, which returns control back to \\{big\_switch}. Thus, \\{main%
+\_control}
+is not an extremely large procedure, in spite of the multiplicity of things
+it must do; it is small enough to be handled by \PASCAL\ compilers that put
+severe restrictions on procedure size.
+
+One case is singled out for special treatment, because it accounts for most
+of \TeX's activities in typical applications. The process of reading simple
+text and converting it into \\{char\_node} records, while looking for ligatures
+and kerns, is part of \TeX's ``inner loop''; the whole program runs
+efficiently when its inner loop is fast, so this part has been written
+with particular care.
+
+\fi
+
+\M1041. We shall concentrate first on the inner loop of \\{main\_control},
+deferring
+consideration of the other cases until later.
+
+\Y\P\D \37$\\{big\_switch}=60$\C{go here to branch on the next token of input}%
+\par
+\P\D \37$\\{main\_loop}=70$\C{go here to typeset a string of consecutive
+characters}\par
+\P\D \37$\\{main\_loop\_wrapup}=80$\C{go here to finish a character or
+ligature}\par
+\P\D \37$\\{main\_loop\_move}=90$\C{go here to advance the ligature cursor}\par
+\P\D \37$\\{main\_loop\_move\_lig}=95$\C{same, when advancing past a generated
+ligature}\par
+\P\D \37$\\{main\_loop\_lookahead}=100$\C{go here to bring in another
+character, if any}\par
+\P\D \37$\\{main\_lig\_loop}=110$\C{go here to check for ligatures or kerning}%
+\par
+\P\D \37$\\{append\_normal\_space}=120$\C{go here to append a normal space
+between words}\par
+\P\D \37$\\{main\_loop\_j}=130$\C{like \\{main\_loop}, but \\{cur\_chr} holds a
+KANJI code}\par
+\P\D \37$\\{skip\_loop}=141$\par
+\P\D \37$\\{again\_2}=150$\par
+\Y\P\hbox{\4}\X1055:Declare action procedures for use by \\{main\_control}\X\6
+\hbox{\4}\X1080:Declare the procedure called \\{handle\_right\_brace}\X\6
+\4\&{procedure}\1\  \37\\{main\_control};\C{governs \TeX's activities}\6
+\4\&{label} \37$\\{big\_switch},\39\\{reswitch},\39\\{main\_loop},\39\\{main%
+\_loop\_wrapup},\39\\{main\_loop\_j},\39\\{main\_loop\_j}+1,\39\\{main\_loop%
+\_j}+3,\39\\{skip\_loop},\39\\{again\_2},\39\\{main\_loop\_move},\39\\{main%
+\_loop\_move}+1,\39\\{main\_loop\_move}+2,\39\\{main\_loop\_move\_lig},\39%
+\\{main\_loop\_lookahead},\39\\{main\_loop\_lookahead}+1,\39\\{main\_lig%
+\_loop},\39\\{main\_lig\_loop}+1,\39\\{main\_lig\_loop}+2,\39\\{append\_normal%
+\_space},\39\\{exit}$;\6
+\4\&{var} \37\|t: \37\\{integer};\C{general-purpose temporary variable}\6
+\\{cx}: \37\\{KANJI\_code};\C{kanji character}\6
+\\{kp}: \37\\{pointer};\C{kinsoku penalty register}\6
+$\\{gp},\39\\{gq}$: \37\\{pointer};\C{temporary registers for list
+manipulation}\6
+\\{disp}: \37\\{scaled};\C{displacement register}\6
+\\{ins\_kp}: \37\\{boolean};\C{whether insert kinsoku penalty}\2\6
+\&{begin} \37\&{if} $\\{every\_job}\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{every\_job},\39\\{every\_job\_text})$;\2\6
+\4\\{big\_switch}: \37\\{get\_x\_token};\6
+\4\\{reswitch}: \37\X1042:Give diagnostic information, if requested\X;\6
+$\\{ins\_kp}\K\\{false}$;\6
+\&{case} $\\{abs}(\\{mode})+\\{cur\_cmd}$ \1\&{of}\6
+\4$\\{hmode}+\\{letter},\39\\{hmode}+\\{other\_char}$: \37\&{goto} \37\\{main%
+\_loop};\6
+\4$\\{hmode}+\\{kanji},\39\\{hmode}+\\{kana},\39\\{hmode}+\\{other\_kchar}$: %
+\37\&{goto} \37\\{main\_loop\_j};\6
+\4$\\{hmode}+\\{char\_given}$: \37\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ \1%
+\&{then}\5
+\&{goto} \37\\{main\_loop}\6
+\4\&{else} \&{goto} \37\\{main\_loop\_j};\2\6
+\4$\\{hmode}+\\{char\_num}$: \37\&{begin} \37\\{scan\_char\_num};\5
+$\\{cur\_chr}\K\\{cur\_val}$;\6
+\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ \1\&{then}\5
+\&{goto} \37\\{main\_loop}\6
+\4\&{else} \&{goto} \37\\{main\_loop\_j};\2\6
+\&{end};\6
+\4$\\{hmode}+\\{no\_boundary}$: \37\&{begin} \37\\{get\_x\_token};\6
+\&{if} $(\\{cur\_cmd}=\\{letter})\V(\\{cur\_cmd}=\\{other\_char})\V(\\{cur%
+\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=\\{other\_kchar})\V(%
+\\{cur\_cmd}=\\{char\_given})\V(\\{cur\_cmd}=\\{char\_num})$ \1\&{then}\5
+$\\{cancel\_boundary}\K\\{true}$;\2\6
+\&{goto} \37\\{reswitch};\6
+\&{end};\6
+\4$\\{hmode}+\\{spacer}$: \37\&{if} $\\{space\_factor}=1000$ \1\&{then}\5
+\&{goto} \37\\{append\_normal\_space}\6
+\4\&{else} \\{app\_space};\2\6
+\4$\\{hmode}+\\{ex\_space},\39\\{mmode}+\\{ex\_space}$: \37\&{goto} \37%
+\\{append\_normal\_space};\6
+\hbox{\4}\X1057:Cases of \\{main\_control} that are not part of the inner loop%
+\X\2\6
+\&{end};\C{of the big   \&{case}  statement}\6
+\&{goto} \37\\{big\_switch};\6
+\4\\{main\_loop\_j}: \37\X1469:Append KANJI-character \\{cur\_chr} to the
+current hlist in the current font; \&{goto} \\{reswitch} when a non-character
+has been fetched\X;\6
+\4\\{main\_loop}: \37$\\{inhibit\_glue\_flag}\K\\{false}$;\5
+\X1045:Append character \\{cur\_chr} and the following characters (if~any) to
+the current hlist in the current font; \&{goto} \\{reswitch} when a
+non-character has been fetched\X;\6
+\4\\{append\_normal\_space}: \37\X1053:Append a normal inter-word space to the
+current list, then \&{goto} \\{big\_switch}\X;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1042. When a new token has just been fetched at \\{big\_switch}, we have an
+ideal place to monitor \TeX's activity.
+
+\Y\P$\4\X1042:Give diagnostic information, if requested\X\S$\6
+\&{if} $\\{interrupt}\I0$ \1\&{then}\6
+\&{if} $\\{OK\_to\_interrupt}$ \1\&{then}\6
+\&{begin} \37\\{back\_input};\5
+\\{check\_interrupt};\5
+\&{goto} \37\\{big\_switch};\6
+\&{end};\2\2\6
+\&{debug} \37\&{if} $\\{panicking}$ \1\&{then}\5
+$\\{check\_mem}(\\{false})$;\ \2\ \&{gubed}\6
+\&{if} $\\{tracing\_commands}>0$ \1\&{then}\5
+\\{show\_cur\_cmd\_chr}\2\par
+\U1041.\fi
+
+\M1043. The following part of the program was first written in a structured
+manner, according to the philosophy that ``premature optimization is
+the root of all evil.'' Then it was rearranged into pieces of
+spaghetti so that the most common actions could proceed with little or
+no redundancy.
+
+The original unoptimized form of this algorithm resembles the
+\\{reconstitute} procedure, which was described earlier in connection with
+hyphenation. Again we have an implied ``cursor'' between characters
+\\{cur\_l} and \\{cur\_r}. The main difference is that the \\{lig\_stack} can
+now
+contain a charnode as well as pseudo-ligatures; that stack is now
+usually nonempty, because the next character of input (if any) has been
+appended to it. In \\{main\_control} we have
+$$\\{cur\_r}=\cases{$\\{character}(\\{lig\_stack})$,&if $\\{lig\_stack}>%
+\\{null}$;\cr
+$\\{font\_bchar}[\\{cur\_font}]$,&otherwise;\cr}$$
+except when $\\{character}(\\{lig\_stack})=\\{font\_false\_bchar}[\\{cur%
+\_font}]$.
+Several additional global variables are needed.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{main\_f}: \37\\{internal\_font\_number};\C{the current font}\6
+\4\\{main\_i}: \37\\{four\_quarters};\C{character information bytes for \\{cur%
+\_l}}\6
+\4\\{main\_j}: \37\\{four\_quarters};\C{ligature/kern command}\6
+\4\\{main\_k}: \37\\{font\_index};\C{index into \\{font\_info}}\6
+\4\\{main\_p}: \37\\{pointer};\C{temporary register for list manipulation}\6
+\4\\{main\_s}: \37\\{integer};\C{space factor value}\6
+\4\\{bchar}: \37\\{halfword};\C{right boundary character of current font, or %
+\\{non\_char}}\6
+\4\\{false\_bchar}: \37\\{halfword};\C{nonexistent character matching %
+\\{bchar}, or \\{non\_char}}\6
+\4\\{cancel\_boundary}: \37\\{boolean};\C{should the left boundary be ignored?}%
+\6
+\4\\{ins\_disc}: \37\\{boolean};\C{should we insert a discretionary node?}\par
+\fi
+
+\M1044. The boolean variables of the main loop are normally false, and always
+reset
+to false before the loop is left. That saves us the extra work of initializing
+each time.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{ligature\_present}\K\\{false}$;\5
+$\\{cancel\_boundary}\K\\{false}$;\5
+$\\{lft\_hit}\K\\{false}$;\5
+$\\{rt\_hit}\K\\{false}$;\5
+$\\{ins\_disc}\K\\{false}$;\par
+\fi
+
+\M1045. We leave the \\{space\_factor} unchanged if $\\{sf\_code}(\\{cur%
+\_chr})=0$; otherwise we
+set it equal to $\\{sf\_code}(\\{cur\_chr})$, except that it should never
+change
+from a value less than 1000 to a value exceeding 1000. The most common
+case is $\\{sf\_code}(\\{cur\_chr})=1000$, so we want that case to be fast.
+
+The overall structure of the main loop is presented here. Some program labels
+are inside the individual sections.
+
+\Y\P\D \37$\\{adjust\_space\_factor}\S\hbox{}$\6
+$\\{main\_s}\K\\{sf\_code}(\\{cur\_chr})$;\6
+\&{if} $\\{main\_s}=1000$ \1\&{then}\5
+$\\{space\_factor}\K1000$\6
+\4\&{else} \&{if} $\\{main\_s}<1000$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{main\_s}>0$ \1\&{then}\5
+$\\{space\_factor}\K\\{main\_s}$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{space\_factor}<1000$ \1\&{then}\5
+$\\{space\_factor}\K1000$\6
+\4\&{else} $\\{space\_factor}\K\\{main\_s}$\2\2\2\par
+\Y\P$\4\X1045:Append character \\{cur\_chr} and the following characters
+(if~any) to the current hlist in the current font; \&{goto} \\{reswitch} when a
+non-character has been fetched\X\S$\6
+\&{if} $((\\{head}=\\{tail})\W(\\{mode}>0))$ \1\&{then}\6
+\&{begin} \37\&{if} $(\\{insert\_src\_special\_auto})$ \1\&{then}\5
+\\{append\_src\_special};\2\6
+\&{end};\2\6
+\\{adjust\_space\_factor};\6
+\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\5
+$\\{disp}\K\\{t\_baseline\_shift}$\6
+\4\&{else} $\\{disp}\K\\{y\_baseline\_shift}$;\2\6
+\X1470:Append \\{disp\_node} at begin of displace area\X;\6
+$\\{main\_f}\K\\{cur\_font}$;\5
+$\\{bchar}\K\\{font\_bchar}[\\{main\_f}]$;\5
+$\\{false\_bchar}\K\\{font\_false\_bchar}[\\{main\_f}]$;\6
+\&{if} $\\{mode}>0$ \1\&{then}\6
+\&{if} $\\{language}\I\\{clang}$ \1\&{then}\5
+\\{fix\_language};\2\2\6
+$\\{fast\_get\_avail}(\\{lig\_stack})$;\5
+$\\{font}(\\{lig\_stack})\K\\{main\_f}$;\5
+$\\{cur\_l}\K\\{qi}(\\{cur\_chr})$;\5
+$\\{character}(\\{lig\_stack})\K\\{cur\_l}$;\6
+$\\{cur\_q}\K\\{tail}$;\6
+\&{if} $\\{cancel\_boundary}$ \1\&{then}\6
+\&{begin} \37$\\{cancel\_boundary}\K\\{false}$;\5
+$\\{main\_k}\K\\{non\_address}$;\6
+\&{end}\6
+\4\&{else} $\\{main\_k}\K\\{bchar\_label}[\\{main\_f}]$;\2\6
+\&{if} $\\{main\_k}=\\{non\_address}$ \1\&{then}\5
+\&{goto} \37$\\{main\_loop\_move}+2$;\C{no left boundary processing}\2\6
+$\\{cur\_r}\K\\{cur\_l}$;\5
+$\\{cur\_l}\K\\{non\_char}$;\5
+\&{goto} \37$\\{main\_lig\_loop}+1$;\C{begin with cursor after left boundary}\7
+\4\\{main\_loop\_wrapup}: \37\X1046:Make a ligature node, if \\{ligature%
+\_present}; insert a null discretionary, if appropriate\X;\6
+\4\\{main\_loop\_move}: \37\X1047:If the cursor is immediately followed by the
+right boundary, \&{goto} \\{reswitch}; if it's followed by an invalid
+character, \&{goto} \\{big\_switch}; otherwise move the cursor one step to the
+right and \&{goto} \\{main\_lig\_loop}\X;\6
+\4\\{main\_loop\_lookahead}: \37\X1049:Look ahead for another character, or
+leave \\{lig\_stack} empty if there's none there\X;\6
+\4\\{main\_lig\_loop}: \37\X1051:If there's a ligature/kern command relevant to
+\\{cur\_l} and \\{cur\_r}, adjust the text appropriately; exit to \\{main\_loop%
+\_wrapup}\X;\6
+\4\\{main\_loop\_move\_lig}: \37\X1048:Move the cursor past a pseudo-ligature,
+then \&{goto} \\{main\_loop\_lookahead} or \\{main\_lig\_loop}\X\par
+\U1041.\fi
+
+\M1046. If $\\{link}(\\{cur\_q})$ is nonnull when \\{wrapup} is invoked, \\{cur%
+\_q} points to
+the list of characters that were consumed while building the ligature
+character~\\{cur\_l}.
+
+A discretionary break is not inserted for an explicit hyphen when we are in
+restricted horizontal mode. In particular, this avoids putting discretionary
+nodes inside of other discretionaries.
+
+\Y\P\D \37$\\{pack\_lig}(\#)\S$\C{the parameter is either \\{rt\_hit} or %
+\\{false}}\6
+\&{begin} \37$\\{main\_p}\K\\{new\_ligature}(\\{main\_f},\39\\{cur\_l},\39%
+\\{link}(\\{cur\_q}))$;\6
+\&{if} $\\{lft\_hit}$ \1\&{then}\6
+\&{begin} \37$\\{subtype}(\\{main\_p})\K2$;\5
+$\\{lft\_hit}\K\\{false}$;\6
+\&{end};\2\6
+\&{if} $\#$ \1\&{then}\6
+\&{if} $\\{lig\_stack}=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{incr}(\\{subtype}(\\{main\_p}))$;\5
+$\\{rt\_hit}\K\\{false}$;\6
+\&{end};\2\2\6
+$\\{link}(\\{cur\_q})\K\\{main\_p}$;\5
+$\\{tail}\K\\{main\_p}$;\5
+$\\{ligature\_present}\K\\{false}$;\6
+\&{end}\par
+\P\D \37$\\{wrapup}(\#)\S$\1\6
+\&{if} $\\{cur\_l}<\\{non\_char}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{link}(\\{cur\_q})>\\{null}$ \1\&{then}\6
+\&{if} $\\{character}(\\{tail})=\\{qi}(\\{hyphen\_char}[\\{main\_f}])$ \1%
+\&{then}\5
+$\\{ins\_disc}\K\\{true}$;\2\2\6
+\&{if} $\\{ligature\_present}$ \1\&{then}\5
+$\\{pack\_lig}(\#)$;\2\6
+\&{if} $\\{ins\_disc}$ \1\&{then}\6
+\&{begin} \37$\\{ins\_disc}\K\\{false}$;\6
+\&{if} $\\{mode}>0$ \1\&{then}\5
+$\\{tail\_append}(\\{new\_disc})$;\2\6
+\&{end};\2\6
+\&{end}\2\2\par
+\Y\P$\4\X1046:Make a ligature node, if \\{ligature\_present}; insert a null
+discretionary, if appropriate\X\S$\6
+$\\{wrapup}(\\{rt\_hit})$\par
+\U1045.\fi
+
+\M1047. \P$\X1047:If the cursor is immediately followed by the right boundary, %
+\&{goto} \\{reswitch}; if it's followed by an invalid character, \&{goto} %
+\\{big\_switch}; otherwise move the cursor one step to the right and \&{goto} %
+\\{main\_lig\_loop}\X\S$\6
+\&{if} $\\{lig\_stack}=\\{null}$ \1\&{then}\6
+\&{begin} \37\X1471:Append \\{disp\_node} at end of displace area\X;\6
+\&{goto} \37\\{reswitch};\6
+\&{end};\2\6
+$\\{cur\_q}\K\\{tail}$;\5
+$\\{cur\_l}\K\\{character}(\\{lig\_stack})$;\6
+\4$\\{main\_loop\_move}+1$: \37\&{if} $\R\\{is\_char\_node}(\\{lig\_stack})$ \1%
+\&{then}\5
+\&{goto} \37\\{main\_loop\_move\_lig};\2\6
+\4$\\{main\_loop\_move}+2$: \37\&{if} $(\\{qo}(\\{effective\_char}(\\{false},%
+\39\\{main\_f},\39\\{qi}(\\{cur\_chr})))>\\{font\_ec}[\\{main\_f}])\V(\\{qo}(%
+\\{effective\_char}(\\{false},\39\\{main\_f},\39\\{qi}(\\{cur\_chr})))<\\{font%
+\_bc}[\\{main\_f}])$ \1\&{then}\6
+\&{begin} \37$\\{char\_warning}(\\{main\_f},\39\\{cur\_chr})$;\5
+$\\{free\_avail}(\\{lig\_stack})$;\5
+\&{goto} \37\\{big\_switch};\6
+\&{end};\2\6
+$\\{main\_i}\K\\{effective\_char\_info}(\\{main\_f},\39\\{cur\_l})$;\6
+\&{if} $\R\\{char\_exists}(\\{main\_i})$ \1\&{then}\6
+\&{begin} \37$\\{char\_warning}(\\{main\_f},\39\\{cur\_chr})$;\5
+$\\{free\_avail}(\\{lig\_stack})$;\5
+\&{goto} \37\\{big\_switch};\6
+\&{end};\2\6
+$\\{link}(\\{tail})\K\\{lig\_stack}$;\5
+$\\{tail}\K\\{lig\_stack}$\C{\\{main\_loop\_lookahead} is next}\par
+\U1045.\fi
+
+\M1048. Here we are at \\{main\_loop\_move\_lig}.
+When we begin this code we have $\\{cur\_q}=\\{tail}$ and $\\{cur\_l}=%
+\\{character}(\\{lig\_stack})$.
+
+\Y\P$\4\X1048:Move the cursor past a pseudo-ligature, then \&{goto} \\{main%
+\_loop\_lookahead} or \\{main\_lig\_loop}\X\S$\6
+$\\{main\_p}\K\\{lig\_ptr}(\\{lig\_stack})$;\6
+\&{if} $\\{main\_p}>\\{null}$ \1\&{then}\5
+$\\{tail\_append}(\\{main\_p})$;\C{append a single character}\2\6
+$\\{temp\_ptr}\K\\{lig\_stack}$;\5
+$\\{lig\_stack}\K\\{link}(\\{temp\_ptr})$;\5
+$\\{free\_node}(\\{temp\_ptr},\39\\{small\_node\_size})$;\5
+$\\{main\_i}\K\\{char\_info}(\\{main\_f})(\\{cur\_l})$;\5
+$\\{ligature\_present}\K\\{true}$;\6
+\&{if} $\\{lig\_stack}=\\{null}$ \1\&{then}\6
+\&{if} $\\{main\_p}>\\{null}$ \1\&{then}\5
+\&{goto} \37\\{main\_loop\_lookahead}\6
+\4\&{else} $\\{cur\_r}\K\\{bchar}$\2\6
+\4\&{else} $\\{cur\_r}\K\\{character}(\\{lig\_stack})$;\2\6
+\&{goto} \37\\{main\_lig\_loop}\par
+\U1045.\fi
+
+\M1049. The result of \.{\\char} can participate in a ligature or kern, so we
+must
+look ahead for it.
+
+\Y\P$\4\X1049:Look ahead for another character, or leave \\{lig\_stack} empty
+if there's none there\X\S$\6
+\\{get\_next};\C{set only \\{cur\_cmd} and \\{cur\_chr}, for speed}\6
+\&{if} $\\{cur\_cmd}=\\{letter}$ \1\&{then}\5
+\&{goto} \37$\\{main\_loop\_lookahead}+1$;\2\6
+\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=%
+\\{other\_kchar})$ \1\&{then}\5
+\X1050:goto \\{main\_lig\_loop}\X;\2\6
+\&{if} $\\{cur\_cmd}=\\{other\_char}$ \1\&{then}\5
+\&{goto} \37$\\{main\_loop\_lookahead}+1$;\2\6
+\&{if} $\\{cur\_cmd}=\\{char\_given}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ \1\&{then}\5
+\&{goto} \37$\\{main\_loop\_lookahead}+1$\6
+\4\&{else} \X1050:goto \\{main\_lig\_loop}\X;\2\6
+\&{end};\2\6
+\\{x\_token};\C{now expand and set \\{cur\_cmd}, \\{cur\_chr}, \\{cur\_tok}}\6
+\&{if} $\\{cur\_cmd}=\\{letter}$ \1\&{then}\5
+\&{goto} \37$\\{main\_loop\_lookahead}+1$;\2\6
+\&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur\_cmd}=%
+\\{other\_kchar})$ \1\&{then}\5
+\X1050:goto \\{main\_lig\_loop}\X;\2\6
+\&{if} $\\{cur\_cmd}=\\{other\_char}$ \1\&{then}\5
+\&{goto} \37$\\{main\_loop\_lookahead}+1$;\2\6
+\&{if} $\\{cur\_cmd}=\\{char\_given}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ \1\&{then}\5
+\&{goto} \37$\\{main\_loop\_lookahead}+1$\6
+\4\&{else} \X1050:goto \\{main\_lig\_loop}\X;\2\6
+\&{end};\2\6
+\&{if} $\\{cur\_cmd}=\\{char\_num}$ \1\&{then}\6
+\&{begin} \37\\{scan\_char\_num};\5
+$\\{cur\_chr}\K\\{cur\_val}$;\6
+\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ \1\&{then}\5
+\&{goto} \37$\\{main\_loop\_lookahead}+1$\6
+\4\&{else} \X1050:goto \\{main\_lig\_loop}\X;\2\6
+\&{end};\2\6
+\&{if} $\\{cur\_cmd}=\\{inhibit\_glue}$ \1\&{then}\6
+\&{begin} \37$\\{inhibit\_glue\_flag}\K\\{true}$;\5
+\&{goto} \37\\{main\_loop\_lookahead};\6
+\&{end};\2\6
+\&{if} $\\{cur\_cmd}=\\{no\_boundary}$ \1\&{then}\5
+$\\{bchar}\K\\{non\_char}$;\2\6
+$\\{cur\_r}\K\\{bchar}$;\5
+$\\{lig\_stack}\K\\{null}$;\5
+\&{goto} \37\\{main\_lig\_loop};\6
+\4$\\{main\_loop\_lookahead}+1$: \37\\{adjust\_space\_factor};\5
+$\\{inhibit\_glue\_flag}\K\\{false}$;\5
+$\\{fast\_get\_avail}(\\{lig\_stack})$;\5
+$\\{font}(\\{lig\_stack})\K\\{main\_f}$;\5
+$\\{cur\_r}\K\\{qi}(\\{cur\_chr})$;\5
+$\\{character}(\\{lig\_stack})\K\\{cur\_r}$;\6
+\&{if} $\\{cur\_r}=\\{false\_bchar}$ \1\&{then}\5
+$\\{cur\_r}\K\\{non\_char}$\C{this prevents spurious ligatures}\2\par
+\U1045.\fi
+
+\M1050. \P$\X1050:goto \\{main\_lig\_loop}\X\S$\6
+\&{begin} \37$\\{bchar}\K\\{non\_char}$;\5
+$\\{cur\_r}\K\\{bchar}$;\5
+$\\{lig\_stack}\K\\{null}$;\6
+\&{if} $\\{ligature\_present}$ \1\&{then}\5
+$\\{pack\_lig}(\\{rt\_hit})$;\2\6
+\&{if} $\\{ins\_kp}=\\{true}$ \1\&{then}\6
+\&{begin} \37$\\{cx}\K\\{cur\_l}$;\5
+\X1443:Insert kinsoku penalty\X;\6
+\&{end};\2\6
+$\\{ins\_kp}\K\\{false}$;\5
+\&{goto} \37\\{main\_loop\_j};\6
+\&{end}\par
+\Us1049, 1049, 1049, 1049\ETs1049.\fi
+
+\M1051. Even though comparatively few characters have a lig/kern program,
+several
+of the instructions here count as part of \TeX's inner loop, since a
+potentially long sequential search must be performed. For example, tests with
+Computer Modern Roman showed that about 40 per cent of all characters
+actually encountered in practice had a lig/kern program, and that about four
+lig/kern commands were investigated for every such character.
+
+At the beginning of this code we have $\\{main\_i}=\\{char\_info}(\\{main\_f})(%
+\\{cur\_l})$.
+
+\Y\P$\4\X1051:If there's a ligature/kern command relevant to \\{cur\_l} and %
+\\{cur\_r}, adjust the text appropriately; exit to \\{main\_loop\_wrapup}\X\S$\6
+\&{if} $\\{char\_tag}(\\{main\_i})\I\\{lig\_tag}$ \1\&{then}\5
+\&{goto} \37\\{main\_loop\_wrapup};\2\6
+\&{if} $\\{cur\_r}=\\{non\_char}$ \1\&{then}\5
+\&{goto} \37\\{main\_loop\_wrapup};\2\6
+$\\{main\_k}\K\\{lig\_kern\_start}(\\{main\_f})(\\{main\_i})$;\5
+$\\{main\_j}\K\\{font\_info}[\\{main\_k}].\\{qqqq}$;\6
+\&{if} $\\{skip\_byte}(\\{main\_j})\L\\{stop\_flag}$ \1\&{then}\5
+\&{goto} \37$\\{main\_lig\_loop}+2$;\2\6
+$\\{main\_k}\K\\{lig\_kern\_restart}(\\{main\_f})(\\{main\_j})$;\6
+\4$\\{main\_lig\_loop}+1$: \37$\\{main\_j}\K\\{font\_info}[\\{main\_k}].%
+\\{qqqq}$;\6
+\4$\\{main\_lig\_loop}+2$: \37\&{if} $\\{next\_char}(\\{main\_j})=\\{cur\_r}$ %
+\1\&{then}\6
+\&{if} $\\{skip\_byte}(\\{main\_j})\L\\{stop\_flag}$ \1\&{then}\5
+\X1052:Do ligature or kern command, returning to \\{main\_lig\_loop} or \\{main%
+\_loop\_wrapup} or \\{main\_loop\_move}\X;\2\2\6
+\&{if} $\\{skip\_byte}(\\{main\_j})=\\{qi}(0)$ \1\&{then}\5
+$\\{incr}(\\{main\_k})$\6
+\4\&{else} \&{begin} \37\&{if} $\\{skip\_byte}(\\{main\_j})\G\\{stop\_flag}$ \1%
+\&{then}\5
+\&{goto} \37\\{main\_loop\_wrapup};\2\6
+$\\{main\_k}\K\\{main\_k}+\\{qo}(\\{skip\_byte}(\\{main\_j}))+1$;\6
+\&{end};\2\6
+\&{goto} \37$\\{main\_lig\_loop}+1$\par
+\U1045.\fi
+
+\M1052. When a ligature or kern instruction matches a character, we know from
+\\{read\_font\_info} that the character exists in the font, even though we
+haven't verified its existence in the normal way.
+
+This section could be made into a subroutine, if the code inside
+\\{main\_control} needs to be shortened.
+
+\chardef\?='174 % vertical line to indicate character retention
+
+\Y\P$\4\X1052:Do ligature or kern command, returning to \\{main\_lig\_loop} or %
+\\{main\_loop\_wrapup} or \\{main\_loop\_move}\X\S$\6
+\&{begin} \37\&{if} $\\{op\_byte}(\\{main\_j})\G\\{kern\_flag}$ \1\&{then}\6
+\&{begin} \37$\\{wrapup}(\\{rt\_hit})$;\5
+$\\{tail\_append}(\\{new\_kern}(\\{char\_kern}(\\{main\_f})(\\{main\_j})))$;\5
+\&{goto} \37\\{main\_loop\_move};\6
+\&{end};\2\6
+\&{if} $\\{cur\_l}=\\{non\_char}$ \1\&{then}\5
+$\\{lft\_hit}\K\\{true}$\6
+\4\&{else} \&{if} $\\{lig\_stack}=\\{null}$ \1\&{then}\5
+$\\{rt\_hit}\K\\{true}$;\2\2\6
+\\{check\_interrupt};\C{allow a way out in case there's an infinite ligature
+loop}\6
+\&{case} $\\{op\_byte}(\\{main\_j})$ \1\&{of}\6
+\4$\\{qi}(1),\39\\{qi}(5)$: \37\&{begin} \37$\\{cur\_l}\K\\{rem\_byte}(\\{main%
+\_j})$;\C{\.{=:\?}, \.{=:\?>}}\6
+$\\{main\_i}\K\\{char\_info}(\\{main\_f})(\\{cur\_l})$;\5
+$\\{ligature\_present}\K\\{true}$;\6
+\&{end};\6
+\4$\\{qi}(2),\39\\{qi}(6)$: \37\&{begin} \37$\\{cur\_r}\K\\{rem\_byte}(\\{main%
+\_j})$;\C{\.{\?=:}, \.{\?=:>}}\6
+\&{if} $\\{lig\_stack}=\\{null}$ \1\&{then}\C{right boundary character is being
+consumed}\6
+\&{begin} \37$\\{lig\_stack}\K\\{new\_lig\_item}(\\{cur\_r})$;\5
+$\\{bchar}\K\\{non\_char}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{is\_char\_node}(\\{lig\_stack})$ \1\&{then}\C{$\\{link}(%
+\\{lig\_stack})=\\{null}$}\6
+\&{begin} \37$\\{main\_p}\K\\{lig\_stack}$;\5
+$\\{lig\_stack}\K\\{new\_lig\_item}(\\{cur\_r})$;\5
+$\\{lig\_ptr}(\\{lig\_stack})\K\\{main\_p}$;\6
+\&{end}\6
+\4\&{else} $\\{character}(\\{lig\_stack})\K\\{cur\_r}$;\2\2\6
+\&{end};\6
+\4$\\{qi}(3)$: \37\&{begin} \37$\\{cur\_r}\K\\{rem\_byte}(\\{main\_j})$;\C{\.{%
+\?=:\?}}\6
+$\\{main\_p}\K\\{lig\_stack}$;\5
+$\\{lig\_stack}\K\\{new\_lig\_item}(\\{cur\_r})$;\5
+$\\{link}(\\{lig\_stack})\K\\{main\_p}$;\6
+\&{end};\6
+\4$\\{qi}(7),\39\\{qi}(11)$: \37\&{begin} \37$\\{wrapup}(\\{false})$;\C{\.{\?=:%
+\?>}, \.{\?=:\?>>}}\6
+$\\{cur\_q}\K\\{tail}$;\5
+$\\{cur\_l}\K\\{rem\_byte}(\\{main\_j})$;\5
+$\\{main\_i}\K\\{char\_info}(\\{main\_f})(\\{cur\_l})$;\5
+$\\{ligature\_present}\K\\{true}$;\6
+\&{end};\6
+\4\&{othercases} \37\&{begin} \37$\\{cur\_l}\K\\{rem\_byte}(\\{main\_j})$;\5
+$\\{ligature\_present}\K\\{true}$;\C{\.{=:}}\6
+\&{if} $\\{lig\_stack}=\\{null}$ \1\&{then}\5
+\&{goto} \37\\{main\_loop\_wrapup}\6
+\4\&{else} \&{goto} \37$\\{main\_loop\_move}+1$;\2\6
+\&{end}\2\6
+\&{endcases};\6
+\&{if} $\\{op\_byte}(\\{main\_j})>\\{qi}(4)$ \1\&{then}\6
+\&{if} $\\{op\_byte}(\\{main\_j})\I\\{qi}(7)$ \1\&{then}\5
+\&{goto} \37\\{main\_loop\_wrapup};\2\2\6
+\&{if} $\\{cur\_l}<\\{non\_char}$ \1\&{then}\5
+\&{goto} \37\\{main\_lig\_loop};\2\6
+$\\{main\_k}\K\\{bchar\_label}[\\{main\_f}]$;\5
+\&{goto} \37$\\{main\_lig\_loop}+1$;\6
+\&{end}\par
+\U1051.\fi
+
+\M1053. The occurrence of blank spaces is almost part of \TeX's inner loop,
+since we usually encounter about one space for every five non-blank characters.
+Therefore \\{main\_control} gives second-highest priority to ordinary spaces.
+
+When a glue parameter like \.{\\spaceskip} is set to `\.{0pt}', we will
+see to it later that the corresponding glue specification is precisely
+\\{zero\_glue}, not merely a pointer to some specification that happens
+to be full of zeroes. Therefore it is simple to test whether a glue parameter
+is zero or~not.
+
+\Y\P$\4\X1053:Append a normal inter-word space to the current list, then %
+\&{goto} \\{big\_switch}\X\S$\6
+\&{if} $\\{space\_skip}=\\{zero\_glue}$ \1\&{then}\6
+\&{begin} \37\X1054:Find the glue specification, \\{main\_p}, for text spaces
+in the current font\X;\6
+$\\{temp\_ptr}\K\\{new\_glue}(\\{main\_p})$;\6
+\&{end}\6
+\4\&{else} $\\{temp\_ptr}\K\\{new\_param\_glue}(\\{space\_skip\_code})$;\2\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=\\{disp\_node})$ \1%
+\&{then}\6
+\&{begin} \37$\\{link}(\\{prev\_node})\K\\{temp\_ptr}$;\5
+$\\{link}(\\{temp\_ptr})\K\\{tail}$;\5
+$\\{prev\_node}\K\\{temp\_ptr}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{link}(\\{tail})\K\\{temp\_ptr}$;\5
+$\\{tail}\K\\{temp\_ptr}$;\6
+\&{end};\2\6
+\&{goto} \37\\{big\_switch}\par
+\U1041.\fi
+
+\M1054. Having \\{font\_glue} allocated for each text font saves both time and
+memory.
+If any of the three spacing parameters are subsequently changed by the
+use of \.{\\fontdimen}, the \\{find\_font\_dimen} procedure deallocates the
+\\{font\_glue} specification allocated here.
+
+\Y\P$\4\X1054:Find the glue specification, \\{main\_p}, for text spaces in the
+current font\X\S$\6
+\&{begin} \37$\\{main\_p}\K\\{font\_glue}[\\{cur\_font}]$;\6
+\&{if} $\\{main\_p}=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{main\_p}\K\\{new\_spec}(\\{zero\_glue})$;\5
+$\\{main\_k}\K\\{param\_base}[\\{cur\_font}]+\\{space\_code}$;\5
+$\\{width}(\\{main\_p})\K\\{font\_info}[\\{main\_k}].\\{sc}$;\C{that's $%
+\\{space}(\\{cur\_font})$}\6
+$\\{stretch}(\\{main\_p})\K\\{font\_info}[\\{main\_k}+1].\\{sc}$;\C{and $%
+\\{space\_stretch}(\\{cur\_font})$}\6
+$\\{shrink}(\\{main\_p})\K\\{font\_info}[\\{main\_k}+2].\\{sc}$;\C{and $%
+\\{space\_shrink}(\\{cur\_font})$}\6
+$\\{font\_glue}[\\{cur\_font}]\K\\{main\_p}$;\6
+\&{end};\2\6
+\&{end}\par
+\Us1053\ET1055.\fi
+
+\M1055. \P$\X1055:Declare action procedures for use by \\{main\_control}\X\S$\6
+\4\&{procedure}\1\  \37\\{app\_space};\C{handle spaces when $\\{space\_factor}%
+\I1000$}\6
+\4\&{var} \37\|q: \37\\{pointer};\C{glue node}\2\6
+\&{begin} \37\&{if} $(\\{space\_factor}\G2000)\W(\\{xspace\_skip}\I\\{zero%
+\_glue})$ \1\&{then}\5
+$\|q\K\\{new\_param\_glue}(\\{xspace\_skip\_code})$\6
+\4\&{else} \&{begin} \37\&{if} $\\{space\_skip}\I\\{zero\_glue}$ \1\&{then}\5
+$\\{main\_p}\K\\{space\_skip}$\6
+\4\&{else} \X1054:Find the glue specification, \\{main\_p}, for text spaces in
+the current font\X;\2\6
+$\\{main\_p}\K\\{new\_spec}(\\{main\_p})$;\5
+\X1056:Modify the glue specification in \\{main\_p} according to the space
+factor\X;\6
+$\|q\K\\{new\_glue}(\\{main\_p})$;\5
+$\\{glue\_ref\_count}(\\{main\_p})\K\\{null}$;\6
+\&{end};\2\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=\\{disp\_node})$ \1%
+\&{then}\6
+\&{begin} \37$\\{link}(\\{prev\_node})\K\|q$;\5
+$\\{link}(\|q)\K\\{tail}$;\5
+$\\{prev\_node}\K\|q$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{link}(\\{tail})\K\|q$;\5
+$\\{tail}\K\|q$;\6
+\&{end}\2\6
+\&{end};\par
+\As1059, 1061, 1062, 1063, 1066, 1072, 1073, 1076, 1081, 1082, 1087, 1091,
+1096, 1098, 1103, 1105, 1107, 1108, 1111, 1113, 1115, 1117, 1122, 1125, 1129,
+1131, 1135, 1139, 1141, 1143, 1147, 1148, 1150, 1154, 1163, 1167, 1171, 1172,
+1175, 1177, 1184, 1186, 1188, 1193, 1203, 1206, 1212, 1223, 1283, 1288, 1292,
+1301, 1306, 1315, 1361, 1389, 1468\ETs1475.
+\U1041.\fi
+
+\M1056. \P$\X1056:Modify the glue specification in \\{main\_p} according to the
+space factor\X\S$\6
+\&{if} $\\{space\_factor}\G2000$ \1\&{then}\5
+$\\{width}(\\{main\_p})\K\\{width}(\\{main\_p})+\\{extra\_space}(\\{cur%
+\_font})$;\2\6
+$\\{stretch}(\\{main\_p})\K\\{xn\_over\_d}(\\{stretch}(\\{main\_p}),\39\\{space%
+\_factor},\391000)$;\5
+$\\{shrink}(\\{main\_p})\K\\{xn\_over\_d}(\\{shrink}(\\{main\_p}),\391000,\39%
+\\{space\_factor})$\par
+\U1055.\fi
+
+\M1057. Whew---that covers the main loop. We can now proceed at a leisurely
+pace through the other combinations of possibilities.
+
+\Y\P\D \37$\\{any\_mode}(\#)\S\\{vmode}+\#,\39\\{hmode}+\#,\39\\{mmode}+\#$%
+\C{for mode-independent commands}\par
+\Y\P$\4\X1057:Cases of \\{main\_control} that are not part of the inner loop\X%
+\S$\6
+\4$\\{any\_mode}(\\{relax}),\39\\{vmode}+\\{spacer},\39\\{mmode}+\\{spacer},\39%
+\\{mmode}+\\{no\_boundary}$: \37\\{do\_nothing};\6
+\4$\\{any\_mode}(\\{ignore\_spaces})$: \37\&{begin} \37\X417:Get the next
+non-blank non-call token\X;\6
+\&{goto} \37\\{reswitch};\6
+\&{end};\6
+\4$\\{vmode}+\\{stop}$: \37\&{if} $\\{its\_all\_over}$ \1\&{then}\5
+\&{return};\C{this is the only way out}\2\6
+\hbox{\4}\X1060:Forbidden cases detected in \\{main\_control}\X\ $\,\\{any%
+\_mode}(\\{mac\_param})$: \37\\{report\_illegal\_case};\6
+\4\X1058:Math-only cases in non-math modes, or vice versa\X: \37\\{insert%
+\_dollar\_sign};\5
+\hbox{\4}\X1068:Cases of \\{main\_control} that build boxes and lists\X\6
+\hbox{\4}\X1222:Cases of \\{main\_control} that don't depend on \\{mode}\X\6
+\hbox{\4}\X1360:Cases of \\{main\_control} that are for extensions to \TeX\X\par
+\U1041.\fi
+
+\M1058. Here is a list of cases where the user has probably gotten into or out
+of math
+mode by mistake. \TeX\ will insert a dollar sign and rescan the current token.
+
+\Y\P\D \37$\\{non\_math}(\#)\S\\{vmode}+\#,\39\\{hmode}+\#$\par
+\Y\P$\4\X1058:Math-only cases in non-math modes, or vice versa\X\S$\6
+$\\{non\_math}(\\{sup\_mark}),\39\\{non\_math}(\\{sub\_mark}),\39\\{non\_math}(%
+\\{math\_char\_num}),\39\\{non\_math}(\\{math\_given}),\39\\{non\_math}(\\{math%
+\_comp}),\39\\{non\_math}(\\{delim\_num}),\39\\{non\_math}(\\{left\_right}),\39%
+\\{non\_math}(\\{above}),\39\\{non\_math}(\\{radical}),\39\\{non\_math}(\\{math%
+\_style}),\39\\{non\_math}(\\{math\_choice}),\39\\{non\_math}(\\{vcenter}),\39%
+\\{non\_math}(\\{non\_script}),\39\\{non\_math}(\\{mkern}),\39\\{non\_math}(%
+\\{limit\_switch}),\39\\{non\_math}(\\{mskip}),\39\\{non\_math}(\\{math%
+\_accent}),\39\\{mmode}+\\{endv},\39\\{mmode}+\\{par\_end},\39\\{mmode}+%
+\\{stop},\39\\{mmode}+\\{vskip},\39\\{mmode}+\\{un\_vbox},\39\\{mmode}+%
+\\{valign},\39\\{mmode}+\\{hrule}$\par
+\U1057.\fi
+
+\M1059. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{insert\_dollar\_sign};\2\6
+\&{begin} \37\\{back\_input};\5
+$\\{cur\_tok}\K\\{math\_shift\_token}+\.{"\$"}$;\5
+$\\{print\_err}(\.{"Missing\ \$\ inserted"})$;\5
+$\\{help2}(\.{"I\'ve\ inserted\ a\ begin-math/end-math\ symbol\ since\ I\
+think"})$\6
+$(\.{"you\ left\ one\ out.\ Proceed,\ with\ fingers\ crossed."})$;\5
+\\{ins\_error};\6
+\&{end};\par
+\fi
+
+\M1060. When erroneous situations arise, \TeX\ usually issues an error message
+specific to the particular error. For example, `\.{\\noalign}' should
+not appear in any mode, since it is recognized by the \\{align\_peek} routine
+in all of its legitimate appearances; a special error message is given
+when `\.{\\noalign}' occurs elsewhere. But sometimes the most appropriate
+error message is simply that the user is not allowed to do what he or she
+has attempted. For example, `\.{\\moveleft}' is allowed only in vertical mode,
+and `\.{\\lower}' only in non-vertical modes.  Such cases are enumerated
+here and in the other sections referred to under `See also \dots.'
+
+\Y\P$\4\X1060:Forbidden cases detected in \\{main\_control}\X\S$\6
+$\\{vmode}+\\{vmove},\39\\{hmode}+\\{hmove},\39\\{mmode}+\\{hmove},\39\\{any%
+\_mode}(\\{last\_item}),\39$\par
+\As1110, 1123\ETs1156.
+\U1057.\fi
+
+\M1061. The `\\{you\_cant}' procedure prints a line saying that the current
+command
+is illegal in the current mode; it identifies these things symbolically.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{you\_cant};\2\6
+\&{begin} \37$\\{print\_err}(\.{"You\ can\'t\ use\ \`"})$;\5
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\5
+$\\{print\_in\_mode}(\\{mode})$;\6
+\&{end};\par
+\fi
+
+\M1062. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{report\_illegal\_case};\2\6
+\&{begin} \37\\{you\_cant};\5
+$\\{help4}(\.{"Sorry,\ but\ I\'m\ not\ programmed\ to\ handle\ this\ case;"})$\6
+$(\.{"I\'ll\ just\ pretend\ that\ you\ didn\'t\ ask\ for\ it."})$\6
+$(\.{"If\ you\'re\ in\ the\ wrong\ mode,\ you\ might\ be\ able\ to"})$\6
+$(\.{"return\ to\ the\ right\ one\ by\ typing\ \`I\}\'\ or\ \`I\$\'\ or\ \`I%
+\\par\'."})$;\6
+\\{error};\6
+\&{end};\par
+\fi
+
+\M1063. Some operations are allowed only in privileged modes, i.e., in cases
+that $\\{mode}>0$. The \\{privileged} function is used to detect violations
+of this rule; it issues an error message and returns \\{false} if the
+current \\{mode} is negative.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{function}\1\  \37\\{privileged}: \37\\{boolean};\2\6
+\&{begin} \37\&{if} $\\{mode}>0$ \1\&{then}\5
+$\\{privileged}\K\\{true}$\6
+\4\&{else} \&{begin} \37\\{report\_illegal\_case};\5
+$\\{privileged}\K\\{false}$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1064. Either \.{\\dump} or \.{\\end} will cause \\{main\_control} to enter
+the
+endgame, since both of them have `\\{stop}' as their command code.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"end"},\39\\{stop},\390)$;\6
+$\\{primitive}(\.{"dump"},\39\\{stop},\391)$;\par
+\fi
+
+\M1065. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{stop}: \37\&{if} $\\{chr\_code}=1$ \1\&{then}\5
+$\\{print\_esc}(\.{"dump"})$\ \&{else} $\\{print\_esc}(\.{"end"})$;\2\par
+\fi
+
+\M1066. We don't want to leave \\{main\_control} immediately when a \\{stop}
+command
+is sensed, because it may be necessary to invoke an \.{\\output} routine
+several times before things really grind to a halt. (The output routine
+might even say `\.{\\gdef\\end\{...\}}', to prolong the life of the job.)
+Therefore \\{its\_all\_over} is \\{true} only when the current page
+and contribution list are empty, and when the last output was not a
+``dead cycle.''
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{function}\1\  \37\\{its\_all\_over}: \37\\{boolean};\C{do this when \.{%
+\\end} or \.{\\dump} occurs}\6
+\4\&{label} \37\\{exit};\2\6
+\&{begin} \37\&{if} $\\{privileged}$ \1\&{then}\6
+\&{begin} \37\&{if} $(\\{page\_head}=\\{page\_tail})\W(\\{head}=\\{tail})\W(%
+\\{dead\_cycles}=0)$ \1\&{then}\6
+\&{begin} \37$\\{its\_all\_over}\K\\{true}$;\5
+\&{return};\6
+\&{end};\2\6
+\\{back\_input};\C{we will try to end again after ejecting residual material}\6
+$\\{tail\_append}(\\{new\_null\_box})$;\5
+$\\{width}(\\{tail})\K\\{hsize}$;\5
+$\\{tail\_append}(\\{new\_glue}(\\{fill\_glue}))$;\5
+$\\{tail\_append}(\\{new\_penalty}(-\O{10000000000}))$;\6
+\\{build\_page};\C{append \.{\\hbox to \\hsize\{\}\\vfill%
+\\penalty-'10000000000}}\6
+\&{end};\2\6
+$\\{its\_all\_over}\K\\{false}$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\N1067.  \[47] Building boxes and lists.
+The most important parts of \\{main\_control} are concerned with \TeX's
+chief mission of box-making. We need to control the activities that put
+entries on vlists and hlists, as well as the activities that convert
+those lists into boxes. All of the necessary machinery has already been
+developed; it remains for us to ``push the buttons'' at the right times.
+
+\fi
+
+\M1068. As an introduction to these routines, let's consider one of the
+simplest
+cases: What happens when `\.{\\hrule}' occurs in vertical mode, or
+`\.{\\vrule}' in horizontal mode or math mode? The code in \\{main\_control}
+is short, since the \\{scan\_rule\_spec} routine already does most of what is
+required; thus, there is no need for a special action procedure.
+
+Note that baselineskip calculations are disabled after a rule in vertical
+mode, by setting $\\{prev\_depth}\K\\{ignore\_depth}$.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X\S$\6
+\4$\\{vmode}+\\{hrule},\39\\{hmode}+\\{vrule},\39\\{mmode}+\\{vrule}$: \37%
+\&{begin} \37$\\{tail\_append}(\\{scan\_rule\_spec})$;\6
+\&{if} $\\{abs}(\\{mode})=\\{vmode}$ \1\&{then}\5
+$\\{prev\_depth}\K\\{ignore\_depth}$\6
+\4\&{else} \&{if} $\\{abs}(\\{mode})=\\{hmode}$ \1\&{then}\5
+$\\{space\_factor}\K1000$;\2\2\6
+\&{end};\par
+\As1069, 1075, 1079, 1085, 1102, 1104, 1106, 1109, 1114, 1116, 1121, 1124,
+1128, 1134, 1138, 1142, 1146, 1149, 1152, 1162, 1166, 1170, 1174, 1176, 1179,
+1183, 1187, 1192, 1202\ETs1205.
+\U1057.\fi
+
+\M1069. The processing of things like \.{\\hskip} and \.{\\vskip} is slightly
+more complicated. But the code in \\{main\_control} is very short, since
+it simply calls on the action routine \\{append\_glue}. Similarly, \.{\\kern}
+activates \\{append\_kern}.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{vmode}+\\{vskip},\39\\{hmode}+\\{hskip},\39\\{mmode}+\\{hskip},\39%
+\\{mmode}+\\{mskip}$: \37\\{append\_glue};\6
+\4$\\{any\_mode}(\\{kern}),\39\\{mmode}+\\{mkern}$: \37\\{append\_kern};\par
+\fi
+
+\M1070. The \\{hskip} and \\{vskip} command codes are used for control
+sequences
+like \.{\\hss} and \.{\\vfil} as well as for \.{\\hskip} and \.{\\vskip}.
+The difference is in the value of \\{cur\_chr}.
+
+\Y\P\D \37$\\{fil\_code}=0$\C{identifies \.{\\hfil} and \.{\\vfil}}\par
+\P\D \37$\\{fill\_code}=1$\C{identifies \.{\\hfill} and \.{\\vfill}}\par
+\P\D \37$\\{ss\_code}=2$\C{identifies \.{\\hss} and \.{\\vss}}\par
+\P\D \37$\\{fil\_neg\_code}=3$\C{identifies \.{\\hfilneg} and \.{\\vfilneg}}\par
+\P\D \37$\\{skip\_code}=4$\C{identifies \.{\\hskip} and \.{\\vskip}}\par
+\P\D \37$\\{mskip\_code}=5$\C{identifies \.{\\mskip}}\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"hskip"},\39\\{hskip},\39\\{skip\_code})$;\6
+$\\{primitive}(\.{"hfil"},\39\\{hskip},\39\\{fil\_code})$;\5
+$\\{primitive}(\.{"hfill"},\39\\{hskip},\39\\{fill\_code})$;\6
+$\\{primitive}(\.{"hss"},\39\\{hskip},\39\\{ss\_code})$;\5
+$\\{primitive}(\.{"hfilneg"},\39\\{hskip},\39\\{fil\_neg\_code})$;\6
+$\\{primitive}(\.{"vskip"},\39\\{vskip},\39\\{skip\_code})$;\6
+$\\{primitive}(\.{"vfil"},\39\\{vskip},\39\\{fil\_code})$;\5
+$\\{primitive}(\.{"vfill"},\39\\{vskip},\39\\{fill\_code})$;\6
+$\\{primitive}(\.{"vss"},\39\\{vskip},\39\\{ss\_code})$;\5
+$\\{primitive}(\.{"vfilneg"},\39\\{vskip},\39\\{fil\_neg\_code})$;\6
+$\\{primitive}(\.{"mskip"},\39\\{mskip},\39\\{mskip\_code})$;\6
+$\\{primitive}(\.{"kern"},\39\\{kern},\39\\{explicit})$;\5
+$\\{primitive}(\.{"mkern"},\39\\{mkern},\39\\{mu\_glue})$;\par
+\fi
+
+\M1071. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{hskip}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{skip\_code}: \37$\\{print\_esc}(\.{"hskip"})$;\6
+\4\\{fil\_code}: \37$\\{print\_esc}(\.{"hfil"})$;\6
+\4\\{fill\_code}: \37$\\{print\_esc}(\.{"hfill"})$;\6
+\4\\{ss\_code}: \37$\\{print\_esc}(\.{"hss"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"hfilneg"})$\2\6
+\&{endcases};\6
+\4\\{vskip}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{skip\_code}: \37$\\{print\_esc}(\.{"vskip"})$;\6
+\4\\{fil\_code}: \37$\\{print\_esc}(\.{"vfil"})$;\6
+\4\\{fill\_code}: \37$\\{print\_esc}(\.{"vfill"})$;\6
+\4\\{ss\_code}: \37$\\{print\_esc}(\.{"vss"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"vfilneg"})$\2\6
+\&{endcases};\6
+\4\\{mskip}: \37$\\{print\_esc}(\.{"mskip"})$;\6
+\4\\{kern}: \37$\\{print\_esc}(\.{"kern"})$;\6
+\4\\{mkern}: \37$\\{print\_esc}(\.{"mkern"})$;\par
+\fi
+
+\M1072. All the work relating to glue creation has been relegated to the
+following subroutine. It does not call \\{build\_page}, because it is
+used in at least one place where that would be a mistake.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{append\_glue};\6
+\4\&{var} \37\|s: \37\\{small\_number};\C{modifier of skip command}\2\6
+\&{begin} \37$\|s\K\\{cur\_chr}$;\6
+\&{case} $\|s$ \1\&{of}\6
+\4\\{fil\_code}: \37$\\{cur\_val}\K\\{fil\_glue}$;\6
+\4\\{fill\_code}: \37$\\{cur\_val}\K\\{fill\_glue}$;\6
+\4\\{ss\_code}: \37$\\{cur\_val}\K\\{ss\_glue}$;\6
+\4\\{fil\_neg\_code}: \37$\\{cur\_val}\K\\{fil\_neg\_glue}$;\6
+\4\\{skip\_code}: \37$\\{scan\_glue}(\\{glue\_val})$;\6
+\4\\{mskip\_code}: \37$\\{scan\_glue}(\\{mu\_val})$;\2\6
+\&{end};\C{now \\{cur\_val} points to the glue specification}\6
+$\\{tail\_append}(\\{new\_glue}(\\{cur\_val}))$;\5
+$\\{inhibit\_glue\_flag}\K\\{false}$;\6
+\&{if} $\|s\G\\{skip\_code}$ \1\&{then}\6
+\&{begin} \37$\\{decr}(\\{glue\_ref\_count}(\\{cur\_val}))$;\6
+\&{if} $\|s>\\{skip\_code}$ \1\&{then}\5
+$\\{subtype}(\\{tail})\K\\{mu\_glue}$;\2\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1073. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{append\_kern};\6
+\4\&{var} \37\|s: \37\\{quarterword};\C{\\{subtype} of the kern node}\2\6
+\&{begin} \37$\|s\K\\{cur\_chr}$;\5
+$\\{scan\_dimen}(\|s=\\{mu\_glue},\39\\{false},\39\\{false})$;\5
+$\\{inhibit\_glue\_flag}\K\\{false}$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=\\{disp\_node})$ \1%
+\&{then}\6
+\&{begin} \37$\\{prev\_append}(\\{new\_kern}(\\{cur\_val}))$;\5
+$\\{subtype}(\\{prev\_node})\K\|s$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{tail\_append}(\\{new\_kern}(\\{cur\_val}))$;\5
+$\\{subtype}(\\{tail})\K\|s$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1074. Many of the actions related to box-making are triggered by the
+appearance
+of braces in the input. For example, when the user says `\.{\\hbox}
+\.{to} \.{100pt\{$\langle\,\hbox{hlist}\,\rangle$\}}' in vertical mode,
+the information about the box size (100pt, \\{exactly}) is put onto \\{save%
+\_stack}
+with a level boundary word just above it, and $\\{cur\_group}\K\\{adjusted%
+\_hbox\_group}$;
+\TeX\ enters restricted horizontal mode to process the hlist. The right
+brace eventually causes \\{save\_stack} to be restored to its former state,
+at which time the information about the box size (100pt, \\{exactly}) is
+available once again; a box is packaged and we leave restricted horizontal
+mode, appending the new box to the current list of the enclosing mode
+(in this case to the current list of vertical mode), followed by any
+vertical adjustments that were removed from the box by \\{hpack}.
+
+The next few sections of the program are therefore concerned with the
+treatment of left and right curly braces.
+
+\fi
+
+\M1075. If a left brace occurs in the middle of a page or paragraph, it simply
+introduces a new level of grouping, and the matching right brace will not have
+such a drastic effect. Such grouping affects neither the mode nor the
+current list.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{non\_math}(\\{left\_brace})$: \37$\\{new\_save\_level}(\\{simple%
+\_group})$;\6
+\4$\\{any\_mode}(\\{begin\_group})$: \37$\\{new\_save\_level}(\\{semi\_simple%
+\_group})$;\6
+\4$\\{any\_mode}(\\{end\_group})$: \37\&{if} $\\{cur\_group}=\\{semi\_simple%
+\_group}$ \1\&{then}\5
+\\{unsave}\6
+\4\&{else} \\{off\_save};\2\par
+\fi
+
+\M1076. We have to deal with errors in which braces and such things are not
+properly nested. Sometimes the user makes an error of commission by
+inserting an extra symbol, but sometimes the user makes an error of omission.
+\TeX\ can't always tell one from the other, so it makes a guess and tries
+to avoid getting into a loop.
+
+The \\{off\_save} routine is called when the current group code is wrong. It
+tries
+to insert something into the user's input that will help clean off
+the top level.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{off\_save};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{inserted token}\2\6
+\&{begin} \37\&{if} $\\{cur\_group}=\\{bottom\_level}$ \1\&{then}\5
+\X1078:Drop current token and complain that it was unmatched\X\6
+\4\&{else} \&{begin} \37\\{back\_input};\5
+$\|p\K\\{get\_avail}$;\5
+$\\{link}(\\{temp\_head})\K\|p$;\5
+$\\{print\_err}(\.{"Missing\ "})$;\5
+\X1077:Prepare to insert a token that matches \\{cur\_group}, and print what it
+is\X;\6
+$\\{print}(\.{"\ inserted"})$;\5
+$\\{ins\_list}(\\{link}(\\{temp\_head}))$;\5
+$\\{help5}(\.{"I\'ve\ inserted\ something\ that\ you\ may\ have\ forgotten."})$%
+\6
+$(\.{"(See\ the\ <inserted\ text>\ above.)"})$\6
+$(\.{"With\ luck,\ this\ will\ get\ me\ unwedged.\ But\ if\ you"})$\6
+$(\.{"really\ didn\'t\ forget\ anything,\ try\ typing\ \`2\'\ now;\ then"})$\6
+$(\.{"my\ insertion\ and\ my\ current\ dilemma\ will\ both\ disappear."})$;\5
+\\{error};\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1077. At this point, $\\{link}(\\{temp\_head})=\|p$, a pointer to an empty
+one-word node.
+
+\Y\P$\4\X1077:Prepare to insert a token that matches \\{cur\_group}, and print
+what it is\X\S$\6
+\&{case} $\\{cur\_group}$ \1\&{of}\6
+\4\\{semi\_simple\_group}: \37\&{begin} \37$\\{info}(\|p)\K\\{cs\_token\_flag}+%
+\\{frozen\_end\_group}$;\5
+$\\{print\_esc}(\.{"endgroup"})$;\6
+\&{end};\6
+\4\\{math\_shift\_group}: \37\&{begin} \37$\\{info}(\|p)\K\\{math\_shift%
+\_token}+\.{"\$"}$;\5
+$\\{print\_char}(\.{"\$"})$;\6
+\&{end};\6
+\4\\{math\_left\_group}: \37\&{begin} \37$\\{info}(\|p)\K\\{cs\_token\_flag}+%
+\\{frozen\_right}$;\5
+$\\{link}(\|p)\K\\{get\_avail}$;\5
+$\|p\K\\{link}(\|p)$;\5
+$\\{info}(\|p)\K\\{other\_token}+\.{"."}$;\5
+$\\{print\_esc}(\.{"right."})$;\6
+\&{end};\6
+\4\&{othercases} \37\&{begin} \37$\\{info}(\|p)\K\\{right\_brace\_token}+\.{"%
+\}"}$;\5
+$\\{print\_char}(\.{"\}"})$;\6
+\&{end}\2\6
+\&{endcases}\par
+\U1076.\fi
+
+\M1078. \P$\X1078:Drop current token and complain that it was unmatched\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Extra\ "})$;\5
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\5
+$\\{help1}(\.{"Things\ are\ pretty\ mixed\ up,\ but\ I\ think\ the\ worst\ is\
+over."})$;\6
+\\{error};\6
+\&{end}\par
+\U1076.\fi
+
+\M1079. The routine for a \\{right\_brace} character branches into many
+subcases,
+since a variety of things may happen, depending on \\{cur\_group}. Some
+types of groups are not supposed to be ended by a right brace; error
+messages are given in hopes of pinpointing the problem. Most branches
+of this routine will be filled in later, when we are ready to understand
+them; meanwhile, we must prepare ourselves to deal with such errors.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{right\_brace})$: \37\\{handle\_right\_brace};\par
+\fi
+
+\M1080. \P$\X1080:Declare the procedure called \\{handle\_right\_brace}\X\S$\6
+\4\&{procedure}\1\  \37\\{handle\_right\_brace};\6
+\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{for short-term use}\6
+\|r: \37\\{pointer};\C{temporaly}\6
+\|d: \37\\{scaled};\C{holds \\{split\_max\_depth} in \\{insert\_group}}\6
+\|f: \37\\{integer};\C{holds \\{floating\_penalty} in \\{insert\_group}}\2\6
+\&{begin} \37\&{case} $\\{cur\_group}$ \1\&{of}\6
+\4\\{simple\_group}: \37\\{unsave};\6
+\4\\{bottom\_level}: \37\&{begin} \37$\\{print\_err}(\.{"Too\ many\ \}\'s"})$;\5
+$\\{help2}(\.{"You\'ve\ closed\ more\ groups\ than\ you\ opened."})$\6
+$(\.{"Such\ booboos\ are\ generally\ harmless,\ so\ keep\ going."})$;\5
+\\{error};\6
+\&{end};\6
+\4$\\{semi\_simple\_group},\39\\{math\_shift\_group},\39\\{math\_left\_group}$:
+\37\\{extra\_right\_brace};\6
+\hbox{\4}\X1097:Cases of \\{handle\_right\_brace} where a \\{right\_brace}
+triggers a delayed action\X\6
+\4\&{othercases} \37$\\{confusion}(\.{"rightbrace"})$\2\6
+\&{endcases};\6
+\&{end};\par
+\U1041.\fi
+
+\M1081. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{extra\_right\_brace};\2\6
+\&{begin} \37$\\{print\_err}(\.{"Extra\ \},\ or\ forgotten\ "})$;\6
+\&{case} $\\{cur\_group}$ \1\&{of}\6
+\4\\{semi\_simple\_group}: \37$\\{print\_esc}(\.{"endgroup"})$;\6
+\4\\{math\_shift\_group}: \37$\\{print\_char}(\.{"\$"})$;\6
+\4\\{math\_left\_group}: \37$\\{print\_esc}(\.{"right"})$;\2\6
+\&{end};\6
+$\\{help5}(\.{"I\'ve\ deleted\ a\ group-closing\ symbol\ because\ it\ seems\ to%
+\ be"})$\6
+$(\.{"spurious,\ as\ in\ \`\$x\}\$\'.\ But\ perhaps\ the\ \}\ is\ legitimate\
+and"})$\6
+$(\.{"you\ forgot\ something\ else,\ as\ in\ \`\\hbox\{\$x\}\'.\ In\ such\
+cases"})$\6
+$(\.{"the\ way\ to\ recover\ is\ to\ insert\ both\ the\ forgotten\ and\ the"})$%
+\6
+$(\.{"deleted\ material,\ e.g.,\ by\ typing\ \`I\$\}\'."})$;\5
+\\{error};\5
+$\\{incr}(\\{align\_state})$;\6
+\&{end};\par
+\fi
+
+\M1082. Here is where we clear the parameters that are supposed to revert to
+their
+default values after every paragraph and when internal vertical mode is
+entered.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{normal\_paragraph};\2\6
+\&{begin} \37\&{if} $\\{looseness}\I0$ \1\&{then}\5
+$\\{eq\_word\_define}(\\{int\_base}+\\{looseness\_code},\390)$;\2\6
+\&{if} $\\{hang\_indent}\I0$ \1\&{then}\5
+$\\{eq\_word\_define}(\\{dimen\_base}+\\{hang\_indent\_code},\390)$;\2\6
+\&{if} $\\{hang\_after}\I1$ \1\&{then}\5
+$\\{eq\_word\_define}(\\{int\_base}+\\{hang\_after\_code},\391)$;\2\6
+\&{if} $\\{par\_shape\_ptr}\I\\{null}$ \1\&{then}\5
+$\\{eq\_define}(\\{par\_shape\_loc},\39\\{shape\_ref},\39\\{null})$;\2\6
+\&{end};\par
+\fi
+
+\M1083. Now let's turn to the question of how \.{\\hbox} is treated. We
+actually
+need to consider also a slightly larger context, since constructions like
+`\.{\\setbox3=}\penalty0\.{\\hbox...}' and
+`\.{\\leaders}\penalty0\.{\\hbox...}' and
+`\.{\\lower3.8pt\\hbox...}'
+are supposed to invoke quite
+different actions after the box has been packaged. Conversely,
+constructions like `\.{\\setbox3=}' can be followed by a variety of
+different kinds of boxes, and we would like to encode such things in an
+efficient way.
+
+In other words, there are two problems: to represent the context of a box,
+and to represent its type.
+
+The first problem is solved by putting a ``context code'' on the \\{save%
+\_stack},
+just below the two entries that give the dimensions produced by \\{scan\_spec}.
+The context code is either a (signed) shift amount, or it is a large
+integer $\G\\{box\_flag}$, where $\\{box\_flag}=\hbox{$2^{30}$}$. Codes \\{box%
+\_flag} through
+$\\{box\_flag}+255$ represent `\.{\\setbox0}' through `\.{\\setbox255}';
+codes $\\{box\_flag}+256$ through $\\{box\_flag}+511$ represent `\.{\\global%
+\\setbox0}'
+through `\.{\\global\\setbox255}';
+code $\\{box\_flag}+512$ represents `\.{\\shipout}'; and codes $\\{box%
+\_flag}+513$
+through $\\{box\_flag}+515$ represent `\.{\\leaders}', `\.{\\cleaders}',
+and `\.{\\xleaders}'.
+
+The second problem is solved by giving the command code \\{make\_box} to all
+control sequences that produce a box, and by using the following \\{chr\_code}
+values to distinguish between them: \\{box\_code}, \\{copy\_code}, \\{last\_box%
+\_code},
+\\{vsplit\_code}, \\{vtop\_code}, $\\{vtop\_code}+\\{vmode}$, and $\\{vtop%
+\_code}+\\{hmode}$,
+where the latter two are used denote \.{\\vbox} and \.{\\hbox}, respectively.
+
+\Y\P\D \37$\\{box\_flag}\S\O{10000000000}$\C{context code for `\.{\\setbox0}'}%
+\par
+\P\D \37$\\{ship\_out\_flag}\S\\{box\_flag}+512$\C{context code for `\.{%
+\\shipout}'}\par
+\P\D \37$\\{leader\_flag}\S\\{box\_flag}+513$\C{context code for `\.{%
+\\leaders}'}\par
+\P\D \37$\\{box\_code}=0$\C{\\{chr\_code} for `\.{\\box}'}\par
+\P\D \37$\\{copy\_code}=1$\C{\\{chr\_code} for `\.{\\copy}'}\par
+\P\D \37$\\{last\_box\_code}=2$\C{\\{chr\_code} for `\.{\\lastbox}'}\par
+\P\D \37$\\{vsplit\_code}=3$\C{\\{chr\_code} for `\.{\\vsplit}'}\par
+\P\D \37$\\{vtop\_code}=4$\C{\\{chr\_code} for `\.{\\vtop}'}\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"moveleft"},\39\\{hmove},\391)$;\5
+$\\{primitive}(\.{"moveright"},\39\\{hmove},\390)$;\6
+$\\{primitive}(\.{"raise"},\39\\{vmove},\391)$;\5
+$\\{primitive}(\.{"lower"},\39\\{vmove},\390)$;\7
+$\\{primitive}(\.{"box"},\39\\{make\_box},\39\\{box\_code})$;\5
+$\\{primitive}(\.{"copy"},\39\\{make\_box},\39\\{copy\_code})$;\5
+$\\{primitive}(\.{"lastbox"},\39\\{make\_box},\39\\{last\_box\_code})$;\5
+$\\{primitive}(\.{"vsplit"},\39\\{make\_box},\39\\{vsplit\_code})$;\5
+$\\{primitive}(\.{"vtop"},\39\\{make\_box},\39\\{vtop\_code})$;\6
+$\\{primitive}(\.{"vbox"},\39\\{make\_box},\39\\{vtop\_code}+\\{vmode})$;\5
+$\\{primitive}(\.{"hbox"},\39\\{make\_box},\39\\{vtop\_code}+\\{hmode})$;\6
+$\\{primitive}(\.{"tate"},\39\\{chg\_dir},\39\\{dir\_tate})$;\6
+$\\{primitive}(\.{"yoko"},\39\\{chg\_dir},\39\\{dir\_yoko})$;\6
+$\\{primitive}(\.{"dtou"},\39\\{chg\_dir},\39\\{dir\_dtou})$;\6
+$\\{primitive}(\.{"shipout"},\39\\{leader\_ship},\39\\{a\_leaders}-1)$;\C{$%
+\\{ship\_out\_flag}=\\{leader\_flag}-1$}\6
+$\\{primitive}(\.{"leaders"},\39\\{leader\_ship},\39\\{a\_leaders})$;\5
+$\\{primitive}(\.{"cleaders"},\39\\{leader\_ship},\39\\{c\_leaders})$;\5
+$\\{primitive}(\.{"xleaders"},\39\\{leader\_ship},\39\\{x\_leaders})$;\par
+\fi
+
+\M1084. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{hmove}: \37\&{if} $\\{chr\_code}=1$ \1\&{then}\5
+$\\{print\_esc}(\.{"moveleft"})$\ \&{else} $\\{print\_esc}(\.{"moveright"})$;\2%
+\6
+\4\\{vmove}: \37\&{if} $\\{chr\_code}=1$ \1\&{then}\5
+$\\{print\_esc}(\.{"raise"})$\ \&{else} $\\{print\_esc}(\.{"lower"})$;\2\6
+\4\\{make\_box}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{box\_code}: \37$\\{print\_esc}(\.{"box"})$;\6
+\4\\{copy\_code}: \37$\\{print\_esc}(\.{"copy"})$;\6
+\4\\{last\_box\_code}: \37$\\{print\_esc}(\.{"lastbox"})$;\6
+\4\\{vsplit\_code}: \37$\\{print\_esc}(\.{"vsplit"})$;\6
+\4\\{vtop\_code}: \37$\\{print\_esc}(\.{"vtop"})$;\6
+\4$\\{vtop\_code}+\\{vmode}$: \37$\\{print\_esc}(\.{"vbox"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"hbox"})$\2\6
+\&{endcases};\6
+\4\\{chg\_dir}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{dir\_yoko}: \37$\\{print\_esc}(\.{"yoko"})$;\6
+\4\\{dir\_tate}: \37$\\{print\_esc}(\.{"tate"})$;\6
+\4\\{dir\_dtou}: \37$\\{print\_esc}(\.{"dtou"})$;\2\6
+\&{endcases};\6
+\4\\{leader\_ship}: \37\&{if} $\\{chr\_code}=\\{a\_leaders}$ \1\&{then}\5
+$\\{print\_esc}(\.{"leaders"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{c\_leaders}$ \1\&{then}\5
+$\\{print\_esc}(\.{"cleaders"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{x\_leaders}$ \1\&{then}\5
+$\\{print\_esc}(\.{"xleaders"})$\6
+\4\&{else} $\\{print\_esc}(\.{"shipout"})$;\2\2\2\par
+\fi
+
+\M1085. Constructions that require a box are started by calling \\{scan\_box}
+with
+a specified context code. The \\{scan\_box} routine verifies
+that a \\{make\_box} command comes next and then it calls \\{begin\_box}.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{vmode}+\\{hmove},\39\\{hmode}+\\{vmove},\39\\{mmode}+\\{vmove}$: \37%
+\&{begin} \37$\|t\K\\{cur\_chr}$;\5
+\\{scan\_normal\_dimen};\6
+\&{if} $\|t=0$ \1\&{then}\5
+$\\{scan\_box}(\\{cur\_val})$\ \&{else} $\\{scan\_box}(-\\{cur\_val})$;\2\6
+\&{end};\6
+\4$\\{any\_mode}(\\{leader\_ship})$: \37$\\{scan\_box}(\\{leader\_flag}-\\{a%
+\_leaders}+\\{cur\_chr})$;\6
+\4$\\{any\_mode}(\\{make\_box})$: \37$\\{begin\_box}(0)$;\6
+\4$\\{any\_mode}(\\{chg\_dir})$: \37\&{begin} \37\&{if} $\\{cur\_group}\I%
+\\{align\_group}$ \1\&{then}\6
+\&{if} $\\{head}=\\{tail}$ \1\&{then}\6
+\&{begin} \37$\\{direction}\K\\{cur\_chr}$;\6
+\&{if} $\\{mode}=\\{vmode}$ \1\&{then}\5
+$\\{page\_dir}\K\\{cur\_chr}$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Use\ \`"})$;\5
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\5
+$\\{print}(\.{"\'\ at\ top\ of\ list"})$;\5
+$\\{help2}(\.{"Direction\ change\ command\ is\ available\ only\ while"})(%
+\.{"current\ list\ is\ null."})$;\5
+\\{error};\6
+\&{end}\2\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"You\ can\'t\ use\ \`"})$;\5
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\5
+$\\{print}(\.{"\'\ in\ an\ align"})$;\5
+$\\{help2}(\.{"To\ change\ direction\ in\ an\ align,"})(\.{"you\ shold\ use\ %
+\\hbox\ or\ \\vbox\ with\ \\tate\ or\ \\yoko."})$;\5
+\\{error};\6
+\&{end}\2\6
+\&{end};\par
+\fi
+
+\M1086. The global variable \\{cur\_box} will point to a newly made box. If the
+box
+is void, we will have $\\{cur\_box}=\\{null}$. Otherwise we will have
+$\\{type}(\\{cur\_box})=\\{hlist\_node}$ or \\{vlist\_node} or \\{rule\_node};
+the \\{rule\_node}
+case can occur only with leaders.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{cur\_box}: \37\\{pointer};\C{box to be placed into its context}\par
+\fi
+
+\M1087. The \\{box\_end} procedure does the right thing with \\{cur\_box}, if
+\\{box\_context} represents the context as explained above.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{box\_end}(\\{box\_context}:\\{integer})$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{\\{ord\_noad} for new box in math mode}\6
+\|q: \37\\{pointer};\2\6
+\&{begin} \37\&{if} $\\{box\_context}<\\{box\_flag}$ \1\&{then}\5
+\X1088:Append box \\{cur\_box} to the current list, shifted by \\{box\_context}%
+\X\6
+\4\&{else} \&{if} $\\{box\_context}<\\{ship\_out\_flag}$ \1\&{then}\5
+\X1089:Store \(c)\\{cur\_box} in a box register\X\6
+\4\&{else} \&{if} $\\{cur\_box}\I\\{null}$ \1\&{then}\6
+\&{if} $\\{box\_context}>\\{ship\_out\_flag}$ \1\&{then}\5
+\X1090:Append a new leader node that uses \\{cur\_box}\X\6
+\4\&{else} $\\{ship\_out}(\\{cur\_box})$;\2\2\2\2\6
+\&{end};\par
+\fi
+
+\M1088. The global variable \\{adjust\_tail} will be non-null if and only if
+the
+current box might include adjustments that should be appended to the
+current vertical list.
+
+\Y\P$\4\X1088:Append box \\{cur\_box} to the current list, shifted by \\{box%
+\_context}\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_box}\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{link}(\\{cur\_box})$;\5
+$\\{link}(\\{cur\_box})\K\\{null}$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\|q\K\|p$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{if} $\\{box\_dir}(\|q)=\\{abs}(\\{direction})$ \1\&{then}\6
+\&{begin} \37$\\{list\_ptr}(\|q)\K\\{cur\_box}$;\5
+$\\{cur\_box}\K\|q$;\5
+$\\{link}(\\{cur\_box})\K\\{null}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{delete\_glue\_ref}(\\{space\_ptr}(\|q))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|q))$;\5
+$\\{free\_node}(\|q,\39\\{box\_node\_size})$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{box\_dir}(\\{cur\_box})\I\\{abs}(\\{direction})$ \1\&{then}\5
+$\\{cur\_box}\K\\{new\_dir\_node}(\\{cur\_box},\39\\{abs}(\\{direction}))$;\2\6
+$\\{shift\_amount}(\\{cur\_box})\K\\{box\_context}$;\6
+\&{if} $\\{abs}(\\{mode})=\\{vmode}$ \1\&{then}\6
+\&{begin} \37$\\{append\_to\_vlist}(\\{cur\_box})$;\6
+\&{if} $\\{adjust\_tail}\I\\{null}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{adjust\_head}\I\\{adjust\_tail}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\\{tail})\K\\{link}(\\{adjust\_head})$;\5
+$\\{tail}\K\\{adjust\_tail}$;\6
+\&{end};\2\6
+$\\{adjust\_tail}\K\\{null}$;\6
+\&{end};\2\6
+\&{if} $\\{mode}>0$ \1\&{then}\5
+\\{build\_page};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{abs}(\\{mode})=\\{hmode}$ \1\&{then}\5
+$\\{space\_factor}\K1000$\6
+\4\&{else} \&{begin} \37$\|p\K\\{new\_noad}$;\5
+$\\{math\_type}(\\{nucleus}(\|p))\K\\{sub\_box}$;\5
+$\\{info}(\\{nucleus}(\|p))\K\\{cur\_box}$;\5
+$\\{cur\_box}\K\|p$;\6
+\&{end};\2\6
+$\\{link}(\\{tail})\K\\{cur\_box}$;\5
+$\\{tail}\K\\{cur\_box}$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end}\par
+\U1087.\fi
+
+\M1089. \P$\X1089:Store \(c)\\{cur\_box} in a box register\X\S$\6
+\&{if} $\\{box\_context}<\\{box\_flag}+256$ \1\&{then}\5
+$\\{eq\_define}(\\{box\_base}-\\{box\_flag}+\\{box\_context},\39\\{box\_ref},%
+\39\\{cur\_box})$\6
+\4\&{else} $\\{geq\_define}(\\{box\_base}-\\{box\_flag}-256+\\{box\_context},%
+\39\\{box\_ref},\39\\{cur\_box})$\2\par
+\U1087.\fi
+
+\M1090. \P$\X1090:Append a new leader node that uses \\{cur\_box}\X\S$\6
+\&{begin} \37\X415:Get the next non-blank non-relax non-call token\X;\6
+\&{if} $((\\{cur\_cmd}=\\{hskip})\W(\\{abs}(\\{mode})\I\\{vmode}))\V\30((\\{cur%
+\_cmd}=\\{vskip})\W(\\{abs}(\\{mode})=\\{vmode}))$ \1\&{then}\6
+\&{begin} \37\\{append\_glue};\5
+$\\{subtype}(\\{tail})\K\\{box\_context}-(\\{leader\_flag}-\\{a\_leaders})$;\6
+\&{if} $\\{type}(\\{cur\_box})\L\\{dir\_node}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{link}(\\{cur\_box})$;\5
+$\\{link}(\\{cur\_box})\K\\{null}$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\|q\K\|p$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{if} $\\{box\_dir}(\|q)=\\{abs}(\\{direction})$ \1\&{then}\6
+\&{begin} \37$\\{list\_ptr}(\|q)\K\\{cur\_box}$;\5
+$\\{cur\_box}\K\|q$;\5
+$\\{link}(\\{cur\_box})\K\\{null}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{delete\_glue\_ref}(\\{space\_ptr}(\|q))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|q))$;\5
+$\\{free\_node}(\|q,\39\\{box\_node\_size})$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\\{box\_dir}(\\{cur\_box})\I\\{abs}(\\{direction})$ \1\&{then}\5
+$\\{cur\_box}\K\\{new\_dir\_node}(\\{cur\_box},\39\\{abs}(\\{direction}))$;\2\6
+\&{end};\2\6
+$\\{leader\_ptr}(\\{tail})\K\\{cur\_box}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Leaders\ not\ followed\ by\ proper\
+glue"})$;\5
+$\\{help3}(\.{"You\ should\ say\ \`\\leaders\ <box\ or\ rule><hskip\ or\ vskip>%
+\'."})$\6
+$(\.{"I\ found\ the\ <box\ or\ rule>,\ but\ there\'s\ no\ suitable"})$\6
+$(\.{"<hskip\ or\ vskip>,\ so\ I\'m\ ignoring\ these\ leaders."})$;\5
+\\{back\_error};\5
+$\\{flush\_node\_list}(\\{cur\_box})$;\6
+\&{end};\2\6
+\&{end}\par
+\U1087.\fi
+
+\M1091. Now that we can see what eventually happens to boxes, we can consider
+the first steps in their creation. The \\{begin\_box} routine is called when
+\\{box\_context} is a context specification, \\{cur\_chr} specifies the type of
+box desired, and $\\{cur\_cmd}=\\{make\_box}$.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{begin\_box}(\\{box\_context}:\\{integer})$;\6
+\4\&{label} \37$\\{exit},\39\\{done}$;\6
+\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{run through the current list}\6
+\|r: \37\\{pointer};\C{running behind \|p}\6
+\\{fd}: \37\\{boolean};\C{a final \\{disp\_node} pair?}\6
+$\\{disp},\39\\{pdisp}$: \37\\{scaled};\C{displacement}\6
+\\{a\_dir}: \37\\{eight\_bits};\C{adjust direction}\6
+\\{tx}: \37\\{pointer};\C{effective tail node}\6
+\|m: \37\\{quarterword};\C{the length of a replacement list}\6
+\|k: \37\\{halfword};\C{0 or \\{vmode} or \\{hmode}}\6
+\|n: \37\\{eight\_bits};\C{a box number}\2\6
+\&{begin} \37\&{case} $\\{cur\_chr}$ \1\&{of}\6
+\4\\{box\_code}: \37\&{begin} \37\\{scan\_eight\_bit\_int};\5
+$\\{cur\_box}\K\\{box}(\\{cur\_val})$;\5
+$\\{box}(\\{cur\_val})\K\\{null}$;\C{the box becomes void, at the same level}\6
+\&{end};\6
+\4\\{copy\_code}: \37\&{begin} \37\\{scan\_eight\_bit\_int};\5
+$\\{cur\_box}\K\\{copy\_node\_list}(\\{box}(\\{cur\_val}))$;\6
+\&{end};\6
+\4\\{last\_box\_code}: \37\X1092:If the current list ends with a box node,
+delete it from the list and make \\{cur\_box} point to it; otherwise set $%
+\\{cur\_box}\K\\{null}$\X;\6
+\4\\{vsplit\_code}: \37\X1094:Split off part of a vertical box, make \\{cur%
+\_box} point to it\X;\6
+\4\&{othercases} \37\X1095:Initiate the construction of an hbox or vbox, then %
+\&{return}\X\2\6
+\&{endcases};\6
+$\\{box\_end}(\\{box\_context})$;\C{in simple cases, we use the box
+immediately}\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1092. Note that in \TeX\ the condition $\R\\{is\_char\_node}(\\{tail})$
+implies that
+$\\{head}\I\\{tail}$, since \\{head} is a one-word node; this is not so for p%
+\TeX.
+
+\Y\P\D \37$\\{check\_effective\_tail\_pTeX}(\#)\S\\{tx}\K\\{tail}$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tx})$ \1\&{then}\6
+\&{if} $\\{type}(\\{tx})=\\{disp\_node}$ \1\&{then}\6
+\&{begin} \37$\\{tx}\K\\{prev\_node}$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tx})$ \1\&{then}\6
+\&{if} $\\{type}(\\{tx})=\\{disp\_node}$ \1\&{then}\5
+$\#$;\C{\\{disp\_node} from a discretionary}\2\2\6
+\&{end}\2\2\par
+\P\D \37$\\{fetch\_effective\_tail\_pTeX}(\#)\S$\C{extract \\{tx}, merge %
+\\{disp\_node} pair}\6
+$\|q\K\\{head}$;\5
+$\|p\K\\{null}$;\5
+$\\{disp}\K0$;\5
+$\\{pdisp}\K0$;\6
+\1\&{repeat} \37$\|r\K\|p$;\5
+$\|p\K\|q$;\5
+$\\{fd}\K\\{false}$;\6
+\&{if} $\R\\{is\_char\_node}(\|q)$ \1\&{then}\6
+\&{if} $\\{type}(\|q)=\\{disc\_node}$ \1\&{then}\6
+\&{begin} \37\&{for} $\|m\K1\mathrel{\&{to}}\\{replace\_count}(\|q)$ \1\&{do}\5
+$\|p\K\\{link}(\|p)$;\2\6
+\&{if} $\|p=\\{tx}$ \1\&{then}\5
+$\#$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{type}(\|q)=\\{disp\_node}$ \1\&{then}\6
+\&{begin} \37$\\{pdisp}\K\\{disp}$;\5
+$\\{disp}\K\\{disp\_dimen}(\|q)$;\5
+$\\{fd}\K\\{true}$;\ \&{end};\2\2\2\6
+$\|q\K\\{link}(\|p)$;\6
+\4\&{until}\5
+$\|q=\\{tx}$;\C{found \|r$\to$\|p$\to$$\|q=\\{tx}$}\2\6
+$\|q\K\\{link}(\\{tx})$;\5
+$\\{link}(\|p)\K\|q$;\5
+$\\{link}(\\{tx})\K\\{null}$;\6
+\&{if} $\|q=\\{null}$ \1\&{then}\5
+$\\{tail}\K\|p$\6
+\4\&{else} \&{if} $\\{fd}$ \1\&{then}\C{\|r$\to$$\|p=\\{disp\_node}$$\to$$\|q=%
+\\{disp\_node}$}\6
+\&{begin} \37$\\{prev\_node}\K\|r$;\5
+$\\{prev\_disp}\K\\{pdisp}$;\5
+$\\{link}(\|p)\K\\{null}$;\5
+$\\{tail}\K\|p$;\5
+$\\{disp\_dimen}(\|p)\K\\{disp\_dimen}(\|q)$;\5
+$\\{free\_node}(\|q,\39\\{small\_node\_size})$;\6
+\&{end}\6
+\4\&{else} $\\{prev\_node}\K\|p$\2\2\par
+\P\D \37$\\{check\_effective\_tail}\S\\{check\_effective\_tail\_pTeX}$\par
+\P\D \37$\\{fetch\_effective\_tail}\S\\{fetch\_effective\_tail\_pTeX}$\par
+\Y\P$\4\X1092:If the current list ends with a box node, delete it from the list
+and make \\{cur\_box} point to it; otherwise set $\\{cur\_box}\K\\{null}$\X\S$\6
+\&{begin} \37$\\{cur\_box}\K\\{null}$;\6
+\&{if} $\\{abs}(\\{mode})=\\{mmode}$ \1\&{then}\6
+\&{begin} \37\\{you\_cant};\5
+$\\{help1}(\.{"Sorry;\ this\ \\lastbox\ will\ be\ void."})$;\5
+\\{error};\6
+\&{end}\6
+\4\&{else} \&{if} $(\\{mode}=\\{vmode})\W(\\{head}=\\{tail})$ \1\&{then}\6
+\&{begin} \37\\{you\_cant};\5
+$\\{help2}(\.{"Sorry...I\ usually\ can\'t\ take\ things\ from\ the\ current\
+page."})$\6
+$(\.{"This\ \\lastbox\ will\ therefore\ be\ void."})$;\5
+\\{error};\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{check\_effective\_tail}($\&{goto} \37\\{done}$)$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tx})\W(\\{head}\I\\{tx})$ \1\&{then}\6
+\&{if} $(\\{type}(\\{tx})=\\{hlist\_node})\V(\\{type}(\\{tx})=\\{vlist\_node})%
+\V(\\{type}(\\{tx})=\\{dir\_node})$ \1\&{then}\5
+\X1093:Remove the last box, unless it's part of a discretionary\X;\2\2\6
+\4\\{done}: \37\&{end};\2\2\6
+\&{end}\par
+\U1091.\fi
+
+\M1093. \P$\X1093:Remove the last box, unless it's part of a discretionary\X\S$%
+\6
+\&{begin} \37$\\{fetch\_effective\_tail}($\&{goto} \37\\{done}$)$;\5
+$\\{cur\_box}\K\\{tx}$;\5
+$\\{shift\_amount}(\\{cur\_box})\K0$;\6
+\&{if} $\\{type}(\\{cur\_box})=\\{dir\_node}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\\{list\_ptr}(\\{cur\_box}))\K\\{cur\_box}$;\5
+$\\{cur\_box}\K\\{list\_ptr}(\\{cur\_box})$;\5
+$\\{list\_ptr}(\\{link}(\\{cur\_box}))\K\\{null}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{box\_dir}(\\{cur\_box})=\\{dir\_default}$ \1\&{then}\5
+$\\{set\_box\_dir}(\\{cur\_box})(\\{abs}(\\{direction}))$;\2\2\6
+\&{end}\par
+\U1092.\fi
+
+\M1094. Here we deal with things like `\.{\\vsplit 13 to 100pt}'.
+
+\Y\P$\4\X1094:Split off part of a vertical box, make \\{cur\_box} point to it\X%
+\S$\6
+\&{begin} \37\\{scan\_eight\_bit\_int};\5
+$\|n\K\\{cur\_val}$;\6
+\&{if} $\R\\{scan\_keyword}(\.{"to"})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ \`to\'\ inserted"})$;\5
+$\\{help2}(\.{"I\'m\ working\ on\ \`\\vsplit<box\ number>\ to\ <dimen>\';"})$\6
+$(\.{"will\ look\ for\ the\ <dimen>\ next."})$;\5
+\\{error};\6
+\&{end};\2\6
+\\{scan\_normal\_dimen};\5
+$\\{cur\_box}\K\\{vsplit}(\|n,\39\\{cur\_val})$;\6
+\&{end}\par
+\U1091.\fi
+
+\M1095. Here is where we enter restricted horizontal mode or internal vertical
+mode, in order to make a box.
+
+\Y\P$\4\X1095:Initiate the construction of an hbox or vbox, then \&{return}\X%
+\S$\6
+\&{begin} \37$\|k\K\\{cur\_chr}-\\{vtop\_code}$;\5
+$\\{saved}(0)\K\\{box\_context}$;\5
+$\\{a\_dir}\K\\{adjust\_dir}$;\6
+\&{if} $\|k=\\{hmode}$ \1\&{then}\6
+\&{if} $(\\{box\_context}<\\{box\_flag})\W(\\{abs}(\\{mode})=\\{vmode})$ \1%
+\&{then}\6
+\&{begin} \37$\\{a\_dir}\K\\{abs}(\\{direction})$;\5
+$\\{scan\_spec}(\\{adjusted\_hbox\_group},\39\\{true})$;\6
+\&{end}\6
+\4\&{else} $\\{scan\_spec}(\\{hbox\_group},\39\\{true})$\2\6
+\4\&{else} \&{begin} \37\&{if} $\|k=\\{vmode}$ \1\&{then}\5
+$\\{scan\_spec}(\\{vbox\_group},\39\\{true})$\6
+\4\&{else} \&{begin} \37$\\{scan\_spec}(\\{vtop\_group},\39\\{true})$;\5
+$\|k\K\\{vmode}$;\6
+\&{end};\2\6
+\\{normal\_paragraph};\6
+\&{end};\2\6
+\\{push\_nest};\5
+$\\{mode}\K-\|k$;\5
+$\\{adjust\_dir}\K\\{a\_dir}$;\6
+\&{if} $\|k=\\{vmode}$ \1\&{then}\6
+\&{begin} \37$\\{prev\_depth}\K\\{ignore\_depth}$;\6
+\&{if} $\\{every\_vbox}\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{every\_vbox},\39\\{every\_vbox\_text})$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{space\_factor}\K1000$;\6
+\&{if} $\\{every\_hbox}\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{every\_hbox},\39\\{every\_hbox\_text})$;\2\6
+\&{end};\2\6
+\&{return};\6
+\&{end}\par
+\U1091.\fi
+
+\M1096. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{scan\_box}(\\{box\_context}:\\{integer})$;\C{the
+next input should specify a box or perhaps a rule}\2\6
+\&{begin} \37\X415:Get the next non-blank non-relax non-call token\X;\6
+\&{if} $\\{cur\_cmd}=\\{make\_box}$ \1\&{then}\5
+$\\{begin\_box}(\\{box\_context})$\6
+\4\&{else} \&{if} $(\\{box\_context}\G\\{leader\_flag})\W((\\{cur\_cmd}=%
+\\{hrule})\V(\\{cur\_cmd}=\\{vrule}))$ \1\&{then}\6
+\&{begin} \37$\\{cur\_box}\K\\{scan\_rule\_spec}$;\5
+$\\{box\_end}(\\{box\_context})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\hbox{}\6
+$\\{print\_err}(\.{"A\ <box>\ was\ supposed\ to\ be\ here"})$;\6
+$\\{help3}(\.{"I\ was\ expecting\ to\ see\ \\hbox\ or\ \\vbox\ or\ \\copy\ or\ %
+\\box\ or"})$\6
+$(\.{"something\ like\ that.\ So\ you\ might\ find\ something\ missing\ in"})$\6
+$(\.{"your\ output.\ But\ keep\ trying;\ you\ can\ fix\ this\ later."})$;\5
+\\{back\_error};\6
+\&{end};\2\2\6
+\&{end};\par
+\fi
+
+\M1097. When the right brace occurs at the end of an \.{\\hbox} or \.{\\vbox}
+or
+\.{\\vtop} construction, the \\{package} routine comes into action. We might
+also have to finish a paragraph that hasn't ended.
+
+\Y\P$\4\X1097:Cases of \\{handle\_right\_brace} where a \\{right\_brace}
+triggers a delayed action\X\S$\6
+\4\\{hbox\_group}: \37\&{begin} \37$\\{adjust\_hlist}(\\{head},\39\\{false})$;\5
+$\\{package}(0)$;\6
+\&{end};\6
+\4\\{adjusted\_hbox\_group}: \37\&{begin} \37$\\{adjust\_hlist}(\\{head},\39%
+\\{false})$;\5
+$\\{adjust\_tail}\K\\{adjust\_head}$;\5
+$\\{package}(0)$;\6
+\&{end};\6
+\4\\{vbox\_group}: \37\&{begin} \37\\{end\_graf};\5
+$\\{package}(0)$;\6
+\&{end};\6
+\4\\{vtop\_group}: \37\&{begin} \37\\{end\_graf};\5
+$\\{package}(\\{vtop\_code})$;\6
+\&{end};\par
+\As1112, 1130, 1144, 1145, 1180, 1185\ETs1198.
+\U1080.\fi
+
+\M1098. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{package}(\|c:\\{small\_number})$;\6
+\4\&{var} \37\|h: \37\\{scaled};\C{height of box}\6
+\|p: \37\\{pointer};\C{first node in a box}\6
+\|d: \37\\{scaled};\C{max depth}\2\6
+\&{begin} \37$\|d\K\\{box\_max\_depth}$;\5
+$\\{delete\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_xkanji\_skip})$;\6
+\&{if} $\\{auto\_spacing}>0$ \1\&{then}\5
+$\\{cur\_kanji\_skip}\K\\{kanji\_skip}$\6
+\4\&{else} $\\{cur\_kanji\_skip}\K\\{zero\_glue}$;\2\6
+\&{if} $\\{auto\_xspacing}>0$ \1\&{then}\5
+$\\{cur\_xkanji\_skip}\K\\{xkanji\_skip}$\6
+\4\&{else} $\\{cur\_xkanji\_skip}\K\\{zero\_glue}$;\2\6
+$\\{add\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{add\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+\\{unsave};\5
+$\\{save\_ptr}\K\\{save\_ptr}-3$;\6
+\&{if} $\\{mode}=-\\{hmode}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_box}\K\\{hpack}(\\{link}(\\{head}),\39\\{saved}(2),\39%
+\\{saved}(1))$;\5
+$\\{set\_box\_dir}(\\{cur\_box})(\\{abs}(\\{direction}))$;\5
+\\{pop\_nest};\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{cur\_box}\K\\{vpackage}(\\{link}(\\{head}),\39%
+\\{saved}(2),\39\\{saved}(1),\39\|d)$;\5
+$\\{set\_box\_dir}(\\{cur\_box})(\\{abs}(\\{direction}))$;\5
+\\{pop\_nest};\6
+\&{if} $\|c=\\{vtop\_code}$ \1\&{then}\5
+\X1099:Readjust the height and depth of \\{cur\_box}, for \.{\\vtop}\X;\2\6
+\&{end};\2\6
+$\\{box\_end}(\\{saved}(0))$;\6
+\&{end};\par
+\fi
+
+\M1099. The height of a `\.{\\vtop}' box is inherited from the first item on
+its list,
+if that item is an \\{hlist\_node}, \\{vlist\_node}, or \\{rule\_node};
+otherwise
+the \.{\\vtop} height is zero.
+
+
+\Y\P$\4\X1099:Readjust the height and depth of \\{cur\_box}, for \.{\\vtop}\X%
+\S$\6
+\&{begin} \37$\|h\K0$;\5
+$\|p\K\\{list\_ptr}(\\{cur\_box})$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{if} $\\{type}(\|p)\L\\{rule\_node}$ \1\&{then}\5
+$\|h\K\\{height}(\|p)$;\2\2\6
+$\\{depth}(\\{cur\_box})\K\\{depth}(\\{cur\_box})-\|h+\\{height}(\\{cur%
+\_box})$;\5
+$\\{height}(\\{cur\_box})\K\|h$;\6
+\&{end}\par
+\U1098.\fi
+
+\M1100. A paragraph begins when horizontal-mode material occurs in vertical
+mode,
+or when the paragraph is explicitly started by `\.{\\indent}' or
+`\.{\\noindent}'.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"indent"},\39\\{start\_par},\391)$;\5
+$\\{primitive}(\.{"noindent"},\39\\{start\_par},\390)$;\par
+\fi
+
+\M1101. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{start\_par}: \37\&{if} $\\{chr\_code}=0$ \1\&{then}\5
+$\\{print\_esc}(\.{"noindent"})$\ \&{else} $\\{print\_esc}(\.{"indent"})$;\2\par
+\fi
+
+\M1102. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{vmode}+\\{start\_par}$: \37$\\{new\_graf}(\\{cur\_chr}>0)$;\6
+\4$\\{vmode}+\\{letter},\39\\{vmode}+\\{other\_char},\39\\{vmode}+\\{char%
+\_num},\39\\{vmode}+\\{char\_given},\39\\{vmode}+\\{math\_shift},\39\\{vmode}+%
+\\{un\_hbox},\39\\{vmode}+\\{vrule},\39\\{vmode}+\\{accent},\39\\{vmode}+%
+\\{discretionary},\39\\{vmode}+\\{hskip},\39\\{vmode}+\\{valign},\39\\{vmode}+%
+\\{kanji},\39\\{vmode}+\\{kana},\39\\{vmode}+\\{other\_kchar},\39\\{vmode}+%
+\\{ex\_space},\39\\{vmode}+\\{no\_boundary}$: \37\hbox{}\6
+\&{begin} \37\\{back\_input};\5
+$\\{new\_graf}(\\{true})$;\6
+\&{end};\par
+\fi
+
+\M1103. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{norm\_min}(\|h:\\{integer})$: \37\\{small\_number};\2%
+\6
+\&{begin} \37\&{if} $\|h\L0$ \1\&{then}\5
+$\\{norm\_min}\K1$\ \&{else} \&{if} $\|h\G63$ \1\&{then}\5
+$\\{norm\_min}\K63$\ \&{else} $\\{norm\_min}\K\|h$;\2\2\6
+\&{end};\7
+\4\&{procedure}\1\  \37$\\{new\_graf}(\\{indented}:\\{boolean})$;\2\6
+\&{begin} \37$\\{prev\_graf}\K0$;\6
+\&{if} $(\\{mode}=\\{vmode})\V(\\{head}\I\\{tail})$ \1\&{then}\5
+$\\{tail\_append}(\\{new\_param\_glue}(\\{par\_skip\_code}))$;\2\6
+$\\{inhibit\_glue\_flag}\K\\{false}$;\5
+\\{push\_nest};\5
+$\\{adjust\_dir}\K\\{abs}(\\{direction})$;\5
+$\\{mode}\K\\{hmode}$;\5
+$\\{space\_factor}\K1000$;\5
+\\{set\_cur\_lang};\5
+$\\{clang}\K\\{cur\_lang}$;\5
+$\\{prev\_graf}\K(\\{norm\_min}(\\{left\_hyphen\_min})\ast\O{100}+\\{norm%
+\_min}(\\{right\_hyphen\_min}))\ast\O{200000}+\\{cur\_lang}$;\6
+\&{if} $\\{indented}$ \1\&{then}\6
+\&{begin} \37$\\{tail}\K\\{new\_null\_box}$;\5
+$\\{link}(\\{head})\K\\{tail}$;\5
+$\\{width}(\\{tail})\K\\{par\_indent}$;\6
+\&{if} $(\\{insert\_src\_special\_every\_par})$ \1\&{then}\5
+\\{insert\_src\_special};\ \2\6
+\&{end};\2\6
+\&{if} $\\{every\_par}\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{every\_par},\39\\{every\_par\_text})$;\2\6
+\&{if} $\\{nest\_ptr}=1$ \1\&{then}\5
+\\{build\_page};\C{put \\{par\_skip} glue on current page}\2\6
+\&{end};\par
+\fi
+
+\M1104. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{hmode}+\\{start\_par},\39\\{mmode}+\\{start\_par}$: \37\\{indent\_in%
+\_hmode};\par
+\fi
+
+\M1105. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{indent\_in\_hmode};\6
+\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\2\6
+\&{begin} \37\&{if} $\\{cur\_chr}>0$ \1\&{then}\C{\.{\\indent}}\6
+\&{begin} \37$\|p\K\\{new\_null\_box}$;\5
+$\\{width}(\|p)\K\\{par\_indent}$;\6
+\&{if} $\\{abs}(\\{mode})=\\{hmode}$ \1\&{then}\5
+$\\{space\_factor}\K1000$\6
+\4\&{else} \&{begin} \37$\|q\K\\{new\_noad}$;\5
+$\\{math\_type}(\\{nucleus}(\|q))\K\\{sub\_box}$;\5
+$\\{info}(\\{nucleus}(\|q))\K\|p$;\5
+$\|p\K\|q$;\6
+\&{end};\2\6
+$\\{tail\_append}(\|p)$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1106. A paragraph ends when a \\{par\_end} command is sensed, or when we are
+in
+horizontal mode when reaching the right brace of vertical-mode routines
+like \.{\\vbox}, \.{\\insert}, or \.{\\output}.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{vmode}+\\{par\_end}$: \37\&{begin} \37\\{normal\_paragraph};\6
+\&{if} $\\{mode}>0$ \1\&{then}\5
+\\{build\_page};\2\6
+\&{end};\6
+\4$\\{hmode}+\\{par\_end}$: \37\&{begin} \37\&{if} $\\{align\_state}<0$ \1%
+\&{then}\5
+\\{off\_save};\C{this tries to     recover from an alignment that didn't end
+properly}\2\6
+\\{end\_graf};\C{this takes us to the enclosing mode, if $\\{mode}>0$}\6
+\&{if} $\\{mode}=\\{vmode}$ \1\&{then}\5
+\\{build\_page};\2\6
+\&{end};\6
+\4$\\{hmode}+\\{stop},\39\\{hmode}+\\{vskip},\39\\{hmode}+\\{hrule},\39%
+\\{hmode}+\\{un\_vbox},\39\\{hmode}+\\{halign}$: \37\\{head\_for\_vmode};\par
+\fi
+
+\M1107. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{head\_for\_vmode};\2\6
+\&{begin} \37\&{if} $\\{mode}<0$ \1\&{then}\6
+\&{if} $\\{cur\_cmd}\I\\{hrule}$ \1\&{then}\5
+\\{off\_save}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"You\ can\'t\ use\ \`"})$;\5
+$\\{print\_esc}(\.{"hrule"})$;\5
+$\\{print}(\.{"\'\ here\ except\ with\ leaders"})$;\5
+$\\{help2}(\.{"To\ put\ a\ horizontal\ rule\ in\ an\ hbox\ or\ an\
+alignment,"})$\6
+$(\.{"you\ should\ use\ \\leaders\ or\ \\hrulefill\ (see\ The\ TeXbook)."})$;\5
+\\{error};\6
+\&{end}\2\6
+\4\&{else} \&{begin} \37\\{back\_input};\5
+$\\{cur\_tok}\K\\{par\_token}$;\5
+\\{back\_input};\5
+$\\{token\_type}\K\\{inserted}$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1108. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{end\_graf};\2\6
+\&{begin} \37\&{if} $\\{mode}=\\{hmode}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{head}=\\{tail}$ \1\&{then}\5
+\\{pop\_nest}\C{null paragraphs are ignored}\6
+\4\&{else} \&{begin} \37$\\{adjust\_hlist}(\\{head},\39\\{true})$;\5
+$\\{line\_break}(\\{widow\_penalty})$\6
+\&{end};\2\6
+\\{normal\_paragraph};\5
+$\\{error\_count}\K0$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1109. Insertion and adjustment and mark nodes are constructed by the
+following
+pieces of the program.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{insert}),\39\\{hmode}+\\{vadjust},\39\\{mmode}+%
+\\{vadjust}$: \37\\{begin\_insert\_or\_adjust};\6
+\4$\\{any\_mode}(\\{mark})$: \37\\{make\_mark};\par
+\fi
+
+\M1110. \P$\X1060:Forbidden cases detected in \\{main\_control}\X\mathrel{+}\S$%
+\6
+$\\{vmode}+\\{vadjust},\39$\par
+\fi
+
+\M1111. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{begin\_insert\_or\_adjust};\2\6
+\&{begin} \37\&{if} $\\{cur\_cmd}=\\{vadjust}$ \1\&{then}\5
+$\\{cur\_val}\K255$\6
+\4\&{else} \&{begin} \37\\{scan\_eight\_bit\_int};\6
+\&{if} $\\{cur\_val}=255$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"You\ can\'t\ "})$;\5
+$\\{print\_esc}(\.{"insert"})$;\5
+$\\{print\_int}(255)$;\5
+$\\{help1}(\.{"I\'m\ changing\ to\ \\insert0;\ box\ 255\ is\ special."})$;\5
+\\{error};\5
+$\\{cur\_val}\K0$;\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{saved}(0)\K\\{cur\_val}$;\5
+$\\{incr}(\\{save\_ptr})$;\5
+$\\{new\_save\_level}(\\{insert\_group})$;\5
+\\{scan\_left\_brace};\5
+\\{normal\_paragraph};\5
+\\{push\_nest};\5
+$\\{mode}\K-\\{vmode}$;\5
+$\\{direction}\K\\{adjust\_dir}$;\5
+$\\{prev\_depth}\K\\{ignore\_depth}$;\6
+\&{end};\par
+\fi
+
+\M1112. \P$\X1097:Cases of \\{handle\_right\_brace} where a \\{right\_brace}
+triggers a delayed action\X\mathrel{+}\S$\6
+\4\\{insert\_group}: \37\&{begin} \37\\{end\_graf};\5
+$\|q\K\\{split\_top\_skip}$;\5
+$\\{add\_glue\_ref}(\|q)$;\5
+$\|d\K\\{split\_max\_depth}$;\5
+$\|f\K\\{floating\_penalty}$;\5
+\\{unsave};\5
+$\\{decr}(\\{save\_ptr})$;\C{now $\\{saved}(0)$ is the insertion number, or 255
+for \\{vadjust}}\6
+$\|p\K\\{vpack}(\\{link}(\\{head}),\39\\{natural})$;\5
+$\\{set\_box\_dir}(\|p)(\\{abs}(\\{direction}))$;\5
+\\{pop\_nest};\6
+\&{if} $\\{saved}(0)<255$ \1\&{then}\6
+\&{begin} \37$\|r\K\\{get\_node}(\\{ins\_node\_size})$;\5
+$\\{type}(\|r)\K\\{ins\_node}$;\5
+$\\{subtype}(\|r)\K\\{qi}(\\{saved}(0))$;\5
+$\\{height}(\|r)\K\\{height}(\|p)+\\{depth}(\|p)$;\5
+$\\{ins\_ptr}(\|r)\K\\{list\_ptr}(\|p)$;\5
+$\\{split\_top\_ptr}(\|r)\K\|q$;\5
+$\\{depth}(\|r)\K\|d$;\5
+$\\{float\_cost}(\|r)\K\|f$;\5
+$\\{ins\_dir}(\|r)\K\\{box\_dir}(\|p)$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=\\{disp\_node})$ \1%
+\&{then}\5
+$\\{prev\_append}(\|r)$\6
+\4\&{else} $\\{tail\_append}(\|r)$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{box\_dir}(\|p)\I\\{adjust\_dir}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Direction\ Incompatible."})$;\5
+$\\{help1}(\.{"\\vadjust\'s\ argument\ and\ outer\ vlist\ must\ have\ same\
+direction."})$;\5
+\\{error};\5
+$\\{flush\_node\_list}(\\{list\_ptr}(\|p))$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|r\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|r)\K\\{adjust\_node}$;\6
+$\\{adjust\_ptr}(\|r)\K\\{list\_ptr}(\|p)$;\5
+$\\{delete\_glue\_ref}(\|q)$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=\\{disp\_node})$ \1%
+\&{then}\5
+$\\{prev\_append}(\|r)$\6
+\4\&{else} $\\{tail\_append}(\|r)$;\2\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|p))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|p))$;\5
+$\\{free\_node}(\|p,\39\\{box\_node\_size})$;\6
+\&{if} $\\{nest\_ptr}=0$ \1\&{then}\5
+\\{build\_page};\2\6
+\&{end};\6
+\4\\{output\_group}: \37\X1037:Resume the page builder after an output routine
+has come to an end\X;\par
+\fi
+
+\M1113. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{make\_mark};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{new node}\2\6
+\&{begin} \37$\|p\K\\{scan\_toks}(\\{false},\39\\{true})$;\5
+$\|p\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{type}(\|p)\K\\{mark\_node}$;\5
+$\\{subtype}(\|p)\K0$;\C{the \\{subtype} is not used}\6
+$\\{mark\_ptr}(\|p)\K\\{def\_ref}$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=\\{disp\_node})$ \1%
+\&{then}\5
+$\\{prev\_append}(\|p)$\6
+\4\&{else} $\\{tail\_append}(\|p)$;\2\6
+\&{end};\par
+\fi
+
+\M1114. Penalty nodes get into a list via the \\{break\_penalty} command.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{break\_penalty})$: \37\\{append\_penalty};\par
+\fi
+
+\M1115. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{append\_penalty};\2\6
+\&{begin} \37\\{scan\_int};\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=\\{disp\_node})$ \1%
+\&{then}\5
+$\\{prev\_append}(\\{new\_penalty}(\\{cur\_val}))$\6
+\4\&{else} $\\{tail\_append}(\\{new\_penalty}(\\{cur\_val}))$;\2\6
+\&{if} $\\{mode}=\\{vmode}$ \1\&{then}\5
+\\{build\_page};\2\6
+\&{end};\par
+\fi
+
+\M1116. The \\{remove\_item} command removes a penalty, kern, or glue node if
+it
+appears at the tail of the current list, using a brute-force linear scan.
+Like \.{\\lastbox}, this command is not allowed in vertical mode (except
+internal vertical mode), since the current list in vertical mode is sent
+to the page builder.  But if we happen to be able to implement it in
+vertical mode, we do.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{remove\_item})$: \37\\{delete\_last};\par
+\fi
+
+\M1117. When \\{delete\_last} is called, \\{cur\_chr} is the \\{type} of node
+that
+will be deleted, if present.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{delete\_last};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{run through the current list}\6
+\|r: \37\\{pointer};\C{running behind \|p}\6
+\\{fd}: \37\\{boolean};\C{a final \\{disp\_node} pair?}\6
+$\\{disp},\39\\{pdisp}$: \37\\{scaled};\C{displacement}\6
+\\{tx}: \37\\{pointer};\C{effective tail node}\6
+\|m: \37\\{quarterword};\C{the length of a replacement list}\2\6
+\&{begin} \37\&{if} $(\\{mode}=\\{vmode})\W(\\{tail}=\\{head})$ \1\&{then}\5
+\X1118:Apologize for inability to do the operation now, unless \.{\\unskip}
+follows non-glue\X\6
+\4\&{else} \&{begin} \37$\\{check\_effective\_tail}(\&{return})$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tx})$ \1\&{then}\6
+\&{if} $\\{type}(\\{tx})=\\{cur\_chr}$ \1\&{then}\6
+\&{begin} \37$\\{fetch\_effective\_tail}(\&{return})$;\5
+$\\{flush\_node\_list}(\\{tx})$;\6
+\&{end};\2\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1118. \P$\X1118:Apologize for inability to do the operation now, unless \.{%
+\\unskip} follows non-glue\X\S$\6
+\&{begin} \37\&{if} $(\\{cur\_chr}\I\\{glue\_node})\V(\\{last\_glue}\I\\{max%
+\_halfword})$ \1\&{then}\6
+\&{begin} \37\\{you\_cant};\5
+$\\{help2}(\.{"Sorry...I\ usually\ can\'t\ take\ things\ from\ the\ current\
+page."})$\6
+$(\.{"Try\ \`I\\vskip-\\lastskip\'\ instead."})$;\6
+\&{if} $\\{cur\_chr}=\\{kern\_node}$ \1\&{then}\5
+$\\{help\_line}[0]\K(\.{"Try\ \`I\\kern-\\lastkern\'\ instead."})$\6
+\4\&{else} \&{if} $\\{cur\_chr}\I\\{glue\_node}$ \1\&{then}\5
+$\\{help\_line}[0]\K\30(\.{"Perhaps\ you\ can\ make\ the\ output\ routine\ do\
+it."})$;\2\2\6
+\\{error};\6
+\&{end};\2\6
+\&{end}\par
+\U1117.\fi
+
+\M1119. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"unpenalty"},\39\\{remove\_item},\39\\{penalty\_node})$;\6
+$\\{primitive}(\.{"unkern"},\39\\{remove\_item},\39\\{kern\_node})$;\6
+$\\{primitive}(\.{"unskip"},\39\\{remove\_item},\39\\{glue\_node})$;\6
+$\\{primitive}(\.{"unhbox"},\39\\{un\_hbox},\39\\{box\_code})$;\6
+$\\{primitive}(\.{"unhcopy"},\39\\{un\_hbox},\39\\{copy\_code})$;\6
+$\\{primitive}(\.{"unvbox"},\39\\{un\_vbox},\39\\{box\_code})$;\6
+$\\{primitive}(\.{"unvcopy"},\39\\{un\_vbox},\39\\{copy\_code})$;\par
+\fi
+
+\M1120. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{remove\_item}: \37\&{if} $\\{chr\_code}=\\{glue\_node}$ \1\&{then}\5
+$\\{print\_esc}(\.{"unskip"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{kern\_node}$ \1\&{then}\5
+$\\{print\_esc}(\.{"unkern"})$\6
+\4\&{else} $\\{print\_esc}(\.{"unpenalty"})$;\2\2\6
+\4\\{un\_hbox}: \37\&{if} $\\{chr\_code}=\\{copy\_code}$ \1\&{then}\5
+$\\{print\_esc}(\.{"unhcopy"})$\6
+\4\&{else} $\\{print\_esc}(\.{"unhbox"})$;\2\6
+\4\\{un\_vbox}: \37\&{if} $\\{chr\_code}=\\{copy\_code}$ \1\&{then}\5
+$\\{print\_esc}(\.{"unvcopy"})$\6
+\4\&{else} $\\{print\_esc}(\.{"unvbox"})$;\2\par
+\fi
+
+\M1121. The \\{un\_hbox} and \\{un\_vbox} commands unwrap one of the 256
+current boxes.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{vmode}+\\{un\_vbox},\39\\{hmode}+\\{un\_hbox},\39\\{mmode}+\\{un\_hbox}$:
+\37\\{unpackage};\par
+\fi
+
+\M1122. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{unpackage};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the box}\6
+\|c: \37$\\{box\_code}\to\\{copy\_code}$;\C{should we copy?}\6
+\\{disp}: \37\\{scaled};\C{displacement}\2\6
+\&{begin} \37$\|c\K\\{cur\_chr}$;\5
+\\{scan\_eight\_bit\_int};\5
+$\|p\K\\{box}(\\{cur\_val})$;\6
+\&{if} $\|p=\\{null}$ \1\&{then}\5
+\&{return};\2\6
+\&{if} $\\{type}(\|p)=\\{dir\_node}$ \1\&{then}\5
+$\|p\K\\{list\_ptr}(\|p)$;\2\6
+\&{if} $(\\{abs}(\\{mode})=\\{mmode})\V((\\{abs}(\\{mode})=\\{vmode})\W(%
+\\{type}(\|p)\I\\{vlist\_node}))\V\30((\\{abs}(\\{mode})=\\{hmode})\W(\\{type}(%
+\|p)\I\\{hlist\_node}))$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Incompatible\ list\ can\'t\ be\ unboxed"})$;\5
+$\\{help3}(\.{"Sorry,\ Pandora.\ (You\ sneaky\ devil.)"})$\6
+$(\.{"I\ refuse\ to\ unbox\ an\ \\hbox\ in\ vertical\ mode\ or\ vice\
+versa."})$\6
+$(\.{"And\ I\ can\'t\ open\ any\ boxes\ in\ math\ mode."})$;\6
+\\{error};\5
+\&{return};\6
+\&{end};\2\6
+\&{case} $\\{box\_dir}(\|p)$ \1\&{of}\6
+\4\\{any\_dir}: \37\&{if} $\\{abs}(\\{direction})\I\\{box\_dir}(\|p)$ \1%
+\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Incompatible\ direction\ list\ can\'t\ be\
+unboxed"})$;\5
+$\\{help2}(\.{"Sorry,\ Pandora.\ (You\ sneaky\ devil.)"})$\6
+$(\.{"I\ refuse\ to\ unbox\ a\ box\ in\ differrent\ direction."})$;\6
+\\{error};\5
+\&{return};\6
+\&{end};\2\2\6
+\&{endcases};\5
+$\\{disp}\K0$;\6
+\&{if} $\|c=\\{copy\_code}$ \1\&{then}\5
+$\\{link}(\\{tail})\K\\{copy\_node\_list}(\\{list\_ptr}(\|p))$\6
+\4\&{else} \&{begin} \37\&{if} $\\{type}(\\{box}(\\{cur\_val}))=\\{dir\_node}$ %
+\1\&{then}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{space\_ptr}(\\{box}(\\{cur\_val})))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\\{box}(\\{cur\_val})))$;\5
+$\\{free\_node}(\\{box}(\\{cur\_val}),\39\\{box\_node\_size})$;\6
+\&{end};\2\6
+$\\{flush\_node\_list}(\\{link}(\|p))$;\5
+$\\{link}(\\{tail})\K\\{list\_ptr}(\|p)$;\5
+$\\{box}(\\{cur\_val})\K\\{null}$;\5
+$\\{delete\_glue\_ref}(\\{space\_ptr}(\|p))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|p))$;\5
+$\\{free\_node}(\|p,\39\\{box\_node\_size})$;\6
+\&{end};\2\6
+\&{while} $\\{link}(\\{tail})\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\|p\K\\{tail}$;\5
+$\\{tail}\K\\{link}(\\{tail})$;\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})$ \1\&{then}\6
+\&{case} $\\{type}(\\{tail})$ \1\&{of}\6
+\4\\{glue\_node}: \37\&{if} $(\\{subtype}(\\{tail})=\\{kanji\_skip\_code}+1)\V(%
+\\{subtype}(\\{tail})=\\{xkanji\_skip\_code}+1)$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|p)\K\\{link}(\\{tail})$;\5
+$\\{delete\_glue\_ref}(\\{glue\_ptr}(\\{tail}))$;\5
+$\\{free\_node}(\\{tail},\39\\{small\_node\_size})$;\5
+$\\{tail}\K\|p$;\6
+\&{end};\2\6
+\4\\{penalty\_node}: \37\&{if} $\\{subtype}(\\{tail})=\\{widow\_pena}$ \1%
+\&{then}\6
+\&{begin} \37$\\{link}(\|p)\K\\{link}(\\{tail})$;\5
+$\\{free\_node}(\\{tail},\39\\{small\_node\_size})$;\5
+$\\{tail}\K\|p$;\6
+\&{end};\2\6
+\4\\{disp\_node}: \37\&{begin} \37$\\{prev\_disp}\K\\{disp}$;\5
+$\\{disp}\K\\{disp\_dimen}(\\{tail})$;\5
+$\\{prev\_node}\K\|p$;\6
+\&{end};\2\6
+\&{endcases};\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1123. \P$\X1060:Forbidden cases detected in \\{main\_control}\X\mathrel{+}\S$%
+\6
+$\\{vmode}+\\{ital\_corr},\39$\par
+\fi
+
+\M1124. Italic corrections are converted to kern nodes when the \\{ital\_corr}
+command
+follows a character. In math mode the same effect is achieved by appending
+a kern of zero here, since italic corrections are supplied later.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{hmode}+\\{ital\_corr}$: \37\\{append\_italic\_correction};\6
+\4$\\{mmode}+\\{ital\_corr}$: \37$\\{tail\_append}(\\{new\_kern}(0))$;\par
+\fi
+
+\M1125. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{append\_italic\_correction};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{\\{char\_node} at the tail of the current
+list}\6
+\|f: \37\\{internal\_font\_number};\C{the font in the \\{char\_node}}\6
+\|d: \37\\{pointer};\C{\\{disp\_node}}\2\6
+\&{begin} \37\&{if} $\\{tail}\I\\{head}$ \1\&{then}\6
+\&{begin} \37\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=%
+\\{disp\_node})$ \1\&{then}\6
+\&{begin} \37$\|d\K\\{tail}$;\5
+$\\{tail}\K\\{prev\_node}$;\6
+\&{end}\6
+\4\&{else} $\|d\K\\{null}$;\2\6
+\&{if} $(\\{last\_jchr}\I\\{null})\W(\\{link}(\\{last\_jchr})=\\{tail})\W(\\{is%
+\_char\_node}(\\{tail}))$ \1\&{then}\5
+$\|p\K\\{last\_jchr}$\6
+\4\&{else} \&{if} $\\{is\_char\_node}(\\{tail})$ \1\&{then}\5
+$\|p\K\\{tail}$\6
+\4\&{else} \&{if} $\\{type}(\\{tail})=\\{ligature\_node}$ \1\&{then}\5
+$\|p\K\\{lig\_char}(\\{tail})$\6
+\4\&{else} \&{return};\2\2\2\6
+$\|f\K\\{font}(\|p)$;\5
+$\\{tail\_append}(\\{new\_kern}(\\{char\_italic}(\|f)(\\{char\_info}(\|f)(%
+\\{character}(\|p)))))$;\5
+$\\{subtype}(\\{tail})\K\\{ita\_kern}$;\6
+\&{if} $\|d\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{prev\_node}\K\\{tail}$;\5
+$\\{tail\_append}(\|d)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1126. Discretionary nodes are easy in the common case `\.{\\-}', but in the
+general case we must process three braces full of items.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"-"},\39\\{discretionary},\391)$;\5
+$\\{primitive}(\.{"discretionary"},\39\\{discretionary},\390)$;\par
+\fi
+
+\M1127. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{discretionary}: \37\&{if} $\\{chr\_code}=1$ \1\&{then}\5
+$\\{print\_esc}(\.{"-"})$\ \&{else} $\\{print\_esc}(\.{"discretionary"})$;\2\par
+\fi
+
+\M1128. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{hmode}+\\{discretionary},\39\\{mmode}+\\{discretionary}$: \37\\{append%
+\_discretionary};\par
+\fi
+
+\M1129. The space factor does not change when we append a discretionary node,
+but it starts out as 1000 in the subsidiary lists.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{append\_discretionary};\6
+\4\&{var} \37\|c: \37\\{integer};\C{hyphen character}\2\6
+\&{begin} \37$\\{tail\_append}(\\{new\_disc})$;\6
+\&{if} $\\{cur\_chr}=1$ \1\&{then}\6
+\&{begin} \37$\|c\K\\{hyphen\_char}[\\{cur\_font}]$;\6
+\&{if} $\|c\G0$ \1\&{then}\6
+\&{if} $\|c<256$ \1\&{then}\5
+$\\{pre\_break}(\\{tail})\K\\{new\_character}(\\{cur\_font},\39\|c)$;\2\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{incr}(\\{save\_ptr})$;\5
+$\\{saved}(-1)\K0$;\5
+$\\{new\_save\_level}(\\{disc\_group})$;\5
+\\{scan\_left\_brace};\5
+\\{push\_nest};\5
+$\\{mode}\K-\\{hmode}$;\5
+$\\{space\_factor}\K1000$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1130. The three discretionary lists are constructed somewhat as if they were
+hboxes. A~subroutine called \\{build\_discretionary} handles the transitions.
+(This is sort of fun.)
+
+\Y\P$\4\X1097:Cases of \\{handle\_right\_brace} where a \\{right\_brace}
+triggers a delayed action\X\mathrel{+}\S$\6
+\4\\{disc\_group}: \37\\{build\_discretionary};\par
+\fi
+
+\M1131. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{build\_discretionary};\6
+\4\&{label} \37$\\{done},\39\\{exit}$;\6
+\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{for link manipulation}\6
+\|n: \37\\{integer};\C{length of discretionary list}\2\6
+\&{begin} \37\\{unsave};\5
+\X1133:Prune the current list, if necessary, until it contains only \\{char%
+\_node}, \\{kern\_node}, \\{hlist\_node}, \\{vlist\_node}, \\{rule\_node}, and %
+\\{ligature\_node} items; set \|n to the length of the list, and set \|q to the
+list's tail\X;\6
+$\|p\K\\{link}(\\{head})$;\5
+\\{pop\_nest};\6
+\&{case} $\\{saved}(-1)$ \1\&{of}\6
+\40: \37$\\{pre\_break}(\\{tail})\K\|p$;\6
+\41: \37$\\{post\_break}(\\{tail})\K\|p$;\6
+\42: \37\X1132:Attach list \|p to the current list, and record its length; then
+finish up and \&{return}\X;\2\6
+\&{end};\C{there are no other cases}\6
+$\\{incr}(\\{saved}(-1))$;\5
+$\\{new\_save\_level}(\\{disc\_group})$;\5
+\\{scan\_left\_brace};\5
+\\{push\_nest};\5
+$\\{mode}\K-\\{hmode}$;\5
+$\\{space\_factor}\K1000$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1132. \P$\X1132:Attach list \|p to the current list, and record its length;
+then finish up and \&{return}\X\S$\6
+\&{begin} \37\&{if} $(\|n>0)\W(\\{abs}(\\{mode})=\\{mmode})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Illegal\ math\ "})$;\5
+$\\{print\_esc}(\.{"discretionary"})$;\5
+$\\{help2}(\.{"Sorry:\ The\ third\ part\ of\ a\ discretionary\ break\ must\
+be"})$\6
+$(\.{"empty,\ in\ math\ formulas.\ I\ had\ to\ delete\ your\ third\ part."})$;\5
+$\\{flush\_node\_list}(\|p)$;\5
+$\|n\K0$;\5
+\\{error};\6
+\&{end}\6
+\4\&{else} $\\{link}(\\{tail})\K\|p$;\2\6
+\&{if} $\|n\L\\{max\_quarterword}$ \1\&{then}\5
+$\\{replace\_count}(\\{tail})\K\|n$\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Discretionary\ list\ is\ too\
+long"})$;\5
+$\\{help2}(\.{"Wow---I\ never\ thought\ anybody\ would\ tweak\ me\ here."})$\6
+$(\.{"You\ can\'t\ seriously\ need\ such\ a\ huge\ discretionary\ list?"})$;\5
+\\{error};\6
+\&{end};\2\6
+\&{if} $\|n>0$ \1\&{then}\5
+$\\{tail}\K\|q$;\2\6
+$\\{decr}(\\{save\_ptr})$;\5
+$\\{prev\_node}\K\\{tail}$;\5
+$\\{tail\_append}(\\{get\_node}(\\{small\_node\_size}))$;\5
+$\\{type}(\\{tail})\K\\{disp\_node}$;\5
+$\\{disp\_dimen}(\\{tail})\K0$;\5
+$\\{prev\_disp}\K0$;\5
+\&{return};\6
+\&{end}\par
+\U1131.\fi
+
+\M1133. During this loop, $\|p=\\{link}(\|q)$ and there are \|n items preceding
+\|p.
+
+\Y\P$\4\X1133:Prune the current list, if necessary, until it contains only %
+\\{char\_node}, \\{kern\_node}, \\{hlist\_node}, \\{vlist\_node}, \\{rule%
+\_node}, and \\{ligature\_node} items; set \|n to the length of the list, and
+set \|q to the list's tail\X\S$\6
+$\|q\K\\{head}$;\5
+$\|p\K\\{link}(\|q)$;\5
+$\|n\K0$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\R\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{if} $(\\{type}(\|p)>\\{rule\_node})\W(\\{type}(\|p)\I\\{kern\_node})\W(%
+\\{type}(\|p)\I\\{ligature\_node})\W(\\{type}(\|p)\I\\{disp\_node})$ \1\&{then}%
+\6
+\&{if} $(\\{type}(\|p)=\\{penalty\_node})\W(\\{subtype}(\|p)\I\\{normal})$ \1%
+\&{then}\6
+\&{begin} \37$\\{link}(\|q)\K\\{link}(\|p)$;\5
+$\\{free\_node}(\|p,\39\\{small\_node\_size})$;\5
+$\|p\K\|q$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Improper\ discretionary\ list"})$;\5
+$\\{help1}(\.{"Discretionary\ lists\ must\ contain\ only\ boxes\ and\
+kerns."})$;\6
+\\{error};\5
+\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"The\ following\ discretionary\ sublist\ has\ been\
+deleted:"})$;\5
+$\\{show\_box}(\|p)$;\5
+$\\{end\_diagnostic}(\\{true})$;\5
+$\\{flush\_node\_list}(\|p)$;\5
+$\\{link}(\|q)\K\\{null}$;\5
+\&{goto} \37\\{done};\6
+\&{end};\2\2\2\6
+$\|q\K\|p$;\5
+$\|p\K\\{link}(\|q)$;\5
+$\\{incr}(\|n)$;\6
+\&{end};\2\6
+\4\\{done}: \37\par
+\U1131.\fi
+
+\M1134. We need only one more thing to complete the horizontal mode routines,
+namely
+the \.{\\accent} primitive.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{hmode}+\\{accent}$: \37\\{make\_accent};\par
+\fi
+
+\M1135. The positioning of accents is straightforward but tedious. Given an
+accent
+of width \|a, designed for characters of height \|x and slant \|s;
+and given a character of width \|w, height \|h, and slant \|t: We will shift
+the accent down by $\|x-\|h$, and we will insert kern nodes that have the
+effect of
+centering the accent over the character and shifting the accent to the
+right by $\delta={1\over2}(w-a)+h\cdot t-x\cdot s$.  If either character is
+absent from the font, we will simply use the other, without shifting.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{make\_accent};\6
+\4\&{var} \37$\|s,\39\|t$: \37\\{real};\C{amount of slant}\6
+\\{disp}: \37\\{scaled};\C{displacement}\6
+\\{cx}: \37\\{KANJI\_code};\C{temporary register for KANJI}\6
+$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{character, box, and kern nodes}\6
+\|f: \37\\{internal\_font\_number};\C{relevant font}\6
+$\|a,\39\|h,\39\|x,\39\|w,\39\\{delta}$: \37\\{scaled};\C{heights and widths,
+as explained above}\6
+\|i: \37\\{four\_quarters};\C{character information}\2\6
+\&{begin} \37\\{scan\_char\_num};\6
+\&{if} $\R\\{is\_char\_ascii}(\\{cur\_val})$ \1\&{then}\6
+\&{begin} \37$\\{KANJI}(\\{cx})\K\\{cur\_val}$;\6
+\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\5
+$\|f\K\\{cur\_tfont}$\6
+\4\&{else} $\|f\K\\{cur\_jfont}$;\2\6
+$\|p\K\\{new\_character}(\|f,\39\\{get\_jfm\_pos}(\\{KANJI}(\\{cx}),\39\|f))$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|p)\K\\{get\_avail}$;\5
+$\\{info}(\\{link}(\|p))\K\\{KANJI}(\\{cx})$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|f\K\\{cur\_font}$;\5
+$\|p\K\\{new\_character}(\|f,\39\\{cur\_val})$;\6
+\&{end};\2\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\|x\K\\{x\_height}(\|f)$;\5
+$\|s\K\\{slant}(\|f)/\\{float\_constant}(65536)$;\5
+$\|a\K\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\|p)))$;\6
+\\{do\_assignments};\6
+\X1136:Create a character node \|q for the next character, but set $\|q\K%
+\\{null}$ if problems arise\X;\6
+\&{if} $\|q\I\\{null}$ \1\&{then}\5
+\X1137:Append the accent with appropriate kerns, then set $\|p\K\|q$\X;\2\6
+$\\{link}(\\{tail})\K\|p$;\6
+\&{if} $\\{link}(\|p)\I\\{null}$ \1\&{then}\5
+$\\{tail}\K\\{link}(\|p)$\6
+\4\&{else} $\\{tail}\K\|p$;\2\6
+\X1471:Append \\{disp\_node} at end of displace area\X;\6
+$\\{space\_factor}\K1000$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1136. \P$\X1136:Create a character node \|q for the next character, but set $%
+\|q\K\\{null}$ if problems arise\X\S$\6
+$\|q\K\\{null}$;\5
+$\|f\K\\{cur\_font}$;\5
+$\\{KANJI}(\\{cx})\K\\{empty}$;\6
+\&{if} $(\\{cur\_cmd}=\\{letter})\V(\\{cur\_cmd}=\\{other\_char})$ \1\&{then}\5
+$\|q\K\\{new\_character}(\|f,\39\\{cur\_chr})$\6
+\4\&{else} \&{if} $(\\{cur\_cmd}=\\{kanji})\V(\\{cur\_cmd}=\\{kana})\V(\\{cur%
+\_cmd}=\\{other\_kchar})$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\5
+$\|f\K\\{cur\_tfont}$\6
+\4\&{else} $\|f\K\\{cur\_jfont}$;\2\6
+$\\{cx}\K\\{cur\_chr}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{char\_given}$ \1\&{then}\6
+\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ \1\&{then}\5
+$\|q\K\\{new\_character}(\|f,\39\\{cur\_chr})$\6
+\4\&{else} \&{begin} \37\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\5
+$\|f\K\\{cur\_tfont}$\6
+\4\&{else} $\|f\K\\{cur\_jfont}$;\2\6
+$\\{KANJI}(\\{cx})\K\\{cur\_chr}$\6
+\&{end}\2\6
+\4\&{else} \&{if} $\\{cur\_cmd}=\\{char\_num}$ \1\&{then}\6
+\&{begin} \37\\{scan\_char\_num};\6
+\&{if} $\\{is\_char\_ascii}(\\{cur\_val})$ \1\&{then}\5
+$\|q\K\\{new\_character}(\|f,\39\\{cur\_val})$\6
+\4\&{else} \&{begin} \37\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\5
+$\|f\K\\{cur\_tfont}$\6
+\4\&{else} $\|f\K\\{cur\_jfont}$;\2\6
+$\\{KANJI}(\\{cx})\K\\{cur\_val}$\6
+\&{end}\2\6
+\&{end}\6
+\4\&{else} \\{back\_input};\2\2\2\2\6
+\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{font\_dir}[\|f]=\\{dir\_tate}$ \1\&{then}\5
+$\\{disp}\K0$\6
+\4\&{else} \&{if} $\\{font\_dir}[\|f]=\\{dir\_yoko}$ \1\&{then}\5
+$\\{disp}\K\\{t\_baseline\_shift}-\\{y\_baseline\_shift}$\6
+\4\&{else} $\\{disp}\K\\{t\_baseline\_shift}$\2\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{font\_dir}[\|f]=\\{dir\_yoko}$ \1\&{then}\5
+$\\{disp}\K0$\6
+\4\&{else} \&{if} $\\{font\_dir}[\|f]=\\{dir\_tate}$ \1\&{then}\5
+$\\{disp}\K\\{y\_baseline\_shift}-\\{t\_baseline\_shift}$\6
+\4\&{else} $\\{disp}\K\\{y\_baseline\_shift}$\2\2\6
+\&{end};\2\6
+\X1470:Append \\{disp\_node} at begin of displace area\X;\6
+\&{if} $\\{KANJI}(\\{cx})\I\\{empty}$ \1\&{then}\6
+\&{begin} \37$\|q\K\\{new\_character}(\|f,\39\\{get\_jfm\_pos}(\\{KANJI}(%
+\\{cx}),\39\|f))$;\5
+$\\{link}(\|q)\K\\{get\_avail}$;\5
+$\\{info}(\\{link}(\|q))\K\\{KANJI}(\\{cx})$;\5
+$\\{last\_jchr}\K\|q$;\6
+\&{end};\2\par
+\U1135.\fi
+
+\M1137. The kern nodes appended here must be distinguished from other kerns,
+lest
+they be wiped away by the hyphenation algorithm or by a previous line break.
+
+The two kerns are computed with (machine-dependent) \\{real} arithmetic, but
+their sum is machine-independent; the net effect is machine-independent,
+because the user cannot remove these nodes nor access them via \.{\\lastkern}.
+
+\Y\P$\4\X1137:Append the accent with appropriate kerns, then set $\|p\K\|q$\X%
+\S$\6
+\&{begin} \37$\|t\K\\{slant}(\|f)/\\{float\_constant}(65536)$;\5
+$\|i\K\\{char\_info}(\|f)(\\{character}(\|q))$;\5
+$\|w\K\\{char\_width}(\|f)(\|i)$;\5
+$\|h\K\\{char\_height}(\|f)(\\{height\_depth}(\|i))$;\6
+\&{if} $\|h\I\|x$ \1\&{then}\C{the accent must be shifted up or down}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\\{cur\_kanji\_skip}\K\\{zero\_glue}$;\5
+$\\{cur\_xkanji\_skip}\K\\{zero\_glue}$;\5
+$\\{add\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{add\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\|p\K\\{hpack}(\|p,\39\\{natural})$;\5
+$\\{shift\_amount}(\|p)\K\|x-\|h$;\6
+\&{end};\2\6
+$\\{delta}\K\\{round}((\|w-\|a)/\\{float\_constant}(2)+\|h\ast\|t-\|x\ast\|s)$;%
+\5
+$\|r\K\\{new\_kern}(\\{delta})$;\5
+$\\{subtype}(\|r)\K\\{acc\_kern}$;\5
+$\\{link}(\\{tail})\K\|r$;\5
+$\\{link}(\|r)\K\|p$;\5
+$\\{tail}\K\\{new\_kern}(-\|a-\\{delta})$;\5
+$\\{subtype}(\\{tail})\K\\{acc\_kern}$;\6
+\&{if} $\|h=\|x$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}%
+\5
+$\\{link}(\\{link}(\|p))\K\\{tail}$\6
+\4\&{else} $\\{link}(\|p)\K\\{tail}$;\2\6
+\&{end}\6
+\4\&{else} $\\{link}(\|p)\K\\{tail}$;\C{ bugfix: if \|p is KANJI char, $%
+\\{link}(\|p)$:=\\{tail} collapses \|p and kern after accent. }\2\6
+$\|p\K\|q$;\6
+\&{end}\par
+\U1135.\fi
+
+\M1138. When `\.{\\cr}' or `\.{\\span}' or a tab mark comes through the scanner
+into \\{main\_control}, it might be that the user has foolishly inserted
+one of them into something that has nothing to do with alignment. But it is
+far more likely that a left brace or right brace has been omitted, since
+\\{get\_next} takes actions appropriate to alignment only when `\.{\\cr}'
+or `\.{\\span}' or tab marks occur with $\\{align\_state}=0$. The following
+program attempts to make an appropriate recovery.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{car\_ret}),\39\\{any\_mode}(\\{tab\_mark})$: \37\\{align%
+\_error};\6
+\4$\\{any\_mode}(\\{no\_align})$: \37\\{no\_align\_error};\6
+\4$\\{any\_mode}(\\{omit})$: \37\\{omit\_error};\par
+\fi
+
+\M1139. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{align\_error};\2\6
+\&{begin} \37\&{if} $\\{abs}(\\{align\_state})>2$ \1\&{then}\5
+\X1140:Express consternation over the fact that no alignment is in progress\X\6
+\4\&{else} \&{begin} \37\\{back\_input};\6
+\&{if} $\\{align\_state}<0$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ \{\ inserted"})$;\5
+$\\{incr}(\\{align\_state})$;\5
+$\\{cur\_tok}\K\\{left\_brace\_token}+\.{"\{"}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Missing\ \}\ inserted"})$;\5
+$\\{decr}(\\{align\_state})$;\5
+$\\{cur\_tok}\K\\{right\_brace\_token}+\.{"\}"}$;\6
+\&{end};\2\6
+$\\{help3}(\.{"I\'ve\ put\ in\ what\ seems\ to\ be\ necessary\ to\ fix"})$\6
+$(\.{"the\ current\ column\ of\ the\ current\ alignment."})$\6
+$(\.{"Try\ to\ go\ on,\ since\ this\ might\ almost\ work."})$;\5
+\\{ins\_error};\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1140. \P$\X1140:Express consternation over the fact that no alignment is in
+progress\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Misplaced\ "})$;\5
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\6
+\&{if} $\\{cur\_tok}=\\{tab\_token}+\.{"\&"}$ \1\&{then}\6
+\&{begin} \37$\\{help6}(\.{"I\ can\'t\ figure\ out\ why\ you\ would\ want\ to\
+use\ a\ tab\ mark"})$\6
+$(\.{"here.\ If\ you\ just\ want\ an\ ampersand,\ the\ remedy\ is"})$\6
+$(\.{"simple:\ Just\ type\ \`I\\\&\'\ now.\ But\ if\ some\ right\ brace"})$\6
+$(\.{"up\ above\ has\ ended\ a\ previous\ alignment\ prematurely,"})$\6
+$(\.{"you\'re\ probably\ due\ for\ more\ error\ messages,\ and\ you"})$\6
+$(\.{"might\ try\ typing\ \`S\'\ now\ just\ to\ see\ what\ is\
+salvageable."})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{help5}(\.{"I\ can\'t\ figure\ out\ why\ you\ would\
+want\ to\ use\ a\ tab\ mark"})$\6
+$(\.{"or\ \\cr\ or\ \\span\ just\ now.\ If\ something\ like\ a\ right\
+brace"})$\6
+$(\.{"up\ above\ has\ ended\ a\ previous\ alignment\ prematurely,"})$\6
+$(\.{"you\'re\ probably\ due\ for\ more\ error\ messages,\ and\ you"})$\6
+$(\.{"might\ try\ typing\ \`S\'\ now\ just\ to\ see\ what\ is\
+salvageable."})$;\6
+\&{end};\2\6
+\\{error};\6
+\&{end}\par
+\U1139.\fi
+
+\M1141. The help messages here contain a little white lie, since \.{\\noalign}
+and \.{\\omit} are allowed also after `\.{\\noalign\{...\}}'.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{no\_align\_error};\2\6
+\&{begin} \37$\\{print\_err}(\.{"Misplaced\ "})$;\5
+$\\{print\_esc}(\.{"noalign"})$;\5
+$\\{help2}(\.{"I\ expect\ to\ see\ \\noalign\ only\ after\ the\ \\cr\ of"})$\6
+$(\.{"an\ alignment.\ Proceed,\ and\ I\'ll\ ignore\ this\ case."})$;\5
+\\{error};\6
+\&{end};\6
+\4\&{procedure}\1\  \37\\{omit\_error};\2\6
+\&{begin} \37$\\{print\_err}(\.{"Misplaced\ "})$;\5
+$\\{print\_esc}(\.{"omit"})$;\5
+$\\{help2}(\.{"I\ expect\ to\ see\ \\omit\ only\ after\ tab\ marks\ or\ the\ %
+\\cr\ of"})$\6
+$(\.{"an\ alignment.\ Proceed,\ and\ I\'ll\ ignore\ this\ case."})$;\5
+\\{error};\6
+\&{end};\par
+\fi
+
+\M1142. We've now covered most of the abuses of \.{\\halign} and \.{\\valign}.
+Let's take a look at what happens when they are used correctly.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{vmode}+\\{halign},\39\\{hmode}+\\{valign}$: \37\\{init\_align};\6
+\4$\\{mmode}+\\{halign}$: \37\&{if} $\\{privileged}$ \1\&{then}\6
+\&{if} $\\{cur\_group}=\\{math\_shift\_group}$ \1\&{then}\5
+\\{init\_align}\6
+\4\&{else} \\{off\_save};\2\2\6
+\4$\\{vmode}+\\{endv},\39\\{hmode}+\\{endv}$: \37\\{do\_endv};\par
+\fi
+
+\M1143. An \\{align\_group} code is supposed to remain on the \\{save\_stack}
+during an entire alignment, until \\{fin\_align} removes it.
+
+A devious user might force an \\{endv} command to occur just about anywhere;
+we must defeat such hacks.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{do\_endv};\2\6
+\&{begin} \37$\\{base\_ptr}\K\\{input\_ptr}$;\5
+$\\{input\_stack}[\\{base\_ptr}]\K\\{cur\_input}$;\6
+\&{while} $(\\{input\_stack}[\\{base\_ptr}].\\{index\_field}\I\\{v\_template})%
+\W(\\{input\_stack}[\\{base\_ptr}].\\{loc\_field}=\\{null})\W(\\{input\_stack}[%
+\\{base\_ptr}].\\{state\_field}=\\{token\_list})$ \1\&{do}\5
+$\\{decr}(\\{base\_ptr})$;\2\6
+\&{if} $(\\{input\_stack}[\\{base\_ptr}].\\{index\_field}\I\\{v\_template})\V(%
+\\{input\_stack}[\\{base\_ptr}].\\{loc\_field}\I\\{null})\V(\\{input\_stack}[%
+\\{base\_ptr}].\\{state\_field}\I\\{token\_list})$ \1\&{then}\5
+$\\{fatal\_error}(\.{"(interwoven\ alignment\ preambles\ are\ not\
+allowed)"})$;\2\6
+\&{if} $\\{cur\_group}=\\{align\_group}$ \1\&{then}\6
+\&{begin} \37\\{end\_graf};\6
+\&{if} $\\{fin\_col}$ \1\&{then}\5
+\\{fin\_row};\2\6
+\&{end}\6
+\4\&{else} \\{off\_save};\2\6
+\&{end};\par
+\fi
+
+\M1144. \P$\X1097:Cases of \\{handle\_right\_brace} where a \\{right\_brace}
+triggers a delayed action\X\mathrel{+}\S$\6
+\4\\{align\_group}: \37\&{begin} \37\\{back\_input};\5
+$\\{cur\_tok}\K\\{cs\_token\_flag}+\\{frozen\_cr}$;\5
+$\\{print\_err}(\.{"Missing\ "})$;\5
+$\\{print\_esc}(\.{"cr"})$;\5
+$\\{print}(\.{"\ inserted"})$;\5
+$\\{help1}(\.{"I\'m\ guessing\ that\ you\ meant\ to\ end\ an\ alignment\
+here."})$;\5
+\\{ins\_error};\6
+\&{end};\par
+\fi
+
+\M1145. \P$\X1097:Cases of \\{handle\_right\_brace} where a \\{right\_brace}
+triggers a delayed action\X\mathrel{+}\S$\6
+\4\\{no\_align\_group}: \37\&{begin} \37\\{end\_graf};\5
+\\{unsave};\5
+\\{align\_peek};\6
+\&{end};\par
+\fi
+
+\M1146. Finally, \.{\\endcsname} is not supposed to get through to \\{main%
+\_control}.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{end\_cs\_name})$: \37\\{cs\_error};\par
+\fi
+
+\M1147. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{cs\_error};\2\6
+\&{begin} \37$\\{print\_err}(\.{"Extra\ "})$;\5
+$\\{print\_esc}(\.{"endcsname"})$;\5
+$\\{help1}(\.{"I\'m\ ignoring\ this,\ since\ I\ wasn\'t\ doing\ a\ %
+\\csname."})$;\5
+\\{error};\6
+\&{end};\par
+\fi
+
+\N1148.  \[48] Building math lists.
+The routines that \TeX\ uses to create mlists are similar to those we have
+just seen for the generation of hlists and vlists. But it is necessary to
+make ``noads'' as well as nodes, so the reader should review the
+discussion of math mode data structures before trying to make sense out of
+the following program.
+
+Here is a little routine that needs to be done whenever a subformula
+is about to be processed. The parameter is a code like \\{math\_group}.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{push\_math}(\|c:\\{group\_code})$;\2\6
+\&{begin} \37\\{push\_nest};\5
+$\\{mode}\K-\\{mmode}$;\5
+$\\{incompleat\_noad}\K\\{null}$;\5
+$\\{new\_save\_level}(\|c)$;\6
+\&{end};\par
+\fi
+
+\M1149. We get into math mode from horizontal mode when a `\.\$' (i.e., a
+\\{math\_shift} character) is scanned. We must check to see whether this
+`\.\$' is immediately followed by another, in case display math mode is
+called for.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{hmode}+\\{math\_shift}$: \37\\{init\_math};\par
+\fi
+
+\M1150. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{init\_math};\6
+\4\&{label} \37$\\{reswitch},\39\\{found},\39\\{not\_found},\39\\{done}$;\6
+\4\&{var} \37\|w: \37\\{scaled};\C{new or partial \\{pre\_display\_size}}\6
+\|l: \37\\{scaled};\C{new \\{display\_width}}\6
+\|s: \37\\{scaled};\C{new \\{display\_indent}}\6
+\|p: \37\\{pointer};\C{current node when calculating \\{pre\_display\_size}}\6
+\|q: \37\\{pointer};\C{glue specification when calculating \\{pre\_display%
+\_size}}\6
+\|f: \37\\{internal\_font\_number};\C{font in current \\{char\_node}}\6
+\|n: \37\\{integer};\C{scope of paragraph shape specification}\6
+\|v: \37\\{scaled};\C{\|w plus possible glue amount}\6
+\|d: \37\\{scaled};\C{increment to \|v}\2\6
+\&{begin} \37\\{get\_token};\C{\\{get\_x\_token} would fail on \.{\\ifmmode}%
+\thinspace!}\6
+\&{if} $(\\{cur\_cmd}=\\{math\_shift})\W(\\{mode}>0)$ \1\&{then}\5
+\X1157:Go into display math mode\X\6
+\4\&{else} \&{begin} \37\\{back\_input};\5
+\X1151:Go into ordinary math mode\X;\6
+\&{end};\2\6
+$\\{direction}\K-\\{abs}(\\{direction})$;\6
+\&{end};\par
+\fi
+
+\M1151. \P$\X1151:Go into ordinary math mode\X\S$\6
+\&{begin} \37$\\{push\_math}(\\{math\_shift\_group})$;\5
+$\\{eq\_word\_define}(\\{int\_base}+\\{cur\_fam\_code},\39-1)$;\6
+\&{if} $(\\{insert\_src\_special\_every\_math})$ \1\&{then}\5
+\\{insert\_src\_special};\2\6
+\&{if} $\\{every\_math}\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{every\_math},\39\\{every\_math\_text})$;\2\6
+\&{end}\par
+\Us1150\ET1154.\fi
+
+\M1152. We get into ordinary math mode from display math mode when `\.{\\eqno}'
+or
+`\.{\\leqno}' appears. In such cases \\{cur\_chr} will be 0 or~1, respectively;
+the value of \\{cur\_chr} is placed onto \\{save\_stack} for safe keeping.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{eq\_no}$: \37\&{if} $\\{privileged}$ \1\&{then}\6
+\&{if} $\\{cur\_group}=\\{math\_shift\_group}$ \1\&{then}\5
+\\{start\_eq\_no}\6
+\4\&{else} \\{off\_save};\2\2\par
+\fi
+
+\M1153. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"eqno"},\39\\{eq\_no},\390)$;\5
+$\\{primitive}(\.{"leqno"},\39\\{eq\_no},\391)$;\par
+\fi
+
+\M1154. When \TeX\ is in display math mode, $\\{cur\_group}=\\{math\_shift%
+\_group}$,
+so it is not necessary for the \\{start\_eq\_no} procedure to test for
+this condition.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{start\_eq\_no};\2\6
+\&{begin} \37$\\{saved}(0)\K\\{cur\_chr}$;\5
+$\\{incr}(\\{save\_ptr})$;\5
+\X1151:Go into ordinary math mode\X;\6
+\&{end};\par
+\fi
+
+\M1155. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{eq\_no}: \37\&{if} $\\{chr\_code}=1$ \1\&{then}\5
+$\\{print\_esc}(\.{"leqno"})$\ \&{else} $\\{print\_esc}(\.{"eqno"})$;\2\par
+\fi
+
+\M1156. \P$\X1060:Forbidden cases detected in \\{main\_control}\X\mathrel{+}\S$%
+\6
+$\\{non\_math}(\\{eq\_no}),\39$\par
+\fi
+
+\M1157. When we enter display math mode, we need to call \\{line\_break} to
+process the partial paragraph that has just been interrupted by the
+display. Then we can set the proper values of \\{display\_width} and
+\\{display\_indent} and \\{pre\_display\_size}.
+
+\Y\P$\4\X1157:Go into display math mode\X\S$\6
+\&{begin} \37\&{if} $\\{head}=\\{tail}$ \1\&{then}\C{`\.{\\noindent\$\$}' or `%
+\.{\$\${ }\$\$}'}\6
+\&{begin} \37\\{pop\_nest};\5
+$\|w\K-\\{max\_dimen}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{adjust\_hlist}(\\{head},\39\\{true})$;\5
+$\\{line\_break}(\\{display\_widow\_penalty})$;\6
+\X1158:Calculate the natural width, \|w, by which the characters of the final
+line extend to the right of the reference point, plus two ems; or set $\|w\K%
+\\{max\_dimen}$ if the non-blank information on that line is affected by
+stretching or shrinking\X;\6
+\&{end};\C{now we are in vertical mode, working on the list that will contain
+the display}\2\6
+\X1161:Calculate the length, \|l, and the shift amount, \|s, of the display
+lines\X;\6
+$\\{push\_math}(\\{math\_shift\_group})$;\5
+$\\{mode}\K\\{mmode}$;\5
+$\\{eq\_word\_define}(\\{int\_base}+\\{cur\_fam\_code},\39-1)$;\6
+$\\{eq\_word\_define}(\\{dimen\_base}+\\{pre\_display\_size\_code},\39\|w)$;\5
+$\\{eq\_word\_define}(\\{dimen\_base}+\\{display\_width\_code},\39\|l)$;\5
+$\\{eq\_word\_define}(\\{dimen\_base}+\\{display\_indent\_code},\39\|s)$;\6
+\&{if} $\\{every\_display}\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{every\_display},\39\\{every\_display\_text})$;\2\6
+\&{if} $\\{nest\_ptr}=1$ \1\&{then}\5
+\\{build\_page};\2\6
+\&{end}\par
+\U1150.\fi
+
+\M1158. \P$\X1158:Calculate the natural width, \|w, by which the characters of
+the final line extend to the right of the reference point, plus two ems; or set
+$\|w\K\\{max\_dimen}$ if the non-blank information on that line is affected by
+stretching or shrinking\X\S$\6
+$\|v\K\\{shift\_amount}(\\{just\_box})+2\ast\\{quad}(\\{cur\_font})$;\5
+$\|w\K-\\{max\_dimen}$;\5
+$\|p\K\\{list\_ptr}(\\{just\_box})$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\X1159:Let \|d be the natural width of node \|p; if the node is
+``visible,'' \&{goto} \\{found}; if the node is glue that stretches or shrinks,
+set $\|v\K\\{max\_dimen}$\X;\6
+\&{if} $\|v<\\{max\_dimen}$ \1\&{then}\5
+$\|v\K\|v+\|d$;\2\6
+\&{goto} \37\\{not\_found};\6
+\4\\{found}: \37\&{if} $\|v<\\{max\_dimen}$ \1\&{then}\6
+\&{begin} \37$\|v\K\|v+\|d$;\5
+$\|w\K\|v$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|w\K\\{max\_dimen}$;\5
+\&{goto} \37\\{done};\6
+\&{end};\2\6
+\4\\{not\_found}: \37$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\4\\{done}: \37\par
+\U1157.\fi
+
+\M1159. \P$\X1159:Let \|d be the natural width of node \|p; if the node is
+``visible,'' \&{goto} \\{found}; if the node is glue that stretches or shrinks,
+set $\|v\K\\{max\_dimen}$\X\S$\6
+\4\\{reswitch}: \37\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{begin} \37$\|f\K\\{font}(\|p)$;\5
+$\|d\K\\{char\_width}(\|f)(\\{orig\_char\_info}(\|f)(\\{character}(\|p)))$;\6
+\&{if} $\\{font\_dir}[\|f]\I\\{dir\_default}$ \1\&{then}\5
+$\|p\K\\{link}(\|p)$;\2\6
+\&{goto} \37\\{found};\6
+\&{end};\2\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{hlist\_node},\39\\{vlist\_node},\39\\{dir\_node},\39\\{rule\_node}$: \37%
+\&{begin} \37$\|d\K\\{width}(\|p)$;\5
+\&{goto} \37\\{found};\6
+\&{end};\6
+\4\\{ligature\_node}: \37\X663:Make node \|p look like a \\{char\_node} and %
+\&{goto} \\{reswitch}\X;\6
+\4$\\{kern\_node},\39\\{math\_node}$: \37$\|d\K\\{width}(\|p)$;\6
+\4\\{glue\_node}: \37\X1160:Let \|d be the natural width of this glue; if
+stretching or shrinking, set $\|v\K\\{max\_dimen}$; \&{goto} \\{found} in the
+case of leaders\X;\6
+\4\\{whatsit\_node}: \37\X1374:Let \|d be the width of the whatsit \|p\X;\6
+\4\&{othercases} \37$\|d\K0$\2\6
+\&{endcases}\par
+\U1158.\fi
+
+\M1160. We need to be careful that \|w, \|v, and \|d do not depend on any %
+\\{glue\_set}
+values, since such values are subject to system-dependent rounding.
+System-dependent numbers are not allowed to infiltrate parameters like
+\\{pre\_display\_size}, since \TeX82 is supposed to make the same decisions on
+all
+machines.
+
+\Y\P$\4\X1160:Let \|d be the natural width of this glue; if stretching or
+shrinking, set $\|v\K\\{max\_dimen}$; \&{goto} \\{found} in the case of leaders%
+\X\S$\6
+\&{begin} \37$\|q\K\\{glue\_ptr}(\|p)$;\5
+$\|d\K\\{width}(\|q)$;\6
+\&{if} $\\{glue\_sign}(\\{just\_box})=\\{stretching}$ \1\&{then}\6
+\&{begin} \37\&{if} $(\\{glue\_order}(\\{just\_box})=\\{stretch\_order}(\|q))\W%
+\30(\\{stretch}(\|q)\I0)$ \1\&{then}\5
+$\|v\K\\{max\_dimen}$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{glue\_sign}(\\{just\_box})=\\{shrinking}$ \1\&{then}\6
+\&{begin} \37\&{if} $(\\{glue\_order}(\\{just\_box})=\\{shrink\_order}(\|q))\W%
+\30(\\{shrink}(\|q)\I0)$ \1\&{then}\5
+$\|v\K\\{max\_dimen}$;\2\6
+\&{end};\2\2\6
+\&{if} $\\{subtype}(\|p)\G\\{a\_leaders}$ \1\&{then}\5
+\&{goto} \37\\{found};\2\6
+\&{end}\par
+\U1159.\fi
+
+\M1161. A displayed equation is considered to be three lines long, so we
+calculate the length and offset of line number $\\{prev\_graf}+2$.
+
+\Y\P$\4\X1161:Calculate the length, \|l, and the shift amount, \|s, of the
+display lines\X\S$\6
+\&{if} $\\{par\_shape\_ptr}=\\{null}$ \1\&{then}\6
+\&{if} $(\\{hang\_indent}\I0)\W\30(((\\{hang\_after}\G0)\W(\\{prev\_graf}+2>%
+\\{hang\_after}))\V\30(\\{prev\_graf}+1<-\\{hang\_after}))$ \1\&{then}\6
+\&{begin} \37$\|l\K\\{hsize}-\\{abs}(\\{hang\_indent})$;\6
+\&{if} $\\{hang\_indent}>0$ \1\&{then}\5
+$\|s\K\\{hang\_indent}$\ \&{else} $\|s\K0$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|l\K\\{hsize}$;\5
+$\|s\K0$;\6
+\&{end}\2\6
+\4\&{else} \&{begin} \37$\|n\K\\{info}(\\{par\_shape\_ptr})$;\6
+\&{if} $\\{prev\_graf}+2\G\|n$ \1\&{then}\5
+$\|p\K\\{par\_shape\_ptr}+2\ast\|n$\6
+\4\&{else} $\|p\K\\{par\_shape\_ptr}+2\ast(\\{prev\_graf}+2)$;\2\6
+$\|s\K\\{mem}[\|p-1].\\{sc}$;\5
+$\|l\K\\{mem}[\|p].\\{sc}$;\6
+\&{end}\2\par
+\U1157.\fi
+
+\M1162. Subformulas of math formulas cause a new level of math mode to be
+entered,
+on the semantic nest as well as the save stack. These subformulas arise in
+several ways: (1)~A left brace by itself indicates the beginning of a
+subformula that will be put into a box, thereby freezing its glue and
+preventing line breaks. (2)~A subscript or superscript is treated as a
+subformula if it is not a single character; the same applies to
+the nucleus of things like \.{\\underline}. (3)~The \.{\\left} primitive
+initiates a subformula that will be terminated by a matching \.{\\right}.
+The group codes placed on \\{save\_stack} in these three cases are
+\\{math\_group}, \\{math\_group}, and \\{math\_left\_group}, respectively.
+
+Here is the code that handles case (1); the other cases are not quite as
+trivial, so we shall consider them later.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{left\_brace}$: \37\&{begin} \37$\\{tail\_append}(\\{new%
+\_noad})$;\5
+\\{back\_input};\5
+$\\{scan\_math}(\\{nucleus}(\\{tail}),\39\\{kcode\_noad}(\\{tail}))$;\6
+\&{end};\par
+\fi
+
+\M1163. Recall that the \\{nucleus}, \\{subscr}, and \\{supscr} fields in a
+noad are
+broken down into subfields called \\{math\_type} and either \\{info} or
+$(\\{fam},\\{character})$. The job of \\{scan\_math} is to figure out what to
+place
+in one of these principal fields; it looks at the subformula that
+comes next in the input, and places an encoding of that subformula
+into a given word of \\{mem}.
+
+\Y\P\D \37$\\{fam\_in\_range}\S((\\{cur\_fam}\G0)\W(\\{cur\_fam}<16))$\par
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{scan\_math}(\|p,\39\|q:\\{pointer})$;\6
+\4\&{label} \37$\\{restart},\39\\{reswitch},\39\\{exit}$;\6
+\4\&{var} \37\|c: \37\\{integer};\C{math character code}\6
+\\{cx}: \37\\{KANJI\_code};\C{temporary register for KANJI}\2\6
+\&{begin} \37$\\{KANJI}(\\{cx})\K0$;\6
+\4\\{restart}: \37\X415:Get the next non-blank non-relax non-call token\X;\6
+\4\\{reswitch}: \37\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\4$\\{letter},\39\\{other\_char},\39\\{char\_given}$: \37\&{if} $(\\{is\_char%
+\_ascii}(\\{cur\_chr})\V(\\{cur\_chr}=256))$ \1\&{then}\6
+\&{begin} \37$\|c\K\\{ho}(\\{math\_code}(\\{cur\_chr}))$;\6
+\&{if} $\|c=\O{100000}$ \1\&{then}\6
+\&{begin} \37\X1164:Treat \\{cur\_chr} as an active character\X;\6
+\&{goto} \37\\{restart};\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} $\\{KANJI}(\\{cx})\K\\{cur\_chr}$;\2\6
+\4$\\{kanji},\39\\{kana},\39\\{other\_kchar}$: \37$\\{cx}\K\\{cur\_chr}$;\6
+\4\\{char\_num}: \37\&{begin} \37\\{scan\_char\_num};\5
+$\\{cur\_chr}\K\\{cur\_val}$;\5
+$\\{cur\_cmd}\K\\{char\_given}$;\5
+\&{goto} \37\\{reswitch};\6
+\&{end};\6
+\4\\{math\_char\_num}: \37\&{begin} \37\\{scan\_fifteen\_bit\_int};\5
+$\|c\K\\{cur\_val}$;\6
+\&{end};\6
+\4\\{math\_given}: \37$\|c\K\\{cur\_chr}$;\6
+\4\\{delim\_num}: \37\&{begin} \37\\{scan\_twenty\_seven\_bit\_int};\5
+$\|c\K\\{cur\_val}\mathbin{\&{div}}\O{10000}$;\6
+\&{end};\6
+\4\&{othercases} \37\X1165:Scan a subformula enclosed in braces and \&{return}%
+\X\2\6
+\&{endcases};\6
+\&{if} $\\{KANJI}(\\{cx})=0$ \1\&{then}\6
+\&{begin} \37$\\{math\_type}(\|p)\K\\{math\_char}$;\5
+$\\{character}(\|p)\K\\{qi}(\|c\mathbin{\&{mod}}256)$;\6
+\&{if} $(\|c\G\\{var\_code})\W(\\{fam\_in\_range})$ \1\&{then}\5
+$\\{fam}(\|p)\K\\{cur\_fam}$\6
+\4\&{else} $\\{fam}(\|p)\K(\|c\mathbin{\&{div}}256)\mathbin{\&{mod}}16$;\2\6
+\&{if} $\\{font\_dir}[\\{fam\_fnt}(\\{fam}(\|p)+\\{cur\_size})]\I\\{dir%
+\_default}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Not\ one-byte\ family"})$;\5
+$\\{help1}(\.{"IGNORE."})$;\6
+\\{error};\6
+\&{end}\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\|q=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{math\_type}(\|p)\K\\{sub\_mlist}$;\5
+$\\{info}(\|p)\K\\{new\_noad}$;\5
+$\|p\K\\{nucleus}(\\{info}(\|p))$;\5
+$\|q\K\\{kcode\_noad\_nucleus}(\|p)$;\6
+\&{end};\2\6
+$\\{math\_type}(\|p)\K\\{math\_jchar}$;\5
+$\\{fam}(\|p)\K\\{cur\_jfam}$;\5
+$\\{character}(\|p)\K\\{qi}(0)$;\5
+$\\{math\_kcode}(\|p-1)\K\\{KANJI}(\\{cx})$;\6
+\&{if} $\\{font\_dir}[\\{fam\_fnt}(\\{fam}(\|p)+\\{cur\_size})]=\\{dir%
+\_default}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Not\ two-byte\ family"})$;\5
+$\\{help1}(\.{"IGNORE."})$;\6
+\\{error};\6
+\&{end}\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1164. An active character that is an \\{outer\_call} is allowed here.
+
+\Y\P$\4\X1164:Treat \\{cur\_chr} as an active character\X\S$\6
+\&{begin} \37$\\{cur\_cs}\K\\{cur\_chr}+\\{active\_base}$;\5
+$\\{cur\_cmd}\K\\{eq\_type}(\\{cur\_cs})$;\5
+$\\{cur\_chr}\K\\{equiv}(\\{cur\_cs})$;\5
+\\{x\_token};\5
+\\{back\_input};\6
+\&{end}\par
+\Us1163\ET1167.\fi
+
+\M1165. The pointer \|p is placed on \\{save\_stack} while a complex subformula
+is being scanned.
+
+\Y\P$\4\X1165:Scan a subformula enclosed in braces and \&{return}\X\S$\6
+\&{begin} \37\\{back\_input};\5
+\\{scan\_left\_brace};\6
+$\\{saved}(0)\K\|p$;\5
+$\\{incr}(\\{save\_ptr})$;\5
+$\\{push\_math}(\\{math\_group})$;\5
+\&{return};\6
+\&{end}\par
+\U1163.\fi
+
+\M1166. The simplest math formula is, of course, `\.{\${ }\$}', when no noads
+are
+generated. The next simplest cases involve a single character, e.g.,
+`\.{\$x\$}'. Even though such cases may not seem to be very interesting,
+the reader can perhaps understand how happy the author was when `\.{\$x\$}'
+was first properly typeset by \TeX. The code in this section was used.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{letter},\39\\{mmode}+\\{other\_char},\39\\{mmode}+\\{char%
+\_given}$: \37\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ \1\&{then}\6
+\&{if} $\\{cur\_chr}<128$ \1\&{then}\5
+$\\{set\_math\_char}(\\{ho}(\\{math\_code}(\\{cur\_chr})))$\6
+\4\&{else} $\\{set\_math\_char}(\\{cur\_chr})$\2\6
+\4\&{else} $\\{set\_math\_kchar}(\\{cur\_chr})$;\2\6
+\4$\\{mmode}+\\{kanji},\39\\{mmode}+\\{kana},\39\\{mmode}+\\{other\_kchar}$: %
+\37\&{begin} \37$\\{cx}\K\\{cur\_chr}$;\5
+$\\{set\_math\_kchar}(\\{KANJI}(\\{cx}))$;\6
+\&{end};\6
+\4$\\{mmode}+\\{char\_num}$: \37\&{begin} \37\\{scan\_char\_num};\5
+$\\{cur\_chr}\K\\{cur\_val}$;\6
+\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ \1\&{then}\6
+\&{if} $\\{cur\_chr}<128$ \1\&{then}\5
+$\\{set\_math\_char}(\\{ho}(\\{math\_code}(\\{cur\_chr})))$\6
+\4\&{else} $\\{set\_math\_char}(\\{cur\_chr})$\2\6
+\4\&{else} $\\{set\_math\_kchar}(\\{cur\_chr})$;\2\6
+\&{end};\6
+\4$\\{mmode}+\\{math\_char\_num}$: \37\&{begin} \37\\{scan\_fifteen\_bit\_int};%
+\5
+$\\{set\_math\_char}(\\{cur\_val})$;\6
+\&{end};\6
+\4$\\{mmode}+\\{math\_given}$: \37$\\{set\_math\_char}(\\{cur\_chr})$;\6
+\4$\\{mmode}+\\{delim\_num}$: \37\&{begin} \37\\{scan\_twenty\_seven\_bit%
+\_int};\5
+$\\{set\_math\_char}(\\{cur\_val}\mathbin{\&{div}}\O{10000})$;\6
+\&{end};\par
+\fi
+
+\M1167. The \\{set\_math\_char} procedure creates a new noad appropriate to a
+given
+math code, and appends it to the current mlist. However, if the math code
+is sufficiently large, the \\{cur\_chr} is treated as an active character and
+nothing is appended.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{set\_math\_char}(\|c:\\{integer})$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new noad}\2\6
+\&{begin} \37\&{if} $\|c\G\O{100000}$ \1\&{then}\5
+\X1164:Treat \\{cur\_chr} as an active character\X\6
+\4\&{else} \&{begin} \37$\|p\K\\{new\_noad}$;\5
+$\\{math\_type}(\\{nucleus}(\|p))\K\\{math\_char}$;\5
+$\\{character}(\\{nucleus}(\|p))\K\\{qi}(\|c\mathbin{\&{mod}}256)$;\5
+$\\{fam}(\\{nucleus}(\|p))\K(\|c\mathbin{\&{div}}256)\mathbin{\&{mod}}16$;\6
+\&{if} $\|c\G\\{var\_code}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{fam\_in\_range}$ \1\&{then}\5
+$\\{fam}(\\{nucleus}(\|p))\K\\{cur\_fam}$;\2\6
+$\\{type}(\|p)\K\\{ord\_noad}$;\6
+\&{end}\6
+\4\&{else} $\\{type}(\|p)\K\\{ord\_noad}+(\|c\mathbin{\&{div}}\O{10000})$;\2\6
+$\\{link}(\\{tail})\K\|p$;\5
+$\\{tail}\K\|p$;\6
+\&{if} $\\{font\_dir}[\\{fam\_fnt}(\\{fam}(\\{nucleus}(\|p))+\\{cur\_size})]\I%
+\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Not\ one-byte\ family"})$;\5
+$\\{help1}(\.{"IGNORE."})$;\6
+\\{error};\6
+\&{end};\2\6
+$\\{inhibit\_glue\_flag}\K\\{false}$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1168. Primitive math operators like \.{\\mathop} and \.{\\underline} are
+given
+the command code \\{math\_comp}, supplemented by the noad type that they
+generate.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"mathord"},\39\\{math\_comp},\39\\{ord\_noad})$;\5
+$\\{primitive}(\.{"mathop"},\39\\{math\_comp},\39\\{op\_noad})$;\5
+$\\{primitive}(\.{"mathbin"},\39\\{math\_comp},\39\\{bin\_noad})$;\5
+$\\{primitive}(\.{"mathrel"},\39\\{math\_comp},\39\\{rel\_noad})$;\5
+$\\{primitive}(\.{"mathopen"},\39\\{math\_comp},\39\\{open\_noad})$;\5
+$\\{primitive}(\.{"mathclose"},\39\\{math\_comp},\39\\{close\_noad})$;\5
+$\\{primitive}(\.{"mathpunct"},\39\\{math\_comp},\39\\{punct\_noad})$;\5
+$\\{primitive}(\.{"mathinner"},\39\\{math\_comp},\39\\{inner\_noad})$;\5
+$\\{primitive}(\.{"underline"},\39\\{math\_comp},\39\\{under\_noad})$;\5
+$\\{primitive}(\.{"overline"},\39\\{math\_comp},\39\\{over\_noad})$;\6
+$\\{primitive}(\.{"displaylimits"},\39\\{limit\_switch},\39\\{normal})$;\5
+$\\{primitive}(\.{"limits"},\39\\{limit\_switch},\39\\{limits})$;\5
+$\\{primitive}(\.{"nolimits"},\39\\{limit\_switch},\39\\{no\_limits})$;\par
+\fi
+
+\M1169. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{math\_comp}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{ord\_noad}: \37$\\{print\_esc}(\.{"mathord"})$;\6
+\4\\{op\_noad}: \37$\\{print\_esc}(\.{"mathop"})$;\6
+\4\\{bin\_noad}: \37$\\{print\_esc}(\.{"mathbin"})$;\6
+\4\\{rel\_noad}: \37$\\{print\_esc}(\.{"mathrel"})$;\6
+\4\\{open\_noad}: \37$\\{print\_esc}(\.{"mathopen"})$;\6
+\4\\{close\_noad}: \37$\\{print\_esc}(\.{"mathclose"})$;\6
+\4\\{punct\_noad}: \37$\\{print\_esc}(\.{"mathpunct"})$;\6
+\4\\{inner\_noad}: \37$\\{print\_esc}(\.{"mathinner"})$;\6
+\4\\{under\_noad}: \37$\\{print\_esc}(\.{"underline"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"overline"})$\2\6
+\&{endcases};\6
+\4\\{limit\_switch}: \37\&{if} $\\{chr\_code}=\\{limits}$ \1\&{then}\5
+$\\{print\_esc}(\.{"limits"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{no\_limits}$ \1\&{then}\5
+$\\{print\_esc}(\.{"nolimits"})$\6
+\4\&{else} $\\{print\_esc}(\.{"displaylimits"})$;\2\2\par
+\fi
+
+\M1170. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{math\_comp}$: \37\&{begin} \37$\\{tail\_append}(\\{new%
+\_noad})$;\5
+$\\{type}(\\{tail})\K\\{cur\_chr}$;\5
+$\\{scan\_math}(\\{nucleus}(\\{tail}),\39\\{kcode\_noad}(\\{tail}))$;\6
+\&{end};\6
+\4$\\{mmode}+\\{limit\_switch}$: \37\\{math\_limit\_switch};\par
+\fi
+
+\M1171. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{math\_limit\_switch};\6
+\4\&{label} \37\\{exit};\2\6
+\&{begin} \37\&{if} $\\{head}\I\\{tail}$ \1\&{then}\6
+\&{if} $\\{type}(\\{tail})=\\{op\_noad}$ \1\&{then}\6
+\&{begin} \37$\\{subtype}(\\{tail})\K\\{cur\_chr}$;\5
+\&{return};\6
+\&{end};\2\2\6
+$\\{print\_err}(\.{"Limit\ controls\ must\ follow\ a\ math\ operator"})$;\5
+$\\{help1}(\.{"I\'m\ ignoring\ this\ misplaced\ \\limits\ or\ \\nolimits\
+command."})$;\5
+\\{error};\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1172. Delimiter fields of noads are filled in by the \\{scan\_delimiter}
+routine.
+The first parameter of this procedure is the \\{mem} address where the
+delimiter is to be placed; the second tells if this delimiter follows
+\.{\\radical} or not.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{scan\_delimiter}(\|p:\\{pointer};\,\35\|r:%
+\\{boolean})$;\2\6
+\&{begin} \37\&{if} $\|r$ \1\&{then}\5
+\\{scan\_twenty\_seven\_bit\_int}\6
+\4\&{else} \&{begin} \37\X415:Get the next non-blank non-relax non-call token%
+\X;\6
+\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\4$\\{letter},\39\\{other\_char}$: \37$\\{cur\_val}\K\\{del\_code}(\\{cur%
+\_chr})$;\6
+\4\\{delim\_num}: \37\\{scan\_twenty\_seven\_bit\_int};\6
+\4\&{othercases} \37$\\{cur\_val}\K-1$\2\6
+\&{endcases};\6
+\&{end};\2\6
+\&{if} $\\{cur\_val}<0$ \1\&{then}\5
+\X1173:Report that an invalid delimiter code is being changed to null; set~$%
+\\{cur\_val}\K0$\X;\2\6
+$\\{small\_fam}(\|p)\K(\\{cur\_val}\mathbin{\&{div}}\O{4000000})\mathbin{%
+\&{mod}}16$;\5
+$\\{small\_char}(\|p)\K\\{qi}((\\{cur\_val}\mathbin{\&{div}}\O{10000})\mathbin{%
+\&{mod}}256)$;\5
+$\\{large\_fam}(\|p)\K(\\{cur\_val}\mathbin{\&{div}}256)\mathbin{\&{mod}}16$;\5
+$\\{large\_char}(\|p)\K\\{qi}(\\{cur\_val}\mathbin{\&{mod}}256)$;\6
+\&{end};\par
+\fi
+
+\M1173. \P$\X1173:Report that an invalid delimiter code is being changed to
+null; set~$\\{cur\_val}\K0$\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ delimiter\ (.\ inserted)"})$;\5
+$\\{help6}(\.{"I\ was\ expecting\ to\ see\ something\ like\ \`(\'\ or\ \`\\\{\'%
+\ or"})$\6
+$(\.{"\`\\\}\'\ here.\ If\ you\ typed,\ e.g.,\ \`\{\'\ instead\ of\ \`\\\{\',\
+you"})$\6
+$(\.{"should\ probably\ delete\ the\ \`\{\'\ by\ typing\ \`1\'\ now,\ so\
+that"})$\6
+$(\.{"braces\ don\'t\ get\ unbalanced.\ Otherwise\ just\ proceed."})$\6
+$(\.{"Acceptable\ delimiters\ are\ characters\ whose\ \\delcode\ is"})$\6
+$(\.{"nonnegative,\ or\ you\ can\ use\ \`\\delimiter\ <delimiter\ code>\'."})$;%
+\5
+\\{back\_error};\5
+$\\{cur\_val}\K0$;\6
+\&{end}\par
+\U1172.\fi
+
+\M1174. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{radical}$: \37\\{math\_radical};\par
+\fi
+
+\M1175. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{math\_radical};\2\6
+\&{begin} \37$\\{tail\_append}(\\{get\_node}(\\{radical\_noad\_size}))$;\5
+$\\{type}(\\{tail})\K\\{radical\_noad}$;\5
+$\\{subtype}(\\{tail})\K\\{normal}$;\5
+$\\{mem}[\\{nucleus}(\\{tail})].\\{hh}\K\\{empty\_field}$;\5
+$\\{mem}[\\{subscr}(\\{tail})].\\{hh}\K\\{empty\_field}$;\5
+$\\{mem}[\\{supscr}(\\{tail})].\\{hh}\K\\{empty\_field}$;\5
+$\\{scan\_delimiter}(\\{left\_delimiter}(\\{tail}),\39\\{true})$;\5
+$\\{scan\_math}(\\{nucleus}(\\{tail}),\39\\{kcode\_noad}(\\{tail}))$;\6
+\&{end};\par
+\fi
+
+\M1176. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{accent},\39\\{mmode}+\\{math\_accent}$: \37\\{math\_ac};\par
+\fi
+
+\M1177. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{math\_ac};\2\6
+\&{begin} \37\&{if} $\\{cur\_cmd}=\\{accent}$ \1\&{then}\5
+\X1178:Complain that the user should have said \.{\\mathaccent}\X;\2\6
+$\\{tail\_append}(\\{get\_node}(\\{accent\_noad\_size}))$;\5
+$\\{type}(\\{tail})\K\\{accent\_noad}$;\5
+$\\{subtype}(\\{tail})\K\\{normal}$;\5
+$\\{mem}[\\{nucleus}(\\{tail})].\\{hh}\K\\{empty\_field}$;\5
+$\\{mem}[\\{subscr}(\\{tail})].\\{hh}\K\\{empty\_field}$;\5
+$\\{mem}[\\{supscr}(\\{tail})].\\{hh}\K\\{empty\_field}$;\5
+$\\{math\_type}(\\{accent\_chr}(\\{tail}))\K\\{math\_char}$;\5
+\\{scan\_fifteen\_bit\_int};\5
+$\\{character}(\\{accent\_chr}(\\{tail}))\K\\{qi}(\\{cur\_val}\mathbin{%
+\&{mod}}256)$;\6
+\&{if} $(\\{cur\_val}\G\\{var\_code})\W\\{fam\_in\_range}$ \1\&{then}\5
+$\\{fam}(\\{accent\_chr}(\\{tail}))\K\\{cur\_fam}$\6
+\4\&{else} $\\{fam}(\\{accent\_chr}(\\{tail}))\K(\\{cur\_val}\mathbin{%
+\&{div}}256)\mathbin{\&{mod}}16$;\2\6
+$\\{scan\_math}(\\{nucleus}(\\{tail}),\39\\{kcode\_noad}(\\{tail}))$;\6
+\&{end};\par
+\fi
+
+\M1178. \P$\X1178:Complain that the user should have said \.{\\mathaccent}\X\S$%
+\6
+\&{begin} \37$\\{print\_err}(\.{"Please\ use\ "})$;\5
+$\\{print\_esc}(\.{"mathaccent"})$;\5
+$\\{print}(\.{"\ for\ accents\ in\ math\ mode"})$;\5
+$\\{help2}(\.{"I\'m\ changing\ \\accent\ to\ \\mathaccent\ here;\ wish\ me\
+luck."})$\6
+$(\.{"(Accents\ are\ not\ the\ same\ in\ formulas\ as\ they\ are\ in\
+text.)"})$;\5
+\\{error};\6
+\&{end}\par
+\U1177.\fi
+
+\M1179. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{vcenter}$: \37\&{begin} \37$\\{scan\_spec}(\\{vcenter\_group},%
+\39\\{false})$;\5
+\\{normal\_paragraph};\5
+$\\{inhibit\_glue\_flag}\K\\{false}$;\5
+\\{push\_nest};\5
+$\\{mode}\K-\\{vmode}$;\5
+$\\{prev\_depth}\K\\{ignore\_depth}$;\6
+\&{if} $(\\{insert\_src\_special\_every\_vbox})$ \1\&{then}\5
+\\{insert\_src\_special};\2\6
+\&{if} $\\{every\_vbox}\I\\{null}$ \1\&{then}\5
+$\\{begin\_token\_list}(\\{every\_vbox},\39\\{every\_vbox\_text})$;\2\6
+\&{end};\par
+\fi
+
+\M1180. \P$\X1097:Cases of \\{handle\_right\_brace} where a \\{right\_brace}
+triggers a delayed action\X\mathrel{+}\S$\6
+\4\\{vcenter\_group}: \37\&{begin} \37\\{end\_graf};\5
+\\{unsave};\5
+$\\{save\_ptr}\K\\{save\_ptr}-2$;\5
+$\|p\K\\{vpack}(\\{link}(\\{head}),\39\\{saved}(1),\39\\{saved}(0))$;\5
+$\\{set\_box\_dir}(\|p)(\\{abs}(\\{direction}))$;\5
+\\{pop\_nest};\6
+\&{if} $\\{box\_dir}(\|p)\I\\{abs}(\\{direction})$ \1\&{then}\5
+$\|p\K\\{new\_dir\_node}(\|p,\39\\{abs}(\\{direction}))$;\2\6
+$\\{tail\_append}(\\{new\_noad})$;\5
+$\\{type}(\\{tail})\K\\{vcenter\_noad}$;\5
+$\\{math\_type}(\\{nucleus}(\\{tail}))\K\\{sub\_box}$;\5
+$\\{info}(\\{nucleus}(\\{tail}))\K\|p$;\6
+\&{end};\par
+\fi
+
+\M1181. The routine that inserts a \\{style\_node} holds no surprises.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"displaystyle"},\39\\{math\_style},\39\\{display\_style})$;\5
+$\\{primitive}(\.{"textstyle"},\39\\{math\_style},\39\\{text\_style})$;\5
+$\\{primitive}(\.{"scriptstyle"},\39\\{math\_style},\39\\{script\_style})$;\5
+$\\{primitive}(\.{"scriptscriptstyle"},\39\\{math\_style},\39\\{script\_script%
+\_style})$;\par
+\fi
+
+\M1182. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{math\_style}: \37$\\{print\_style}(\\{chr\_code})$;\par
+\fi
+
+\M1183. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{math\_style}$: \37$\\{tail\_append}(\\{new\_style}(\\{cur%
+\_chr}))$;\6
+\4$\\{mmode}+\\{non\_script}$: \37\&{begin} \37$\\{tail\_append}(\\{new\_glue}(%
+\\{zero\_glue}))$;\5
+$\\{subtype}(\\{tail})\K\\{cond\_math\_glue}$;\6
+\&{end};\6
+\4$\\{mmode}+\\{math\_choice}$: \37\\{append\_choices};\par
+\fi
+
+\M1184. The routine that scans the four mlists of a \.{\\mathchoice} is very
+much like the routine that builds discretionary nodes.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{append\_choices};\2\6
+\&{begin} \37$\\{tail\_append}(\\{new\_choice})$;\5
+$\\{incr}(\\{save\_ptr})$;\5
+$\\{saved}(-1)\K0$;\5
+$\\{push\_math}(\\{math\_choice\_group})$;\5
+\\{scan\_left\_brace};\6
+\&{end};\par
+\fi
+
+\M1185. \P$\X1097:Cases of \\{handle\_right\_brace} where a \\{right\_brace}
+triggers a delayed action\X\mathrel{+}\S$\6
+\4\\{math\_choice\_group}: \37\\{build\_choices};\par
+\fi
+
+\M1186. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\hbox{\4}\X1196:Declare the function called \\{fin\_mlist}\X\hbox{}\6
+\4\&{procedure}\1\  \37\\{build\_choices};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the current mlist}\2\6
+\&{begin} \37\\{unsave};\5
+$\|p\K\\{fin\_mlist}(\\{null})$;\6
+\&{case} $\\{saved}(-1)$ \1\&{of}\6
+\40: \37$\\{display\_mlist}(\\{tail})\K\|p$;\6
+\41: \37$\\{text\_mlist}(\\{tail})\K\|p$;\6
+\42: \37$\\{script\_mlist}(\\{tail})\K\|p$;\6
+\43: \37\&{begin} \37$\\{script\_script\_mlist}(\\{tail})\K\|p$;\5
+$\\{decr}(\\{save\_ptr})$;\5
+\&{return};\6
+\&{end};\2\6
+\&{end};\C{there are no other cases}\6
+$\\{incr}(\\{saved}(-1))$;\5
+$\\{push\_math}(\\{math\_choice\_group})$;\5
+\\{scan\_left\_brace};\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1187. Subscripts and superscripts are attached to the previous nucleus by the
+action procedure called \\{sub\_sup}. We use the facts that $\\{sub\_mark}=%
+\\{sup\_mark}+1$
+and $\\{subscr}(\|p)=\\{supscr}(\|p)+1$.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{sub\_mark},\39\\{mmode}+\\{sup\_mark}$: \37\\{sub\_sup};\par
+\fi
+
+\M1188. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{sub\_sup};\6
+\4\&{var} \37\|t: \37\\{small\_number};\C{type of previous sub/superscript}\6
+\|p: \37\\{pointer};\C{field to be filled by \\{scan\_math}}\2\6
+\&{begin} \37$\|t\K\\{empty}$;\5
+$\|p\K\\{null}$;\5
+$\\{inhibit\_glue\_flag}\K\\{false}$;\6
+\&{if} $\\{tail}\I\\{head}$ \1\&{then}\6
+\&{if} $\\{scripts\_allowed}(\\{tail})$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{supscr}(\\{tail})+\\{cur\_cmd}-\\{sup\_mark}$;\C{%
+\\{supscr} or \\{subscr}}\6
+$\|t\K\\{math\_type}(\|p)$;\6
+\&{end};\2\2\6
+\&{if} $(\|p=\\{null})\V(\|t\I\\{empty})$ \1\&{then}\5
+\X1189:Insert a dummy noad to be sub/superscripted\X;\2\6
+$\\{scan\_math}(\|p,\39\\{null})$;\6
+\&{end};\par
+\fi
+
+\M1189. \P$\X1189:Insert a dummy noad to be sub/superscripted\X\S$\6
+\&{begin} \37$\\{tail\_append}(\\{new\_noad})$;\5
+$\|p\K\\{supscr}(\\{tail})+\\{cur\_cmd}-\\{sup\_mark}$;\C{\\{supscr} or %
+\\{subscr}}\6
+\&{if} $\|t\I\\{empty}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{cur\_cmd}=\\{sup\_mark}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Double\ superscript"})$;\5
+$\\{help1}(\.{"I\ treat\ \`x\^1\^2\'\ essentially\ like\ \`x\^1\{\}\^2\'."})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Double\ subscript"})$;\5
+$\\{help1}(\.{"I\ treat\ \`x\_1\_2\'\ essentially\ like\ \`x\_1\{\}\_2\'."})$;\6
+\&{end};\2\6
+\\{error};\6
+\&{end};\2\6
+\&{end}\par
+\U1188.\fi
+
+\M1190. An operation like `\.{\\over}' causes the current mlist to go into a
+state of suspended animation: \\{incompleat\_noad} points to a \\{fraction%
+\_noad}
+that contains the mlist-so-far as its numerator, while the denominator
+is yet to come. Finally when the mlist is finished, the denominator will
+go into the incompleat fraction noad, and that noad will become the
+whole formula, unless it is surrounded by `\.{\\left}' and `\.{\\right}'
+delimiters.
+
+\Y\P\D \37$\\{above\_code}=0$\C{ `\.{\\above}' }\par
+\P\D \37$\\{over\_code}=1$\C{ `\.{\\over}' }\par
+\P\D \37$\\{atop\_code}=2$\C{ `\.{\\atop}' }\par
+\P\D \37$\\{delimited\_code}=3$\C{ `\.{\\abovewithdelims}', etc.}\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"above"},\39\\{above},\39\\{above\_code})$;\6
+$\\{primitive}(\.{"over"},\39\\{above},\39\\{over\_code})$;\6
+$\\{primitive}(\.{"atop"},\39\\{above},\39\\{atop\_code})$;\6
+$\\{primitive}(\.{"abovewithdelims"},\39\\{above},\39\\{delimited\_code}+%
+\\{above\_code})$;\6
+$\\{primitive}(\.{"overwithdelims"},\39\\{above},\39\\{delimited\_code}+\\{over%
+\_code})$;\6
+$\\{primitive}(\.{"atopwithdelims"},\39\\{above},\39\\{delimited\_code}+\\{atop%
+\_code})$;\par
+\fi
+
+\M1191. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{above}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{over\_code}: \37$\\{print\_esc}(\.{"over"})$;\6
+\4\\{atop\_code}: \37$\\{print\_esc}(\.{"atop"})$;\6
+\4$\\{delimited\_code}+\\{above\_code}$: \37$\\{print\_esc}(%
+\.{"abovewithdelims"})$;\6
+\4$\\{delimited\_code}+\\{over\_code}$: \37$\\{print\_esc}(%
+\.{"overwithdelims"})$;\6
+\4$\\{delimited\_code}+\\{atop\_code}$: \37$\\{print\_esc}(%
+\.{"atopwithdelims"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"above"})$\2\6
+\&{endcases};\par
+\fi
+
+\M1192. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{above}$: \37\\{math\_fraction};\par
+\fi
+
+\M1193. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{math\_fraction};\6
+\4\&{var} \37\|c: \37\\{small\_number};\C{the type of generalized fraction we
+are scanning}\2\6
+\&{begin} \37$\|c\K\\{cur\_chr}$;\5
+$\\{inhibit\_glue\_flag}\K\\{false}$;\6
+\&{if} $\\{incompleat\_noad}\I\\{null}$ \1\&{then}\5
+\X1195:Ignore the fraction operation and complain about this ambiguous case\X\6
+\4\&{else} \&{begin} \37$\\{incompleat\_noad}\K\\{get\_node}(\\{fraction\_noad%
+\_size})$;\5
+$\\{type}(\\{incompleat\_noad})\K\\{fraction\_noad}$;\5
+$\\{subtype}(\\{incompleat\_noad})\K\\{normal}$;\5
+$\\{math\_type}(\\{numerator}(\\{incompleat\_noad}))\K\\{sub\_mlist}$;\5
+$\\{info}(\\{numerator}(\\{incompleat\_noad}))\K\\{link}(\\{head})$;\5
+$\\{mem}[\\{denominator}(\\{incompleat\_noad})].\\{hh}\K\\{empty\_field}$;\5
+$\\{mem}[\\{left\_delimiter}(\\{incompleat\_noad})].\\{qqqq}\K\\{null%
+\_delimiter}$;\5
+$\\{mem}[\\{right\_delimiter}(\\{incompleat\_noad})].\\{qqqq}\K\\{null%
+\_delimiter}$;\6
+$\\{link}(\\{head})\K\\{null}$;\5
+$\\{tail}\K\\{head}$;\5
+\X1194:Use code \|c to distinguish between generalized fractions\X;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1194. \P$\X1194:Use code \|c to distinguish between generalized fractions\X%
+\S$\6
+\&{if} $\|c\G\\{delimited\_code}$ \1\&{then}\6
+\&{begin} \37$\\{scan\_delimiter}(\\{left\_delimiter}(\\{incompleat\_noad}),\39%
+\\{false})$;\5
+$\\{scan\_delimiter}(\\{right\_delimiter}(\\{incompleat\_noad}),\39\\{false})$;%
+\6
+\&{end};\2\6
+\&{case} $\|c\mathbin{\&{mod}}\\{delimited\_code}$ \1\&{of}\6
+\4\\{above\_code}: \37\&{begin} \37\\{scan\_normal\_dimen};\5
+$\\{thickness}(\\{incompleat\_noad})\K\\{cur\_val}$;\6
+\&{end};\6
+\4\\{over\_code}: \37$\\{thickness}(\\{incompleat\_noad})\K\\{default\_code}$;\6
+\4\\{atop\_code}: \37$\\{thickness}(\\{incompleat\_noad})\K0$;\2\6
+\&{end}\C{there are no other cases}\par
+\U1193.\fi
+
+\M1195. \P$\X1195:Ignore the fraction operation and complain about this
+ambiguous case\X\S$\6
+\&{begin} \37\&{if} $\|c\G\\{delimited\_code}$ \1\&{then}\6
+\&{begin} \37$\\{scan\_delimiter}(\\{garbage},\39\\{false})$;\5
+$\\{scan\_delimiter}(\\{garbage},\39\\{false})$;\6
+\&{end};\2\6
+\&{if} $\|c\mathbin{\&{mod}}\\{delimited\_code}=\\{above\_code}$ \1\&{then}\5
+\\{scan\_normal\_dimen};\2\6
+$\\{print\_err}(\.{"Ambiguous;\ you\ need\ another\ \{\ and\ \}"})$;\5
+$\\{help3}(\.{"I\'m\ ignoring\ this\ fraction\ specification,\ since\ I\ don%
+\'t"})$\6
+$(\.{"know\ whether\ a\ construction\ like\ \`x\ \\over\ y\ \\over\ z\'"})$\6
+$(\.{"means\ \`\{x\ \\over\ y\}\ \\over\ z\'\ or\ \`x\ \\over\ \{y\ \\over\ z\}%
+\'."})$;\5
+\\{error};\6
+\&{end}\par
+\U1193.\fi
+
+\M1196. At the end of a math formula or subformula, the \\{fin\_mlist} routine
+is
+called upon to return a pointer to the newly completed mlist, and to
+pop the nest back to the enclosing semantic level. The parameter to
+\\{fin\_mlist}, if not null, points to a \\{right\_noad} that ends the
+current mlist; this \\{right\_noad} has not yet been appended.
+
+\Y\P$\4\X1196:Declare the function called \\{fin\_mlist}\X\S$\6
+\4\&{function}\1\  \37$\\{fin\_mlist}(\|p:\\{pointer})$: \37\\{pointer};\6
+\4\&{var} \37\|q: \37\\{pointer};\C{the mlist to return}\2\6
+\&{begin} \37\&{if} $\\{incompleat\_noad}\I\\{null}$ \1\&{then}\5
+\X1197:Compleat the incompleat noad\X\6
+\4\&{else} \&{begin} \37$\\{link}(\\{tail})\K\|p$;\5
+$\|q\K\\{link}(\\{head})$;\6
+\&{end};\2\6
+\\{pop\_nest};\5
+$\\{fin\_mlist}\K\|q$;\6
+\&{end};\par
+\U1186.\fi
+
+\M1197. \P$\X1197:Compleat the incompleat noad\X\S$\6
+\&{begin} \37$\\{math\_type}(\\{denominator}(\\{incompleat\_noad}))\K\\{sub%
+\_mlist}$;\5
+$\\{info}(\\{denominator}(\\{incompleat\_noad}))\K\\{link}(\\{head})$;\6
+\&{if} $\|p=\\{null}$ \1\&{then}\5
+$\|q\K\\{incompleat\_noad}$\6
+\4\&{else} \&{begin} \37$\|q\K\\{info}(\\{numerator}(\\{incompleat\_noad}))$;\6
+\&{if} $\\{type}(\|q)\I\\{left\_noad}$ \1\&{then}\5
+$\\{confusion}(\.{"right"})$;\2\6
+$\\{info}(\\{numerator}(\\{incompleat\_noad}))\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\\{incompleat\_noad}$;\5
+$\\{link}(\\{incompleat\_noad})\K\|p$;\6
+\&{end};\2\6
+\&{end}\par
+\U1196.\fi
+
+\M1198. Now at last we're ready to see what happens when a right brace occurs
+in a math formula. Two special cases are simplified here: Braces are
+effectively
+removed when they surround a single Ord without sub/superscripts, or when they
+surround an accent that is the nucleus of an Ord atom.
+
+\Y\P$\4\X1097:Cases of \\{handle\_right\_brace} where a \\{right\_brace}
+triggers a delayed action\X\mathrel{+}\S$\6
+\4\\{math\_group}: \37\&{begin} \37\\{unsave};\5
+$\\{decr}(\\{save\_ptr})$;\6
+$\\{math\_type}(\\{saved}(0))\K\\{sub\_mlist}$;\5
+$\|p\K\\{fin\_mlist}(\\{null})$;\5
+$\\{info}(\\{saved}(0))\K\|p$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{if} $\\{link}(\|p)=\\{null}$ \1\&{then}\6
+\&{if} $\\{type}(\|p)=\\{ord\_noad}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{math\_type}(\\{subscr}(\|p))=\\{empty}$ \1\&{then}\6
+\&{if} $((\\{math\_type}(\\{supscr}(\|p))=\\{empty})\W(\\{math\_kcode}(\|p)=%
+\\{null}))$ \1\&{then}\6
+\&{begin} \37$\\{mem}[\\{saved}(0)].\\{hh}\K\\{mem}[\\{nucleus}(\|p)].\\{hh}$;\5
+$\\{free\_node}(\|p,\39\\{noad\_size})$;\6
+\&{end};\2\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{type}(\|p)=\\{accent\_noad}$ \1\&{then}\6
+\&{if} $\\{saved}(0)=\\{nucleus}(\\{tail})$ \1\&{then}\6
+\&{if} $\\{type}(\\{tail})=\\{ord\_noad}$ \1\&{then}\5
+\X1199:Replace the tail of the list by \|p\X;\2\2\2\2\2\2\6
+\&{end};\par
+\fi
+
+\M1199. \P$\X1199:Replace the tail of the list by \|p\X\S$\6
+\&{begin} \37$\|q\K\\{head}$;\6
+\&{while} $\\{link}(\|q)\I\\{tail}$ \1\&{do}\5
+$\|q\K\\{link}(\|q)$;\2\6
+$\\{link}(\|q)\K\|p$;\5
+$\\{free\_node}(\\{tail},\39\\{noad\_size})$;\5
+$\\{tail}\K\|p$;\6
+\&{end}\par
+\U1198.\fi
+
+\M1200. We have dealt with all constructions of math mode except `\.{\\left}'
+and
+`\.{\\right}', so the picture is completed by the following sections of
+the program.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"left"},\39\\{left\_right},\39\\{left\_noad})$;\5
+$\\{primitive}(\.{"right"},\39\\{left\_right},\39\\{right\_noad})$;\5
+$\\{text}(\\{frozen\_right})\K\.{"right"}$;\5
+$\\{eqtb}[\\{frozen\_right}]\K\\{eqtb}[\\{cur\_val}]$;\par
+\fi
+
+\M1201. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{left\_right}: \37\&{if} $\\{chr\_code}=\\{left\_noad}$ \1\&{then}\5
+$\\{print\_esc}(\.{"left"})$\6
+\4\&{else} $\\{print\_esc}(\.{"right"})$;\2\par
+\fi
+
+\M1202. \P$\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{left\_right}$: \37\\{math\_left\_right};\par
+\fi
+
+\M1203. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{math\_left\_right};\6
+\4\&{var} \37\|t: \37\\{small\_number};\C{\\{left\_noad} or \\{right\_noad}}\6
+\|p: \37\\{pointer};\C{new noad}\2\6
+\&{begin} \37$\|t\K\\{cur\_chr}$;\5
+$\\{inhibit\_glue\_flag}\K\\{false}$;\6
+\&{if} $(\|t=\\{right\_noad})\W(\\{cur\_group}\I\\{math\_left\_group})$ \1%
+\&{then}\5
+\X1204:Try to recover from mismatched \.{\\right}\X\6
+\4\&{else} \&{begin} \37$\|p\K\\{new\_noad}$;\5
+$\\{type}(\|p)\K\|t$;\5
+$\\{scan\_delimiter}(\\{delimiter}(\|p),\39\\{false})$;\6
+\&{if} $\|t=\\{left\_noad}$ \1\&{then}\6
+\&{begin} \37$\\{push\_math}(\\{math\_left\_group})$;\5
+$\\{link}(\\{head})\K\|p$;\5
+$\\{tail}\K\|p$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|p\K\\{fin\_mlist}(\|p)$;\5
+\\{unsave};\C{end of \\{math\_left\_group}}\6
+$\\{tail\_append}(\\{new\_noad})$;\5
+$\\{type}(\\{tail})\K\\{inner\_noad}$;\5
+$\\{math\_type}(\\{nucleus}(\\{tail}))\K\\{sub\_mlist}$;\5
+$\\{info}(\\{nucleus}(\\{tail}))\K\|p$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1204. \P$\X1204:Try to recover from mismatched \.{\\right}\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_group}=\\{math\_shift\_group}$ \1\&{then}\6
+\&{begin} \37$\\{scan\_delimiter}(\\{garbage},\39\\{false})$;\5
+$\\{print\_err}(\.{"Extra\ "})$;\5
+$\\{print\_esc}(\.{"right"})$;\5
+$\\{help1}(\.{"I\'m\ ignoring\ a\ \\right\ that\ had\ no\ matching\ %
+\\left."})$;\5
+\\{error};\6
+\&{end}\6
+\4\&{else} \\{off\_save};\2\6
+\&{end}\par
+\U1203.\fi
+
+\M1205. Here is the only way out of math mode.
+
+\Y\P$\4\X1068:Cases of \\{main\_control} that build boxes and lists\X%
+\mathrel{+}\S$\6
+\4$\\{mmode}+\\{math\_shift}$: \37\&{if} $\\{cur\_group}=\\{math\_shift%
+\_group}$ \1\&{then}\5
+\\{after\_math}\6
+\4\&{else} \\{off\_save};\2\par
+\fi
+
+\M1206. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{after\_math};\6
+\4\&{var} \37\|l: \37\\{boolean};\C{`\.{\\leqno}' instead of `\.{\\eqno}'}\6
+\\{disp}: \37\\{scaled};\C{displacement}\6
+\\{danger}: \37\\{boolean};\C{not enough symbol fonts are present}\6
+\|m: \37\\{integer};\C{\\{mmode} or $-\\{mmode}$}\6
+\|p: \37\\{pointer};\C{the formula}\6
+\|a: \37\\{pointer};\C{box containing equation number}\6
+\X1210:Local variables for finishing a displayed formula\X\2\6
+\&{begin} \37$\\{danger}\K\\{false}$;\5
+\X1207:Check that the necessary fonts for math symbols are present; if not,
+flush the current math lists and set $\\{danger}\K\\{true}$\X;\6
+$\\{delete\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_xkanji\_skip})$;\6
+\&{if} $\\{auto\_spacing}>0$ \1\&{then}\5
+$\\{cur\_kanji\_skip}\K\\{kanji\_skip}$\6
+\4\&{else} $\\{cur\_kanji\_skip}\K\\{zero\_glue}$;\2\6
+\&{if} $\\{auto\_xspacing}>0$ \1\&{then}\5
+$\\{cur\_xkanji\_skip}\K\\{xkanji\_skip}$\6
+\4\&{else} $\\{cur\_xkanji\_skip}\K\\{zero\_glue}$;\2\6
+$\\{add\_glue\_ref}(\\{cur\_kanji\_skip})$;\5
+$\\{add\_glue\_ref}(\\{cur\_xkanji\_skip})$;\5
+$\|m\K\\{mode}$;\5
+$\|l\K\\{false}$;\5
+$\|p\K\\{fin\_mlist}(\\{null})$;\C{this pops the nest}\6
+\&{if} $\\{mode}=-\|m$ \1\&{then}\C{end of equation number}\6
+\&{begin} \37\X1209:Check that another \.\$ follows\X;\6
+$\\{cur\_mlist}\K\|p$;\5
+$\\{cur\_style}\K\\{text\_style}$;\5
+$\\{mlist\_penalties}\K\\{false}$;\5
+\\{mlist\_to\_hlist};\5
+$\|a\K\\{hpack}(\\{link}(\\{temp\_head}),\39\\{natural})$;\5
+\\{unsave};\5
+$\\{decr}(\\{save\_ptr})$;\C{now $\\{cur\_group}=\\{math\_shift\_group}$}\6
+\&{if} $\\{saved}(0)=1$ \1\&{then}\5
+$\|l\K\\{true}$;\2\6
+$\\{danger}\K\\{false}$;\5
+\X1207:Check that the necessary fonts for math symbols are present; if not,
+flush the current math lists and set $\\{danger}\K\\{true}$\X;\6
+$\|m\K\\{mode}$;\5
+$\|p\K\\{fin\_mlist}(\\{null})$;\6
+\&{end}\6
+\4\&{else} $\|a\K\\{null}$;\2\6
+\&{if} $\|m<0$ \1\&{then}\5
+\X1208:Finish math in text\X\6
+\4\&{else} \&{begin} \37\&{if} $\|a=\\{null}$ \1\&{then}\5
+\X1209:Check that another \.\$ follows\X;\2\6
+\X1211:Finish displayed math\X;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1207. \P$\X1207:Check that the necessary fonts for math symbols are present;
+if not, flush the current math lists and set $\\{danger}\K\\{true}$\X\S$\6
+\&{if} $(\\{font\_params}[\\{fam\_fnt}(2+\\{text\_size})]<\\{total\_mathsy%
+\_params})\V\30(\\{font\_params}[\\{fam\_fnt}(2+\\{script\_size})]<\\{total%
+\_mathsy\_params})\V\30(\\{font\_params}[\\{fam\_fnt}(2+\\{script\_script%
+\_size})]<\\{total\_mathsy\_params})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Math\ formula\ deleted:\ Insufficient\ symbol\
+fonts"})$;\6
+$\\{help3}(\.{"Sorry,\ but\ I\ can\'t\ typeset\ math\ unless\ \\textfont\ 2"})$%
+\6
+$(\.{"and\ \\scriptfont\ 2\ and\ \\scriptscriptfont\ 2\ have\ all"})$\6
+$(\.{"the\ \\fontdimen\ values\ needed\ in\ math\ symbol\ fonts."})$;\5
+\\{error};\5
+\\{flush\_math};\5
+$\\{danger}\K\\{true}$;\6
+\&{end}\6
+\4\&{else} \&{if} $(\\{font\_params}[\\{fam\_fnt}(3+\\{text\_size})]<\\{total%
+\_mathex\_params})\V\30(\\{font\_params}[\\{fam\_fnt}(3+\\{script\_size})]<%
+\\{total\_mathex\_params})\V\30(\\{font\_params}[\\{fam\_fnt}(3+\\{script%
+\_script\_size})]<\\{total\_mathex\_params})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Math\ formula\ deleted:\ Insufficient\
+extension\ fonts"})$;\6
+$\\{help3}(\.{"Sorry,\ but\ I\ can\'t\ typeset\ math\ unless\ \\textfont\ 3"})$%
+\6
+$(\.{"and\ \\scriptfont\ 3\ and\ \\scriptscriptfont\ 3\ have\ all"})$\6
+$(\.{"the\ \\fontdimen\ values\ needed\ in\ math\ extension\ fonts."})$;\5
+\\{error};\5
+\\{flush\_math};\5
+$\\{danger}\K\\{true}$;\6
+\&{end}\2\2\par
+\Us1206\ET1206.\fi
+
+\M1208. The \\{unsave} is done after everything else here; hence an appearance
+of
+`\.{\\mathsurround}' inside of `\.{\$...\$}' affects the spacing at these
+particular \.\$'s. This is consistent with the conventions of
+`\.{\$\$...\$\$}', since `\.{\\abovedisplayskip}' inside a display affects the
+space above that display.
+
+\Y\P$\4\X1208:Finish math in text\X\S$\6
+\&{begin} \37\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\5
+$\\{disp}\K\\{t\_baseline\_shift}$\6
+\4\&{else} $\\{disp}\K\\{y\_baseline\_shift}$;\2\6
+\X1470:Append \\{disp\_node} at begin of displace area\X;\6
+$\\{tail\_append}(\\{new\_math}(\\{math\_surround},\39\\{before}))$;\5
+$\\{cur\_mlist}\K\|p$;\5
+$\\{cur\_style}\K\\{text\_style}$;\5
+$\\{mlist\_penalties}\K(\\{mode}>0)$;\5
+\\{mlist\_to\_hlist};\5
+$\\{link}(\\{tail})\K\\{link}(\\{temp\_head})$;\6
+\&{while} $\\{link}(\\{tail})\I\\{null}$ \1\&{do}\5
+$\\{tail}\K\\{link}(\\{tail})$;\2\6
+$\\{tail\_append}(\\{new\_math}(\\{math\_surround},\39\\{after}))$;\5
+\X1471:Append \\{disp\_node} at end of displace area\X;\6
+$\\{space\_factor}\K1000$;\5
+\\{unsave};\6
+\&{end}\par
+\U1206.\fi
+
+\M1209. \TeX\ gets to the following part of the program when the first `\.\$'
+ending
+a display has been scanned.
+
+\Y\P$\4\X1209:Check that another \.\$ follows\X\S$\6
+\&{begin} \37\\{get\_x\_token};\6
+\&{if} $\\{cur\_cmd}\I\\{math\_shift}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Display\ math\ should\ end\ with\ \$\$"})$;\5
+$\\{help2}(\.{"The\ \`\$\'\ that\ I\ just\ saw\ supposedly\ matches\ a\
+previous\ \`\$\$\'."})$\6
+$(\.{"So\ I\ shall\ assume\ that\ you\ typed\ \`\$\$\'\ both\ times."})$;\5
+\\{back\_error};\6
+\&{end};\2\6
+\&{end}\par
+\Us1206, 1206\ETs1218.\fi
+
+\M1210. We have saved the worst for last: The fussiest part of math mode
+processing
+occurs when a displayed formula is being centered and placed with an optional
+equation number.
+
+\Y\P$\4\X1210:Local variables for finishing a displayed formula\X\S$\6
+\4\|b: \37\\{pointer};\C{box containing the equation}\6
+\4\|w: \37\\{scaled};\C{width of the equation}\6
+\4\|z: \37\\{scaled};\C{width of the line}\6
+\4\|e: \37\\{scaled};\C{width of equation number}\6
+\4\|q: \37\\{scaled};\C{width of equation number plus space to separate from
+equation}\6
+\4\|d: \37\\{scaled};\C{displacement of equation in the line}\6
+\4\|s: \37\\{scaled};\C{move the line right this much}\6
+\4$\\{g1},\39\\{g2}$: \37\\{small\_number};\C{glue parameter codes for before
+and after}\6
+\4\|r: \37\\{pointer};\C{kern node used to position the display}\6
+\4\|t: \37\\{pointer};\C{tail of adjustment list}\par
+\U1206.\fi
+
+\M1211. At this time \|p points to the mlist for the formula; \|a is either
+\\{null} or it points to a box containing the equation number; and we are in
+vertical mode (or internal vertical mode).
+
+\Y\P$\4\X1211:Finish displayed math\X\S$\6
+$\\{cur\_mlist}\K\|p$;\5
+$\\{cur\_style}\K\\{display\_style}$;\5
+$\\{mlist\_penalties}\K\\{false}$;\5
+\\{mlist\_to\_hlist};\5
+$\|p\K\\{link}(\\{temp\_head})$;\6
+$\\{adjust\_tail}\K\\{adjust\_head}$;\5
+$\|b\K\\{hpack}(\|p,\39\\{natural})$;\5
+$\|p\K\\{list\_ptr}(\|b)$;\5
+$\|t\K\\{adjust\_tail}$;\5
+$\\{adjust\_tail}\K\\{null}$;\6
+$\|w\K\\{width}(\|b)$;\5
+$\|z\K\\{display\_width}$;\5
+$\|s\K\\{display\_indent}$;\6
+\&{if} $(\|a=\\{null})\V\\{danger}$ \1\&{then}\6
+\&{begin} \37$\|e\K0$;\5
+$\|q\K0$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|e\K\\{width}(\|a)$;\5
+$\|q\K\|e+\\{math\_quad}(\\{text\_size})$;\6
+\&{end};\2\6
+\&{if} $\|w+\|q>\|z$ \1\&{then}\5
+\X1213:Squeeze the equation as much as possible; if there is an equation number
+that should go on a separate line by itself, set~$\|e\K0$\X;\2\6
+\X1214:Determine the displacement, \|d, of the left edge of the equation, with
+respect to the line size \|z, assuming that $\|l=\\{false}$\X;\6
+\X1215:Append the glue or equation number preceding the display\X;\6
+\X1216:Append the display and perhaps also the equation number\X;\6
+\X1217:Append the glue or equation number following the display\X;\6
+\\{resume\_after\_display}\par
+\U1206.\fi
+
+\M1212. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{resume\_after\_display};\2\6
+\&{begin} \37\&{if} $\\{cur\_group}\I\\{math\_shift\_group}$ \1\&{then}\5
+$\\{confusion}(\.{"display"})$;\2\6
+\\{unsave};\5
+$\\{prev\_graf}\K\\{prev\_graf}+3$;\5
+\\{push\_nest};\5
+$\\{adjust\_dir}\K\\{abs}(\\{direction})$;\5
+$\\{mode}\K\\{hmode}$;\5
+$\\{space\_factor}\K1000$;\5
+\\{set\_cur\_lang};\5
+$\\{clang}\K\\{cur\_lang}$;\5
+$\\{prev\_graf}\K(\\{norm\_min}(\\{left\_hyphen\_min})\ast\O{100}+\\{norm%
+\_min}(\\{right\_hyphen\_min}))\ast\O{200000}+\\{cur\_lang}$;\5
+\X454:Scan an optional space\X;\6
+\&{if} $\\{nest\_ptr}=1$ \1\&{then}\5
+\\{build\_page};\2\6
+\&{end};\par
+\fi
+
+\M1213. The user can force the equation number to go on a separate line
+by causing its width to be zero.
+
+\Y\P$\4\X1213:Squeeze the equation as much as possible; if there is an equation
+number that should go on a separate line by itself, set~$\|e\K0$\X\S$\6
+\&{begin} \37\&{if} $(\|e\I0)\W((\|w-\\{total\_shrink}[\\{normal}]+\|q\L\|z)\V%
+\30(\\{total\_shrink}[\\{fil}]\I0)\V(\\{total\_shrink}[\\{fill}]\I0)\V(\\{total%
+\_shrink}[\\{filll}]\I0))$ \1\&{then}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{space\_ptr}(\|b))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|b))$;\5
+$\\{free\_node}(\|b,\39\\{box\_node\_size})$;\5
+$\|b\K\\{hpack}(\|p,\39\|z-\|q,\39\\{exactly})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|e\K0$;\6
+\&{if} $\|w>\|z$ \1\&{then}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{space\_ptr}(\|b))$;\5
+$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|b))$;\5
+$\\{free\_node}(\|b,\39\\{box\_node\_size})$;\5
+$\|b\K\\{hpack}(\|p,\39\|z,\39\\{exactly})$;\6
+\&{end};\2\6
+\&{end};\2\6
+$\|w\K\\{width}(\|b)$;\6
+\&{end}\par
+\U1211.\fi
+
+\M1214. We try first to center the display without regard to the existence of
+the equation number. If that would make it too close (where ``too close''
+means that the space between display and equation number is less than the
+width of the equation number), we either center it in the remaining space
+or move it as far from the equation number as possible. The latter alternative
+is taken only if the display begins with glue, since we assume that the
+user put glue there to control the spacing precisely.
+
+\Y\P$\4\X1214:Determine the displacement, \|d, of the left edge of the
+equation, with respect to the line size \|z, assuming that $\|l=\\{false}$\X\S$%
+\6
+$\|d\K\\{half}(\|z-\|w)$;\6
+\&{if} $(\|e>0)\W(\|d<2\ast\|e)$ \1\&{then}\C{too close}\6
+\&{begin} \37$\|d\K\\{half}(\|z-\|w-\|e)$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\6
+\&{if} $\R\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{if} $\\{type}(\|p)=\\{glue\_node}$ \1\&{then}\5
+$\|d\K0$;\2\2\2\6
+\&{end}\2\par
+\U1211.\fi
+
+\M1215. If the equation number is set on a line by itself, either before or
+after the formula, we append an infinite penalty so that no page break will
+separate the display from its number; and we use the same size and
+displacement for all three potential lines of the display, even though
+`\.{\\parshape}' may specify them differently.
+
+\Y\P$\4\X1215:Append the glue or equation number preceding the display\X\S$\6
+$\\{tail\_append}(\\{new\_penalty}(\\{pre\_display\_penalty}))$;\6
+\&{if} $(\|d+\|s\L\\{pre\_display\_size})\V\|l$ \1\&{then}\C{not enough
+clearance}\6
+\&{begin} \37$\\{g1}\K\\{above\_display\_skip\_code}$;\5
+$\\{g2}\K\\{below\_display\_skip\_code}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{g1}\K\\{above\_display\_short\_skip\_code}$;\5
+$\\{g2}\K\\{below\_display\_short\_skip\_code}$;\6
+\&{end};\2\6
+\&{if} $\|l\W(\|e=0)$ \1\&{then}\C{it follows that $\\{type}(\|a)=\\{hlist%
+\_node}$}\6
+\&{begin} \37$\\{shift\_amount}(\|a)\K\|s$;\5
+$\\{append\_to\_vlist}(\|a)$;\5
+$\\{tail\_append}(\\{new\_penalty}(\\{inf\_penalty}))$;\6
+\&{end}\6
+\4\&{else} $\\{tail\_append}(\\{new\_param\_glue}(\\{g1}))$\2\par
+\U1211.\fi
+
+\M1216. \P$\X1216:Append the display and perhaps also the equation number\X\S$\6
+\&{if} $\|e\I0$ \1\&{then}\6
+\&{begin} \37$\|r\K\\{new\_kern}(\|z-\|w-\|e-\|d)$;\6
+\&{if} $\|l$ \1\&{then}\6
+\&{begin} \37$\\{link}(\|a)\K\|r$;\5
+$\\{link}(\|r)\K\|b$;\5
+$\|b\K\|a$;\5
+$\|d\K0$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{link}(\|b)\K\|r$;\5
+$\\{link}(\|r)\K\|a$;\6
+\&{end};\2\6
+$\|b\K\\{hpack}(\|b,\39\\{natural})$;\6
+\&{end};\2\6
+$\\{shift\_amount}(\|b)\K\|s+\|d$;\5
+$\\{append\_to\_vlist}(\|b)$\par
+\U1211.\fi
+
+\M1217. \P$\X1217:Append the glue or equation number following the display\X\S$%
+\6
+\&{if} $(\|a\I\\{null})\W(\|e=0)\W\R\|l$ \1\&{then}\6
+\&{begin} \37$\\{tail\_append}(\\{new\_penalty}(\\{inf\_penalty}))$;\5
+$\\{shift\_amount}(\|a)\K\|s+\|z-\\{width}(\|a)$;\5
+$\\{append\_to\_vlist}(\|a)$;\5
+$\\{g2}\K0$;\6
+\&{end};\2\6
+\&{if} $\|t\I\\{adjust\_head}$ \1\&{then}\C{migrating material comes after
+equation number}\6
+\&{begin} \37$\\{link}(\\{tail})\K\\{link}(\\{adjust\_head})$;\5
+$\\{tail}\K\|t$;\6
+\&{end};\2\6
+$\\{tail\_append}(\\{new\_penalty}(\\{post\_display\_penalty}))$;\6
+\&{if} $\\{g2}>0$ \1\&{then}\5
+$\\{tail\_append}(\\{new\_param\_glue}(\\{g2}))$\2\par
+\U1211.\fi
+
+\M1218. When \.{\\halign} appears in a display, the alignment routines operate
+essentially as they do in vertical mode. Then the following program is
+activated, with \|p and \|q pointing to the beginning and end of the
+resulting list, and with \\{aux\_save} holding the \\{prev\_depth} value.
+
+\Y\P$\4\X1218:Finish an alignment in a display\X\S$\6
+\&{begin} \37\\{do\_assignments};\6
+\&{if} $\\{cur\_cmd}\I\\{math\_shift}$ \1\&{then}\5
+\X1219:Pontificate about improper alignment in display\X\6
+\4\&{else} \X1209:Check that another \.\$ follows\X;\2\6
+\\{pop\_nest};\5
+$\\{tail\_append}(\\{new\_penalty}(\\{pre\_display\_penalty}))$;\5
+$\\{tail\_append}(\\{new\_param\_glue}(\\{above\_display\_skip\_code}))$;\5
+$\\{link}(\\{tail})\K\|p$;\6
+\&{if} $\|p\I\\{null}$ \1\&{then}\5
+$\\{tail}\K\|q$;\2\6
+$\\{tail\_append}(\\{new\_penalty}(\\{post\_display\_penalty}))$;\5
+$\\{tail\_append}(\\{new\_param\_glue}(\\{below\_display\_skip\_code}))$;\5
+$\\{prev\_depth}\K\\{aux\_save}.\\{sc}$;\5
+\\{resume\_after\_display};\6
+\&{end}\par
+\U823.\fi
+
+\M1219. \P$\X1219:Pontificate about improper alignment in display\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ \$\$\ inserted"})$;\5
+$\\{help2}(\.{"Displays\ can\ use\ special\ alignments\ (like\ \\eqalignno)"})$%
+\6
+$(\.{"only\ if\ nothing\ but\ the\ alignment\ itself\ is\ between\ \$\$%
+\'s."})$;\5
+\\{back\_error};\6
+\&{end}\par
+\U1218.\fi
+
+\N1220.  \[49] Mode-independent processing.
+The long \\{main\_control} procedure has now been fully specified, except for
+certain activities that are independent of the current mode. These activities
+do not change the current vlist or hlist or mlist; if they change anything,
+it is the value of a parameter or the meaning of a control sequence.
+
+Assignments to values in \\{eqtb} can be global or local. Furthermore, a
+control sequence can be defined to be `\.{\\long}' or `\.{\\outer}', and
+it might or might not be expanded. The prefixes `\.{\\global}', `\.{\\long}',
+and `\.{\\outer}' can occur in any order. Therefore we assign binary numeric
+codes, making it possible to accumulate the union of all specified prefixes
+by adding the corresponding codes.  (\PASCAL's \&{set}  operations could also
+have been used.)
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"long"},\39\\{prefix},\391)$;\5
+$\\{primitive}(\.{"outer"},\39\\{prefix},\392)$;\5
+$\\{primitive}(\.{"global"},\39\\{prefix},\394)$;\5
+$\\{primitive}(\.{"def"},\39\\{def},\390)$;\5
+$\\{primitive}(\.{"gdef"},\39\\{def},\391)$;\5
+$\\{primitive}(\.{"edef"},\39\\{def},\392)$;\5
+$\\{primitive}(\.{"xdef"},\39\\{def},\393)$;\par
+\fi
+
+\M1221. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{prefix}: \37\&{if} $\\{chr\_code}=1$ \1\&{then}\5
+$\\{print\_esc}(\.{"long"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=2$ \1\&{then}\5
+$\\{print\_esc}(\.{"outer"})$\6
+\4\&{else} $\\{print\_esc}(\.{"global"})$;\2\2\6
+\4\\{def}: \37\&{if} $\\{chr\_code}=0$ \1\&{then}\5
+$\\{print\_esc}(\.{"def"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=1$ \1\&{then}\5
+$\\{print\_esc}(\.{"gdef"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=2$ \1\&{then}\5
+$\\{print\_esc}(\.{"edef"})$\6
+\4\&{else} $\\{print\_esc}(\.{"xdef"})$;\2\2\2\par
+\fi
+
+\M1222. Every prefix, and every command code that might or might not be
+prefixed,
+calls the action procedure \\{prefixed\_command}. This routine accumulates
+a sequence of prefixes until coming to a non-prefix, then it carries out
+the command.
+
+\Y\P$\4\X1222:Cases of \\{main\_control} that don't depend on \\{mode}\X\S$\6
+\4$\\{any\_mode}(\\{assign\_kinsoku}),\39\\{any\_mode}(\\{assign\_inhibit\_xsp%
+\_code}),\39\\{any\_mode}(\\{set\_auto\_spacing}),\39\\{any\_mode}(\\{set%
+\_kansuji\_char}),\39\\{any\_mode}(\\{toks\_register}),\39\\{any\_mode}(%
+\\{assign\_toks}),\39\\{any\_mode}(\\{assign\_int}),\39\\{any\_mode}(\\{def%
+\_jfont}),\39\\{any\_mode}(\\{def\_tfont}),\39\\{any\_mode}(\\{assign\_dimen}),%
+\39\\{any\_mode}(\\{assign\_glue}),\39\\{any\_mode}(\\{assign\_mu\_glue}),\39%
+\\{any\_mode}(\\{assign\_font\_dimen}),\39\\{any\_mode}(\\{assign\_font\_int}),%
+\39\\{any\_mode}(\\{set\_aux}),\39\\{any\_mode}(\\{set\_prev\_graf}),\39\\{any%
+\_mode}(\\{set\_page\_dimen}),\39\\{any\_mode}(\\{set\_page\_int}),\39\\{any%
+\_mode}(\\{set\_box\_dimen}),\39\\{any\_mode}(\\{set\_shape}),\39\\{any\_mode}(%
+\\{def\_code}),\39\\{any\_mode}(\\{def\_family}),\39\\{any\_mode}(\\{set%
+\_font}),\39\\{any\_mode}(\\{def\_font}),\39\\{any\_mode}(\\{register}),\39%
+\\{any\_mode}(\\{advance}),\39\\{any\_mode}(\\{multiply}),\39\\{any\_mode}(%
+\\{divide}),\39\\{any\_mode}(\\{prefix}),\39\\{any\_mode}(\\{let}),\39\\{any%
+\_mode}(\\{shorthand\_def}),\39\\{any\_mode}(\\{read\_to\_cs}),\39\\{any%
+\_mode}(\\{def}),\39\\{any\_mode}(\\{set\_box}),\39\\{any\_mode}(\\{hyph%
+\_data}),\39\\{any\_mode}(\\{set\_interaction})$: \37\\{prefixed\_command};\par
+\As1281, 1284, 1287, 1289, 1298, 1303\ETs1432.
+\U1057.\fi
+
+\M1223. If the user says, e.g., `\.{\\global\\global}', the redundancy is
+silently accepted.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\hbox{\4}\X1227:Declare subprocedures for \\{prefixed\_command}\X\hbox{}\6
+\4\&{procedure}\1\  \37\\{prefixed\_command};\6
+\4\&{label} \37$\\{done},\39\\{exit}$;\6
+\4\&{var} \37\|a: \37\\{small\_number};\C{accumulated prefix codes so far}\6
+\|m: \37\\{integer};\C{ditto}\6
+\|f: \37\\{internal\_font\_number};\C{identifies a font}\6
+\|j: \37\\{halfword};\C{index into a \.{\\parshape} specification}\6
+\|k: \37\\{font\_index};\C{index into \\{font\_info}}\6
+$\|p,\39\|q$: \37\\{pointer};\C{for temporary short-term use}\6
+\|n: \37\\{integer};\C{ditto}\6
+\|e: \37\\{boolean};\C{should a definition be expanded? or was \.{\\let} not
+done?}\2\6
+\&{begin} \37$\|a\K0$;\6
+\&{while} $\\{cur\_cmd}=\\{prefix}$ \1\&{do}\6
+\&{begin} \37\&{if} $\R\\{odd}(\|a\mathbin{\&{div}}\\{cur\_chr})$ \1\&{then}\5
+$\|a\K\|a+\\{cur\_chr}$;\2\6
+\X415:Get the next non-blank non-relax non-call token\X;\6
+\&{if} $\\{cur\_cmd}\L\\{max\_non\_prefixed\_command}$ \1\&{then}\5
+\X1224:Discard erroneous prefixes and \&{return}\X;\2\6
+\&{end};\2\6
+\X1225:Discard the prefixes \.{\\long} and \.{\\outer} if they are irrelevant%
+\X;\6
+\X1226:Adjust \(f)for the setting of \.{\\globaldefs}\X;\6
+\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\hbox{\4}\X1229:Assignments\X\6
+\4\&{othercases} \37$\\{confusion}(\.{"prefix"})$\2\6
+\&{endcases};\6
+\4\\{done}: \37\X1282:Insert a token saved by \.{\\afterassignment}, if any\X;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1224. \P$\X1224:Discard erroneous prefixes and \&{return}\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"You\ can\'t\ use\ a\ prefix\ with\ \`"})$;\5
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\5
+$\\{print\_char}(\.{"\'"})$;\5
+$\\{help1}(\.{"I\'ll\ pretend\ you\ didn\'t\ say\ \\long\ or\ \\outer\ or\ %
+\\global."})$;\5
+\\{back\_error};\5
+\&{return};\6
+\&{end}\par
+\U1223.\fi
+
+\M1225. \P$\X1225:Discard the prefixes \.{\\long} and \.{\\outer} if they are
+irrelevant\X\S$\6
+\&{if} $(\\{cur\_cmd}\I\\{def})\W(\|a\mathbin{\&{mod}}4\I0)$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"You\ can\'t\ use\ \`"})$;\5
+$\\{print\_esc}(\.{"long"})$;\5
+$\\{print}(\.{"\'\ or\ \`"})$;\5
+$\\{print\_esc}(\.{"outer"})$;\5
+$\\{print}(\.{"\'\ with\ \`"})$;\5
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\5
+$\\{print\_char}(\.{"\'"})$;\5
+$\\{help1}(\.{"I\'ll\ pretend\ you\ didn\'t\ say\ \\long\ or\ \\outer\
+here."})$;\5
+\\{error};\6
+\&{end}\2\par
+\U1223.\fi
+
+\M1226. The previous routine does not have to adjust \|a so that $\|a\mathbin{%
+\&{mod}}4=0$,
+since the following routines test for the \.{\\global} prefix as follows.
+
+\Y\P\D \37$\\{global}\S(\|a\G4)$\par
+\P\D \37$\\{define}(\#)\S$\1\6
+\&{if} $\\{global}$ \1\&{then}\5
+$\\{geq\_define}(\#)$\ \&{else} $\\{eq\_define}(\#)$\2\2\par
+\P\D \37$\\{word\_define}(\#)\S$\1\6
+\&{if} $\\{global}$ \1\&{then}\5
+$\\{geq\_word\_define}(\#)$\ \&{else} $\\{eq\_word\_define}(\#)$\2\2\par
+\Y\P$\4\X1226:Adjust \(f)for the setting of \.{\\globaldefs}\X\S$\6
+\&{if} $\\{global\_defs}\I0$ \1\&{then}\6
+\&{if} $\\{global\_defs}<0$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{global}$ \1\&{then}\5
+$\|a\K\|a-4$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\R\\{global}$ \1\&{then}\5
+$\|a\K\|a+4$;\2\6
+\&{end}\2\2\par
+\U1223.\fi
+
+\M1227. When a control sequence is to be defined, by \.{\\def} or \.{\\let} or
+something similar, the \\{get\_r\_token} routine will substitute a special
+control sequence for a token that is not redefinable.
+
+\Y\P$\4\X1227:Declare subprocedures for \\{prefixed\_command}\X\S$\6
+\4\&{procedure}\1\  \37\\{get\_r\_token};\6
+\4\&{label} \37\\{restart};\2\6
+\&{begin} \37\\{restart}: \37\1\&{repeat} \37\\{get\_token};\6
+\4\&{until}\5
+$\\{cur\_tok}\I\\{space\_token}$;\2\6
+\&{if} $(\\{cur\_cs}=0)\V(\\{cur\_cs}>\\{eqtb\_top})\V((\\{cur\_cs}>\\{frozen%
+\_control\_sequence})\W(\\{cur\_cs}\L\\{eqtb\_size}))$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ control\ sequence\ inserted"})$;\5
+$\\{help5}(\.{"Please\ don\'t\ say\ \`\\def\ cs\{...\}\',\ say\ \`\\def\\cs%
+\{...\}\'."})$\6
+$(\.{"I\'ve\ inserted\ an\ inaccessible\ control\ sequence\ so\ that\ your"})$\6
+$(\.{"definition\ will\ be\ completed\ without\ mixing\ me\ up\ too\ badly."})$%
+\6
+$(\.{"You\ can\ recover\ graciously\ from\ this\ error,\ if\ you\'re"})$\6
+$(\.{"careful;\ see\ exercise\ 27.2\ in\ The\ TeXbook."})$;\6
+\&{if} $\\{cur\_cs}=0$ \1\&{then}\5
+\\{back\_input};\2\6
+$\\{cur\_tok}\K\\{cs\_token\_flag}+\\{frozen\_protection}$;\5
+\\{ins\_error};\5
+\&{goto} \37\\{restart};\6
+\&{end};\2\6
+\&{end};\par
+\As1241, 1249, 1256, 1257, 1258, 1259, 1260, 1270\ETs1278.
+\U1223.\fi
+
+\M1228. \P$\X170:Initialize table entries (done by \.{INITEX} only)\X%
+\mathrel{+}\S$\6
+$\\{text}(\\{frozen\_protection})\K\.{"inaccessible"}$;\par
+\fi
+
+\M1229. Here's an example of the way many of the following routines operate.
+(Unfortunately, they aren't all as simple as this.)
+
+\Y\P$\4\X1229:Assignments\X\S$\6
+\4\\{set\_font}: \37\&{begin} \37\&{if} $\\{font\_dir}[\\{cur\_chr}]=\\{dir%
+\_yoko}$ \1\&{then}\5
+$\\{define}(\\{cur\_jfont\_loc},\39\\{data},\39\\{cur\_chr})$\6
+\4\&{else} \&{if} $\\{font\_dir}[\\{cur\_chr}]=\\{dir\_tate}$ \1\&{then}\5
+$\\{define}(\\{cur\_tfont\_loc},\39\\{data},\39\\{cur\_chr})$\6
+\4\&{else} $\\{define}(\\{cur\_font\_loc},\39\\{data},\39\\{cur\_chr})$\2\2\6
+\&{end};\par
+\As1230, 1233, 1236, 1237, 1238, 1240, 1244, 1247, 1248, 1254, 1255, 1261,
+1265, 1266, 1269, 1277, 1423, 1428, 1436\ETs1441.
+\U1223.\fi
+
+\M1230. When a \\{def} command has been scanned,
+\\{cur\_chr} is odd if the definition is supposed to be global, and
+$\\{cur\_chr}\G2$ if the definition is supposed to be expanded.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{def}: \37\&{begin} \37\&{if} $\\{odd}(\\{cur\_chr})\W\R\\{global}\W(%
+\\{global\_defs}\G0)$ \1\&{then}\5
+$\|a\K\|a+4$;\2\6
+$\|e\K(\\{cur\_chr}\G2)$;\5
+\\{get\_r\_token};\5
+$\|p\K\\{cur\_cs}$;\5
+$\|q\K\\{scan\_toks}(\\{true},\39\|e)$;\5
+$\\{define}(\|p,\39\\{call}+(\|a\mathbin{\&{mod}}4),\39\\{def\_ref})$;\6
+\&{end};\par
+\fi
+
+\M1231. Both \.{\\let} and \.{\\futurelet} share the command code \\{let}.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"let"},\39\\{let},\39\\{normal})$;\6
+$\\{primitive}(\.{"futurelet"},\39\\{let},\39\\{normal}+1)$;\par
+\fi
+
+\M1232. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{let}: \37\&{if} $\\{chr\_code}\I\\{normal}$ \1\&{then}\5
+$\\{print\_esc}(\.{"futurelet"})$\ \&{else} $\\{print\_esc}(\.{"let"})$;\2\par
+\fi
+
+\M1233. \P$\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{let}: \37\&{begin} \37$\|n\K\\{cur\_chr}$;\5
+\\{get\_r\_token};\5
+$\|p\K\\{cur\_cs}$;\6
+\&{if} $\|n=\\{normal}$ \1\&{then}\6
+\&{begin} \37\1\&{repeat} \37\\{get\_token};\6
+\4\&{until}\5
+$\\{cur\_cmd}\I\\{spacer}$;\2\6
+\&{if} $\\{cur\_tok}=\\{other\_token}+\.{"="}$ \1\&{then}\6
+\&{begin} \37\\{get\_token};\6
+\&{if} $\\{cur\_cmd}=\\{spacer}$ \1\&{then}\5
+\\{get\_token};\2\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\\{get\_token};\5
+$\|q\K\\{cur\_tok}$;\5
+\\{get\_token};\5
+\\{back\_input};\5
+$\\{cur\_tok}\K\|q$;\5
+\\{back\_input};\C{look ahead, then back up}\6
+\&{end};\C{note that \\{back\_input} doesn't affect \\{cur\_cmd}, \\{cur\_chr}}%
+\2\6
+\&{if} $\\{cur\_cmd}\G\\{call}$ \1\&{then}\5
+$\\{add\_token\_ref}(\\{cur\_chr})$;\2\6
+$\\{define}(\|p,\39\\{cur\_cmd},\39\\{cur\_chr})$;\6
+\&{end};\par
+\fi
+
+\M1234. A \.{\\chardef} creates a control sequence whose \\{cmd} is \\{char%
+\_given};
+a \.{\\mathchardef} creates a control sequence whose \\{cmd} is \\{math%
+\_given};
+and the corresponding \\{chr} is the character code or math code. A \.{%
+\\countdef}
+or \.{\\dimendef} or \.{\\skipdef} or \.{\\muskipdef} creates a control
+sequence whose \\{cmd} is \\{assign\_int} or \dots\ or \\{assign\_mu\_glue},
+and the
+corresponding \\{chr} is the \\{eqtb} location of the internal register in
+question.
+
+\Y\P\D \37$\\{char\_def\_code}=0$\C{\\{shorthand\_def} for \.{\\chardef}}\par
+\P\D \37$\\{math\_char\_def\_code}=1$\C{\\{shorthand\_def} for \.{%
+\\mathchardef}}\par
+\P\D \37$\\{count\_def\_code}=2$\C{\\{shorthand\_def} for \.{\\countdef}}\par
+\P\D \37$\\{dimen\_def\_code}=3$\C{\\{shorthand\_def} for \.{\\dimendef}}\par
+\P\D \37$\\{skip\_def\_code}=4$\C{\\{shorthand\_def} for \.{\\skipdef}}\par
+\P\D \37$\\{mu\_skip\_def\_code}=5$\C{\\{shorthand\_def} for \.{\\muskipdef}}%
+\par
+\P\D \37$\\{toks\_def\_code}=6$\C{\\{shorthand\_def} for \.{\\toksdef}}\par
+\P\D \37$\\{char\_sub\_def\_code}=7$\C{\\{shorthand\_def} for \.{\\charsubdef}}%
+\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"chardef"},\39\\{shorthand\_def},\39\\{char\_def\_code})$;\6
+$\\{primitive}(\.{"mathchardef"},\39\\{shorthand\_def},\39\\{math\_char\_def%
+\_code})$;\6
+$\\{primitive}(\.{"countdef"},\39\\{shorthand\_def},\39\\{count\_def\_code})$;\6
+$\\{primitive}(\.{"dimendef"},\39\\{shorthand\_def},\39\\{dimen\_def\_code})$;\6
+$\\{primitive}(\.{"skipdef"},\39\\{shorthand\_def},\39\\{skip\_def\_code})$;\6
+$\\{primitive}(\.{"muskipdef"},\39\\{shorthand\_def},\39\\{mu\_skip\_def%
+\_code})$;\6
+$\\{primitive}(\.{"toksdef"},\39\\{shorthand\_def},\39\\{toks\_def\_code})$;\6
+\&{if} $\\{mltex\_p}$ \1\&{then}\6
+\&{begin} \37$\\{primitive}(\.{"charsubdef"},\39\\{shorthand\_def},\39\\{char%
+\_sub\_def\_code})$;\6
+\&{end};\2\par
+\fi
+
+\M1235. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{shorthand\_def}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{char\_def\_code}: \37$\\{print\_esc}(\.{"chardef"})$;\6
+\4\\{math\_char\_def\_code}: \37$\\{print\_esc}(\.{"mathchardef"})$;\6
+\4\\{count\_def\_code}: \37$\\{print\_esc}(\.{"countdef"})$;\6
+\4\\{dimen\_def\_code}: \37$\\{print\_esc}(\.{"dimendef"})$;\6
+\4\\{skip\_def\_code}: \37$\\{print\_esc}(\.{"skipdef"})$;\6
+\4\\{mu\_skip\_def\_code}: \37$\\{print\_esc}(\.{"muskipdef"})$;\6
+\4\\{char\_sub\_def\_code}: \37$\\{print\_esc}(\.{"charsubdef"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"toksdef"})$\2\6
+\&{endcases};\6
+\4\\{char\_given}: \37\&{begin} \37$\\{print\_esc}(\.{"char"})$;\5
+$\\{print\_hex}(\\{chr\_code})$;\6
+\&{end};\6
+\4\\{math\_given}: \37\&{begin} \37$\\{print\_esc}(\.{"mathchar"})$;\5
+$\\{print\_hex}(\\{chr\_code})$;\6
+\&{end};\par
+\fi
+
+\M1236. We temporarily define \|p to be \\{relax}, so that an occurrence of \|p
+while scanning the definition will simply stop the scanning instead of
+producing an ``undefined control sequence'' error or expanding the
+previous meaning.  This allows, for instance, `\.{\\chardef\\foo=123\\foo}'.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{shorthand\_def}: \37\&{if} $\\{cur\_chr}=\\{char\_sub\_def\_code}$ \1%
+\&{then}\6
+\&{begin} \37\\{scan\_char\_num};\5
+$\|p\K\\{char\_sub\_code\_base}+\\{cur\_val}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_char\_num};\5
+$\|n\K\\{cur\_val}$;\C{accent character in substitution}\6
+\\{scan\_char\_num};\6
+\&{if} $(\\{tracing\_char\_sub\_def}>0)$ \1\&{then}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"New\ character\ substitution:\ "})$;\5
+$\\{print\_ASCII}(\|p-\\{char\_sub\_code\_base})$;\5
+$\\{print}(\.{"\ =\ "})$;\5
+$\\{print\_ASCII}(\|n)$;\5
+$\\{print\_char}(\.{"\ "})$;\5
+$\\{print\_ASCII}(\\{cur\_val})$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end};\2\6
+$\|n\K\|n\ast256+\\{cur\_val}$;\5
+$\\{define}(\|p,\39\\{data},\39\\{hi}(\|n))$;\6
+\&{if} $(\|p-\\{char\_sub\_code\_base})<\\{char\_sub\_def\_min}$ \1\&{then}\5
+$\\{word\_define}(\\{int\_base}+\\{char\_sub\_def\_min\_code},\39\|p-\\{char%
+\_sub\_code\_base})$;\2\6
+\&{if} $(\|p-\\{char\_sub\_code\_base})>\\{char\_sub\_def\_max}$ \1\&{then}\5
+$\\{word\_define}(\\{int\_base}+\\{char\_sub\_def\_max\_code},\39\|p-\\{char%
+\_sub\_code\_base})$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|n\K\\{cur\_chr}$;\5
+\\{get\_r\_token};\5
+$\|p\K\\{cur\_cs}$;\5
+$\\{define}(\|p,\39\\{relax},\39256)$;\5
+\\{scan\_optional\_equals};\6
+\&{case} $\|n$ \1\&{of}\6
+\4\\{char\_def\_code}: \37\&{begin} \37\\{scan\_char\_num};\5
+$\\{define}(\|p,\39\\{char\_given},\39\\{cur\_val})$;\6
+\&{end};\6
+\4\\{math\_char\_def\_code}: \37\&{begin} \37\\{scan\_fifteen\_bit\_int};\5
+$\\{define}(\|p,\39\\{math\_given},\39\\{cur\_val})$;\6
+\&{end};\6
+\4\&{othercases} \37\&{begin} \37\\{scan\_eight\_bit\_int};\6
+\&{case} $\|n$ \1\&{of}\6
+\4\\{count\_def\_code}: \37$\\{define}(\|p,\39\\{assign\_int},\39\\{count%
+\_base}+\\{cur\_val})$;\6
+\4\\{dimen\_def\_code}: \37$\\{define}(\|p,\39\\{assign\_dimen},\39\\{scaled%
+\_base}+\\{cur\_val})$;\6
+\4\\{skip\_def\_code}: \37$\\{define}(\|p,\39\\{assign\_glue},\39\\{skip%
+\_base}+\\{cur\_val})$;\6
+\4\\{mu\_skip\_def\_code}: \37$\\{define}(\|p,\39\\{assign\_mu\_glue},\39\\{mu%
+\_skip\_base}+\\{cur\_val})$;\6
+\4\\{toks\_def\_code}: \37$\\{define}(\|p,\39\\{assign\_toks},\39\\{toks%
+\_base}+\\{cur\_val})$;\2\6
+\&{end};\C{there are no other cases}\6
+\&{end}\2\6
+\&{endcases};\6
+\&{end};\2\par
+\fi
+
+\M1237. \P$\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{read\_to\_cs}: \37\&{begin} \37\\{scan\_int};\5
+$\|n\K\\{cur\_val}$;\6
+\&{if} $\R\\{scan\_keyword}(\.{"to"})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Missing\ \`to\'\ inserted"})$;\5
+$\\{help2}(\.{"You\ should\ have\ said\ \`\\read<number>\ to\ \\cs\'."})$\6
+$(\.{"I\'m\ going\ to\ look\ for\ the\ \\cs\ now."})$;\5
+\\{error};\6
+\&{end};\2\6
+\\{get\_r\_token};\5
+$\|p\K\\{cur\_cs}$;\5
+$\\{read\_toks}(\|n,\39\|p)$;\5
+$\\{define}(\|p,\39\\{call},\39\\{cur\_val})$;\6
+\&{end};\par
+\fi
+
+\M1238. The token-list parameters, \.{\\output} and \.{\\everypar}, etc.,
+receive
+their values in the following way. (For safety's sake, we place an
+enclosing pair of braces around an \.{\\output} list.)
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4$\\{toks\_register},\39\\{assign\_toks}$: \37\&{begin} \37$\|q\K\\{cur\_cs}$;%
+\6
+\&{if} $\\{cur\_cmd}=\\{toks\_register}$ \1\&{then}\6
+\&{begin} \37\\{scan\_eight\_bit\_int};\5
+$\|p\K\\{toks\_base}+\\{cur\_val}$;\6
+\&{end}\6
+\4\&{else} $\|p\K\\{cur\_chr}$;\C{$\|p=\\{every\_par\_loc}$ or \\{output%
+\_routine\_loc} or \dots}\2\6
+\\{scan\_optional\_equals};\5
+\X415:Get the next non-blank non-relax non-call token\X;\6
+\&{if} $\\{cur\_cmd}\I\\{left\_brace}$ \1\&{then}\5
+\X1239:If the right-hand side is a token parameter or token register, finish
+the assignment and \&{goto} \\{done}\X;\2\6
+\\{back\_input};\5
+$\\{cur\_cs}\K\|q$;\5
+$\|q\K\\{scan\_toks}(\\{false},\39\\{false})$;\6
+\&{if} $\\{link}(\\{def\_ref})=\\{null}$ \1\&{then}\C{empty list: revert to the
+default}\6
+\&{begin} \37$\\{define}(\|p,\39\\{undefined\_cs},\39\\{null})$;\5
+$\\{free\_avail}(\\{def\_ref})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\|p=\\{output\_routine\_loc}$ \1\&{then}%
+\C{enclose in curlies}\6
+\&{begin} \37$\\{link}(\|q)\K\\{get\_avail}$;\5
+$\|q\K\\{link}(\|q)$;\5
+$\\{info}(\|q)\K\\{right\_brace\_token}+\.{"\}"}$;\5
+$\|q\K\\{get\_avail}$;\5
+$\\{info}(\|q)\K\\{left\_brace\_token}+\.{"\{"}$;\5
+$\\{link}(\|q)\K\\{link}(\\{def\_ref})$;\5
+$\\{link}(\\{def\_ref})\K\|q$;\6
+\&{end};\2\6
+$\\{define}(\|p,\39\\{call},\39\\{def\_ref})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1239. \P$\X1239:If the right-hand side is a token parameter or token
+register, finish the assignment and \&{goto} \\{done}\X\S$\6
+\&{begin} \37\&{if} $\\{cur\_cmd}=\\{toks\_register}$ \1\&{then}\6
+\&{begin} \37\\{scan\_eight\_bit\_int};\5
+$\\{cur\_cmd}\K\\{assign\_toks}$;\5
+$\\{cur\_chr}\K\\{toks\_base}+\\{cur\_val}$;\6
+\&{end};\2\6
+\&{if} $\\{cur\_cmd}=\\{assign\_toks}$ \1\&{then}\6
+\&{begin} \37$\|q\K\\{equiv}(\\{cur\_chr})$;\6
+\&{if} $\|q=\\{null}$ \1\&{then}\5
+$\\{define}(\|p,\39\\{undefined\_cs},\39\\{null})$\6
+\4\&{else} \&{begin} \37$\\{add\_token\_ref}(\|q)$;\5
+$\\{define}(\|p,\39\\{call},\39\|q)$;\6
+\&{end};\2\6
+\&{goto} \37\\{done};\6
+\&{end};\2\6
+\&{end}\par
+\U1238.\fi
+
+\M1240. Similar routines are used to assign values to the numeric parameters.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{assign\_int}: \37\&{begin} \37$\|p\K\\{cur\_chr}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_int};\6
+\&{if} $\|p=\\{int\_base}+\\{cur\_fam\_code}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{font\_dir}[\\{fam\_fnt}(\\{cur\_val})]\I\\{dir%
+\_default}$ \1\&{then}\5
+$\\{word\_define}(\\{int\_base}+\\{cur\_jfam\_code},\39\\{cur\_val})$\6
+\4\&{else} $\\{word\_define}(\|p,\39\\{cur\_val})$;\2\6
+\&{end}\6
+\4\&{else} $\\{word\_define}(\|p,\39\\{cur\_val})$;\2\6
+\&{end};\6
+\4\\{assign\_dimen}: \37\&{begin} \37$\|p\K\\{cur\_chr}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_normal\_dimen};\5
+$\\{word\_define}(\|p,\39\\{cur\_val})$;\6
+\&{end};\6
+\4$\\{assign\_glue},\39\\{assign\_mu\_glue}$: \37\&{begin} \37$\|p\K\\{cur%
+\_chr}$;\5
+$\|n\K\\{cur\_cmd}$;\5
+\\{scan\_optional\_equals};\6
+\&{if} $\|n=\\{assign\_mu\_glue}$ \1\&{then}\5
+$\\{scan\_glue}(\\{mu\_val})$\ \&{else} $\\{scan\_glue}(\\{glue\_val})$;\2\6
+\\{trap\_zero\_glue};\5
+$\\{define}(\|p,\39\\{glue\_ref},\39\\{cur\_val})$;\6
+\&{end};\par
+\fi
+
+\M1241. When a glue register or parameter becomes zero, it will always point to
+\\{zero\_glue} because of the following procedure. (Exception: The tabskip
+glue isn't trapped while preambles are being scanned.)
+
+\Y\P$\4\X1227:Declare subprocedures for \\{prefixed\_command}\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{trap\_zero\_glue};\2\6
+\&{begin} \37\&{if} $(\\{width}(\\{cur\_val})=0)\W(\\{stretch}(\\{cur\_val})=0)%
+\W(\\{shrink}(\\{cur\_val})=0)$ \1\&{then}\6
+\&{begin} \37$\\{add\_glue\_ref}(\\{zero\_glue})$;\5
+$\\{delete\_glue\_ref}(\\{cur\_val})$;\5
+$\\{cur\_val}\K\\{zero\_glue}$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1242. The various character code tables are changed by the \\{def\_code}
+commands,
+and the font families are declared by \\{def\_family}.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"catcode"},\39\\{def\_code},\39\\{cat\_code\_base})$;\5
+$\\{primitive}(\.{"kcatcode"},\39\\{def\_code},\39\\{kcat\_code\_base})$;\5
+$\\{primitive}(\.{"xspcode"},\39\\{def\_code},\39\\{auto\_xsp\_code\_base})$;\5
+$\\{primitive}(\.{"mathcode"},\39\\{def\_code},\39\\{math\_code\_base})$;\5
+$\\{primitive}(\.{"lccode"},\39\\{def\_code},\39\\{lc\_code\_base})$;\5
+$\\{primitive}(\.{"uccode"},\39\\{def\_code},\39\\{uc\_code\_base})$;\5
+$\\{primitive}(\.{"sfcode"},\39\\{def\_code},\39\\{sf\_code\_base})$;\5
+$\\{primitive}(\.{"delcode"},\39\\{def\_code},\39\\{del\_code\_base})$;\5
+$\\{primitive}(\.{"textfont"},\39\\{def\_family},\39\\{math\_font\_base})$;\5
+$\\{primitive}(\.{"scriptfont"},\39\\{def\_family},\39\\{math\_font\_base}+%
+\\{script\_size})$;\5
+$\\{primitive}(\.{"scriptscriptfont"},\39\\{def\_family},\39\\{math\_font%
+\_base}+\\{script\_script\_size})$;\par
+\fi
+
+\M1243. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{def\_code}: \37\&{if} $\\{chr\_code}=\\{cat\_code\_base}$ \1\&{then}\5
+$\\{print\_esc}(\.{"catcode"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{kcat\_code\_base}$ \1\&{then}\5
+$\\{print\_esc}(\.{"kcatcode"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{auto\_xsp\_code\_base}$ \1\&{then}\5
+$\\{print\_esc}(\.{"xspcode"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{math\_code\_base}$ \1\&{then}\5
+$\\{print\_esc}(\.{"mathcode"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{lc\_code\_base}$ \1\&{then}\5
+$\\{print\_esc}(\.{"lccode"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{uc\_code\_base}$ \1\&{then}\5
+$\\{print\_esc}(\.{"uccode"})$\6
+\4\&{else} \&{if} $\\{chr\_code}=\\{sf\_code\_base}$ \1\&{then}\5
+$\\{print\_esc}(\.{"sfcode"})$\6
+\4\&{else} $\\{print\_esc}(\.{"delcode"})$;\2\2\2\2\2\2\2\6
+\4\\{def\_family}: \37$\\{print\_size}(\\{chr\_code}-\\{math\_font\_base})$;\par
+\fi
+
+\M1244. The different types of code values have different legal ranges; the
+following program is careful to check each case properly.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{def\_code}: \37\&{begin} \37\X1245:Let \|m be the minimal legal code
+value, based on \\{cur\_chr}\X;\6
+\X1246:Let \|n be the largest legal code value, based on \\{cur\_chr}\X;\6
+$\|p\K\\{cur\_chr}$;\5
+\\{scan\_char\_num};\6
+\&{if} $\|p=\\{kcat\_code\_base}$ \1\&{then}\5
+$\|p\K\|p+\\{kcatcodekey}(\\{cur\_val})$\6
+\4\&{else} \&{if} $\R\\{is\_char\_ascii}(\\{cur\_val})$ \1\&{then}\5
+$\|p\K\|p+\\{Hi}(\\{cur\_val})$\C{ If \\{cur\_val} is a KANJI code, we use its
+upper half, as the case of retrieving. }\6
+\4\&{else} $\|p\K\|p+\\{cur\_val}$;\2\2\6
+\\{scan\_optional\_equals};\5
+\\{scan\_int};\6
+\&{if} $((\\{cur\_val}<\|m)\W(\|p<\\{del\_code\_base}))\V(\\{cur\_val}>\|n)$ \1%
+\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Invalid\ code\ ("})$;\5
+$\\{print\_int}(\\{cur\_val})$;\6
+\&{if} $\|p<\\{del\_code\_base}$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"),\ should\ be\ in\ the\ range\ "})$;\5
+$\\{print\_int}(\|m)$;\5
+$\\{print}(\.{".."})$;\6
+\&{end}\6
+\4\&{else} $\\{print}(\.{"),\ should\ be\ at\ most\ "})$;\2\6
+$\\{print\_int}(\|n)$;\6
+\&{if} $\|m=0$ \1\&{then}\6
+\&{begin} \37$\\{help1}(\.{"I\'m\ going\ to\ use\ 0\ instead\ of\ that\ illegal%
+\ code\ value."})$;\6
+\\{error};\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{help1}(\.{"I\'m\ going\ to\ use\ 16\ instead\ of\
+that\ illegal\ code\ value."})$;\6
+\\{error};\6
+\&{end};\2\6
+$\\{cur\_val}\K\|m$;\6
+\&{end};\2\6
+\&{if} $\|p<\\{math\_code\_base}$ \1\&{then}\5
+$\\{define}(\|p,\39\\{data},\39\\{cur\_val})$\6
+\4\&{else} \&{if} $\|p<\\{del\_code\_base}$ \1\&{then}\5
+$\\{define}(\|p,\39\\{data},\39\\{hi}(\\{cur\_val}))$\6
+\4\&{else} $\\{word\_define}(\|p,\39\\{cur\_val})$;\2\2\6
+\&{end};\par
+\fi
+
+\M1245. \P$\X1245:Let \|m be the minimal legal code value, based on \\{cur%
+\_chr}\X\S$\6
+\&{if} $\\{cur\_chr}=\\{kcat\_code\_base}$ \1\&{then}\5
+$\|m\K\\{kanji}$\6
+\4\&{else} $\|m\K0$\2\par
+\U1244.\fi
+
+\M1246. \P$\X1246:Let \|n be the largest legal code value, based on \\{cur%
+\_chr}\X\S$\6
+\&{if} $\\{cur\_chr}=\\{cat\_code\_base}$ \1\&{then}\5
+$\|n\K\\{invalid\_char}$\C{1byte \\{max\_char\_code}}\6
+\4\&{else} \&{if} $\\{cur\_chr}=\\{kcat\_code\_base}$ \1\&{then}\5
+$\|n\K\\{max\_char\_code}$\6
+\4\&{else} \&{if} $\\{cur\_chr}=\\{math\_code\_base}$ \1\&{then}\5
+$\|n\K\O{100000}$\6
+\4\&{else} \&{if} $\\{cur\_chr}=\\{sf\_code\_base}$ \1\&{then}\5
+$\|n\K\O{77777}$\6
+\4\&{else} \&{if} $\\{cur\_chr}=\\{del\_code\_base}$ \1\&{then}\5
+$\|n\K\O{77777777}$\6
+\4\&{else} $\|n\K255$\2\2\2\2\2\par
+\U1244.\fi
+
+\M1247. \P$\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{def\_family}: \37\&{begin} \37$\|p\K\\{cur\_chr}$;\5
+\\{scan\_four\_bit\_int};\5
+$\|p\K\|p+\\{cur\_val}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_font\_ident};\5
+$\\{define}(\|p,\39\\{data},\39\\{cur\_val})$;\6
+\&{end};\par
+\fi
+
+\M1248. Next we consider changes to \TeX's numeric registers.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4$\\{register},\39\\{advance},\39\\{multiply},\39\\{divide}$: \37$\\{do%
+\_register\_command}(\|a)$;\par
+\fi
+
+\M1249. We use the fact that $\\{register}<\\{advance}<\\{multiply}<%
+\\{divide}$.
+
+\Y\P$\4\X1227:Declare subprocedures for \\{prefixed\_command}\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{do\_register\_command}(\|a:\\{small\_number})$;\6
+\4\&{label} \37$\\{found},\39\\{exit}$;\6
+\4\&{var} \37$\|l,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{for list
+manipulation}\6
+\|p: \37$\\{int\_val}\to\\{mu\_val}$;\C{type of register involved}\2\6
+\&{begin} \37$\|q\K\\{cur\_cmd}$;\5
+\X1250:Compute the register location \|l and its type \|p; but \&{return} if
+invalid\X;\6
+\&{if} $\|q=\\{register}$ \1\&{then}\5
+\\{scan\_optional\_equals}\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"by"})$ \1\&{then}\5
+\\{do\_nothing};\C{optional `\.{by}'}\2\2\6
+$\\{arith\_error}\K\\{false}$;\6
+\&{if} $\|q<\\{multiply}$ \1\&{then}\5
+\X1251:Compute result of \\{register} or \\{advance}, put it in \\{cur\_val}\X\6
+\4\&{else} \X1253:Compute result of \\{multiply} or \\{divide}, put it in %
+\\{cur\_val}\X;\2\6
+\&{if} $\\{arith\_error}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Arithmetic\ overflow"})$;\5
+$\\{help2}(\.{"I\ can\'t\ carry\ out\ that\ multiplication\ or\ division,"})$\6
+$(\.{"since\ the\ result\ is\ out\ of\ range."})$;\6
+\&{if} $\|p\G\\{glue\_val}$ \1\&{then}\5
+$\\{delete\_glue\_ref}(\\{cur\_val})$;\2\6
+\\{error};\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $\|p<\\{glue\_val}$ \1\&{then}\5
+$\\{word\_define}(\|l,\39\\{cur\_val})$\6
+\4\&{else} \&{begin} \37\\{trap\_zero\_glue};\5
+$\\{define}(\|l,\39\\{glue\_ref},\39\\{cur\_val})$;\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1250. Here we use the fact that the consecutive codes $\\{int\_val}\to\\{mu%
+\_val}$ and
+$\\{assign\_int}\to\\{assign\_mu\_glue}$ correspond to each other nicely.
+
+\Y\P$\4\X1250:Compute the register location \|l and its type \|p; but %
+\&{return} if invalid\X\S$\6
+\&{begin} \37\&{if} $\|q\I\\{register}$ \1\&{then}\6
+\&{begin} \37\\{get\_x\_token};\6
+\&{if} $(\\{cur\_cmd}\G\\{assign\_int})\W(\\{cur\_cmd}\L\\{assign\_mu\_glue})$ %
+\1\&{then}\6
+\&{begin} \37$\|l\K\\{cur\_chr}$;\5
+$\|p\K\\{cur\_cmd}-\\{assign\_int}$;\5
+\&{goto} \37\\{found};\6
+\&{end};\2\6
+\&{if} $\\{cur\_cmd}\I\\{register}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"You\ can\'t\ use\ \`"})$;\5
+$\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr})$;\5
+$\\{print}(\.{"\'\ after\ "})$;\5
+$\\{print\_cmd\_chr}(\|q,\390)$;\5
+$\\{help1}(\.{"I\'m\ forgetting\ what\ you\ said\ and\ not\ changing\
+anything."})$;\5
+\\{error};\5
+\&{return};\6
+\&{end};\2\6
+\&{end};\2\6
+$\|p\K\\{cur\_chr}$;\5
+\\{scan\_eight\_bit\_int};\6
+\&{case} $\|p$ \1\&{of}\6
+\4\\{int\_val}: \37$\|l\K\\{cur\_val}+\\{count\_base}$;\6
+\4\\{dimen\_val}: \37$\|l\K\\{cur\_val}+\\{scaled\_base}$;\6
+\4\\{glue\_val}: \37$\|l\K\\{cur\_val}+\\{skip\_base}$;\6
+\4\\{mu\_val}: \37$\|l\K\\{cur\_val}+\\{mu\_skip\_base}$;\2\6
+\&{end};\C{there are no other cases}\6
+\&{end};\6
+\4\\{found}: \37\par
+\U1249.\fi
+
+\M1251. \P$\X1251:Compute result of \\{register} or \\{advance}, put it in %
+\\{cur\_val}\X\S$\6
+\&{if} $\|p<\\{glue\_val}$ \1\&{then}\6
+\&{begin} \37\&{if} $\|p=\\{int\_val}$ \1\&{then}\5
+\\{scan\_int}\ \&{else} \\{scan\_normal\_dimen};\2\6
+\&{if} $\|q=\\{advance}$ \1\&{then}\5
+$\\{cur\_val}\K\\{cur\_val}+\\{eqtb}[\|l].\\{int}$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{scan\_glue}(\|p)$;\6
+\&{if} $\|q=\\{advance}$ \1\&{then}\5
+\X1252:Compute the sum of two glue specs\X;\2\6
+\&{end}\2\par
+\U1249.\fi
+
+\M1252. \P$\X1252:Compute the sum of two glue specs\X\S$\6
+\&{begin} \37$\|q\K\\{new\_spec}(\\{cur\_val})$;\5
+$\|r\K\\{equiv}(\|l)$;\5
+$\\{delete\_glue\_ref}(\\{cur\_val})$;\5
+$\\{width}(\|q)\K\\{width}(\|q)+\\{width}(\|r)$;\6
+\&{if} $\\{stretch}(\|q)=0$ \1\&{then}\5
+$\\{stretch\_order}(\|q)\K\\{normal}$;\2\6
+\&{if} $\\{stretch\_order}(\|q)=\\{stretch\_order}(\|r)$ \1\&{then}\5
+$\\{stretch}(\|q)\K\\{stretch}(\|q)+\\{stretch}(\|r)$\6
+\4\&{else} \&{if} $(\\{stretch\_order}(\|q)<\\{stretch\_order}(\|r))\W(%
+\\{stretch}(\|r)\I0)$ \1\&{then}\6
+\&{begin} \37$\\{stretch}(\|q)\K\\{stretch}(\|r)$;\5
+$\\{stretch\_order}(\|q)\K\\{stretch\_order}(\|r)$;\6
+\&{end};\2\2\6
+\&{if} $\\{shrink}(\|q)=0$ \1\&{then}\5
+$\\{shrink\_order}(\|q)\K\\{normal}$;\2\6
+\&{if} $\\{shrink\_order}(\|q)=\\{shrink\_order}(\|r)$ \1\&{then}\5
+$\\{shrink}(\|q)\K\\{shrink}(\|q)+\\{shrink}(\|r)$\6
+\4\&{else} \&{if} $(\\{shrink\_order}(\|q)<\\{shrink\_order}(\|r))\W(%
+\\{shrink}(\|r)\I0)$ \1\&{then}\6
+\&{begin} \37$\\{shrink}(\|q)\K\\{shrink}(\|r)$;\5
+$\\{shrink\_order}(\|q)\K\\{shrink\_order}(\|r)$;\6
+\&{end};\2\2\6
+$\\{cur\_val}\K\|q$;\6
+\&{end}\par
+\U1251.\fi
+
+\M1253. \P$\X1253:Compute result of \\{multiply} or \\{divide}, put it in %
+\\{cur\_val}\X\S$\6
+\&{begin} \37\\{scan\_int};\6
+\&{if} $\|p<\\{glue\_val}$ \1\&{then}\6
+\&{if} $\|q=\\{multiply}$ \1\&{then}\6
+\&{if} $\|p=\\{int\_val}$ \1\&{then}\5
+$\\{cur\_val}\K\\{mult\_integers}(\\{eqtb}[\|l].\\{int},\39\\{cur\_val})$\6
+\4\&{else} $\\{cur\_val}\K\\{nx\_plus\_y}(\\{eqtb}[\|l].\\{int},\39\\{cur%
+\_val},\390)$\2\6
+\4\&{else} $\\{cur\_val}\K\\{x\_over\_n}(\\{eqtb}[\|l].\\{int},\39\\{cur%
+\_val})$\2\6
+\4\&{else} \&{begin} \37$\|s\K\\{equiv}(\|l)$;\5
+$\|r\K\\{new\_spec}(\|s)$;\6
+\&{if} $\|q=\\{multiply}$ \1\&{then}\6
+\&{begin} \37$\\{width}(\|r)\K\\{nx\_plus\_y}(\\{width}(\|s),\39\\{cur\_val},%
+\390)$;\5
+$\\{stretch}(\|r)\K\\{nx\_plus\_y}(\\{stretch}(\|s),\39\\{cur\_val},\390)$;\5
+$\\{shrink}(\|r)\K\\{nx\_plus\_y}(\\{shrink}(\|s),\39\\{cur\_val},\390)$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{width}(\|r)\K\\{x\_over\_n}(\\{width}(\|s),\39%
+\\{cur\_val})$;\5
+$\\{stretch}(\|r)\K\\{x\_over\_n}(\\{stretch}(\|s),\39\\{cur\_val})$;\5
+$\\{shrink}(\|r)\K\\{x\_over\_n}(\\{shrink}(\|s),\39\\{cur\_val})$;\6
+\&{end};\2\6
+$\\{cur\_val}\K\|r$;\6
+\&{end};\2\6
+\&{end}\par
+\U1249.\fi
+
+\M1254. The processing of boxes is somewhat different, because we may need
+to scan and create an entire box before we actually change the value of the old
+one.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{set\_box}: \37\&{begin} \37\\{scan\_eight\_bit\_int};\6
+\&{if} $\\{global}$ \1\&{then}\5
+$\|n\K256+\\{cur\_val}$\ \&{else} $\|n\K\\{cur\_val}$;\2\6
+\\{scan\_optional\_equals};\6
+\&{if} $\\{set\_box\_allowed}$ \1\&{then}\5
+$\\{scan\_box}(\\{box\_flag}+\|n)$\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Improper\ "})$;\5
+$\\{print\_esc}(\.{"setbox"})$;\5
+$\\{help2}(\.{"Sorry,\ \\setbox\ is\ not\ allowed\ after\ \\halign\ in\ a\
+display,"})$\6
+$(\.{"or\ between\ \\accent\ and\ an\ accented\ character."})$;\5
+\\{error};\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1255. The \\{space\_factor} or \\{prev\_depth} settings are changed when a %
+\\{set\_aux}
+command is sensed. Similarly, \\{prev\_graf} is changed in the presence of
+\\{set\_prev\_graf}, and \\{dead\_cycles} or \\{insert\_penalties} in the
+presence of
+\\{set\_page\_int}. These definitions are always global.
+
+When some dimension of a box register is changed, the change isn't exactly
+global; but \TeX\ does not look at the \.{\\global} switch.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{set\_aux}: \37\\{alter\_aux};\6
+\4\\{set\_prev\_graf}: \37\\{alter\_prev\_graf};\6
+\4\\{set\_page\_dimen}: \37\\{alter\_page\_so\_far};\6
+\4\\{set\_page\_int}: \37\\{alter\_integer};\6
+\4\\{set\_box\_dimen}: \37\\{alter\_box\_dimen};\par
+\fi
+
+\M1256. \P$\X1227:Declare subprocedures for \\{prefixed\_command}\X\mathrel{+}%
+\S$\6
+\4\&{procedure}\1\  \37\\{alter\_aux};\6
+\4\&{var} \37\|c: \37\\{halfword};\C{\\{hmode} or \\{vmode}}\2\6
+\&{begin} \37\&{if} $\\{cur\_chr}\I\\{abs}(\\{mode})$ \1\&{then}\5
+\\{report\_illegal\_case}\6
+\4\&{else} \&{begin} \37$\|c\K\\{cur\_chr}$;\5
+\\{scan\_optional\_equals};\6
+\&{if} $\|c=\\{vmode}$ \1\&{then}\6
+\&{begin} \37\\{scan\_normal\_dimen};\5
+$\\{prev\_depth}\K\\{cur\_val}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\\{scan\_int};\6
+\&{if} $(\\{cur\_val}\L0)\V(\\{cur\_val}>32767)$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Bad\ space\ factor"})$;\5
+$\\{help1}(\.{"I\ allow\ only\ values\ in\ the\ range\ 1..32767\ here."})$;\5
+$\\{int\_error}(\\{cur\_val})$;\6
+\&{end}\6
+\4\&{else} $\\{space\_factor}\K\\{cur\_val}$;\2\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1257. \P$\X1227:Declare subprocedures for \\{prefixed\_command}\X\mathrel{+}%
+\S$\6
+\4\&{procedure}\1\  \37\\{alter\_prev\_graf};\6
+\4\&{var} \37\|p: \37$0\to\\{nest\_size}$;\C{index into \\{nest}}\2\6
+\&{begin} \37$\\{nest}[\\{nest\_ptr}]\K\\{cur\_list}$;\5
+$\|p\K\\{nest\_ptr}$;\6
+\&{while} $\\{abs}(\\{nest}[\|p].\\{mode\_field})\I\\{vmode}$ \1\&{do}\5
+$\\{decr}(\|p)$;\2\6
+\\{scan\_optional\_equals};\5
+\\{scan\_int};\6
+\&{if} $\\{cur\_val}<0$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Bad\ "})$;\5
+$\\{print\_esc}(\.{"prevgraf"})$;\5
+$\\{help1}(\.{"I\ allow\ only\ nonnegative\ values\ here."})$;\5
+$\\{int\_error}(\\{cur\_val})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{nest}[\|p].\\{pg\_field}\K\\{cur\_val}$;\5
+$\\{cur\_list}\K\\{nest}[\\{nest\_ptr}]$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1258. \P$\X1227:Declare subprocedures for \\{prefixed\_command}\X\mathrel{+}%
+\S$\6
+\4\&{procedure}\1\  \37\\{alter\_page\_so\_far};\6
+\4\&{var} \37\|c: \37$0\to7$;\C{index into \\{page\_so\_far}}\2\6
+\&{begin} \37$\|c\K\\{cur\_chr}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_normal\_dimen};\5
+$\\{page\_so\_far}[\|c]\K\\{cur\_val}$;\6
+\&{end};\par
+\fi
+
+\M1259. \P$\X1227:Declare subprocedures for \\{prefixed\_command}\X\mathrel{+}%
+\S$\6
+\4\&{procedure}\1\  \37\\{alter\_integer};\6
+\4\&{var} \37\|c: \37$0\to1$;\C{0 for \.{\\deadcycles}, 1 for \.{%
+\\insertpenalties}}\2\6
+\&{begin} \37$\|c\K\\{cur\_chr}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_int};\6
+\&{if} $\|c=0$ \1\&{then}\5
+$\\{dead\_cycles}\K\\{cur\_val}$\6
+\4\&{else} $\\{insert\_penalties}\K\\{cur\_val}$;\2\6
+\&{end};\par
+\fi
+
+\M1260. \P$\X1227:Declare subprocedures for \\{prefixed\_command}\X\mathrel{+}%
+\S$\6
+\4\&{procedure}\1\  \37\\{alter\_box\_dimen};\6
+\4\&{var} \37\|c: \37\\{small\_number};\C{\\{width\_offset} or \\{height%
+\_offset} or \\{depth\_offset}}\6
+$\|p,\39\|q$: \37\\{pointer};\C{temporary registers}\6
+\|b: \37\\{eight\_bits};\C{box number}\2\6
+\&{begin} \37$\|c\K\\{cur\_chr}$;\5
+\\{scan\_eight\_bit\_int};\5
+$\|b\K\\{cur\_val}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_normal\_dimen};\6
+\&{if} $\\{box}(\|b)\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\|q\K\\{box}(\|b)$;\5
+$\|p\K\\{link}(\|q)$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{abs}(\\{direction})=\\{box\_dir}(\|p)$ \1\&{then}\5
+$\|q\K\|p$;\2\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\&{if} $\\{box\_dir}(\|q)\I\\{abs}(\\{direction})$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{link}(\\{box}(\|b))$;\5
+$\\{link}(\\{box}(\|b))\K\\{null}$;\5
+$\|q\K\\{new\_dir\_node}(\|q,\39\\{abs}(\\{direction}))$;\5
+$\\{list\_ptr}(\|q)\K\\{null}$;\5
+$\\{link}(\|q)\K\|p$;\5
+$\\{link}(\\{box}(\|b))\K\|q$;\6
+\&{end};\2\6
+$\\{mem}[\|q+\|c].\\{sc}\K\\{cur\_val}$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1261. Paragraph shapes are set up in the obvious way.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{set\_shape}: \37\&{begin} \37\\{scan\_optional\_equals};\5
+\\{scan\_int};\5
+$\|n\K\\{cur\_val}$;\6
+\&{if} $\|n\L0$ \1\&{then}\5
+$\|p\K\\{null}$\6
+\4\&{else} \&{begin} \37$\|p\K\\{get\_node}(2\ast\|n+1)$;\5
+$\\{info}(\|p)\K\|n$;\6
+\&{for} $\|j\K1\mathrel{\&{to}}\|n$ \1\&{do}\6
+\&{begin} \37\\{scan\_normal\_dimen};\5
+$\\{mem}[\|p+2\ast\|j-1].\\{sc}\K\\{cur\_val}$;\C{indentation}\6
+\\{scan\_normal\_dimen};\5
+$\\{mem}[\|p+2\ast\|j].\\{sc}\K\\{cur\_val}$;\C{width}\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{define}(\\{par\_shape\_loc},\39\\{shape\_ref},\39\|p)$;\6
+\&{end};\par
+\fi
+
+\M1262. Here's something that isn't quite so obvious. It guarantees that
+$\\{info}(\\{par\_shape\_ptr})$ can hold any positive~\|n for which $\\{get%
+\_node}(2\ast\|n+1)$
+doesn't overflow the memory capacity.
+
+\Y\P$\4\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6
+\&{if} $2\ast\\{max\_halfword}<\\{mem\_top}-\\{mem\_min}$ \1\&{then}\5
+$\\{bad}\K41$;\2\par
+\fi
+
+\M1263. New hyphenation data is loaded by the \\{hyph\_data} command.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"hyphenation"},\39\\{hyph\_data},\390)$;\5
+$\\{primitive}(\.{"patterns"},\39\\{hyph\_data},\391)$;\par
+\fi
+
+\M1264. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{hyph\_data}: \37\&{if} $\\{chr\_code}=1$ \1\&{then}\5
+$\\{print\_esc}(\.{"patterns"})$\6
+\4\&{else} $\\{print\_esc}(\.{"hyphenation"})$;\2\par
+\fi
+
+\M1265. \P$\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{hyph\_data}: \37\&{if} $\\{cur\_chr}=1$ \1\&{then}\6
+\&{begin} \37\&{Init} \37\\{new\_patterns};\5
+\&{goto} \37\\{done};\ \&{Tini}\6
+$\\{print\_err}(\.{"Patterns\ can\ be\ loaded\ only\ by\ INITEX"})$;\5
+\\{help0};\5
+\\{error};\6
+\1\&{repeat} \37\\{get\_token};\6
+\4\&{until}\5
+$\\{cur\_cmd}=\\{right\_brace}$;\C{flush the patterns}\2\6
+\&{return};\6
+\&{end}\6
+\4\&{else} \&{begin} \37\\{new\_hyph\_exceptions};\5
+\&{goto} \37\\{done};\6
+\&{end};\2\par
+\fi
+
+\M1266. All of \TeX's parameters are kept in \\{eqtb} except the font
+information,
+the interaction mode, and the hyphenation tables; these are strictly global.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{assign\_font\_dimen}: \37\&{begin} \37$\\{find\_font\_dimen}(\\{true})$;\5
+$\|k\K\\{cur\_val}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_normal\_dimen};\5
+$\\{font\_info}[\|k].\\{sc}\K\\{cur\_val}$;\6
+\&{end};\6
+\4\\{assign\_font\_int}: \37\&{begin} \37$\|n\K\\{cur\_chr}$;\5
+\\{scan\_font\_ident};\5
+$\|f\K\\{cur\_val}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_int};\6
+\&{if} $\|n=0$ \1\&{then}\5
+$\\{hyphen\_char}[\|f]\K\\{cur\_val}$\ \&{else} $\\{skew\_char}[\|f]\K\\{cur%
+\_val}$;\2\6
+\&{end};\par
+\fi
+
+\M1267. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"hyphenchar"},\39\\{assign\_font\_int},\390)$;\5
+$\\{primitive}(\.{"skewchar"},\39\\{assign\_font\_int},\391)$;\par
+\fi
+
+\M1268. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{assign\_font\_int}: \37\&{if} $\\{chr\_code}=0$ \1\&{then}\5
+$\\{print\_esc}(\.{"hyphenchar"})$\6
+\4\&{else} $\\{print\_esc}(\.{"skewchar"})$;\2\par
+\fi
+
+\M1269. Here is where the information for a new font gets loaded.
+
+\Y\P$\4\X1229:Assignments\X\mathrel{+}\S$\6
+\4$\\{def\_tfont},\39\\{def\_jfont},\39\\{def\_font}$: \37$\\{new\_font}(\|a)$;%
+\par
+\fi
+
+\M1270. \P$\X1227:Declare subprocedures for \\{prefixed\_command}\X\mathrel{+}%
+\S$\6
+\4\&{procedure}\1\  \37$\\{new\_font}(\|a:\\{small\_number})$;\6
+\4\&{label} \37\\{common\_ending};\6
+\4\&{var} \37\|u: \37\\{pointer};\C{user's font identifier}\6
+\|s: \37\\{scaled};\C{stated ``at'' size, or negative of scaled magnification}\6
+\|f: \37\\{internal\_font\_number};\C{runs through existing fonts}\6
+\|t: \37\\{str\_number};\C{name for the frozen font identifier}\6
+\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{holds \\{selector} setting}\2\6
+\&{begin} \37\&{if} $\\{job\_name}=0$ \1\&{then}\5
+\\{open\_log\_file};\C{avoid confusing \.{texput} with the font name}\2\6
+\\{get\_r\_token};\5
+$\|u\K\\{cur\_cs}$;\6
+\&{if} $\|u\G\\{hash\_base}$ \1\&{then}\5
+$\|t\K\\{text}(\|u)$\6
+\4\&{else} \&{if} $\|u\G\\{single\_base}$ \1\&{then}\6
+\&{if} $\|u=\\{null\_cs}$ \1\&{then}\5
+$\|t\K\.{"FONT"}$\ \&{else} $\|t\K\|u-\\{single\_base}$\2\6
+\4\&{else} \&{begin} \37$\\{old\_setting}\K\\{selector}$;\5
+$\\{selector}\K\\{new\_string}$;\5
+$\\{print}(\.{"FONT"})$;\5
+$\\{print}(\|u-\\{active\_base})$;\5
+$\\{selector}\K\\{old\_setting}$;\5
+$\\{str\_room}(1)$;\5
+$\|t\K\\{make\_string}$;\6
+\&{end};\2\2\6
+$\\{define}(\|u,\39\\{set\_font},\39\\{null\_font})$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_file\_name};\5
+\X1271:Scan the font size specification\X;\6
+\X1273:If this font has already been loaded, set \|f to the internal font
+number and \&{goto} \\{common\_ending}\X;\6
+$\|f\K\\{read\_font\_info}(\|u,\39\\{cur\_name},\39\\{cur\_area},\39\|s)$;\6
+\4\\{common\_ending}: \37$\\{equiv}(\|u)\K\|f$;\5
+$\\{eqtb}[\\{font\_id\_base}+\|f]\K\\{eqtb}[\|u]$;\5
+$\\{font\_id\_text}(\|f)\K\|t$;\6
+\&{end};\par
+\fi
+
+\M1271. \P$\X1271:Scan the font size specification\X\S$\6
+$\\{name\_in\_progress}\K\\{true}$;\C{this keeps \\{cur\_name} from being
+changed}\6
+\&{if} $\\{scan\_keyword}(\.{"at"})$ \1\&{then}\5
+\X1272:Put the \(p)(positive) `at' size into \|s\X\6
+\4\&{else} \&{if} $\\{scan\_keyword}(\.{"scaled"})$ \1\&{then}\6
+\&{begin} \37\\{scan\_int};\5
+$\|s\K-\\{cur\_val}$;\6
+\&{if} $(\\{cur\_val}\L0)\V(\\{cur\_val}>32768)$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Illegal\ magnification\ has\ been\ changed\ to%
+\ 1000"})$;\6
+$\\{help1}(\.{"The\ magnification\ ratio\ must\ be\ between\ 1\ and\
+32768."})$;\5
+$\\{int\_error}(\\{cur\_val})$;\5
+$\|s\K-1000$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} $\|s\K-1000$;\2\2\6
+$\\{name\_in\_progress}\K\\{false}$\par
+\U1270.\fi
+
+\M1272. \P$\X1272:Put the \(p)(positive) `at' size into \|s\X\S$\6
+\&{begin} \37\\{scan\_normal\_dimen};\5
+$\|s\K\\{cur\_val}$;\6
+\&{if} $(\|s\L0)\V(\|s\G\O{1000000000})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Improper\ \`at\'\ size\ ("})$;\5
+$\\{print\_scaled}(\|s)$;\5
+$\\{print}(\.{"pt),\ replaced\ by\ 10pt"})$;\5
+$\\{help2}(\.{"I\ can\ only\ handle\ fonts\ at\ positive\ sizes\ that\ are"})$\6
+$(\.{"less\ than\ 2048pt,\ so\ I\'ve\ changed\ what\ you\ said\ to\ 10pt."})$;\5
+\\{error};\5
+$\|s\K10\ast\\{unity}$;\6
+\&{end};\2\6
+\&{end}\par
+\U1271.\fi
+
+\M1273. When the user gives a new identifier to a font that was previously
+loaded,
+the new name becomes the font identifier of record. Font names `\.{xyz}' and
+`\.{XYZ}' are considered to be different.
+
+\Y\P$\4\X1273:If this font has already been loaded, set \|f to the internal
+font number and \&{goto} \\{common\_ending}\X\S$\6
+\&{for} $\|f\K\\{font\_base}+1\mathrel{\&{to}}\\{font\_ptr}$ \1\&{do}\6
+\&{if} $\\{str\_eq\_str}(\\{font\_name}[\|f],\39\\{cur\_name})\W\\{str\_eq%
+\_str}(\\{font\_area}[\|f],\39\\{cur\_area})$ \1\&{then}\6
+\&{begin} \37\&{if} $\|s>0$ \1\&{then}\6
+\&{begin} \37\&{if} $\|s=\\{font\_size}[\|f]$ \1\&{then}\5
+\&{goto} \37\\{common\_ending};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{font\_size}[\|f]=\\{xn\_over\_d}(\\{font\_dsize}[\|f],%
+\39-\|s,\391000)$ \1\&{then}\5
+\&{goto} \37\\{common\_ending};\2\2\6
+\&{end}\2\2\par
+\U1270.\fi
+
+\M1274. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{set\_font}: \37\&{begin} \37$\\{print}(\.{"select\ font\ "})$;\5
+$\\{slow\_print}(\\{font\_name}[\\{chr\_code}])$;\6
+\&{if} $\\{font\_size}[\\{chr\_code}]\I\\{font\_dsize}[\\{chr\_code}]$ \1%
+\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ at\ "})$;\5
+$\\{print\_scaled}(\\{font\_size}[\\{chr\_code}])$;\5
+$\\{print}(\.{"pt"})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1275. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"batchmode"},\39\\{set\_interaction},\39\\{batch\_mode})$;\5
+$\\{primitive}(\.{"nonstopmode"},\39\\{set\_interaction},\39\\{nonstop%
+\_mode})$;\5
+$\\{primitive}(\.{"scrollmode"},\39\\{set\_interaction},\39\\{scroll\_mode})$;\5
+$\\{primitive}(\.{"errorstopmode"},\39\\{set\_interaction},\39\\{error\_stop%
+\_mode})$;\par
+\fi
+
+\M1276. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{set\_interaction}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{batch\_mode}: \37$\\{print\_esc}(\.{"batchmode"})$;\6
+\4\\{nonstop\_mode}: \37$\\{print\_esc}(\.{"nonstopmode"})$;\6
+\4\\{scroll\_mode}: \37$\\{print\_esc}(\.{"scrollmode"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"errorstopmode"})$\2\6
+\&{endcases};\par
+\fi
+
+\M1277. \P$\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{set\_interaction}: \37\\{new\_interaction};\par
+\fi
+
+\M1278. \P$\X1227:Declare subprocedures for \\{prefixed\_command}\X\mathrel{+}%
+\S$\6
+\4\&{procedure}\1\  \37\\{new\_interaction};\2\6
+\&{begin} \37\\{print\_ln};\5
+$\\{interaction}\K\\{cur\_chr}$;\6
+\&{if} $\\{interaction}=\\{batch\_mode}$ \1\&{then}\5
+$\\{kpse\_make\_tex\_discard\_errors}\K1$\6
+\4\&{else} $\\{kpse\_make\_tex\_discard\_errors}\K0$;\2\6
+\X76:Initialize the print \\{selector} based on \\{interaction}\X;\6
+\&{if} $\\{log\_opened}$ \1\&{then}\5
+$\\{selector}\K\\{selector}+2$;\2\6
+\&{end};\par
+\fi
+
+\M1279. The \.{\\afterassignment} command puts a token into the global
+variable \\{after\_token}. This global variable is examined just after
+every assignment has been performed.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{after\_token}: \37\\{halfword};\C{zero, or a saved token}\par
+\fi
+
+\M1280. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{after\_token}\K0$;\par
+\fi
+
+\M1281. \P$\X1222:Cases of \\{main\_control} that don't depend on \\{mode}\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{after\_assignment})$: \37\&{begin} \37\\{get\_token};\5
+$\\{after\_token}\K\\{cur\_tok}$;\6
+\&{end};\par
+\fi
+
+\M1282. \P$\X1282:Insert a token saved by \.{\\afterassignment}, if any\X\S$\6
+\&{if} $\\{after\_token}\I0$ \1\&{then}\6
+\&{begin} \37$\\{cur\_tok}\K\\{after\_token}$;\5
+\\{back\_input};\5
+$\\{after\_token}\K0$;\6
+\&{end}\2\par
+\U1223.\fi
+
+\M1283. Here is a procedure that might be called `Get the next non-blank
+non-relax
+non-call non-assignment token'.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{do\_assignments};\6
+\4\&{label} \37\\{exit};\2\6
+\&{begin} \37\~ \1\&{loop}\6
+\&{begin} \37\X415:Get the next non-blank non-relax non-call token\X;\6
+\&{if} $\\{cur\_cmd}\L\\{max\_non\_prefixed\_command}$ \1\&{then}\5
+\&{return};\2\6
+$\\{set\_box\_allowed}\K\\{false}$;\5
+\\{prefixed\_command};\5
+$\\{set\_box\_allowed}\K\\{true}$;\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1284. \P$\X1222:Cases of \\{main\_control} that don't depend on \\{mode}\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{after\_group})$: \37\&{begin} \37\\{get\_token};\5
+$\\{save\_for\_after}(\\{cur\_tok})$;\6
+\&{end};\par
+\fi
+
+\M1285. Files for \.{\\read} are opened and closed by the \\{in\_stream}
+command.
+
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"openin"},\39\\{in\_stream},\391)$;\5
+$\\{primitive}(\.{"closein"},\39\\{in\_stream},\390)$;\par
+\fi
+
+\M1286. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{in\_stream}: \37\&{if} $\\{chr\_code}=0$ \1\&{then}\5
+$\\{print\_esc}(\.{"closein"})$\6
+\4\&{else} $\\{print\_esc}(\.{"openin"})$;\2\par
+\fi
+
+\M1287. \P$\X1222:Cases of \\{main\_control} that don't depend on \\{mode}\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{in\_stream})$: \37\\{open\_or\_close\_in};\par
+\fi
+
+\M1288. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{open\_or\_close\_in};\6
+\4\&{var} \37\|c: \37$0\to1$;\C{1 for \.{\\openin}, 0 for \.{\\closein}}\6
+\|n: \37$0\to15$;\C{stream number}\2\6
+\&{begin} \37$\|c\K\\{cur\_chr}$;\5
+\\{scan\_four\_bit\_int};\5
+$\|n\K\\{cur\_val}$;\6
+\&{if} $\\{read\_open}[\|n]\I\\{closed}$ \1\&{then}\6
+\&{begin} \37$\\{a\_close}(\\{read\_file}[\|n])$;\5
+$\\{read\_open}[\|n]\K\\{closed}$;\6
+\&{end};\2\6
+\&{if} $\|c\I0$ \1\&{then}\6
+\&{begin} \37\\{scan\_optional\_equals};\5
+\\{scan\_file\_name};\5
+\\{pack\_cur\_name};\5
+$\\{tex\_input\_type}\K0$;\C{Tell \\{open\_input} we are \.{\\openin}.}\6
+\&{if} $\\{kpse\_in\_name\_ok}(\\{stringcast}(\\{name\_of\_file}+1))\W\\{a%
+\_open\_in}(\\{read\_file}[\|n],\39\\{kpse\_tex\_format})$ \1\&{then}\5
+$\\{read\_open}[\|n]\K\\{just\_open}$;\2\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1289. The user can issue messages to the terminal, regardless of the
+current mode.
+
+\Y\P$\4\X1222:Cases of \\{main\_control} that don't depend on \\{mode}\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{message})$: \37\\{issue\_message};\par
+\fi
+
+\M1290. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"message"},\39\\{message},\390)$;\5
+$\\{primitive}(\.{"errmessage"},\39\\{message},\391)$;\par
+\fi
+
+\M1291. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{message}: \37\&{if} $\\{chr\_code}=0$ \1\&{then}\5
+$\\{print\_esc}(\.{"message"})$\6
+\4\&{else} $\\{print\_esc}(\.{"errmessage"})$;\2\par
+\fi
+
+\M1292. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{issue\_message};\6
+\4\&{var} \37\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{holds \\{selector}
+setting}\6
+\|c: \37$0\to1$;\C{identifies \.{\\message} and \.{\\errmessage}}\6
+\|s: \37\\{str\_number};\C{the message}\2\6
+\&{begin} \37$\|c\K\\{cur\_chr}$;\5
+$\\{link}(\\{garbage})\K\\{scan\_toks}(\\{false},\39\\{true})$;\5
+$\\{old\_setting}\K\\{selector}$;\5
+$\\{selector}\K\\{new\_string}$;\5
+$\\{token\_show}(\\{def\_ref})$;\5
+$\\{selector}\K\\{old\_setting}$;\5
+$\\{flush\_list}(\\{def\_ref})$;\5
+$\\{str\_room}(1)$;\5
+$\|s\K\\{make\_string}$;\6
+\&{if} $\|c=0$ \1\&{then}\5
+\X1293:Print string \|s on the terminal\X\6
+\4\&{else} \X1296:Print string \|s as an error message\X;\2\6
+\\{flush\_string};\6
+\&{end};\par
+\fi
+
+\M1293. \P$\X1293:Print string \|s on the terminal\X\S$\6
+\&{begin} \37\&{if} $\\{term\_offset}+\\{length}(\|s)>\\{max\_print\_line}-2$ %
+\1\&{then}\5
+\\{print\_ln}\6
+\4\&{else} \&{if} $(\\{term\_offset}>0)\V(\\{file\_offset}>0)$ \1\&{then}\5
+$\\{print\_char}(\.{"\ "})$;\2\2\6
+$\\{slow\_print}(\|s)$;\5
+\\{update\_terminal};\6
+\&{end}\par
+\U1292.\fi
+
+\M1294. If \.{\\errmessage} occurs often in \\{scroll\_mode}, without
+user-defined
+\.{\\errhelp}, we don't want to give a long help message each time. So we
+give a verbose explanation only once.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{long\_help\_seen}: \37\\{boolean};\C{has the long \.{\\errmessage} help
+been used?}\par
+\fi
+
+\M1295. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{long\_help\_seen}\K\\{false}$;\par
+\fi
+
+\M1296. \P$\X1296:Print string \|s as an error message\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{""})$;\5
+$\\{slow\_print}(\|s)$;\6
+\&{if} $\\{err\_help}\I\\{null}$ \1\&{then}\5
+$\\{use\_err\_help}\K\\{true}$\6
+\4\&{else} \&{if} $\\{long\_help\_seen}$ \1\&{then}\5
+$\\{help1}(\.{"(That\ was\ another\ \\errmessage.)"})$\6
+\4\&{else} \&{begin} \37\&{if} $\\{interaction}<\\{error\_stop\_mode}$ \1%
+\&{then}\5
+$\\{long\_help\_seen}\K\\{true}$;\2\6
+$\\{help4}(\.{"This\ error\ message\ was\ generated\ by\ an\ \\errmessage"})$\6
+$(\.{"command,\ so\ I\ can\'t\ give\ any\ explicit\ help."})$\6
+$(\.{"Pretend\ that\ you\'re\ Hercule\ Poirot:\ Examine\ all\ clues,"})$\6
+$(\.{"and\ deduce\ the\ truth\ by\ order\ and\ method."})$;\6
+\&{end};\2\2\6
+\\{error};\5
+$\\{use\_err\_help}\K\\{false}$;\6
+\&{end}\par
+\U1292.\fi
+
+\M1297. The \\{error} routine calls on \\{give\_err\_help} if help is requested
+from
+the \\{err\_help} parameter.
+
+\Y\P\4\&{procedure}\1\  \37\\{give\_err\_help};\2\6
+\&{begin} \37$\\{token\_show}(\\{err\_help})$;\6
+\&{end};\par
+\fi
+
+\M1298. The \.{\\uppercase} and \.{\\lowercase} commands are implemented by
+building a token list and then changing the cases of the letters in it.
+
+\Y\P$\4\X1222:Cases of \\{main\_control} that don't depend on \\{mode}\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{case\_shift})$: \37\\{shift\_case};\par
+\fi
+
+\M1299. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"lowercase"},\39\\{case\_shift},\39\\{lc\_code\_base})$;\5
+$\\{primitive}(\.{"uppercase"},\39\\{case\_shift},\39\\{uc\_code\_base})$;\par
+\fi
+
+\M1300. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{case\_shift}: \37\&{if} $\\{chr\_code}=\\{lc\_code\_base}$ \1\&{then}\5
+$\\{print\_esc}(\.{"lowercase"})$\6
+\4\&{else} $\\{print\_esc}(\.{"uppercase"})$;\2\par
+\fi
+
+\M1301. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{shift\_case};\6
+\4\&{var} \37\|b: \37\\{pointer};\C{\\{lc\_code\_base} or \\{uc\_code\_base}}\6
+\|p: \37\\{pointer};\C{runs through the token list}\6
+\|t: \37\\{halfword};\C{token}\6
+\|c: \37\\{eight\_bits};\C{character code}\2\6
+\&{begin} \37$\|b\K\\{cur\_chr}$;\5
+$\|p\K\\{scan\_toks}(\\{false},\39\\{false})$;\5
+$\|p\K\\{link}(\\{def\_ref})$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\X1302:Change the case of the token in \|p, if a change is
+appropriate\X;\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+$\\{back\_list}(\\{link}(\\{def\_ref}))$;\5
+$\\{free\_avail}(\\{def\_ref})$;\C{omit reference count}\6
+\&{end};\par
+\fi
+
+\M1302. When the case of a \\{chr\_code} changes, we don't change the \\{cmd}.
+We also change active characters, using the fact that
+$\\{cs\_token\_flag}+\\{active\_base}$ is a multiple of~256.
+
+\Y\P$\4\X1302:Change the case of the token in \|p, if a change is appropriate\X%
+\S$\6
+$\|t\K\\{info}(\|p)$;\6
+\&{if} $(\|t<\\{cs\_token\_flag}+\\{single\_base})\W(\R\\{check\_kanji}(\|t))$ %
+\1\&{then}\6
+\&{begin} \37$\|c\K\|t\mathbin{\&{mod}}256$;\6
+\&{if} $\\{equiv}(\|b+\|c)\I0$ \1\&{then}\5
+$\\{info}(\|p)\K\|t-\|c+\\{equiv}(\|b+\|c)$;\2\6
+\&{end}\2\par
+\U1301.\fi
+
+\M1303. We come finally to the last pieces missing from \\{main\_control},
+namely the
+`\.{\\show}' commands that are useful when debugging.
+
+\Y\P$\4\X1222:Cases of \\{main\_control} that don't depend on \\{mode}\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{xray})$: \37\\{show\_whatever};\par
+\fi
+
+\M1304. \P\D \37$\\{show\_code}=0$\C{ \.{\\show} }\par
+\P\D \37$\\{show\_box\_code}=1$\C{ \.{\\showbox} }\par
+\P\D \37$\\{show\_the\_code}=2$\C{ \.{\\showthe} }\par
+\P\D \37$\\{show\_lists}=3$\C{ \.{\\showlists} }\par
+\P\D \37$\\{show\_mode}=4$\C{ \.{\\showmode} }\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"show"},\39\\{xray},\39\\{show\_code})$;\5
+$\\{primitive}(\.{"showbox"},\39\\{xray},\39\\{show\_box\_code})$;\5
+$\\{primitive}(\.{"showthe"},\39\\{xray},\39\\{show\_the\_code})$;\5
+$\\{primitive}(\.{"showlists"},\39\\{xray},\39\\{show\_lists})$;\5
+$\\{primitive}(\.{"showmode"},\39\\{xray},\39\\{show\_mode})$;\par
+\fi
+
+\M1305. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{xray}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{show\_box\_code}: \37$\\{print\_esc}(\.{"showbox"})$;\6
+\4\\{show\_the\_code}: \37$\\{print\_esc}(\.{"showthe"})$;\6
+\4\\{show\_lists}: \37$\\{print\_esc}(\.{"showlists"})$;\6
+\4\\{show\_mode}: \37$\\{print\_esc}(\.{"showmode"})$;\6
+\4\&{othercases} \37$\\{print\_esc}(\.{"show"})$\2\6
+\&{endcases};\par
+\fi
+
+\M1306. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{show\_whatever};\6
+\4\&{label} \37\\{common\_ending};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{tail of a token list to show}\2\6
+\&{begin} \37\&{case} $\\{cur\_chr}$ \1\&{of}\6
+\4\\{show\_lists}: \37\&{begin} \37\\{begin\_diagnostic};\5
+\\{show\_activities};\6
+\&{end};\6
+\4\\{show\_box\_code}: \37\X1309:Show the current contents of a box\X;\6
+\4\\{show\_code}: \37\X1307:Show the current meaning of a token, then \&{goto} %
+\\{common\_ending}\X;\6
+\4\\{show\_mode}: \37\X1429:Show the current japanese processing mode\X;\6
+\4\&{othercases} \37\X1310:Show the current value of some parameter or
+register, then \&{goto} \\{common\_ending}\X\2\6
+\&{endcases};\6
+\X1311:Complete a potentially long \.{\\show} command\X;\6
+\4\\{common\_ending}: \37\&{if} $\\{interaction}<\\{error\_stop\_mode}$ \1%
+\&{then}\6
+\&{begin} \37\\{help0};\5
+$\\{decr}(\\{error\_count})$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{tracing\_online}>0$ \1\&{then}\6
+\&{begin} \37\hbox{}\6
+$\\{help3}(\.{"This\ isn\'t\ an\ error\ message;\ I\'m\ just\ \\showing\
+something."})$\6
+$(\.{"Type\ \`I\\show...\'\ to\ show\ more\ (e.g.,\ \\show\\cs,"})$\6
+$(\.{"\\showthe\\count10,\ \\showbox255,\ \\showlists)."})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\hbox{}\6
+$\\{help5}(\.{"This\ isn\'t\ an\ error\ message;\ I\'m\ just\ \\showing\
+something."})$\6
+$(\.{"Type\ \`I\\show...\'\ to\ show\ more\ (e.g.,\ \\show\\cs,"})$\6
+$(\.{"\\showthe\\count10,\ \\showbox255,\ \\showlists)."})$\6
+$(\.{"And\ type\ \`I\\tracingonline=1\\show...\'\ to\ show\ boxes\ and"})$\6
+$(\.{"lists\ on\ your\ terminal\ as\ well\ as\ in\ the\ transcript\ file."})$;\6
+\&{end};\2\2\6
+\\{error};\6
+\&{end};\par
+\fi
+
+\M1307. \P$\X1307:Show the current meaning of a token, then \&{goto} \\{common%
+\_ending}\X\S$\6
+\&{begin} \37\\{get\_token};\6
+\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5
+\\{wake\_up\_terminal};\2\6
+$\\{print\_nl}(\.{">\ "})$;\6
+\&{if} $\\{cur\_cs}\I0$ \1\&{then}\6
+\&{begin} \37$\\{sprint\_cs}(\\{cur\_cs})$;\5
+$\\{print\_char}(\.{"="})$;\6
+\&{end};\2\6
+\\{print\_meaning};\5
+\&{goto} \37\\{common\_ending};\6
+\&{end}\par
+\U1306.\fi
+
+\M1308. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{undefined\_cs}: \37$\\{print}(\.{"undefined"})$;\6
+\4\\{call}: \37$\\{print}(\.{"macro"})$;\6
+\4\\{long\_call}: \37$\\{print\_esc}(\.{"long\ macro"})$;\6
+\4\\{outer\_call}: \37$\\{print\_esc}(\.{"outer\ macro"})$;\6
+\4\\{long\_outer\_call}: \37\&{begin} \37$\\{print\_esc}(\.{"long"})$;\5
+$\\{print\_esc}(\.{"outer\ macro"})$;\6
+\&{end};\6
+\4\\{end\_template}: \37$\\{print\_esc}(\.{"outer\ endtemplate"})$;\par
+\fi
+
+\M1309. \P$\X1309:Show the current contents of a box\X\S$\6
+\&{begin} \37\\{scan\_eight\_bit\_int};\5
+\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{">\ \\box"})$;\5
+$\\{print\_int}(\\{cur\_val})$;\5
+$\\{print\_char}(\.{"="})$;\6
+\&{if} $\\{box}(\\{cur\_val})=\\{null}$ \1\&{then}\5
+$\\{print}(\.{"void"})$\6
+\4\&{else} $\\{show\_box}(\\{box}(\\{cur\_val}))$;\2\6
+\&{end}\par
+\U1306.\fi
+
+\M1310. \P$\X1310:Show the current value of some parameter or register, then %
+\&{goto} \\{common\_ending}\X\S$\6
+\&{begin} \37$\|p\K\\{the\_toks}$;\6
+\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5
+\\{wake\_up\_terminal};\2\6
+$\\{print\_nl}(\.{">\ "})$;\5
+$\\{token\_show}(\\{temp\_head})$;\5
+$\\{flush\_list}(\\{link}(\\{temp\_head}))$;\5
+\&{goto} \37\\{common\_ending};\6
+\&{end}\par
+\U1306.\fi
+
+\M1311. \P$\X1311:Complete a potentially long \.{\\show} command\X\S$\6
+$\\{end\_diagnostic}(\\{true})$;\5
+$\\{print\_err}(\.{"OK"})$;\6
+\&{if} $\\{selector}=\\{term\_and\_log}$ \1\&{then}\6
+\&{if} $\\{tracing\_online}\L0$ \1\&{then}\6
+\&{begin} \37$\\{selector}\K\\{term\_only}$;\5
+$\\{print}(\.{"\ (see\ the\ transcript\ file)"})$;\5
+$\\{selector}\K\\{term\_and\_log}$;\6
+\&{end}\2\2\par
+\U1306.\fi
+
+\N1312.  \[50] Dumping and undumping the tables.
+After \.{INITEX} has seen a collection of fonts and macros, it
+can write all the necessary information on an auxiliary file so
+that production versions of \TeX\ are able to initialize their
+memory at high speed. The present section of the program takes
+care of such output and input. We shall consider simultaneously
+the processes of storing and restoring,
+so that the inverse relation between them is clear.
+
+The global variable \\{format\_ident} is a string that is printed right
+after the \\{banner} line when \TeX\ is ready to start. For \.{INITEX} this
+string says simply `\.{(INITEX)}'; for other versions of \TeX\ it says,
+for example, `\.{(preloaded format=plain 1982.11.19)}', showing the year,
+month, and day that the format file was created. We have $\\{format\_ident}=0$
+before \TeX's tables are loaded.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{format\_ident}: \37\\{str\_number};\par
+\fi
+
+\M1313. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{format\_ident}\K0$;\par
+\fi
+
+\M1314. \P$\X170:Initialize table entries (done by \.{INITEX} only)\X%
+\mathrel{+}\S$\6
+\&{if} $\\{ini\_version}$ \1\&{then}\5
+$\\{format\_ident}\K\.{"\ (INITEX)"}$;\2\par
+\fi
+
+\M1315. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\&{init} \37\&{procedure}\1\  \37\\{store\_fmt\_file};\6
+\4\&{label} \37$\\{found1},\39\\{found2},\39\\{done1},\39\\{done2}$;\6
+\4\&{var} \37$\|j,\39\|k,\39\|l$: \37\\{integer};\C{all-purpose indices}\6
+$\|p,\39\|q$: \37\\{pointer};\C{all-purpose pointers}\6
+\|x: \37\\{integer};\C{something to dump}\6
+\\{format\_engine}: \37$\^\\{text\_char}$;\2\6
+\&{begin} \37\X1317:If dumping is not allowed, abort\X;\6
+\X1341:Create the \\{format\_ident}, open the format file, and inform the user
+that dumping has begun\X;\6
+\X1320:Dump constants for consistency check\X;\6
+\X1414:Dump ML\TeX-specific data\X;\6
+\X1322:Dump the string pool\X;\6
+\X1324:Dump the dynamic memory\X;\6
+\X1326:Dump the table of equivalents\X;\6
+\X1333:Dump the font information\X;\6
+\X1337:Dump the hyphenation tables\X;\6
+\X1339:Dump a couple more things and the closing check word\X;\6
+\X1342:Close the format file\X;\6
+\&{end};\6
+\&{tini}\par
+\fi
+
+\M1316. Corresponding to the procedure that dumps a format file, we have a
+function
+that reads one in. The function returns \\{false} if the dumped format is
+incompatible with the present \TeX\ table sizes, etc.
+
+\Y\P\D \37$\\{bad\_fmt}=6666$\C{go here if the format file is unacceptable}\par
+\P\D \37$\\{too\_small}(\#)\S$\1\6
+\&{begin} \37\\{wake\_up\_terminal};\5
+$\\{wterm\_ln}(\.{\'---!\ Must\ increase\ the\ \'},\39\#)$;\5
+\&{goto} \37\\{bad\_fmt};\6
+\&{end}\2\par
+\Y\P\hbox{\4}\X535:Declare the function called \\{open\_fmt\_file}\X\6
+\4\&{function}\1\  \37\\{load\_fmt\_file}: \37\\{boolean};\6
+\4\&{label} \37$\\{bad\_fmt},\39\\{exit}$;\6
+\4\&{var} \37$\|j,\39\|k$: \37\\{integer};\C{all-purpose indices}\6
+$\|p,\39\|q$: \37\\{pointer};\C{all-purpose pointers}\6
+\|x: \37\\{integer};\C{something undumped}\6
+\\{format\_engine}: \37$\^\\{text\_char}$;\5
+\\{dummy\_xord}: \37\\{ASCII\_code};\5
+\\{dummy\_xchr}: \37\\{text\_char};\5
+\\{dummy\_xprn}: \37\\{ASCII\_code};\2\6
+\&{begin} \37\X1321:Undump constants for consistency check\X;\6
+\X1415:Undump ML\TeX-specific data\X;\6
+\X1323:Undump the string pool\X;\6
+\X1325:Undump the dynamic memory\X;\6
+\X1327:Undump the table of equivalents\X;\6
+\X1334:Undump the font information\X;\6
+\X1338:Undump the hyphenation tables\X;\6
+\X1340:Undump a couple more things and the closing check word\X;\6
+$\\{load\_fmt\_file}\K\\{true}$;\5
+\&{return};\C{it worked!}\6
+\4\\{bad\_fmt}: \37\\{wake\_up\_terminal};\5
+$\\{wterm\_ln}(\.{\'(Fatal\ format\ file\ error;\ I\'}\.{\'m\ stymied)\'})$;\5
+$\\{load\_fmt\_file}\K\\{false}$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1317. The user is not allowed to dump a format file unless $\\{save\_ptr}=0$.
+This condition implies that $\\{cur\_level}=\\{level\_one}$, hence
+the \\{xeq\_level} array is constant and it need not be dumped.
+
+\Y\P$\4\X1317:If dumping is not allowed, abort\X\S$\6
+\&{if} $\\{save\_ptr}\I0$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"You\ can\'t\ dump\ inside\ a\ group"})$;\5
+$\\{help1}(\.{"\`\{...\\dump\}\'\ is\ a\ no-no."})$;\5
+\\{succumb};\6
+\&{end}\2\par
+\U1315.\fi
+
+\M1318. Format files consist of \\{memory\_word} items, and we use the
+following
+macros to dump words of different types:
+
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{fmt\_file}: \37\\{word\_file};\C{for input or output of format
+information}\par
+\fi
+
+\M1319. The inverse macros are slightly more complicated, since we need to
+check
+the range of the values we are reading in. We say `$\\{undump}(\|a)(\|b)(\|x)$'
+to
+read an integer value \|x that is supposed to be in the range $\|a\L\|x\L\|b$.
+
+\Y\P\D \37$\\{undump\_end\_end}(\#)\S\#\K\|x$;\ \&{end} \par
+\P\D $\\{undump\_end}(\#)\S(\|x>\#)$ \&{then} \&{goto} \37\\{bad\_fmt}\ %
+\&{else} \37\\{undump\_end\_end}\par
+\P\D $\\{undump}(\#)\S$ \6
+\&{begin} \37$\\{undump\_int}(\|x)$;  \6
+\&{if} $(\|x<\#)\V\\{undump\_end}$\par
+\P\D \37$\\{format\_debug\_end}(\#)\S\\{write\_ln}(\\{stderr},\39\.{\'\ =\ \'},%
+\39\#)$; \6
+\&{end} ;\par
+\P\D $\\{format\_debug}(\#)\S$  \6
+\&{if} $\\{debug\_format\_file}$ \1\&{then} \6
+\&{begin} \37$\\{write}(\\{stderr},\39\.{\'fmtdebug:\'},\39\#)$;\5
+\\{format\_debug\_end}\par
+\P\D \37$\\{undump\_size\_end\_end}(\#)\S\\{too\_small}(\#)$\ \&{else} \37$%
+\\{format\_debug}(\#)(\|x)$;\5
+\\{undump\_end\_end}\par
+\P\D \37$\\{undump\_size\_end}(\#)\S$\1\6
+\&{if} $\|x>\#$ \1\&{then}\5
+\\{undump\_size\_end\_end}\2\2\par
+\P\D $\\{undump\_size}(\#)\S$ \6
+\&{begin} \37$\\{undump\_int}(\|x)$;\6
+\&{if} $\|x<\#$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+\\{undump\_size\_end}\par
+\fi
+
+\M1320. The next few sections of the program should make it clear how we use
+the
+dump/undump macros.
+
+\Y\P$\4\X1320:Dump constants for consistency check\X\S$\6
+$\\{dump\_int}(\H{57325458})$;\C{Web2C \TeX's magic constant: "W2TX"}\6
+\C{Align engine to 4 bytes with one or more trailing NUL}\6
+$\|x\K\\{strlen}(\\{engine\_name})$;\5
+$\\{format\_engine}\K\\{xmalloc\_array}(\\{text\_char},\39\|x+4)$;\5
+$\\{strcpy}(\\{stringcast}(\\{format\_engine}),\39\\{engine\_name})$;\6
+\&{for} $\|k\K\|x\mathrel{\&{to}}\|x+3$ \1\&{do}\5
+$\\{format\_engine}[\|k]\K0$;\2\6
+$\|x\K\|x+4-(\|x\mathbin{\&{mod}}4)$;\5
+$\\{dump\_int}(\|x)$;\5
+$\\{dump\_things}(\\{format\_engine}[0],\39\|x)$;\5
+$\\{libc\_free}(\\{format\_engine})$;\6
+$\\{dump\_int}(\))$;\6
+\X1400:Dump \\{xord}, \\{xchr}, and \\{xprn}\X;\6
+$\\{dump\_int}(\\{max\_halfword})$;\6
+$\\{dump\_int}(\\{hash\_high})$;\5
+$\\{dump\_int}(\\{mem\_bot})$;\6
+$\\{dump\_int}(\\{mem\_top})$;\6
+$\\{dump\_int}(\\{eqtb\_size})$;\6
+$\\{dump\_int}(\\{hash\_prime})$;\6
+$\\{dump\_int}(\\{hyph\_prime})$\par
+\U1315.\fi
+
+\M1321. Sections of a \.{WEB} program that are ``commented out'' still
+contribute
+strings to the string pool; therefore \.{INITEX} and \TeX\ will have
+the same strings. (And it is, of course, a good thing that they do.)
+
+\Y\P$\4\X1321:Undump constants for consistency check\X\S$\ \&{Init} \37$\\{libc%
+\_free}(\\{font\_info})$;\5
+$\\{libc\_free}(\\{str\_pool})$;\5
+$\\{libc\_free}(\\{str\_start})$;\5
+$\\{libc\_free}(\\{yhash})$;\5
+$\\{libc\_free}(\\{zeqtb})$;\5
+$\\{libc\_free}(\\{yzmem})$;\ \&{Tini}$\\{undump\_int}(\|x)$;\5
+$\\{format\_debug}(\.{\'format\ magic\ number\'})(\|x)$;\6
+\&{if} $\|x\I\H{57325458}$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\C{not a format file}\2\6
+$\\{undump\_int}(\|x)$;\5
+$\\{format\_debug}(\.{\'engine\ name\ size\'})(\|x)$;\6
+\&{if} $(\|x<0)\V(\|x>256)$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\C{corrupted format file}\2\6
+$\\{format\_engine}\K\\{xmalloc\_array}(\\{text\_char},\39\|x)$;\5
+$\\{undump\_things}(\\{format\_engine}[0],\39\|x)$;\5
+$\\{format\_engine}[\|x-1]\K0$;\C{force string termination, just in case}\6
+\&{if} $\\{strcmp}(\\{engine\_name},\39\\{stringcast}(\\{format\_engine}))$ \1%
+\&{then}\6
+\&{begin} \37\\{wake\_up\_terminal};\5
+$\\{wterm\_ln}(\.{\'---!\ \'},\39\\{stringcast}(\\{name\_of\_file}+1),\39\.{\'\
+was\ written\ by\ \'},\39\\{format\_engine})$;\5
+$\\{libc\_free}(\\{format\_engine})$;\5
+\&{goto} \37\\{bad\_fmt};\6
+\&{end};\2\6
+$\\{libc\_free}(\\{format\_engine})$;\5
+$\\{undump\_int}(\|x)$;\5
+$\\{format\_debug}(\.{\'string\ pool\ checksum\'})(\|x)$;\6
+\&{if} $\|x\I\)$ \1\&{then}\6
+\&{begin} \37\C{check that strings are the same}\6
+\\{wake\_up\_terminal};\5
+$\\{wterm\_ln}(\.{\'---!\ \'},\39\\{stringcast}(\\{name\_of\_file}+1),\39\.{\'\
+doesn\'}\.{\'t\ match\ \'},\39\\{pool\_name})$;\5
+\&{goto} \37\\{bad\_fmt};\6
+\&{end};\2\6
+\X1401:Undump \\{xord}, \\{xchr}, and \\{xprn}\X;\6
+$\\{undump\_int}(\|x)$;\6
+\&{if} $\|x\I\\{max\_halfword}$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\C{check \\{max\_halfword}}\2\6
+$\\{undump\_int}(\\{hash\_high})$;\6
+\&{if} $(\\{hash\_high}<0)\V(\\{hash\_high}>\\{sup\_hash\_extra})$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+\&{if} $\\{hash\_extra}<\\{hash\_high}$ \1\&{then}\5
+$\\{hash\_extra}\K\\{hash\_high}$;\2\6
+$\\{eqtb\_top}\K\\{eqtb\_size}+\\{hash\_extra}$;\6
+\&{if} $\\{hash\_extra}=0$ \1\&{then}\5
+$\\{hash\_top}\K\\{undefined\_control\_sequence}$\6
+\4\&{else} $\\{hash\_top}\K\\{eqtb\_top}$;\2\6
+$\\{yhash}\K\\{xmalloc\_array}(\\{two\_halves},\391+\\{hash\_top}-\\{hash%
+\_offset})$;\5
+$\\{hash}\K\\{yhash}-\\{hash\_offset}$;\5
+$\\{next}(\\{hash\_base})\K0$;\5
+$\\{text}(\\{hash\_base})\K0$;\6
+\&{for} $\|x\K\\{hash\_base}+1\mathrel{\&{to}}\\{hash\_top}$ \1\&{do}\5
+$\\{hash}[\|x]\K\\{hash}[\\{hash\_base}]$;\2\6
+$\\{zeqtb}\K\\{xmalloc\_array}(\\{memory\_word},\39\\{eqtb\_top}+1)$;\5
+$\\{eqtb}\K\\{zeqtb}$;\5
+$\\{eq\_type}(\\{undefined\_control\_sequence})\K\\{undefined\_cs}$;\5
+$\\{equiv}(\\{undefined\_control\_sequence})\K\\{null}$;\5
+$\\{eq\_level}(\\{undefined\_control\_sequence})\K\\{level\_zero}$;\6
+\&{for} $\|x\K\\{eqtb\_size}+1\mathrel{\&{to}}\\{eqtb\_top}$ \1\&{do}\5
+$\\{eqtb}[\|x]\K\\{eqtb}[\\{undefined\_control\_sequence}]$;\2\6
+$\\{undump\_int}(\|x)$;\5
+$\\{format\_debug}(\.{\'mem\_bot\'})(\|x)$;\6
+\&{if} $\|x\I\\{mem\_bot}$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+$\\{undump\_int}(\\{mem\_top})$;\5
+$\\{format\_debug}(\.{\'mem\_top\'})(\\{mem\_top})$;\6
+\&{if} $\\{mem\_bot}+1100>\\{mem\_top}$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+$\\{head}\K\\{contrib\_head}$;\5
+$\\{tail}\K\\{contrib\_head}$;\5
+$\\{page\_tail}\K\\{page\_head}$;\C{page initialization}\6
+$\\{mem\_min}\K\\{mem\_bot}-\\{extra\_mem\_bot}$;\5
+$\\{mem\_max}\K\\{mem\_top}+\\{extra\_mem\_top}$;\5
+$\\{yzmem}\K\\{xmalloc\_array}(\\{memory\_word},\39\\{mem\_max}-\\{mem%
+\_min}+1)$;\5
+$\\{zmem}\K\\{yzmem}-\\{mem\_min}$;\C{this pointer arithmetic fails with some
+compilers}\6
+$\\{mem}\K\\{zmem}$;\5
+$\\{undump\_int}(\|x)$;\6
+\&{if} $\|x\I\\{eqtb\_size}$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+$\\{undump\_int}(\|x)$;\6
+\&{if} $\|x\I\\{hash\_prime}$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+$\\{undump\_int}(\|x)$;\6
+\&{if} $\|x\I\\{hyph\_prime}$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt}\2\par
+\U1316.\fi
+
+\M1322. \P\D \37$\\{dump\_four\_ASCII}\S\|w.\\{b0}\K\\{qi}(\\{so}(\\{str%
+\_pool}[\|k]))$;\5
+$\|w.\\{b1}\K\\{qi}(\\{so}(\\{str\_pool}[\|k+1]))$;\5
+$\|w.\\{b2}\K\\{qi}(\\{so}(\\{str\_pool}[\|k+2]))$;\5
+$\|w.\\{b3}\K\\{qi}(\\{so}(\\{str\_pool}[\|k+3]))$;\5
+$\\{dump\_qqqq}(\|w)$\par
+\Y\P$\4\X1322:Dump the string pool\X\S$\6
+$\\{dump\_int}(\\{pool\_ptr})$;\5
+$\\{dump\_int}(\\{str\_ptr})$;\5
+$\\{dump\_things}(\\{str\_start}[0],\39\\{str\_ptr}+1)$;\5
+$\\{dump\_things}(\\{str\_pool}[0],\39\\{pool\_ptr})$;\5
+\\{print\_ln};\5
+$\\{print\_int}(\\{str\_ptr})$;\5
+$\\{print}(\.{"\ strings\ of\ total\ length\ "})$;\5
+$\\{print\_int}(\\{pool\_ptr})$\par
+\U1315.\fi
+
+\M1323. \P\D \37$\\{undump\_four\_ASCII}\S\\{undump\_qqqq}(\|w)$;\5
+$\\{str\_pool}[\|k]\K\\{si}(\\{qo}(\|w.\\{b0}))$;\5
+$\\{str\_pool}[\|k+1]\K\\{si}(\\{qo}(\|w.\\{b1}))$;\5
+$\\{str\_pool}[\|k+2]\K\\{si}(\\{qo}(\|w.\\{b2}))$;\5
+$\\{str\_pool}[\|k+3]\K\\{si}(\\{qo}(\|w.\\{b3}))$\par
+\Y\P$\4\X1323:Undump the string pool\X\S$\6
+$\\{undump\_size}(0)(\\{sup\_pool\_size}-\\{pool\_free})(\.{\'string\ pool\
+size\'})(\\{pool\_ptr})$;\6
+\&{if} $\\{pool\_size}<\\{pool\_ptr}+\\{pool\_free}$ \1\&{then}\5
+$\\{pool\_size}\K\\{pool\_ptr}+\\{pool\_free}$;\2\6
+$\\{undump\_size}(0)(\\{sup\_max\_strings}-\\{strings\_free})(\.{\'sup\ strings%
+\'})(\\{str\_ptr})$;\6
+\&{if} $\\{max\_strings}<\\{str\_ptr}+\\{strings\_free}$ \1\&{then}\5
+$\\{max\_strings}\K\\{str\_ptr}+\\{strings\_free}$;\2\6
+$\\{str\_start}\K\\{xmalloc\_array}(\\{pool\_pointer},\39\\{max\_strings})$;\5
+$\\{undump\_checked\_things}(0,\39\\{pool\_ptr},\39\\{str\_start}[0],\39\\{str%
+\_ptr}+1)$;\6
+$\\{str\_pool}\K\\{xmalloc\_array}(\\{packed\_ASCII\_code},\39\\{pool\_size})$;%
+\5
+$\\{undump\_things}(\\{str\_pool}[0],\39\\{pool\_ptr})$;\5
+$\\{init\_str\_ptr}\K\\{str\_ptr}$;\5
+$\\{init\_pool\_ptr}\K\\{pool\_ptr}$\par
+\U1316.\fi
+
+\M1324. By sorting the list of available spaces in the variable-size portion of
+\\{mem}, we are usually able to get by without having to dump very much
+of the dynamic memory.
+
+We recompute \\{var\_used} and \\{dyn\_used}, so that \.{INITEX} dumps valid
+information even when it has not been gathering statistics.
+
+\Y\P$\4\X1324:Dump the dynamic memory\X\S$\6
+\\{sort\_avail};\5
+$\\{var\_used}\K0$;\5
+$\\{dump\_int}(\\{lo\_mem\_max})$;\5
+$\\{dump\_int}(\\{rover})$;\5
+$\|p\K\\{mem\_bot}$;\5
+$\|q\K\\{rover}$;\5
+$\|x\K0$;\6
+\1\&{repeat} \37$\\{dump\_things}(\\{mem}[\|p],\39\|q+2-\|p)$;\5
+$\|x\K\|x+\|q+2-\|p$;\5
+$\\{var\_used}\K\\{var\_used}+\|q-\|p$;\5
+$\|p\K\|q+\\{node\_size}(\|q)$;\5
+$\|q\K\\{rlink}(\|q)$;\6
+\4\&{until}\5
+$\|q=\\{rover}$;\2\6
+$\\{var\_used}\K\\{var\_used}+\\{lo\_mem\_max}-\|p$;\5
+$\\{dyn\_used}\K\\{mem\_end}+1-\\{hi\_mem\_min}$;\6
+$\\{dump\_things}(\\{mem}[\|p],\39\\{lo\_mem\_max}+1-\|p)$;\5
+$\|x\K\|x+\\{lo\_mem\_max}+1-\|p$;\5
+$\\{dump\_int}(\\{hi\_mem\_min})$;\5
+$\\{dump\_int}(\\{avail})$;\5
+$\\{dump\_things}(\\{mem}[\\{hi\_mem\_min}],\39\\{mem\_end}+1-\\{hi\_mem%
+\_min})$;\5
+$\|x\K\|x+\\{mem\_end}+1-\\{hi\_mem\_min}$;\5
+$\|p\K\\{avail}$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\\{dyn\_used})$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+$\\{dump\_int}(\\{var\_used})$;\5
+$\\{dump\_int}(\\{dyn\_used})$;\5
+\\{print\_ln};\5
+$\\{print\_int}(\|x)$;\5
+$\\{print}(\.{"\ memory\ locations\ dumped;\ current\ usage\ is\ "})$;\5
+$\\{print\_int}(\\{var\_used})$;\5
+$\\{print\_char}(\.{"\&"})$;\5
+$\\{print\_int}(\\{dyn\_used})$\par
+\U1315.\fi
+
+\M1325. \P$\X1325:Undump the dynamic memory\X\S$\6
+$\\{undump}(\\{lo\_mem\_stat\_max}+1000)(\\{hi\_mem\_stat\_min}-1)(\\{lo\_mem%
+\_max})$;\5
+$\\{undump}(\\{lo\_mem\_stat\_max}+1)(\\{lo\_mem\_max})(\\{rover})$;\5
+$\|p\K\\{mem\_bot}$;\5
+$\|q\K\\{rover}$;\6
+\1\&{repeat} \37$\\{undump\_things}(\\{mem}[\|p],\39\|q+2-\|p)$;\5
+$\|p\K\|q+\\{node\_size}(\|q)$;\6
+\&{if} $(\|p>\\{lo\_mem\_max})\V((\|q\G\\{rlink}(\|q))\W(\\{rlink}(\|q)\I%
+\\{rover}))$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+$\|q\K\\{rlink}(\|q)$;\6
+\4\&{until}\5
+$\|q=\\{rover}$;\2\6
+$\\{undump\_things}(\\{mem}[\|p],\39\\{lo\_mem\_max}+1-\|p)$;\6
+\&{if} $\\{mem\_min}<\\{mem\_bot}-2$ \1\&{then}\C{make more low memory
+available}\6
+\&{begin} \37$\|p\K\\{llink}(\\{rover})$;\5
+$\|q\K\\{mem\_min}+1$;\5
+$\\{link}(\\{mem\_min})\K\\{null}$;\5
+$\\{info}(\\{mem\_min})\K\\{null}$;\C{we don't use the bottom word}\6
+$\\{rlink}(\|p)\K\|q$;\5
+$\\{llink}(\\{rover})\K\|q$;\6
+$\\{rlink}(\|q)\K\\{rover}$;\5
+$\\{llink}(\|q)\K\|p$;\5
+$\\{link}(\|q)\K\\{empty\_flag}$;\5
+$\\{node\_size}(\|q)\K\\{mem\_bot}-\|q$;\6
+\&{end};\2\6
+$\\{undump}(\\{lo\_mem\_max}+1)(\\{hi\_mem\_stat\_min})(\\{hi\_mem\_min})$;\5
+$\\{undump}(\\{null})(\\{mem\_top})(\\{avail})$;\5
+$\\{mem\_end}\K\\{mem\_top}$;\5
+$\\{undump\_things}(\\{mem}[\\{hi\_mem\_min}],\39\\{mem\_end}+1-\\{hi\_mem%
+\_min})$;\5
+$\\{undump\_int}(\\{var\_used})$;\5
+$\\{undump\_int}(\\{dyn\_used})$\par
+\U1316.\fi
+
+\M1326. \P$\X1326:Dump the table of equivalents\X\S$\6
+\X1328:Dump regions 1 to 4 of \\{eqtb}\X;\6
+\X1329:Dump regions 5 and 6 of \\{eqtb}\X;\6
+$\\{dump\_int}(\\{par\_loc})$;\5
+$\\{dump\_int}(\\{write\_loc})$;\6
+\X1331:Dump the hash table\X\par
+\U1315.\fi
+
+\M1327. \P$\X1327:Undump the table of equivalents\X\S$\6
+\X1330:Undump regions 1 to 6 of \\{eqtb}\X;\6
+$\\{undump}(\\{hash\_base})(\\{hash\_top})(\\{par\_loc})$;\5
+$\\{par\_token}\K\\{cs\_token\_flag}+\\{par\_loc}$;\6
+$\\{undump}(\\{hash\_base})(\\{hash\_top})(\\{write\_loc})$;\6
+\X1332:Undump the hash table\X\par
+\U1316.\fi
+
+\M1328. The table of equivalents usually contains repeated information, so we
+dump it
+in compressed form: The sequence of $n+2$ values $(n,x_1,\ldots,x_n,m)$ in the
+format file represents $n+m$ consecutive entries of \\{eqtb}, with \|m extra
+copies of $x_n$, namely $(x_1,\ldots,x_n,x_n,\ldots,x_n)$.
+
+\Y\P$\4\X1328:Dump regions 1 to 4 of \\{eqtb}\X\S$\6
+$\|k\K\\{active\_base}$;\6
+\1\&{repeat} \37$\|j\K\|k$;\6
+\&{while} $\|j<\\{int\_base}-1$ \1\&{do}\6
+\&{begin} \37\&{if} $(\\{equiv}(\|j)=\\{equiv}(\|j+1))\W(\\{eq\_type}(\|j)=%
+\\{eq\_type}(\|j+1))\W\30(\\{eq\_level}(\|j)=\\{eq\_level}(\|j+1))$ \1\&{then}\5
+\&{goto} \37\\{found1};\2\6
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+$\|l\K\\{int\_base}$;\5
+\&{goto} \37\\{done1};\C{$\|j=\\{int\_base}-1$}\6
+\4\\{found1}: \37$\\{incr}(\|j)$;\5
+$\|l\K\|j$;\6
+\&{while} $\|j<\\{int\_base}-1$ \1\&{do}\6
+\&{begin} \37\&{if} $(\\{equiv}(\|j)\I\\{equiv}(\|j+1))\V(\\{eq\_type}(\|j)\I%
+\\{eq\_type}(\|j+1))\V\30(\\{eq\_level}(\|j)\I\\{eq\_level}(\|j+1))$ \1\&{then}%
+\5
+\&{goto} \37\\{done1};\2\6
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+\4\\{done1}: \37$\\{dump\_int}(\|l-\|k)$;\5
+$\\{dump\_things}(\\{eqtb}[\|k],\39\|l-\|k)$;\5
+$\|k\K\|j+1$;\5
+$\\{dump\_int}(\|k-\|l)$;\6
+\4\&{until}\5
+$\|k=\\{int\_base}$\2\par
+\U1326.\fi
+
+\M1329. \P$\X1329:Dump regions 5 and 6 of \\{eqtb}\X\S$\6
+\1\&{repeat} \37$\|j\K\|k$;\6
+\&{while} $\|j<\\{eqtb\_size}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{eqtb}[\|j].\\{int}=\\{eqtb}[\|j+1].\\{int}$ \1\&{then}\5
+\&{goto} \37\\{found2};\2\6
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+$\|l\K\\{eqtb\_size}+1$;\5
+\&{goto} \37\\{done2};\C{$\|j=\\{eqtb\_size}$}\6
+\4\\{found2}: \37$\\{incr}(\|j)$;\5
+$\|l\K\|j$;\6
+\&{while} $\|j<\\{eqtb\_size}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{eqtb}[\|j].\\{int}\I\\{eqtb}[\|j+1].\\{int}$ \1\&{then}%
+\5
+\&{goto} \37\\{done2};\2\6
+$\\{incr}(\|j)$;\6
+\&{end};\2\6
+\4\\{done2}: \37$\\{dump\_int}(\|l-\|k)$;\5
+$\\{dump\_things}(\\{eqtb}[\|k],\39\|l-\|k)$;\5
+$\|k\K\|j+1$;\5
+$\\{dump\_int}(\|k-\|l)$;\6
+\4\&{until}\5
+$\|k>\\{eqtb\_size}$;\2\6
+\&{if} $\\{hash\_high}>0$ \1\&{then}\5
+$\\{dump\_things}(\\{eqtb}[\\{eqtb\_size}+1],\39\\{hash\_high})$;\C{dump %
+\\{hash\_extra} part}\2\par
+\U1326.\fi
+
+\M1330. \P$\X1330:Undump regions 1 to 6 of \\{eqtb}\X\S$\6
+$\|k\K\\{active\_base}$;\6
+\1\&{repeat} \37$\\{undump\_int}(\|x)$;\6
+\&{if} $(\|x<1)\V(\|k+\|x>\\{eqtb\_size}+1)$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+$\\{undump\_things}(\\{eqtb}[\|k],\39\|x)$;\5
+$\|k\K\|k+\|x$;\5
+$\\{undump\_int}(\|x)$;\6
+\&{if} $(\|x<0)\V(\|k+\|x>\\{eqtb\_size}+1)$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+\&{for} $\|j\K\|k\mathrel{\&{to}}\|k+\|x-1$ \1\&{do}\5
+$\\{eqtb}[\|j]\K\\{eqtb}[\|k-1]$;\2\6
+$\|k\K\|k+\|x$;\6
+\4\&{until}\5
+$\|k>\\{eqtb\_size}$;\2\6
+\&{if} $\\{hash\_high}>0$ \1\&{then}\5
+$\\{undump\_things}(\\{eqtb}[\\{eqtb\_size}+1],\39\\{hash\_high})$;\C{undump %
+\\{hash\_extra} part}\2\par
+\U1327.\fi
+
+\M1331. A different scheme is used to compress the hash table, since its lower
+region is usually sparse. When $\\{text}(\|p)\I0$ for $\|p\L\\{hash\_used}$, we
+output
+two words, \|p and $\\{hash}[\|p]$. The hash table is, of course, densely
+packed
+for $\|p\G\\{hash\_used}$, so the remaining entries are output in a~block.
+
+\Y\P$\4\X1331:Dump the hash table\X\S$\6
+$\\{dump\_int}(\\{hash\_used})$;\5
+$\\{cs\_count}\K\\{frozen\_control\_sequence}-1-\\{hash\_used}+\\{hash\_high}$;%
+\6
+\&{for} $\|p\K\\{hash\_base}\mathrel{\&{to}}\\{hash\_used}$ \1\&{do}\6
+\&{if} $\\{text}(\|p)\I0$ \1\&{then}\6
+\&{begin} \37$\\{dump\_int}(\|p)$;\5
+$\\{dump\_hh}(\\{hash}[\|p])$;\5
+$\\{incr}(\\{cs\_count})$;\6
+\&{end};\2\2\6
+$\\{dump\_things}(\\{hash}[\\{hash\_used}+1],\39\\{undefined\_control%
+\_sequence}-1-\\{hash\_used})$;\6
+\&{if} $\\{hash\_high}>0$ \1\&{then}\5
+$\\{dump\_things}(\\{hash}[\\{eqtb\_size}+1],\39\\{hash\_high})$;\2\6
+$\\{dump\_int}(\\{cs\_count})$;\6
+\\{print\_ln};\5
+$\\{print\_int}(\\{cs\_count})$;\5
+$\\{print}(\.{"\ multiletter\ control\ sequences"})$\par
+\U1326.\fi
+
+\M1332. \P$\X1332:Undump the hash table\X\S$\6
+$\\{undump}(\\{hash\_base})(\\{frozen\_control\_sequence})(\\{hash\_used})$;\5
+$\|p\K\\{hash\_base}-1$;\6
+\1\&{repeat} \37$\\{undump}(\|p+1)(\\{hash\_used})(\|p)$;\5
+$\\{undump\_hh}(\\{hash}[\|p])$;\6
+\4\&{until}\5
+$\|p=\\{hash\_used}$;\2\6
+$\\{undump\_things}(\\{hash}[\\{hash\_used}+1],\39\\{undefined\_control%
+\_sequence}-1-\\{hash\_used})$;\6
+\&{if} $\\{debug\_format\_file}$ \1\&{then}\6
+\&{begin} \37$\\{print\_csnames}(\\{hash\_base},\39\\{undefined\_control%
+\_sequence}-1)$;\6
+\&{end};\2\6
+\&{if} $\\{hash\_high}>0$ \1\&{then}\6
+\&{begin} \37$\\{undump\_things}(\\{hash}[\\{eqtb\_size}+1],\39\\{hash%
+\_high})$;\6
+\&{if} $\\{debug\_format\_file}$ \1\&{then}\6
+\&{begin} \37$\\{print\_csnames}(\\{eqtb\_size}+1,\39\\{hash\_high}-(\\{eqtb%
+\_size}+1))$;\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{undump\_int}(\\{cs\_count})$\par
+\U1327.\fi
+
+\M1333. \P$\X1333:Dump the font information\X\S$\6
+$\\{dump\_int}(\\{fmem\_ptr})$;\5
+$\\{dump\_things}(\\{font\_info}[0],\39\\{fmem\_ptr})$;\5
+$\\{dump\_int}(\\{font\_ptr})$;\5
+\X1335:Dump the array info for internal font number \|k\X;\6
+\\{print\_ln};\5
+$\\{print\_int}(\\{fmem\_ptr}-7)$;\5
+$\\{print}(\.{"\ words\ of\ font\ info\ for\ "})$;\5
+$\\{print\_int}(\\{font\_ptr}-\\{font\_base})$;\6
+\&{if} $\\{font\_ptr}\I\\{font\_base}+1$ \1\&{then}\5
+$\\{print}(\.{"\ preloaded\ fonts"})$\6
+\4\&{else} $\\{print}(\.{"\ preloaded\ font"})$\2\par
+\U1315.\fi
+
+\M1334. \P$\X1334:Undump the font information\X\S$\6
+$\\{undump\_size}(7)(\\{sup\_font\_mem\_size})(\.{\'font\ mem\ size\'})(\\{fmem%
+\_ptr})$;\6
+\&{if} $\\{fmem\_ptr}>\\{font\_mem\_size}$ \1\&{then}\5
+$\\{font\_mem\_size}\K\\{fmem\_ptr}$;\2\6
+$\\{font\_info}\K\\{xmalloc\_array}(\\{memory\_word},\39\\{font\_mem\_size})$;\5
+$\\{undump\_things}(\\{font\_info}[0],\39\\{fmem\_ptr})$;\6
+$\\{undump\_size}(\\{font\_base})(\\{font\_base}+\\{max\_font\_max})(\.{\'font\
+max\'})(\\{font\_ptr})$;\C{This undumps all of the font info, despite the
+name.}\6
+\X1336:Undump the array info for internal font number \|k\X;\par
+\U1316.\fi
+
+\M1335. \P$\X1335:Dump the array info for internal font number \|k\X\S$\6
+\&{begin} \37$\\{dump\_things}(\\{font\_dir}[\\{null\_font}],\39\\{font%
+\_ptr}+1-\\{null\_font})$;\5
+$\\{dump\_things}(\\{font\_num\_ext}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_check}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_size}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_dsize}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_params}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{hyphen\_char}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{skew\_char}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_name}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_area}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_bc}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_ec}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{ctype\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{char\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{width\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{height\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{depth\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{italic\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{lig\_kern\_base}[\\{null\_font}],\39\\{font\_ptr}+1-%
+\\{null\_font})$;\5
+$\\{dump\_things}(\\{kern\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{exten\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{param\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_glue}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{bchar\_label}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_bchar}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{dump\_things}(\\{font\_false\_bchar}[\\{null\_font}],\39\\{font\_ptr}+1-%
+\\{null\_font})$;\6
+\&{for} $\|k\K\\{null\_font}\mathrel{\&{to}}\\{font\_ptr}$ \1\&{do}\6
+\&{begin} \37$\\{print\_nl}(\.{"\\font"})$;\5
+$\\{print\_esc}(\\{font\_id\_text}(\|k))$;\5
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_file\_name}(\\{font\_name}[\|k],\39\\{font\_area}[\|k],\39\.{""})$;\6
+\&{if} $\\{font\_size}[\|k]\I\\{font\_dsize}[\|k]$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ at\ "})$;\5
+$\\{print\_scaled}(\\{font\_size}[\|k])$;\5
+$\\{print}(\.{"pt"})$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end}\par
+\U1333.\fi
+
+\M1336. This module should now be named `Undump all the font arrays'.
+
+\Y\P$\4\X1336:Undump the array info for internal font number \|k\X\S$\6
+\&{begin} \37\C{Allocate the font arrays}\6
+$\\{font\_dir}\K\\{xmalloc\_array}(\\{eight\_bits},\39\\{font\_max})$;\5
+$\\{font\_num\_ext}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{font\_check}\K\\{xmalloc\_array}(\\{four\_quarters},\39\\{font\_max})$;\5
+$\\{font\_size}\K\\{xmalloc\_array}(\\{scaled},\39\\{font\_max})$;\5
+$\\{font\_dsize}\K\\{xmalloc\_array}(\\{scaled},\39\\{font\_max})$;\5
+$\\{font\_params}\K\\{xmalloc\_array}(\\{font\_index},\39\\{font\_max})$;\5
+$\\{font\_name}\K\\{xmalloc\_array}(\\{str\_number},\39\\{font\_max})$;\5
+$\\{font\_area}\K\\{xmalloc\_array}(\\{str\_number},\39\\{font\_max})$;\5
+$\\{font\_bc}\K\\{xmalloc\_array}(\\{eight\_bits},\39\\{font\_max})$;\5
+$\\{font\_ec}\K\\{xmalloc\_array}(\\{eight\_bits},\39\\{font\_max})$;\5
+$\\{font\_glue}\K\\{xmalloc\_array}(\\{halfword},\39\\{font\_max})$;\5
+$\\{hyphen\_char}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{skew\_char}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{bchar\_label}\K\\{xmalloc\_array}(\\{font\_index},\39\\{font\_max})$;\5
+$\\{font\_bchar}\K\\{xmalloc\_array}(\\{nine\_bits},\39\\{font\_max})$;\5
+$\\{font\_false\_bchar}\K\\{xmalloc\_array}(\\{nine\_bits},\39\\{font\_max})$;\5
+$\\{ctype\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{char\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{width\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{height\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{depth\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{italic\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{lig\_kern\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{kern\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{exten\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{param\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{undump\_things}(\\{font\_dir}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{font\_num\_ext}[\\{null\_font}],\39\\{font\_ptr}+1-%
+\\{null\_font})$;\5
+$\\{undump\_things}(\\{font\_check}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{font\_size}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{font\_dsize}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_checked\_things}(\\{min\_halfword},\39\\{max\_halfword},\39\\{font%
+\_params}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null\_font})$;\5
+$\\{undump\_things}(\\{hyphen\_char}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{skew\_char}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_upper\_check\_things}(\\{str\_ptr},\39\\{font\_name}[\\{null%
+\_font}],\39\\{font\_ptr}+1-\\{null\_font})$;\5
+$\\{undump\_upper\_check\_things}(\\{str\_ptr},\39\\{font\_area}[\\{null%
+\_font}],\39\\{font\_ptr}+1-\\{null\_font})$;\C{There's no point in checking
+these values against the range $[0,255]$,  since the data type is \\{unsigned}%
+\\{char}, and all values of that type are  in that range by definition.}\6
+$\\{undump\_things}(\\{font\_bc}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{font\_ec}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{ctype\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{char\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{width\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{height\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{depth\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{italic\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{lig\_kern\_base}[\\{null\_font}],\39\\{font\_ptr}+1-%
+\\{null\_font})$;\5
+$\\{undump\_things}(\\{kern\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{exten\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_things}(\\{param\_base}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null%
+\_font})$;\5
+$\\{undump\_checked\_things}(\\{min\_halfword},\39\\{lo\_mem\_max},\39\\{font%
+\_glue}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null\_font})$;\5
+$\\{undump\_checked\_things}(0,\39\\{fmem\_ptr}-1,\39\\{bchar\_label}[\\{null%
+\_font}],\39\\{font\_ptr}+1-\\{null\_font})$;\5
+$\\{undump\_checked\_things}(\\{min\_quarterword},\39\\{non\_char},\39\\{font%
+\_bchar}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null\_font})$;\5
+$\\{undump\_checked\_things}(\\{min\_quarterword},\39\\{non\_char},\39\\{font%
+\_false\_bchar}[\\{null\_font}],\39\\{font\_ptr}+1-\\{null\_font})$;\6
+\&{end}\par
+\U1334.\fi
+
+\M1337. \P$\X1337:Dump the hyphenation tables\X\S$\6
+$\\{dump\_int}(\\{hyph\_count})$;\6
+\&{if} $\\{hyph\_next}\L\\{hyph\_prime}$ \1\&{then}\5
+$\\{hyph\_next}\K\\{hyph\_size}$;\2\6
+$\\{dump\_int}(\\{hyph\_next})$;\C{minumum value of \\{hyphen\_size} needed}\6
+\&{for} $\|k\K0\mathrel{\&{to}}\\{hyph\_size}$ \1\&{do}\6
+\&{if} $\\{hyph\_word}[\|k]\I0$ \1\&{then}\6
+\&{begin} \37$\\{dump\_int}(\|k+65536\ast\\{hyph\_link}[\|k])$;\C{assumes
+number of hyphen exceptions does not exceed 65535}\6
+$\\{dump\_int}(\\{hyph\_word}[\|k])$;\5
+$\\{dump\_int}(\\{hyph\_list}[\|k])$;\6
+\&{end};\2\2\6
+\\{print\_ln};\5
+$\\{print\_int}(\\{hyph\_count})$;\6
+\&{if} $\\{hyph\_count}\I1$ \1\&{then}\5
+$\\{print}(\.{"\ hyphenation\ exceptions"})$\6
+\4\&{else} $\\{print}(\.{"\ hyphenation\ exception"})$;\2\6
+\&{if} $\\{trie\_not\_ready}$ \1\&{then}\5
+\\{init\_trie};\2\6
+$\\{dump\_int}(\\{trie\_max})$;\5
+$\\{dump\_things}(\\{trie\_trl}[0],\39\\{trie\_max}+1)$;\5
+$\\{dump\_things}(\\{trie\_tro}[0],\39\\{trie\_max}+1)$;\5
+$\\{dump\_things}(\\{trie\_trc}[0],\39\\{trie\_max}+1)$;\5
+$\\{dump\_int}(\\{trie\_op\_ptr})$;\5
+$\\{dump\_things}(\\{hyf\_distance}[1],\39\\{trie\_op\_ptr})$;\5
+$\\{dump\_things}(\\{hyf\_num}[1],\39\\{trie\_op\_ptr})$;\5
+$\\{dump\_things}(\\{hyf\_next}[1],\39\\{trie\_op\_ptr})$;\5
+$\\{print\_nl}(\.{"Hyphenation\ trie\ of\ length\ "})$;\5
+$\\{print\_int}(\\{trie\_max})$;\5
+$\\{print}(\.{"\ has\ "})$;\5
+$\\{print\_int}(\\{trie\_op\_ptr})$;\6
+\&{if} $\\{trie\_op\_ptr}\I1$ \1\&{then}\5
+$\\{print}(\.{"\ ops"})$\6
+\4\&{else} $\\{print}(\.{"\ op"})$;\2\6
+$\\{print}(\.{"\ out\ of\ "})$;\5
+$\\{print\_int}(\\{trie\_op\_size})$;\6
+\&{for} $\|k\K255\mathrel{\&{downto}}0$ \1\&{do}\6
+\&{if} $\\{trie\_used}[\|k]>\\{min\_quarterword}$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"\ \ "})$;\5
+$\\{print\_int}(\\{qo}(\\{trie\_used}[\|k]))$;\5
+$\\{print}(\.{"\ for\ language\ "})$;\5
+$\\{print\_int}(\|k)$;\5
+$\\{dump\_int}(\|k)$;\5
+$\\{dump\_int}(\\{qo}(\\{trie\_used}[\|k]))$;\6
+\&{end}\2\2\par
+\U1315.\fi
+
+\M1338. Only ``nonempty'' parts of \\{op\_start} need to be restored.
+
+\Y\P$\4\X1338:Undump the hyphenation tables\X\S$\6
+$\\{undump\_size}(0)(\\{hyph\_size})(\.{\'hyph\_size\'})(\\{hyph\_count})$;\5
+$\\{undump\_size}(\\{hyph\_prime})(\\{hyph\_size})(\.{\'hyph\_size\'})(\\{hyph%
+\_next})$;\5
+$\|j\K0$;\6
+\&{for} $\|k\K1\mathrel{\&{to}}\\{hyph\_count}$ \1\&{do}\6
+\&{begin} \37$\\{undump\_int}(\|j)$;\6
+\&{if} $\|j<0$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+\&{if} $\|j>65535$ \1\&{then}\6
+\&{begin} \37$\\{hyph\_next}\K\|j\mathbin{\&{div}}65536$;\5
+$\|j\K\|j-\\{hyph\_next}\ast65536$;\6
+\&{end}\6
+\4\&{else} $\\{hyph\_next}\K0$;\2\6
+\&{if} $(\|j\G\\{hyph\_size})\V(\\{hyph\_next}>\\{hyph\_size})$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+$\\{hyph\_link}[\|j]\K\\{hyph\_next}$;\5
+$\\{undump}(0)(\\{str\_ptr})(\\{hyph\_word}[\|j])$;\5
+$\\{undump}(\\{min\_halfword})(\\{max\_halfword})(\\{hyph\_list}[\|j])$;\6
+\&{end};\C{\|j is now the largest occupied location in \\{hyph\_word}}\2\6
+$\\{incr}(\|j)$;\6
+\&{if} $\|j<\\{hyph\_prime}$ \1\&{then}\5
+$\|j\K\\{hyph\_prime}$;\2\6
+$\\{hyph\_next}\K\|j$;\6
+\&{if} $\\{hyph\_next}\G\\{hyph\_size}$ \1\&{then}\5
+$\\{hyph\_next}\K\\{hyph\_prime}$\6
+\4\&{else} \&{if} $\\{hyph\_next}\G\\{hyph\_prime}$ \1\&{then}\5
+$\\{incr}(\\{hyph\_next})$;\2\2\6
+$\\{undump\_size}(0)(\\{trie\_size})(\.{\'trie\ size\'})(\|j)$;\ \&{init} \37$%
+\\{trie\_max}\K\|j$;\ \&{tini}\C{These first three haven't been allocated yet
+unless we're \.{INITEX};  we do that precisely so we don't allocate more space
+than necessary.}\6
+\&{if} $\R\\{trie\_trl}$ \1\&{then}\5
+$\\{trie\_trl}\K\\{xmalloc\_array}(\\{trie\_pointer},\39\|j+1)$;\2\6
+$\\{undump\_things}(\\{trie\_trl}[0],\39\|j+1)$;\6
+\&{if} $\R\\{trie\_tro}$ \1\&{then}\5
+$\\{trie\_tro}\K\\{xmalloc\_array}(\\{trie\_pointer},\39\|j+1)$;\2\6
+$\\{undump\_things}(\\{trie\_tro}[0],\39\|j+1)$;\6
+\&{if} $\R\\{trie\_trc}$ \1\&{then}\5
+$\\{trie\_trc}\K\\{xmalloc\_array}(\\{quarterword},\39\|j+1)$;\2\6
+$\\{undump\_things}(\\{trie\_trc}[0],\39\|j+1)$;\5
+$\\{undump\_size}(0)(\\{trie\_op\_size})(\.{\'trie\ op\ size\'})(\|j)$;\ %
+\&{init} \37$\\{trie\_op\_ptr}\K\|j$;\ \&{tini}\C{I'm not sure we have such a
+strict limitation (64) on these values, so  let's leave them unchecked.}\6
+$\\{undump\_things}(\\{hyf\_distance}[1],\39\|j)$;\5
+$\\{undump\_things}(\\{hyf\_num}[1],\39\|j)$;\5
+$\\{undump\_upper\_check\_things}(\\{max\_trie\_op},\39\\{hyf\_next}[1],\39%
+\|j)$;\6
+\&{init} \37\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{trie\_used}[\|k]\K\\{min\_quarterword}$;\ \2\6
+\&{tini}\6
+$\|k\K256$;\6
+\&{while} $\|j>0$ \1\&{do}\6
+\&{begin} \37$\\{undump}(0)(\|k-1)(\|k)$;\5
+$\\{undump}(1)(\|j)(\|x)$;\ \&{init} \37$\\{trie\_used}[\|k]\K\\{qi}(\|x)$;\ %
+\&{tini}\6
+$\|j\K\|j-\|x$;\5
+$\\{op\_start}[\|k]\K\\{qo}(\|j)$;\6
+\&{end};\2\6
+\&{init} \37$\\{trie\_not\_ready}\K\\{false}$\ \&{tini}\par
+\U1316.\fi
+
+\M1339. We have already printed a lot of statistics, so we set $\\{tracing%
+\_stats}\K0$
+to prevent them from appearing again.
+
+\Y\P$\4\X1339:Dump a couple more things and the closing check word\X\S$\6
+$\\{dump\_int}(\\{interaction})$;\5
+$\\{dump\_int}(\\{format\_ident})$;\5
+$\\{dump\_int}(69069)$;\5
+$\\{tracing\_stats}\K0$\par
+\U1315.\fi
+
+\M1340. \P$\X1340:Undump a couple more things and the closing check word\X\S$\6
+$\\{undump}(\\{batch\_mode})(\\{error\_stop\_mode})(\\{interaction})$;\6
+\&{if} $\\{interaction\_option}\I\\{unspecified\_mode}$ \1\&{then}\5
+$\\{interaction}\K\\{interaction\_option}$;\2\6
+$\\{undump}(0)(\\{str\_ptr})(\\{format\_ident})$;\5
+$\\{undump\_int}(\|x)$;\6
+\&{if} $\|x\I69069$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt}\2\par
+\U1316.\fi
+
+\M1341. \P$\X1341:Create the \\{format\_ident}, open the format file, and
+inform the user that dumping has begun\X\S$\6
+$\\{selector}\K\\{new\_string}$;\5
+$\\{print}(\.{"\ (format="})$;\5
+$\\{print}(\\{job\_name})$;\5
+$\\{print\_char}(\.{"\ "})$;\5
+$\\{print\_int}(\\{year})$;\5
+$\\{print\_char}(\.{"."})$;\5
+$\\{print\_int}(\\{month})$;\5
+$\\{print\_char}(\.{"."})$;\5
+$\\{print\_int}(\\{day})$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{if} $\\{interaction}=\\{batch\_mode}$ \1\&{then}\5
+$\\{selector}\K\\{log\_only}$\6
+\4\&{else} $\\{selector}\K\\{term\_and\_log}$;\2\6
+$\\{str\_room}(1)$;\5
+$\\{format\_ident}\K\\{make\_string}$;\5
+$\\{pack\_job\_name}(\\{format\_extension})$;\6
+\&{while} $\R\\{w\_open\_out}(\\{fmt\_file})$ \1\&{do}\5
+$\\{prompt\_file\_name}(\.{"format\ file\ name"},\39\\{format\_extension})$;\2\6
+$\\{print\_nl}(\.{"Beginning\ to\ dump\ on\ file\ "})$;\5
+$\\{slow\_print}(\\{w\_make\_name\_string}(\\{fmt\_file}))$;\5
+\\{flush\_string};\5
+$\\{print\_nl}(\.{""})$;\5
+$\\{slow\_print}(\\{format\_ident})$\par
+\U1315.\fi
+
+\M1342. \P$\X1342:Close the format file\X\S$\6
+$\\{w\_close}(\\{fmt\_file})$\par
+\U1315.\fi
+
+\N1343.  \[51] The main program.
+This is it: the part of \TeX\ that executes all those procedures we have
+written.
+
+Well---almost. Let's leave space for a few more routines that we may
+have forgotten.
+
+\Y\P\X1346:Last-minute procedures\X\par
+\fi
+
+\M1344. We have noted that there are two versions of \TeX82. One, called %
+\.{INITEX},
+has to be run first; it initializes everything from scratch, without
+reading a format file, and it has the capability of dumping a format file.
+The other one is called `\.{VIRTEX}'; it is a ``virgin'' program that needs
+to input a format file in order to get started. \.{VIRTEX} typically has
+more memory capacity than \.{INITEX}, because it does not need the space
+consumed by the auxiliary hyphenation tables and the numerous calls on
+\\{primitive}, etc.
+
+The \.{VIRTEX} program cannot read a format file instantaneously, of course;
+the best implementations therefore allow for production versions of \TeX\ that
+not only avoid the loading routine for \PASCAL\ object code, they also have
+a format file pre-loaded. This is impossible to do if we stick to standard
+\PASCAL; but there is a simple way to fool many systems into avoiding the
+initialization, as follows:\quad(1)~We declare a global integer variable
+called \\{ready\_already}. The probability is negligible that this
+variable holds any particular value like 314159 when \.{VIRTEX} is first
+loaded.\quad(2)~After we have read in a format file and initialized
+everything, we set $\\{ready\_already}\K314159$.\quad(3)~Soon \.{VIRTEX}
+will print `\.*', waiting for more input; and at this point we
+interrupt the program and save its core image in some form that the
+operating system can reload speedily.\quad(4)~When that core image is
+activated, the program starts again at the beginning; but now
+$\\{ready\_already}=314159$ and all the other global variables have
+their initial values too. The former chastity has vanished!
+
+In other words, if we allow ourselves to test the condition
+$\\{ready\_already}=314159$, before \\{ready\_already} has been
+assigned a value, we can avoid the lengthy initialization. Dirty tricks
+rarely pay off so handsomely.
+
+On systems that allow such preloading, the standard program called \.{TeX}
+should be the one that has \.{plain} format preloaded, since that agrees
+with {\sl The \TeX book}. Other versions, e.g., \.{AmSTeX}, should also
+be provided for commonly used formats.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{ready\_already}: \37\\{integer};\C{a sacrifice of purity for economy}\par
+\fi
+
+\M1345. Now this is really it: \TeX\ starts and ends here.
+
+The initial test involving \\{ready\_already} should be deleted if the
+\PASCAL\ runtime system is smart enough to detect such a ``mistake.''
+
+\Y\P\D \37$\\{const\_chk}(\#)\S$\1\6
+\&{begin} \37\&{if} $\#<\\{inf}\J\#$ \1\&{then}\5
+$\#\K\\{inf}\J\#$\6
+\4\&{else} \&{if} $\#>\\{sup}\J\#$ \1\&{then}\5
+$\#\K\\{sup}\J\#$\2\2\6
+\&{end}\C{\\{setup\_bound\_var} stuff duplicated in \.{mf.ch}.}\2\par
+\P\D \37$\\{setup\_bound\_var}(\#)\S\\{bound\_default}\K\#$;\5
+\\{setup\_bound\_var\_end}\par
+\P\D \37$\\{setup\_bound\_var\_end}(\#)\S\\{bound\_name}\K\#$;\5
+\\{setup\_bound\_var\_end\_end}\par
+\P\D \37$\\{setup\_bound\_var\_end\_end}(\#)\S\\{setup\_bound\_variable}(%
+\\{addressof}(\#),\39\\{bound\_name},\39\\{bound\_default})$\par
+\Y\P\4\&{procedure}\1\  \37\\{main\_body};\2\6
+\&{begin} \37\C{\\{start\_here}}\6
+\C{Bounds that may be set from the configuration file. We want the user to  be
+able to specify the names with underscores, but \.{TANGLE} removes
+underscores, so we're stuck giving the names twice, once as a string,  once as
+the identifier. How ugly.}\6
+$\\{setup\_bound\_var}(0)(\.{\'mem\_bot\'})(\\{mem\_bot})$;\5
+$\\{setup\_bound\_var}(250000)(\.{\'main\_memory\'})(\\{main\_memory})$;\C{%
+\\{memory\_word}s for \\{mem} in \.{INITEX}}\6
+$\\{setup\_bound\_var}(0)(\.{\'extra\_mem\_top\'})(\\{extra\_mem\_top})$;%
+\C{increase high mem in \.{VIRTEX}}\6
+$\\{setup\_bound\_var}(0)(\.{\'extra\_mem\_bot\'})(\\{extra\_mem\_bot})$;%
+\C{increase low mem in \.{VIRTEX}}\6
+$\\{setup\_bound\_var}(200000)(\.{\'pool\_size\'})(\\{pool\_size})$;\5
+$\\{setup\_bound\_var}(75000)(\.{\'string\_vacancies\'})(\\{string%
+\_vacancies})$;\5
+$\\{setup\_bound\_var}(5000)(\.{\'pool\_free\'})(\\{pool\_free})$;\C{min pool
+avail after fmt}\6
+$\\{setup\_bound\_var}(15000)(\.{\'max\_strings\'})(\\{max\_strings})$;\5
+$\\{setup\_bound\_var}(100)(\.{\'strings\_free\'})(\\{strings\_free})$;\5
+$\\{setup\_bound\_var}(100000)(\.{\'font\_mem\_size\'})(\\{font\_mem\_size})$;\5
+$\\{setup\_bound\_var}(500)(\.{\'font\_max\'})(\\{font\_max})$;\5
+$\\{setup\_bound\_var}(20000)(\.{\'trie\_size\'})(\\{trie\_size})$;\C{if %
+\\{ssup\_trie\_size} increases, recompile}\6
+$\\{setup\_bound\_var}(659)(\.{\'hyph\_size\'})(\\{hyph\_size})$;\5
+$\\{setup\_bound\_var}(3000)(\.{\'buf\_size\'})(\\{buf\_size})$;\5
+$\\{setup\_bound\_var}(50)(\.{\'nest\_size\'})(\\{nest\_size})$;\5
+$\\{setup\_bound\_var}(15)(\.{\'max\_in\_open\'})(\\{max\_in\_open})$;\5
+$\\{setup\_bound\_var}(60)(\.{\'param\_size\'})(\\{param\_size})$;\5
+$\\{setup\_bound\_var}(4000)(\.{\'save\_size\'})(\\{save\_size})$;\5
+$\\{setup\_bound\_var}(300)(\.{\'stack\_size\'})(\\{stack\_size})$;\5
+$\\{setup\_bound\_var}(16384)(\.{\'dvi\_buf\_size\'})(\\{dvi\_buf\_size})$;\5
+$\\{setup\_bound\_var}(79)(\.{\'error\_line\'})(\\{error\_line})$;\5
+$\\{setup\_bound\_var}(50)(\.{\'half\_error\_line\'})(\\{half\_error\_line})$;\5
+$\\{setup\_bound\_var}(79)(\.{\'max\_print\_line\'})(\\{max\_print\_line})$;\5
+$\\{setup\_bound\_var}(0)(\.{\'hash\_extra\'})(\\{hash\_extra})$;\5
+$\\{setup\_bound\_var}(10000)(\.{\'expand\_depth\'})(\\{expand\_depth})$;\5
+$\\{const\_chk}(\\{mem\_bot})$;\5
+$\\{const\_chk}(\\{main\_memory})$;\ \&{Init} \37$\\{extra\_mem\_top}\K0$;\5
+$\\{extra\_mem\_bot}\K0$;\ \&{Tini}\6
+\&{if} $\\{extra\_mem\_bot}>\\{sup\_main\_memory}$ \1\&{then}\5
+$\\{extra\_mem\_bot}\K\\{sup\_main\_memory}$;\2\6
+\&{if} $\\{extra\_mem\_top}>\\{sup\_main\_memory}$ \1\&{then}\5
+$\\{extra\_mem\_top}\K\\{sup\_main\_memory}$;\C{\\{mem\_top} is an index, %
+\\{main\_memory} a size}\2\6
+$\\{mem\_top}\K\\{mem\_bot}+\\{main\_memory}-1$;\5
+$\\{mem\_min}\K\\{mem\_bot}$;\5
+$\\{mem\_max}\K\\{mem\_top}$;\C{Check other constants against their sup and
+inf.}\6
+$\\{const\_chk}(\\{trie\_size})$;\5
+$\\{const\_chk}(\\{hyph\_size})$;\5
+$\\{const\_chk}(\\{buf\_size})$;\5
+$\\{const\_chk}(\\{nest\_size})$;\5
+$\\{const\_chk}(\\{max\_in\_open})$;\5
+$\\{const\_chk}(\\{param\_size})$;\5
+$\\{const\_chk}(\\{save\_size})$;\5
+$\\{const\_chk}(\\{stack\_size})$;\5
+$\\{const\_chk}(\\{dvi\_buf\_size})$;\5
+$\\{const\_chk}(\\{pool\_size})$;\5
+$\\{const\_chk}(\\{string\_vacancies})$;\5
+$\\{const\_chk}(\\{pool\_free})$;\5
+$\\{const\_chk}(\\{max\_strings})$;\5
+$\\{const\_chk}(\\{strings\_free})$;\5
+$\\{const\_chk}(\\{font\_mem\_size})$;\5
+$\\{const\_chk}(\\{font\_max})$;\5
+$\\{const\_chk}(\\{hash\_extra})$;\6
+\&{if} $\\{error\_line}>\\{ssup\_error\_line}$ \1\&{then}\5
+$\\{error\_line}\K\\{ssup\_error\_line}$;\C{array memory allocation}\2\6
+$\\{buffer}\K\\{xmalloc\_array}(\\{ASCII\_code},\39\\{buf\_size})$;\5
+$\\{nest}\K\\{xmalloc\_array}(\\{list\_state\_record},\39\\{nest\_size})$;\5
+$\\{save\_stack}\K\\{xmalloc\_array}(\\{memory\_word},\39\\{save\_size})$;\5
+$\\{input\_stack}\K\\{xmalloc\_array}(\\{in\_state\_record},\39\\{stack%
+\_size})$;\5
+$\\{input\_file}\K\\{xmalloc\_array}(\\{alpha\_file},\39\\{max\_in\_open})$;\5
+$\\{line\_stack}\K\\{xmalloc\_array}(\\{integer},\39\\{max\_in\_open})$;\5
+$\\{source\_filename\_stack}\K\\{xmalloc\_array}(\\{str\_number},\39\\{max\_in%
+\_open})$;\5
+$\\{full\_source\_filename\_stack}\K\\{xmalloc\_array}(\\{str\_number},\39%
+\\{max\_in\_open})$;\5
+$\\{param\_stack}\K\\{xmalloc\_array}(\\{halfword},\39\\{param\_size})$;\5
+$\\{dvi\_buf}\K\\{xmalloc\_array}(\\{eight\_bits},\39\\{dvi\_buf\_size})$;\5
+$\\{hyph\_word}\K\\{xmalloc\_array}(\\{str\_number},\39\\{hyph\_size})$;\5
+$\\{hyph\_list}\K\\{xmalloc\_array}(\\{halfword},\39\\{hyph\_size})$;\5
+$\\{hyph\_link}\K\\{xmalloc\_array}(\\{hyph\_pointer},\39\\{hyph\_size})$;\ %
+\&{Init} \37$\\{yzmem}\K\\{xmalloc\_array}(\\{memory\_word},\39\\{mem\_top}-%
+\\{mem\_bot}+1)$;\5
+$\\{zmem}\K\\{yzmem}-\\{mem\_bot}$;\C{Some compilers require $\\{mem\_bot}=0$}\6
+$\\{eqtb\_top}\K\\{eqtb\_size}+\\{hash\_extra}$;\6
+\&{if} $\\{hash\_extra}=0$ \1\&{then}\5
+$\\{hash\_top}\K\\{undefined\_control\_sequence}$\6
+\4\&{else} $\\{hash\_top}\K\\{eqtb\_top}$;\2\6
+$\\{yhash}\K\\{xmalloc\_array}(\\{two\_halves},\391+\\{hash\_top}-\\{hash%
+\_offset})$;\5
+$\\{hash}\K\\{yhash}-\\{hash\_offset}$;\C{Some compilers require $\\{hash%
+\_offset}=0$}\6
+$\\{next}(\\{hash\_base})\K0$;\5
+$\\{text}(\\{hash\_base})\K0$;\6
+\&{for} $\\{hash\_used}\K\\{hash\_base}+1\mathrel{\&{to}}\\{hash\_top}$ \1%
+\&{do}\5
+$\\{hash}[\\{hash\_used}]\K\\{hash}[\\{hash\_base}]$;\2\6
+$\\{zeqtb}\K\\{xmalloc\_array}(\\{memory\_word},\39\\{eqtb\_top})$;\5
+$\\{eqtb}\K\\{zeqtb}$;\5
+$\\{str\_start}\K\\{xmalloc\_array}(\\{pool\_pointer},\39\\{max\_strings})$;\5
+$\\{str\_pool}\K\\{xmalloc\_array}(\\{packed\_ASCII\_code},\39\\{pool\_size})$;%
+\5
+$\\{font\_info}\K\\{xmalloc\_array}(\\{memory\_word},\39\\{font\_mem\_size})$;\
+\&{Tini}$\\{history}\K\\{fatal\_error\_stop}$;\C{in case we quit during
+initialization}\6
+\\{t\_open\_out};\C{open the terminal for output}\6
+\&{if} $\\{ready\_already}=314159$ \1\&{then}\5
+\&{goto} \37\\{start\_of\_TEX};\2\6
+\X14:Check the ``constant'' values for consistency\X\6
+\&{if} $\\{bad}>0$ \1\&{then}\6
+\&{begin} \37$\\{wterm\_ln}(\.{\'Ouch---my\ internal\ constants\ have\ been\
+clobbered!\'},\39\.{\'---case\ \'},\39\\{bad}:1)$;\5
+\&{goto} \37\\{final\_end};\6
+\&{end};\2\6
+\\{initialize};\C{set global variables to their starting values}\6
+\&{Init} \37\&{if} $\R\\{get\_strings\_started}$ \1\&{then}\5
+\&{goto} \37\\{final\_end};\2\6
+\\{init\_prim};\C{call \\{primitive} for each primitive}\6
+$\\{init\_str\_ptr}\K\\{str\_ptr}$;\5
+$\\{init\_pool\_ptr}\K\\{pool\_ptr}$;\5
+\\{fix\_date\_and\_time};\6
+\&{Tini}\6
+$\\{ready\_already}\K314159$;\6
+\4\\{start\_of\_TEX}: \37\X56:Initialize the output routines\X;\6
+\X1350:Get the first line of input and prepare to start\X;\6
+$\\{history}\K\\{spotless}$;\C{ready to go!}\6
+\\{main\_control};\C{come to life}\6
+\\{final\_cleanup};\C{prepare for death}\6
+\\{close\_files\_and\_terminate};\6
+\4\\{final\_end}: \37\\{do\_final\_end};\6
+\&{end}\C{\\{main\_body}}\6
+;\par
+\fi
+
+\M1346. Here we do whatever is needed to complete \TeX's job gracefully on the
+local operating system. The code here might come into play after a fatal
+error; it must therefore consist entirely of ``safe'' operations that
+cannot produce error messages. For example, it would be a mistake to call
+\\{str\_room} or \\{make\_string} at this time, because a call on \\{overflow}
+might lead to an infinite loop.
+
+Actually there's one way to get error messages, via \\{prepare\_mag};
+but that can't cause infinite recursion.
+
+This program doesn't bother to close the input files that may still be open.
+
+\Y\P$\4\X1346:Last-minute procedures\X\S$\6
+\4\&{procedure}\1\  \37\\{close\_files\_and\_terminate};\6
+\4\&{var} \37\|k: \37\\{integer};\C{all-purpose index}\2\6
+\&{begin} \37\X1391:Finish the extensions\X;\6
+\&{stat} \37\&{if} $\\{tracing\_stats}>0$ \1\&{then}\5
+\X1347:Output statistics about this job\X;\2\ \&{tats}\6
+\\{wake\_up\_terminal};\5
+\X653:Finish the \.{DVI} file\X;\6
+\&{if} $\\{log\_opened}$ \1\&{then}\6
+\&{begin} \37\\{wlog\_cr};\5
+$\\{a\_close}(\\{log\_file})$;\5
+$\\{selector}\K\\{selector}-2$;\6
+\&{if} $\\{selector}=\\{term\_only}$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"Transcript\ written\ on\ "})$;\5
+$\\{print\_file\_name}(0,\39\\{log\_name},\390)$;\5
+$\\{print\_char}(\.{"."})$;\6
+\&{end};\2\6
+\&{end};\2\6
+\\{print\_ln};\6
+\&{if} $(\\{edit\_name\_start}\I0)\W(\\{interaction}>\\{batch\_mode})$ \1%
+\&{then}\5
+$\\{call\_edit}(\\{str\_pool},\39\\{edit\_name\_start},\39\\{edit\_name%
+\_length},\39\\{edit\_line})$;\2\6
+\&{end};\par
+\As1348, 1349\ETs1351.
+\U1343.\fi
+
+\M1347. The present section goes directly to the log file instead of using
+\\{print} commands, because there's no need for these strings to take
+up \\{str\_pool} memory when a non-{\bf stat} version of \TeX\ is being used.
+
+\Y\P$\4\X1347:Output statistics about this job\X\S$\6
+\&{if} $\\{log\_opened}$ \1\&{then}\6
+\&{begin} \37$\\{wlog\_ln}(\.{\'\ \'})$;\5
+$\\{wlog\_ln}(\.{\'Here\ is\ how\ much\ of\ TeX\'}\.{\'s\ memory\'},\39\.{\'\
+you\ used:\'})$;\5
+$\\{wlog}(\.{\'\ \'},\39\\{str\_ptr}-\\{init\_str\_ptr}:1,\39\.{\'\ string%
+\'})$;\6
+\&{if} $\\{str\_ptr}\I\\{init\_str\_ptr}+1$ \1\&{then}\5
+$\\{wlog}(\.{\'s\'})$;\2\6
+$\\{wlog\_ln}(\.{\'\ out\ of\ \'},\39\\{max\_strings}-\\{init\_str\_ptr}:1)$;\6
+$\\{wlog\_ln}(\.{\'\ \'},\39\\{pool\_ptr}-\\{init\_pool\_ptr}:1,\39\.{\'\
+string\ characters\ out\ of\ \'},\39\\{pool\_size}-\\{init\_pool\_ptr}:1)$;\6
+$\\{wlog\_ln}(\.{\'\ \'},\39\\{lo\_mem\_max}-\\{mem\_min}+\\{mem\_end}-\\{hi%
+\_mem\_min}+2:1,\39\30\.{\'\ words\ of\ memory\ out\ of\ \'},\39\\{mem\_end}+1-%
+\\{mem\_min}:1)$;\6
+$\\{wlog\_ln}(\.{\'\ \'},\39\\{cs\_count}:1,\39\.{\'\ multiletter\ control\
+sequences\ out\ of\ \'},\39\\{hash\_size}:1,\39\.{\'+\'},\39\\{hash%
+\_extra}:1)$;\6
+$\\{wlog}(\.{\'\ \'},\39\\{fmem\_ptr}:1,\39\.{\'\ words\ of\ font\ info\ for\ %
+\'},\39\\{font\_ptr}-\\{font\_base}:1,\39\.{\'\ font\'})$;\6
+\&{if} $\\{font\_ptr}\I\\{font\_base}+1$ \1\&{then}\5
+$\\{wlog}(\.{\'s\'})$;\2\6
+$\\{wlog\_ln}(\.{\',\ out\ of\ \'},\39\\{font\_mem\_size}:1,\39\.{\'\ for\ \'},%
+\39\\{font\_max}-\\{font\_base}:1)$;\6
+$\\{wlog}(\.{\'\ \'},\39\\{hyph\_count}:1,\39\.{\'\ hyphenation\ exception%
+\'})$;\6
+\&{if} $\\{hyph\_count}\I1$ \1\&{then}\5
+$\\{wlog}(\.{\'s\'})$;\2\6
+$\\{wlog\_ln}(\.{\'\ out\ of\ \'},\39\\{hyph\_size}:1)$;\6
+$\\{wlog\_ln}(\.{\'\ \'},\39\\{max\_in\_stack}:1,\39\.{\'i,\'},\39\\{max\_nest%
+\_stack}:1,\39\.{\'n,\'},\39\30\\{max\_param\_stack}:1,\39\.{\'p,\'},\39\30%
+\\{max\_buf\_stack}+1:1,\39\.{\'b,\'},\39\30\\{max\_save\_stack}+6:1,\39\.{\'s\
+stack\ positions\ out\ of\ \'},\39\30\\{stack\_size}:1,\39\.{\'i,\'},\39\\{nest%
+\_size}:1,\39\.{\'n,\'},\39\\{param\_size}:1,\39\.{\'p,\'},\39\\{buf\_size}:1,%
+\39\.{\'b,\'},\39\\{save\_size}:1,\39\.{\'s\'})$;\6
+\&{end}\2\par
+\U1346.\fi
+
+\M1348. We get to the \\{final\_cleanup} routine when \.{\\end} or \.{\\dump}
+has
+been scanned and \\{its\_all\_over}\kern-2pt.
+
+\Y\P$\4\X1346:Last-minute procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{final\_cleanup};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|c: \37\\{small\_number};\C{0 for \.{\\end}, 1 for \.{\\dump}}\2\6
+\&{begin} \37$\|c\K\\{cur\_chr}$;\6
+\&{if} $\\{job\_name}=0$ \1\&{then}\5
+\\{open\_log\_file};\2\6
+\&{while} $\\{input\_ptr}>0$ \1\&{do}\6
+\&{if} $\\{state}=\\{token\_list}$ \1\&{then}\5
+\\{end\_token\_list}\ \&{else} \\{end\_file\_reading};\2\2\6
+\&{while} $\\{open\_parens}>0$ \1\&{do}\6
+\&{begin} \37$\\{print}(\.{"\ )"})$;\5
+$\\{decr}(\\{open\_parens})$;\6
+\&{end};\2\6
+\&{if} $\\{cur\_level}>\\{level\_one}$ \1\&{then}\6
+\&{begin} \37$\\{print\_nl}(\.{"("})$;\5
+$\\{print\_esc}(\.{"end\ occurred\ "})$;\5
+$\\{print}(\.{"inside\ a\ group\ at\ level\ "})$;\5
+$\\{print\_int}(\\{cur\_level}-\\{level\_one})$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\2\6
+\&{while} $\\{cond\_ptr}\I\\{null}$ \1\&{do}\6
+\&{begin} \37$\\{print\_nl}(\.{"("})$;\5
+$\\{print\_esc}(\.{"end\ occurred\ "})$;\5
+$\\{print}(\.{"when\ "})$;\5
+$\\{print\_cmd\_chr}(\\{if\_test},\39\\{cur\_if})$;\6
+\&{if} $\\{if\_line}\I0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"\ on\ line\ "})$;\5
+$\\{print\_int}(\\{if\_line})$;\6
+\&{end};\2\6
+$\\{print}(\.{"\ was\ incomplete)"})$;\5
+$\\{if\_line}\K\\{if\_line\_field}(\\{cond\_ptr})$;\5
+$\\{cur\_if}\K\\{subtype}(\\{cond\_ptr})$;\5
+$\\{temp\_ptr}\K\\{cond\_ptr}$;\5
+$\\{cond\_ptr}\K\\{link}(\\{cond\_ptr})$;\5
+$\\{free\_node}(\\{temp\_ptr},\39\\{if\_node\_size})$;\6
+\&{end};\2\6
+\&{if} $\\{history}\I\\{spotless}$ \1\&{then}\6
+\&{if} $((\\{history}=\\{warning\_issued})\V(\\{interaction}<\\{error\_stop%
+\_mode}))$ \1\&{then}\6
+\&{if} $\\{selector}=\\{term\_and\_log}$ \1\&{then}\6
+\&{begin} \37$\\{selector}\K\\{term\_only}$;\5
+$\\{print\_nl}(\.{"(see\ the\ transcript\ file\ for\ additional\
+information)"})$;\5
+$\\{selector}\K\\{term\_and\_log}$;\6
+\&{end};\2\2\2\6
+\&{if} $\|c=1$ \1\&{then}\6
+\&{begin} \37\&{Init} \37\&{for} $\|c\K\\{top\_mark\_code}\mathrel{\&{to}}%
+\\{split\_bot\_mark\_code}$ \1\&{do}\6
+\&{if} $\\{cur\_mark}[\|c]\I\\{null}$ \1\&{then}\5
+$\\{delete\_token\_ref}(\\{cur\_mark}[\|c])$;\2\2\6
+\&{if} $\\{last\_glue}\I\\{max\_halfword}$ \1\&{then}\5
+$\\{delete\_glue\_ref}(\\{last\_glue})$;\2\6
+\\{store\_fmt\_file};\5
+\&{return};\ \&{Tini}\6
+$\\{print\_nl}(\.{"(\\dump\ is\ performed\ only\ by\ INITEX)"})$;\5
+\&{return};\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1349. \P$\X1346:Last-minute procedures\X\mathrel{+}\S$\6
+\&{init} \37\&{procedure}\1\  \37\\{init\_prim};\C{initialize all the
+primitives}\2\6
+\&{begin} \37$\\{no\_new\_control\_sequence}\K\\{false}$;\5
+\X232:Put each of \TeX's primitives into the hash table\X;\6
+$\\{no\_new\_control\_sequence}\K\\{true}$;\6
+\&{end};\6
+\&{tini}\par
+\fi
+
+\M1350. When we begin the following code, \TeX's tables may still contain
+garbage;
+the strings might not even be present. Thus we must proceed cautiously to get
+bootstrapped in.
+
+But when we finish this part of the program, \TeX\ is ready to call on the
+\\{main\_control} routine to do its work.
+
+\Y\P$\4\X1350:Get the first line of input and prepare to start\X\S$\6
+\&{begin} \37\X337:Initialize the input routines\X;\6
+\&{if} $(\\{format\_ident}=0)\V(\\{buffer}[\\{loc}]=\.{"\&"})\V\\{dump\_line}$ %
+\1\&{then}\6
+\&{begin} \37\&{if} $\\{format\_ident}\I0$ \1\&{then}\5
+\\{initialize};\C{erase preloaded format}\2\6
+\&{if} $\R\\{open\_fmt\_file}$ \1\&{then}\5
+\&{goto} \37\\{final\_end};\2\6
+\&{if} $\R\\{load\_fmt\_file}$ \1\&{then}\6
+\&{begin} \37$\\{w\_close}(\\{fmt\_file})$;\5
+\&{goto} \37\\{final\_end};\6
+\&{end};\2\6
+$\\{w\_close}(\\{fmt\_file})$;\5
+$\\{eqtb}\K\\{zeqtb}$;\6
+\&{while} $(\\{loc}<\\{limit})\W(\\{buffer}[\\{loc}]=\.{"\ "})$ \1\&{do}\5
+$\\{incr}(\\{loc})$;\2\6
+\&{end};\2\6
+\&{if} $\\{end\_line\_char\_inactive}$ \1\&{then}\5
+$\\{decr}(\\{limit})$\6
+\4\&{else} $\\{buffer}[\\{limit}]\K\\{end\_line\_char}$;\2\6
+\&{if} $\\{mltex\_enabled\_p}$ \1\&{then}\6
+\&{begin} \37$\\{wterm\_ln}(\.{\'MLTeX\ v2.2\ enabled\'})$;\6
+\&{end};\2\6
+\\{fix\_date\_and\_time};\6
+\&{init} \37\&{if} $\\{trie\_not\_ready}$ \1\&{then}\6
+\&{begin} \37\C{initex without format loaded}\6
+$\\{trie\_trl}\K\\{xmalloc\_array}(\\{trie\_pointer},\39\\{trie\_size})$;\5
+$\\{trie\_tro}\K\\{xmalloc\_array}(\\{trie\_pointer},\39\\{trie\_size})$;\5
+$\\{trie\_trc}\K\\{xmalloc\_array}(\\{quarterword},\39\\{trie\_size})$;\5
+$\\{trie\_c}\K\\{xmalloc\_array}(\\{packed\_ASCII\_code},\39\\{trie\_size})$;\5
+$\\{trie\_o}\K\\{xmalloc\_array}(\\{trie\_opcode},\39\\{trie\_size})$;\5
+$\\{trie\_l}\K\\{xmalloc\_array}(\\{trie\_pointer},\39\\{trie\_size})$;\5
+$\\{trie\_r}\K\\{xmalloc\_array}(\\{trie\_pointer},\39\\{trie\_size})$;\5
+$\\{trie\_hash}\K\\{xmalloc\_array}(\\{trie\_pointer},\39\\{trie\_size})$;\5
+$\\{trie\_taken}\K\\{xmalloc\_array}(\\{boolean},\39\\{trie\_size})$;\5
+$\\{trie\_root}\K0$;\5
+$\\{trie\_c}[0]\K\\{si}(0)$;\5
+$\\{trie\_ptr}\K0$;\C{Allocate and initialize font arrays}\6
+$\\{font\_dir}\K\\{xmalloc\_array}(\\{eight\_bits},\39\\{font\_max})$;\5
+$\\{font\_num\_ext}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{font\_check}\K\\{xmalloc\_array}(\\{four\_quarters},\39\\{font\_max})$;\5
+$\\{font\_size}\K\\{xmalloc\_array}(\\{scaled},\39\\{font\_max})$;\5
+$\\{font\_dsize}\K\\{xmalloc\_array}(\\{scaled},\39\\{font\_max})$;\5
+$\\{font\_params}\K\\{xmalloc\_array}(\\{font\_index},\39\\{font\_max})$;\5
+$\\{font\_name}\K\\{xmalloc\_array}(\\{str\_number},\39\\{font\_max})$;\5
+$\\{font\_area}\K\\{xmalloc\_array}(\\{str\_number},\39\\{font\_max})$;\5
+$\\{font\_bc}\K\\{xmalloc\_array}(\\{eight\_bits},\39\\{font\_max})$;\5
+$\\{font\_ec}\K\\{xmalloc\_array}(\\{eight\_bits},\39\\{font\_max})$;\5
+$\\{font\_glue}\K\\{xmalloc\_array}(\\{halfword},\39\\{font\_max})$;\5
+$\\{hyphen\_char}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{skew\_char}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{bchar\_label}\K\\{xmalloc\_array}(\\{font\_index},\39\\{font\_max})$;\5
+$\\{font\_bchar}\K\\{xmalloc\_array}(\\{nine\_bits},\39\\{font\_max})$;\5
+$\\{font\_false\_bchar}\K\\{xmalloc\_array}(\\{nine\_bits},\39\\{font\_max})$;\5
+$\\{ctype\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{char\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{width\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{height\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{depth\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{italic\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{lig\_kern\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{kern\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{exten\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{param\_base}\K\\{xmalloc\_array}(\\{integer},\39\\{font\_max})$;\5
+$\\{font\_ptr}\K\\{null\_font}$;\5
+$\\{fmem\_ptr}\K7$;\5
+$\\{font\_dir}[\\{null\_font}]\K\\{dir\_default}$;\5
+$\\{font\_num\_ext}[\\{null\_font}]\K0$;\5
+$\\{font\_name}[\\{null\_font}]\K\.{"nullfont"}$;\5
+$\\{font\_area}[\\{null\_font}]\K\.{""}$;\5
+$\\{hyphen\_char}[\\{null\_font}]\K\.{"-"}$;\5
+$\\{skew\_char}[\\{null\_font}]\K-1$;\5
+$\\{bchar\_label}[\\{null\_font}]\K\\{non\_address}$;\5
+$\\{font\_bchar}[\\{null\_font}]\K\\{non\_char}$;\5
+$\\{font\_false\_bchar}[\\{null\_font}]\K\\{non\_char}$;\5
+$\\{font\_bc}[\\{null\_font}]\K1$;\5
+$\\{font\_ec}[\\{null\_font}]\K0$;\5
+$\\{font\_size}[\\{null\_font}]\K0$;\5
+$\\{font\_dsize}[\\{null\_font}]\K0$;\5
+$\\{ctype\_base}[\\{null\_font}]\K0$;\5
+$\\{char\_base}[\\{null\_font}]\K0$;\5
+$\\{width\_base}[\\{null\_font}]\K0$;\5
+$\\{height\_base}[\\{null\_font}]\K0$;\5
+$\\{depth\_base}[\\{null\_font}]\K0$;\5
+$\\{italic\_base}[\\{null\_font}]\K0$;\5
+$\\{lig\_kern\_base}[\\{null\_font}]\K0$;\5
+$\\{kern\_base}[\\{null\_font}]\K0$;\5
+$\\{exten\_base}[\\{null\_font}]\K0$;\5
+$\\{font\_glue}[\\{null\_font}]\K\\{null}$;\5
+$\\{font\_params}[\\{null\_font}]\K7$;\5
+$\\{param\_base}[\\{null\_font}]\K-1$;\6
+\&{for} $\\{font\_k}\K0\mathrel{\&{to}}6$ \1\&{do}\5
+$\\{font\_info}[\\{font\_k}].\\{sc}\K0$;\2\6
+\&{end};\2\6
+\&{tini}\6
+$\\{font\_used}\K\\{xmalloc\_array}(\\{boolean},\39\\{font\_max})$;\6
+\&{for} $\\{font\_k}\K\\{font\_base}\mathrel{\&{to}}\\{font\_max}$ \1\&{do}\5
+$\\{font\_used}[\\{font\_k}]\K\\{false}$;\2\6
+\X776:Compute the magic offset\X;\6
+\X76:Initialize the print \\{selector} based on \\{interaction}\X;\6
+\&{if} $(\\{loc}<\\{limit})\W(\\{cat\_code}(\\{buffer}[\\{loc}])\I\\{escape})$ %
+\1\&{then}\5
+\\{start\_input};\C{\.{\\input} assumed}\2\6
+\&{end}\par
+\U1345.\fi
+
+\N1351.  \[52] Debugging.
+Once \TeX\ is working, you should be able to diagnose most errors with
+the \.{\\show} commands and other diagnostic features. But for the initial
+stages of debugging, and for the revelation of really deep mysteries, you
+can compile \TeX\ with a few more aids, including the \PASCAL\ runtime
+checks and its debugger. An additional routine called \\{debug\_help}
+will also come into play when you type `\.D' after an error message;
+\\{debug\_help} also occurs just before a fatal error causes \TeX\ to succumb.
+
+The interface to \\{debug\_help} is primitive, but it is good enough when used
+with a \PASCAL\ debugger that allows you to set breakpoints and to read
+variables and change their values. After getting the prompt `\.{debug \#}', you
+type either a negative number (this exits \\{debug\_help}), or zero (this
+goes to a location where you can set a breakpoint, thereby entering into
+dialog with the \PASCAL\ debugger), or a positive number \|m followed by
+an argument \|n. The meaning of \|m and \|n will be clear from the
+program below. (If $\|m=13$, there is an additional argument, \|l.)
+
+\Y\P\D \37$\\{breakpoint}=888$\C{place where a breakpoint is desirable}\par
+\Y\P$\4\X1346:Last-minute procedures\X\mathrel{+}\S$\6
+\&{debug} \37\&{procedure}\1\  \37\\{debug\_help};\C{routine to display various
+things}\6
+\4\&{label} \37$\\{breakpoint},\39\\{exit}$;\6
+\4\&{var} \37$\|k,\39\|l,\39\|m,\39\|n$: \37\\{integer};\2\6
+\&{begin} \37\~ \1\&{loop}\6
+\&{begin} \37\\{wake\_up\_terminal};\5
+$\\{print\_nl}(\.{"debug\ \#\ (-1\ to\ exit):"})$;\5
+\\{update\_terminal};\5
+$\\{read}(\\{term\_in},\39\|m)$;\6
+\&{if} $\|m<0$ \1\&{then}\5
+\&{return}\6
+\4\&{else} \&{if} $\|m=0$ \1\&{then}\5
+\\{dump\_core}\C{do something to cause a core dump}\6
+\4\&{else} \&{begin} \37$\\{read}(\\{term\_in},\39\|n)$;\6
+\&{case} $\|m$ \1\&{of}\6
+\hbox{\4}\X1352:Numbered cases for \\{debug\_help}\X\6
+\4\&{othercases} \37$\\{print}(\.{"?"})$\2\6
+\&{endcases};\6
+\&{end};\2\2\6
+\&{end};\2\6
+\4\\{exit}: \37\&{end};\6
+\&{gubed}\par
+\fi
+
+\M1352. \P$\X1352:Numbered cases for \\{debug\_help}\X\S$\6
+\41: \37$\\{print\_word}(\\{mem}[\|n])$;\C{display $\\{mem}[\|n]$ in all forms}%
+\6
+\42: \37$\\{print\_int}(\\{info}(\|n))$;\6
+\43: \37$\\{print\_int}(\\{link}(\|n))$;\6
+\44: \37$\\{print\_word}(\\{eqtb}[\|n])$;\6
+\45: \37\&{begin} \37$\\{print\_scaled}(\\{font\_info}[\|n].\\{sc})$;\5
+$\\{print\_char}(\.{"\ "})$;\6
+$\\{print\_int}(\\{font\_info}[\|n].\\{qqqq}.\\{b0})$;\5
+$\\{print\_char}(\.{":"})$;\6
+$\\{print\_int}(\\{font\_info}[\|n].\\{qqqq}.\\{b1})$;\5
+$\\{print\_char}(\.{":"})$;\6
+$\\{print\_int}(\\{font\_info}[\|n].\\{qqqq}.\\{b2})$;\5
+$\\{print\_char}(\.{":"})$;\6
+$\\{print\_int}(\\{font\_info}[\|n].\\{qqqq}.\\{b3})$;\6
+\&{end};\6
+\46: \37$\\{print\_word}(\\{save\_stack}[\|n])$;\6
+\47: \37$\\{show\_box}(\|n)$;\C{show a box, abbreviated by \\{show\_box\_depth}
+and \\{show\_box\_breadth}}\6
+\48: \37\&{begin} \37$\\{breadth\_max}\K10000$;\5
+$\\{depth\_threshold}\K\\{pool\_size}-\\{pool\_ptr}-10$;\5
+$\\{show\_node\_list}(\|n)$;\C{show a box in its entirety}\6
+\&{end};\6
+\49: \37$\\{show\_token\_list}(\|n,\39\\{null},\391000)$;\6
+\410: \37$\\{slow\_print}(\|n)$;\6
+\411: \37$\\{check\_mem}(\|n>0)$;\C{check wellformedness; print new busy
+locations if $\|n>0$}\6
+\412: \37$\\{search\_mem}(\|n)$;\C{look for pointers to \|n}\6
+\413: \37\&{begin} \37$\\{read}(\\{term\_in},\39\|l)$;\5
+$\\{print\_cmd\_chr}(\|n,\39\|l)$;\6
+\&{end};\6
+\414: \37\&{for} $\|k\K0\mathrel{\&{to}}\|n$ \1\&{do}\5
+$\\{print}(\\{buffer}[\|k])$;\2\6
+\415: \37\&{begin} \37$\\{font\_in\_short\_display}\K\\{null\_font}$;\5
+$\\{short\_display}(\|n)$;\6
+\&{end};\6
+\416: \37$\\{panicking}\K\R\\{panicking}$;\par
+\U1351.\fi
+
+\N1353.  \[53] Extensions.
+The program above includes a bunch of ``hooks'' that allow further
+capabilities to be added without upsetting \TeX's basic structure.
+Most of these hooks are concerned with ``whatsit'' nodes, which are
+intended to be used for special purposes; whenever a new extension to
+\TeX\ involves a new kind of whatsit node, a corresponding change needs
+to be made to the routines below that deal with such nodes,
+but it will usually be unnecessary to make many changes to the
+other parts of this program.
+
+In order to demonstrate how extensions can be made, we shall treat
+`\.{\\write}', `\.{\\openout}', `\.{\\closeout}', `\.{\\immediate}',
+`\.{\\special}', and `\.{\\setlanguage}' as if they were extensions.
+These commands are actually primitives of \TeX, and they should
+appear in all implementations of the system; but let's try to imagine
+that they aren't. Then the program below illustrates how a person
+could add them.
+
+Sometimes, of course, an extension will require changes to \TeX\ itself;
+no system of hooks could be complete enough for all conceivable extensions.
+The features associated with `\.{\\write}' are almost all confined to the
+following paragraphs, but there are small parts of the \\{print\_ln} and
+\\{print\_char} procedures that were introduced specifically to \.{\\write}
+characters. Furthermore one of the token lists recognized by the scanner
+is a \\{write\_text}; and there are a few other miscellaneous places where we
+have already provided for some aspect of \.{\\write}.  The goal of a \TeX\
+extender should be to minimize alterations to the standard parts of the
+program, and to avoid them completely if possible. He or she should also
+be quite sure that there's no easy way to accomplish the desired goals
+with the standard features that \TeX\ already has. ``Think thrice before
+extending,'' because that may save a lot of work, and it will also keep
+incompatible extensions of \TeX\ from proliferating.
+
+\fi
+
+\M1354. First let's consider the format of whatsit nodes that are used to
+represent
+the data associated with \.{\\write} and its relatives. Recall that a whatsit
+has $\\{type}=\\{whatsit\_node}$, and the \\{subtype} is supposed to
+distinguish
+different kinds of whatsits. Each node occupies two or more words; the
+exact number is immaterial, as long as it is readily determined from the
+\\{subtype} or other data.
+
+We shall introduce five \\{subtype} values here, corresponding to the
+control sequences \.{\\openout}, \.{\\write}, \.{\\closeout}, \.{\\special},
+and
+\.{\\setlanguage}. The second word of I/O whatsits has a \\{write\_stream}
+field
+that identifies the write-stream number (0 to 15, or 16 for out-of-range and
+positive, or 17 for out-of-range and negative).
+In the case of \.{\\write} and \.{\\special}, there is also a field that
+points to the reference count of a token list that should be sent. In the
+case of \.{\\openout}, we need three words and three auxiliary subfields
+to hold the string numbers for name, area, and extension.
+
+\Y\P\D \37$\\{write\_node\_size}=2$\C{number of words in a write/whatsit node}%
+\par
+\P\D \37$\\{open\_node\_size}=3$\C{number of words in an open/whatsit node}\par
+\P\D \37$\\{open\_node}=0$\C{\\{subtype} in whatsits that represent files to %
+\.{\\openout}}\par
+\P\D \37$\\{write\_node}=1$\C{\\{subtype} in whatsits that represent things to %
+\.{\\write}}\par
+\P\D \37$\\{close\_node}=2$\C{\\{subtype} in whatsits that represent streams to
+\.{\\closeout}}\par
+\P\D \37$\\{special\_node}=3$\C{\\{subtype} in whatsits that represent \.{%
+\\special} things}\par
+\P\D \37$\\{language\_node}=4$\C{\\{subtype} in whatsits that change the
+current language}\par
+\P\D \37$\\{what\_lang}(\#)\S\\{link}(\#+1)$\C{language number, in the range $0%
+\to255$}\par
+\P\D \37$\\{what\_lhm}(\#)\S\\{type}(\#+1)$\C{minimum left fragment, in the
+range $1\to63$}\par
+\P\D \37$\\{what\_rhm}(\#)\S\\{subtype}(\#+1)$\C{minimum right fragment, in the
+range $1\to63$}\par
+\P\D \37$\\{write\_tokens}(\#)\S\\{link}(\#+1)$\C{reference count of token list
+to write}\par
+\P\D \37$\\{write\_stream}(\#)\S\\{info}(\#+1)$\C{stream number (0 to 17)}\par
+\P\D \37$\\{open\_name}(\#)\S\\{link}(\#+1)$\C{string number of file name to
+open}\par
+\P\D \37$\\{open\_area}(\#)\S\\{info}(\#+2)$\C{string number of file area for %
+\\{open\_name}}\par
+\P\D \37$\\{open\_ext}(\#)\S\\{link}(\#+2)$\C{string number of file extension
+for \\{open\_name}}\par
+\fi
+
+\M1355. The sixteen possible \.{\\write} streams are represented by the %
+\\{write\_file}
+array. The \|jth file is open if and only if $\\{write\_open}[\|j]=\\{true}$.
+The last
+two streams are special; $\\{write\_open}[16]$ represents a stream number
+greater than 15, while $\\{write\_open}[17]$ represents a negative stream
+number,
+and both of these variables are always \\{false}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{write\_file}: \37\&{array} $[0\to15]$ \1\&{of}\5
+\\{alpha\_file};\2\6
+\4\\{write\_open}: \37\&{array} $[0\to17]$ \1\&{of}\5
+\\{boolean};\2\par
+\fi
+
+\M1356. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+\&{for} $\|k\K0\mathrel{\&{to}}17$ \1\&{do}\5
+$\\{write\_open}[\|k]\K\\{false}$;\2\par
+\fi
+
+\M1357. Extensions might introduce new command codes; but it's best to use
+\\{extension} with a modifier, whenever possible, so that \\{main\_control}
+stays the same.
+
+\Y\P\D \37$\\{immediate\_code}=4$\C{command modifier for \.{\\immediate}}\par
+\P\D \37$\\{set\_language\_code}=5$\C{command modifier for \.{\\setlanguage}}%
+\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"openout"},\39\\{extension},\39\\{open\_node})$;\6
+$\\{primitive}(\.{"write"},\39\\{extension},\39\\{write\_node})$;\5
+$\\{write\_loc}\K\\{cur\_val}$;\6
+$\\{primitive}(\.{"closeout"},\39\\{extension},\39\\{close\_node})$;\6
+$\\{primitive}(\.{"special"},\39\\{extension},\39\\{special\_node})$;\6
+$\\{text}(\\{frozen\_special})\K\.{"special"}$;\5
+$\\{eqtb}[\\{frozen\_special}]\K\\{eqtb}[\\{cur\_val}]$;\6
+$\\{primitive}(\.{"immediate"},\39\\{extension},\39\\{immediate\_code})$;\6
+$\\{primitive}(\.{"setlanguage"},\39\\{extension},\39\\{set\_language\_code})$;%
+\par
+\fi
+
+\M1358. The variable \\{write\_loc} just introduced is used to provide an
+appropriate error message in case of ``runaway'' write texts.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{write\_loc}: \37\\{pointer};\C{\\{eqtb} address of \.{\\write}}\par
+\fi
+
+\M1359. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{extension}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{open\_node}: \37$\\{print\_esc}(\.{"openout"})$;\6
+\4\\{write\_node}: \37$\\{print\_esc}(\.{"write"})$;\6
+\4\\{close\_node}: \37$\\{print\_esc}(\.{"closeout"})$;\6
+\4\\{special\_node}: \37$\\{print\_esc}(\.{"special"})$;\6
+\4\\{immediate\_code}: \37$\\{print\_esc}(\.{"immediate"})$;\6
+\4\\{set\_language\_code}: \37$\\{print\_esc}(\.{"setlanguage"})$;\6
+\4\&{othercases} \37$\\{print}(\.{"[unknown\ extension!]"})$\2\6
+\&{endcases};\par
+\fi
+
+\M1360. When an \\{extension} command occurs in \\{main\_control}, in any mode,
+the \\{do\_extension} routine is called.
+
+\Y\P$\4\X1360:Cases of \\{main\_control} that are for extensions to \TeX\X\S$\6
+\4$\\{any\_mode}(\\{extension})$: \37\\{do\_extension};\par
+\U1057.\fi
+
+\M1361. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\hbox{\4}\X1362:Declare procedures needed in \\{do\_extension}\X\6
+\4\&{procedure}\1\  \37\\{do\_extension};\6
+\4\&{var} \37\|k: \37\\{integer};\C{all-purpose integers}\6
+\|p: \37\\{pointer};\C{all-purpose pointers}\2\6
+\&{begin} \37\&{case} $\\{cur\_chr}$ \1\&{of}\6
+\4\\{open\_node}: \37\X1364:Implement \.{\\openout}\X;\6
+\4\\{write\_node}: \37\X1365:Implement \.{\\write}\X;\6
+\4\\{close\_node}: \37\X1366:Implement \.{\\closeout}\X;\6
+\4\\{special\_node}: \37\X1367:Implement \.{\\special}\X;\6
+\4\\{immediate\_code}: \37\X1388:Implement \.{\\immediate}\X;\6
+\4\\{set\_language\_code}: \37\X1390:Implement \.{\\setlanguage}\X;\6
+\4\&{othercases} \37$\\{confusion}(\.{"ext1"})$\2\6
+\&{endcases};\6
+\&{end};\par
+\fi
+
+\M1362. Here is a subroutine that creates a whatsit node having a given %
+\\{subtype}
+and a given number of words. It initializes only the first word of the whatsit,
+and appends it to the current list.
+
+\Y\P$\4\X1362:Declare procedures needed in \\{do\_extension}\X\S$\6
+\4\&{procedure}\1\  \37$\\{new\_whatsit}(\|s:\\{small\_number};\,\35\|w:%
+\\{small\_number})$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6
+\&{begin} \37$\|p\K\\{get\_node}(\|w)$;\5
+$\\{type}(\|p)\K\\{whatsit\_node}$;\5
+$\\{subtype}(\|p)\K\|s$;\5
+$\\{link}(\\{tail})\K\|p$;\5
+$\\{tail}\K\|p$;\6
+\&{end};\par
+\A1363.
+\U1361.\fi
+
+\M1363. The next subroutine uses \\{cur\_chr} to decide what sort of whatsit is
+involved, and also inserts a \\{write\_stream} number.
+
+\Y\P$\4\X1362:Declare procedures needed in \\{do\_extension}\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{new\_write\_whatsit}(\|w:\\{small\_number})$;\2\6
+\&{begin} \37$\\{new\_whatsit}(\\{cur\_chr},\39\|w)$;\6
+\&{if} $\|w\I\\{write\_node\_size}$ \1\&{then}\5
+\\{scan\_four\_bit\_int}\6
+\4\&{else} \&{begin} \37\\{scan\_int};\6
+\&{if} $\\{cur\_val}<0$ \1\&{then}\5
+$\\{cur\_val}\K17$\6
+\4\&{else} \&{if} $(\\{cur\_val}>15)\W(\\{cur\_val}\I18)$ \1\&{then}\5
+$\\{cur\_val}\K16$;\2\2\6
+\&{end};\2\6
+$\\{write\_stream}(\\{tail})\K\\{cur\_val}$;\6
+\&{end};\par
+\fi
+
+\M1364. \P$\X1364:Implement \.{\\openout}\X\S$\6
+\&{begin} \37$\\{new\_write\_whatsit}(\\{open\_node\_size})$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_file\_name};\6
+$\\{open\_name}(\\{tail})\K\\{cur\_name}$;\5
+$\\{open\_area}(\\{tail})\K\\{cur\_area}$;\5
+$\\{open\_ext}(\\{tail})\K\\{cur\_ext}$;\6
+\&{end}\par
+\U1361.\fi
+
+\M1365. When `\.{\\write 12\{...\}}' appears, we scan the token list `\.{\{...%
+\}}'
+without expanding its macros; the macros will be expanded later when this
+token list is rescanned.
+
+\Y\P$\4\X1365:Implement \.{\\write}\X\S$\6
+\&{begin} \37$\|k\K\\{cur\_cs}$;\5
+$\\{new\_write\_whatsit}(\\{write\_node\_size})$;\6
+$\\{cur\_cs}\K\|k$;\5
+$\|p\K\\{scan\_toks}(\\{false},\39\\{false})$;\5
+$\\{write\_tokens}(\\{tail})\K\\{def\_ref}$;\6
+\&{end}\par
+\U1361.\fi
+
+\M1366. \P$\X1366:Implement \.{\\closeout}\X\S$\6
+\&{begin} \37$\\{new\_write\_whatsit}(\\{write\_node\_size})$;\5
+$\\{write\_tokens}(\\{tail})\K\\{null}$;\6
+\&{end}\par
+\U1361.\fi
+
+\M1367. When `\.{\\special\{...\}}' appears, we expand the macros in the token
+list as in \.{\\xdef} and \.{\\mark}.
+
+\Y\P$\4\X1367:Implement \.{\\special}\X\S$\6
+\&{begin} \37$\\{new\_whatsit}(\\{special\_node},\39\\{write\_node\_size})$;\5
+$\\{write\_stream}(\\{tail})\K\\{null}$;\5
+$\|p\K\\{scan\_toks}(\\{false},\39\\{true})$;\5
+$\\{write\_tokens}(\\{tail})\K\\{def\_ref}$;\6
+\&{end}\par
+\U1361.\fi
+
+\M1368. Each new type of node that appears in our data structure must be
+capable
+of being displayed, copied, destroyed, and so on. The routines that we
+need for write-oriented whatsits are somewhat like those for mark nodes;
+other extensions might, of course, involve more subtlety here.
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_write\_whatsit}(\|s:\\{str\_number};\,\35\|p:%
+\\{pointer})$;\2\6
+\&{begin} \37$\\{print\_esc}(\|s)$;\6
+\&{if} $\\{write\_stream}(\|p)<16$ \1\&{then}\5
+$\\{print\_int}(\\{write\_stream}(\|p))$\6
+\4\&{else} \&{if} $\\{write\_stream}(\|p)=16$ \1\&{then}\5
+$\\{print\_char}(\.{"*"})$\6
+\4\&{else} $\\{print\_char}(\.{"-"})$;\2\2\6
+\&{end};\par
+\fi
+
+\M1369. \P$\X1369:Display the whatsit node \|p\X\S$\6
+\&{case} $\\{subtype}(\|p)$ \1\&{of}\6
+\4\\{open\_node}: \37\&{begin} \37$\\{print\_write\_whatsit}(\.{"openout"},\39%
+\|p)$;\5
+$\\{print\_char}(\.{"="})$;\5
+$\\{print\_file\_name}(\\{open\_name}(\|p),\39\\{open\_area}(\|p),\39\\{open%
+\_ext}(\|p))$;\6
+\&{end};\6
+\4\\{write\_node}: \37\&{begin} \37$\\{print\_write\_whatsit}(\.{"write"},\39%
+\|p)$;\5
+$\\{print\_mark}(\\{write\_tokens}(\|p))$;\6
+\&{end};\6
+\4\\{close\_node}: \37$\\{print\_write\_whatsit}(\.{"closeout"},\39\|p)$;\6
+\4\\{special\_node}: \37\&{begin} \37$\\{print\_esc}(\.{"special"})$;\5
+$\\{print\_mark}(\\{write\_tokens}(\|p))$;\6
+\&{end};\6
+\4\\{language\_node}: \37\&{begin} \37$\\{print\_esc}(\.{"setlanguage"})$;\5
+$\\{print\_int}(\\{what\_lang}(\|p))$;\5
+$\\{print}(\.{"\ (hyphenmin\ "})$;\5
+$\\{print\_int}(\\{what\_lhm}(\|p))$;\5
+$\\{print\_char}(\.{","})$;\5
+$\\{print\_int}(\\{what\_rhm}(\|p))$;\5
+$\\{print\_char}(\.{")"})$;\6
+\&{end};\6
+\4\&{othercases} \37$\\{print}(\.{"whatsit?"})$\2\6
+\&{endcases}\par
+\U189.\fi
+
+\M1370. \P$\X1370:Make a partial copy of the whatsit node \|p and make \|r
+point to it; set \\{words} to the number of initial words not yet copied\X\S$\6
+\&{case} $\\{subtype}(\|p)$ \1\&{of}\6
+\4\\{open\_node}: \37\&{begin} \37$\|r\K\\{get\_node}(\\{open\_node\_size})$;\5
+$\\{words}\K\\{open\_node\_size}$;\6
+\&{end};\6
+\4$\\{write\_node},\39\\{special\_node}$: \37\&{begin} \37$\|r\K\\{get\_node}(%
+\\{write\_node\_size})$;\5
+$\\{add\_token\_ref}(\\{write\_tokens}(\|p))$;\5
+$\\{words}\K\\{write\_node\_size}$;\6
+\&{end};\6
+\4$\\{close\_node},\39\\{language\_node}$: \37\&{begin} \37$\|r\K\\{get\_node}(%
+\\{small\_node\_size})$;\5
+$\\{words}\K\\{small\_node\_size}$;\6
+\&{end};\6
+\4\&{othercases} \37$\\{confusion}(\.{"ext2"})$\2\6
+\&{endcases}\par
+\U212.\fi
+
+\M1371. \P$\X1371:Wipe out the whatsit node \|p and \&{goto} \\{done}\X\S$\6
+\&{begin} \37\&{case} $\\{subtype}(\|p)$ \1\&{of}\6
+\4\\{open\_node}: \37$\\{free\_node}(\|p,\39\\{open\_node\_size})$;\6
+\4$\\{write\_node},\39\\{special\_node}$: \37\&{begin} \37$\\{delete\_token%
+\_ref}(\\{write\_tokens}(\|p))$;\5
+$\\{free\_node}(\|p,\39\\{write\_node\_size})$;\5
+\&{goto} \37\\{done};\6
+\&{end};\6
+\4$\\{close\_node},\39\\{language\_node}$: \37$\\{free\_node}(\|p,\39\\{small%
+\_node\_size})$;\6
+\4\&{othercases} \37$\\{confusion}(\.{"ext3"})$\2\6
+\&{endcases};\6
+\&{goto} \37\\{done};\6
+\&{end}\par
+\U208.\fi
+
+\M1372. \P$\X1372:Incorporate a whatsit node into a vbox\X\S$\6
+\\{do\_nothing}\par
+\U680.\fi
+
+\M1373. \P$\X1373:Incorporate a whatsit node into an hbox\X\S$\6
+\\{do\_nothing}\par
+\U662.\fi
+
+\M1374. \P$\X1374:Let \|d be the width of the whatsit \|p\X\S$\6
+$\|d\K0$\par
+\U1159.\fi
+
+\M1375. \P\D \37$\\{adv\_past}(\#)\S$\ \&{if} $\\{subtype}(\#)=\\{language%
+\_node}$ \1\&{then}\6
+\&{begin} \37$\\{cur\_lang}\K\\{what\_lang}(\#)$;\5
+$\\{l\_hyf}\K\\{what\_lhm}(\#)$;\5
+$\\{r\_hyf}\K\\{what\_rhm}(\#)$;\ \&{end}\2\par
+\Y\P$\4\X1375:Advance \(p)past a whatsit node in the \(l)\\{line\_break} loop\X%
+\S$\ $\\{adv\_past}(\\{cur\_p})$\par
+\U877.\fi
+
+\M1376. \P$\X1376:Advance \(p)past a whatsit node in the \(p)pre-hyphenation
+loop\X\S$\ $\\{adv\_past}(\|s)$\par
+\U907.\fi
+
+\M1377. \P$\X1377:Prepare to move whatsit \|p to the current page, then %
+\&{goto} \\{contribute}\X\S$\6
+\&{goto} \37\\{contribute}\par
+\U1011.\fi
+
+\M1378. \P$\X1378:Process whatsit \|p in \\{vert\_break} loop, \&{goto} \\{not%
+\_found}\X\S$\6
+\&{goto} \37\\{not\_found}\par
+\U984.\fi
+
+\M1379. \P$\X1379:Output the whatsit node \|p in a vlist\X\S$\6
+$\\{out\_what}(\|p)$\par
+\U642.\fi
+
+\M1380. \P$\X1380:Output the whatsit node \|p in an hlist\X\S$\6
+$\\{out\_what}(\|p)$\par
+\U633.\fi
+
+\M1381. After all this preliminary shuffling, we come finally to the routines
+that actually send out the requested data. Let's do \.{\\special} first
+(it's easier).
+
+\Y\P$\4\X1381:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X\S$\6
+\4\&{procedure}\1\  \37$\\{special\_out}(\|p:\\{pointer})$;\6
+\4\&{var} \37\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{holds print %
+\\{selector}}\6
+\|k: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\2\6
+\&{begin} \37\\{synch\_h};\5
+\\{synch\_v};\6
+$\\{old\_setting}\K\\{selector}$;\5
+$\\{selector}\K\\{new\_string}$;\5
+$\\{show\_token\_list}(\\{link}(\\{write\_tokens}(\|p)),\39\\{null},\39\\{pool%
+\_size}-\\{pool\_ptr})$;\5
+$\\{selector}\K\\{old\_setting}$;\5
+$\\{str\_room}(1)$;\6
+\&{if} $\\{cur\_length}<256$ \1\&{then}\6
+\&{begin} \37$\\{dvi\_out}(\\{xxx1})$;\5
+$\\{dvi\_out}(\\{cur\_length})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{dvi\_out}(\\{xxx4})$;\5
+$\\{dvi\_four}(\\{cur\_length})$;\6
+\&{end};\2\6
+\&{for} $\|k\K\\{str\_start}[\\{str\_ptr}]\mathrel{\&{to}}\\{pool\_ptr}-1$ \1%
+\&{do}\5
+$\\{dvi\_out}(\\{so}(\\{str\_pool}[\|k]))$;\2\6
+$\\{pool\_ptr}\K\\{str\_start}[\\{str\_ptr}]$;\C{erase the string}\6
+\&{end};\par
+\As1383, 1386, 1448, 1450, 1451\ETs1465.
+\U630.\fi
+
+\M1382. To write a token list, we must run it through \TeX's scanner, expanding
+macros and \.{\\the} and \.{\\number}, etc. This might cause runaways,
+if a delimited macro parameter isn't matched, and runaways would be
+extremely confusing since we are calling on \TeX's scanner in the middle
+of a \.{\\shipout} command. Therefore we will put a dummy control sequence as
+a ``stopper,'' right after the token list. This control sequence is
+artificially defined to be \.{\\outer}.
+
+\Y\P$\4\X170:Initialize table entries (done by \.{INITEX} only)\X\mathrel{+}\S$%
+\6
+$\\{text}(\\{end\_write})\K\.{"endwrite"}$;\5
+$\\{eq\_level}(\\{end\_write})\K\\{level\_one}$;\5
+$\\{eq\_type}(\\{end\_write})\K\\{outer\_call}$;\5
+$\\{equiv}(\\{end\_write})\K\\{null}$;\par
+\fi
+
+\M1383. \P$\X1381:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{write\_out}(\|p:\\{pointer})$;\6
+\4\&{var} \37\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{holds print %
+\\{selector}}\6
+\\{old\_mode}: \37\\{integer};\C{saved \\{mode}}\6
+\|j: \37\\{small\_number};\C{write stream number}\6
+$\|q,\39\|r$: \37\\{pointer};\C{temporary variables for list manipulation}\6
+\|d: \37\\{integer};\C{number of characters in incomplete current string}\6
+\\{clobbered}: \37\\{boolean};\C{system string is ok?}\6
+\\{runsystem\_ret}: \37\\{integer};\C{return value from \\{runsystem}}\2\6
+\&{begin} \37\X1384:Expand macros in the token list and make $\\{link}(\\{def%
+\_ref})$ point to the result\X;\6
+$\\{old\_setting}\K\\{selector}$;\5
+$\|j\K\\{write\_stream}(\|p)$;\6
+\&{if} $\|j=18$ \1\&{then}\5
+$\\{selector}\K\\{new\_string}$\6
+\4\&{else} \&{if} $\\{write\_open}[\|j]$ \1\&{then}\5
+$\\{selector}\K\|j$\6
+\4\&{else} \&{begin} \37\C{write to the terminal if file isn't open}\6
+\&{if} $(\|j=17)\W(\\{selector}=\\{term\_and\_log})$ \1\&{then}\5
+$\\{selector}\K\\{log\_only}$;\2\6
+$\\{print\_nl}(\.{""})$;\6
+\&{end};\2\2\6
+$\\{token\_show}(\\{def\_ref})$;\5
+\\{print\_ln};\5
+$\\{flush\_list}(\\{def\_ref})$;\6
+\&{if} $\|j=18$ \1\&{then}\6
+\&{begin} \37\&{if} $(\\{tracing\_online}\L0)$ \1\&{then}\5
+$\\{selector}\K\\{log\_only}$\C{Show what we're doing in the log file.}\6
+\4\&{else} $\\{selector}\K\\{term\_and\_log}$;\C{Show what we're doing.}\6
+\C{If the log file isn't open yet, we can only send output to the terminal.
+Calling \\{open\_log\_file} from here seems to result in bad data in the log.}%
+\2\6
+\&{if} $\R\\{log\_opened}$ \1\&{then}\5
+$\\{selector}\K\\{term\_only}$;\2\6
+$\\{print\_nl}(\.{"runsystem("})$;\6
+\&{for} $\|d\K0\mathrel{\&{to}}\\{cur\_length}-1$ \1\&{do}\6
+\&{begin} \37\C{\\{print} gives up if passed \\{str\_ptr}, so do it by hand.}\6
+$\\{print}(\\{so}(\\{str\_pool}[\\{str\_start}[\\{str\_ptr}]+\|d]))$;\C{N.B.:
+not \\{print\_char}}\6
+\&{end};\2\6
+$\\{print}(\.{")..."})$;\6
+\&{if} $\\{shellenabledp}$ \1\&{then}\6
+\&{begin} \37$\\{str\_room}(1)$;\5
+$\\{append\_char}(0)$;\C{Append a null byte to the expansion.}\6
+$\\{clobbered}\K\\{false}$;\6
+\&{for} $\|d\K0\mathrel{\&{to}}\\{cur\_length}-1$ \1\&{do}\C{Convert to
+external character set.}\6
+\&{begin} \37$\\{str\_pool}[\\{str\_start}[\\{str\_ptr}]+\|d]\K\\{xchr}[\\{str%
+\_pool}[\\{str\_start}[\\{str\_ptr}]+\|d]]$;\6
+\&{if} $(\\{str\_pool}[\\{str\_start}[\\{str\_ptr}]+\|d]=\\{null\_code})\W(\|d<%
+\\{cur\_length}-1)$ \1\&{then}\5
+$\\{clobbered}\K\\{true}$;\C{minimal checking: NUL not allowed in argument
+string of \\{system}()}\2\6
+\&{end};\2\6
+\&{if} $\\{clobbered}$ \1\&{then}\5
+$\\{print}(\.{"clobbered"})$\6
+\4\&{else} \&{begin} \37\C{We have the command.  See if we're allowed to
+execute it,          and report in the log.  We don't check the actual exit
+status of          the command, or do anything with the output.}\6
+$\\{runsystem\_ret}\K\\{runsystem}(\\{conststringcast}(\\{addressof}(\\{str%
+\_pool}[\\{str\_start}[\\{str\_ptr}]])))$;\6
+\&{if} $\\{runsystem\_ret}=-1$ \1\&{then}\5
+$\\{print}(\.{"quotation\ error\ in\ system\ command"})$\6
+\4\&{else} \&{if} $\\{runsystem\_ret}=0$ \1\&{then}\5
+$\\{print}(\.{"disabled\ (restricted)"})$\6
+\4\&{else} \&{if} $\\{runsystem\_ret}=1$ \1\&{then}\5
+$\\{print}(\.{"executed"})$\6
+\4\&{else} \&{if} $\\{runsystem\_ret}=2$ \1\&{then}\5
+$\\{print}(\.{"executed\ safely\ (allowed)"})$\2\2\2\2\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print}(\.{"disabled"})$;\C{\\{shellenabledp} false}%
+\6
+\&{end};\2\6
+$\\{print\_char}(\.{"."})$;\5
+$\\{print\_nl}(\.{""})$;\5
+\\{print\_ln};\5
+$\\{pool\_ptr}\K\\{str\_start}[\\{str\_ptr}]$;\C{erase the string}\6
+\&{end};\2\6
+$\\{selector}\K\\{old\_setting}$;\6
+\&{end};\par
+\fi
+
+\M1384. The final line of this routine is slightly subtle; at least, the author
+didn't think about it until getting burnt! There is a used-up token list
+on the stack, namely the one that contained \\{end\_write\_token}. (We
+insert this artificial `\.{\\endwrite}' to prevent runaways, as explained
+above.) If it were not removed, and if there were numerous writes on a
+single page, the stack would overflow.
+
+\Y\P\D \37$\\{end\_write\_token}\S\\{cs\_token\_flag}+\\{end\_write}$\par
+\Y\P$\4\X1384:Expand macros in the token list and make $\\{link}(\\{def\_ref})$
+point to the result\X\S$\6
+$\|q\K\\{get\_avail}$;\5
+$\\{info}(\|q)\K\\{right\_brace\_token}+\.{"\}"}$;\6
+$\|r\K\\{get\_avail}$;\5
+$\\{link}(\|q)\K\|r$;\5
+$\\{info}(\|r)\K\\{end\_write\_token}$;\5
+$\\{ins\_list}(\|q)$;\6
+$\\{begin\_token\_list}(\\{write\_tokens}(\|p),\39\\{write\_text})$;\6
+$\|q\K\\{get\_avail}$;\5
+$\\{info}(\|q)\K\\{left\_brace\_token}+\.{"\{"}$;\5
+$\\{ins\_list}(\|q)$;\C{now we're ready to scan   `\.\{$\langle\,$token list$\,%
+\rangle$\.{\} \\endwrite}'}\6
+$\\{old\_mode}\K\\{mode}$;\5
+$\\{mode}\K0$;\C{disable \.{\\prevdepth}, \.{\\spacefactor}, \.{\\lastskip}, %
+\.{\\prevgraf}}\6
+$\\{cur\_cs}\K\\{write\_loc}$;\5
+$\|q\K\\{scan\_toks}(\\{false},\39\\{true})$;\C{expand macros, etc.}\6
+\\{get\_token};\ \&{if} $\\{cur\_tok}\I\\{end\_write\_token}$ \1\&{then}\5
+\X1385:Recover from an unbalanced write command\X;\2\6
+$\\{mode}\K\\{old\_mode}$;\5
+\\{end\_token\_list}\C{conserve stack space}\par
+\U1383.\fi
+
+\M1385. \P$\X1385:Recover from an unbalanced write command\X\S$\6
+\&{begin} \37$\\{print\_err}(\.{"Unbalanced\ write\ command"})$;\5
+$\\{help2}(\.{"On\ this\ page\ there\'s\ a\ \\write\ with\ fewer\ real\ \{\'s\
+than\ \}\'s."})$\6
+$(\.{"I\ can\'t\ handle\ that\ very\ well;\ good\ luck."})$;\5
+\\{error};\6
+\1\&{repeat} \37\\{get\_token};\6
+\4\&{until}\5
+$\\{cur\_tok}=\\{end\_write\_token}$;\2\6
+\&{end}\par
+\U1384.\fi
+
+\M1386. The \\{out\_what} procedure takes care of outputting whatsit nodes for
+\\{vlist\_out} and \\{hlist\_out}\kern-.3pt.
+
+\Y\P$\4\X1381:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{out\_what}(\|p:\\{pointer})$;\6
+\4\&{var} \37\|j: \37\\{small\_number};\C{write stream number}\6
+\\{old\_setting}: \37$0\to\\{max\_selector}$;\2\6
+\&{begin} \37\&{case} $\\{subtype}(\|p)$ \1\&{of}\6
+\4$\\{open\_node},\39\\{write\_node},\39\\{close\_node}$: \37\X1387:Do some
+work that has been queued up for \.{\\write}\X;\6
+\4\\{special\_node}: \37$\\{special\_out}(\|p)$;\6
+\4\\{language\_node}: \37\\{do\_nothing};\6
+\4\&{othercases} \37$\\{confusion}(\.{"ext4"})$\2\6
+\&{endcases};\6
+\&{end};\par
+\fi
+
+\M1387. We don't implement \.{\\write} inside of leaders. (The reason is that
+the number of times a leader box appears might be different in different
+implementations, due to machine-dependent rounding in the glue calculations.)
+
+\Y\P$\4\X1387:Do some work that has been queued up for \.{\\write}\X\S$\6
+\&{if} $\R\\{doing\_leaders}$ \1\&{then}\6
+\&{begin} \37$\|j\K\\{write\_stream}(\|p)$;\6
+\&{if} $\\{subtype}(\|p)=\\{write\_node}$ \1\&{then}\5
+$\\{write\_out}(\|p)$\6
+\4\&{else} \&{begin} \37\&{if} $\\{write\_open}[\|j]$ \1\&{then}\5
+$\\{a\_close}(\\{write\_file}[\|j])$;\2\6
+\&{if} $\\{subtype}(\|p)=\\{close\_node}$ \1\&{then}\5
+$\\{write\_open}[\|j]\K\\{false}$\6
+\4\&{else} \&{if} $\|j<16$ \1\&{then}\6
+\&{begin} \37$\\{cur\_name}\K\\{open\_name}(\|p)$;\5
+$\\{cur\_area}\K\\{open\_area}(\|p)$;\5
+$\\{cur\_ext}\K\\{open\_ext}(\|p)$;\6
+\&{if} $\\{cur\_ext}=\.{""}$ \1\&{then}\5
+$\\{cur\_ext}\K\.{".tex"}$;\2\6
+\\{pack\_cur\_name};\6
+\&{while} $\R\\{kpse\_out\_name\_ok}(\\{stringcast}(\\{name\_of\_file}+1))\V\R%
+\\{a\_open\_out}(\\{write\_file}[\|j])$ \1\&{do}\5
+$\\{prompt\_file\_name}(\.{"output\ file\ name"},\39\.{".tex"})$;\2\6
+$\\{write\_open}[\|j]\K\\{true}$;\C{If on first line of input, log file is not
+ready yet, so don't log.}\6
+\&{if} $\\{log\_opened}$ \1\&{then}\6
+\&{begin} \37$\\{old\_setting}\K\\{selector}$;\6
+\&{if} $(\\{tracing\_online}\L0)$ \1\&{then}\5
+$\\{selector}\K\\{log\_only}$\C{Show what we're doing in the log file.}\6
+\4\&{else} $\\{selector}\K\\{term\_and\_log}$;\C{Show what we're doing.}\2\6
+$\\{print\_nl}(\.{"\\openout"})$;\5
+$\\{print\_int}(\|j)$;\5
+$\\{print}(\.{"\ =\ \`"})$;\5
+$\\{print\_file\_name}(\\{cur\_name},\39\\{cur\_area},\39\\{cur\_ext})$;\5
+$\\{print}(\.{"\'."})$;\5
+$\\{print\_nl}(\.{""})$;\5
+\\{print\_ln};\5
+$\\{selector}\K\\{old\_setting}$;\6
+\&{end};\2\6
+\&{end};\2\2\6
+\&{end};\2\6
+\&{end}\2\par
+\U1386.\fi
+
+\M1388. The presence of `\.{\\immediate}' causes the \\{do\_extension}
+procedure
+to descend to one level of recursion. Nothing happens unless \.{\\immediate}
+is followed by `\.{\\openout}', `\.{\\write}', or `\.{\\closeout}'.
+
+\Y\P$\4\X1388:Implement \.{\\immediate}\X\S$\6
+\&{begin} \37\\{get\_x\_token};\6
+\&{if} $(\\{cur\_cmd}=\\{extension})\W(\\{cur\_chr}\L\\{close\_node})$ \1%
+\&{then}\6
+\&{begin} \37$\|p\K\\{tail}$;\5
+\\{do\_extension};\C{append a whatsit node}\6
+$\\{out\_what}(\\{tail})$;\C{do the action immediately}\6
+$\\{flush\_node\_list}(\\{tail})$;\5
+$\\{tail}\K\|p$;\5
+$\\{link}(\|p)\K\\{null}$;\6
+\&{end}\6
+\4\&{else} \\{back\_input};\2\6
+\&{end}\par
+\U1361.\fi
+
+\M1389. The \.{\\language} extension is somewhat different.
+We need a subroutine that comes into play when a character of
+a non-\\{clang} language is being appended to the current paragraph.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{fix\_language};\6
+\4\&{var} \37\|l: \37\\{ASCII\_code};\C{the new current language}\2\6
+\&{begin} \37\&{if} $\\{language}\L0$ \1\&{then}\5
+$\|l\K0$\6
+\4\&{else} \&{if} $\\{language}>255$ \1\&{then}\5
+$\|l\K0$\6
+\4\&{else} $\|l\K\\{language}$;\2\2\6
+\&{if} $\|l\I\\{clang}$ \1\&{then}\6
+\&{begin} \37$\\{new\_whatsit}(\\{language\_node},\39\\{small\_node\_size})$;\5
+$\\{what\_lang}(\\{tail})\K\|l$;\5
+$\\{clang}\K\|l$;\6
+$\\{what\_lhm}(\\{tail})\K\\{norm\_min}(\\{left\_hyphen\_min})$;\5
+$\\{what\_rhm}(\\{tail})\K\\{norm\_min}(\\{right\_hyphen\_min})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1390. \P$\X1390:Implement \.{\\setlanguage}\X\S$\6
+\&{if} $\\{abs}(\\{mode})\I\\{hmode}$ \1\&{then}\5
+\\{report\_illegal\_case}\6
+\4\&{else} \&{begin} \37$\\{new\_whatsit}(\\{language\_node},\39\\{small\_node%
+\_size})$;\5
+\\{scan\_int};\6
+\&{if} $\\{cur\_val}\L0$ \1\&{then}\5
+$\\{clang}\K0$\6
+\4\&{else} \&{if} $\\{cur\_val}>255$ \1\&{then}\5
+$\\{clang}\K0$\6
+\4\&{else} $\\{clang}\K\\{cur\_val}$;\2\2\6
+$\\{what\_lang}(\\{tail})\K\\{clang}$;\5
+$\\{what\_lhm}(\\{tail})\K\\{norm\_min}(\\{left\_hyphen\_min})$;\5
+$\\{what\_rhm}(\\{tail})\K\\{norm\_min}(\\{right\_hyphen\_min})$;\6
+\&{end}\2\par
+\U1361.\fi
+
+\M1391. \P$\X1391:Finish the extensions\X\S$\6
+\&{for} $\|k\K0\mathrel{\&{to}}15$ \1\&{do}\6
+\&{if} $\\{write\_open}[\|k]$ \1\&{then}\5
+$\\{a\_close}(\\{write\_file}[\|k])$\2\2\par
+\U1346.\fi
+
+\N1392.  \[54/web2c] System-dependent changes for Web2c.
+Here are extra variables for Web2c.  (This numbering of the
+system-dependent section allows easy integration of Web2c and e-\TeX, etc.)
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{edit\_name\_start}: \37\\{pool\_pointer};\C{where the filename to switch
+to starts}\6
+\4$\\{edit\_name\_length},\39\\{edit\_line}$: \37\\{integer};\C{what line to
+start editing at}\6
+\4\\{ipc\_on}: \37\\{cinttype};\C{level of IPC action, 0 for none [default]}\6
+\4\\{stop\_at\_space}: \37\\{boolean};\C{whether \\{more\_name} returns false
+for space}\par
+\fi
+
+\M1393. The \\{edit\_name\_start} will be set to point into \\{str\_pool}
+somewhere after
+its beginning if \TeX\ is supposed to switch to an editor on exit.
+
+\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{edit\_name\_start}\K0$;\5
+$\\{stop\_at\_space}\K\\{true}$;\par
+\fi
+
+\M1394. These are used when we regenerate the representation of the first 256
+strings.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{save\_str\_ptr}: \37\\{str\_number};\6
+\4\\{save\_pool\_ptr}: \37\\{pool\_pointer};\6
+\4\\{shellenabledp}: \37\\{cinttype};\6
+\4\\{restrictedshell}: \37\\{cinttype};\6
+\4\\{output\_comment}: \37$\^\\{char}$;\6
+\4$\|k,\39\|l$: \37$0\to255$;\C{used by `Make the first 256 strings', etc.}\par
+\fi
+
+\M1395. When debugging a macro package, it can be useful to see the exact
+control sequence names in the format file.  For example, if ten new
+csnames appear, it's nice to know what they are, to help pinpoint where
+they came from.  (This isn't a truly ``basic'' printing procedure, but
+that's a convenient module in which to put it.)
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_csnames}(\\{hstart}:\\{integer};\,\35%
+\\{hfinish}:\\{integer})$;\6
+\4\&{var} \37$\|c,\39\|h$: \37\\{integer};\2\6
+\&{begin} \37$\\{write\_ln}(\\{stderr},\39\.{\'fmtdebug:csnames\ from\ \'},\39%
+\\{hstart},\39\.{\'\ to\ \'},\39\\{hfinish},\39\.{\':\'})$;\6
+\&{for} $\|h\K\\{hstart}\mathrel{\&{to}}\\{hfinish}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{text}(\|h)>0$ \1\&{then}\6
+\&{begin} \37\C{if have anything at this position}\6
+\&{for} $\|c\K\\{str\_start}[\\{text}(\|h)]\mathrel{\&{to}}\\{str\_start}[%
+\\{text}(\|h)+1]-1$ \1\&{do}\6
+\&{begin} \37$\\{put\_byte}(\\{str\_pool}[\|c],\39\\{stderr})$;\C{print the
+characters}\6
+\&{end};\2\6
+$\\{write\_ln}(\\{stderr},\39\.{\'|\'})$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1396. Are we printing extra info as we read the format file?
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{debug\_format\_file}: \37\\{boolean};\par
+\fi
+
+\M1397. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+\&{debug} \37$\\{debug\_format\_file}\K\\{true}$;\ \&{gubed};\par
+\fi
+
+\M1398. A helper for printing file:line:error style messages.  Look for a
+filename in \\{full\_source\_filename\_stack}, and if we fail to find
+one fall back on the non-file:line:error style.
+
+\Y\P$\4\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{print\_file\_line};\6
+\4\&{var} \37\\{level}: \37$0\to\\{max\_in\_open}$;\2\6
+\&{begin} \37$\\{level}\K\\{in\_open}$;\6
+\&{while} $(\\{level}>0)\W(\\{full\_source\_filename\_stack}[\\{level}]=0)$ \1%
+\&{do}\5
+$\\{decr}(\\{level})$;\2\6
+\&{if} $\\{level}=0$ \1\&{then}\5
+$\\{print\_nl}(\.{"!\ "})$\6
+\4\&{else} \&{begin} \37$\\{print\_nl}(\.{""})$;\5
+$\\{print}(\\{full\_source\_filename\_stack}[\\{level}])$;\5
+$\\{print}(\.{":"})$;\6
+\&{if} $\\{level}=\\{in\_open}$ \1\&{then}\5
+$\\{print\_int}(\\{line})$\6
+\4\&{else} $\\{print\_int}(\\{line\_stack}[\\{level}+1])$;\2\6
+$\\{print}(\.{":\ "})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1399. To be able to determine whether \.{\\write18} is enabled from within
+\TeX\ we also implement \.{\\eof18}.  We sort of cheat by having an
+additional route \\{scan\_four\_bit\_int\_or\_18} which is the same as
+\\{scan\_four\_bit\_int} except it also accepts the value 18.
+
+\Y\P$\4\X444:Declare procedures that scan restricted classes of integers\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{scan\_four\_bit\_int\_or\_18};\2\6
+\&{begin} \37\\{scan\_int};\6
+\&{if} $(\\{cur\_val}<0)\V((\\{cur\_val}>15)\W(\\{cur\_val}\I18))$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Bad\ number"})$;\5
+$\\{help2}(\.{"Since\ I\ expected\ to\ read\ a\ number\ between\ 0\ and\
+15,"})$\6
+$(\.{"I\ changed\ this\ one\ to\ zero."})$;\5
+$\\{int\_error}(\\{cur\_val})$;\5
+$\\{cur\_val}\K0$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1400. Dumping the \\{xord}, \\{xchr}, and \\{xprn} arrays.  We dump these
+always
+in the format, so a TCX file loaded during format creation can set a
+default for users of the format.
+
+\Y\P$\4\X1400:Dump \\{xord}, \\{xchr}, and \\{xprn}\X\S$\6
+$\\{dump\_things}(\\{xord}[0],\39256)$;\5
+$\\{dump\_things}(\\{xchr}[0],\39256)$;\5
+$\\{dump\_things}(\\{xprn}[0],\39256)$;\par
+\U1320.\fi
+
+\M1401. Undumping the \\{xord}, \\{xchr}, and \\{xprn} arrays.  This code is
+more
+complicated, because we want to ensure that a TCX file specified on
+the command line will override whatever is in the format.  Since the
+tcx file has already been loaded, that implies throwing away the data
+in the format.  Also, if no \\{translate\_filename} is given, but
+\\{eight\_bit\_p} is set we have to make all characters printable.
+
+\Y\P$\4\X1401:Undump \\{xord}, \\{xchr}, and \\{xprn}\X\S$\6
+\&{if} $\\{translate\_filename}$ \1\&{then}\6
+\&{begin} \37\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{undump\_things}(\\{dummy\_xord},\391)$;\2\6
+\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{undump\_things}(\\{dummy\_xchr},\391)$;\2\6
+\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{undump\_things}(\\{dummy\_xprn},\391)$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{undump\_things}(\\{xord}[0],\39256)$;\5
+$\\{undump\_things}(\\{xchr}[0],\39256)$;\5
+$\\{undump\_things}(\\{xprn}[0],\39256)$;\6
+\&{if} $\\{eight\_bit\_p}$ \1\&{then}\6
+\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\5
+$\\{xprn}[\|k]\K1$;\2\2\6
+\&{end};\2\par
+\U1321.\fi
+
+\N1402.  \[54/web2c-string] The string recycling routines.
+\TeX{} uses 2 upto 4 {\it new\/} strings when scanning a filename in an
+\.{\\input}, \.{\\openin}, or \.{\\openout} operation.  These strings are
+normally lost because the reference to them are not saved after finishing
+the operation.  \\{search\_string} searches through the string pool for the
+given string and returns either 0 or the found string number.
+
+\Y\P$\4\X1402:Declare additional routines for string recycling\X\S$\6
+\4\&{function}\1\  \37$\\{search\_string}(\\{search}:\\{str\_number})$: \37%
+\\{str\_number};\6
+\4\&{label} \37\\{found};\6
+\4\&{var} \37\\{result}: \37\\{str\_number};\5
+\|s: \37\\{str\_number};\C{running index}\6
+\\{len}: \37\\{integer};\C{length of searched string}\2\6
+\&{begin} \37$\\{result}\K0$;\5
+$\\{len}\K\\{length}(\\{search})$;\6
+\&{if} $\\{len}=0$ \1\&{then}\C{trivial case}\6
+\&{begin} \37$\\{result}\K\.{""}$;\5
+\&{goto} \37\\{found};\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|s\K\\{search}-1$;\C{start search with newest string
+below \|s; $\\{search}>1$!}\6
+\&{while} $\|s>255$ \1\&{do}\C{first 256 strings depend on implementation!!}\6
+\&{begin} \37\&{if} $\\{length}(\|s)=\\{len}$ \1\&{then}\6
+\&{if} $\\{str\_eq\_str}(\|s,\39\\{search})$ \1\&{then}\6
+\&{begin} \37$\\{result}\K\|s$;\5
+\&{goto} \37\\{found};\6
+\&{end};\2\2\6
+$\\{decr}(\|s)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{found}: \37$\\{search\_string}\K\\{result}$;\6
+\&{end};\par
+\A1403.
+\U48.\fi
+
+\M1403. The following routine is a variant of \\{make\_string}.  It searches
+the whole string pool for a string equal to the string currently built
+and returns a found string.  Otherwise a new string is created and
+returned.  Be cautious, you can not apply \\{flush\_string} to a replaced
+string!
+
+\Y\P$\4\X1402:Declare additional routines for string recycling\X\mathrel{+}\S$\6
+\4\&{function}\1\  \37\\{slow\_make\_string}: \37\\{str\_number};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\|s: \37\\{str\_number};\C{result of \\{search\_string}}\6
+\|t: \37\\{str\_number};\C{new string}\2\6
+\&{begin} \37$\|t\K\\{make\_string}$;\5
+$\|s\K\\{search\_string}(\|t)$;\6
+\&{if} $\|s>0$ \1\&{then}\6
+\&{begin} \37\\{flush\_string};\5
+$\\{slow\_make\_string}\K\|s$;\5
+\&{return};\6
+\&{end};\2\6
+$\\{slow\_make\_string}\K\|t$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\N1404.  \[54/ML\TeX] System-dependent changes for ML\TeX.
+
+The boolean variable \\{mltex\_p} is set by web2c according to the given
+command line option (or an entry in the configuration file) before any
+\TeX{} function is called.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{mltex\_p}: \37\\{boolean};\par
+\fi
+
+\M1405. The boolean variable \\{mltex\_enabled\_p} is used to enable ML\TeX's
+character substitution.  It is initialised to \\{false}.  When loading
+a \.{FMT} it is set to the value of the boolean \\{mltex\_p} saved in
+the \.{FMT} file.  Additionally it is set to the value of \\{mltex\_p}
+in Ini\TeX.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{mltex\_enabled\_p}: \37\\{boolean};\C{enable character substitution}\par
+\fi
+
+\M1406. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{mltex\_enabled\_p}\K\\{false}$;\par
+\fi
+
+\M1407. The function \\{effective\_char} computes the effective character with
+respect to font information.  The effective character is either the
+base character part of a character substitution definition, if the
+character does not exist in the font or the character itself.
+
+Inside \\{effective\_char} we can not use \\{char\_info} because the macro
+\\{char\_info} uses \\{effective\_char} calling this function a second time
+with the same arguments.
+
+If neither the character \|c exists in font \|f nor a character
+substitution for \|c was defined, you can not use the function value
+as a character offset in \\{char\_info} because it will access an
+undefined or invalid \\{font\_info} entry!  Therefore inside \\{char\_info}
+and in other places, \\{effective\_char}'s boolean parameter \\{err\_p} is
+set to \\{true} to issue a warning and return the incorrect
+replacement, but always existing character $\\{font\_bc}[\|f]$.
+
+\Y\P$\4\X1407:Declare additional functions for ML\TeX\X\S$\6
+\4\&{function}\1\  \37$\\{effective\_char}(\\{err\_p}:\\{boolean};\,\35\|f:%
+\\{internal\_font\_number};\,\35\|c:\\{quarterword})$: \37\\{integer};\6
+\4\&{label} \37\\{found};\6
+\4\&{var} \37\\{base\_c}: \37\\{integer};\C{or \\{eightbits}: replacement base
+character}\6
+\\{result}: \37\\{integer};\C{or \\{quarterword}}\2\6
+\&{begin} \37$\\{result}\K\|c$;\C{return \|c unless it does not exist in the
+font}\6
+\&{if} $\R\\{mltex\_enabled\_p}$ \1\&{then}\5
+\&{goto} \37\\{found};\2\6
+\&{if} $\\{font\_ec}[\|f]\G\\{qo}(\|c)$ \1\&{then}\6
+\&{if} $\\{font\_bc}[\|f]\L\\{qo}(\|c)$ \1\&{then}\6
+\&{if} $\\{char\_exists}(\\{orig\_char\_info}(\|f)(\|c))$ \1\&{then}\C{N.B.:
+not \\{char\_info}(f)(c)}\6
+\&{goto} \37\\{found};\2\2\2\6
+\&{if} $\\{qo}(\|c)\G\\{char\_sub\_def\_min}$ \1\&{then}\6
+\&{if} $\\{qo}(\|c)\L\\{char\_sub\_def\_max}$ \1\&{then}\6
+\&{if} $\\{char\_list\_exists}(\\{qo}(\|c))$ \1\&{then}\6
+\&{begin} \37$\\{base\_c}\K\\{char\_list\_char}(\\{qo}(\|c))$;\5
+$\\{result}\K\\{qi}(\\{base\_c})$;\C{return \\{base\_c}}\6
+\&{if} $\R\\{err\_p}$ \1\&{then}\5
+\&{goto} \37\\{found};\2\6
+\&{if} $\\{font\_ec}[\|f]\G\\{base\_c}$ \1\&{then}\6
+\&{if} $\\{font\_bc}[\|f]\L\\{base\_c}$ \1\&{then}\6
+\&{if} $\\{char\_exists}(\\{orig\_char\_info}(\|f)(\\{qi}(\\{base\_c})))$ \1%
+\&{then}\5
+\&{goto} \37\\{found};\2\2\2\6
+\&{end};\2\2\2\6
+\&{if} $\\{err\_p}$ \1\&{then}\C{print error and return existing character?}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"Missing\ character:\ There\ is\ no\ "})$;\5
+$\\{print}(\.{"substitution\ for\ "})$;\5
+$\\{print\_ASCII}(\\{qo}(\|c))$;\5
+$\\{print}(\.{"\ in\ font\ "})$;\5
+$\\{slow\_print}(\\{font\_name}[\|f])$;\5
+$\\{print\_char}(\.{"!"})$;\5
+$\\{end\_diagnostic}(\\{false})$;\5
+$\\{result}\K\\{qi}(\\{font\_bc}[\|f])$;\C{N.B.: not non-existing character %
+\|c!}\6
+\&{end};\2\6
+\4\\{found}: \37$\\{effective\_char}\K\\{result}$;\6
+\&{end};\par
+\A1408.
+\U571.\fi
+
+\M1408. The function \\{effective\_char\_info} is equivalent to \\{char\_info},
+except it will return \\{null\_character} if neither the character \|c
+exists in font \|f nor is there a substitution definition for \|c.
+(For these cases \\{char\_info} using \\{effective\_char} will access an
+undefined or invalid \\{font\_info} entry.  See the documentation of
+\\{effective\_char} for more information.)
+
+\Y\P$\4\X1407:Declare additional functions for ML\TeX\X\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{effective\_char\_info}(\|f:\\{internal\_font%
+\_number};\,\35\|c:\\{quarterword})$: \37\\{four\_quarters};\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37\\{ci}: \37\\{four\_quarters};\C{character information bytes for %
+\|c}\6
+\\{base\_c}: \37\\{integer};\C{or \\{eightbits}: replacement base character}\2\6
+\&{begin} \37\&{if} $\R\\{mltex\_enabled\_p}$ \1\&{then}\6
+\&{begin} \37$\\{effective\_char\_info}\K\\{orig\_char\_info}(\|f)(\|c)$;\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $\\{font\_ec}[\|f]\G\\{qo}(\|c)$ \1\&{then}\6
+\&{if} $\\{font\_bc}[\|f]\L\\{qo}(\|c)$ \1\&{then}\6
+\&{begin} \37$\\{ci}\K\\{orig\_char\_info}(\|f)(\|c)$;\C{N.B.: not \\{char%
+\_info}(f)(c)}\6
+\&{if} $\\{char\_exists}(\\{ci})$ \1\&{then}\6
+\&{begin} \37$\\{effective\_char\_info}\K\\{ci}$;\5
+\&{return};\6
+\&{end};\2\6
+\&{end};\2\2\6
+\&{if} $\\{qo}(\|c)\G\\{char\_sub\_def\_min}$ \1\&{then}\6
+\&{if} $\\{qo}(\|c)\L\\{char\_sub\_def\_max}$ \1\&{then}\6
+\&{if} $\\{char\_list\_exists}(\\{qo}(\|c))$ \1\&{then}\6
+\&{begin} \37\C{$\\{effective\_char\_info}\K\\{char\_info}(\|f)(\\{qi}(\\{char%
+\_list\_char}(\\{qo}(\|c))))$;}\6
+$\\{base\_c}\K\\{char\_list\_char}(\\{qo}(\|c))$;\6
+\&{if} $\\{font\_ec}[\|f]\G\\{base\_c}$ \1\&{then}\6
+\&{if} $\\{font\_bc}[\|f]\L\\{base\_c}$ \1\&{then}\6
+\&{begin} \37$\\{ci}\K\\{orig\_char\_info}(\|f)(\\{qi}(\\{base\_c}))$;\C{N.B.:
+not \\{char\_info}(f)(c)}\6
+\&{if} $\\{char\_exists}(\\{ci})$ \1\&{then}\6
+\&{begin} \37$\\{effective\_char\_info}\K\\{ci}$;\5
+\&{return};\6
+\&{end};\2\6
+\&{end};\2\2\6
+\&{end};\2\2\2\6
+$\\{effective\_char\_info}\K\\{null\_character}$;\6
+\4\\{exit}: \37\&{end};\par
+\fi
+
+\M1409. This code is called for a virtual character \|c in \\{hlist\_out}
+during \\{ship\_out}.  It tries to built a character substitution
+construct for \|c generating appropriate \.{DVI} code using the
+character substitution definition for this character.  If a valid
+character substitution exists \.{DVI} code is created as if
+\\{make\_accent} was used.  In all other cases the status of the
+substituion for this character has been changed between the creation
+of the character node in the hlist and the output of the page---the
+created \.{DVI} code will be correct but the visual result will be
+undefined.
+
+Former ML\TeX\ versions have replaced the character node by a
+sequence of character, box, and accent kern nodes splicing them into
+the original horizontal list.  This version does not do this to avoid
+a)~a memory overflow at this processing stage, b)~additional code to
+add a pointer to the previous node needed for the replacement, and
+c)~to avoid wrong code resulting in anomalies because of the use
+within a \.{\\leaders} box.
+
+\Y\P$\4\X1409:Output a substitution, \&{goto} \\{continue} if not possible\X\S$%
+\6
+\&{begin} \37\X1411:Get substitution information, check it, goto \\{found} if
+all is ok, otherwise goto \\{continue}\X;\6
+\4\\{found}: \37\X1412:Print character substition tracing log\X;\6
+\X1413:Rebuild character using substitution information\X;\6
+\&{end}\par
+\U631.\fi
+
+\M1410. The global variables for the code to substitute a virtual character
+can be declared as local.  Nonetheless we declare them as global to
+avoid stack overflows because \\{hlist\_out} can be called recursivly.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4$\\{accent\_c},\39\\{base\_c},\39\\{replace\_c}$: \37\\{integer};\6
+\4$\\{ia\_c},\39\\{ib\_c}$: \37\\{four\_quarters};\C{accent and base character
+information}\6
+\4$\\{base\_slant},\39\\{accent\_slant}$: \37\\{real};\C{amount of slant}\6
+\4\\{base\_x\_height}: \37\\{scaled};\C{accent is designed for characters of
+this height}\6
+\4$\\{base\_width},\39\\{base\_height}$: \37\\{scaled};\C{height and width for
+base character}\6
+\4$\\{accent\_width},\39\\{accent\_height}$: \37\\{scaled};\C{height and width
+for accent}\6
+\4\\{delta}: \37\\{scaled};\C{amount of right shift}\par
+\fi
+
+\M1411. Get the character substitution information in \\{char\_sub\_code} for
+the character \|c.  The current code checks that the substition
+exists and is valid and all substitution characters exist in the
+font, so we can {\it not\/} substitute a character used in a
+substitution.  This simplifies the code because we have not to check
+for cycles in all character substitution definitions.
+
+\Y\P$\4\X1411:Get substitution information, check it, goto \\{found} if all is
+ok, otherwise goto \\{continue}\X\S$\6
+\&{if} $\\{qo}(\|c)\G\\{char\_sub\_def\_min}$ \1\&{then}\6
+\&{if} $\\{qo}(\|c)\L\\{char\_sub\_def\_max}$ \1\&{then}\6
+\&{if} $\\{char\_list\_exists}(\\{qo}(\|c))$ \1\&{then}\6
+\&{begin} \37$\\{base\_c}\K\\{char\_list\_char}(\\{qo}(\|c))$;\5
+$\\{accent\_c}\K\\{char\_list\_accent}(\\{qo}(\|c))$;\6
+\&{if} $(\\{font\_ec}[\|f]\G\\{base\_c})$ \1\&{then}\6
+\&{if} $(\\{font\_bc}[\|f]\L\\{base\_c})$ \1\&{then}\6
+\&{if} $(\\{font\_ec}[\|f]\G\\{accent\_c})$ \1\&{then}\6
+\&{if} $(\\{font\_bc}[\|f]\L\\{accent\_c})$ \1\&{then}\6
+\&{begin} \37$\\{ia\_c}\K\\{char\_info}(\|f)(\\{qi}(\\{accent\_c}))$;\5
+$\\{ib\_c}\K\\{char\_info}(\|f)(\\{qi}(\\{base\_c}))$;\6
+\&{if} $\\{char\_exists}(\\{ib\_c})$ \1\&{then}\6
+\&{if} $\\{char\_exists}(\\{ia\_c})$ \1\&{then}\5
+\&{goto} \37\\{found};\2\2\6
+\&{end};\2\2\2\2\6
+\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"Missing\ character:\ Incomplete\ substitution\ "})$;\5
+$\\{print\_ASCII}(\\{qo}(\|c))$;\5
+$\\{print}(\.{"\ =\ "})$;\5
+$\\{print\_ASCII}(\\{accent\_c})$;\5
+$\\{print}(\.{"\ "})$;\5
+$\\{print\_ASCII}(\\{base\_c})$;\5
+$\\{print}(\.{"\ in\ font\ "})$;\5
+$\\{slow\_print}(\\{font\_name}[\|f])$;\5
+$\\{print\_char}(\.{"!"})$;\5
+$\\{end\_diagnostic}(\\{false})$;\5
+\&{goto} \37\\{continue};\6
+\&{end};\2\2\2\6
+\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"Missing\ character:\ There\ is\ no\ "})$;\5
+$\\{print}(\.{"substitution\ for\ "})$;\5
+$\\{print\_ASCII}(\\{qo}(\|c))$;\5
+$\\{print}(\.{"\ in\ font\ "})$;\5
+$\\{slow\_print}(\\{font\_name}[\|f])$;\5
+$\\{print\_char}(\.{"!"})$;\5
+$\\{end\_diagnostic}(\\{false})$;\5
+\&{goto} \37\\{continue}\par
+\U1409.\fi
+
+\M1412. For $\\{tracinglostchars}>99$ the substitution is shown in the log
+file.
+
+\Y\P$\4\X1412:Print character substition tracing log\X\S$\6
+\&{if} $\\{tracing\_lost\_chars}>99$ \1\&{then}\6
+\&{begin} \37\\{begin\_diagnostic};\5
+$\\{print\_nl}(\.{"Using\ character\ substitution:\ "})$;\5
+$\\{print\_ASCII}(\\{qo}(\|c))$;\5
+$\\{print}(\.{"\ =\ "})$;\5
+$\\{print\_ASCII}(\\{accent\_c})$;\5
+$\\{print}(\.{"\ "})$;\5
+$\\{print\_ASCII}(\\{base\_c})$;\5
+$\\{print}(\.{"\ in\ font\ "})$;\5
+$\\{slow\_print}(\\{font\_name}[\|f])$;\5
+$\\{print\_char}(\.{"."})$;\5
+$\\{end\_diagnostic}(\\{false})$;\6
+\&{end}\2\par
+\U1409.\fi
+
+\M1413. This outputs the accent and the base character given in the
+substitution.  It uses code virtually identical to the \\{make\_accent}
+procedure, but without the node creation steps.
+
+Additionally if the accent character has to be shifted vertically it
+does {\it not\/} create the same code.  The original routine in
+\\{make\_accent} and former versions of ML\TeX{} creates a box node
+resulting in \\{push} and \\{pop} operations, whereas this code simply
+produces vertical positioning operations.  This can influence the
+pixel rounding algorithm in some \.{DVI} drivers---and therefore will
+probably be changed in one of the next ML\TeX{} versions.
+
+\Y\P$\4\X1413:Rebuild character using substitution information\X\S$\6
+$\\{base\_x\_height}\K\\{x\_height}(\|f)$;\5
+$\\{base\_slant}\K\\{slant}(\|f)/\\{float\_constant}(65536)$;\5
+$\\{accent\_slant}\K\\{base\_slant}$;\C{slant of accent character font}\6
+$\\{base\_width}\K\\{char\_width}(\|f)(\\{ib\_c})$;\5
+$\\{base\_height}\K\\{char\_height}(\|f)(\\{height\_depth}(\\{ib\_c}))$;\5
+$\\{accent\_width}\K\\{char\_width}(\|f)(\\{ia\_c})$;\5
+$\\{accent\_height}\K\\{char\_height}(\|f)(\\{height\_depth}(\\{ia\_c}))$;\6
+\C{compute necessary horizontal shift (don't forget slant)}\6
+$\\{delta}\K\\{round}((\\{base\_width}-\\{accent\_width})/\\{float%
+\_constant}(2)+\\{base\_height}\ast\\{base\_slant}-\\{base\_x\_height}\ast%
+\\{accent\_slant})$;\5
+$\\{dvi\_h}\K\\{cur\_h}$;\C{update \\{dvi\_h}, similar to the last statement in
+module 620}\6
+\C{1. For centering/horizontal shifting insert a kern node.}\6
+$\\{cur\_h}\K\\{cur\_h}+\\{delta}$;\5
+\\{synch\_h};\6
+\C{2. Then insert the accent character possibly shifted up or down.}\6
+\&{if} $((\\{base\_height}\I\\{base\_x\_height})\W(\\{accent\_height}>0))$ \1%
+\&{then}\6
+\&{begin} \37\C{the accent must be shifted up or down}\6
+$\\{cur\_v}\K\\{base\_line}+(\\{base\_x\_height}-\\{base\_height})$;\5
+\\{synch\_v};\6
+\&{if} $\\{accent\_c}\G128$ \1\&{then}\5
+$\\{dvi\_out}(\\{set1})$;\2\6
+$\\{dvi\_out}(\\{accent\_c})$;\6
+$\\{cur\_v}\K\\{base\_line}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\\{synch\_v};\6
+\&{if} $\\{accent\_c}\G128$ \1\&{then}\5
+$\\{dvi\_out}(\\{set1})$;\2\6
+$\\{dvi\_out}(\\{accent\_c})$;\6
+\&{end};\2\6
+$\\{cur\_h}\K\\{cur\_h}+\\{accent\_width}$;\5
+$\\{dvi\_h}\K\\{cur\_h}$;\6
+\C{3. For centering/horizontal shifting insert another kern node.}\6
+$\\{cur\_h}\K\\{cur\_h}+(-\\{accent\_width}-\\{delta})$;\6
+\C{4. Output the base character.}\6
+\\{synch\_h};\5
+\\{synch\_v};\6
+\&{if} $\\{base\_c}\G128$ \1\&{then}\5
+$\\{dvi\_out}(\\{set1})$;\2\6
+$\\{dvi\_out}(\\{base\_c})$;\6
+$\\{cur\_h}\K\\{cur\_h}+\\{base\_width}$;\5
+$\\{dvi\_h}\K\\{cur\_h}$\C{update of \\{dvi\_h} is unnecessary, will be set in
+module 620}\par
+\U1409.\fi
+
+\M1414. Dumping ML\TeX-related material.  This is just the flag in the
+format that tells us whether ML\TeX{} is enabled.
+
+\Y\P$\4\X1414:Dump ML\TeX-specific data\X\S$\6
+$\\{dump\_int}(\H{4D4C5458})$;\C{ML\TeX's magic constant: "MLTX"}\6
+\&{if} $\\{mltex\_p}$ \1\&{then}\5
+$\\{dump\_int}(1)$\6
+\4\&{else} $\\{dump\_int}(0)$;\2\par
+\U1315.\fi
+
+\M1415. Undump ML\TeX-related material, which is just a flag in the format
+that tells us whether ML\TeX{} is enabled.
+
+\Y\P$\4\X1415:Undump ML\TeX-specific data\X\S$\6
+$\\{undump\_int}(\|x)$;\C{check magic constant of ML\TeX}\6
+\&{if} $\|x\I\H{4D4C5458}$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\6
+$\\{undump\_int}(\|x)$;\C{undump \\{mltex\_p} flag into \\{mltex\_enabled\_p}}\6
+\&{if} $\|x=1$ \1\&{then}\5
+$\\{mltex\_enabled\_p}\K\\{true}$\6
+\4\&{else} \&{if} $\|x\I0$ \1\&{then}\5
+\&{goto} \37\\{bad\_fmt};\2\2\par
+\U1316.\fi
+
+\N1416.  \[55/p\TeX] System-dependent changes for p\TeX.
+This section described extended variables, procesures, functions and so on
+for pTeX.
+
+\Y\P$\4\X588:Declare procedures that scan font-related stuff\X\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{get\_jfm\_pos}(\\{kcode}:\\{KANJI\_code};\,\35\|f:%
+\\{internal\_font\_number})$: \37\\{eight\_bits};\6
+\4\&{var} \37\\{jc}: \37\\{KANJI\_code};\C{temporary register for KANJI}\6
+$\\{sp},\39\\{mp},\39\\{ep}$: \37\\{pointer};\2\6
+\&{begin} \37\&{if} $\|f=\\{null\_font}$ \1\&{then}\6
+\&{begin} \37$\\{get\_jfm\_pos}\K\\{kchar\_type}(\\{null\_font})(0)$;\5
+\&{return};\6
+\&{end};\2\6
+$\\{jc}\K\\{toDVI}(\\{kcode})$;\5
+$\\{sp}\K1$;\C{ start position }\6
+$\\{ep}\K\\{font\_num\_ext}[\|f]-1$;\C{ end position }\6
+\&{if} $(\\{ep}\G1)\W(\\{kchar\_code}(\|f)(\\{sp})\L\\{jc})\W(\\{jc}\L\\{kchar%
+\_code}(\|f)(\\{ep}))$ \1\&{then}\6
+\&{begin} \37\&{while} $(\\{sp}\L\\{ep})$ \1\&{do}\6
+\&{begin} \37$\\{mp}\K\\{sp}+((\\{ep}-\\{sp})\mathbin{\&{div}}2)$;\6
+\&{if} $\\{jc}<\\{kchar\_code}(\|f)(\\{mp})$ \1\&{then}\5
+$\\{ep}\K\\{mp}-1$\6
+\4\&{else} \&{if} $\\{jc}>\\{kchar\_code}(\|f)(\\{mp})$ \1\&{then}\5
+$\\{sp}\K\\{mp}+1$\6
+\4\&{else} \&{begin} \37$\\{get\_jfm\_pos}\K\\{kchar\_type}(\|f)(\\{mp})$;\5
+\&{return};\6
+\&{end};\2\2\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{get\_jfm\_pos}\K\\{kchar\_type}(\|f)(0)$;\6
+\&{end};\par
+\fi
+
+\M1417. Following codes are used to calcutation a KANJI width and height.
+
+\Y\P$\4\X461:Local variables for dimension calculations\X\mathrel{+}\S$\6
+\4\|t: \37\\{eight\_bits};\par
+\fi
+
+\M1418. \P$\X1418:The KANJI width for \\{cur\_jfont}\X\S$\6
+\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\5
+$\|v\K\\{char\_width}(\\{cur\_tfont})(\\{orig\_char\_info}(\\{cur\_tfont})(%
+\\{qi}(0)))$\6
+\4\&{else} $\|v\K\\{char\_width}(\\{cur\_jfont})(\\{orig\_char\_info}(\\{cur%
+\_jfont})(\\{qi}(0)))$\2\par
+\U466.\fi
+
+\M1419. \P$\X1419:The KANJI height for \\{cur\_jfont}\X\S$\6
+\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\6
+\&{begin} \37$\|t\K\\{height\_depth}(\\{orig\_char\_info}(\\{cur\_tfont})(%
+\\{qi}(0)))$;\5
+$\|v\K\\{char\_height}(\\{cur\_tfont})(\|t)+\\{char\_depth}(\\{cur\_tfont})(%
+\|t)$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|t\K\\{height\_depth}(\\{orig\_char\_info}(\\{cur%
+\_jfont})(\\{qi}(0)))$;\5
+$\|v\K\\{char\_height}(\\{cur\_jfont})(\|t)+\\{char\_depth}(\\{cur\_jfont})(%
+\|t)$;\6
+\&{end}\2\par
+\U466.\fi
+
+\M1420. set a kansuji character.
+
+\fi
+
+\M1421. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"kansujichar"},\39\\{set\_kansuji\_char},\390)$;\par
+\fi
+
+\M1422. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{set\_kansuji\_char}: \37$\\{print\_esc}(\.{"kansujichar"})$;\par
+\fi
+
+\M1423. \P$\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{set\_kansuji\_char}: \37\&{begin} \37$\|p\K\\{cur\_chr}$;\5
+\\{scan\_int};\5
+$\|n\K\\{cur\_val}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_int};\6
+\&{if} $\R\\{is\_char\_kanji}(\\{cur\_val})$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Invalid\ KANSUJI\ char\ ("})$;\5
+$\\{print\_hex}(\\{cur\_val})$;\5
+$\\{print\_char}(\.{")"})$;\5
+$\\{help1}(\.{"I\'m\ skip\ this\ control\ sequences."})$;\6
+\\{error};\5
+\&{return};\6
+\&{end}\6
+\4\&{else} \&{if} $(\|n<0)\V(\|n>9)$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Invalid\ KANSUJI\ number\ ("})$;\5
+$\\{print\_int}(\|n)$;\5
+$\\{print\_char}(\.{")"})$;\5
+$\\{help1}(\.{"I\'m\ skip\ this\ control\ sequences."})$;\6
+\\{error};\5
+\&{return};\6
+\&{end}\6
+\4\&{else} $\\{define}(\\{kansuji\_base}+\|n,\39\|n,\39\\{tokanji}(\\{toDVI}(%
+\\{cur\_val})))$;\2\2\6
+\&{end};\par
+\fi
+
+\M1424. \\{print\_kansuji} procedure converts a number to KANJI number.
+
+\fi
+
+\M1425. \P$\X1425:Declare procedures needed in \\{scan\_something\_internal}\X%
+\S$\6
+\4\&{procedure}\1\  \37$\\{print\_kansuji}(\|n:\\{integer})$;\6
+\4\&{var} \37\|k: \37$0\to23$;\C{index to current digit; we assume that $%
+\|n<10^{23}$}\6
+\\{cx}: \37\\{KANJI\_code};\C{temporary register for KANJI}\2\6
+\&{begin} \37$\|k\K0$;\6
+\&{if} $\|n<0$ \1\&{then}\5
+\&{return};\C{nonpositive input produces no output}\2\6
+\1\&{repeat} \37$\\{dig}[\|k]\K\|n\mathbin{\&{mod}}10$;\5
+$\|n\K\|n\mathbin{\&{div}}10$;\5
+$\\{incr}(\|k)$;\6
+\4\&{until}\5
+$\|n=0$;\2\6
+\&{begin} \37\&{while} $\|k>0$ \1\&{do}\6
+\&{begin} \37$\\{decr}(\|k)$;\5
+$\\{cx}\K\\{kansuji\_char}(\\{dig}[\|k])$;\5
+$\\{print\_kanji}(\\{fromDVI}(\\{cx}))$;\6
+\&{end};\2\6
+\&{end};\6
+\&{end};\par
+\As1435\ET1440.
+\U424.\fi
+
+\M1426. pTeX inserts a glue specified by \.{\\kanjiskip} between
+2byte-characters,
+automatically, if \.{\\autospacing}.  This glue is suppressed by
+\.{\\noautospacing}.
+\.{\\xkanjiskip}, \.{\\noautoxspacing}, \.{\\autoxspacing}, \.{\\xspcode} is
+used to control between 2byte and 1byte characters.
+
+\Y\P\D \37$\\{reset\_auto\_spacing\_code}=0$\par
+\P\D \37$\\{set\_auto\_spacing\_code}=1$\par
+\P\D \37$\\{reset\_auto\_xspacing\_code}=2$\par
+\P\D \37$\\{set\_auto\_xspacing\_code}=3$\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"autospacing"},\39\\{set\_auto\_spacing},\39\\{set\_auto%
+\_spacing\_code})$;\5
+$\\{primitive}(\.{"noautospacing"},\39\\{set\_auto\_spacing},\39\\{reset\_auto%
+\_spacing\_code})$;\5
+$\\{primitive}(\.{"autoxspacing"},\39\\{set\_auto\_spacing},\39\\{set\_auto%
+\_xspacing\_code})$;\5
+$\\{primitive}(\.{"noautoxspacing"},\39\\{set\_auto\_spacing},\39\\{reset\_auto%
+\_xspacing\_code})$;\par
+\fi
+
+\M1427. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{set\_auto\_spacing}: \37\&{begin} \37\&{if} $(\\{chr\_code}\mathbin{%
+\&{mod}}2)=0$ \1\&{then}\5
+$\\{print\_esc}(\.{"noauto"})$\6
+\4\&{else} $\\{print\_esc}(\.{"auto"})$;\2\6
+\&{if} $\\{chr\_code}<2$ \1\&{then}\5
+$\\{print}(\.{"spacing"})$\6
+\4\&{else} $\\{print}(\.{"xspacing"})$;\2\6
+\&{end};\par
+\fi
+
+\M1428. \P$\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{set\_auto\_spacing}: \37\&{begin} \37\&{if} $\\{cur\_chr}<2$ \1\&{then}\5
+$\|p\K\\{auto\_spacing\_code}$\6
+\4\&{else} \&{begin} \37$\|p\K\\{auto\_xspacing\_code}$;\5
+$\\{cur\_chr}\K(\\{cur\_chr}\mathbin{\&{mod}}2)$;\6
+\&{end};\2\6
+$\\{define}(\|p,\39\\{data},\39\\{cur\_chr})$;\6
+\&{end};\par
+\fi
+
+\M1429. Following codes are used in section 49.
+
+\Y\P$\4\X1429:Show the current japanese processing mode\X\S$\6
+\&{begin} \37$\\{print\_nl}(\.{">\ "})$;\6
+\&{if} $\\{auto\_spacing}>0$ \1\&{then}\5
+$\\{print}(\.{"auto\ spacing\ mode;\ "})$\6
+\4\&{else} $\\{print}(\.{"no\ auto\ spacing\ mode;\ "})$;\2\6
+$\\{print\_nl}(\.{">\ "})$;\6
+\&{if} $\\{auto\_xspacing}>0$ \1\&{then}\5
+$\\{print}(\.{"auto\ xspacing\ mode"})$\6
+\4\&{else} $\\{print}(\.{"no\ auto\ xspacing\ mode"})$;\2\6
+\&{goto} \37\\{common\_ending};\6
+\&{end}\par
+\U1306.\fi
+
+\M1430. The \.{\\inhibitglue} primitive control to insert a glue specified
+JFM (Japanese Font Metic) file.  The \.{\\inhibitxspcode} is used to control
+inserting a space between 2byte-char and 1byte-char.
+
+\Y\P\D \37$\\{inhibit\_both}=0$\C{disable to insert space before 2byte-char and
+after it}\par
+\P\D \37$\\{inhibit\_previous}=1$\C{disable to insert space before 2byte-char}%
+\par
+\P\D \37$\\{inhibit\_after}=2$\C{disable to insert space after 2byte-char}\par
+\P\D \37$\\{no\_entry}=1000$\par
+\P\D \37$\\{new\_pos}=0$\par
+\P\D \37$\\{cur\_pos}=1$\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{inhibit\_glue\_flag}: \37\\{boolean};\par
+\fi
+
+\M1431. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{inhibit\_glue\_flag}\K\\{false}$;\par
+\fi
+
+\M1432. \P$\X1222:Cases of \\{main\_control} that don't depend on \\{mode}\X%
+\mathrel{+}\S$\6
+\4$\\{any\_mode}(\\{inhibit\_glue})$: \37$\\{inhibit\_glue\_flag}\K\\{true}$;%
+\par
+\fi
+
+\M1433. \P$\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}%
+\S$\6
+$\\{primitive}(\.{"inhibitglue"},\39\\{inhibit\_glue},\390)$;\5
+$\\{primitive}(\.{"inhibitxspcode"},\39\\{assign\_inhibit\_xsp\_code},\39%
+\\{inhibit\_xsp\_code\_base})$;\par
+\fi
+
+\M1434. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{inhibit\_glue}: \37$\\{print\_esc}(\.{"inhibitglue"})$;\6
+\4\\{assign\_inhibit\_xsp\_code}: \37$\\{print\_esc}(\.{"inhibitxspcode"})$;\par
+\fi
+
+\M1435. \P$\X1425:Declare procedures needed in \\{scan\_something\_internal}\X%
+\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{get\_inhibit\_pos}(\|c:\\{KANJI\_code};\,\35\|n:%
+\\{small\_number})$: \37\\{pointer};\6
+\4\&{label} \37$\\{done},\39\\{done1}$;\6
+\4\&{var} \37$\|p,\39\|s$: \37\\{pointer};\2\6
+\&{begin} \37$\|s\K\\{calc\_pos}(\|c)$;\5
+$\|p\K\|s$;\6
+\&{if} $\|n=\\{new\_pos}$ \1\&{then}\6
+\&{begin} \37\1\&{repeat} \37\&{if} $(\\{inhibit\_xsp\_code}(\|p)=0)\V(%
+\\{inhibit\_xsp\_code}(\|p)=\|c)$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\\{incr}(\|p)$;\6
+\&{if} $\|p>255$ \1\&{then}\5
+$\|p\K0$;\2\6
+\4\&{until}\5
+$\|s=\|p$;\2\6
+$\|p\K\\{no\_entry}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\1\&{repeat} \37\&{if} $\\{inhibit\_xsp\_code}(\|p)=0$ %
+\1\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\&{if} $\\{inhibit\_xsp\_code}(\|p)=\|c$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\\{incr}(\|p)$;\6
+\&{if} $\|p>255$ \1\&{then}\5
+$\|p\K0$;\2\6
+\4\&{until}\5
+$\|s=\|p$;\2\6
+\4\\{done1}: \37$\|p\K\\{no\_entry}$;\6
+\&{end};\2\6
+\4\\{done}: \37$\\{get\_inhibit\_pos}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M1436. \P$\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{assign\_inhibit\_xsp\_code}: \37\&{begin} \37$\|p\K\\{cur\_chr}$;\5
+\\{scan\_int};\5
+$\|n\K\\{cur\_val}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_int};\6
+\&{if} $\\{is\_char\_kanji}(\|n)$ \1\&{then}\6
+\&{begin} \37$\|j\K\\{get\_inhibit\_pos}(\\{tokanji}(\|n),\39\\{new\_pos})$;\6
+\&{if} $\|j=\\{no\_entry}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Inhibit\ table\ is\ full!!"})$;\5
+$\\{help1}(\.{"I\'m\ skip\ this\ control\ sequences."})$;\6
+\\{error};\5
+\&{return};\6
+\&{end};\2\6
+$\\{define}(\\{inhibit\_xsp\_code\_base}+\|j,\39\\{cur\_val},\39\|n)$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Invalid\ KANJI\ code\ ("})$;\5
+$\\{print\_hex}(\|n)$;\5
+$\\{print\_char}(\.{")"})$;\5
+$\\{help1}(\.{"I\'m\ skip\ this\ control\ sequences."})$;\6
+\\{error};\5
+\&{return};\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1437. \P$\X1437:Fetch inhibit type from some table\X\S$\6
+\&{begin} \37\\{scan\_int};\5
+$\|q\K\\{get\_inhibit\_pos}(\\{tokanji}(\\{cur\_val}),\39\\{cur\_pos})$;\5
+$\\{cur\_val\_level}\K\\{int\_val}$;\5
+$\\{cur\_val}\K3$;\6
+\&{if} $\|q\I\\{no\_entry}$ \1\&{then}\5
+$\\{cur\_val}\K\\{inhibit\_xsp\_type}(\|q)$;\2\6
+\&{end}\par
+\U424.\fi
+
+\M1438. The \.{\\prebreakpenalty} is used to specified amount of penalties
+inserted
+before the 2byte-char which is first argument of this primitive.
+The \.{\\postbreakpenalty} is inserted after the 2byte-char.
+
+\Y\P\D \37$\\{pre\_break\_penalty\_code}=1$\par
+\P\D \37$\\{post\_break\_penalty\_code}=2$\par
+\Y\P$\4\X232:Put each of \TeX's primitives into the hash table\X\mathrel{+}\S$\6
+$\\{primitive}(\.{"prebreakpenalty"},\39\\{assign\_kinsoku},\39\\{pre\_break%
+\_penalty\_code})$;\5
+$\\{primitive}(\.{"postbreakpenalty"},\39\\{assign\_kinsoku},\39\\{post\_break%
+\_penalty\_code})$;\par
+\fi
+
+\M1439. \P$\X233:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X\mathrel{+}\S$\6
+\4\\{assign\_kinsoku}: \37\&{case} $\\{chr\_code}$ \1\&{of}\6
+\4\\{pre\_break\_penalty\_code}: \37$\\{print\_esc}(\.{"prebreakpenalty"})$;\6
+\4\\{post\_break\_penalty\_code}: \37$\\{print\_esc}(\.{"postbreakpenalty"})$;%
+\2\6
+\&{endcases};\par
+\fi
+
+\M1440. \P$\X1425:Declare procedures needed in \\{scan\_something\_internal}\X%
+\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{get\_kinsoku\_pos}(\|c:\\{KANJI\_code};\,\35\|n:%
+\\{small\_number})$: \37\\{pointer};\6
+\4\&{label} \37$\\{done},\39\\{done1}$;\6
+\4\&{var} \37$\|p,\39\|s$: \37\\{pointer};\2\6
+\&{begin} \37$\|s\K\\{calc\_pos}(\|c)$;\5
+$\|p\K\|s$;\6
+\&{debug} \37\\{print\_ln};\5
+$\\{print}(\.{"c:="})$;\5
+$\\{print\_int}(\|c)$;\5
+$\\{print}(\.{",\ p:="})$;\5
+$\\{print\_int}(\|s)$;\6
+\&{if} $\|p+\\{kinsoku\_base}<0$ \1\&{then}\6
+\&{begin} \37$\\{print}(\.{"p\ is\ negative\ value"})$;\5
+\\{print\_ln};\6
+\&{end};\2\6
+\&{gubed}\6
+\&{if} $\|n=\\{new\_pos}$ \1\&{then}\6
+\&{begin} \37\1\&{repeat} \37\&{if} $(\\{kinsoku\_type}(\|p)=0)\V(\\{kinsoku%
+\_code}(\|p)=\|c)$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\\{incr}(\|p)$;\6
+\&{if} $\|p>255$ \1\&{then}\5
+$\|p\K0$;\2\6
+\4\&{until}\5
+$\|s=\|p$;\2\6
+$\|p\K\\{no\_entry}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\1\&{repeat} \37\&{if} $\\{kinsoku\_type}(\|p)=0$ \1%
+\&{then}\5
+\&{goto} \37\\{done1};\2\6
+\&{if} $\\{kinsoku\_code}(\|p)=\|c$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+$\\{incr}(\|p)$;\6
+\&{if} $\|p>255$ \1\&{then}\5
+$\|p\K0$;\2\6
+\4\&{until}\5
+$\|s=\|p$;\2\6
+\4\\{done1}: \37$\|p\K\\{no\_entry}$;\6
+\&{end};\2\6
+\4\\{done}: \37$\\{get\_kinsoku\_pos}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M1441. \P$\X1229:Assignments\X\mathrel{+}\S$\6
+\4\\{assign\_kinsoku}: \37\&{begin} \37$\|p\K\\{cur\_chr}$;\5
+\\{scan\_int};\5
+$\|n\K\\{cur\_val}$;\5
+\\{scan\_optional\_equals};\5
+\\{scan\_int};\6
+\&{if} $\\{is\_char\_ascii}(\|n)\V\\{is\_char\_kanji}(\|n)$ \1\&{then}\6
+\&{begin} \37$\|j\K\\{get\_kinsoku\_pos}(\\{tokanji}(\|n),\39\\{new\_pos})$;\6
+\&{if} $\|j=\\{no\_entry}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"KINSOKU\ table\ is\ full!!"})$;\5
+$\\{help1}(\.{"I\'m\ skip\ this\ control\ sequences."})$;\6
+\\{error};\5
+\&{return};\6
+\&{end};\2\6
+\&{if} $(\|p=\\{pre\_break\_penalty\_code})\V(\|p=\\{post\_break\_penalty%
+\_code})$ \1\&{then}\6
+\&{begin} \37$\\{define}(\\{kinsoku\_base}+\|j,\39\|p,\39\\{tokanji}(\|n))$;\5
+$\\{word\_define}(\\{kinsoku\_penalty\_base}+\|j,\39\\{cur\_val})$;\6
+\&{end}\6
+\4\&{else} $\\{confusion}(\.{"kinsoku"})$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Invalid\ KANJI\ code\ for\ "})$;\6
+\&{if} $\|p=\\{pre\_break\_penalty\_code}$ \1\&{then}\5
+$\\{print}(\.{"pre"})$\6
+\4\&{else} \&{if} $\|p=\\{post\_break\_penalty\_code}$ \1\&{then}\5
+$\\{print}(\.{"post"})$\6
+\4\&{else} $\\{print\_char}(\.{"?"})$;\2\2\6
+$\\{print}(\.{"breakpenalty\ ("})$;\5
+$\\{print\_hex}(\|n)$;\5
+$\\{print\_char}(\.{")"})$;\5
+$\\{help1}(\.{"I\'m\ skip\ this\ control\ sequences."})$;\6
+\\{error};\5
+\&{return};\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1442. \P$\X1442:Fetch breaking penalty from some table\X\S$\6
+\&{begin} \37\\{scan\_int};\5
+$\|q\K\\{get\_kinsoku\_pos}(\\{tokanji}(\\{cur\_val}),\39\\{cur\_pos})$;\5
+$\\{cur\_val\_level}\K\\{int\_val}$;\5
+$\\{cur\_val}\K0$;\6
+\&{if} $(\|q\I\\{no\_entry})\W(\|m=\\{kinsoku\_type}(\|q))$ \1\&{then}\5
+$\\{scanned\_result}(\\{kinsoku\_penalty}(\|q))(\\{int\_val})$;\2\6
+\&{end}\par
+\U424.\fi
+
+\M1443. Following codes are used in \\{main\_control}.
+
+\Y\P$\4\X1443:Insert kinsoku penalty\X\S$\6
+\&{begin} \37$\\{kp}\K\\{get\_kinsoku\_pos}(\\{cx},\39\\{cur\_pos})$;\6
+\&{if} $\\{kp}\I\\{no\_entry}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{kinsoku\_type}(\\{kp})=\\{pre\_break\_penalty\_code}$ %
+\1\&{then}\6
+\&{begin} \37\&{if} $\R\\{is\_char\_node}(\\{cur\_q})\W(\\{type}(\\{cur\_q})=%
+\\{penalty\_node})$ \1\&{then}\5
+$\\{penalty}(\\{cur\_q})\K\\{penalty}(\\{cur\_q})+\\{kinsoku\_penalty}(\\{kp})$%
+\6
+\4\&{else} \&{begin} \37$\\{main\_p}\K\\{link}(\\{cur\_q})$;\5
+$\\{link}(\\{cur\_q})\K\\{new\_penalty}(\\{kinsoku\_penalty}(\\{kp}))$;\5
+$\\{subtype}(\\{link}(\\{cur\_q}))\K\\{kinsoku\_pena}$;\5
+$\\{link}(\\{link}(\\{cur\_q}))\K\\{main\_p}$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{kinsoku\_type}(\\{kp})=\\{post\_break\_penalty\_code}$ \1%
+\&{then}\6
+\&{begin} \37$\\{tail\_append}(\\{new\_penalty}(\\{kinsoku\_penalty}(%
+\\{kp})))$;\5
+$\\{subtype}(\\{tail})\K\\{kinsoku\_pena}$;\6
+\&{end};\2\2\6
+\&{end};\2\6
+\&{end};\par
+\Us1050\ET1469.\fi
+
+\M1444. \P$\X1444:Insert \\{pre\_break\_penalty} of \\{cur\_chr}\X\S$\6
+\&{begin} \37$\\{kp}\K\\{get\_kinsoku\_pos}(\\{cur\_chr},\39\\{cur\_pos})$;\6
+\&{if} $\\{kp}\I\\{no\_entry}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{kinsoku\_type}(\\{kp})=\\{pre\_break\_penalty\_code}$ %
+\1\&{then}\6
+\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=\\{penalty\_node})$
+\1\&{then}\5
+$\\{penalty}(\\{tail})\K\\{penalty}(\\{tail})+\\{kinsoku\_penalty}(\\{kp})$\6
+\4\&{else} \&{begin} \37$\\{tail\_append}(\\{new\_penalty}(\\{kinsoku%
+\_penalty}(\\{kp})))$;\5
+$\\{subtype}(\\{tail})\K\\{kinsoku\_pena}$;\6
+\&{end};\2\2\6
+\&{end};\2\6
+\&{end};\par
+\U1469.\fi
+
+\M1445. \P$\X1445:Insert \\{post\_break\_penalty}\X\S$\6
+\&{begin} \37$\\{kp}\K\\{get\_kinsoku\_pos}(\\{cx},\39\\{cur\_pos})$;\6
+\&{if} $\\{kp}\I\\{no\_entry}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{kinsoku\_type}(\\{kp})=\\{post\_break\_penalty\_code}$ %
+\1\&{then}\6
+\&{begin} \37$\\{tail\_append}(\\{new\_penalty}(\\{kinsoku\_penalty}(%
+\\{kp})))$;\5
+$\\{subtype}(\\{tail})\K\\{kinsoku\_pena}$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end};\par
+\Us1469\ET1469.\fi
+
+\M1446. This is a part of section 32.
+
+The procedure \\{synch\_dir} is used in \\{hlist\_out} and \\{vlist\_out}.
+
+\Y\P\D \37$\\{dvi\_yoko}=0$\par
+\P\D \37$\\{dvi\_tate}=1$\par
+\P\D \37$\\{dvi\_dtou}=3$\par
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{dvi\_dir}: \37\\{integer};\C{a \.{DVI} reader program thinks we direct to}%
+\6
+\4\\{cur\_dir\_hv}: \37\\{integer};\C{\TeX\ thinks we direct to}\6
+\4\\{page\_dir}: \37\\{eight\_bits};\par
+\fi
+
+\M1447. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6
+$\\{page\_dir}\K\\{dir\_yoko}$;\par
+\fi
+
+\M1448. \P$\X1381:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{synch\_dir};\6
+\4\&{var} \37\\{tmp}: \37\\{scaled};\C{temporary resister}\2\6
+\&{begin} \37\&{case} $\\{cur\_dir\_hv}$ \1\&{of}\6
+\4\\{dir\_yoko}: \37\&{if} $\\{dvi\_dir}\I\\{cur\_dir\_hv}$ \1\&{then}\6
+\&{begin} \37\\{synch\_h};\5
+\\{synch\_v};\5
+$\\{dvi\_out}(\\{dirchg})$;\5
+$\\{dvi\_out}(\\{dvi\_yoko})$;\5
+$\\{dir\_used}\K\\{true}$;\6
+\&{case} $\\{dvi\_dir}$ \1\&{of}\6
+\4\\{dir\_tate}: \37\&{begin} \37$\\{tmp}\K\\{cur\_h}$;\5
+$\\{cur\_h}\K-\\{cur\_v}$;\5
+$\\{cur\_v}\K\\{tmp}$\6
+\&{end};\6
+\4\\{dir\_dtou}: \37\&{begin} \37$\\{tmp}\K\\{cur\_h}$;\5
+$\\{cur\_h}\K\\{cur\_v}$;\5
+$\\{cur\_v}\K-\\{tmp}$\6
+\&{end};\2\6
+\&{endcases};\5
+$\\{dvi\_h}\K\\{cur\_h}$;\5
+$\\{dvi\_v}\K\\{cur\_v}$;\5
+$\\{dvi\_dir}\K\\{cur\_dir\_hv}$;\6
+\&{end};\2\6
+\4\\{dir\_tate}: \37\&{if} $\\{dvi\_dir}\I\\{cur\_dir\_hv}$ \1\&{then}\6
+\&{begin} \37\\{synch\_h};\5
+\\{synch\_v};\5
+$\\{dvi\_out}(\\{dirchg})$;\5
+$\\{dvi\_out}(\\{dvi\_tate})$;\5
+$\\{dir\_used}\K\\{true}$;\6
+\&{case} $\\{dvi\_dir}$ \1\&{of}\6
+\4\\{dir\_yoko}: \37\&{begin} \37$\\{tmp}\K\\{cur\_h}$;\5
+$\\{cur\_h}\K\\{cur\_v}$;\5
+$\\{cur\_v}\K-\\{tmp}$\6
+\&{end};\6
+\4\\{dir\_dtou}: \37\&{begin} \37$\\{cur\_v}\K-\\{cur\_v}$;\5
+$\\{cur\_h}\K-\\{cur\_h}$;\6
+\&{end};\2\6
+\&{endcases};\5
+$\\{dvi\_h}\K\\{cur\_h}$;\5
+$\\{dvi\_v}\K\\{cur\_v}$;\5
+$\\{dvi\_dir}\K\\{cur\_dir\_hv}$;\6
+\&{end};\2\6
+\4\\{dir\_dtou}: \37\&{if} $\\{dvi\_dir}\I\\{cur\_dir\_hv}$ \1\&{then}\6
+\&{begin} \37\\{synch\_h};\5
+\\{synch\_v};\5
+$\\{dvi\_out}(\\{dirchg})$;\5
+$\\{dvi\_out}(\\{dvi\_dtou})$;\5
+$\\{dir\_used}\K\\{true}$;\6
+\&{case} $\\{dvi\_dir}$ \1\&{of}\6
+\4\\{dir\_yoko}: \37\&{begin} \37$\\{tmp}\K\\{cur\_h}$;\5
+$\\{cur\_h}\K-\\{cur\_v}$;\5
+$\\{cur\_v}\K\\{tmp}$\6
+\&{end};\6
+\4\\{dir\_tate}: \37\&{begin} \37$\\{cur\_v}\K-\\{cur\_v}$;\5
+$\\{cur\_h}\K-\\{cur\_h}$;\6
+\&{end};\2\6
+\&{endcases};\5
+$\\{dvi\_h}\K\\{cur\_h}$;\5
+$\\{dvi\_v}\K\\{cur\_v}$;\5
+$\\{dvi\_dir}\K\\{cur\_dir\_hv}$;\6
+\&{end};\6
+\4\&{othercases} $\\{confusion}(\.{"synch\_dir"})$;\2\2\6
+\&{endcases}\6
+\&{end};\par
+\fi
+
+\M1449. This function is called from \\{adjust\_hlist} to used to check,
+whether
+a list which pointed \\{box\_p} contain a printing character.
+If the list contain such a character, then return `true', otherwise `false'.
+If the first matter is a character, \\{first\_char} is stored it.
+\\{last\_char} is stored a last character.  If no printing characters exist
+in the list, \\{first\_char} and \\{last\_char} is null.
+
+Note that \\{first\_char} and \\{last\_char} may be \\{math\_node}.
+
+\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6
+\4\\{first\_char}: \37\\{pointer};\C{first printable character}\6
+\4\\{last\_char}: \37\\{pointer};\C{last printable character}\6
+\4\\{find\_first\_char}: \37\\{boolean};\C{find for a first printable
+character?}\par
+\fi
+
+\M1450. \P$\X1381:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X%
+\mathrel{+}\S$\6
+\4\&{function}\1\  \37$\\{check\_box}(\\{box\_p}:\\{pointer})$: \37\\{boolean};%
+\6
+\4\&{label} \37\\{done};\6
+\4\&{var} \37\|p: \37\\{pointer};\C{run through the current box}\6
+\\{flag}: \37\\{boolean};\C{found any printable character?}\2\6
+\&{begin} \37$\\{flag}\K\\{false}$;\5
+$\|p\K\\{box\_p}$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\1\&{repeat} \37\&{if} $\\{find\_first\_char}$ \1\&{then}\6
+\&{begin} \37$\\{first\_char}\K\|p$;\5
+$\\{find\_first\_char}\K\\{false}$\6
+\&{end};\2\6
+$\\{last\_char}\K\|p$;\5
+$\\{flag}\K\\{true}$;\6
+\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}\5
+$\|p\K\\{link}(\|p)$;\2\6
+$\|p\K\\{link}(\|p)$;\6
+\&{if} $\|p=\\{null}$ \1\&{then}\5
+\&{goto} \37\\{done};\2\6
+\4\&{until}\5
+$\R\\{is\_char\_node}(\|p)$;\2\2\6
+\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4\\{hlist\_node}: \37\&{begin} \37$\\{flag}\K\\{true}$;\6
+\&{if} $\\{shift\_amount}(\|p)=0$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{check\_box}(\\{list\_ptr}(\|p))$ \1\&{then}\5
+$\\{flag}\K\\{true}$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{find\_first\_char}$ \1\&{then}\5
+$\\{find\_first\_char}\K\\{false}$\6
+\4\&{else} $\\{last\_char}\K\\{null}$;\2\2\6
+\&{end};\6
+\4\\{ligature\_node}: \37\&{if} $\\{check\_box}(\\{lig\_ptr}(\|p))$ \1\&{then}\5
+$\\{flag}\K\\{true}$;\2\6
+\4$\\{ins\_node},\39\\{disp\_node},\39\\{mark\_node},\39\\{adjust\_node},\39%
+\\{whatsit\_node},\39\\{penalty\_node}$: \37\\{do\_nothing};\6
+\4\\{math\_node}: \37\&{if} $(\\{subtype}(\|p)=\\{before})\V(\\{subtype}(\|p)=%
+\\{after})$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{find\_first\_char}$ \1\&{then}\6
+\&{begin} \37$\\{find\_first\_char}\K\\{false}$;\5
+$\\{first\_char}\K\|p$;\6
+\&{end};\2\6
+$\\{last\_char}\K\|p$;\5
+$\\{flag}\K\\{true}$;\6
+\&{end}\6
+\4\&{else} \\{do\_nothing};\C{\.{\\beginR} etc.}\2\6
+\4\&{othercases} \37\&{begin} \37$\\{flag}\K\\{true}$;\6
+\&{if} $\\{find\_first\_char}$ \1\&{then}\5
+$\\{find\_first\_char}\K\\{false}$\6
+\4\&{else} $\\{last\_char}\K\\{null}$;\2\6
+\&{end};\2\6
+\&{endcases};\5
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\4\\{done}: \37$\\{check\_box}\K\\{flag}$;\6
+\&{end};\par
+\fi
+
+\M1451. Following procedure \\{adjust\_hlist} inserts \.{\\xkanjiskip} between
+2byte-char and 1byte-char in hlist which pointed \|p.
+Note that the skip is inserted into a place where too difficult to decide
+whether inserting or not (i.e, before penalty, after penalty).
+
+If \\{pf} is true then insert \\{jchr\_widow\_penalty} that is penalty for
+creating a widow KANJI character line.
+
+\Y\P\D \37$\\{no\_skip}=0$\par
+\P\D \37$\\{after\_schar}=1$\C{denote after single byte character}\par
+\P\D \37$\\{after\_wchar}=2$\C{denote after double bytes character}\par
+\Y\P$\4\X1381:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{adjust\_hlist}(\|p:\\{pointer};\,\35\\{pf}:%
+\\{boolean})$;\6
+\4\&{label} \37\\{exit};\6
+\4\&{var} \37$\|q,\39\|s,\39\|t,\39\|u,\39\|v,\39\|x,\39\|z$: \37\\{pointer};\5
+$\|i,\39\|k$: \37\\{halfword};\5
+\|a: \37\\{pointer};\C{ temporary pointer for accent }\6
+\\{insert\_skip}: \37$\\{no\_skip}\to\\{after\_wchar}$;\5
+\\{cx}: \37\\{KANJI\_code};\C{temporaly register for KANJI character}\6
+\\{ax}: \37\\{ASCII\_code};\C{temporaly register for ASCII character}\6
+\\{do\_ins}: \37\\{boolean};\C{for inserting \\{xkanji\_skip} into prevous (or
+after) KANJI}\6
+\&{begin} \37\&{if} $\\{link}(\|p)=\\{null}$ \1\&{then}\5
+\&{goto} \37\\{exit};\2\6
+\&{if} $\\{auto\_spacing}>0$ \1\&{then}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{space\_ptr}(\|p))$;\5
+$\\{space\_ptr}(\|p)\K\\{kanji\_skip}$;\5
+$\\{add\_glue\_ref}(\\{kanji\_skip})$;\6
+\&{end};\2\6
+\&{if} $\\{auto\_xspacing}>0$ \1\&{then}\6
+\&{begin} \37$\\{delete\_glue\_ref}(\\{xspace\_ptr}(\|p))$;\5
+$\\{xspace\_ptr}(\|p)\K\\{xkanji\_skip}$;\5
+$\\{add\_glue\_ref}(\\{xkanji\_skip})$;\6
+\&{end};\2\6
+$\|u\K\\{space\_ptr}(\|p)$;\5
+$\\{add\_glue\_ref}(\|u)$;\5
+$\|s\K\\{xspace\_ptr}(\|p)$;\5
+$\\{add\_glue\_ref}(\|s)$;  \6
+\&{if} $\R\\{is\_char\_node}(\\{link}(\|p))$\C{p1.0.9d}\6
+$\W(\\{type}(\\{link}(\|p))=\\{glue\_node})\W(\\{subtype}(\\{link}(\|p))=\\{jfm%
+\_skip}+1)$ \&{then} \6
+\&{begin} \37$\|v\K\\{link}(\|p)$;\5
+$\\{link}(\|p)\K\\{link}(\|v)$;\5
+$\\{fast\_delete\_glue\_ref}(\\{glue\_ptr}(\|v))$;\5
+$\\{free\_node}(\|v,\39\\{small\_node\_size})$;\6
+\&{end};\5
+$\|i\K0$;\5
+$\\{insert\_skip}\K\\{no\_skip}$;\5
+$\|p\K\\{link}(\|p)$;\5
+$\|v\K\|p$;\5
+$\|q\K\|p$;\6
+\&{while} $\|p\I\\{null}$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{begin} \37\1\&{repeat} \37\X1452:Insert a space around the character \|p\X;\6
+$\|q\K\|p$;\5
+$\|p\K\\{link}(\|p)$;\5
+$\\{incr}(\|i)$;\6
+\&{if} $(\|i>5)\W\\{pf}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|v)$ \1\&{then}\6
+\&{if} $\\{font\_dir}[\\{font}(\|v)]\I\\{dir\_default}$ \1\&{then}\5
+$\|v\K\\{link}(\|v)$;\2\2\6
+$\|v\K\\{link}(\|v)$;\6
+\&{end};\2\6
+\4\&{until}\5
+$\R\\{is\_char\_node}(\|p)$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4\\{hlist\_node}: \37\X1453:Insert hbox surround spacing\X;\6
+\4\\{ligature\_node}: \37\X1457:Insert ligature surround spacing\X;\6
+\4$\\{penalty\_node},\39\\{disp\_node}$: \37\X1458:Insert penalty or displace
+surround spacing\X;\6
+\4\\{kern\_node}: \37\&{if} $\\{subtype}(\|p)=\\{explicit}$ \1\&{then}\5
+$\\{insert\_skip}\K\\{no\_skip}$\6
+\4\&{else} \&{if} $\\{subtype}(\|p)=\\{acc\_kern}$ \1\&{then}\6
+\&{begin} \37\C{ When we insert \.{\\xkanjiskip}, we first ignore accent (and
+kerns) and           insert \.{\\xkanjiskip}, then we recover the accent. }\6
+\&{if} $\|q=\|p$ \1\&{then}\6
+\&{begin} \37$\|t\K\\{link}(\|p)$;\C{ if p is beginning on the list, we have
+only to ignore nodes. }\6
+\&{if} $\\{is\_char\_node}(\|t)$ \1\&{then}\6
+\&{if} $\\{font\_dir}[\\{font}(\|t)]\I\\{dir\_default}$ \1\&{then}\5
+$\|t\K\\{link}(\|t)$;\2\2\6
+$\|p\K\\{link}(\\{link}(\|t))$;\6
+\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\|p\K\\{link}(\|p)$;\5
+$\\{insert\_skip}\K\\{after\_wchar}$;\6
+\&{end}\6
+\4\&{else} $\\{insert\_skip}\K\\{after\_schar}$;\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|a\K\|p$;\5
+$\|t\K\\{link}(\|p)$;\6
+\&{if} $\\{is\_char\_node}(\|t)$ \1\&{then}\6
+\&{if} $\\{font\_dir}[\\{font}(\|t)]\I\\{dir\_default}$ \1\&{then}\5
+$\|t\K\\{link}(\|t)$;\2\2\6
+$\|t\K\\{link}(\\{link}(\|t))$;\5
+$\\{link}(\|q)\K\|t$;\5
+$\|p\K\|t$;\5
+\X1452:Insert a space around the character \|p\X;\6
+$\\{incr}(\|i)$;\6
+\&{if} $(\|i>5)\W\\{pf}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|v)$ \1\&{then}\6
+\&{if} $\\{font\_dir}[\\{font}(\|v)]\I\\{dir\_default}$ \1\&{then}\5
+$\|v\K\\{link}(\|v)$;\2\2\6
+$\|v\K\\{link}(\|v)$;\6
+\&{end};\2\6
+\&{if} $\\{link}(\|q)\I\|t$ \1\&{then}\5
+$\\{link}(\\{link}(\|q))\K\|a$\6
+\4\&{else} $\\{link}(\|q)\K\|a$;\2\6
+\&{end};\2\6
+\&{end};\2\2\6
+\4\\{math\_node}: \37\X1456:Insert math surround spacing\X;\6
+\4$\\{mark\_node},\39\\{adjust\_node},\39\\{ins\_node},\39\\{whatsit\_node}$: %
+\37\C{These nodes are vanished when typeset is done}\6
+\\{do\_nothing};\6
+\4\&{othercases} \37$\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{endcases};\5
+$\|q\K\|p$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{if} $\R\\{is\_char\_node}(\|q)\W(\\{type}(\|q)=\\{glue\_node})\W(%
+\\{subtype}(\|q)=\\{jfm\_skip}+1)$ \1\&{then}\6
+\&{begin} \37$\\{fast\_delete\_glue\_ref}(\\{glue\_ptr}(\|q))$;\5
+$\\{glue\_ptr}(\|q)\K\\{zero\_glue}$;\5
+$\\{add\_glue\_ref}(\\{zero\_glue})$;\6
+\&{end};\2\6
+$\\{delete\_glue\_ref}(\|u)$;\5
+$\\{delete\_glue\_ref}(\|s)$;\6
+\&{if} $(\|v\I\\{null})\W\\{pf}\W(\|i>5)$ \1\&{then}\5
+\X1463:Make \\{jchr\_widow\_penalty} node\X;\2\6
+\4\\{exit}: \37 \6
+\&{end} ;\par
+\fi
+
+\M1452. \P$\X1452:Insert a space around the character \|p\X\S$\6
+\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\\{KANJI}(\\{cx})\K\\{info}(\\{link}(\|p))$;\6
+\&{if} $\\{insert\_skip}=\\{after\_schar}$ \1\&{then}\5
+\X1459:Insert ASCII-KANJI spacing\X;\2\6
+$\|p\K\\{link}(\|p)$;\5
+$\\{insert\_skip}\K\\{after\_wchar}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{ax}\K\\{qo}(\\{character}(\|p))$;\6
+\&{if} $\\{insert\_skip}=\\{after\_wchar}$ \1\&{then}\5
+\X1460:Insert KANJI-ASCII spacing\X;\2\6
+\&{if} $\\{auto\_xsp\_code}(\\{ax})\G2$ \1\&{then}\5
+$\\{insert\_skip}\K\\{after\_schar}$\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{end}\2\par
+\Us1451\ET1451.\fi
+
+\M1453. \P$\X1453:Insert hbox surround spacing\X\S$\6
+\&{begin} \37$\\{find\_first\_char}\K\\{true}$;\5
+$\\{first\_char}\K\\{null}$;\5
+$\\{last\_char}\K\\{null}$;\6
+\&{if} $\\{shift\_amount}(\|p)=0$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{check\_box}(\\{list\_ptr}(\|p))$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{first\_char}\I\\{null}$ \1\&{then}\5
+\X1454:Insert a space before the \\{first\_char}\X;\2\6
+\&{if} $\\{last\_char}\I\\{null}$ \1\&{then}\6
+\&{begin} \37\X1455:Insert a space after the \\{last\_char}\X;\6
+\&{end}\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{end}\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{end}\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{end}\par
+\U1451.\fi
+
+\M1454. \P$\X1454:Insert a space before the \\{first\_char}\X\S$\6
+\&{if} $\\{type}(\\{first\_char})=\\{math\_node}$ \1\&{then}\6
+\&{begin} \37$\\{ax}\K\\{qo}(\.{"0"})$;\6
+\&{if} $\\{insert\_skip}=\\{after\_wchar}$ \1\&{then}\5
+\X1460:Insert KANJI-ASCII spacing\X;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{font\_dir}[\\{font}(\\{first\_char})]\I\\{dir\_default}$ %
+\1\&{then}\6
+\&{begin} \37$\\{KANJI}(\\{cx})\K\\{info}(\\{link}(\\{first\_char}))$;\6
+\&{if} $\\{insert\_skip}=\\{after\_schar}$ \1\&{then}\5
+\X1459:Insert ASCII-KANJI spacing\X\6
+\4\&{else} \&{if} $\\{insert\_skip}=\\{after\_wchar}$ \1\&{then}\5
+\X1461:Insert KANJI-KANJI spacing\X;\2\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{ax}\K\\{qo}(\\{character}(\\{first\_char}))$;\6
+\&{if} $\\{insert\_skip}=\\{after\_wchar}$ \1\&{then}\5
+\X1460:Insert KANJI-ASCII spacing\X;\2\6
+\&{end};\2\2\par
+\U1453.\fi
+
+\M1455. \P$\X1455:Insert a space after the \\{last\_char}\X\S$\6
+\&{if} $\\{type}(\\{last\_char})=\\{math\_node}$ \1\&{then}\6
+\&{begin} \37$\\{ax}\K\\{qo}(\.{"0"})$;\6
+\&{if} $\\{auto\_xsp\_code}(\\{ax})\G2$ \1\&{then}\5
+$\\{insert\_skip}\K\\{after\_schar}$\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{font\_dir}[\\{font}(\\{last\_char})]\I\\{dir\_default}$ %
+\1\&{then}\6
+\&{begin} \37$\\{insert\_skip}\K\\{after\_wchar}$;\5
+$\\{KANJI}(\\{cx})\K\\{info}(\\{link}(\\{last\_char}))$;\6
+\&{if} $\\{is\_char\_node}(\\{link}(\|p))\W(\\{font\_dir}[\\{font}(\\{link}(%
+\|p))]\I\\{dir\_default})$ \1\&{then}\6
+\&{begin} \37\X1462:Append KANJI-KANJI spacing\X;\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{ax}\K\\{qo}(\\{character}(\\{last\_char}))$;\6
+\&{if} $\\{auto\_xsp\_code}(\\{ax})\G2$ \1\&{then}\5
+$\\{insert\_skip}\K\\{after\_schar}$\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{end};\2\2\par
+\U1453.\fi
+
+\M1456. \P$\X1456:Insert math surround spacing\X\S$\6
+\&{begin} \37\&{if} $(\\{subtype}(\|p)=\\{before})\W(\\{insert\_skip}=\\{after%
+\_wchar})$ \1\&{then}\6
+\&{begin} \37$\\{ax}\K\\{qo}(\.{"0"})$;\5
+\X1460:Insert KANJI-ASCII spacing\X;\6
+$\\{insert\_skip}\K\\{no\_skip}$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{subtype}(\|p)=\\{after}$ \1\&{then}\6
+\&{begin} \37$\\{ax}\K\\{qo}(\.{"0"})$;\6
+\&{if} $\\{auto\_xsp\_code}(\\{ax})\G2$ \1\&{then}\5
+$\\{insert\_skip}\K\\{after\_schar}$\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{end}\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\2\6
+\&{end}\par
+\U1451.\fi
+
+\M1457. \P$\X1457:Insert ligature surround spacing\X\S$\6
+\&{begin} \37$\|t\K\\{lig\_ptr}(\|p)$;\6
+\&{if} $\\{is\_char\_node}(\|t)$ \1\&{then}\6
+\&{begin} \37$\\{ax}\K\\{qo}(\\{character}(\|t))$;\6
+\&{if} $\\{insert\_skip}=\\{after\_wchar}$ \1\&{then}\5
+\X1460:Insert KANJI-ASCII spacing\X;\2\6
+\&{while} $\\{link}(\|t)\I\\{null}$ \1\&{do}\5
+$\|t\K\\{link}(\|t)$;\2\6
+\&{if} $\\{is\_char\_node}(\|t)$ \1\&{then}\6
+\&{begin} \37$\\{ax}\K\\{qo}(\\{character}(\|t))$;\6
+\&{if} $\\{auto\_xsp\_code}(\\{ax})\G2$ \1\&{then}\5
+$\\{insert\_skip}\K\\{after\_schar}$\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end}\par
+\U1451.\fi
+
+\M1458. \P$\X1458:Insert penalty or displace surround spacing\X\S$\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\\{link}(\|p))$ \1\&{then}\6
+\&{begin} \37$\|q\K\|p$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\\{KANJI}(\\{cx})\K\\{info}(\\{link}(\|p))$;\6
+\&{if} $\\{insert\_skip}=\\{after\_schar}$ \1\&{then}\5
+\X1459:Insert ASCII-KANJI spacing\X\6
+\4\&{else} \&{if} $\\{insert\_skip}=\\{after\_wchar}$ \1\&{then}\5
+\X1461:Insert KANJI-KANJI spacing\X;\2\2\6
+$\|p\K\\{link}(\|p)$;\5
+$\\{insert\_skip}\K\\{after\_wchar}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{ax}\K\\{qo}(\\{character}(\|p))$;\6
+\&{if} $\\{insert\_skip}=\\{after\_wchar}$ \1\&{then}\5
+\X1460:Insert KANJI-ASCII spacing\X;\2\6
+\&{if} $\\{auto\_xsp\_code}(\\{ax})\G2$ \1\&{then}\5
+$\\{insert\_skip}\K\\{after\_schar}$\6
+\4\&{else} $\\{insert\_skip}\K\\{no\_skip}$;\2\6
+\&{end};\2\6
+\&{end}\2\6
+\&{end}\par
+\U1451.\fi
+
+\M1459. \P$\X1459:Insert ASCII-KANJI spacing\X\S$\6
+\&{begin} \37\&{begin} \37$\|x\K\\{get\_inhibit\_pos}(\\{cx},\39\\{cur\_pos})$;%
+\6
+\&{if} $\|x\I\\{no\_entry}$ \1\&{then}\6
+\&{if} $(\\{inhibit\_xsp\_type}(\|x)=\\{inhibit\_both})\V(\\{inhibit\_xsp%
+\_type}(\|x)=\\{inhibit\_previous})$ \1\&{then}\5
+$\\{do\_ins}\K\\{false}$\6
+\4\&{else} $\\{do\_ins}\K\\{true}$\2\6
+\4\&{else} $\\{do\_ins}\K\\{true}$;\2\6
+\&{end};\6
+\&{if} $\\{do\_ins}$ \1\&{then}\6
+\&{begin} \37$\|z\K\\{new\_glue}(\|s)$;\5
+$\\{subtype}(\|z)\K\\{xkanji\_skip\_code}+1$;\5
+$\\{link}(\|z)\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\|z$;\5
+$\|q\K\|z$;\6
+\&{end};\2\6
+\&{end}\par
+\Us1452, 1454\ETs1458.\fi
+
+\M1460. \P$\X1460:Insert KANJI-ASCII spacing\X\S$\6
+\&{begin} \37\&{if} $(\\{auto\_xsp\_code}(\\{ax})\mathbin{\&{mod}}2)=1$ \1%
+\&{then}\6
+\&{begin} \37$\|x\K\\{get\_inhibit\_pos}(\\{cx},\39\\{cur\_pos})$;\6
+\&{if} $\|x\I\\{no\_entry}$ \1\&{then}\6
+\&{if} $(\\{inhibit\_xsp\_type}(\|x)=\\{inhibit\_both})\V(\\{inhibit\_xsp%
+\_type}(\|x)=\\{inhibit\_after})$ \1\&{then}\5
+$\\{do\_ins}\K\\{false}$\6
+\4\&{else} $\\{do\_ins}\K\\{true}$\2\6
+\4\&{else} $\\{do\_ins}\K\\{true}$;\2\6
+\&{end}\6
+\4\&{else} $\\{do\_ins}\K\\{false}$;\2\6
+\&{if} $\\{do\_ins}$ \1\&{then}\6
+\&{begin} \37$\|z\K\\{new\_glue}(\|s)$;\5
+$\\{subtype}(\|z)\K\\{xkanji\_skip\_code}+1$;\5
+$\\{link}(\|z)\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\|z$;\5
+$\|q\K\|z$;\6
+\&{end};\2\6
+\&{end}\par
+\Us1452, 1454, 1454, 1456, 1457\ETs1458.\fi
+
+\M1461. \P$\X1461:Insert KANJI-KANJI spacing\X\S$\6
+\&{begin} \37$\|z\K\\{new\_glue}(\|u)$;\5
+$\\{subtype}(\|z)\K\\{kanji\_skip\_code}+1$;\5
+$\\{link}(\|z)\K\\{link}(\|q)$;\5
+$\\{link}(\|q)\K\|z$;\5
+$\|q\K\|z$;\6
+\&{end}\par
+\Us1454\ET1458.\fi
+
+\M1462. \P$\X1462:Append KANJI-KANJI spacing\X\S$\6
+\&{begin} \37$\|z\K\\{new\_glue}(\|u)$;\5
+$\\{subtype}(\|z)\K\\{kanji\_skip\_code}+1$;\5
+$\\{link}(\|z)\K\\{link}(\|p)$;\5
+$\\{link}(\|p)\K\|z$;\5
+$\|p\K\\{link}(\|z)$;\5
+$\|q\K\|z$;\6
+\&{end}\par
+\U1455.\fi
+
+\M1463. \P$\X1463:Make \\{jchr\_widow\_penalty} node\X\S$\6
+\&{begin} \37$\|q\K\|v$;\5
+$\|p\K\\{link}(\|v)$;\6
+\&{if} $\\{is\_char\_node}(\|v)\W(\\{font\_dir}[\\{font}(\|v)]\I\\{dir%
+\_default})$ \1\&{then}\6
+\&{begin} \37$\|q\K\|p$;\5
+$\|p\K\\{link}(\|p)$;\6
+\&{end};\2\6
+$\|t\K\|q$;\5
+$\|s\K\\{null}$;\5
+\X1464:Seek list and make \|t pointing widow penalty position\X;\6
+\&{if} $\|s\I\\{null}$ \1\&{then}\6
+\&{begin} \37$\|s\K\\{link}(\|t)$;\6
+\&{if} $\R\\{is\_char\_node}(\|s)\W(\\{type}(\|s)=\\{penalty\_node})$ \1%
+\&{then}\5
+$\\{penalty}(\|s)\K\\{penalty}(\|s)+\\{jchr\_widow\_penalty}$\6
+\4\&{else} \&{if} $\\{jchr\_widow\_penalty}\I0$ \1\&{then}\6
+\&{begin} \37$\|s\K\\{new\_penalty}(\\{jchr\_widow\_penalty})$;\5
+$\\{subtype}(\|s)\K\\{widow\_pena}$;\5
+$\\{link}(\|s)\K\\{link}(\|t)$;\5
+$\\{link}(\|t)\K\|s$;\5
+$\|t\K\\{link}(\|s)$;\6
+\&{while} $(\R\\{is\_char\_node}(\|t))$ \1\&{do}\6
+\&{begin} \37\&{if} $(\\{type}(\|t)=\\{glue\_node})\V(\\{type}(\|t)=\\{kern%
+\_node})$ \1\&{then}\5
+\&{goto} \37\\{exit};\2\6
+$\|t\K\\{link}(\|t)$;\6
+\&{end};\2\6
+$\|z\K\\{new\_glue}(\|u)$;\5
+$\\{subtype}(\|z)\K\\{kanji\_skip\_code}+1$;\5
+$\\{link}(\|z)\K\\{link}(\|s)$;\5
+$\\{link}(\|s)\K\|z$;\6
+\&{end};\2\2\6
+\&{end};\2\6
+\&{end};\par
+\U1451.\fi
+
+\M1464. \P$\X1464:Seek list and make \|t pointing widow penalty position\X\S$\6
+\&{while} $(\|p\I\\{null})$ \1\&{do}\6
+\&{begin} \37\&{if} $\\{is\_char\_node}(\|p)$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{font\_dir}[\\{font}(\|p)]\I\\{dir\_default}$ \1\&{then}%
+\6
+\&{begin} \37$\\{KANJI}(\\{cx})\K\\{info}(\\{link}(\|p))$;\5
+$\|i\K\\{kcat\_code}(\\{kcatcodekey}(\\{cx}))$;\5
+$\|k\K0$;\6
+\&{if} $(\|i=\\{kanji})\V(\|i=\\{kana})$ \1\&{then}\6
+\&{begin} \37$\|t\K\|q$;\5
+$\|s\K\|p$;\6
+\&{end};\2\6
+$\|p\K\\{link}(\|p)$;\5
+$\|q\K\|p$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\|k\K\|k+1$;\6
+\&{if} $\|k>1$ \1\&{then}\6
+\&{begin} \37$\|q\K\|p$;\5
+$\|s\K\\{null}$;\6
+\&{end};\2\6
+\&{end};\2\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{case} $\\{type}(\|p)$ \1\&{of}\6
+\4$\\{penalty\_node},\39\\{mark\_node},\39\\{adjust\_node},\39\\{whatsit%
+\_node},\39\\{glue\_node},\39\\{kern\_node},\39\\{math\_node},\39\\{disp%
+\_node}$: \37\\{do\_nothing};\6
+\4\&{othercases} \37\&{begin} \37$\|q\K\|p$;\5
+$\|s\K\\{null}$;\6
+\&{end};\2\6
+\&{endcases};\6
+\&{end};\2\6
+$\|p\K\\{link}(\|p)$;\6
+\&{end}\2\par
+\U1463.\fi
+
+\M1465. \P$\X1381:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{dir\_out};\6
+\4\&{var} \37\\{this\_box}: \37\\{pointer};\C{pointer to containing box}\2\6
+\&{begin} \37$\\{this\_box}\K\\{temp\_ptr}$;\5
+$\\{temp\_ptr}\K\\{list\_ptr}(\\{this\_box})$;\6
+\&{if} $(\\{type}(\\{temp\_ptr})\I\\{hlist\_node})\W(\\{type}(\\{temp\_ptr})\I%
+\\{vlist\_node})$ \1\&{then}\5
+$\\{confusion}(\.{"dir\_out"})$;\2\6
+\&{case} $\\{box\_dir}(\\{this\_box})$ \1\&{of}\6
+\4\\{dir\_yoko}: \37\&{case} $\\{box\_dir}(\\{temp\_ptr})$ \1\&{of}\6
+\4\\{dir\_tate}: \37\C{Tate in Yoko}\6
+\&{begin} \37$\\{cur\_v}\K\\{cur\_v}-\\{height}(\\{this\_box})$;\5
+$\\{cur\_h}\K\\{cur\_h}+\\{depth}(\\{temp\_ptr})$\6
+\&{end};\6
+\4\\{dir\_dtou}: \37\C{DtoU in Yoko}\6
+\&{begin} \37$\\{cur\_v}\K\\{cur\_v}+\\{depth}(\\{this\_box})$;\5
+$\\{cur\_h}\K\\{cur\_h}+\\{height}(\\{temp\_ptr})$\6
+\&{end};\2\6
+\&{endcases};\6
+\4\\{dir\_tate}: \37\&{case} $\\{box\_dir}(\\{temp\_ptr})$ \1\&{of}\6
+\4\\{dir\_yoko}: \37\C{Yoko in Tate}\6
+\&{begin} \37$\\{cur\_v}\K\\{cur\_v}+\\{depth}(\\{this\_box})$;\5
+$\\{cur\_h}\K\\{cur\_h}+\\{height}(\\{temp\_ptr})$\6
+\&{end};\6
+\4\\{dir\_dtou}: \37\C{DtoU in Tate}\6
+\&{begin} \37$\\{cur\_v}\K\\{cur\_v}+\\{depth}(\\{this\_box})-\\{height}(%
+\\{temp\_ptr})$;\5
+$\\{cur\_h}\K\\{cur\_h}+\\{width}(\\{temp\_ptr})$\6
+\&{end};\2\6
+\&{endcases};\6
+\4\\{dir\_dtou}: \37\&{case} $\\{box\_dir}(\\{temp\_ptr})$ \1\&{of}\6
+\4\\{dir\_yoko}: \37\C{Yoko in DtoU}\6
+\&{begin} \37$\\{cur\_v}\K\\{cur\_v}-\\{height}(\\{this\_box})$;\5
+$\\{cur\_h}\K\\{cur\_h}+\\{depth}(\\{temp\_ptr})$\6
+\&{end};\6
+\4\\{dir\_tate}: \37\C{Tate in DtoU}\6
+\&{begin} \37$\\{cur\_v}\K\\{cur\_v}+\\{depth}(\\{this\_box})-\\{height}(%
+\\{temp\_ptr})$;\5
+$\\{cur\_h}\K\\{cur\_h}+\\{width}(\\{temp\_ptr})$\6
+\&{end};\2\6
+\&{endcases};\2\6
+\&{endcases};\5
+$\\{cur\_dir\_hv}\K\\{box\_dir}(\\{temp\_ptr})$;\6
+\&{if} $\\{type}(\\{temp\_ptr})=\\{vlist\_node}$ \1\&{then}\5
+\\{vlist\_out}\ \&{else} \\{hlist\_out};\2\6
+\&{end};\par
+\fi
+
+\M1466. These routines are used to output diagnostic which related direction.
+
+\fi
+
+\M1467. \P$\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_dir}(\\{dir}:\\{eight\_bits})$;\C{prints %
+\\{dir} data}\2\6
+\&{begin} \37\&{if} $\\{dir}=\\{dir\_yoko}$ \1\&{then}\5
+$\\{print\_char}(\.{"Y"})$\6
+\4\&{else} \&{if} $\\{dir}=\\{dir\_tate}$ \1\&{then}\5
+$\\{print\_char}(\.{"T"})$\6
+\4\&{else} \&{if} $\\{dir}=\\{dir\_dtou}$ \1\&{then}\5
+$\\{print\_char}(\.{"D"})$\2\2\2\6
+\&{end};\7
+\4\&{procedure}\1\  \37$\\{print\_direction}(\|d:\\{integer})$;\C{print the
+direction represented by d}\2\6
+\&{begin} \37\&{case} $\\{abs}(\|d)$ \1\&{of}\6
+\4\\{dir\_yoko}: \37$\\{print}(\.{"yoko"})$;\6
+\4\\{dir\_tate}: \37$\\{print}(\.{"tate"})$;\6
+\4\\{dir\_dtou}: \37$\\{print}(\.{"dtou"})$;\2\6
+\&{end};\6
+\&{if} $\|d<0$ \1\&{then}\5
+$\\{print}(\.{"(math)"})$;\2\6
+$\\{print}(\.{"\ direction"})$;\6
+\&{end};\par
+\fi
+
+\M1468. The procedure \\{set\_math\_kchar} is same as \\{set\_math\_char} which
+written in section 48.
+
+\Y\P$\4\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{set\_math\_kchar}(\|c:\\{integer})$;\6
+\4\&{var} \37\|p: \37\\{pointer};\C{the new noad}\2\6
+\&{begin} \37$\|p\K\\{new\_noad}$;\5
+$\\{math\_type}(\\{nucleus}(\|p))\K\\{math\_jchar}$;\5
+$\\{inhibit\_glue\_flag}\K\\{false}$;\5
+$\\{character}(\\{nucleus}(\|p))\K\\{qi}(0)$;\5
+$\\{math\_kcode}(\|p)\K\|c$;\5
+$\\{fam}(\\{nucleus}(\|p))\K\\{cur\_jfam}$;\6
+\&{if} $\\{font\_dir}[\\{fam\_fnt}(\\{fam}(\\{nucleus}(\|p))+\\{cur\_size})]=%
+\\{dir\_default}$ \1\&{then}\6
+\&{begin} \37$\\{print\_err}(\.{"Not\ two-byte\ family"})$;\5
+$\\{help1}(\.{"IGNORE."})$;\6
+\\{error};\6
+\&{end};\2\6
+$\\{type}(\|p)\K\\{ord\_noad}$;\5
+$\\{link}(\\{tail})\K\|p$;\5
+$\\{tail}\K\|p$;\6
+\&{end};\par
+\fi
+
+\M1469. This section is a part of \\{main\_control}.
+
+\Y\P$\4\X1469:Append KANJI-character \\{cur\_chr} to the current hlist in the
+current font; \&{goto} \\{reswitch} when a non-character has been fetched\X\S$\6
+\&{if} $\\{is\_char\_node}(\\{tail})$ \1\&{then}\6
+\&{begin} \37$\\{cx}\K\\{qo}(\\{character}(\\{tail}))$;\5
+\X1445:Insert \\{post\_break\_penalty}\X;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{type}(\\{tail})=\\{ligature\_node}$ \1\&{then}\6
+\&{begin} \37$\\{cx}\K\\{qo}(\\{character}(\\{lig\_char}(\\{tail})))$;\5
+\X1445:Insert \\{post\_break\_penalty}\X;\6
+\&{end};\2\2\6
+\&{if} $\\{direction}=\\{dir\_tate}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{font\_dir}[\\{main\_f}]=\\{dir\_tate}$ \1\&{then}\5
+$\\{disp}\K0$\6
+\4\&{else} \&{if} $\\{font\_dir}[\\{main\_f}]=\\{dir\_yoko}$ \1\&{then}\5
+$\\{disp}\K\\{t\_baseline\_shift}-\\{y\_baseline\_shift}$\6
+\4\&{else} $\\{disp}\K\\{t\_baseline\_shift}$;\2\2\6
+$\\{main\_f}\K\\{cur\_tfont}$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37\&{if} $\\{font\_dir}[\\{main\_f}]=\\{dir\_yoko}$ \1%
+\&{then}\5
+$\\{disp}\K0$\6
+\4\&{else} \&{if} $\\{font\_dir}[\\{main\_f}]=\\{dir\_tate}$ \1\&{then}\5
+$\\{disp}\K\\{y\_baseline\_shift}-\\{t\_baseline\_shift}$\6
+\4\&{else} $\\{disp}\K\\{y\_baseline\_shift}$;\2\2\6
+$\\{main\_f}\K\\{cur\_jfont}$;\6
+\&{end};\2\6
+\X1471:Append \\{disp\_node} at end of displace area\X;\6
+$\\{ins\_kp}\K\\{false}$;\5
+$\\{ligature\_present}\K\\{false}$;\5
+$\\{cur\_l}\K\\{qi}(\\{get\_jfm\_pos}(\\{KANJI}(\\{cur\_chr}),\39\\{main%
+\_f}))$;\5
+$\\{main\_i}\K\\{orig\_char\_info}(\\{main\_f})(\\{qi}(0))$;\5
+\&{goto} \37$\\{main\_loop\_j}+3$;\7
+\4$\\{main\_loop\_j}+1$: \37$\\{space\_factor}\K1000$;\6
+\&{if} $\\{main\_f}\I\\{null\_font}$ \1\&{then}\6
+\&{begin} \37$\\{fast\_get\_avail}(\\{main\_p})$;\5
+$\\{font}(\\{main\_p})\K\\{main\_f}$;\5
+$\\{character}(\\{main\_p})\K\\{cur\_l}$;\5
+$\\{link}(\\{tail})\K\\{main\_p}$;\5
+$\\{tail}\K\\{main\_p}$;\5
+$\\{last\_jchr}\K\\{tail}$;\5
+$\\{fast\_get\_avail}(\\{main\_p})$;\5
+$\\{info}(\\{main\_p})\K\\{KANJI}(\\{cur\_chr})$;\5
+$\\{link}(\\{tail})\K\\{main\_p}$;\5
+$\\{tail}\K\\{main\_p}$;\5
+$\\{cx}\K\\{cur\_chr}$;\5
+\X1443:Insert kinsoku penalty\X;\6
+\&{end};\2\6
+$\\{ins\_kp}\K\\{false}$;\6
+\4\\{again\_2}: \37\\{get\_next};\5
+$\\{main\_i}\K\\{orig\_char\_info}(\\{main\_f})(\\{cur\_l})$;\6
+\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\4$\\{kanji},\39\\{kana},\39\\{other\_kchar}$: \37\&{begin} \37$\\{cur\_l}\K%
+\\{qi}(\\{get\_jfm\_pos}(\\{KANJI}(\\{cur\_chr}),\39\\{main\_f}))$;\5
+\&{goto} \37$\\{main\_loop\_j}+3$;\6
+\&{end};\6
+\4$\\{letter},\39\\{other\_char}$: \37\&{begin} \37$\\{ins\_kp}\K\\{true}$;\5
+$\\{cur\_l}\K\\{qi}(0)$;\5
+\&{goto} \37$\\{main\_loop\_j}+3$;\6
+\&{end};\2\6
+\&{endcases};\5
+\\{x\_token};\6
+\&{case} $\\{cur\_cmd}$ \1\&{of}\6
+\4$\\{kanji},\39\\{kana},\39\\{other\_kchar}$: \37$\\{cur\_l}\K\\{qi}(\\{get%
+\_jfm\_pos}(\\{KANJI}(\\{cur\_chr}),\39\\{main\_f}))$;\6
+\4$\\{letter},\39\\{other\_char}$: \37\&{begin} \37$\\{ins\_kp}\K\\{true}$;\5
+$\\{cur\_l}\K\\{qi}(0)$;\6
+\&{end};\6
+\4\\{char\_given}: \37\&{begin} \37\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ %
+\1\&{then}\6
+\&{begin} \37$\\{ins\_kp}\K\\{true}$;\5
+$\\{cur\_l}\K\\{qi}(0)$;\6
+\&{end}\6
+\4\&{else} $\\{cur\_l}\K\\{qi}(\\{get\_jfm\_pos}(\\{KANJI}(\\{cur\_chr}),\39%
+\\{main\_f}))$;\2\6
+\&{end};\6
+\4\\{char\_num}: \37\&{begin} \37\\{scan\_char\_num};\5
+$\\{cur\_chr}\K\\{cur\_val}$;\6
+\&{if} $\\{is\_char\_ascii}(\\{cur\_chr})$ \1\&{then}\6
+\&{begin} \37$\\{ins\_kp}\K\\{true}$;\5
+$\\{cur\_l}\K\\{qi}(0)$;\6
+\&{end}\6
+\4\&{else} $\\{cur\_l}\K\\{qi}(\\{get\_jfm\_pos}(\\{KANJI}(\\{cur\_chr}),\39%
+\\{main\_f}))$;\2\6
+\&{end};\6
+\4\\{inhibit\_glue}: \37\&{begin} \37$\\{inhibit\_glue\_flag}\K\\{true}$;\5
+\&{goto} \37\\{again\_2};\6
+\&{end};\6
+\4\&{othercases} \37\&{begin} \37$\\{ins\_kp}\K\\{max\_halfword}$;\5
+$\\{cur\_l}\K\\{qi}(0)$;\5
+$\\{cur\_r}\K\\{non\_char}$;\5
+$\\{lig\_stack}\K\\{null}$;\6
+\&{end};\2\6
+\&{endcases};\7
+\4$\\{main\_loop\_j}+3$: \37\&{if} $\\{ins\_kp}=\\{true}$ \1\&{then}\5
+\X1444:Insert \\{pre\_break\_penalty} of \\{cur\_chr}\X;\2\6
+\&{if} $\\{main\_f}\I\\{null\_font}$ \1\&{then}\6
+\&{begin} \37\X1472:Look ahead for glue or kerning\X;\6
+\&{end}\6
+\4\&{else} $\\{inhibit\_glue\_flag}\K\\{false}$;\2\6
+\&{if} $\\{ins\_kp}=\\{false}$ \1\&{then}\6
+\&{begin} \37\C{ Kanji -> Kanji }\6
+\&{goto} \37$\\{main\_loop\_j}+1$;\6
+\&{end}\6
+\4\&{else} \&{if} $\\{ins\_kp}=\\{true}$ \1\&{then}\6
+\&{begin} \37\C{ Kanji -> Ascii }\6
+\C{@<Append \\{disp\_node} at begin of displace area@>;}\6
+$\\{ins\_kp}\K\\{false}$;\5
+\&{goto} \37\\{main\_loop};\6
+\&{end}\6
+\4\&{else} \&{begin} \37\C{ Kanji -> cs }\6
+\C{@<Append \\{disp\_node} at begin of displace area@>;}\6
+\&{goto} \37\\{reswitch};\6
+\&{end};\2\2\par
+\U1041.\fi
+
+\M1470. \P$\X1470:Append \\{disp\_node} at begin of displace area\X\S$\6
+\&{begin} \37\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=%
+\\{disp\_node})$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{prev\_disp}=\\{disp}$ \1\&{then}\6
+\&{begin} \37$\\{free\_node}(\\{tail},\39\\{small\_node\_size})$;\5
+$\\{tail}\K\\{prev\_node}$;\5
+$\\{link}(\\{tail})\K\\{null}$;\6
+\&{end}\6
+\4\&{else} $\\{disp\_dimen}(\\{tail})\K\\{disp}$;\2\6
+\&{end}\6
+\4\&{else} \&{if} $\\{disp}\I0$ \1\&{then}\6
+\&{begin} \37$\\{prev\_node}\K\\{tail}$;\5
+$\\{tail\_append}(\\{get\_node}(\\{small\_node\_size}))$;\5
+$\\{type}(\\{tail})\K\\{disp\_node}$;\5
+$\\{disp\_dimen}(\\{tail})\K\\{disp}$;\5
+$\\{prev\_disp}\K\\{disp}$;\6
+\&{end};\2\2\6
+\&{end};\par
+\Us1045, 1136\ETs1208.\fi
+
+\M1471. \P$\X1471:Append \\{disp\_node} at end of displace area\X\S$\6
+\&{if} $\\{disp}\I0$ \1\&{then}\6
+\&{begin} \37\&{if} $\R\\{is\_char\_node}(\\{tail})\W(\\{type}(\\{tail})=%
+\\{disp\_node})$ \1\&{then}\6
+\&{begin} \37$\\{disp\_dimen}(\\{tail})\K0$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{prev\_node}\K\\{tail}$;\5
+$\\{tail\_append}(\\{get\_node}(\\{small\_node\_size}))$;\5
+$\\{type}(\\{tail})\K\\{disp\_node}$;\5
+$\\{disp\_dimen}(\\{tail})\K0$;\5
+$\\{prev\_disp}\K\\{disp}$;\6
+\&{end};\2\6
+\&{end};\2\par
+\Us1047, 1135, 1208\ETs1469.\fi
+
+\M1472. \P$\X1472:Look ahead for glue or kerning\X\S$\6
+$\\{cur\_q}\K\\{tail}$;\6
+\&{if} $\\{inhibit\_glue\_flag}\I\\{true}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{char\_tag}(\\{main\_i})=\\{gk\_tag}$ \1\&{then}\6
+\&{begin} \37$\\{main\_k}\K\\{glue\_kern\_start}(\\{main\_f})(\\{main\_i})$;\6
+\1\&{repeat} \37$\\{main\_j}\K\\{font\_info}[\\{main\_k}].\\{qqqq}$;\6
+\&{if} $\\{next\_char}(\\{main\_j})=\\{cur\_l}$ \1\&{then}\6
+\&{begin} \37\&{if} $\\{op\_byte}(\\{main\_j})<\\{kern\_flag}$ \1\&{then}\6
+\&{begin} \37$\\{gp}\K\\{font\_glue}[\\{main\_f}]$;\5
+$\\{cur\_r}\K\\{rem\_byte}(\\{main\_j})$;\6
+\&{if} $\\{gp}\I\\{null}$ \1\&{then}\6
+\&{begin} \37\&{while} $((\\{type}(\\{gp})\I\\{cur\_r})\W(\\{link}(\\{gp})\I%
+\\{null}))$ \1\&{do}\5
+$\\{gp}\K\\{link}(\\{gp})$;\2\6
+$\\{gq}\K\\{glue\_ptr}(\\{gp})$;\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{gp}\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{font\_glue}[\\{main\_f}]\K\\{gp}$;\5
+$\\{gq}\K\\{null}$;\6
+\&{end};\2\6
+\&{if} $\\{gq}=\\{null}$ \1\&{then}\6
+\&{begin} \37$\\{type}(\\{gp})\K\\{cur\_r}$;\5
+$\\{gq}\K\\{new\_spec}(\\{zero\_glue})$;\5
+$\\{glue\_ptr}(\\{gp})\K\\{gq}$;\5
+$\\{main\_k}\K\\{exten\_base}[\\{main\_f}]+\\{qi}((\\{qo}(\\{cur\_r}))\ast3)$;\5
+$\\{width}(\\{gq})\K\\{font\_info}[\\{main\_k}].\\{sc}$;\5
+$\\{stretch}(\\{gq})\K\\{font\_info}[\\{main\_k}+1].\\{sc}$;\5
+$\\{shrink}(\\{gq})\K\\{font\_info}[\\{main\_k}+2].\\{sc}$;\5
+$\\{add\_glue\_ref}(\\{gq})$;\5
+$\\{link}(\\{gp})\K\\{get\_node}(\\{small\_node\_size})$;\5
+$\\{gp}\K\\{link}(\\{gp})$;\5
+$\\{glue\_ptr}(\\{gp})\K\\{null}$;\5
+$\\{link}(\\{gp})\K\\{null}$;\6
+\&{end};\2\6
+$\\{tail\_append}(\\{new\_glue}(\\{gq}))$;\5
+$\\{subtype}(\\{tail})\K\\{jfm\_skip}+1$;\5
+\&{goto} \37\\{skip\_loop};\6
+\&{end}\6
+\4\&{else} \&{begin} \37$\\{tail\_append}(\\{new\_kern}(\\{char\_kern}(\\{main%
+\_f})(\\{main\_j})))$;\5
+\&{goto} \37\\{skip\_loop};\6
+\&{end};\2\6
+\&{end};\2\6
+$\\{incr}(\\{main\_k})$;\6
+\4\&{until}\5
+$\\{skip\_byte}(\\{main\_j})\G\\{stop\_flag}$;\2\6
+\&{end};\2\6
+\&{end};\2\6
+\4\\{skip\_loop}: \37$\\{inhibit\_glue\_flag}\K\\{false}$;\par
+\U1469.\fi
+
+\M1473. \P$\X58:Basic printing procedures\X\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37$\\{print\_kanji}(\|s:\\{KANJI\_code})$;\C{prints a
+single character}\2\6
+\&{begin} \37\&{if} $\|s>255$ \1\&{then}\6
+\&{begin} \37$\\{print\_char}(\\{Hi}(\|s))$;\5
+$\\{print\_char}(\\{Lo}(\|s))$;\6
+\&{end}\6
+\4\&{else} $\\{print\_char}(\|s)$;\2\6
+\&{end};\par
+\fi
+
+\N1474.  \[56] System-dependent changes.
+This section should be replaced, if necessary, by any special
+modifications of the program
+that are necessary to make \TeX\ work at a particular installation.
+It is usually best to design your change file so that all changes to
+previous sections preserve the section numbering; then everybody's version
+will be consistent with the published program. More extensive changes,
+which introduce new sections, can be inserted here; then only the index
+itself will get a new section number.
+
+
+\fi
+
+\M1475. \P$\X1055:Declare action procedures for use by \\{main\_control}\X%
+\mathrel{+}\S$\6
+\4\&{procedure}\1\  \37\\{insert\_src\_special};\6
+\4\&{var} \37$\\{toklist},\39\|p,\39\|q$: \37\\{pointer};\2\6
+\&{begin} \37\&{if} $(\\{source\_filename\_stack}[\\{in\_open}]>0\W\\{is\_new%
+\_source}(\\{source\_filename\_stack}[\\{in\_open}],\39\\{line}))$ \1\&{then}\6
+\&{begin} \37$\\{toklist}\K\\{get\_avail}$;\5
+$\|p\K\\{toklist}$;\5
+$\\{info}(\|p)\K\\{cs\_token\_flag}+\\{frozen\_special}$;\5
+$\\{link}(\|p)\K\\{get\_avail}$;\5
+$\|p\K\\{link}(\|p)$;\5
+$\\{info}(\|p)\K\\{left\_brace\_token}+\.{"\{"}$;\5
+$\|q\K\\{str\_toks}(\\{make\_src\_special}(\\{source\_filename\_stack}[\\{in%
+\_open}],\39\\{line}))$;\5
+$\\{link}(\|p)\K\\{link}(\\{temp\_head})$;\5
+$\|p\K\|q$;\5
+$\\{link}(\|p)\K\\{get\_avail}$;\5
+$\|p\K\\{link}(\|p)$;\5
+$\\{info}(\|p)\K\\{right\_brace\_token}+\.{"\}"}$;\5
+$\\{ins\_list}(\\{toklist})$;\5
+$\\{remember\_source\_info}(\\{source\_filename\_stack}[\\{in\_open}],\39%
+\\{line})$;\6
+\&{end};\2\6
+\&{end};\6
+\4\&{procedure}\1\  \37\\{append\_src\_special};\6
+\4\&{var} \37\|q: \37\\{pointer};\2\6
+\&{begin} \37\&{if} $(\\{source\_filename\_stack}[\\{in\_open}]>0\W\\{is\_new%
+\_source}(\\{source\_filename\_stack}[\\{in\_open}],\39\\{line}))$ \1\&{then}\6
+\&{begin} \37$\\{new\_whatsit}(\\{special\_node},\39\\{write\_node\_size})$;\5
+$\\{write\_stream}(\\{tail})\K0$;\5
+$\\{def\_ref}\K\\{get\_avail}$;\5
+$\\{token\_ref\_count}(\\{def\_ref})\K\\{null}$;\5
+$\|q\K\\{str\_toks}(\\{make\_src\_special}(\\{source\_filename\_stack}[\\{in%
+\_open}],\39\\{line}))$;\5
+$\\{link}(\\{def\_ref})\K\\{link}(\\{temp\_head})$;\5
+$\\{write\_tokens}(\\{tail})\K\\{def\_ref}$;\5
+$\\{remember\_source\_info}(\\{source\_filename\_stack}[\\{in\_open}],\39%
+\\{line})$;\6
+\&{end};\2\6
+\&{end};\par
+\fi
+
+\M1476. This function used to be in pdftex, but is useful in tex too.
+
+\Y\P\4\&{function}\1\  \37\\{get\_nullstr}: \37\\{str\_number};\2\6
+\&{begin} \37$\\{get\_nullstr}\K\.{""}$;\6
+\&{end};\par
+\fi
+
+\N1477.  \[55] Index.
+Here is where you can find all uses of each identifier in the program,
+with underlined entries pointing to where the identifier was defined.
+If the identifier is only one letter long, however, you get to see only
+the underlined entries. {\sl All references are to section numbers instead of
+page numbers.}
+
+This index also lists error messages and other aspects of the program
+that you might want to look up some day. For example, the entry
+for ``system dependencies'' lists all sections that should receive
+special attention from people who are installing \TeX\ in a new
+operating environment. A list of various things that can't happen appears
+under ``this can't happen''. Approximately 40 sections are listed under
+``inner loop''; these account for about 60\pct! of \TeX's running time,
+exclusive of input and output.
+\fi
+
+
+\inx
+\:\.{**}, 38, 545.
+\:\.{*\relax}, 180, 182, 184, 319, 368, 867, 1017, 1368.
+\:\.{->}, 300.
+\:{<system dependencies}, 1392.
+\:\.{=>}, 371.
+\:\.{???}, 60.
+\:\.{?\relax}, 84.
+\:\.{\AT!}, 867.
+\:\.{\AT!\AT!}, 857.
+\:\|{a}, \[48], \[103], \[224], \[529], \[530], \[534], \[571], \[702], \[733],
+\[749], \[763], \[1135], \[1206], \[1223], \[1249], \[1270].
+\:\.{A <box> was supposed to...}, 1096.
+\:\\{a\_close}, 52, 335, 496, 497, 1288, 1346, 1387, 1391.
+\:\\{a\_dir}, \[1091], 1095.
+\:\\{a\_leaders}, \[155], 195, 636, 638, 645, 647, 667, 682, 1083, 1084, 1085,
+1090, 1160.
+\:\\{a\_make\_name\_string}, \[536], 545, 548.
+\:\\{a\_open\_in}, 52, 548, 1288.
+\:\\{a\_open\_out}, 545, 1387.
+\:\\{A\_token}, \[456].
+\:\\{abort}, \[571], 574, 575, 576, 579, 580, 581, 582, 584, 586.
+\:\\{above}, \[214], 1058, 1190, 1191, 1192.
+\:\9{above\_}{\.{\\above} primitive}, \[1190].
+\:\\{above\_code}, \[1190], 1191, 1194, 1195.
+\:\\{above\_display\_short\_skip}, \[230], 825.
+\:\9{above\_display\_short\_skip\_}{\.{\\abovedisplayshortskip} primitive}, %
+\[232].
+\:\\{above\_display\_short\_skip\_code}, \[230], 231, 232, 1215.
+\:\\{above\_display\_skip}, \[230], 825.
+\:\9{above\_display\_skip\_}{\.{\\abovedisplayskip} primitive}, \[232].
+\:\\{above\_display\_skip\_code}, \[230], 231, 232, 1215, 1218.
+\:\9{above\_with\_delims\_}{\.{\\abovewithdelims} primitive}, \[1190].
+\:\\{abs}, 67, 192, 217, 224, 225, 429, 431, 433, 459, 512, 621, 674, 686, 729,
+748, 768, 769, 770, 818, 820, 821, 822, 842, 847, 860, 870, 955, 959, 1040,
+1041, 1068, 1088, 1090, 1092, 1093, 1095, 1098, 1103, 1105, 1112, 1122, 1132,
+1139, 1150, 1161, 1180, 1212, 1256, 1257, 1260, 1390, 1467.
+\:\\{absorbing}, \[311], 312, 345, 484.
+\:\\{acc\_kern}, \[161], 197, 1137, 1451.
+\:\\{accent}, \[214], 271, 272, 1102, 1134, 1176, 1177.
+\:\9{accent\_}{\.{\\accent} primitive}, \[271].
+\:\\{accent\_c}, \[1410], 1411, 1412, 1413.
+\:\\{accent\_chr}, \[698], 707, 749, 1177.
+\:\\{accent\_height}, \[1410], 1413.
+\:\\{accent\_noad}, \[698], 701, 707, 709, 744, 772, 1177, 1198.
+\:\\{accent\_noad\_size}, \[698], 709, 772, 1177.
+\:\\{accent\_slant}, \[1410], 1413.
+\:\\{accent\_width}, \[1410], 1413.
+\:\\{act\_width}, \[877], 878, 879, 880, 882.
+\:{action procedure}, \[1040].
+\:\\{active}, \[168], 830, 840, 854, 865, 871, 872, 874, 875, 876, 884, 885,
+886.
+\:\\{active\_base}, 226, \[228], 258, 261, 268, 269, 361, 453, 517, 1164, 1270,
+1302, 1328, 1330.
+\:\\{active\_char}, \[213], 350, 517.
+\:\\{active\_height}, \[981], 986, 987.
+\:\\{active\_node\_size}, \[830], 856, 871, 875, 876.
+\:\\{active\_width}, \[834], 835, 840, 854, 872, 875, 877, 878, 879, 981.
+\:\\{actual\_looseness}, \[883], 884, 886.
+\:\\{add\_delims\_to}, \[353].
+\:\\{add\_glue\_ref}, 137, \[209], 212, 441, 660, 679, 763, 807, 810, 813, 815,
+827, 892, 1007, 1098, 1112, 1137, 1206, 1241, 1451, 1472.
+\:\\{add\_token\_ref}, \[209], 212, 329, 990, 1023, 1027, 1233, 1239, 1370.
+\:\\{additional}, \[655], 656, 668, 683.
+\:\\{addressof}, 1345, 1383.
+\:\\{adj\_demerits}, \[242], 847, 870.
+\:\9{adj\_demerits\_}{\.{\\adjdemerits} primitive}, \[244].
+\:\\{adj\_demerits\_code}, \[242], 243, 244.
+\:\\{adj\_dir\_field}, \[218], 219.
+\:\\{adjust}, \[587].
+\:\\{adjust\_dir}, \[219], 221, 1095, 1103, 1111, 1112, 1212.
+\:\\{adjust\_head}, \[168], 899, 900, 1088, 1097, 1211, 1217.
+\:\\{adjust\_hlist}, 737, 807, 810, 815, 1097, 1108, 1157, 1449, \[1451].
+\:\\{adjust\_node}, \[148], 154, 181, 189, 208, 212, 658, 662, 666, 741, 772,
+877, 910, 1112, 1450, 1451, 1464.
+\:\\{adjust\_ptr}, \[148], 203, 208, 212, 666, 1112.
+\:\\{adjust\_space\_factor}, \[1045], 1049.
+\:\\{adjust\_tail}, \[658], 659, 660, 662, 666, 807, 899, 900, 1088, 1097, 1211.
+\:\\{adjusted\_hbox\_group}, \[275], 1074, 1095, 1097.
+\:\\{adv\_past}, \[1375], 1376.
+\:\\{advance}, \[215], 271, 272, 1222, 1248, 1249, 1251.
+\:\9{advance\_}{\.{\\advance} primitive}, \[271].
+\:\\{advance\_major\_tail}, \[925], 928.
+\:\\{after}, \[153], 877, 1208, 1450, 1456.
+\:\\{after\_assignment}, \[214], 271, 272, 1281.
+\:\9{after\_assignment\_}{\.{\\afterassignment} primitive}, \[271].
+\:\\{after\_group}, \[214], 271, 272, 1284.
+\:\9{after\_group\_}{\.{\\aftergroup} primitive}, \[271].
+\:\\{after\_math}, 1205, \[1206].
+\:\\{after\_schar}, \[1451], 1452, 1454, 1455, 1456, 1457, 1458.
+\:\\{after\_token}, \[1279], 1280, 1281, 1282.
+\:\\{after\_wchar}, \[1451], 1452, 1454, 1455, 1456, 1457, 1458.
+\:\\{again\_2}, \[1041], 1469.
+\:\\{aire}, \[571], 572, 574, 587.
+\:\\{align\_error}, 1138, \[1139].
+\:\\{align\_group}, \[275], 779, 785, 802, 811, 1085, 1143, 1144.
+\:\\{align\_head}, \[168], 781, 788.
+\:\\{align\_peek}, 784, 785, \[796], 810, 1060, 1145.
+\:\\{align\_ptr}, \[781], 782, 783.
+\:\\{align\_stack\_node\_size}, \[781], 783.
+\:\\{align\_state}, 89, \[315], 330, 331, 337, 345, 348, 353, 365, 405, 406,
+407, 414, 453, 486, 493, 494, 497, 781, 782, 783, 785, 788, 794, 795, 796, 799,
+800, 802, 1081, 1106, 1138, 1139.
+\:\\{aligning}, \[311], 312, 345, 788, 800.
+\:{alignment of rules with characters}, 600.
+\:\\{all\_jcode}, \[353].
+\:\\{alpha}, \[571], 582, 583.
+\:\\{alpha\_file}, \[25], 51, 55, 310, 491, 536, 1345, 1355.
+\:\\{alpha\_token}, \[449], 451.
+\:\\{alter\_aux}, 1255, \[1256].
+\:\\{alter\_box\_dimen}, 1255, \[1260].
+\:\\{alter\_integer}, 1255, \[1259].
+\:\\{alter\_page\_so\_far}, 1255, \[1258].
+\:\\{alter\_prev\_graf}, 1255, \[1257].
+\:\.{Ambiguous...}, 1195.
+\:{Amble, Ole}, 936.
+\:\.{AmSTeX}, 1344.
+\:\\{any\_dir}, \[136], 1031, 1122.
+\:\\{any\_mode}, \[1057], 1060, 1069, 1075, 1079, 1085, 1109, 1114, 1116, 1138,
+1146, 1222, 1281, 1284, 1287, 1289, 1298, 1303, 1360, 1432.
+\:\\{any\_state\_plus}, \[350], 351, 353.
+\:\\{app\_lc\_hex}, \[49].
+\:\\{app\_space}, 1041, \[1055].
+\:\\{append\_char}, \[43], 49, 53, 59, 186, 201, 266, 527, 536, 537, 703, 706,
+950, 1383.
+\:\\{append\_charnode\_to\_t}, \[919], 922.
+\:\\{append\_choices}, 1183, \[1184].
+\:\\{append\_discretionary}, 1128, \[1129].
+\:\\{append\_glue}, 1069, \[1072], 1090.
+\:\\{append\_italic\_correction}, 1124, \[1125].
+\:\\{append\_kern}, 1069, \[1073].
+\:\\{append\_normal\_space}, \[1041].
+\:\\{append\_penalty}, 1114, \[1115].
+\:\\{append\_src\_special}, 1045, \[1475].
+\:\\{append\_to\_name}, \[530], 534.
+\:\\{append\_to\_vlist}, \[690], 810, 899, 1088, 1215, 1216, 1217.
+\:\\{area\_delimiter}, \[524], 526, 527, 528, 536.
+\:\.{Argument of \\x has...}, 406.
+\:\\{arith\_error}, \[105], 106, 107, 108, 459, 464, 471, 1249.
+\:\.{Arithmetic overflow}, 1249.
+\:\\{artificial\_demerits}, \[841], 862, 865, 866, 867.
+\:{ASCII code}, 17, 514.
+\:\\{ASCII\_code}, \[18], 19, 20, 30, 31, 32, 39, 43, 52, 55, 59, 61, 83, 298,
+347, 400, 527, 530, 534, 703, 873, 903, 923, 932, 954, 961, 964, 970, 971,
+1316, 1345, 1389, 1451.
+\:\\{assign\_dimen}, \[215], 254, 255, 424, 1222, 1236, 1240.
+\:\\{assign\_font\_dimen}, \[215], 271, 272, 424, 1222, 1266.
+\:\\{assign\_font\_int}, \[215], 424, 1222, 1266, 1267, 1268.
+\:\\{assign\_glue}, \[215], 232, 233, 424, 793, 1222, 1236, 1240.
+\:\\{assign\_inhibit\_xsp\_code}, \[215], 424, 1222, 1433, 1434, 1436.
+\:\\{assign\_int}, \[215], 244, 245, 424, 1222, 1234, 1236, 1240, 1250.
+\:\\{assign\_kinsoku}, \[215], 424, 1222, 1438, 1439, 1441.
+\:\\{assign\_mu\_glue}, \[215], 232, 233, 424, 1222, 1234, 1236, 1240, 1250.
+\:\\{assign\_toks}, \[215], 236, 237, 239, 329, 424, 426, 1222, 1236, 1238,
+1239.
+\:\.{at}, 1271.
+\:\9{atop\_}{\.{\\atop} primitive}, \[1190].
+\:\\{atop\_code}, \[1190], 1191, 1194.
+\:\9{atop\_with\_delims\_}{\.{\\atopwithdelims} primitive}, \[1190].
+\:\\{attach\_fraction}, \[459], 464, 465, 467.
+\:\\{attach\_sign}, \[459], 460, 466.
+\:\\{auto\_breaking}, \[873], 874, 877, 879.
+\:\\{auto\_spacing}, \[236], 1098, 1206, 1429, 1451.
+\:\9{auto\_spacing\_}{\.{\\autospacing} primitive}, \[1426].
+\:\\{auto\_spacing\_code}, \[236], 238, 1428.
+\:\\{auto\_spacing\_glue}, 630.
+\:\\{auto\_xsp\_code}, \[236], 238, 1452, 1455, 1456, 1457, 1458, 1460.
+\:\9{auto\_xsp\_code\_}{\.{\\xspcode} primitive}, \[1242].
+\:\\{auto\_xsp\_code\_base}, \[236], 241, 1242, 1243.
+\:\\{auto\_xspacing}, \[236], 1098, 1206, 1429, 1451.
+\:\9{auto\_xspacing\_}{\.{\\autoxspacing} primitive}, \[1426].
+\:\\{auto\_xspacing\_code}, \[236], 238, 1428.
+\:\\{aux}, 218, \[219], 222, 811, 823.
+\:\\{aux\_field}, \[218], 219, 224, 786.
+\:\\{aux\_save}, \[811], 823, 1218.
+\:\\{avail}, \[119], 121, 122, 123, 124, 170, 174, 1324, 1325.
+\:\.{AVAIL list clobbered...}, 174.
+\:\\{awful\_bad}, \[844], 845, 846, 847, 865, 885, 981, 985, 986, 998, 1016,
+1017, 1018.
+\:\\{ax}, 1451, 1452, 1454, 1455, 1456, 1457, 1458, 1460.
+\:\\{axis\_height}, \[711], 717, 747, 757, 758, 760, 773.
+\:\|{b}, \[475], \[476], \[481], \[509], \[534], \[571], \[690], \[716], %
+\[717], \[720], \[722], \[726], \[841], \[981], \[1005], \[1210], \[1260], %
+\[1301].
+\:\\{b\_close}, 571, 653.
+\:\\{b\_make\_name\_string}, \[536], 543.
+\:\\{b\_open\_in}, 574.
+\:\\{b\_open\_out}, 543.
+\:\\{back\_error}, \[333], 384, 407, 414, 426, 453, 457, 487, 490, 514, 588,
+794, 1090, 1096, 1173, 1209, 1219, 1224.
+\:\\{back\_input}, 287, \[331], 332, 333, 379, 380, 383, 386, 390, 406, 416,
+418, 426, 454, 455, 459, 463, 466, 472, 537, 799, 1042, 1059, 1066, 1076, 1102,
+1107, 1136, 1139, 1144, 1150, 1162, 1164, 1165, 1227, 1233, 1238, 1282, 1388.
+\:\\{back\_list}, \[329], 331, 343, 418, 1301.
+\:\\{backed\_up}, \[313], 317, 318, 320, 325, 329, 330, 331, 1037.
+\:\\{background}, \[834], 835, 838, 848, 874, 875.
+\:\\{backup\_backup}, \[377].
+\:\\{backup\_head}, \[168], 377, 418.
+\:\.{BAD}, 299, 300.
+\:\\{bad}, \[13], 14, 112, 296, 533, 1262, 1345.
+\:\.{Bad \\patterns}, 972.
+\:\.{Bad \\prevgraf}, 1257.
+\:\.{Bad character code}, 445.
+\:\.{Bad delimiter code}, 448.
+\:\.{Bad flag...}, 176.
+\:\.{Bad link...}, 188.
+\:\.{Bad mathchar}, 447.
+\:\.{Bad number}, 446, 1399.
+\:\.{Bad register code}, 444.
+\:\.{Bad space factor}, 1256.
+\:\\{bad\_fmt}, \[1316], 1319, 1321, 1325, 1330, 1338, 1340, 1415.
+\:\\{bad\_pool}, \[52], 53, 54.
+\:\\{bad\_tfm}, \[571].
+\:\\{badness}, \[109], 671, 678, 685, 689, 839, 863, 864, 986, 1018.
+\:\9{badness\_}{\.{\\badness} primitive}, \[427].
+\:\\{badness\_code}, \[427], 435.
+\:\\{banner}, \[2], 62, 547, 1312.
+\:\\{banner\_k}, \[2], 62, 547.
+\:\\{base\_c}, \[1407], \[1408], \[1410], 1411, 1412, 1413.
+\:\\{base\_height}, \[1410], 1413.
+\:\\{base\_line}, \[630], 633, 634, 635, 639, 1413.
+\:\\{base\_ptr}, 85, 86, \[316], 317, 318, 319, 325, 1143.
+\:\\{base\_slant}, \[1410], 1413.
+\:\\{base\_width}, \[1410], 1413.
+\:\\{base\_x\_height}, \[1410], 1413.
+\:\\{baseline\_skip}, \[230], 253, 690.
+\:\9{baseline\_skip\_}{\.{\\baselineskip} primitive}, \[232].
+\:\\{baseline\_skip\_code}, 155, \[230], 231, 232, 690.
+\:\\{batch\_mode}, \[74], 76, 87, 91, 93, 94, 546, 1275, 1276, 1278, 1340,
+1341, 1346.
+\:\9{batch\_mode\_}{\.{\\batchmode} primitive}, \[1275].
+\:\\{bc}, 551, 552, 554, 556, \[571], 576, 577, 580, 581, 587.
+\:\\{bch\_label}, \[571], 584, 587.
+\:\\{bchar}, \[571], 584, 587, \[912], 914, 916, \[917], 919, 922, 924, 927,
+928, \[1043], 1045, 1048, 1049, 1050, 1052.
+\:\\{bchar\_label}, \[560], 587, 920, 927, 1045, 1052, 1335, 1336, 1350.
+\:\\{before}, \[153], 198, 1208, 1450, 1456.
+\:\&{begin}, 7, 8.
+\:\\{begin\_box}, 1085, \[1091], 1096.
+\:\\{begin\_diagnostic}, 77, \[251], 290, 305, 329, 411, 412, 513, 520, 592,
+649, 652, 674, 686, 874, 998, 1003, 1017, 1022, 1133, 1236, 1306, 1309, 1407,
+1411, 1412.
+\:\\{begin\_file\_reading}, 79, 88, \[334], 494, 548.
+\:\\{begin\_group}, \[214], 271, 272, 1075.
+\:\9{begin\_group\_}{\.{\\begingroup} primitive}, \[271].
+\:\\{begin\_insert\_or\_adjust}, 1109, \[1111].
+\:\\{begin\_name}, 523, \[526], 536, 537, 538, 542.
+\:\\{begin\_pseudoprint}, \[322], 324, 325.
+\:\\{begin\_token\_list}, \[329], 367, 397, 401, 785, 799, 800, 810, 1036,
+1041, 1095, 1103, 1151, 1157, 1179, 1384.
+\:\.{Beginning to dump...}, 1341.
+\:\\{below\_display\_short\_skip}, \[230].
+\:\9{below\_display\_short\_skip\_}{\.{\\belowdisplayshortskip} primitive}, %
+\[232].
+\:\\{below\_display\_short\_skip\_code}, \[230], 231, 232, 1215.
+\:\\{below\_display\_skip}, \[230].
+\:\9{below\_display\_skip\_}{\.{\\belowdisplayskip} primitive}, \[232].
+\:\\{below\_display\_skip\_code}, \[230], 231, 232, 1215, 1218.
+\:\\{best\_bet}, \[883], 885, 886, 888, 889.
+\:\\{best\_height\_plus\_depth}, \[982], 985, 1021, 1022.
+\:\\{best\_ins\_ptr}, \[992], 1016, 1020, 1029, 1031, 1032.
+\:\\{best\_line}, \[883], 885, 886, 888, 901.
+\:\\{best\_page\_break}, \[991], 1016, 1024, 1025.
+\:\\{best\_pl\_line}, \[844], 856, 866.
+\:\\{best\_place}, \[844], 856, 866, \[981], 985, 991.
+\:\\{best\_size}, \[991], 1016, 1028.
+\:\\{beta}, \[571], 582, 583.
+\:\\{big\_op\_spacing1}, \[712], 762.
+\:\\{big\_op\_spacing2}, \[712], 762.
+\:\\{big\_op\_spacing3}, \[712], 762.
+\:\\{big\_op\_spacing4}, \[712], 762.
+\:\\{big\_op\_spacing5}, \[712], 762.
+\:\\{big\_switch}, 215, 242, 1005, 1040, \[1041], 1042, 1047, 1053.
+\:{BigEndian order}, \[551].
+\:\\{billion}, \[636].
+\:\\{bin\_noad}, \[693], 701, 707, 709, 739, 740, 772, 1168, 1169.
+\:\\{bin\_op\_penalty}, \[242], 772.
+\:\9{bin\_op\_penalty\_}{\.{\\binoppenalty} primitive}, \[244].
+\:\\{bin\_op\_penalty\_code}, \[242], 243, 244.
+\:\\{blank\_line}, \[251].
+\:\\{boolean}, 33, 38, 46, 47, 48, 77, 80, 97, 105, 107, 108, 171, 173, 251,
+262, 317, 354, 369, 418, 424, 451, 459, 472, 484, 509, 527, 528, 529, 535, 536,
+538, 560, 571, 589, 603, 630, 640, 656, 717, 730, 737, 802, 836, 839, 840, 841,
+873, 888, 911, 918, 954, 961, 971, 1000, 1023, 1041, 1043, 1063, 1066, 1091,
+1103, 1117, 1172, 1206, 1223, 1294, 1316, 1350, 1355, 1383, 1392, 1396, 1404,
+1405, 1407, 1430, 1449, 1450, 1451.
+\:\\{bop}, 594, 596, \[597], 599, 601, 603, 649, 651.
+\:{Bosshard, Hans Rudolf}, 469.
+\:\\{bot}, \[557].
+\:\\{bot\_mark}, \[393], 394, 1023, 1027.
+\:\9{bot\_mark\_}{\.{\\botmark} primitive}, \[395].
+\:\\{bot\_mark\_code}, \[393], 395, 396.
+\:\\{bottom\_level}, \[275], 278, 287, 1076, 1080.
+\:\\{bottom\_line}, \[317].
+\:\\{bound\_default}, \[33], 1345.
+\:\\{bound\_name}, \[33], 1345.
+\:{bowels}, 603.
+\:\\{box}, \[236], 238, 431, 516, 988, 1003, 1004, 1020, 1026, 1028, 1029,
+1031, 1032, 1034, 1039, 1091, 1122, 1260, 1309.
+\:\9{box\_}{\.{\\box} primitive}, \[1083].
+\:\\{box\_base}, \[236], 238, 239, 261, 1089.
+\:\\{box\_code}, \[1083], 1084, 1091, 1119, 1122.
+\:\\{box\_context}, \[1087], 1088, 1089, 1090, \[1091], 1095, \[1096].
+\:\\{box\_dir}, \[136], 139, 190, 431, 516, 649, 988, 1020, 1031, 1088, 1090,
+1093, 1112, 1122, 1180, 1260, 1465.
+\:\\{box\_end}, \[1087], 1091, 1096, 1098.
+\:\\{box\_error}, \[1003], 1004, 1020, 1026, 1031, 1039.
+\:\\{box\_flag}, \[1083], 1087, 1089, 1095, 1254.
+\:\\{box\_max\_depth}, \[253], 1098.
+\:\9{box\_max\_depth\_}{\.{\\boxmaxdepth} primitive}, \[254].
+\:\\{box\_max\_depth\_code}, \[253], 254.
+\:\\{box\_node\_size}, \[136], 137, 208, 212, 223, 431, 649, 660, 679, 726,
+737, 738, 762, 767, 815, 988, 989, 1004, 1032, 1088, 1090, 1112, 1122, 1213.
+\:\\{box\_p}, 1449, 1450.
+\:\\{box\_ref}, \[216], 238, 281, 1089.
+\:\\{box\_there}, \[991], 998, 1011, 1012.
+\:\9{box255}{\.{\\box255 is not void}}, 1026.
+\:\.{bp}, 469.
+\:{brain}, 1040.
+\:\\{breadth\_max}, \[187], 188, 204, 239, 242, 1352.
+\:\\{break\_node}, \[830], 856, 866, 867, 875, 888, 889.
+\:\\{break\_penalty}, \[214], 271, 272, 1114.
+\:\\{break\_type}, \[840], 848, 856, 857, 870.
+\:\\{break\_width}, \[834], 835, 848, 849, 851, 852, 853, 854, 855, 890.
+\:\\{breakpoint}, \[1351].
+\:\\{broken\_ins}, \[992], 997, 1021, 1032.
+\:\\{broken\_penalty}, \[242], 901.
+\:\9{broken\_penalty\_}{\.{\\brokenpenalty} primitive}, \[244].
+\:\\{broken\_penalty\_code}, \[242], 243, 244.
+\:\\{broken\_ptr}, \[992], 1021, 1032.
+\:\\{buf\_size}, 31, 32, \[33], 36, 72, 112, 321, 334, 337, 347, 371, 377, 385,
+535, 541, 545, 1345, 1347.
+\:\\{buffer}, \[31], 32, 37, 38, 46, 72, 84, 88, 89, 265, 266, 267, 270, 308,
+309, 321, 324, 337, 347, 349, 360, 362, 363, 364, 368, 370, 371, 377, 385, 494,
+495, 534, 535, 541, 542, 545, 549, 1345, 1350, 1352.
+\:\\{build\_choices}, 1185, \[1186].
+\:\\{build\_discretionary}, 1130, \[1131].
+\:\\{build\_page}, 811, 823, 999, \[1005], 1037, 1066, 1072, 1088, 1103, 1106,
+1112, 1115, 1157, 1212.
+\:\.{by}, 1249.
+\:\\{bypass\_eoln}, 32.
+\:\\{byte\_file}, \[25], 536, 543, 550.
+\:\\{b0}, 111, 115, 134, 227, 274, 556, 557, 561, 565, 567, 575, 613, 694, 696,
+1322, 1323, 1352.
+\:\\{b1}, 111, 115, 134, 227, 274, 556, 557, 565, 567, 575, 613, 694, 696,
+1322, 1323, 1352.
+\:\\{b2}, 111, 115, 556, 557, 565, 567, 575, 613, 694, 696, 1322, 1323, 1352.
+\:\\{b3}, 111, 115, 556, 557, 567, 575, 613, 694, 696, 1322, 1323, 1352.
+\:\|{c}, \[48], \[64], \[83], \[150], \[270], \[280], \[298], \[347], \[481], %
+\[527], \[530], \[534], \[571], \[592], \[593], \[603], \[656], \[703], \[705],
+\[717], \[720], \[722], \[723], \[749], \[760], \[904], \[923], \[964], \[970],
+\[971], \[1005], \[1023], \[1098], \[1122], \[1129], \[1148], \[1163], \[1167],
+\[1193], \[1256], \[1258], \[1259], \[1260], \[1288], \[1292], \[1301], %
+\[1348], \[1395], \[1407], \[1408], \[1468].
+\:\\{c\_leaders}, \[155], 196, 638, 647, 1083, 1084.
+\:\9{c\_leaders\_}{\.{\\cleaders} primitive}, \[1083].
+\:\\{c\_loc}, \[923], 927.
+\:\\{calc\_pos}, 1435, 1440.
+\:\\{call}, \[216], 229, 281, 302, 374, 377, 391, 398, 406, 407, 518, 1230,
+1233, 1237, 1238, 1239, 1308.
+\:\\{call\_edit}, 85, 1346.
+\:\\{cancel\_boundary}, 1041, \[1043], 1044, 1045.
+\:\.{cannot \\read}, 495.
+\:\\{car\_ret}, \[213], 238, 348, 353, 788, 791, 792, 794, 795, 796, 799, 1138.
+\:\\{carriage\_return}, \[22], 50, 213, 238, 246, 371.
+\:\\{case\_shift}, \[214], 1298, 1299, 1300.
+\:\\{cat}, \[347], 362, 363, 364.
+\:\\{cat\_code}, \[236], 238, 242, 268, 347, 349, 362, 363, 364, 1350.
+\:\9{cat\_code\_}{\.{\\catcode} primitive}, \[1242].
+\:\9{cat\_code\_}{\.{\\kcatcode} primitive}, \[1242].
+\:\\{cat\_code\_base}, \[236], 238, 239, 241, 1242, 1243, 1246.
+\:\\{cc}, \[347], 360, 363, 364, \[873], 878.
+\:\.{cc}, 469.
+\:\\{chain}, 631, 662, 665, 827, \[839], 848, 878.
+\:\\{change\_if\_limit}, \[508], 509, 520.
+\:\\{char}, 19, 1336, 1394.
+\:\9{char\_}{\.{\\char} primitive}, \[271].
+\:\\{char\_base}, \[561], 565, 577, 580, 581, 587, 1335, 1336, 1350.
+\:\\{char\_box}, \[720], 721, 722, 749.
+\:\9{char\_def\_}{\.{\\chardef} primitive}, \[1234].
+\:\\{char\_def\_code}, \[1234], 1235, 1236.
+\:\\{char\_depth}, \[565], 665, 719, 720, 723, 1419.
+\:\\{char\_depth\_end}, \[565].
+\:\\{char\_exists}, \[565], 584, 587, 593, 631, 719, 733, 749, 751, 760, 766,
+1047, 1407, 1408, 1411.
+\:\\{char\_given}, \[214], 424, 946, 1041, 1049, 1102, 1136, 1163, 1166, 1234,
+1235, 1236, 1469.
+\:\\{char\_height}, \[565], 665, 719, 720, 723, 1137, 1413, 1419.
+\:\\{char\_height\_end}, \[565].
+\:\\{char\_info}, 554, 561, \[565], 566, 568, 593, 631, 665, 720, 723, 725,
+735, 749, 877, 920, 1048, 1051, 1052, 1125, 1135, 1137, 1407, 1408, 1411.
+\:\\{char\_info\_end}, \[565].
+\:\\{char\_info\_word}, 552, \[554], 555.
+\:\\{char\_italic}, \[565], 720, 725, 760, 766, 1125.
+\:\\{char\_italic\_end}, \[565].
+\:\\{char\_kern}, \[568], 752, 763, 764, 920, 1052, 1472.
+\:\\{char\_kern\_end}, \[568].
+\:\\{char\_list\_accent}, \[565], 1411.
+\:\\{char\_list\_char}, \[565], 1407, 1408, 1411.
+\:\\{char\_list\_exists}, \[565], 1407, 1408, 1411.
+\:\\{char\_node}, \[135], 149, 151, 168, 182, 559, 603, 631, 660, 763, 892,
+918, 1040, 1125, 1150.
+\:\\{char\_num}, \[214], 271, 272, 946, 1041, 1049, 1102, 1136, 1163, 1166,
+1469.
+\:\\{char\_sub\_code}, \[236], 565, 593, 1411.
+\:\\{char\_sub\_code\_base}, \[236], 1236.
+\:\9{char\_sub\_def\_}{\.{\\charsubdef} primitive}, \[1234].
+\:\\{char\_sub\_def\_code}, \[1234], 1235, 1236.
+\:\\{char\_sub\_def\_max}, \[242], 246, 1236, 1407, 1408, 1411.
+\:\9{char\_sub\_def\_max\_}{\.{\\charsubdefmax} primitive}, \[244].
+\:\\{char\_sub\_def\_max\_code}, \[242], 243, 244, 1236.
+\:\\{char\_sub\_def\_min}, \[242], 246, 1236, 1407, 1408, 1411.
+\:\9{char\_sub\_def\_min\_}{\.{\\charsubdefmin} primitive}, \[244].
+\:\\{char\_sub\_def\_min\_code}, \[242], 243, 244, 1236.
+\:\\{char\_tag}, \[565], 581, 719, 721, 751, 752, 760, 763, 920, 1051, 1472.
+\:\\{char\_type}, 551, 560, 571.
+\:\\{char\_warning}, \[592], 593, 733, 1047.
+\:\\{char\_width}, \[565], 631, 665, 720, 725, 726, 751, 852, 853, 877, 878,
+881, 882, 1135, 1137, 1159, 1413, 1418.
+\:\\{char\_width\_end}, \[565].
+\:\\{character}, \[135], 149, 150, 180, 182, 212, 593, 631, 665, 692, 693, 694,
+698, 702, 720, 726, 733, 735, 760, 763, 764, 852, 853, 877, 878, 881, 882, 907,
+908, 909, 914, 918, 919, 921, 922, 1043, 1045, 1046, 1047, 1048, 1049, 1052,
+1125, 1135, 1137, 1159, 1163, 1167, 1177, 1452, 1454, 1455, 1457, 1458, 1468,
+1469.
+\:{character set dependencies}, 23, 50.
+\:{check sum}, 54, 553, 599.
+\:\\{check\_box}, \[1450], 1453.
+\:\\{check\_byte\_range}, \[581], 584.
+\:\\{check\_dimensions}, \[737], 738, 744, 765.
+\:\\{check\_effective\_tail}, \[1092], 1117.
+\:\\{check\_effective\_tail\_pTeX}, \[1092].
+\:\\{check\_existence}, \[584], 585.
+\:\\{check\_full\_save\_stack}, \[279], 280, 282, 286.
+\:\\{check\_interrupt}, \[97], 330, 349, 764, 922, 1042, 1052.
+\:\\{check\_kanji}, 299, 325, 365, 385, 1302.
+\:\\{check\_mem}, 171, \[173], 1042, 1352.
+\:\\{check\_outer\_validity}, \[342], 359, 361, 362, 365, 370, 386.
+\:\\{check\_quoted}, \[529].
+\:\\{check\_shrinkage}, \[836], 838, 878, 879.
+\:\\{chg\_dir}, \[214], 1083, 1084, 1085.
+\:{Chinese characters}, 135, 596.
+\:\\{choice\_node}, 699, \[700], 701, 709, 741.
+\:\\{choose\_mlist}, \[742].
+\:\\{chr}, 19, 20, 23, 24, 1234.
+\:\\{chr\_cmd}, \[304], 792.
+\:\\{chr\_code}, 233, 237, 245, 255, \[304], 388, 396, 422, 423, 424, 428, 480,
+499, 503, 792, 995, 1065, 1071, 1083, 1084, 1101, 1120, 1127, 1155, 1169, 1182,
+1191, 1201, 1221, 1232, 1235, 1243, 1264, 1268, 1274, 1276, 1286, 1291, 1300,
+1302, 1305, 1359, 1427, 1439.
+\:\\{ci}, \[1408].
+\:\\{cinttype}, 33, 1392, 1394.
+\:\\{clang}, 218, \[219], 823, 1045, 1103, 1212, 1389, 1390.
+\:\\{clean\_box}, \[731], 745, 746, 748, 749, 753, 755, 760, 761, 768, 769, 770.
+\:\\{clear\_for\_error\_prompt}, 79, 84, \[336], 352.
+\:\\{clear\_terminal}, \[35], 336, 541.
+\:\\{clear\_trie}, \[969].
+\:\.{CLOBBERED}, 299.
+\:\\{clobbered}, \[173], 174, 175, \[1383].
+\:\\{close\_files\_and\_terminate}, 79, 82, 1345, \[1346].
+\:\9{close\_in\_}{\.{\\closein} primitive}, \[1285].
+\:\\{close\_noad}, \[693], 701, 707, 709, 739, 772, 773, 1168, 1169.
+\:\\{close\_node}, \[1354], 1357, 1359, 1361, 1369, 1370, 1371, 1386, 1387,
+1388.
+\:\9{close\_out\_}{\.{\\closeout} primitive}, \[1357].
+\:\\{closed}, \[491], 492, 494, 496, 497, 512, 1288.
+\:\\{clr}, \[748], \[754], 756, 757, \[767], 768, 769, 770.
+\:\\{club\_penalty}, \[242], 901.
+\:\9{club\_penalty\_}{\.{\\clubpenalty} primitive}, \[244].
+\:\\{club\_penalty\_code}, \[242], 243, 244.
+\:\.{cm}, 469.
+\:\\{cmd}, \[304], 1234, 1302.
+\:\\{co\_backup}, \[377].
+\:\\{combine\_two\_deltas}, \[871].
+\:\\{comment}, \[213], 238, 353.
+\:\\{common\_ending}, \[15], 509, 511, 520, 660, 671, 677, 678, 679, 685, 688,
+689, 906, 914, 1270, 1273, 1306, 1307, 1310, 1429.
+\:\.{Completed box...}, 649.
+\:\\{compress\_trie}, \[960], 963.
+\:\\{cond\_math\_glue}, \[155], 195, 743, 1183.
+\:\\{cond\_ptr}, \[500], 501, 506, 507, 508, 509, 511, 520, 1348.
+\:\\{conditional}, 377, 378, \[509].
+\:\\{confusion}, \[96], 139, 140, 141, 142, 208, 212, 287, 508, 641, 680, 739,
+747, 765, 772, 777, 802, 809, 811, 852, 853, 877, 881, 882, 888, 979, 984,
+1011, 1080, 1197, 1212, 1223, 1361, 1370, 1371, 1386, 1441, 1448, 1465.
+\:\\{const\_chk}, \[1345].
+\:\\{const\_cstring}, 33, 545.
+\:\\{conststringcast}, 62, 547, 1383.
+\:\\{continental\_point\_token}, \[449], 459.
+\:\\{continue}, \[15], 83, 84, 85, 89, 90, 400, 403, 404, 405, 406, 408, 630,
+631, 717, 719, 785, 795, 826, 840, 843, 862, 907, 917, 920, 921, 922, 1005,
+1012, 1411.
+\:\\{contrib\_head}, \[168], 221, 224, 999, 1005, 1006, 1009, 1010, 1012, 1028,
+1034, 1037, 1321.
+\:\\{contrib\_tail}, \[1006], 1028, 1034, 1037.
+\:\\{contribute}, \[1005], 1008, 1011, 1013, 1019, 1377.
+\:\\{conv\_toks}, 377, 378, \[481].
+\:{conventions for representing stacks}, 306.
+\:\\{convert}, \[216], 374, 378, 479, 480, 481.
+\:\\{convert\_to\_break\_width}, \[854].
+\:\9{copy\_}{\.{\\copy} primitive}, \[1083].
+\:\\{copy\_code}, \[1083], 1084, 1091, 1119, 1120, 1122.
+\:\\{copy\_node\_list}, 167, 209, \[210], 212, 1091, 1122.
+\:\\{copy\_to\_cur\_active}, \[840], 872.
+\:\\{count}, \[242], 438, 649, 651, 997, 1019, 1020, 1021.
+\:\9{count\_}{\.{\\count} primitive}, \[422].
+\:\\{count\_base}, \[242], 245, 248, 1236, 1250.
+\:\9{count\_def\_}{\.{\\countdef} primitive}, \[1234].
+\:\\{count\_def\_code}, \[1234], 1235, 1236.
+\:\9{cr\_}{\.{\\cr} primitive}, \[791].
+\:\\{cr\_code}, \[791], 792, 800, 802, 803.
+\:\9{cr\_cr\_}{\.{\\crcr} primitive}, \[791].
+\:\\{cr\_cr\_code}, \[791], 796, 800.
+\:\\{cramped}, \[699], 713.
+\:\\{cramped\_style}, \[713], 745, 748, 749.
+\:\\{cs\_count}, \[262], 264, 266, 1331, 1332, 1347.
+\:\\{cs\_error}, 1146, \[1147].
+\:\\{cs\_name}, \[216], 271, 272, 374, 378.
+\:\9{cs\_name\_}{\.{\\csname} primitive}, \[271].
+\:\\{cs\_token\_flag}, \[295], 296, 299, 340, 342, 343, 345, 365, 366, 373,
+380, 383, 386, 390, 391, 392, 453, 477, 517, 791, 1077, 1144, 1227, 1302, 1327,
+1384, 1475.
+\:\\{cstring}, 531.
+\:\\{ctype\_base}, \[561], 565, 577, 580, 587, 1335, 1336, 1350.
+\:\\{cur\_active\_width}, \[834], 835, 840, 843, 848, 854, 855, 862, 863, 864,
+871.
+\:\\{cur\_align}, \[781], 782, 783, 788, 789, 790, 794, 797, 799, 800, 802,
+803, 806, 807, 809.
+\:\\{cur\_area}, \[523], 528, 536, 540, 541, 1270, 1273, 1364, 1387.
+\:\\{cur\_boundary}, 276, \[277], 278, 280, 288.
+\:\\{cur\_box}, \[1086], 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1096,
+1098, 1099.
+\:\\{cur\_break}, \[832], 856, 890, 891, 892.
+\:\\{cur\_c}, 733, 734, \[735], 749, 760, 763, 764, 766.
+\:\\{cur\_chr}, 89, 302, \[303], 305, 338, 343, 347, 349, 356, 357, 359, 360,
+361, 362, 363, 364, 365, 366, 367, 368, 372, 373, 389, 391, 392, 397, 398, 400,
+414, 418, 424, 435, 439, 453, 481, 483, 485, 487, 490, 494, 505, 506, 509, 511,
+517, 518, 519, 520, 521, 537, 588, 793, 796, 800, 946, 948, 973, 1041, 1045,
+1047, 1049, 1061, 1070, 1072, 1073, 1078, 1085, 1091, 1095, 1102, 1105, 1117,
+1118, 1122, 1129, 1136, 1140, 1152, 1154, 1163, 1164, 1166, 1167, 1170, 1171,
+1172, 1183, 1193, 1203, 1223, 1224, 1225, 1229, 1230, 1233, 1236, 1238, 1239,
+1240, 1244, 1245, 1246, 1247, 1250, 1256, 1258, 1259, 1260, 1265, 1266, 1278,
+1288, 1292, 1301, 1306, 1348, 1361, 1363, 1388, 1423, 1428, 1436, 1441, 1444,
+1469.
+\:\\{cur\_cmd}, 89, 217, 302, \[303], 305, 338, 343, 347, 348, 349, 350, 356,
+357, 359, 361, 362, 365, 366, 368, 372, 373, 377, 378, 379, 383, 391, 392, 397,
+398, 414, 415, 417, 418, 424, 426, 439, 451, 453, 454, 455, 459, 463, 466, 472,
+474, 482, 485, 487, 488, 489, 490, 494, 505, 517, 518, 537, 588, 788, 793, 794,
+795, 796, 799, 800, 946, 972, 1040, 1041, 1049, 1061, 1078, 1085, 1090, 1091,
+1096, 1107, 1111, 1136, 1140, 1150, 1163, 1164, 1172, 1177, 1188, 1189, 1209,
+1218, 1223, 1224, 1225, 1233, 1238, 1239, 1240, 1249, 1250, 1265, 1283, 1388,
+1469.
+\:\\{cur\_cs}, \[303], 338, 339, 342, 343, 344, 347, 359, 361, 362, 364, 365,
+366, 373, 383, 385, 390, 391, 392, 400, 402, 418, 483, 484, 518, 785, 1164,
+1227, 1230, 1233, 1236, 1237, 1238, 1270, 1307, 1365, 1384.
+\:\\{cur\_dir\_hv}, 628, 634, 639, 643, 648, \[1446], 1448, 1465.
+\:\\{cur\_ext}, \[523], 528, 536, 540, 541, 1364, 1387.
+\:\\{cur\_f}, 733, \[735], 749, 752, 760, 763, 764, 766.
+\:\\{cur\_fam}, \[242], 1163, 1167, 1177.
+\:\\{cur\_fam\_code}, \[242], 243, 244, 1151, 1157, 1240.
+\:\\{cur\_file}, \[310], 335, 370, 548, 549.
+\:\\{cur\_font}, \[236], 238, 569, 570, 588, 1043, 1045, 1054, 1056, 1129,
+1135, 1136, 1158.
+\:\\{cur\_font\_loc}, \[236], 238, 239, 240, 1229.
+\:\\{cur\_g}, \[630], 636, \[640], 645.
+\:\\{cur\_glue}, \[630], 636, \[640], 645.
+\:\\{cur\_group}, 276, \[277], 278, 280, 287, 288, 811, 1074, 1075, 1076, 1077,
+1079, 1080, 1081, 1085, 1142, 1143, 1152, 1154, 1203, 1204, 1205, 1206, 1212.
+\:\\{cur\_h}, \[627], 628, 629, 630, 631, 633, 634, 637, 638, 639, 640, 643,
+648, 1413, 1448, 1465.
+\:\\{cur\_head}, \[781], 782, 783, 797, 810.
+\:\\{cur\_height}, \[981], 983, 984, 985, 986, 987.
+\:\\{cur\_i}, 733, 734, \[735], 749, 752, 760, 763, 764, 766.
+\:\\{cur\_if}, 342, \[500], 501, 506, 507, 1348.
+\:\\{cur\_indent}, \[888], 900.
+\:\\{cur\_input}, 36, 37, 88, \[307], 308, 317, 325, 327, 328, 545, 1143.
+\:\\{cur\_jfam}, \[242], 1163, 1468.
+\:\9{cur\_jfam\_}{\.{\\jfam} primitive}, \[244].
+\:\\{cur\_jfam\_code}, \[242], 243, 244, 1240.
+\:\\{cur\_jfont}, \[236], 238, 588, 1135, 1136, 1418, 1419, 1469.
+\:\\{cur\_jfont\_loc}, \[236], 238, 1229.
+\:\\{cur\_kanji\_skip}, \[658], 659, 660, 807, 810, 815, 827, 848, 878, 1098,
+1137, 1206.
+\:\\{cur\_l}, \[918], 919, 920, 921, 922, 1043, 1045, 1046, 1047, 1048, 1050,
+1051, 1052, 1469, 1472.
+\:\\{cur\_lang}, 902, \[903], 934, 935, 941, 945, 950, 955, 974, 1103, 1212,
+1375.
+\:\\{cur\_length}, \[42], 186, 188, 266, 527, 536, 628, 703, 1381, 1383.
+\:\\{cur\_level}, 276, \[277], 278, 280, 283, 284, 286, 287, 1317, 1348.
+\:\\{cur\_line}, \[888], 900, 901.
+\:\\{cur\_list}, \[219], 222, 223, 224, 433, 1257.
+\:\\{cur\_loop}, \[781], 782, 783, 788, 794, 803, 804, 805.
+\:\\{cur\_mark}, 302, \[393], 397, 1348.
+\:\\{cur\_mlist}, \[730], 731, 737, 765, 1206, 1208, 1211.
+\:\\{cur\_mu}, 714, \[730], 741, 743, 777.
+\:\\{cur\_name}, \[523], 528, 536, 540, 541, 548, 1270, 1271, 1273, 1364, 1387.
+\:\\{cur\_order}, 377, 450, \[458], 459, 465, 473.
+\:\\{cur\_p}, 834, \[839], 840, 841, 844, 848, 850, 851, 856, 862, 864, 866,
+867, 868, 869, 870, 871, 873, 874, 876, 877, 878, 879, 880, 883, 888, 889, 890,
+891, 892, 905, 914, 1375.
+\:\\{cur\_pos}, \[1430], 1437, 1442, 1443, 1444, 1445, 1459, 1460.
+\:\\{cur\_q}, \[918], 919, 921, 922, 1045, 1046, 1047, 1048, 1052, 1443, 1472.
+\:\\{cur\_r}, \[918], 919, 920, 921, 922, 1043, 1045, 1048, 1049, 1050, 1051,
+1052, 1469, 1472.
+\:\\{cur\_rh}, \[917], 919, 920, 921.
+\:\\{cur\_s}, 604, 609, 610, \[627], 630, 640, 651, 653.
+\:\\{cur\_size}, 711, 712, 714, \[730], 733, 734, 743, 747, 748, 755, 757, 758,
+759, 760, 763, 768, 769, 770, 773, 1163, 1167, 1468.
+\:\\{cur\_span}, \[781], 782, 783, 798, 807, 809.
+\:\\{cur\_style}, 714, \[730], 731, 737, 741, 742, 745, 746, 748, 749, 753,
+755, 756, 757, 759, 760, 761, 765, 767, 768, 769, 770, 771, 774, 777, 1206,
+1208, 1211.
+\:\\{cur\_tail}, \[781], 782, 783, 797, 807, 810.
+\:\\{cur\_tfont}, \[236], 238, 588, 1135, 1136, 1418, 1419, 1469.
+\:\\{cur\_tfont\_loc}, \[236], 238, 1229.
+\:\\{cur\_tok}, 89, 287, \[303], 331, 332, 333, 342, 372, 373, 377, 379, 380,
+383, 386, 390, 391, 392, 403, 404, 405, 406, 408, 410, 414, 416, 418, 451, 452,
+453, 455, 456, 459, 463, 482, 485, 487, 488, 490, 494, 505, 514, 517, 794, 795,
+1049, 1059, 1107, 1139, 1140, 1144, 1227, 1233, 1281, 1282, 1284, 1384, 1385.
+\:\\{cur\_v}, \[627], 629, 630, 633, 634, 635, 639, 640, 642, 643, 644, 646,
+647, 648, 651, 1413, 1448, 1465.
+\:\\{cur\_val}, 270, 271, 340, 377, \[421], 424, 425, 426, 430, 431, 432, 434,
+435, 436, 437, 438, 440, 441, 442, 444, 445, 446, 447, 448, 449, 450, 451, 453,
+455, 456, 458, 459, 461, 462, 464, 466, 468, 469, 471, 472, 473, 474, 476, 477,
+483, 493, 502, 512, 514, 515, 516, 520, 564, 588, 589, 590, 591, 656, 791, 793,
+946, 1041, 1049, 1072, 1073, 1085, 1091, 1094, 1111, 1115, 1122, 1135, 1136,
+1163, 1166, 1172, 1173, 1177, 1194, 1200, 1236, 1237, 1238, 1239, 1240, 1241,
+1244, 1247, 1249, 1250, 1251, 1252, 1253, 1254, 1256, 1257, 1258, 1259, 1260,
+1261, 1266, 1271, 1272, 1288, 1309, 1357, 1363, 1390, 1399, 1423, 1436, 1437,
+1441, 1442, 1469.
+\:\\{cur\_val\_level}, 377, \[421], 424, 430, 431, 432, 434, 435, 438, 440,
+441, 450, 460, 462, 466, 472, 476, 477, 1437, 1442.
+\:\\{cur\_width}, \[888], 900.
+\:\\{cur\_xkanji\_skip}, \[658], 659, 660, 807, 810, 815, 827, 1098, 1137, 1206.
+\:{current page}, 991.
+\:\\{current\_character\_being\_worked\_on}, \[581].
+\:\\{cv\_backup}, \[377].
+\:\\{cvl\_backup}, \[377].
+\:\\{cx}, \[481], 482, 483, \[571], 580, \[702], \[1041], 1050, \[1135], 1136,
+1163, 1166, \[1425], 1443, 1445, 1451, 1452, 1454, 1455, 1458, 1459, 1460,
+1464, 1469.
+\:\|{d}, \[108], \[182], \[183], \[265], \[347], \[451], \[571], \[660], %
+\[679], \[690], \[717], \[841], \[955], \[981], \[1080], \[1098], \[1125], %
+\[1150], \[1210], \[1383], \[1467].
+\:\\{d\_fixed}, \[619], 620.
+\:\\{danger}, \[1206], 1207, 1211.
+\:\\{data}, \[216], 238, 1229, 1236, 1244, 1247, 1428.
+\:{data structure assumptions}, \[167], 170, 210, 827, 979, 992, 1302.
+\:\\{date\_and\_time}, 247.
+\:\\{day}, \[242], 247, 547, 628, 1341.
+\:\9{day\_}{\.{\\day} primitive}, \[244].
+\:\\{day\_code}, \[242], 243, 244.
+\:\.{dd}, 469.
+\:\\{deactivate}, \[840], 862, 865.
+\:\\{dead\_cycles}, 430, \[603], 604, 649, 1023, 1035, 1036, 1066, 1255, 1259.
+\:\9{dead\_cycles\_}{\.{\\deadcycles} primitive}, \[427].
+\:\&{debug}, \[7], \[9], \[79], \[85], \[94], \[115], \[171], \[172], \[173], %
+\[178], \[1042], \[1351], \[1397], \[1440].
+\:\.{debug \#}, 1351.
+\:\\{debug\_format\_file}, 1319, 1332, \[1396], 1397.
+\:\\{debug\_help}, 79, 85, 94, \[1351].
+\:{debugging}, 7, 85, 97, 115, 171, 188, 1042, 1351.
+\:\\{decent\_fit}, \[828], 845, 863, 864, 875.
+\:\\{decr}, 43, 45, 65, 72, 87, 89, 90, 91, 93, 103, 121, 122, 124, 181, 183,
+206, 207, 211, 223, 251, 266, 287, 288, 317, 328, 330, 331, 335, 337, 353, 364,
+365, 368, 370, 377, 405, 410, 433, 440, 453, 488, 494, 505, 520, 528, 545, 549,
+579, 587, 612, 630, 640, 649, 653, 654, 727, 728, 814, 819, 851, 869, 880, 894,
+926, 927, 941, 942, 951, 952, 955, 959, 976, 1072, 1112, 1132, 1139, 1143,
+1186, 1198, 1206, 1257, 1306, 1324, 1348, 1350, 1398, 1402, 1425.
+\:\\{def}, \[215], 1220, 1221, 1222, 1225, 1230.
+\:\9{def\_}{\.{\\def} primitive}, \[1220].
+\:\\{def\_code}, \[215], 424, 1222, 1242, 1243, 1244.
+\:\\{def\_family}, \[215], 424, 588, 1222, 1242, 1243, 1247.
+\:\\{def\_font}, \[215], 271, 272, 424, 588, 1222, 1269.
+\:\\{def\_jfont}, \[215], 271, 272, 424, 588, 1222, 1269.
+\:\\{def\_ref}, \[311], 312, 484, 493, 971, 1113, 1230, 1238, 1292, 1301, 1365,
+1367, 1383, 1475.
+\:\\{def\_tfont}, \[215], 271, 272, 424, 588, 1222, 1269.
+\:\\{default\_code}, \[694], 708, 754, 1194.
+\:\\{default\_hyphen\_char}, \[242], 587.
+\:\9{default\_hyphen\_char\_}{\.{\\defaulthyphenchar} primitive}, \[244].
+\:\\{default\_hyphen\_char\_code}, \[242], 243, 244.
+\:\\{default\_rule}, \[474].
+\:\\{default\_rule\_thickness}, 694, \[712], 745, 746, 748, 754, 756, 770.
+\:\\{default\_skew\_char}, \[242], 587.
+\:\9{default\_skew\_char\_}{\.{\\defaultskewchar} primitive}, \[244].
+\:\\{default\_skew\_char\_code}, \[242], 243, 244.
+\:{defecation}, 608.
+\:\\{define}, \[1226], 1229, 1230, 1233, 1236, 1237, 1238, 1239, 1240, 1244,
+1247, 1249, 1261, 1270, 1423, 1428, 1436, 1441.
+\:\\{defining}, \[311], 312, 345, 484, 493.
+\:\\{del\_code}, \[242], 246, 1172.
+\:\9{del\_code\_}{\.{\\delcode} primitive}, \[1242].
+\:\\{del\_code\_base}, \[242], 246, 248, 1242, 1244, 1246.
+\:\\{del\_node}, \[649].
+\:\\{delete\_glue\_ref}, \[207], 208, 281, 431, 462, 476, 589, 649, 726, 737,
+738, 743, 762, 767, 807, 810, 813, 815, 827, 837, 892, 987, 988, 989, 1004,
+1007, 1015, 1028, 1032, 1033, 1088, 1090, 1098, 1112, 1122, 1137, 1206, 1213,
+1241, 1249, 1252, 1348, 1451.
+\:\\{delete\_last}, 1116, \[1117].
+\:\\{delete\_q}, \[737], 771, 774.
+\:\\{delete\_token\_ref}, \[206], 208, 281, 330, 988, 990, 1023, 1027, 1348,
+1371.
+\:\\{deletions\_allowed}, \[77], 78, 85, 86, 99, 342, 352.
+\:\\{delim\_num}, \[213], 271, 272, 1058, 1163, 1166, 1172.
+\:\\{delimited\_code}, \[1190], 1191, 1194, 1195.
+\:\\{delimiter}, \[698], 707, 773, 1203.
+\:\9{delimiter\_}{\.{\\delimiter} primitive}, \[271].
+\:\\{delimiter\_factor}, \[242], 773.
+\:\9{delimiter\_factor\_}{\.{\\delimiterfactor} primitive}, \[244].
+\:\\{delimiter\_factor\_code}, \[242], 243, 244.
+\:\\{delimiter\_shortfall}, \[253], 773.
+\:\9{delimiter\_shortfall\_}{\.{\\delimitershortfall} primitive}, \[254].
+\:\\{delimiter\_shortfall\_code}, \[253], 254.
+\:\\{delim1}, \[711], 759.
+\:\\{delim2}, \[711], 759.
+\:\\{delta}, \[104], \[737], 739, 744, \[746], \[747], \[748], \[749], 753, %
+\[754], 756, 757, 758, 759, \[760], 761, 765, 766, \[767], 770, \[773], %
+\[1005], 1019, 1021, \[1135], 1137, \[1410], 1413.
+\:\\{delta\_node}, \[833], 841, 843, 854, 855, 871, 872, 876, 885, 886.
+\:\\{delta\_node\_size}, \[833], 854, 855, 871, 872, 876.
+\:\\{delta1}, \[754], 757, \[773].
+\:\\{delta2}, \[754], 757, \[773].
+\:\\{den}, 596, \[598], 601.
+\:\\{denom}, \[461], 469.
+\:\\{denom\_style}, \[713], 755.
+\:\\{denominator}, \[694], 701, 708, 709, 755, 1193, 1197.
+\:\\{denom1}, \[711], 755.
+\:\\{denom2}, \[711], 755.
+\:\\{deplorable}, \[985], 1016.
+\:\.{depth}, 474.
+\:\\{depth}, \[136], 137, 140, 141, 142, 143, 144, 145, 190, 193, 194, 474,
+565, 633, 635, 637, 642, 643, 646, 652, 660, 664, 667, 679, 681, 690, 699, 715,
+717, 720, 724, 738, 741, 742, 746, 747, 748, 756, 757, 758, 760, 761, 762, 767,
+769, 770, 779, 780, 812, 817, 821, 984, 1013, 1020, 1021, 1032, 1099, 1112,
+1465.
+\:\\{depth\_base}, \[561], 565, 577, 582, 1335, 1336, 1350.
+\:\\{depth\_index}, \[554], 565.
+\:\\{depth\_offset}, \[136], 427, 780, 1260.
+\:\\{depth\_threshold}, \[187], 188, 204, 239, 242, 703, 1352.
+\:\\{dig}, \[55], 65, 66, 68, 103, 463, 1425.
+\:\\{digit\_sensed}, \[971], 972, 973.
+\:\\{dimen}, \[253], 438, 1019, 1021.
+\:\9{dimen\_}{\.{\\dimen} primitive}, \[422].
+\:\\{dimen\_base}, 226, \[242], 253, 254, 255, 256, 257, 258, 1082, 1157.
+\:\9{dimen\_def\_}{\.{\\dimendef} primitive}, \[1234].
+\:\\{dimen\_def\_code}, \[1234], 1235, 1236.
+\:\\{dimen\_par}, \[253].
+\:\\{dimen\_pars}, \[253].
+\:\\{dimen\_val}, \[421], 422, 423, 424, 426, 427, 428, 429, 431, 432, 435,
+436, 438, 439, 440, 460, 466, 476, 1250.
+\:\.{Dimension too large}, 471.
+\:\\{dir}, 139, 140, 141, 142, \[1467].
+\:\\{dir\_default}, \[136], 180, 182, 189, 190, 571, 576, 577, 580, 584, 585,
+631, 665, 726, 732, 733, 766, 852, 853, 878, 881, 882, 907, 1093, 1137, 1159,
+1163, 1167, 1240, 1350, 1450, 1451, 1452, 1454, 1455, 1458, 1463, 1464, 1468.
+\:\\{dir\_dtou}, \[136], 139, 140, 141, 512, 516, 1083, 1084, 1448, 1465, 1467.
+\:\\{dir\_field}, \[218], 219, 224.
+\:\\{dir\_node}, \[139], 181, 189, 190, 208, 212, 516, 633, 634, 639, 642, 643,
+648, 649, 651, 662, 680, 731, 747, 852, 853, 877, 878, 881, 882, 979, 984, 988,
+989, 1004, 1011, 1090, 1092, 1093, 1122, 1159.
+\:\\{dir\_out}, 634, 639, 643, 648, 651, \[1465].
+\:\\{dir\_tate}, \[136], 139, 140, 142, 512, 516, 571, 576, 1045, 1083, 1084,
+1135, 1136, 1208, 1229, 1418, 1419, 1448, 1465, 1467, 1469.
+\:\\{dir\_used}, \[603], 604, 653, 1448.
+\:\\{dir\_yoko}, \[136], 139, 141, 142, 218, 221, 512, 516, 576, 628, 649,
+1083, 1084, 1136, 1229, 1447, 1448, 1465, 1467, 1469.
+\:\\{dirchg}, \[597], 1448.
+\:\\{direction}, \[219], 221, 431, 512, 818, 820, 821, 822, 1045, 1085, 1088,
+1090, 1093, 1095, 1098, 1103, 1111, 1112, 1122, 1135, 1136, 1150, 1180, 1208,
+1212, 1260, 1418, 1419, 1469.
+\:{dirty \PASCAL}, \[3], 115, 178, 188, 192, 291, 823, 1344.
+\:\\{disc\_break}, \[888], 891, 892, 893, 901.
+\:\\{disc\_group}, \[275], 1129, 1130, 1131.
+\:\\{disc\_node}, \[151], 154, 181, 189, 208, 212, 741, 772, 828, 830, 840,
+867, 869, 877, 878, 892, 925, 1092.
+\:\\{disc\_width}, \[850], 851, 880, 881.
+\:\\{discretionary}, \[214], 1102, 1126, 1127, 1128.
+\:\.{Discretionary list is too long}, 1132.
+\:\9{discretionary\_}{\.{\\discretionary} primitive}, \[1126].
+\:\\{disp}, \[630], 633, 634, 635, 639, \[660], 662, 664, 665, \[1041], 1045, %
+\[1091], 1092, \[1117], \[1122], \[1135], 1136, \[1206], 1208, 1469, 1470, 1471.
+\:\\{disp\_dimen}, \[146], 189, 633, 662, 898, 1092, 1122, 1132, 1470, 1471.
+\:\\{disp\_node}, \[146], 189, 208, 212, 219, 435, 633, 662, 741, 772, 827,
+852, 853, 877, 881, 882, 898, 907, 910, 1053, 1055, 1073, 1091, 1092, 1112,
+1113, 1115, 1117, 1122, 1125, 1132, 1133, 1450, 1451, 1464, 1469, 1470, 1471.
+\:\.{Display math...with \$\$}, 1209.
+\:\\{display\_indent}, \[253], 811, 1150, 1157, 1211.
+\:\9{display\_indent\_}{\.{\\displayindent} primitive}, \[254].
+\:\\{display\_indent\_code}, \[253], 254, 1157.
+\:\9{display\_limits\_}{\.{\\displaylimits} primitive}, \[1168].
+\:\\{display\_mlist}, \[700], 706, 709, 742, 1186.
+\:\\{display\_style}, \[699], 705, 742, 1181, 1211.
+\:\9{display\_style\_}{\.{\\displaystyle} primitive}, \[1181].
+\:\\{display\_widow\_penalty}, \[242], 1157.
+\:\9{display\_widow\_penalty\_}{\.{\\displaywidowpenalty} primitive}, \[244].
+\:\\{display\_widow\_penalty\_code}, \[242], 243, 244.
+\:\\{display\_width}, \[253], 1150, 1157, 1211.
+\:\9{display\_width\_}{\.{\\displaywidth} primitive}, \[254].
+\:\\{display\_width\_code}, \[253], 254, 1157.
+\:\&{div}, \[101], \[638], \[647].
+\:\\{divide}, \[215], 271, 272, 1222, 1248, 1249.
+\:\9{divide\_}{\.{\\divide} primitive}, \[271].
+\:\\{do\_all\_six}, \[834], 840, 843, 848, 854, 855, 871, 872, 875, 981, 998.
+\:\\{do\_assignments}, 811, 1135, 1218, \[1283].
+\:\\{do\_endv}, 1142, \[1143].
+\:\\{do\_extension}, 1360, \[1361], 1388.
+\:\\{do\_final\_end}, \[82], 1345.
+\:\\{do\_ins}, 1451, 1459, 1460.
+\:\\{do\_nothing}, \[16], 35, 58, 59, 85, 181, 208, 281, 350, 365, 549, 580,
+620, 622, 623, 633, 642, 662, 680, 703, 739, 744, 772, 848, 852, 853, 877, 878,
+881, 882, 910, 1057, 1249, 1372, 1373, 1386, 1450, 1451, 1464.
+\:\\{do\_register\_command}, 1248, \[1249].
+\:\\{doing\_leaders}, \[603], 604, 639, 648, 1387.
+\:\\{done}, \[15], 48, 54, 208, 287, 288, 317, 391, 400, 408, 451, 456, 459,
+464, 469, 484, 485, 487, 493, 494, 505, 537, 541, 542, 548, 571, 578, 587, 626,
+649, 651, 652, 709, 737, 749, 751, 771, 772, 785, 788, 826, 840, 848, 874, 884,
+888, 892, 906, 917, 920, 922, 942, 971, 972, 981, 985, 988, 990, 1005, 1008,
+1009, 1016, 1091, 1092, 1093, 1131, 1133, 1150, 1158, 1223, 1239, 1265, 1371,
+1435, 1440, 1450.
+\:\\{done\_with\_noad}, \[737], 738, 739, 744, 765.
+\:\\{done\_with\_node}, \[737], 738, 741, 742, 765.
+\:\\{done1}, \[15], 173, 174, 317, 325, 400, 410, 459, 463, 484, 485, 749, 752,
+785, 794, 826, 840, 863, 888, 890, 905, 907, 910, 971, 976, 1005, 1008, 1011,
+1315, 1328, 1435, 1440.
+\:\\{done2}, \[15], 173, 175, 459, 469, 470, 484, 489, 785, 795, 826, 907,
+1315, 1329.
+\:\\{done3}, \[15], 826, 908, 909.
+\:\\{done4}, \[15], 826, 910.
+\:\\{done5}, \[15], 826, 877, 880.
+\:\\{done6}, \[15].
+\:\\{dont\_expand}, \[216], 264, 365, 380.
+\:\.{Double subscript}, 1189.
+\:\.{Double superscript}, 1189.
+\:\\{double\_hyphen\_demerits}, \[242], 870.
+\:\9{double\_hyphen\_demerits\_}{\.{\\doublehyphendemerits} primitive}, \[244].
+\:\\{double\_hyphen\_demerits\_code}, \[242], 243, 244.
+\:\.{Doubly free location...}, 175.
+\:\\{down\_ptr}, \[616], 617, 618, 626.
+\:\\{downdate\_width}, \[871].
+\:\\{down1}, 596, \[597], 618, 620, 621, 624, 625, 627.
+\:\\{down2}, \[596], 605, 621.
+\:\\{down3}, \[596], 621.
+\:\\{down4}, \[596], 621.
+\:\9{dp\_}{\.{\\dp} primitive}, \[427].
+\:{dry rot}, 96.
+\:\9{dtou\_}{\.{\\dtou} primitive}, \[1083].
+\:\\{dummy\_xchr}, \[1316], 1401.
+\:\\{dummy\_xord}, \[1316], 1401.
+\:\\{dummy\_xprn}, \[1316], 1401.
+\:\9{dump\_}{\.{\\dump...only by INITEX}}, 1348.
+\:\9{dump\_}{\.{\\dump} primitive}, \[1064].
+\:\\{dump\_core}, 1351.
+\:\\{dump\_four\_ASCII}, \[1322].
+\:\\{dump\_hh}, 1331.
+\:\\{dump\_int}, 1320, 1322, 1324, 1326, 1328, 1329, 1331, 1333, 1337, 1339,
+1414.
+\:\\{dump\_line}, \[33], 1350.
+\:\\{dump\_option}, \[33].
+\:\\{dump\_qqqq}, 1322.
+\:\\{dump\_things}, 1320, 1322, 1324, 1328, 1329, 1331, 1333, 1335, 1337, 1400.
+\:\.{Duplicate pattern}, 974.
+\:\.{dvi length exceeds...}, 609, 610, 651.
+\:\\{dvi\_buf}, 605, \[606], 608, 609, 618, 624, 625, 1345.
+\:\\{dvi\_buf\_size}, 14, \[33], 605, 606, 607, 609, 610, 618, 624, 625, 651,
+653, 1345.
+\:\\{dvi\_dir}, 628, 630, 634, 639, 640, 643, 648, \[1446], 1448.
+\:\\{dvi\_dtou}, \[1446], 1448.
+\:\\{dvi\_f}, \[627], 628, 631, 632.
+\:\\{dvi\_file}, \[543], 603, 606, 608, 609, 653.
+\:\9{DVI\_files}{\.{DVI} files}, 594.
+\:\\{dvi\_font\_def}, \[613], 632, 654.
+\:\\{dvi\_four}, \[611], 613, 621, 628, 635, 644, 651, 653, 1381.
+\:\\{dvi\_gone}, 605, \[606], 607, 609, 623, 651.
+\:\\{dvi\_h}, \[627], 628, 630, 631, 634, 635, 639, 640, 643, 648, 1413, 1448.
+\:\\{dvi\_index}, \[605].
+\:\\{dvi\_limit}, 605, \[606], 607, 609, 610, 651.
+\:\\{dvi\_offset}, 605, \[606], 607, 609, 610, 612, 616, 618, 624, 625, 630,
+640, 651, 653.
+\:\\{dvi\_out}, \[609], 611, 612, 613, 614, 620, 621, 628, 630, 631, 632, 635,
+640, 644, 651, 653, 1381, 1413, 1448.
+\:\\{dvi\_pop}, \[612], 630, 640.
+\:\\{dvi\_ptr}, 605, \[606], 607, 609, 610, 612, 618, 630, 640, 651, 653.
+\:\\{dvi\_swap}, \[609].
+\:\\{dvi\_tate}, \[1446], 1448.
+\:\\{dvi\_v}, \[627], 628, 630, 634, 639, 640, 643, 648, 1448.
+\:\\{dvi\_yoko}, \[1446], 1448.
+\:\\{dyn\_used}, \[118], 121, 122, 123, 124, 170, 650, 1324, 1325.
+\:\|{e}, \[283], \[285], \[529], \[530], \[541], \[1210], \[1223].
+\:\\{easy\_line}, 830, 846, \[858], 859, 861.
+\:\\{ec}, 551, 552, 554, 556, \[571], 576, 577, 581, 587, \[593].
+\:\9{edef\_}{\.{\\edef} primitive}, \[1220].
+\:\\{edge}, \[630], 634, 637, \[640], 646.
+\:\\{edit\_file}, \[85].
+\:\\{edit\_line}, 85, 1346, \[1392].
+\:\\{edit\_name\_length}, 85, 1346, \[1392].
+\:\\{edit\_name\_start}, 85, 1346, \[1392], 1393.
+\:\\{effective\_char}, 565, 593, 1047, \[1407], 1408.
+\:\\{effective\_char\_info}, 1047, \[1408].
+\:\\{eight\_bit\_p}, 24, \[33], 1401.
+\:\\{eight\_bits}, \[25], 65, 113, 139, 303, 560, 571, 592, 593, 606, 618, 630,
+660, 717, 720, 723, 988, 1003, 1004, 1091, 1260, 1301, 1336, 1345, 1350, 1416,
+1417, 1446, 1467.
+\:\\{eightbits}, 1407, 1408.
+\:\\{eject\_penalty}, \[163], 840, 842, 862, 870, 884, 981, 983, 985, 1016,
+1021, 1022.
+\:\&{else}, 10.
+\:\9{else\_}{\.{\\else} primitive}, \[502].
+\:\\{else\_code}, \[500], 502, 509.
+\:\.{em}, 466.
+\:\.{Emergency stop}, 94.
+\:\\{emergency\_stretch}, \[253], 839, 874.
+\:\9{emergency\_stretch\_}{\.{\\emergencystretch} primitive}, \[254].
+\:\\{emergency\_stretch\_code}, \[253], 254.
+\:\\{empty}, \[16], 221, 432, 692, 696, 698, 703, 733, 734, 749, 760, 762, 763,
+765, 766, 767, 991, 997, 998, 1002, 1012, 1019, 1136, 1188, 1189, 1198.
+\:{empty line at end of file}, 497, 549.
+\:\\{empty\_field}, \[695], 696, 697, 753, 1175, 1177, 1193.
+\:\\{empty\_flag}, \[125], 127, 131, 156, 170, 1325.
+\:\&{end}, 7, 8, 10.
+\:\.{End of file on the terminal}, 38, 72.
+\:\9{end\_}{\.{(\\end occurred...)}}, 1348.
+\:\9{end\_}{\.{\\end} primitive}, \[1064].
+\:\\{end\_cs\_name}, \[214], 271, 272, 383, 1146.
+\:\9{end\_cs\_name\_}{\.{\\endcsname} primitive}, \[271].
+\:\\{end\_diagnostic}, \[251], 290, 305, 329, 411, 412, 513, 520, 592, 649,
+652, 674, 686, 874, 998, 1003, 1017, 1022, 1133, 1236, 1311, 1407, 1411, 1412.
+\:\\{end\_file\_reading}, \[335], 336, 368, 370, 494, 548, 1348.
+\:\\{end\_graf}, 1037, 1097, 1106, \[1108], 1112, 1143, 1145, 1180.
+\:\\{end\_group}, \[214], 271, 272, 1075.
+\:\9{end\_group\_}{\.{\\endgroup} primitive}, \[271].
+\:\9{end\_input\_}{\.{\\endinput} primitive}, \[387].
+\:\\{end\_line\_char}, 88, \[242], 246, 309, 324, 338, 368, 370, 494, 545, 549,
+1350.
+\:\9{end\_line\_char\_}{\.{\\endlinechar} primitive}, \[244].
+\:\\{end\_line\_char\_code}, \[242], 243, 244.
+\:\\{end\_line\_char\_inactive}, \[368], 370, 494, 549, 1350.
+\:\\{end\_match}, \[213], 295, 297, 300, 402, 403, 405.
+\:\\{end\_match\_token}, \[295], 400, 402, 403, 404, 405, 485, 487, 493.
+\:\\{end\_name}, 523, \[528], 536, 537, 542.
+\:\\{end\_of\_TEX}, 82.
+\:\\{end\_span}, \[168], 779, 790, 804, 808, 812, 814.
+\:\\{end\_template}, \[216], 374, 377, 386, 391, 791, 1308.
+\:\\{end\_template\_token}, \[791], 795, 801.
+\:\\{end\_token\_list}, \[330], 331, 365, 401, 1037, 1348, 1384.
+\:\\{end\_write}, \[228], 1382, 1384.
+\:\9{end\_write\_}{\.{\\endwrite}}, 1382.
+\:\\{end\_write\_token}, \[1384], 1385.
+\:\&{endcases}, \[10].
+\:\\{endif}, 7, 8, 651, 653.
+\:\\{endifn}, 653.
+\:\\{endv}, \[213], 304, 386, 391, 779, 791, 793, 802, 1058, 1142, 1143.
+\:\\{engine\_name}, \[11], 1320, 1321.
+\:\\{ensure\_dvi\_open}, \[543], 628.
+\:\\{ensure\_vbox}, \[1004], 1020, 1029.
+\:\\{eof}, 26, 32, 53, 575.
+\:\\{eoln}, 32, 53.
+\:\\{eop}, 594, 596, \[597], 599, 651, 653.
+\:\\{ep}, \[1416].
+\:\\{eq\_define}, \[283], 284, 285, 383, 793, 1082, 1089, 1226.
+\:\\{eq\_destroy}, \[281], 283, 285, 289.
+\:\\{eq\_level}, \[227], 228, 234, 238, 242, 259, 270, 283, 285, 289, 791, 988,
+1321, 1328, 1382.
+\:\\{eq\_level\_field}, \[227].
+\:\\{eq\_no}, \[214], 1152, 1153, 1155, 1156.
+\:\9{eq\_no\_}{\.{\\eqno} primitive}, \[1153].
+\:\\{eq\_save}, \[282], 283, 284.
+\:\\{eq\_type}, 216, \[227], 228, 229, 234, 236, 238, 259, 264, 270, 271, 273,
+283, 285, 359, 361, 362, 365, 366, 383, 400, 402, 791, 1164, 1321, 1328, 1382.
+\:\\{eq\_type\_field}, \[227], 281.
+\:\\{eq\_word\_define}, \[284], 285, 1082, 1151, 1157, 1226.
+\:\\{eqtb}, 116, 169, 226, 227, 228, 229, 230, 234, 236, 238, 242, 246, 248,
+253, 256, 257, 258, 259, 261, 262, 268, 270, 271, 272, 273, 274, 276, 278, 280,
+281, 282, 283, 284, 285, 287, 288, 289, 290, 291, 292, 295, 297, 303, 304, 311,
+313, 338, 339, 362, 400, 424, 425, 484, 502, 559, 564, 791, 825, 1200, 1220,
+1234, 1251, 1253, 1266, 1270, 1321, 1328, 1329, 1330, 1345, 1350, 1352, 1357,
+1358.
+\:\\{eqtb\_size}, 226, \[253], 256, 258, 259, 260, 262, 266, 268, 289, 296,
+1227, 1320, 1321, 1329, 1330, 1331, 1332, 1345.
+\:\\{eqtb\_top}, 228, 258, \[262], 268, 1227, 1321, 1345.
+\:\\{equiv}, \[227], 228, 229, 230, 234, 235, 236, 238, 239, 240, 241, 259,
+261, 270, 271, 273, 281, 283, 285, 359, 361, 362, 365, 366, 424, 425, 426, 519,
+588, 791, 1164, 1239, 1252, 1253, 1270, 1302, 1321, 1328, 1382.
+\:\\{equiv\_field}, \[227], 281, 291.
+\:\\{err\_help}, 80, \[236], 1296, 1297.
+\:\9{err\_help\_}{\.{\\errhelp} primitive}, \[236].
+\:\\{err\_help\_loc}, \[236].
+\:\9{err\_message\_}{\.{\\errmessage} primitive}, \[1290].
+\:\\{err\_p}, \[1407].
+\:\\{error}, 73, 76, 77, 79, 80, \[83], 89, 92, 94, 99, 333, 344, 352, 381,
+409, 419, 429, 439, 456, 465, 467, 470, 471, 486, 487, 497, 511, 521, 534, 546,
+572, 578, 590, 652, 734, 787, 795, 803, 837, 947, 948, 971, 972, 973, 974, 987,
+989, 1003, 1015, 1020, 1035, 1038, 1062, 1076, 1078, 1080, 1081, 1085, 1092,
+1094, 1107, 1111, 1112, 1118, 1122, 1132, 1133, 1140, 1141, 1147, 1163, 1167,
+1171, 1178, 1189, 1195, 1204, 1207, 1225, 1237, 1244, 1249, 1250, 1254, 1265,
+1272, 1296, 1297, 1306, 1385, 1423, 1436, 1441, 1468.
+\:\\{error\_context\_lines}, \[242], 317.
+\:\9{error\_context\_lines\_}{\.{\\errorcontextlines} primitive}, \[244].
+\:\\{error\_context\_lines\_code}, \[242], 243, 244.
+\:\\{error\_count}, \[77], 78, 83, 87, 1108, 1306.
+\:\\{error\_line}, 14, \[33], 59, 312, 317, 321, 322, 323, 1345.
+\:\\{error\_message\_issued}, \[77], 83, 96.
+\:\\{error\_stop\_mode}, 73, \[74], 75, 83, 94, 99, 1275, 1296, 1306, 1307,
+1310, 1340, 1348.
+\:\9{error\_stop\_mode\_}{\.{\\errorstopmode} primitive}, \[1275].
+\:\\{escape}, \[213], 238, 347, 350, 1350.
+\:\\{escape\_char}, \[242], 246, 249.
+\:\9{escape\_char\_}{\.{\\escapechar} primitive}, \[244].
+\:\\{escape\_char\_code}, \[242], 243, 244.
+\:\.{etc}, 188.
+\:\.{ETC}, 298.
+\:\9{euc\_}{\.{\\euc} primitive}, \[479].
+\:\\{euc\_code}, \[479], 480, 482, 483.
+\:\\{every\_cr}, \[236], 785, 810.
+\:\9{every\_cr\_}{\.{\\everycr} primitive}, \[236].
+\:\\{every\_cr\_loc}, \[236], 237.
+\:\\{every\_cr\_text}, \[313], 320, 785, 810.
+\:\\{every\_display}, \[236], 1157.
+\:\9{every\_display\_}{\.{\\everydisplay} primitive}, \[236].
+\:\\{every\_display\_loc}, \[236], 237.
+\:\\{every\_display\_text}, \[313], 320, 1157.
+\:\\{every\_hbox}, \[236], 1095.
+\:\9{every\_hbox\_}{\.{\\everyhbox} primitive}, \[236].
+\:\\{every\_hbox\_loc}, \[236], 237.
+\:\\{every\_hbox\_text}, \[313], 320, 1095.
+\:\\{every\_job}, \[236], 1041.
+\:\9{every\_job\_}{\.{\\everyjob} primitive}, \[236].
+\:\\{every\_job\_loc}, \[236], 237.
+\:\\{every\_job\_text}, \[313], 320, 1041.
+\:\\{every\_math}, \[236], 1151.
+\:\9{every\_math\_}{\.{\\everymath} primitive}, \[236].
+\:\\{every\_math\_loc}, \[236], 237.
+\:\\{every\_math\_text}, \[313], 320, 1151.
+\:\\{every\_par}, \[236], 1103.
+\:\9{every\_par\_}{\.{\\everypar} primitive}, \[236].
+\:\\{every\_par\_loc}, \[236], 237, 313, 1238.
+\:\\{every\_par\_text}, \[313], 320, 1103.
+\:\\{every\_vbox}, \[236], 1095, 1179.
+\:\9{every\_vbox\_}{\.{\\everyvbox} primitive}, \[236].
+\:\\{every\_vbox\_loc}, \[236], 237.
+\:\\{every\_vbox\_text}, \[313], 320, 1095, 1179.
+\:\.{ex}, 466.
+\:\\{ex\_hyphen\_penalty}, 151, \[242], 880.
+\:\9{ex\_hyphen\_penalty\_}{\.{\\exhyphenpenalty} primitive}, \[244].
+\:\\{ex\_hyphen\_penalty\_code}, \[242], 243, 244.
+\:\\{ex\_id\_byte}, \[598], 653.
+\:\\{ex\_space}, \[214], 271, 272, 1041, 1102.
+\:\\{exactly}, \[655], 656, 726, 900, 988, 1028, 1074, 1213.
+\:\\{exit}, \[15], 16, 38, 48, 59, 60, 70, 83, 126, 188, 298, 347, 400, 418,
+472, 508, 509, 535, 593, 618, 626, 660, 679, 763, 802, 840, 906, 945, 955, 959,
+988, 1005, 1023, 1041, 1066, 1091, 1117, 1122, 1125, 1131, 1163, 1171, 1186,
+1223, 1249, 1283, 1316, 1348, 1351, 1403, 1408, 1451, 1463.
+\:\\{expand}, 33, 366, 375, \[377], 379, 382, 391, 392, 450, 478, 489, 509,
+521, 793.
+\:\\{expand\_after}, \[216], 271, 272, 374, 378.
+\:\9{expand\_after\_}{\.{\\expandafter} primitive}, \[271].
+\:\\{expand\_depth}, \[33], 375, 377, 1345.
+\:\\{expand\_depth\_count}, 375, 376, 377.
+\:\\{explicit}, \[161], 728, 848, 877, 879, 890, 1070, 1451.
+\:\\{ext\_bot}, \[557], 724, 725.
+\:\\{ext\_delimiter}, \[524], 526, 527, 528, 536.
+\:\\{ext\_mid}, \[557], 724, 725.
+\:\\{ext\_rep}, \[557], 724, 725.
+\:\\{ext\_tag}, \[555], 580, 719, 721.
+\:\\{ext\_top}, \[557], 724, 725.
+\:\\{exten}, \[555].
+\:\\{exten\_base}, \[561], 577, 584, 585, 587, 724, 763, 1335, 1336, 1350, 1472.
+\:\\{extensible\_recipe}, 552, \[557].
+\:\\{extension}, \[214], 1357, 1359, 1360, 1388.
+\:{extensions to \TeX}, 2, 152, 1353.
+\:\.{Extra \\else}, 521.
+\:\.{Extra \\endcsname}, 1147.
+\:\.{Extra \\fi}, 521.
+\:\.{Extra \\or}, 511, 521.
+\:\.{Extra \\right.}, 1204.
+\:\.{Extra \}, or forgotten x}, 1081.
+\:\.{Extra alignment tab...}, 803.
+\:\.{Extra x}, 1078.
+\:\\{extra\_info}, \[780], 799, 800, 802, 803.
+\:\\{extra\_mem\_bot}, \[33], 1321, 1345.
+\:\\{extra\_mem\_top}, \[33], 1321, 1345.
+\:\\{extra\_right\_brace}, 1080, \[1081].
+\:\\{extra\_space}, 558, \[569], 1056.
+\:\\{extra\_space\_code}, \[558], 569.
+\:{eyes and mouth}, 338.
+\:\|{f}, \[150], \[459], \[536], \[571], \[588], \[589], \[592], \[593], %
+\[603], \[613], \[660], \[717], \[720], \[722], \[723], \[726], \[727], \[728],
+\[749], \[841], \[873], \[1080], \[1125], \[1135], \[1150], \[1223], \[1270], %
+\[1407], \[1408], \[1416].
+\:\\{fabs}, 192.
+\:\\{false}, 32, 38, 46, 47, 48, 52, 77, 81, 89, 90, 99, 107, 108, 172, 173,
+174, 175, 244, 270, 290, 305, 317, 329, 333, 337, 342, 352, 369, 370, 373, 385,
+411, 412, 418, 436, 451, 452, 453, 456, 458, 459, 460, 466, 471, 472, 473, 476,
+496, 512, 513, 516, 518, 520, 523, 526, 527, 528, 529, 535, 536, 537, 539, 549,
+574, 592, 593, 604, 631, 662, 665, 717, 731, 733, 737, 765, 785, 802, 807, 810,
+815, 827, 837, 839, 848, 862, 865, 874, 878, 892, 914, 917, 921, 922, 962, 965,
+971, 972, 973, 974, 977, 998, 1001, 1017, 1022, 1031, 1037, 1041, 1042, 1044,
+1045, 1046, 1047, 1049, 1050, 1052, 1063, 1066, 1072, 1073, 1092, 1097, 1103,
+1113, 1167, 1179, 1188, 1193, 1194, 1195, 1203, 1204, 1206, 1211, 1236, 1238,
+1249, 1271, 1283, 1292, 1295, 1296, 1301, 1316, 1338, 1349, 1350, 1355, 1356,
+1365, 1367, 1383, 1384, 1387, 1405, 1406, 1407, 1411, 1412, 1431, 1450, 1459,
+1460, 1468, 1469, 1472.
+\:\\{false\_bchar}, \[1043], 1045, 1049.
+\:\\{fam}, \[692], 693, 694, 698, 702, 733, 734, 763, 764, 1163, 1167, 1177,
+1468.
+\:\9{fam\_}{\.{\\fam} primitive}, \[244].
+\:\\{fam\_fnt}, \[236], 711, 712, 718, 733, 763, 1163, 1167, 1207, 1240, 1468.
+\:\\{fam\_in\_range}, \[1163], 1167, 1177.
+\:\\{fast\_delete\_glue\_ref}, \[207], 208, 223, 1451.
+\:\\{fast\_get\_avail}, \[123], 382, 1045, 1049, 1469.
+\:\\{fast\_store\_new\_token}, \[382], 410, 475, 477.
+\:\.{Fatal format file error}, 1316.
+\:\\{fatal\_error}, 72, \[94], 330, 368, 495, 541, 546, 609, 610, 651, 793,
+800, 802, 1143.
+\:\\{fatal\_error\_stop}, \[77], 78, 83, 94, 1345.
+\:\\{fbyte}, \[575], 579, 582, 586.
+\:\\{fd}, \[1091], 1092, \[1117].
+\:\\{feof}, 586.
+\:{Ferguson, Michael John}, 2.
+\:\\{fetch}, \[733], 735, 749, 752, 760, 763, 766.
+\:\\{fetch\_effective\_tail}, \[1092], 1093, 1117.
+\:\\{fetch\_effective\_tail\_pTeX}, \[1092].
+\:\\{fewest\_demerits}, \[883], 885, 886.
+\:\\{fflush}, 35.
+\:\\{fget}, \[575], 576, 579, 580, 582, 586.
+\:\9{fi\_}{\.{\\fi} primitive}, \[502].
+\:\\{fi\_code}, \[500], 502, 503, 505, 509, 511, 520, 521.
+\:\\{fi\_or\_else}, \[216], 374, 378, 500, 502, 503, 505, 521.
+\:\.{fil}, 465.
+\:\\{fil}, 136, \[156], 170, 183, 465, 661, 670, 676, 1213.
+\:\\{fil\_code}, \[1070], 1071, 1072.
+\:\\{fil\_glue}, \[168], 170, 1072.
+\:\\{fil\_neg\_code}, \[1070], 1072.
+\:\\{fil\_neg\_glue}, \[168], 170, 1072.
+\:\.{File ended while scanning...}, 344.
+\:\.{File ended within \\read}, 497.
+\:\\{file\_line\_error\_style\_p}, \[33], 62, 74, 547.
+\:\\{file\_name\_size}, \[11], 26, 530, 533, 534, 536.
+\:\\{file\_offset}, \[55], 56, 58, 59, 63, 548, 649, 1293.
+\:\\{file\_opened}, \[571], 572, 574.
+\:\\{fill}, 136, \[156], 170, 661, 670, 676, 1213.
+\:\\{fill\_code}, \[1070], 1071, 1072.
+\:\\{fill\_glue}, \[168], 170, 1066, 1072.
+\:\\{filll}, 136, \[156], 183, 465, 661, 670, 676, 1213.
+\:\\{fin\_align}, 784, 796, \[811], 1143.
+\:\\{fin\_col}, 784, \[802], 1143.
+\:\\{fin\_mlist}, 1186, \[1196], 1198, 1203, 1206.
+\:\\{fin\_row}, 784, \[810], 1143.
+\:\\{fin\_rule}, \[630], 633, 637, 640, 642, 646.
+\:\\{final\_cleanup}, 1345, \[1348].
+\:\\{final\_end}, \[6], 36, 337, 1345, 1350.
+\:\\{final\_hyphen\_demerits}, \[242], 870.
+\:\9{final\_hyphen\_demerits\_}{\.{\\finalhyphendemerits} primitive}, \[244].
+\:\\{final\_hyphen\_demerits\_code}, \[242], 243, 244.
+\:\\{final\_pass}, \[839], 865, 874, 884.
+\:\\{final\_widow\_penalty}, 825, \[826], 887, \[888], 901.
+\:\\{find\_effective\_tail}, \[435].
+\:\\{find\_effective\_tail\_pTeX}, \[435].
+\:\\{find\_first\_char}, \[1449], 1450, 1453.
+\:\\{find\_font\_dimen}, 436, \[589], 1054, 1266.
+\:{fingers}, 522.
+\:\\{finite\_shrink}, 836, \[837].
+\:\\{fire\_up}, 1016, \[1023].
+\:\\{firm\_up\_the\_line}, 346, 370, \[371], 549.
+\:\\{first}, \[31], 32, 36, 37, 38, 72, 84, 88, 89, 334, 335, 337, 363, 364,
+368, 370, 371, 385, 494, 542, 549.
+\:\\{first\_char}, \[1449], 1450, 1453, 1454.
+\:\\{first\_child}, \[971], 974, 975.
+\:\\{first\_count}, \[55], 321, 322, 323.
+\:\\{first\_fit}, \[964], 968, 977.
+\:\\{first\_indent}, \[858], 860, 900.
+\:\\{first\_mark}, \[393], 394, 1023, 1027.
+\:\9{first\_mark\_}{\.{\\firstmark} primitive}, \[395].
+\:\\{first\_mark\_code}, \[393], 395, 396.
+\:\\{first\_text\_char}, \[19], 24.
+\:\\{first\_use}, 827, \[873], 878.
+\:\\{first\_width}, \[858], 860, 861, 900.
+\:\\{fit\_class}, \[841], 847, 856, 857, 863, 864, 866, 870.
+\:\\{fitness}, \[830], 856, 870, 875.
+\:\\{fix\_date\_and\_time}, \[247], 1345, 1350.
+\:\\{fix\_language}, 1045, \[1389].
+\:\\{fix\_word}, \[552], 553, 558, 559, 582.
+\:\\{flag}, \[1450].
+\:\\{float}, \[110], 115, 192, 631, 636, 645, 820.
+\:\\{float\_constant}, \[110], 192, 630, 636, 640, 1135, 1137, 1413.
+\:\\{float\_cost}, \[145], 194, 1019, 1112.
+\:\\{floating\_penalty}, 145, \[242], 1080, 1112.
+\:\9{floating\_penalty\_}{\.{\\floatingpenalty} primitive}, \[244].
+\:\\{floating\_penalty\_code}, \[242], 243, 244.
+\:\\{flush\_char}, \[43], 186, 201, 703, 706.
+\:\\{flush\_dvi}, 651.
+\:\\{flush\_list}, \[124], 206, 330, 383, 407, 418, 812, 914, 952, 971, 1292,
+1310, 1383.
+\:\\{flush\_math}, \[729], 787, 1207.
+\:\\{flush\_node\_list}, 205, \[208], 281, 649, 650, 709, 729, 742, 743, 753,
+811, 827, 890, 894, 914, 929, 979, 989, 1003, 1010, 1032, 1090, 1112, 1117,
+1122, 1132, 1133, 1388.
+\:\\{flush\_string}, \[45], 270, 528, 548, 952, 1292, 1341, 1403.
+\:\\{fmem\_ptr}, 436, \[560], 577, 587, 589, 590, 591, 1333, 1334, 1336, 1347,
+1350.
+\:\\{fmt\_file}, 535, \[1318], 1341, 1342, 1350.
+\:\\{fnt\_def1}, 596, \[597], 613.
+\:\\{fnt\_def2}, \[596].
+\:\\{fnt\_def3}, \[596].
+\:\\{fnt\_def4}, \[596].
+\:\\{fnt\_num\_0}, 596, \[597], 632.
+\:\\{fnt1}, 596, \[597], 632.
+\:\\{fnt2}, \[596].
+\:\\{fnt3}, \[596].
+\:\\{fnt4}, \[596].
+\:\\{font}, \[135], 149, 150, 180, 182, 189, 199, 212, 273, 559, 593, 631, 665,
+692, 720, 726, 732, 735, 852, 853, 877, 878, 881, 882, 907, 908, 909, 914, 919,
+922, 1045, 1049, 1125, 1137, 1159, 1450, 1451, 1452, 1454, 1455, 1458, 1463,
+1464, 1469.
+\:{font metric files}, 550.
+\:{font parameters}, 711, 712.
+\:\.{Font x has only...}, 590.
+\:\.{Font x=xx not loadable...}, 572.
+\:\.{Font x=xx not loaded...}, 578.
+\:\9{font\_}{\.{\\font} primitive}, \[271].
+\:\\{font\_area}, \[560], 587, 613, 614, 1273, 1335, 1336, 1350.
+\:\\{font\_base}, \[11], 33, 112, 135, 228, 238, 613, 632, 654, 1273, 1333,
+1334, 1347, 1350.
+\:\\{font\_bc}, \[560], 565, 587, 593, 631, 719, 733, 1047, 1335, 1336, 1350,
+1407, 1408, 1411.
+\:\\{font\_bchar}, \[560], 587, 908, 909, 926, 1043, 1045, 1335, 1336, 1350.
+\:\\{font\_check}, \[560], 579, 613, 1335, 1336, 1350.
+\:\9{font\_dimen\_}{\.{\\fontdimen} primitive}, \[271].
+\:\\{font\_dir}, 180, 182, 189, \[560], 577, 631, 665, 726, 732, 733, 766, 852,
+853, 878, 881, 882, 907, 1136, 1137, 1159, 1163, 1167, 1229, 1240, 1335, 1336,
+1350, 1450, 1451, 1452, 1454, 1455, 1458, 1463, 1464, 1468, 1469.
+\:\\{font\_dsize}, 483, \[560], 579, 613, 1273, 1274, 1335, 1336, 1350.
+\:\\{font\_ec}, \[560], 587, 593, 631, 719, 733, 1047, 1335, 1336, 1350, 1407,
+1408, 1411.
+\:\\{font\_false\_bchar}, \[560], 587, 1043, 1045, 1335, 1336, 1350.
+\:\\{font\_glue}, \[560], 587, 589, 763, 1054, 1335, 1336, 1350, 1472.
+\:\\{font\_id\_base}, \[228], 240, 262, 426, 559, 1270.
+\:\\{font\_id\_text}, 240, \[262], 273, 590, 1270, 1335.
+\:\\{font\_in\_short\_display}, \[179], 180, 199, 674, 875, 1352.
+\:\\{font\_index}, \[559], 560, 571, 917, 1043, 1223, 1336, 1350.
+\:\\{font\_info}, 33, 436, 559, \[560], 561, 565, 568, 569, 571, 577, 580, 582,
+584, 585, 586, 589, 591, 711, 712, 724, 752, 763, 920, 1043, 1051, 1054, 1223,
+1266, 1321, 1333, 1334, 1345, 1350, 1352, 1407, 1408, 1472.
+\:\\{font\_k}, \[33], 1350.
+\:\\{font\_max}, 12, \[33], 112, 180, 182, 577, 1336, 1345, 1347, 1350.
+\:\\{font\_mem\_size}, \[33], 577, 591, 1334, 1345, 1347.
+\:\\{font\_name}, 483, \[560], 587, 592, 613, 614, 1273, 1274, 1335, 1336,
+1350, 1407, 1411, 1412.
+\:\9{font\_name\_}{\.{\\fontname} primitive}, \[479].
+\:\\{font\_name\_code}, \[479], 480, 482, 483.
+\:\\{font\_num\_ext}, \[560], 577, 1335, 1336, 1350, 1416.
+\:\\{font\_params}, \[560], 587, 589, 590, 591, 1207, 1335, 1336, 1350.
+\:\\{font\_ptr}, \[560], 577, 587, 589, 654, 1273, 1333, 1334, 1335, 1336,
+1347, 1350.
+\:\\{font\_size}, 483, \[560], 579, 613, 1273, 1274, 1335, 1336, 1350.
+\:\\{font\_used}, \[560], 632, 654, 1350.
+\:\.{FONTx}, 1270.
+\:\.{for accent}, 197.
+\:\.{Forbidden control sequence...}, 344.
+\:\\{force\_eof}, 337, \[369], 370, 389.
+\:\\{format\_area\_length}, \[531].
+\:\\{format\_debug}, \[1319], 1321.
+\:\\{format\_debug\_end}, \[1319].
+\:\\{format\_default\_length}, \[531], 533, 534, 535.
+\:\\{format\_engine}, \[1315], \[1316], 1320, 1321.
+\:\\{format\_ext\_length}, \[531], 534, 535.
+\:\\{format\_extension}, \[531], 540, 1341.
+\:\\{format\_ident}, 62, 547, \[1312], 1313, 1314, 1339, 1340, 1341, 1350.
+\:\\{forward}, 79, 224, 287, 346, 377, 420, 629, 703, 704, 731, 785, 811.
+\:\\{found}, \[15], 126, 129, 130, 265, 347, 362, 364, 400, 403, 405, 459, 466,
+484, 486, 488, 535, 618, 620, 623, 624, 625, 630, 656, 717, 719, 731, 906, 934,
+942, 945, 951, 952, 964, 966, 1150, 1158, 1159, 1160, 1249, 1250, 1402, 1407,
+1409, 1411.
+\:\\{found1}, \[15], 906, 913, 1315, 1328.
+\:\\{found2}, \[15], 906, 914, 1315, 1329.
+\:\\{four\_choices}, \[114].
+\:\\{four\_quarters}, 559, 560, 565, 566, 571, 660, 694, 695, 717, 720, 723,
+735, 749, 760, 917, 1043, 1135, 1336, 1350, 1408, 1410.
+\:\\{fputs}, 62, 535, 547.
+\:\\{fraction\_noad}, \[694], 698, 701, 709, 744, 772, 1190, 1193.
+\:\\{fraction\_noad\_size}, \[694], 709, 772, 1193.
+\:\\{fraction\_rule}, \[715], 716, 746, 758.
+\:\\{free}, \[171], 173, 174, 175, 176, 177.
+\:\\{free\_arr}, 171.
+\:\\{free\_avail}, \[122], 208, 210, 325, 411, 463, 783, 926, 1047, 1238, 1301.
+\:\\{free\_node}, \[131], 207, 208, 223, 281, 431, 507, 626, 649, 666, 709,
+726, 732, 737, 738, 762, 764, 767, 771, 783, 814, 815, 827, 871, 872, 876, 914,
+921, 988, 989, 1004, 1030, 1032, 1033, 1048, 1088, 1090, 1092, 1112, 1122,
+1133, 1198, 1199, 1213, 1348, 1371, 1451, 1470.
+\:\\{freeze\_page\_specs}, \[998], 1012, 1019.
+\:\\{fromBUFF}, 349, 362, 364, 475.
+\:\\{fromDVI}, 1425.
+\:\\{fromEUC}, 483.
+\:\\{fromJIS}, 238, 483.
+\:\\{fromKUTEN}, 238, 483.
+\:\\{fromSJIS}, 483.
+\:\\{frozen\_control\_sequence}, \[228], 264, 1227, 1331, 1332.
+\:\\{frozen\_cr}, \[228], 345, 791, 1144.
+\:\\{frozen\_dont\_expand}, \[228], 264, 380.
+\:\\{frozen\_end\_group}, \[228], 271, 1077.
+\:\\{frozen\_end\_template}, \[228], 386, 791.
+\:\\{frozen\_endv}, \[228], 386, 391, 791.
+\:\\{frozen\_fi}, \[228], 342, 502.
+\:\\{frozen\_null\_font}, \[228], 564.
+\:\\{frozen\_protection}, \[228], 1227, 1228.
+\:\\{frozen\_relax}, \[228], 271, 390.
+\:\\{frozen\_right}, \[228], 1077, 1200.
+\:\\{frozen\_special}, \[228], 1357, 1475.
+\:{Fuchs, David Raymond}, 2, 594, 602.
+\:\\{full\_source\_filename\_stack}, \[310], 334, 337, 548, 1345, 1398.
+\:\9{future\_let\_}{\.{\\futurelet} primitive}, \[1231].
+\:\\{fwrite}, 608.
+\:\|{g}, \[48], \[188], \[571], \[603], \[660], \[679], \[717], \[727].
+\:\\{g\_order}, \[630], 631, 636, \[640], 645.
+\:\\{g\_sign}, \[630], 631, 636, \[640], 645.
+\:\\{garbage}, \[168], 478, 481, 971, 1195, 1204, 1292.
+\:\9{gdef\_}{\.{\\gdef} primitive}, \[1220].
+\:\\{geq\_define}, \[285], 793, 1089, 1226.
+\:\\{geq\_word\_define}, \[285], 294, 1024, 1226.
+\:\\{get}, 26, 30, 32, 496, 549, 575.
+\:\\{get\_avail}, \[121], 123, 210, 211, 325, 331, 343, 345, 380, 382, 383,
+463, 484, 493, 593, 720, 766, 783, 794, 795, 805, 919, 922, 949, 1076, 1077,
+1135, 1136, 1238, 1384, 1475.
+\:\\{get\_date\_and\_time}, 247.
+\:\\{get\_enc\_string}, 62, 547.
+\:\\{get\_inhibit\_pos}, \[1435], 1436, 1437, 1459, 1460.
+\:\\{get\_jfm\_pos}, 733, 763, 1135, 1136, \[1416], 1469.
+\:\\{get\_job\_name}, 545, 548.
+\:\\{get\_kinsoku\_pos}, \[1440], 1441, 1442, 1443, 1444, 1445.
+\:\\{get\_next}, 77, 303, 338, 342, 346, \[347], 365, 368, 372, 373, 374, 377,
+380, 391, 392, 398, 400, 489, 505, 518, 655, 1049, 1138, 1469.
+\:\\{get\_node}, \[126], 132, 137, 144, 150, 151, 153, 157, 158, 159, 162, 164,
+212, 506, 618, 660, 679, 697, 699, 700, 727, 763, 783, 809, 854, 855, 856, 875,
+898, 925, 1020, 1112, 1113, 1132, 1175, 1177, 1193, 1261, 1262, 1362, 1370,
+1470, 1471, 1472.
+\:\\{get\_nullstr}, \[1476].
+\:\\{get\_preamble\_token}, \[793], 794, 795.
+\:\\{get\_r\_token}, \[1227], 1230, 1233, 1236, 1237, 1270.
+\:\\{get\_strings\_started}, \[48], 52, 1345.
+\:\\{get\_token}, 77, 79, 89, 372, \[373], 379, 380, 403, 410, 453, 463, 482,
+484, 485, 487, 488, 490, 494, 793, 1038, 1150, 1227, 1233, 1265, 1281, 1284,
+1307, 1384, 1385.
+\:\\{get\_x\_token}, 372, 377, 383, \[391], 392, 413, 415, 417, 418, 454, 455,
+456, 463, 476, 490, 517, 537, 791, 946, 972, 1040, 1041, 1150, 1209, 1250, 1388.
+\:\\{get\_x\_token\_or\_active\_char}, \[517].
+\:\\{getc}, 575.
+\:\\{give\_err\_help}, 79, 90, 91, \[1297].
+\:\\{gk\_tag}, \[555], 763, 1472.
+\:\\{global}, \[1226], 1230, 1254.
+\:{global definitions}, 227, 285, 289.
+\:\9{global\_}{\.{\\global} primitive}, \[1220].
+\:\\{global\_defs}, \[242], 793, 1226, 1230.
+\:\9{global\_defs\_}{\.{\\globaldefs} primitive}, \[244].
+\:\\{global\_defs\_code}, \[242], 243, 244.
+\:\\{glue\_base}, 226, \[228], 230, 232, 233, 234, 235, 258, 793.
+\:\\{glue\_kern}, 555.
+\:\\{glue\_kern\_start}, \[568], 763, 1472.
+\:\\{glue\_node}, \[155], 158, 159, 181, 189, 208, 212, 435, 633, 642, 662,
+680, 741, 743, 772, 827, 828, 848, 867, 873, 877, 890, 892, 910, 914, 979, 983,
+984, 999, 1007, 1008, 1011, 1118, 1119, 1120, 1122, 1159, 1214, 1451, 1463,
+1464.
+\:\\{glue\_offset}, \[136], 165, 192.
+\:\\{glue\_ord}, \[156], 458, 630, 640, 657, 660, 679, 802.
+\:\\{glue\_order}, \[136], 137, 165, 191, 192, 630, 640, 668, 669, 675, 683,
+684, 687, 780, 807, 812, 818, 820, 821, 822, 1160.
+\:\\{glue\_par}, \[230], 777.
+\:\\{glue\_pars}, \[230].
+\:\\{glue\_ptr}, \[155], 158, 159, 181, 195, 196, 208, 212, 435, 636, 645, 667,
+682, 690, 743, 763, 797, 804, 806, 813, 814, 820, 827, 849, 879, 892, 980, 987,
+1007, 1012, 1015, 1122, 1160, 1451, 1472.
+\:\\{glue\_ratio}, 110, 111, 136, 192.
+\:\\{glue\_ref}, \[216], 234, 281, 793, 1240, 1249.
+\:\\{glue\_ref\_count}, \[156], 157, 158, 159, 160, 170, 207, 209, 234, 659,
+777, 1055, 1072.
+\:\\{glue\_set}, \[136], 137, 165, 192, 631, 636, 645, 668, 669, 675, 683, 684,
+687, 818, 820, 821, 822, 1160.
+\:\\{glue\_shrink}, \[165], 191, 807, 810, 812, 821, 822.
+\:\\{glue\_sign}, \[136], 137, 165, 191, 192, 630, 640, 668, 669, 675, 683,
+684, 687, 780, 807, 812, 818, 820, 821, 822, 1160.
+\:\\{glue\_spec\_size}, \[156], 157, 168, 170, 207, 727.
+\:\\{glue\_stretch}, \[165], 191, 807, 810, 812, 821, 822.
+\:\\{glue\_temp}, \[630], 636, \[640], 645.
+\:\\{glue\_val}, \[421], 422, 423, 424, 427, 428, 435, 438, 440, 441, 462, 472,
+476, 793, 1072, 1240, 1249, 1250, 1251, 1253.
+\:\.{goal height}, 997, 998.
+\:\&{goto}, \[36], \[82].
+\:\\{gp}, \[763], \[1041], 1472.
+\:\\{gq}, \[763], 1041, 1472.
+\:\\{gr}, 111, 115, 136.
+\:\\{group\_code}, \[275], 277, 280, 656, 1148.
+\:\&{gubed}, \[7].
+\:{Guibas, Leonidas Ioannis}, 2.
+\:\\{g1}, \[1210], 1215.
+\:\\{g2}, \[1210], 1215, 1217.
+\:\|{h}, \[210], \[265], \[660], \[679], \[749], \[940], \[945], \[955], %
+\[959], \[964], \[981], \[988], \[1005], \[1098], \[1103], \[1135].
+\:\\{h\_offset}, \[253], 628, 652.
+\:\9{h\_offset\_}{\.{\\hoffset} primitive}, \[254].
+\:\\{h\_offset\_code}, \[253], 254.
+\:\\{ha}, \[903], 907, 911, 914, 923.
+\:\\{half}, \[101], 717, 747, 748, 749, 756, 757, 760, 761, 1214.
+\:\\{half\_buf}, 605, \[606], 607, 609, 610, 651.
+\:\\{half\_error\_line}, 14, \[33], 317, 321, 322, 323, 1345.
+\:\\{halfword}, 109, 111, \[114], 116, 131, 270, 283, 285, 286, 287, 303, 304,
+306, 339, 347, 377, 400, 424, 475, 484, 560, 571, 588, 692, 731, 763, 802, 811,
+832, 840, 841, 844, 858, 883, 888, 903, 912, 917, 918, 1043, 1091, 1223, 1256,
+1279, 1301, 1336, 1345, 1350, 1451.
+\:\\{halign}, \[214], 271, 272, 1106, 1142.
+\:\9{halign\_}{\.{\\halign} primitive}, \[271].
+\:\\{halt\_on\_error\_p}, \[33], 83.
+\:\\{handle\_right\_brace}, 1079, \[1080].
+\:\\{hang\_after}, \[242], 246, 858, 860, 1082, 1161.
+\:\9{hang\_after\_}{\.{\\hangafter} primitive}, \[244].
+\:\\{hang\_after\_code}, \[242], 243, 244, 1082.
+\:\\{hang\_indent}, \[253], 858, 859, 860, 1082, 1161.
+\:\9{hang\_indent\_}{\.{\\hangindent} primitive}, \[254].
+\:\\{hang\_indent\_code}, \[253], 254, 1082.
+\:{hanging indentation}, 858.
+\:\\{hash}, 240, \[262], 265, 266, 1321, 1331, 1332, 1345.
+\:\\{hash\_base}, 11, 226, \[228], 262, 265, 268, 269, 296, 1270, 1321, 1327,
+1331, 1332, 1345.
+\:\\{hash\_brace}, \[484], 487.
+\:\\{hash\_extra}, \[262], 266, 296, 1321, 1329, 1330, 1345, 1347.
+\:\\{hash\_high}, \[262], 264, 266, 1320, 1321, 1329, 1330, 1331, 1332.
+\:\\{hash\_is\_full}, \[262], 266.
+\:\\{hash\_offset}, \[11], 296, 1321, 1345.
+\:\\{hash\_prime}, \[12], 14, 265, 267, 1320, 1321.
+\:\\{hash\_size}, 11, \[12], 14, 228, 266, 267, 1347.
+\:\\{hash\_top}, \[262], 1321, 1327, 1345.
+\:\\{hash\_used}, \[262], 264, 266, 1331, 1332, 1345.
+\:\\{hb}, \[903], 908, 909, 911, 914.
+\:\\{hbadness}, \[242], 671, 677, 678.
+\:\9{hbadness\_}{\.{\\hbadness} primitive}, \[244].
+\:\\{hbadness\_code}, \[242], 243, 244.
+\:\9{hbox\_}{\.{\\hbox} primitive}, \[1083].
+\:\\{hbox\_group}, \[275], 280, 1095, 1097.
+\:\\{hc}, \[903], 904, 908, 909, 911, 912, 930, 931, 934, 941, 942, 945, 948,
+950, 971, 973, 974, 976.
+\:\\{hchar}, 916, \[917], 919, 920.
+\:\\{hd}, \[660], 665, \[717], 719, \[720], \[723].
+\:\\{head}, 218, \[219], 221, 222, 223, 435, 729, 787, 807, 810, 816, 823, 825,
+827, 1037, 1045, 1066, 1085, 1092, 1097, 1098, 1103, 1108, 1112, 1117, 1125,
+1131, 1133, 1157, 1171, 1180, 1188, 1193, 1196, 1197, 1199, 1203, 1321.
+\:\\{head\_field}, \[218], 219, 224.
+\:\\{head\_for\_vmode}, 1106, \[1107].
+\:\\{header}, 553.
+\:{Hedrick, Charles Locke}, 3.
+\:\\{height}, \[136], 137, 140, 141, 142, 143, 144, 145, 190, 193, 194, 474,
+565, 633, 635, 637, 640, 642, 643, 646, 648, 651, 652, 660, 664, 667, 681, 683,
+690, 715, 717, 720, 722, 724, 738, 741, 746, 747, 748, 749, 750, 753, 756, 757,
+758, 760, 761, 762, 767, 768, 770, 779, 780, 807, 812, 815, 817, 818, 820, 821,
+822, 980, 984, \[992], 997, 1012, 1013, 1019, 1020, 1021, 1032, 1099, 1112,
+1465.
+\:\.{height}, 474.
+\:\\{height\_base}, \[561], 565, 577, 582, 1335, 1336, 1350.
+\:\\{height\_depth}, \[565], 665, 719, 720, 723, 1137, 1413, 1419.
+\:\\{height\_index}, \[554], 565.
+\:\\{height\_offset}, \[136], 427, 428, 780, 1260.
+\:\\{height\_plus\_depth}, \[723], 725.
+\:\.{held over for next output}, 997.
+\:\\{help\_line}, \[80], 90, 91, 342, 1118.
+\:\\{help\_ptr}, \[80], 81, 90, 91.
+\:\\{help0}, \[80], 1265, 1306.
+\:\\{help1}, \[80], 94, 96, 294, 419, 439, 465, 487, 497, 511, 514, 521, 971,
+972, 973, 974, 1078, 1092, 1111, 1112, 1133, 1144, 1147, 1163, 1167, 1171,
+1189, 1204, 1224, 1225, 1244, 1250, 1256, 1257, 1271, 1296, 1317, 1423, 1436,
+1441, 1468.
+\:\\{help2}, 73, \[80], 89, 90, 95, 96, 294, 352, 384, 444, 445, 446, 447, 448,
+453, 456, 471, 486, 487, 588, 590, 652, 947, 948, 989, 1026, 1038, 1059, 1080,
+1085, 1092, 1094, 1107, 1118, 1122, 1132, 1141, 1178, 1209, 1219, 1237, 1249,
+1254, 1272, 1385, 1399.
+\:\\{help3}, 73, \[80], 99, 342, 407, 426, 457, 490, 787, 794, 795, 803, 1004,
+1020, 1031, 1035, 1039, 1090, 1096, 1122, 1139, 1195, 1207, 1306.
+\:\\{help4}, \[80], 90, 344, 409, 414, 429, 467, 578, 734, 987, 1015, 1062,
+1296.
+\:\\{help5}, \[80], 381, 572, 837, 1076, 1081, 1140, 1227, 1306.
+\:\\{help6}, \[80], 406, 470, 1140, 1173.
+\:\.{Here is how much...}, 1347.
+\:\\{hex\_to\_cur\_chr}, \[360], 363, 364.
+\:\\{hex\_token}, \[449], 455.
+\:\\{hf}, \[903], 907, 908, 909, 914, 919, 920, 921, 922, 926, 927.
+\:\9{hfil\_}{\.{\\hfil} primitive}, \[1070].
+\:\9{hfil\_neg\_}{\.{\\hfilneg} primitive}, \[1070].
+\:\9{hfill\_}{\.{\\hfill} primitive}, \[1070].
+\:\\{hfinish}, 1395.
+\:\\{hfuzz}, \[253], 677.
+\:\9{hfuzz\_}{\.{\\hfuzz} primitive}, \[254].
+\:\\{hfuzz\_code}, \[253], 254.
+\:\\{hh}, 111, 115, 119, 134, 188, 219, 225, 227, 274, 565, 580, 697, 753,
+1175, 1177, 1193, 1198.
+\:\\{hi}, 112, \[113], 238, 565, 1236, 1244.
+\:\\{Hi}, 299, 365, 385, 425, 537, 631, 1244, 1473.
+\:\\{hi\_mem\_min}, \[117], 119, 121, 126, 127, 135, 170, 171, 173, 174, 177,
+178, 182, 299, 650, 1324, 1325, 1347.
+\:\\{hi\_mem\_stat\_min}, \[168], 170, 1325.
+\:\\{hi\_mem\_stat\_usage}, \[168], 170.
+\:\\{HILO}, 238.
+\:\\{history}, \[77], 78, 82, 83, 94, 96, 251, 1345, 1348.
+\:\\{hlist\_node}, \[136], 137, 138, 143, 154, 165, 181, 189, 190, 208, 212,
+516, 629, 630, 633, 634, 639, 642, 643, 648, 651, 655, 660, 662, 680, 692, 726,
+818, 821, 825, 852, 853, 877, 878, 881, 882, 979, 984, 1011, 1086, 1092, 1099,
+1122, 1159, 1215, 1450, 1451, 1465.
+\:\\{hlist\_out}, 603, 626, 627, 629, \[630], 631, 634, 639, 640, 643, 648,
+649, 651, 704, 1386, 1409, 1410, 1446, 1465.
+\:\\{hlp1}, \[80].
+\:\\{hlp2}, \[80].
+\:\\{hlp3}, \[80].
+\:\\{hlp4}, \[80].
+\:\\{hlp5}, \[80].
+\:\\{hlp6}, \[80].
+\:\\{hmode}, \[217], 224, 427, 512, 797, 798, 807, 810, 1041, 1057, 1058, 1060,
+1068, 1069, 1083, 1085, 1088, 1091, 1095, 1098, 1103, 1104, 1105, 1106, 1108,
+1109, 1121, 1122, 1124, 1128, 1129, 1131, 1134, 1142, 1149, 1212, 1256, 1390.
+\:\\{hmove}, \[214], 1060, 1083, 1084, 1085.
+\:\\{hn}, \[903], 908, 909, 910, 913, 923, 924, 926, 927, 928, 930, 934, 941,
+942.
+\:\\{ho}, \[113], 241, 425, 565, 1163, 1166.
+\:\\{hold\_head}, \[168], 312, 790, 794, 795, 805, 819, 916, 917, 924, 925,
+926, 927, 928, 1025, 1028.
+\:\\{holding\_inserts}, \[242], 1025.
+\:\9{holding\_inserts\_}{\.{\\holdinginserts} primitive}, \[244].
+\:\\{holding\_inserts\_code}, \[242], 243, 244.
+\:\\{hpack}, 168, 242, 655, 656, 657, 658, \[660], 672, 720, 726, 731, 738,
+748, 759, 765, 767, 807, 810, 815, 817, 900, 1074, 1098, 1137, 1206, 1211,
+1213, 1216.
+\:\\{hrule}, \[214], 271, 272, 474, 1058, 1068, 1096, 1106, 1107.
+\:\9{hrule\_}{\.{\\hrule} primitive}, \[271].
+\:\\{hsize}, \[253], 858, 859, 860, 1066, 1161.
+\:\9{hsize\_}{\.{\\hsize} primitive}, \[254].
+\:\\{hsize\_code}, \[253], 254.
+\:\\{hskip}, \[214], 1069, 1070, 1071, 1090, 1102.
+\:\9{hskip\_}{\.{\\hskip} primitive}, \[1070].
+\:\9{hss\_}{\.{\\hss} primitive}, \[1070].
+\:\\{hstart}, 1395.
+\:\9{ht\_}{\.{\\ht} primitive}, \[427].
+\:\\{hu}, \[903], 904, 908, 909, 912, 914, 916, 918, 919, 921, 922, 923, 926,
+927.
+\:\.{Huge page...}, 652.
+\:\\{hyf}, \[911], 913, 916, 919, 920, 924, 925, 930, 931, 934, 935, 943, 971,
+972, 973, 974, 976.
+\:\\{hyf\_bchar}, \[903], 908, 909, 914.
+\:\\{hyf\_char}, \[903], 907, 924, 926.
+\:\\{hyf\_distance}, 931, \[932], 933, 935, 954, 955, 956, 1337, 1338.
+\:\\{hyf\_next}, 931, \[932], 935, 954, 955, 956, 1337, 1338.
+\:\\{hyf\_node}, \[923], 926.
+\:\\{hyf\_num}, 931, \[932], 935, 954, 955, 956, 1337, 1338.
+\:\\{hyph\_count}, \[937], 939, 951, 952, 1337, 1338, 1347.
+\:\\{hyph\_data}, \[215], 1222, 1263, 1264, 1265.
+\:\\{hyph\_link}, 936, \[937], 939, 941, 951, 1337, 1338, 1345.
+\:\\{hyph\_list}, \[937], 939, 940, 943, 944, 945, 951, 952, 1337, 1338, 1345.
+\:\\{hyph\_next}, \[937], 939, 951, 1337, 1338.
+\:\\{hyph\_pointer}, \[936], 937, 938, 940, 945, 1345.
+\:\\{hyph\_prime}, 11, \[12], 939, 941, 950, 951, 1320, 1321, 1337, 1338.
+\:\\{hyph\_size}, \[33], 939, 944, 951, 1337, 1338, 1345, 1347.
+\:\\{hyph\_word}, \[937], 939, 940, 942, 945, 951, 952, 1337, 1338, 1345.
+\:\\{hyphen\_char}, 437, \[560], 587, 902, 907, 1046, 1129, 1266, 1335, 1336,
+1350.
+\:\9{hyphen\_char\_}{\.{\\hyphenchar} primitive}, \[1267].
+\:\\{hyphen\_passed}, \[916], 917, 920, 924, 925.
+\:\\{hyphen\_penalty}, 151, \[242], 880.
+\:\9{hyphen\_penalty\_}{\.{\\hyphenpenalty} primitive}, \[244].
+\:\\{hyphen\_penalty\_code}, \[242], 243, 244.
+\:\\{hyphen\_size}, 1337.
+\:\\{hyphenate}, 905, \[906].
+\:\\{hyphenated}, \[830], 831, 840, 857, 870, 880, 884.
+\:\.{Hyphenation trie...}, 1337.
+\:\9{hyphenation\_}{\.{\\hyphenation} primitive}, \[1263].
+\:\|{i}, \[19], \[321], \[598], \[660], \[749], \[760], \[912], \[1135].
+\:\.{I can't find file x}, 541.
+\:\.{I can't find the format...}, 535.
+\:\.{I can't go on...}, 96.
+\:\.{I can't read TEX.POOL}, 52.
+\:\.{I can't write on file x}, 541.
+\:\\{ia\_c}, \[1410], 1411, 1413.
+\:\\{ib\_c}, \[1410], 1411, 1413.
+\:\\{id}, 551.
+\:\\{id\_byte}, \[598], 628, 653.
+\:\\{id\_lookup}, \[265], 270, 362, 364, 385.
+\:\\{ident\_val}, \[421], 426, 476, 477.
+\:\9{if\_case\_}{\.{\\ifcase} primitive}, \[498].
+\:\\{if\_case\_code}, \[498], 499, 512.
+\:\\{if\_cat\_code}, \[498], 499, 512.
+\:\9{if\_cat\_code\_}{\.{\\ifcat} primitive}, \[498].
+\:\9{if\_char\_}{\.{\\if} primitive}, \[498].
+\:\\{if\_char\_code}, \[498], 512, 517.
+\:\\{if\_code}, \[500], 506, 521.
+\:\9{if\_dbox\_}{\.{\\ifdbox} primitive}, \[498].
+\:\\{if\_dbox\_code}, \[498], 499, 512.
+\:\9{if\_ddir\_}{\.{\\ifddir} primitive}, \[498].
+\:\\{if\_ddir\_code}, \[498], 499, 512.
+\:\9{if\_dim\_}{\.{\\ifdim} primitive}, \[498].
+\:\\{if\_dim\_code}, \[498], 499, 512.
+\:\9{if\_eof\_}{\.{\\ifeof} primitive}, \[498].
+\:\\{if\_eof\_code}, \[498], 499, 512.
+\:\9{if\_false\_}{\.{\\iffalse} primitive}, \[498].
+\:\\{if\_false\_code}, \[498], 499, 512.
+\:\9{if\_hbox\_}{\.{\\ifhbox} primitive}, \[498].
+\:\\{if\_hbox\_code}, \[498], 499, 512, 516.
+\:\9{if\_hmode\_}{\.{\\ifhmode} primitive}, \[498].
+\:\\{if\_hmode\_code}, \[498], 499, 512.
+\:\9{if\_inner\_}{\.{\\ifinner} primitive}, \[498].
+\:\\{if\_inner\_code}, \[498], 499, 512.
+\:\9{if\_int\_}{\.{\\ifnum} primitive}, \[498].
+\:\\{if\_int\_code}, \[498], 499, 512, 514.
+\:\\{if\_limit}, \[500], 501, 506, 507, 508, 509, 521.
+\:\\{if\_line}, \[500], 501, 506, 507, 1348.
+\:\\{if\_line\_field}, \[500], 506, 507, 1348.
+\:\9{if\_mdir\_}{\.{\\ifmdir} primitive}, \[498].
+\:\\{if\_mdir\_code}, \[498], 499, 512.
+\:\9{if\_mmode\_}{\.{\\ifmmode} primitive}, \[498].
+\:\\{if\_mmode\_code}, \[498], 499, 512.
+\:\\{if\_node\_size}, \[500], 506, 507, 1348.
+\:\9{if\_odd\_}{\.{\\ifodd} primitive}, \[498].
+\:\\{if\_odd\_code}, \[498], 499, 512.
+\:\9{if\_tbox\_}{\.{\\iftbox} primitive}, \[498].
+\:\\{if\_tbox\_code}, \[498], 499, 512, 516.
+\:\9{if\_tdir\_}{\.{\\iftdir} primitive}, \[498].
+\:\\{if\_tdir\_code}, \[498], 499, 512.
+\:\\{if\_test}, \[216], 342, 374, 378, 498, 499, 505, 509, 514, 1348.
+\:\9{if\_true\_}{\.{\\iftrue} primitive}, \[498].
+\:\\{if\_true\_code}, \[498], 499, 512.
+\:\9{if\_vbox\_}{\.{\\ifvbox} primitive}, \[498].
+\:\\{if\_vbox\_code}, \[498], 499, 512, 516.
+\:\9{if\_vmode\_}{\.{\\ifvmode} primitive}, \[498].
+\:\\{if\_vmode\_code}, \[498], 499, 512.
+\:\9{if\_void\_}{\.{\\ifvoid} primitive}, \[498].
+\:\\{if\_void\_code}, \[498], 499, 512, 516.
+\:\9{if\_ybox\_}{\.{\\ifybox} primitive}, \[498].
+\:\\{if\_ybox\_code}, \[498], 499, 512, 516.
+\:\9{if\_ydir\_}{\.{\\ifydir} primitive}, \[498].
+\:\\{if\_ydir\_code}, \[498], 499, 512.
+\:\\{ifdef}, 7, 8, 651, 653.
+\:\\{ifndef}, 653.
+\:\9{ifx\_}{\.{\\ifx} primitive}, \[498].
+\:\\{ifx\_code}, \[498], 499, 512.
+\:\\{ignore}, \[213], 238, 338, 351.
+\:\\{ignore\_depth}, \[218], 221, 225, 690, 798, 1036, 1068, 1095, 1111, 1179.
+\:\\{ignore\_spaces}, \[214], 271, 272, 1057.
+\:\9{ignore\_spaces\_}{\.{\\ignorespaces} primitive}, \[271].
+\:\\{iinf\_hyphen\_size}, \[11], 12.
+\:\.{Illegal magnification...}, 294, 1271.
+\:\.{Illegal math \\disc...}, 1132.
+\:\.{Illegal parameter number...}, 490.
+\:\.{Illegal unit of measure}, 465, 467, 470.
+\:\9{immediate\_}{\.{\\immediate} primitive}, \[1357].
+\:\\{immediate\_code}, \[1357], 1359, 1361.
+\:\.{IMPOSSIBLE}, 268.
+\:\.{Improper \\halign...}, 787.
+\:\.{Improper \\hyphenation...}, 947.
+\:\.{Improper \\prevdepth}, 429.
+\:\.{Improper \\setbox}, 1254.
+\:\.{Improper \\spacefactor}, 429.
+\:\.{Improper `at' size...}, 1272.
+\:\.{Improper alphabetic constant}, 453.
+\:\.{Improper discretionary list}, 1133.
+\:\.{in}, 469.
+\:\\{in\_open}, \[310], 334, 335, 337, 548, 1398, 1475.
+\:\\{in\_state\_record}, \[306], 307, 1345.
+\:\\{in\_stream}, \[214], 1285, 1286, 1287.
+\:\.{Incompatible glue units}, 419.
+\:\.{Incompatible list...}, 1122.
+\:\.{Incompatible magnification}, 294.
+\:\\{incompleat\_noad}, 218, \[219], 729, 787, 1148, 1190, 1193, 1194, 1196,
+1197.
+\:\.{Incomplete \\if...}, 342.
+\:\\{incr}, 38, 43, 44, 46, 47, 54, 59, 60, 61, 66, 68, 71, 72, 83, 91, 99,
+121, 123, 158, 159, 176, 188, 209, 222, 266, 280, 282, 286, 300, 317, 318, 322,
+327, 331, 334, 349, 353, 360, 362, 363, 364, 365, 368, 370, 377, 385, 403, 406,
+408, 410, 411, 414, 418, 453, 463, 465, 475, 486, 487, 488, 505, 528, 529, 530,
+535, 536, 542, 548, 591, 609, 630, 640, 651, 653, 656, 659, 725, 763, 809, 856,
+888, 908, 909, 921, 922, 925, 926, 934, 941, 942, 948, 950, 951, 952, 955, 965,
+967, 973, 974, 975, 997, 1033, 1036, 1046, 1051, 1081, 1111, 1129, 1131, 1133,
+1139, 1154, 1165, 1184, 1186, 1328, 1329, 1331, 1338, 1350, 1425, 1435, 1440,
+1451, 1472.
+\:\9{indent\_}{\.{\\indent} primitive}, \[1100].
+\:\\{indent\_in\_hmode}, 1104, \[1105].
+\:\\{indented}, \[1103].
+\:\\{index}, 306, \[308], 309, 310, 313, 334, 335, 337.
+\:\\{index\_field}, \[306], 308, 1143.
+\:\\{inf}, 458, \[459], 464, 1345.
+\:\\{inf\_bad}, \[109], 163, 862, 863, 864, 867, 874, 985, 1016, 1028.
+\:\\{inf\_buf\_size}, \[11].
+\:\\{inf\_dvi\_buf\_size}, \[11].
+\:\\{inf\_expand\_depth}, \[11].
+\:\\{inf\_font\_max}, \[11].
+\:\\{inf\_font\_mem\_size}, \[11].
+\:\\{inf\_hash\_extra}, \[11].
+\:\\{inf\_hyph\_size}, \[11].
+\:\\{inf\_main\_memory}, \[11].
+\:\\{inf\_max\_in\_open}, \[11].
+\:\\{inf\_max\_strings}, \[11].
+\:\\{inf\_mem\_bot}, \[11].
+\:\\{inf\_nest\_size}, \[11].
+\:\\{inf\_param\_size}, \[11].
+\:\\{inf\_penalty}, \[163], 772, 778, 827, 840, 842, 985, 1016, 1024, 1215,
+1217.
+\:\\{inf\_pool\_free}, \[11].
+\:\\{inf\_pool\_size}, \[11].
+\:\\{inf\_save\_size}, \[11].
+\:\\{inf\_stack\_size}, \[11].
+\:\\{inf\_string\_vacancies}, \[11].
+\:\\{inf\_strings\_free}, \[11].
+\:\\{inf\_trie\_size}, \[11].
+\:\.{Infinite glue shrinkage...}, 837, 987, 1015, 1020.
+\:\\{infinity}, \[456].
+\:\\{info}, \[119], 125, 127, 136, 145, 170, 178, 180, 182, 206, 239, 281, 297,
+299, 325, 331, 343, 345, 365, 366, 380, 382, 385, 400, 402, 403, 404, 405, 408,
+411, 434, 463, 477, 519, 616, 619, 620, 621, 622, 623, 624, 625, 626, 631, 692,
+700, 703, 704, 709, 731, 745, 746, 747, 748, 749, 753, 760, 765, 766, 779, 780,
+783, 790, 794, 795, 801, 804, 805, 808, 809, 812, 814, 832, 858, 859, 907, 936,
+943, 949, 992, 1077, 1088, 1105, 1135, 1136, 1161, 1163, 1180, 1193, 1197,
+1198, 1203, 1238, 1261, 1262, 1302, 1325, 1352, 1354, 1384, 1452, 1454, 1455,
+1458, 1464, 1469, 1475.
+\:\\{inhibit\_after}, \[1430], 1460.
+\:\\{inhibit\_both}, \[1430], 1459, 1460.
+\:\\{inhibit\_glue}, \[214], 1049, 1432, 1433, 1434, 1469.
+\:\9{inhibit\_glue\_}{\.{\\inhibitglue} primitive}, \[1433].
+\:\\{inhibit\_glue\_flag}, 1041, 1049, 1072, 1073, 1103, 1167, 1179, 1188,
+1193, 1203, 1430, 1431, 1432, 1468, 1469, 1472.
+\:\\{inhibit\_previous}, \[1430], 1459.
+\:\\{inhibit\_xsp\_code}, \[236], 238, 1435.
+\:\9{inhibit\_xsp\_code\_}{\.{\\inhibitxspcode} primitive}, \[1433].
+\:\\{inhibit\_xsp\_code\_base}, \[236], 241, 1433, 1436.
+\:\\{inhibit\_xsp\_type}, \[236], 238, 1437, 1459, 1460.
+\:\\{ini\_version}, 8, \[33], 1314.
+\:\&{Init}, \[8], \[1265], \[1345], \[1348].
+\:\&{init}, \[8], \[33], \[48], \[51], \[132], \[270], \[902], \[953], \[954], %
+\[958], \[961], \[1315], \[1338], \[1349], \[1350].
+\:\\{init\_align}, 784, \[785], 1142.
+\:\\{init\_col}, 784, 796, \[799], 802.
+\:\\{init\_cur\_lang}, 827, 902, \[903].
+\:\\{init\_l\_hyf}, 827, 902, \[903].
+\:\\{init\_lft}, \[911], 914, 916, 919.
+\:\\{init\_lig}, \[911], 914, 916, 919.
+\:\\{init\_list}, \[911], 914, 916, 919.
+\:\\{init\_math}, 1149, \[1150].
+\:\\{init\_pool\_ptr}, \[40], 43, 1323, 1345, 1347.
+\:\\{init\_prim}, 1345, \[1349].
+\:\\{init\_r\_hyf}, 827, 902, \[903].
+\:\\{init\_row}, 784, 796, \[797].
+\:\\{init\_span}, 784, 797, \[798], 802.
+\:\\{init\_str\_ptr}, \[40], 44, 528, 1323, 1345, 1347.
+\:\\{init\_terminal}, \[38], 337.
+\:\\{init\_trie}, 902, \[977], 1337.
+\:\.{INITEX}, 8, 11, 12, 48, 51, 117, 1312, 1344.
+\:\\{initialize}, \[4], 1345, 1350.
+\:{inner loop}, 32, 113, 121, 122, 123, 124, 126, 128, 129, 131, 208, 330, 331,
+347, 348, 349, 365, 373, 391, 410, 418, 565, 608, 622, 631, 662, 665, 666, 843,
+846, 862, 863, 878, 1041, 1051, 1053, 1407, 1408.
+\:\\{inner\_noad}, \[693], 694, 701, 707, 709, 744, 772, 775, 1168, 1169, 1203.
+\:\\{input}, \[216], 374, 378, 387, 388.
+\:\9{input\_}{\.{\\input} primitive}, \[387].
+\:\\{input\_file}, \[310], 1345.
+\:\9{input\_line\_no\_}{\.{\\inputlineno} primitive}, \[427].
+\:\\{input\_line\_no\_code}, \[427], 428, 435.
+\:\\{input\_ln}, 31, 32, 38, 59, 72, 370, 496, 497, 549.
+\:\\{input\_ptr}, \[307], 317, 318, 327, 328, 336, 337, 368, 545, 1143, 1348.
+\:\\{input\_stack}, 85, \[307], 317, 325, 327, 328, 545, 1143, 1345.
+\:\\{ins\_dir}, \[145], 194, 1020, 1031, 1032, 1112.
+\:\\{ins\_disc}, \[1043], 1044, 1046.
+\:\\{ins\_error}, \[333], 342, 406, 1059, 1139, 1144, 1227.
+\:\\{ins\_kp}, \[1041], 1050, 1469.
+\:\\{ins\_list}, \[329], 345, 478, 481, 1076, 1384, 1475.
+\:\\{ins\_node}, \[145], 154, 181, 189, 208, 212, 658, 662, 741, 772, 877, 910,
+979, 984, 992, 997, 1011, 1025, 1112, 1450, 1451.
+\:\\{ins\_node\_size}, \[145], 208, 212, 1033, 1112.
+\:\\{ins\_ptr}, \[145], 194, 208, 212, 1021, 1031, 1032, 1112.
+\:\\{ins\_the\_toks}, 377, 378, \[478].
+\:\\{insert}, \[214], 271, 272, 1109.
+\:\.{insert>}, 88.
+\:\9{insert\_}{\.{\\insert} primitive}, \[271].
+\:\\{insert\_dollar\_sign}, 1057, \[1059].
+\:\\{insert\_group}, \[275], 1080, 1111, 1112.
+\:\\{insert\_penalties}, 430, \[993], 1001, 1016, 1019, 1021, 1025, 1033, 1037,
+1255, 1259.
+\:\9{insert\_penalties\_}{\.{\\insertpenalties} primitive}, \[427].
+\:\\{insert\_relax}, 389, \[390], 521.
+\:\\{insert\_skip}, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458.
+\:\\{insert\_src\_special}, 1103, 1151, 1179, \[1475].
+\:\\{insert\_src\_special\_auto}, \[33], 1045.
+\:\\{insert\_src\_special\_every\_cr}, \[33].
+\:\\{insert\_src\_special\_every\_display}, \[33].
+\:\\{insert\_src\_special\_every\_hbox}, \[33].
+\:\\{insert\_src\_special\_every\_math}, \[33], 1151.
+\:\\{insert\_src\_special\_every\_par}, \[33], 1103.
+\:\\{insert\_src\_special\_every\_parend}, \[33].
+\:\\{insert\_src\_special\_every\_vbox}, \[33], 1179.
+\:\\{insert\_token}, \[274], 286, 288.
+\:\\{inserted}, \[313], 320, 329, 330, 333, 390, 1107.
+\:\\{inserting}, \[992], 1020.
+\:\.{Insertions can only...}, 1004, 1020, 1031.
+\:\\{inserts\_only}, \[991], 998, 1019.
+\:\\{int}, 111, 114, 115, 145, 147, 163, 192, 219, 225, 242, 246, 248, 253,
+280, 284, 285, 424, 425, 500, 616, 736, 780, 783, 830, 1251, 1253, 1329.
+\:\\{int\_base}, 226, \[236], 238, 242, 244, 245, 246, 248, 258, 259, 260, 274,
+289, 294, 1024, 1082, 1151, 1157, 1236, 1240, 1328.
+\:\\{int\_error}, \[92], 294, 444, 445, 446, 447, 448, 1256, 1257, 1271, 1399.
+\:\\{int\_par}, \[242].
+\:\\{int\_pars}, \[242].
+\:\\{int\_val}, \[421], 422, 423, 424, 425, 427, 428, 429, 430, 433, 434, 435,
+437, 438, 439, 440, 450, 451, 460, 472, 476, 1249, 1250, 1251, 1253, 1437, 1442.
+\:\\{intcast}, 128, 870, 886, 955, 959.
+\:\\{integer}, 3, 11, 13, 19, 33, 39, 46, 48, 55, 60, 61, 64, 66, 67, 68, 70,
+83, 92, 95, 97, 101, 102, 103, 106, 107, 108, 109, 110, 111, 114, 118, 126,
+164, 169, 178, 179, 180, 182, 183, 184, 187, 188, 217, 218, 224, 231, 243, 253,
+262, 265, 268, 284, 285, 292, 298, 310, 314, 315, 317, 321, 375, 377, 421, 451,
+459, 461, 493, 500, 504, 505, 509, 529, 530, 531, 534, 559, 560, 561, 571, 589,
+603, 606, 611, 612, 618, 626, 627, 630, 640, 649, 656, 657, 672, 702, 705, 710,
+717, 727, 728, 737, 749, 763, 775, 826, 839, 840, 841, 844, 883, 888, 903, 923,
+933, 937, 977, 981, 991, 993, 1005, 1023, 1041, 1043, 1080, 1087, 1091, 1096,
+1103, 1129, 1131, 1150, 1163, 1167, 1206, 1223, 1315, 1316, 1336, 1344, 1345,
+1346, 1350, 1351, 1361, 1383, 1392, 1395, 1402, 1407, 1408, 1410, 1425, 1446,
+1467, 1468.
+\:\\{inter\_line\_penalty}, \[242], 901.
+\:\9{inter\_line\_penalty\_}{\.{\\interlinepenalty} primitive}, \[244].
+\:\\{inter\_line\_penalty\_code}, \[242], 243, 244.
+\:\\{interaction}, 72, 73, \[74], 75, 76, 83, 85, 87, 91, 93, 94, 99, 368, 371,
+495, 541, 1278, 1296, 1306, 1307, 1310, 1339, 1340, 1341, 1346, 1348.
+\:\\{interaction\_option}, \[74], 75, 1340.
+\:\\{internal\_font\_number}, 150, \[559], 560, 571, 588, 589, 592, 593, 603,
+613, 627, 660, 717, 720, 722, 723, 726, 735, 749, 841, 873, 903, 1043, 1125,
+1135, 1150, 1223, 1270, 1407, 1408, 1416.
+\:\\{interrupt}, \[97], 98, 99, 1042.
+\:\.{Interruption}, 99.
+\:\.{interwoven alignment preambles...}, 330, 793, 800, 802, 1143.
+\:\.{Invalid code}, 1244.
+\:\.{Invalid KANJI code}, 1436, 1441.
+\:\.{Invalid KANSUJI char}, 1423.
+\:\.{Invalid KANSUJI number}, 1423.
+\:\\{invalid\_char}, \[213], 238, 350, 1246.
+\:\\{invalid\_code}, \[22], 24, 238.
+\:\\{ipc\_on}, 651, \[1392].
+\:\\{ipc\_page}, 651.
+\:\\{is\_char\_ascii}, 425, 445, 1041, 1049, 1135, 1136, 1163, 1166, 1244,
+1441, 1469.
+\:\\{is\_char\_kanji}, 445, 1423, 1436, 1441.
+\:\\{is\_char\_node}, \[135], 180, 189, 208, 211, 435, 631, 641, 662, 680, 726,
+731, 732, 767, 816, 827, 848, 852, 853, 867, 877, 878, 879, 881, 882, 890, 892,
+907, 908, 910, 914, 1047, 1052, 1053, 1055, 1073, 1092, 1112, 1113, 1115, 1117,
+1122, 1125, 1133, 1159, 1214, 1443, 1444, 1450, 1451, 1455, 1457, 1458, 1463,
+1464, 1469, 1470, 1471.
+\:\\{IS\_DIR\_SEP}, 527.
+\:\\{is\_empty}, \[125], 128, 175, 176.
+\:\\{is\_hex}, \[360], 363, 364.
+\:\\{is\_new\_source}, 1475.
+\:\\{is\_running}, \[143], 182, 635, 644, 817.
+\:\\{iskanji1}, 59.
+\:\\{ismultiprn}, 50.
+\:\\{issue\_message}, 1289, \[1292].
+\:\\{ita\_kern}, \[161], 848, 877, 879, 890, 1125.
+\:\\{ital\_corr}, \[214], 271, 272, 1123, 1124.
+\:{italic correction}, \[554].
+\:\\{italic\_base}, \[561], 565, 577, 582, 1335, 1336, 1350.
+\:\\{italic\_index}, \[554].
+\:\\{its\_all\_over}, 1057, \[1066], 1348.
+\:\|{j}, \[46], \[47], \[60], \[61], \[70], \[71], \[265], \[270], \[321], %
+\[377], \[528], \[529], \[530], \[534], \[535], \[649], \[904], \[912], \[917],
+\[945], \[977], \[1223], \[1315], \[1316], \[1383], \[1386].
+\:{Japanese characters}, 135, 596.
+\:{Japanese extentions}, 692.
+\:\\{jc}, \[630], 631, \[731], \[1416].
+\:\\{jchr\_widow\_penalty}, \[242], 1451, 1463.
+\:\9{jchr\_widow\_penalty}{\.{\\jcharwidowpenalty} primitive}, \[244].
+\:\\{jchr\_widow\_penalty\_code}, \[242], 243, 244.
+\:{Jensen, Kathleen}, 10.
+\:\\{jfm\_flag}, \[571], 576, 577, 580, 584, 585.
+\:\\{jfm\_skip}, \[230], 231, 1451, 1472.
+\:\9{jfont\_}{\.{\\jfont} primitive}, \[271].
+\:\9{jis\_}{\.{\\jis} primitive}, \[479].
+\:\\{jis\_code}, \[479], 480, 482, 483.
+\:\.{job aborted}, 368.
+\:\.{job aborted, file error...}, 541.
+\:\\{job\_name}, 93, 482, 483, \[538], 539, 540, 543, 545, 548, 1270, 1341,
+1348.
+\:\9{job\_name\_}{\.{\\jobname} primitive}, \[479].
+\:\\{job\_name\_code}, \[479], 481, 482, 483.
+\:\\{jump\_out}, \[82], 83, 85, 94.
+\:\\{just\_box}, \[825], 899, 900, 1158, 1160.
+\:\\{just\_open}, \[491], 494, 1288.
+\:\|{k}, \[46], \[47], \[48], \[65], \[66], \[68], \[70], \[72], \[103], %
+\[169], \[265], \[270], \[347], \[371], \[418], \[461], \[475], \[530], \[534],
+\[536], \[541], \[545], \[571], \[598], \[613], \[618], \[649], \[660], \[716],
+\[917], \[940], \[945], \[971], \[977], \[1091], \[1223], \[1315], \[1316], %
+\[1346], \[1351], \[1361], \[1381], \[1394], \[1425].
+\:\\{kana}, \[213], 238, 300, 304, 353, 362, 364, 373, 391, 392, 453, 482, 517,
+537, 1041, 1049, 1102, 1136, 1163, 1166, 1464, 1469.
+\:\\{kanji}, \[213], 238, 299, 300, 304, 353, 362, 364, 373, 391, 392, 453,
+482, 517, 537, 692, 1041, 1049, 1102, 1136, 1163, 1166, 1245, 1464, 1469.
+\:\\{KANJI}, \[113], 300, 304, 482, 483, 631, 692, 702, 733, 1135, 1136, 1163,
+1166, 1452, 1454, 1455, 1458, 1464, 1469.
+\:\\{KANJI\_code}, \[18], 48, 481, 571, 630, 702, 1041, 1135, 1163, 1416, 1425,
+1435, 1440, 1451, 1473.
+\:\\{kanji\_skip}, \[230], 1098, 1206, 1451.
+\:\9{kanji\_skip\_}{\.{\\kanjiskip} primitive}, \[232].
+\:\\{kanji\_skip\_code}, \[230], 231, 232, 1122, 1461, 1462, 1463.
+\:\\{kanji\_space}, 660.
+\:\9{kansuji\_}{\.{\\kansuji} primitive}, \[479].
+\:\\{kansuji\_base}, \[236], 241, 1423.
+\:\\{kansuji\_char}, \[236], 238, 1425.
+\:\\{kansuji\_code}, \[479], 480, 482, 483.
+\:\9{kansujichar\_}{\.{\\kansujichar} primitive}, \[1421].
+\:\\{kcat\_code}, \[236], 238, 299, 349, 362, 364, 365, 1464.
+\:\\{kcat\_code\_base}, \[236], 241, 425, 1242, 1243, 1244, 1245, 1246.
+\:\\{kcatcodekey}, 238, 299, 349, 362, 364, 365, 425, 1244, 1464.
+\:\\{kchar\_code}, \[565], 580, 1416.
+\:\\{kchar\_code\_end}, \[565].
+\:\\{kchar\_type}, \[565], 580, 1416.
+\:\\{kchar\_type\_end}, \[565].
+\:\\{kcode}, \[1416].
+\:\\{kcode\_noad}, \[692], 697, 1162, 1170, 1175, 1177.
+\:\\{kcode\_noad\_nucleus}, \[692], 1163.
+\:\\{kcode\_pos}, \[55], 56, 58, 59, 322.
+\:\\{kern}, \[214], 556, 1069, 1070, 1071.
+\:\9{kern\_}{\.{\\kern} primitive}, \[1070].
+\:\\{kern\_base}, \[561], 568, 577, 584, 587, 1335, 1336, 1350.
+\:\\{kern\_base\_offset}, \[568], 577, 584.
+\:\\{kern\_break}, \[877].
+\:\\{kern\_flag}, \[556], 752, 763, 764, 920, 1052, 1472.
+\:\\{kern\_node}, \[161], 162, 189, 208, 212, 435, 633, 642, 662, 680, 732,
+741, 743, 772, 848, 852, 853, 867, 877, 879, 881, 882, 890, 892, 907, 908, 910,
+979, 983, 984, 987, 1007, 1008, 1011, 1015, 1118, 1119, 1120, 1133, 1159, 1451,
+1463, 1464.
+\:\\{kinsoku\_base}, \[236], 241, 1440, 1441.
+\:\\{kinsoku\_code}, \[236], 238, 1440.
+\:\\{kinsoku\_pena}, \[163], 200, 1443, 1444, 1445.
+\:\\{kinsoku\_penalty}, \[253], 1442, 1443, 1444, 1445.
+\:\\{kinsoku\_penalty\_base}, \[253], 258, 1441.
+\:\\{kinsoku\_type}, \[236], 238, 1440, 1442, 1443, 1444, 1445.
+\:\\{kk}, \[461], 463.
+\:{Knuth, Donald Ervin}, 2, 87, 704, 824, 902, 936, 1008, 1166, 1384.
+\:\\{kp}, \[1041], 1443, 1444, 1445.
+\:\\{kpse\_find\_file}, 574.
+\:\\{kpse\_in\_name\_ok}, 548, 1288.
+\:\\{kpse\_make\_tex\_discard\_errors}, 1278.
+\:\\{kpse\_out\_name\_ok}, 1387.
+\:\\{kpse\_tex\_format}, 548, 1288.
+\:\\{kpse\_texpool\_format}, 52.
+\:\\{ksp\_ptr}, \[630], 631.
+\:\9{kuten\_}{\.{\\kuten} primitive}, \[479].
+\:\\{kuten\_code}, \[479], 480, 482, 483.
+\:\|{l}, \[48], \[265], \[270], \[282], \[287], \[298], \[321], \[347], \[505],
+\[508], \[545], \[592], \[612], \[626], \[679], \[841], \[912], \[955], \[964],
+\[971], \[1150], \[1206], \[1249], \[1315], \[1351], \[1389].
+\:\\{l\_hyf}, 902, \[903], 905, 910, 913, 934, 1375.
+\:\\{language}, \[242], 945, 1045, 1389.
+\:\9{language\_}{\.{\\language} primitive}, \[244].
+\:\\{language\_code}, \[242], 243, 244.
+\:\\{language\_node}, \[1354], 1369, 1370, 1371, 1375, 1386, 1389, 1390.
+\:\\{large\_attempt}, \[717].
+\:\\{large\_char}, \[694], 702, 708, 717, 1172.
+\:\\{large\_fam}, \[694], 702, 708, 717, 1172.
+\:\\{last}, \[31], 32, 36, 37, 38, 72, 84, 88, 89, 337, 368, 371, 494, 535, 542.
+\:\\{last\_active}, \[830], 831, 843, 846, 855, 865, 871, 872, 874, 875, 876,
+884, 885, 886.
+\:\\{last\_badness}, 435, \[657], 659, 660, 671, 675, 678, 679, 685, 687, 689.
+\:\\{last\_bop}, \[603], 604, 651, 653.
+\:\9{last\_box\_}{\.{\\lastbox} primitive}, \[1083].
+\:\\{last\_box\_code}, \[1083], 1084, 1091.
+\:\\{last\_char}, \[1449], 1450, 1453, 1455.
+\:\\{last\_disp}, \[658], 660, 888, 898.
+\:\\{last\_glue}, 221, 435, \[993], 1002, 1007, 1028, 1118, 1348.
+\:\\{last\_ins\_ptr}, \[992], 1016, 1019, 1029, 1031.
+\:\\{last\_item}, \[214], 424, 427, 428, 1060.
+\:\\{last\_jchr}, \[219], 221, 222, 1125, 1136, 1469.
+\:\\{last\_jchr\_field}, \[218], 219.
+\:\\{last\_kern}, 221, 435, \[993], 1002, 1007.
+\:\9{last\_kern\_}{\.{\\lastkern} primitive}, \[427].
+\:\\{last\_penalty}, 221, 435, \[993], 1002, 1007.
+\:\9{last\_penalty\_}{\.{\\lastpenalty} primitive}, \[427].
+\:\9{last\_skip\_}{\.{\\lastskip} primitive}, \[427].
+\:\\{last\_special\_line}, \[858], 859, 860, 861, 900.
+\:\\{last\_text\_char}, \[19], 24.
+\:\\{lc\_code}, \[236], 238, 902, 907, 908, 909, 948, 973.
+\:\9{lc\_code\_}{\.{\\lccode} primitive}, \[1242].
+\:\\{lc\_code\_base}, \[236], 241, 1242, 1243, 1299, 1300, 1301.
+\:\\{leader\_box}, \[630], 637, 639, \[640], 646, 648.
+\:\\{leader\_flag}, \[1083], 1085, 1090, 1096.
+\:\\{leader\_ht}, \[640], 646, 647, 648.
+\:\\{leader\_ptr}, \[155], 158, 159, 196, 208, 212, 637, 646, 667, 682, 827,
+1090.
+\:\\{leader\_ship}, \[214], 1083, 1084, 1085.
+\:\\{leader\_wd}, \[630], 637, 638, 639.
+\:{leaders}, 1387.
+\:\.{Leaders not followed by...}, 1090.
+\:\9{leaders\_}{\.{\\leaders} primitive}, \[1083].
+\:\\{least\_cost}, \[981], 985, 991.
+\:\\{least\_page\_cost}, \[991], 998, 1016, 1017.
+\:\9{left\_}{\.{\\left} primitive}, \[1200].
+\:\\{left\_brace}, \[213], 295, 300, 304, 353, 365, 414, 484, 487, 788, 1075,
+1162, 1238.
+\:\\{left\_brace\_limit}, \[295], 331, 403, 405, 410.
+\:\\{left\_brace\_token}, \[295], 414, 1139, 1238, 1384, 1475.
+\:\\{left\_delimiter}, \[694], 707, 708, 748, 759, 1175, 1193, 1194.
+\:\\{left\_edge}, \[630], 638, \[640], 643, 648.
+\:\\{left\_hyphen\_min}, \[242], 1103, 1212, 1389, 1390.
+\:\9{left\_hyphen\_min\_}{\.{\\lefthyphenmin} primitive}, \[244].
+\:\\{left\_hyphen\_min\_code}, \[242], 243, 244.
+\:\\{left\_noad}, \[698], 701, 707, 709, 736, 739, 744, 771, 772, 773, 1197,
+1200, 1201, 1203.
+\:\\{left\_right}, \[214], 1058, 1200, 1201, 1202.
+\:\\{left\_skip}, \[230], 838, 891, 898.
+\:\9{left\_skip\_}{\.{\\leftskip} primitive}, \[232].
+\:\\{left\_skip\_code}, \[230], 231, 232, 898.
+\:\\{len}, \[1402].
+\:\\{length}, \[41], 47, 265, 530, 541, 548, 574, 613, 942, 952, 1293, 1402.
+\:{length of lines}, 858.
+\:\9{leq\_no\_}{\.{\\leqno} primitive}, \[1153].
+\:\\{let}, \[215], 1222, 1231, 1232, 1233.
+\:\9{let\_}{\.{\\let} primitive}, \[1231].
+\:\\{letter}, \[213], 238, 268, 295, 297, 300, 304, 353, 362, 364, 946, 972,
+1040, 1041, 1049, 1102, 1136, 1163, 1166, 1172, 1469.
+\:\\{letter\_token}, \[295], 456.
+\:\\{level}, 421, \[424], 426, 429, 439, \[472], \[1398].
+\:\\{level\_boundary}, \[274], 276, 280, 288.
+\:\\{level\_one}, \[227], 234, 238, 260, 270, 278, 283, 284, 285, 286, 287,
+289, 791, 1317, 1348, 1382.
+\:\\{level\_zero}, \[227], 228, 278, 282, 286, 1321.
+\:\\{lf}, 551, \[571], 576, 577, 586, 587.
+\:\\{lft\_hit}, 917, \[918], 919, 921, 922, 1044, 1046, 1052.
+\:\\{lh}, 111, 115, 119, 219, 225, 262, 551, 552, \[571], 576, 577, 579, 696.
+\:\\{lhfield}, 565, 580.
+\:{Liang, Franklin Mark}, 2, 930.
+\:\\{libc\_free}, 530, 534, 1320, 1321.
+\:\\{lig\_char}, \[149], 150, 199, 212, 663, 852, 853, 877, 881, 882, 909, 914,
+1125, 1469.
+\:\\{lig\_kern}, 555, 556, 560.
+\:\\{lig\_kern\_base}, \[561], 568, 577, 582, 584, 587, 1335, 1336, 1350.
+\:\\{lig\_kern\_command}, 552, \[556].
+\:\\{lig\_kern\_restart}, \[568], 752, 763, 920, 1051.
+\:\\{lig\_kern\_restart\_end}, \[568].
+\:\\{lig\_kern\_start}, \[568], 752, 763, 920, 1051.
+\:\\{lig\_ptr}, \[149], 150, 181, 199, 208, 212, 907, 909, 914, 918, 921, 922,
+1048, 1052, 1450, 1457.
+\:\\{lig\_stack}, \[918], 919, 921, 922, 1043, 1045, 1046, 1047, 1048, 1049,
+1050, 1052, 1469.
+\:\\{lig\_tag}, \[555], 580, 752, 763, 920, 1051.
+\:\\{lig\_trick}, \[168], 663.
+\:\\{ligature\_node}, \[149], 150, 154, 181, 189, 208, 212, 633, 662, 763, 852,
+853, 877, 878, 881, 882, 907, 908, 910, 914, 1125, 1133, 1159, 1450, 1451, 1469.
+\:\\{ligature\_present}, 917, \[918], 919, 921, 922, 1044, 1046, 1048, 1050,
+1052, 1469.
+\:\\{limit}, 306, \[308], 309, 313, 324, 334, 336, 337, 349, 356, 358, 359,
+360, 362, 363, 364, 368, 370, 371, 494, 537, 548, 549, 1350.
+\:\.{Limit controls must follow...}, 1171.
+\:\\{limit\_field}, 36, 88, \[306], 308, 545.
+\:\\{limit\_switch}, \[214], 1058, 1168, 1169, 1170.
+\:\\{limits}, \[693], 707, 744, 760, 1168, 1169.
+\:\9{limits\_}{\.{\\limits} primitive}, \[1168].
+\:\\{line}, 85, 222, \[310], 319, 334, 335, 337, 370, 435, 505, 506, 549, 674,
+686, 1036, 1398, 1475.
+\:\\{line\_break}, 168, 825, \[826], 839, 850, 859, 873, 874, 877, 887, 905,
+945, 978, 981, 993, 1108, 1157.
+\:\\{line\_diff}, \[883], 886.
+\:\\{line\_number}, \[830], 831, 844, 846, 856, 857, 861, 875, 883, 885, 886.
+\:\\{line\_penalty}, \[242], 870.
+\:\9{line\_penalty\_}{\.{\\linepenalty} primitive}, \[244].
+\:\\{line\_penalty\_code}, \[242], 243, 244.
+\:\\{line\_skip}, \[230], 253.
+\:\9{line\_skip\_}{\.{\\lineskip} primitive}, \[232].
+\:\\{line\_skip\_code}, 155, 158, \[230], 231, 232, 690.
+\:\\{line\_skip\_limit}, \[253], 690.
+\:\9{line\_skip\_limit\_}{\.{\\lineskiplimit} primitive}, \[254].
+\:\\{line\_skip\_limit\_code}, \[253], 254.
+\:\\{line\_stack}, \[310], 334, 335, 1345, 1398.
+\:\\{line\_width}, \[841], 861, 862.
+\:\\{link}, \[119], 121, 122, 123, 124, 125, 126, 127, 131, 134, 135, 136, 139,
+145, 149, 156, 170, 174, 178, 180, 181, 182, 188, 189, 208, 210, 218, 220, 221,
+224, 229, 239, 298, 301, 312, 325, 329, 345, 365, 366, 377, 380, 382, 385, 400,
+401, 402, 405, 407, 408, 411, 418, 431, 435, 463, 475, 477, 478, 481, 489, 500,
+506, 507, 508, 519, 616, 618, 620, 622, 626, 631, 633, 641, 649, 660, 662, 663,
+665, 666, 677, 680, 690, 692, 700, 716, 722, 726, 729, 730, 731, 732, 737, 738,
+742, 743, 746, 748, 749, 750, 758, 759, 762, 763, 764, 765, 766, 767, 770, 771,
+772, 777, 778, 781, 783, 789, 790, 794, 795, 797, 801, 802, 804, 805, 806, 807,
+808, 809, 810, 812, 813, 814, 815, 816, 817, 818, 819, 820, 823, 825, 827, 830,
+832, 833, 840, 841, 848, 851, 852, 853, 854, 855, 856, 865, 868, 869, 871, 872,
+873, 874, 875, 876, 877, 878, 880, 881, 882, 884, 885, 886, 888, 890, 891, 892,
+893, 894, 895, 896, 897, 898, 899, 901, 905, 907, 908, 909, 910, 914, 916, 917,
+918, 919, 921, 922, 924, 925, 926, 927, 928, 929, 943, 949, 971, 979, 980, 981,
+984, 989, 990, 991, 992, 997, 999, 1002, 1005, 1009, 1010, 1011, 1012, 1016,
+1019, 1020, 1025, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1037, 1046, 1047,
+1048, 1052, 1053, 1055, 1076, 1077, 1088, 1090, 1092, 1093, 1098, 1103, 1112,
+1122, 1125, 1131, 1132, 1133, 1135, 1136, 1137, 1158, 1159, 1167, 1180, 1193,
+1196, 1197, 1198, 1199, 1203, 1206, 1208, 1211, 1216, 1217, 1218, 1238, 1260,
+1292, 1301, 1310, 1324, 1325, 1348, 1352, 1354, 1362, 1381, 1384, 1388, 1443,
+1450, 1451, 1452, 1454, 1455, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464,
+1468, 1469, 1470, 1472, 1475.
+\:\\{list\_offset}, \[136], 660, 780, 1029, 1031.
+\:\\{list\_ptr}, \[136], 137, 139, 190, 208, 212, 516, 630, 634, 640, 643, 649,
+669, 674, 675, 679, 684, 687, 720, 722, 726, 732, 747, 750, 758, 762, 818, 988,
+989, 990, 1004, 1032, 1088, 1090, 1093, 1099, 1112, 1122, 1158, 1211, 1260,
+1450, 1453, 1465.
+\:\\{list\_state\_record}, \[218], 219, 1345.
+\:\\{list\_tag}, \[555], 580, 581, 719, 751, 760.
+\:\\{ll}, \[964], 967.
+\:\\{llink}, \[125], 127, 128, 130, 131, 132, 151, 155, 170, 175, 783, 830,
+832, 1325.
+\:\\{Lo}, 299, 325, 365, 385, 537, 631, 1473.
+\:\\{lo\_mem\_max}, \[117], 121, 126, 127, 170, 171, 173, 175, 176, 177, 178,
+184, 650, 1324, 1325, 1336, 1347.
+\:\\{lo\_mem\_stat\_max}, \[168], 170, 1325.
+\:\\{load\_fmt\_file}, \[1316], 1350.
+\:\\{loc}, \[37], 38, 88, 306, 308, 309, 313, 318, 320, 324, 325, 329, 331,
+334, 336, 337, 349, 356, 358, 359, 360, 362, 364, 365, 366, 368, 370, 380, 401,
+494, 535, 537, 548, 549, 1037, 1038, 1350.
+\:\\{loc\_field}, 36, 37, \[306], 308, 1143.
+\:\\{local\_base}, 226, \[230], 234, 236, 258.
+\:\\{location}, \[616], 618, 623, 624, 625, 626.
+\:\\{log\_file}, \[55], 57, 76, 545, 547, 1346.
+\:\\{log\_name}, \[543], 545, 1346.
+\:\\{log\_only}, \[55], 58, 59, 63, 76, 99, 368, 545, 1341, 1383, 1387.
+\:\\{log\_opened}, 93, 94, \[538], 539, 545, 546, 1278, 1346, 1347, 1383, 1387.
+\:\9{long\_}{\.{\\long} primitive}, \[1220].
+\:\\{long\_call}, \[216], 281, 374, 398, 400, 403, 410, 1308.
+\:\\{long\_help\_seen}, \[1294], 1295, 1296.
+\:\\{long\_outer\_call}, \[216], 281, 374, 398, 400, 1308.
+\:\\{long\_state}, 345, \[398], 402, 403, 406, 407, 410.
+\:\&{loop}, 15, \[16].
+\:\.{Loose \\hbox...}, 671.
+\:\.{Loose \\vbox...}, 685.
+\:\\{loose\_fit}, \[828], 845, 863.
+\:\\{looseness}, \[242], 859, 884, 886, 1082.
+\:\9{looseness\_}{\.{\\looseness} primitive}, \[244].
+\:\\{looseness\_code}, \[242], 243, 244, 1082.
+\:\9{lower\_}{\.{\\lower} primitive}, \[1083].
+\:\9{lowercase\_}{\.{\\lowercase} primitive}, \[1299].
+\:\\{lq}, \[603], 638, 647.
+\:\\{lr}, \[603], 638, 647.
+\:\\{lx}, \[630], 637, 638, 639, \[640], 646, 647, 648.
+\:\|{m}, \[48], \[66], \[164], \[217], \[224], \[298], \[321], \[400], \[424], %
+\[451], \[493], \[509], \[588], \[660], \[679], \[717], \[727], \[728], %
+\[1091], \[1117], \[1206], \[1223], \[1351].
+\:\\{mac\_param}, \[213], 297, 300, 304, 353, 485, 488, 490, 794, 795, 1057.
+\:\\{macro}, \[313], 320, 325, 329, 330, 401.
+\:\\{macro\_call}, 297, 377, 391, 393, 398, 399, \[400], 402.
+\:\\{macro\_def}, \[484], 488.
+\:\\{mag}, \[242], 246, 294, 468, 596, \[598], 599, 601, 628, 653.
+\:\9{mag\_}{\.{\\mag} primitive}, \[244].
+\:\\{mag\_code}, \[242], 243, 244, 294.
+\:\\{mag\_set}, \[292], 293, 294.
+\:\\{magic\_offset}, \[775], 776, 777.
+\:\\{main\_body}, \[1345].
+\:\\{main\_control}, 1040, \[1041], 1043, 1052, 1053, 1064, 1066, 1067, 1068,
+1069, 1138, 1146, 1220, 1303, 1345, 1350, 1357, 1360, 1443, 1469.
+\:\\{main\_f}, \[1043], 1045, 1046, 1047, 1048, 1049, 1051, 1052, 1469, 1472.
+\:\\{main\_i}, \[1043], 1047, 1048, 1051, 1052, 1469, 1472.
+\:\\{main\_j}, \[1043], 1051, 1052, 1472.
+\:\\{main\_k}, \[1043], 1045, 1051, 1052, 1054, 1472.
+\:\\{main\_lig\_loop}, \[1041], 1045, 1048, 1049, 1051, 1052.
+\:\\{main\_loop}, \[1041], 1469.
+\:\\{main\_loop\_j}, \[1041], 1050, 1469.
+\:\\{main\_loop\_lookahead}, \[1041], 1045, 1047, 1048, 1049.
+\:\\{main\_loop\_move}, \[1041], 1045, 1047, 1052.
+\:\\{main\_loop\_move\_lig}, \[1041], 1045, 1047, 1048.
+\:\\{main\_loop\_wrapup}, \[1041], 1045, 1051, 1052.
+\:\\{main\_memory}, \[33], 1345.
+\:\\{main\_p}, \[1043], 1046, 1048, 1052, 1053, 1054, 1055, 1056, 1443, 1469.
+\:\\{main\_s}, \[1043], 1045.
+\:\\{major\_tail}, \[923], 925, 928, 929.
+\:\\{make\_accent}, 1134, \[1135], 1409, 1413.
+\:\\{make\_box}, \[214], 1083, 1084, 1085, 1091, 1096.
+\:\\{make\_fraction}, 744, 745, \[754].
+\:\\{make\_full\_name\_string}, 548.
+\:\\{make\_left\_right}, 772, \[773].
+\:\\{make\_mark}, 1109, \[1113].
+\:\\{make\_math\_accent}, 744, \[749].
+\:\\{make\_name\_string}, \[536].
+\:\\{make\_op}, 744, \[760].
+\:\\{make\_ord}, 744, \[763].
+\:\\{make\_over}, 744, \[745].
+\:\\{make\_radical}, 744, 745, \[748].
+\:\\{make\_scripts}, 765, \[767].
+\:\\{make\_src\_special}, 1475.
+\:\\{make\_string}, \[44], 49, 53, 266, 528, 536, 950, 1270, 1292, 1341, 1346,
+1403.
+\:\\{make\_under}, 744, \[746].
+\:\\{make\_vcenter}, 744, \[747].
+\:\\{mark}, \[214], 271, 272, 1109.
+\:\9{mark\_}{\.{\\mark} primitive}, \[271].
+\:\\{mark\_node}, \[147], 154, 181, 189, 208, 212, 658, 662, 741, 772, 877,
+910, 979, 984, 990, 1011, 1025, 1113, 1450, 1451, 1464.
+\:\\{mark\_ptr}, \[147], 148, 202, 208, 212, 990, 1027, 1113.
+\:\\{mark\_text}, \[313], 320, 329, 397.
+\:{mastication}, 347.
+\:\\{match}, \[213], 295, 297, 298, 300, 402, 403.
+\:\\{match\_chr}, \[298], 300, \[400], 402, 411.
+\:\\{match\_token}, \[295], 402, 403, 404, 405, 487.
+\:\\{matching}, \[311], 312, 345, 402.
+\:\.{Math formula deleted...}, 1207.
+\:\\{math\_ac}, 1176, \[1177].
+\:\\{math\_accent}, \[214], 271, 272, 1058, 1176.
+\:\9{math\_accent\_}{\.{\\mathaccent} primitive}, \[271].
+\:\9{math\_bin\_}{\.{\\mathbin} primitive}, \[1168].
+\:\\{math\_char}, \[692], 702, 703, 707, 731, 733, 735, 749, 752, 760, 763,
+764, 765, 1163, 1167, 1177.
+\:\9{math\_char\_}{\.{\\mathchar} primitive}, \[271].
+\:\9{math\_char\_def\_}{\.{\\mathchardef} primitive}, \[1234].
+\:\\{math\_char\_def\_code}, \[1234], 1235, 1236.
+\:\\{math\_char\_num}, \[214], 271, 272, 1058, 1163, 1166.
+\:\\{math\_choice}, \[214], 271, 272, 1058, 1183.
+\:\9{math\_choice\_}{\.{\\mathchoice} primitive}, \[271].
+\:\\{math\_choice\_group}, \[275], 1184, 1185, 1186.
+\:\9{math\_close\_}{\.{\\mathclose} primitive}, \[1168].
+\:\\{math\_code}, \[236], 238, 242, 425, 1163, 1166.
+\:\9{math\_code\_}{\.{\\mathcode} primitive}, \[1242].
+\:\\{math\_code\_base}, \[236], 241, 425, 1242, 1243, 1244, 1246.
+\:\\{math\_comp}, \[214], 1058, 1168, 1169, 1170.
+\:\\{math\_font\_base}, \[236], 238, 240, 1242, 1243.
+\:\\{math\_fraction}, 1192, \[1193].
+\:\\{math\_given}, \[214], 424, 1058, 1163, 1166, 1234, 1235, 1236.
+\:\\{math\_glue}, \[727], 743, 777.
+\:\\{math\_group}, \[275], 1148, 1162, 1165, 1198.
+\:\9{math\_inner\_}{\.{\\mathinner} primitive}, \[1168].
+\:\\{math\_jchar}, \[692], 703, 731, 763, 765, 1163, 1468.
+\:\\{math\_kcode}, \[692], 731, 745, 746, 748, 749, 753, 755, 760, 761, 763,
+766, 768, 769, 770, 1163, 1198, 1468.
+\:\\{math\_kcode\_nucleus}, \[692], 702, 733.
+\:\\{math\_kern}, \[728], 741.
+\:\\{math\_left\_group}, \[275], 1077, 1080, 1081, 1162, 1203.
+\:\\{math\_left\_right}, 1202, \[1203].
+\:\\{math\_limit\_switch}, 1170, \[1171].
+\:\\{math\_node}, \[153], 154, 181, 189, 208, 212, 633, 662, 828, 848, 877,
+878, 890, 892, 1159, 1449, 1450, 1451, 1454, 1455, 1464.
+\:\9{math\_op\_}{\.{\\mathop} primitive}, \[1168].
+\:\9{math\_open\_}{\.{\\mathopen} primitive}, \[1168].
+\:\9{math\_ord\_}{\.{\\mathord} primitive}, \[1168].
+\:\9{math\_punct\_}{\.{\\mathpunct} primitive}, \[1168].
+\:\\{math\_quad}, \[711], 714, 1211.
+\:\\{math\_radical}, 1174, \[1175].
+\:\9{math\_rel\_}{\.{\\mathrel} primitive}, \[1168].
+\:\\{math\_shift}, \[213], 295, 300, 304, 353, 1102, 1149, 1150, 1205, 1209,
+1218.
+\:\\{math\_shift\_group}, \[275], 1077, 1080, 1081, 1142, 1151, 1152, 1154,
+1157, 1204, 1205, 1206, 1212.
+\:\\{math\_shift\_token}, \[295], 1059, 1077.
+\:\\{math\_spacing}, \[775], 776.
+\:\\{math\_style}, \[214], 1058, 1181, 1182, 1183.
+\:\\{math\_surround}, \[253], 1208.
+\:\9{math\_surround\_}{\.{\\mathsurround} primitive}, \[254].
+\:\\{math\_surround\_code}, \[253], 254.
+\:\\{math\_text\_char}, \[692], 763, 764, 765, 766.
+\:\\{math\_text\_jchar}, \[692], 763, 765, 766.
+\:\\{math\_type}, \[692], 694, 698, 703, 709, 731, 733, 734, 745, 746, 748,
+749, 752, 753, 760, 762, 763, 764, 765, 766, 767, 1088, 1105, 1163, 1167, 1177,
+1180, 1188, 1193, 1197, 1198, 1203, 1468.
+\:\\{math\_x\_height}, \[711], 748, 768, 769, 770.
+\:\\{mathex}, \[712].
+\:\\{mathsy}, \[711].
+\:\\{mathsy\_end}, \[711].
+\:\\{max\_answer}, \[106].
+\:\\{max\_buf\_stack}, \[31], 32, 337, 385, 1347.
+\:\\{max\_char\_code}, \[213], 214, 309, 347, 350, 453, 1246.
+\:\\{max\_command}, \[215], 216, 217, 225, 366, 374, 377, 379, 391, 392, 489,
+793.
+\:\\{max\_d}, \[737], 738, 741, 771, 772, \[773].
+\:\\{max\_dead\_cycles}, \[242], 246, 1023.
+\:\9{max\_dead\_cycles\_}{\.{\\maxdeadcycles} primitive}, \[244].
+\:\\{max\_dead\_cycles\_code}, \[242], 243, 244.
+\:\\{max\_depth}, \[253], 991, 998.
+\:\9{max\_depth\_}{\.{\\maxdepth} primitive}, \[254].
+\:\\{max\_depth\_code}, \[253], 254.
+\:\\{max\_dimen}, \[432], 471, 652, 679, 1021, 1028, 1157, 1158, 1160.
+\:\\{max\_font\_max}, \[11], 33, 112, 228, 1334.
+\:\\{max\_group\_code}, \[275].
+\:\\{max\_h}, \[603], 604, 652, 653, \[737], 738, 741, 771, 772, \[773].
+\:\\{max\_halfword}, 14, 33, \[111], 112, 113, 114, 125, 126, 127, 132, 133,
+221, 295, 296, 435, 831, 859, 861, 931, 993, 1002, 1007, 1028, 1118, 1262,
+1320, 1321, 1336, 1338, 1348, 1469.
+\:\\{max\_in\_open}, 14, \[33], 310, 334, 1345, 1398.
+\:\\{max\_in\_stack}, \[307], 327, 337, 1347.
+\:\\{max\_internal}, \[215], 424, 451, 459, 466, 472.
+\:\\{max\_nest\_stack}, \[219], 221, 222, 1347.
+\:\\{max\_non\_prefixed\_command}, \[214], 215, 1223, 1283.
+\:\\{max\_op\_used}, \[954], 955, 957.
+\:\\{max\_param\_stack}, \[314], 337, 401, 1347.
+\:\\{max\_print\_line}, 14, \[33], 55, 59, 62, 73, 182, 548, 649, 1293, 1345.
+\:\\{max\_push}, \[603], 604, 630, 640, 653.
+\:\\{max\_quarterword}, 33, \[111], 112, 114, 280, 808, 809, 931, 1132.
+\:\\{max\_save\_stack}, \[277], 278, 279, 1347.
+\:\\{max\_selector}, \[55], 252, 317, 476, 481, 545, 649, 1270, 1292, 1381,
+1383, 1386.
+\:\\{max\_strings}, \[33], 44, 112, 528, 536, 1323, 1345, 1347.
+\:\\{max\_trie\_op}, \[11], 931, 955, 1338.
+\:\\{max\_v}, \[603], 604, 652, 653.
+\:\\{maxint}, 11.
+\:\9{meaning\_}{\.{\\meaning} primitive}, \[479].
+\:\\{meaning\_code}, \[479], 480, 482, 483.
+\:\\{med\_mu\_skip}, \[230].
+\:\9{med\_mu\_skip\_}{\.{\\medmuskip} primitive}, \[232].
+\:\\{med\_mu\_skip\_code}, \[230], 231, 232, 777.
+\:\\{mem}, 33, 116, 117, 119, 125, 127, 132, 134, 135, 136, 145, 146, 147, 156,
+157, 163, 165, 168, 169, 170, 171, 173, 178, 188, 192, 209, 211, 212, 227, 230,
+281, 297, 398, 431, 500, 616, 663, 691, 692, 694, 697, 698, 731, 736, 753, 764,
+780, 781, 783, 808, 827, 829, 830, 833, 834, 843, 854, 855, 858, 859, 861, 871,
+872, 900, 936, 1161, 1163, 1172, 1175, 1177, 1193, 1198, 1260, 1261, 1321,
+1324, 1325, 1345, 1352.
+\:\\{mem\_bot}, 14, \[33], 112, 117, 126, 127, 168, 170, 1320, 1321, 1324,
+1325, 1345.
+\:\\{mem\_end}, 117, \[119], 121, 170, 171, 173, 174, 177, 178, 180, 182, 188,
+299, 1324, 1325, 1347.
+\:\\{mem\_max}, 12, 14, \[33], 111, 112, 117, 121, 125, 126, 172, 1321, 1345.
+\:\\{mem\_min}, 12, \[33], 112, 117, 121, 126, 172, 173, 175, 176, 177, 178,
+180, 184, 188, 1262, 1321, 1325, 1345, 1347.
+\:\\{mem\_top}, 14, \[33], 112, 117, 168, 170, 1262, 1320, 1321, 1325, 1345.
+\:\.{Memory usage...}, 650.
+\:\\{memory\_word}, 111, 114, 115, 117, 188, 218, 224, 227, 259, 274, 277, 281,
+559, 560, 811, 1318, 1321, 1334, 1345.
+\:\\{message}, \[214], 1289, 1290, 1291.
+\:\9{message\_}{\.{\\message} primitive}, \[1290].
+\:\9{METAFONT}{\MF}, 600.
+\:\\{mid}, \[557].
+\:\\{mid\_kanji}, \[309], 350, 353.
+\:\\{mid\_line}, 88, \[309], 334, 350, 353, 360, 361, 362.
+\:\\{min\_halfword}, 33, \[111], 112, 113, 114, 116, 236, 1038, 1336, 1338.
+\:\\{min\_internal}, \[214], 424, 451, 459, 466, 472.
+\:\\{min\_quarterword}, 11, \[111], 112, 113, 114, 135, 137, 145, 191, 227,
+280, 559, 561, 565, 567, 568, 577, 587, 660, 679, 696, 708, 718, 724, 725, 807,
+812, 814, 819, 969, 1005, 1023, 1336, 1337, 1338.
+\:\\{min\_trie\_op}, \[11], 931, 934, 935, 954, 955, 956, 957, 969, 974, 975,
+976.
+\:\\{minimal\_demerits}, \[844], 845, 847, 856, 866.
+\:\\{minimum\_demerits}, \[844], 845, 846, 847, 865, 866.
+\:\\{minor\_tail}, \[923], 926, 927.
+\:\.{minus}, 473.
+\:\.{Misplaced \&}, 1140.
+\:\.{Misplaced \\cr}, 1140.
+\:\.{Misplaced \\noalign}, 1141.
+\:\.{Misplaced \\omit}, 1141.
+\:\.{Misplaced \\span}, 1140.
+\:\.{Missing = inserted}, 514.
+\:\.{Missing \# inserted...}, 794.
+\:\.{Missing \$ inserted}, 1059, 1077.
+\:\.{Missing \\cr inserted}, 1144.
+\:\.{Missing \\endcsname...}, 384.
+\:\.{Missing \\endgroup inserted}, 1077.
+\:\.{Missing \\right\hbox{.} inserted}, 1077.
+\:\.{Missing \{ inserted}, 414, 486, 1139.
+\:\.{Missing \} inserted}, 1077, 1139.
+\:\.{Missing `to' inserted}, 1094.
+\:\.{Missing `to'...}, 1237.
+\:\.{Missing {\$\$} inserted}, 1219.
+\:\.{Missing character}, 592, 1407, 1411.
+\:\.{Missing control...}, 1227.
+\:\.{Missing delimiter...}, 1173.
+\:\.{Missing font identifier}, 588.
+\:\.{Missing number...}, 426, 457.
+\:\\{mkern}, \[214], 1058, 1069, 1070, 1071.
+\:\9{mkern\_}{\.{\\mkern} primitive}, \[1070].
+\:\\{ml\_field}, \[218], 219, 224.
+\:\\{mlist}, \[737], 771.
+\:\\{mlist\_penalties}, \[730], 731, 737, 765, 1206, 1208, 1211.
+\:\\{mlist\_to\_hlist}, 704, 730, 731, 736, \[737], 745, 765, 771, 1206, 1208,
+1211.
+\:\\{mltex\_enabled\_p}, 244, 545, 631, 1350, \[1405], 1406, 1407, 1408, 1415.
+\:\\{mltex\_p}, 244, 1234, \[1404], 1405, 1414, 1415.
+\:\.{mm}, 469.
+\:\\{mmode}, \[217], 218, 219, 224, 512, 729, 786, 787, 811, 823, 1041, 1057,
+1058, 1060, 1068, 1069, 1085, 1092, 1104, 1109, 1121, 1122, 1124, 1128, 1132,
+1142, 1148, 1152, 1157, 1162, 1166, 1170, 1174, 1176, 1179, 1183, 1187, 1192,
+1202, 1205, 1206.
+\:\\{mode}, 217, 218, \[219], 221, 222, 305, 429, 433, 435, 512, 729, 786, 787,
+796, 797, 798, 807, 810, 815, 818, 819, 820, 823, 1036, 1040, 1041, 1045, 1046,
+1061, 1063, 1068, 1085, 1088, 1090, 1092, 1095, 1098, 1103, 1105, 1106, 1107,
+1108, 1111, 1115, 1117, 1122, 1129, 1131, 1132, 1148, 1150, 1157, 1179, 1206,
+1208, 1212, 1256, 1383, 1384, 1390.
+\:\\{mode\_field}, \[218], 219, 224, 433, 811, 1257.
+\:\\{mode\_line}, 218, \[219], 221, 222, 310, 815, 826, 1036.
+\:\\{month}, \[242], 247, 547, 628, 1341.
+\:\9{month\_}{\.{\\month} primitive}, \[244].
+\:\\{month\_code}, \[242], 243, 244.
+\:\\{months}, \[545], 547.
+\:\\{more\_name}, 523, \[527], 536, 537, 542, 1392.
+\:\9{move\_left\_}{\.{\\moveleft} primitive}, \[1083].
+\:\\{move\_past}, \[630], 633, 636, 640, 642, 645.
+\:\9{move\_right\_}{\.{\\moveright} primitive}, \[1083].
+\:\\{movement}, \[618], 620, 627.
+\:\\{movement\_node\_size}, \[616], 618, 626.
+\:\\{mp}, \[1416].
+\:\\{mskip}, \[214], 1058, 1069, 1070, 1071.
+\:\9{mskip\_}{\.{\\mskip} primitive}, \[1070].
+\:\\{mskip\_code}, \[1070], 1072.
+\:\\{mstate}, \[618], 622, 623.
+\:\&{mtype}, \[4].
+\:\\{mu}, 458, \[459], 460, 464, 466, \[472], 473.
+\:\.{mu}, 467.
+\:\\{mu\_error}, \[419], 440, 460, 466, 472.
+\:\\{mu\_glue}, \[155], 161, 197, 435, 728, 743, 1070, 1072, 1073.
+\:\\{mu\_mult}, \[727], 728.
+\:\\{mu\_skip}, \[230], 438.
+\:\9{mu\_skip\_}{\.{\\muskip} primitive}, \[422].
+\:\\{mu\_skip\_base}, \[230], 233, 235, 1236, 1250.
+\:\9{mu\_skip\_def\_}{\.{\\muskipdef} primitive}, \[1234].
+\:\\{mu\_skip\_def\_code}, \[1234], 1235, 1236.
+\:\\{mu\_val}, \[421], 422, 424, 435, 438, 440, 441, 460, 462, 466, 472, 476,
+1072, 1240, 1249, 1250.
+\:\\{mult\_and\_add}, \[106].
+\:\\{mult\_integers}, \[106], 1253.
+\:\\{multiply}, \[215], 271, 272, 1222, 1248, 1249, 1253.
+\:\9{multiply\_}{\.{\\multiply} primitive}, \[271].
+\:\\{multistrlen}, 349, 362, 364, 475.
+\:\.{Must increase the x}, 1316.
+\:\\{must\_quote}, \[528], \[529].
+\:\|{n}, \[48], \[66], \[67], \[68], \[70], \[92], \[95], \[106], \[107], %
+\[108], \[158], \[160], \[180], \[188], \[231], \[243], \[253], \[258], \[298],
+\[321], \[400], \[493], \[509], \[529], \[530], \[534], \[589], \[717], \[727],
+\[728], \[802], \[811], \[917], \[945], \[955], \[988], \[1003], \[1004], %
+\[1005], \[1023], \[1091], \[1131], \[1150], \[1223], \[1288], \[1351], \[1425].
+\:\\{name}, 306, \[308], 309, 310, 313, 317, 319, 320, 329, 334, 335, 337, 343,
+368, 401, 494, 548.
+\:\\{name\_field}, 85, \[306], 308.
+\:\\{name\_in\_progress}, 389, 536, 537, \[538], 539, 1271.
+\:\\{name\_length}, \[26], 52, 530, 534, 536.
+\:\\{name\_of\_file}, \[26], 52, 530, 534, 535, 536, 541, 545, 548, 1288, 1321,
+1387.
+\:\\{name\_too\_long}, \[571], 572, 574.
+\:\\{natural}, \[655], 716, 726, 731, 738, 746, 748, 749, 759, 765, 767, 770,
+807, 810, 817, 988, 1032, 1112, 1137, 1206, 1211, 1216.
+\:\\{nd}, 551, 552, \[571], 576, 577, 580.
+\:\\{ne}, 551, 552, \[571], 576, 577, 580, 584.
+\:\\{neg\_trie\_op\_size}, \[11], 954, 955.
+\:\\{negate}, \[16], 66, 104, 106, 107, 108, 441, 442, 451, 459, 472, 786.
+\:\\{negative}, \[107], \[424], 441, \[451], 452, \[459], \[472].
+\:\\{nest}, 218, \[219], 222, 223, 224, 225, 424, 433, 786, 811, 1006, 1257,
+1345.
+\:\\{nest\_ptr}, \[219], 221, 222, 223, 224, 433, 786, 811, 1006, 1028, 1034,
+1103, 1112, 1157, 1212, 1257.
+\:\\{nest\_size}, \[33], 219, 222, 224, 424, 1257, 1345, 1347.
+\:\\{new\_character}, \[593], 766, 926, 1129, 1135, 1136.
+\:\\{new\_choice}, \[700], 1184.
+\:\\{new\_delta\_from\_break\_width}, \[855].
+\:\\{new\_delta\_to\_break\_width}, \[854].
+\:\\{new\_dir\_node}, \[139], 431, 649, 1088, 1090, 1180, 1260.
+\:\\{new\_disc}, \[151], 1046, 1129.
+\:\\{new\_font}, 1269, \[1270].
+\:\\{new\_glue}, \[159], 160, 726, 763, 777, 797, 804, 806, 820, 1053, 1055,
+1066, 1072, 1183, 1459, 1460, 1461, 1462, 1463, 1472.
+\:\\{new\_graf}, 1102, \[1103].
+\:\\{new\_hlist}, \[736], 738, 754, 759, 760, 761, 765, 767, 773, 778.
+\:\\{new\_hyph\_exceptions}, \[945], 1265.
+\:\\{new\_interaction}, 1277, \[1278].
+\:\\{new\_kern}, \[162], 716, 726, 746, 749, 750, 758, 762, 763, 764, 766, 770,
+921, 1052, 1073, 1124, 1125, 1137, 1216, 1472.
+\:\\{new\_lig\_item}, \[150], 922, 1052.
+\:\\{new\_ligature}, \[150], 921, 1046.
+\:\\{new\_line}, \[309], 337, 349, 350, 351, 353, 494, 548.
+\:\\{new\_line\_char}, 60, \[242], 250.
+\:\9{new\_line\_char\_}{\.{\\newlinechar} primitive}, \[244].
+\:\\{new\_line\_char\_code}, \[242], 243, 244.
+\:\\{new\_math}, \[153], 1208.
+\:\\{new\_noad}, \[697], 731, 753, 764, 1088, 1105, 1162, 1163, 1167, 1170,
+1180, 1189, 1203, 1468.
+\:\\{new\_null\_box}, \[137], 139, 222, 717, 720, 724, 731, 737, 758, 761, 790,
+804, 815, 820, 1029, 1031, 1066, 1103, 1105.
+\:\\{new\_param\_glue}, \[158], 160, 690, 789, 827, 897, 898, 1053, 1055, 1103,
+1215, 1217, 1218.
+\:\\{new\_patterns}, \[971], 1265.
+\:\\{new\_penalty}, \[164], 778, 827, 901, 1066, 1115, 1215, 1217, 1218, 1443,
+1444, 1445, 1463.
+\:\\{new\_pos}, \[1430], 1435, 1436, 1440, 1441.
+\:\\{new\_rule}, \[144], 474, 677, 715.
+\:\\{new\_save\_level}, \[280], 656, 785, 796, 802, 1036, 1075, 1111, 1129,
+1131, 1148.
+\:\\{new\_skip\_param}, \[160], 690, 980, 1012.
+\:\\{new\_spec}, \[157], 160, 441, 473, 763, 837, 987, 1015, 1054, 1055, 1252,
+1253, 1472.
+\:\\{new\_string}, \[55], 58, 59, 476, 481, 628, 1270, 1292, 1341, 1381, 1383.
+\:\\{new\_style}, \[699], 1183.
+\:\\{new\_trie\_op}, 954, \[955], 956, 976.
+\:\\{new\_whatsit}, \[1362], 1363, 1367, 1389, 1390, 1475.
+\:\\{new\_write\_whatsit}, \[1363], 1364, 1365, 1366.
+\:\\{next}, \[262], 265, 266, 1321, 1345.
+\:\\{next\_break}, \[888], 889.
+\:\\{next\_char}, \[556], 752, 763, 764, 920, 1051, 1472.
+\:\\{next\_p}, \[630], 633, 637, 640, 641, 642, 644, 646.
+\:\\{nh}, 551, 552, \[571], 576, 577, 580.
+\:\\{ni}, 551, 552, \[571], 576, 577, 580.
+\:\&{nil}, 16.
+\:\\{nine\_bits}, \[559], 560, 1336, 1350.
+\:\\{nk}, 551, 552, \[571], 576, 577, 584.
+\:\\{nl}, \[60], 551, 552, 556, \[571], 576, 577, 580, 584, 587.
+\:\\{nn}, \[317], 318.
+\:\.{No pages of output}, 653.
+\:\\{no\_align}, \[214], 271, 272, 796, 1138.
+\:\9{no\_align\_}{\.{\\noalign} primitive}, \[271].
+\:\\{no\_align\_error}, 1138, \[1141].
+\:\\{no\_align\_group}, \[275], 779, 796, 1145.
+\:\9{no\_auto\_spacing\_}{\.{\\noautospacing} primitive}, \[1426].
+\:\9{no\_auto\_xspacing\_}{\.{\\noautoxspacing} primitive}, \[1426].
+\:\\{no\_boundary}, \[214], 271, 272, 1041, 1049, 1057, 1102.
+\:\9{no\_boundary\_}{\.{\\noboundary} primitive}, \[271].
+\:\\{no\_break\_yet}, \[840], 847, 848.
+\:\\{no\_entry}, \[1430], 1435, 1436, 1437, 1440, 1441, 1442, 1443, 1444, 1445,
+1459, 1460.
+\:\\{no\_expand}, \[216], 271, 272, 374, 378.
+\:\9{no\_expand\_}{\.{\\noexpand} primitive}, \[271].
+\:\\{no\_expand\_flag}, \[366], 517.
+\:\9{no\_indent\_}{\.{\\noindent} primitive}, \[1100].
+\:\\{no\_limits}, \[693], 1168, 1169.
+\:\9{no\_limits\_}{\.{\\nolimits} primitive}, \[1168].
+\:\\{no\_new\_control\_sequence}, \[262], 263, 265, 270, 373, 385, 1349.
+\:\\{no\_print}, \[55], 58, 59, 76, 99.
+\:\\{no\_shrink\_error\_yet}, \[836], 837, 838.
+\:\\{no\_skip}, \[1451], 1452, 1453, 1455, 1456, 1457, 1458.
+\:\\{no\_tag}, \[555], 580.
+\:\\{noad\_size}, \[692], 697, 709, 764, 772, 1198, 1199.
+\:\\{node\_list\_display}, \[186], 190, 194, 196, 201, 203.
+\:\\{node\_r\_stays\_active}, \[841], 862, 865.
+\:\\{node\_size}, \[125], 127, 128, 129, 131, 170, 175, 1324, 1325.
+\:\\{nom}, \[571], 572, 574, 587.
+\:\\{non\_address}, \[560], 587, 920, 927, 1045, 1350.
+\:\\{non\_char}, 559, \[560], 587, 908, 909, 912, 919, 920, 921, 922, 926, 927,
+928, 1043, 1045, 1046, 1049, 1050, 1051, 1052, 1336, 1350, 1469.
+\:\\{non\_discardable}, \[154], 890.
+\:\\{non\_math}, \[1058], 1075, 1156.
+\:\\{non\_script}, \[214], 271, 272, 1058, 1183.
+\:\9{non\_script\_}{\.{\\nonscript} primitive}, \[271], \[743].
+\:\\{none\_seen}, \[622], 623.
+\:\.{NONEXISTENT}, 268.
+\:\.{Nonletter}, 973.
+\:\\{nonnegative\_integer}, 70, \[102], 108.
+\:\\{nonstop\_mode}, \[74], 87, 368, 371, 495, 1275, 1276.
+\:\9{nonstop\_mode\_}{\.{\\nonstopmode} primitive}, \[1275].
+\:\\{nop}, 594, 596, \[597], 599, 601.
+\:\\{noreturn}, 82, 94, 95, 96.
+\:\\{norm\_min}, \[1103], 1212, 1389, 1390.
+\:\\{normal}, \[136], 137, 155, 156, 159, 161, 162, 170, 183, 192, 195, 197,
+311, 337, 342, 380, 450, 459, 482, 484, 491, 493, 496, 500, 501, 518, 630, 631,
+636, 640, 645, 661, 668, 669, 670, 671, 675, 676, 677, 678, 683, 684, 685, 687,
+688, 689, 693, 697, 707, 727, 743, 760, 788, 812, 821, 822, 836, 837, 907, 908,
+910, 987, 999, 1015, 1020, 1133, 1168, 1175, 1177, 1193, 1213, 1231, 1232,
+1233, 1252.
+\:\\{normal\_paragraph}, 785, 796, 798, 1036, \[1082], 1095, 1106, 1108, 1111,
+1179.
+\:\\{normalize\_selector}, 79, \[93], 94, 95, 96, 874.
+\:\.{Not a letter}, 948.
+\:\\{not\_found}, \[15], 46, 47, 459, 466, 571, 581, 618, 622, 623, 906, 941,
+942, 945, 952, 964, 966, 981, 983, 984, 1150, 1158, 1378.
+\:\\{not\_kanji\_char\_seq}, 527.
+\:\.{notexpanded:}, 264.
+\:\\{np}, 551, 552, \[571], 576, 577, 586, 587.
+\:\\{nt}, 551, \[571], 576, 577, 580.
+\:\\{nucleus}, \[692], 693, 694, 697, 698, 701, 707, 709, 731, 736, 745, 746,
+747, 748, 749, 752, 753, 760, 761, 763, 764, 765, 766, 1088, 1105, 1162, 1163,
+1167, 1170, 1175, 1177, 1180, 1198, 1203, 1468.
+\:\\{null}, \[116], 117, 119, 121, 123, 124, 126, 127, 136, 137, 139, 150, 151,
+155, 156, 157, 158, 159, 160, 170, 174, 175, 181, 182, 188, 206, 207, 208, 210,
+216, 218, 221, 222, 224, 225, 228, 229, 238, 239, 281, 298, 301, 312, 313, 318,
+320, 325, 331, 337, 365, 366, 382, 385, 393, 394, 397, 401, 402, 403, 408, 411,
+418, 421, 431, 434, 463, 475, 477, 484, 489, 493, 500, 501, 508, 516, 519, 560,
+587, 589, 593, 617, 622, 626, 630, 634, 640, 643, 649, 659, 660, 662, 666, 669,
+675, 677, 679, 684, 687, 692, 696, 700, 703, 726, 729, 730, 731, 732, 737, 742,
+743, 763, 765, 766, 767, 771, 772, 777, 778, 782, 785, 787, 788, 794, 795, 800,
+801, 802, 803, 805, 807, 808, 810, 812, 815, 816, 817, 818, 823, 827, 832, 840,
+848, 851, 857, 858, 859, 861, 867, 868, 869, 870, 874, 875, 876, 878, 880, 883,
+888, 889, 890, 892, 893, 894, 895, 896, 898, 899, 900, 905, 907, 909, 914, 917,
+918, 919, 921, 922, 924, 925, 926, 927, 928, 929, 939, 943, 946, 979, 980, 981,
+983, 984, 988, 989, 990, 992, 1002, 1003, 1004, 1005, 1009, 1010, 1011, 1020,
+1021, 1022, 1023, 1025, 1026, 1027, 1028, 1029, 1031, 1032, 1033, 1034, 1037,
+1038, 1039, 1041, 1043, 1046, 1047, 1048, 1049, 1050, 1052, 1054, 1055, 1082,
+1086, 1087, 1088, 1090, 1091, 1092, 1093, 1095, 1099, 1103, 1122, 1125, 1133,
+1135, 1136, 1143, 1148, 1151, 1157, 1158, 1161, 1163, 1179, 1186, 1188, 1193,
+1196, 1197, 1198, 1206, 1208, 1211, 1214, 1217, 1218, 1238, 1239, 1260, 1261,
+1296, 1301, 1309, 1321, 1324, 1325, 1348, 1350, 1352, 1366, 1367, 1381, 1382,
+1388, 1450, 1451, 1453, 1457, 1463, 1464, 1469, 1470, 1472, 1475.
+\:{null delimiter}, 246, 1077.
+\:\\{null\_character}, \[566], 567, 733, 734, 1408.
+\:\\{null\_code}, \[22], 238, 1383.
+\:\\{null\_cs}, \[228], 268, 269, 362, 385, 1270.
+\:\\{null\_delimiter}, \[695], 696, 1193.
+\:\\{null\_delimiter\_space}, \[253], 717.
+\:\9{null\_delimiter\_space\_}{\.{\\nulldelimiterspace} primitive}, \[254].
+\:\\{null\_delimiter\_space\_code}, \[253], 254.
+\:\\{null\_flag}, \[143], 144, 474, 664, 790, 804, 812.
+\:\\{null\_font}, \[238], 564, 571, 588, 628, 674, 717, 718, 733, 875, 1270,
+1335, 1336, 1350, 1352, 1416, 1469.
+\:\9{null\_font\_}{\.{\\nullfont} primitive}, \[564].
+\:\\{null\_list}, 14, \[168], 391, 791.
+\:\\{num}, \[461], 469, 596, \[598], 601.
+\:\\{num\_style}, \[713], 755.
+\:\.{Number too big}, 456.
+\:\9{number\_}{\.{\\number} primitive}, \[479].
+\:\\{number\_code}, \[479], 480, 481, 482, 483.
+\:\\{numerator}, \[694], 701, 708, 709, 755, 1193, 1197.
+\:\\{num1}, \[711], 755.
+\:\\{num2}, \[711], 755.
+\:\\{num3}, \[711], 755.
+\:\\{nw}, 551, 552, \[571], 576, 577, 580.
+\:\\{nx\_plus\_y}, \[106], 466, 727, 1253.
+\:\|{o}, \[270], \[618], \[660], \[679], \[802], \[811].
+\:\\{octal\_token}, \[449], 455.
+\:\\{odd}, 63, 101, 199, 515, 769, 909, 913, 919, 920, 924, 925, 1223, 1230.
+\:\\{off\_save}, 1075, \[1076], 1106, 1107, 1142, 1143, 1152, 1204, 1205.
+\:\.{OK}, 1311.
+\:\\{OK\_so\_far}, \[451], 456.
+\:\\{OK\_to\_interrupt}, 89, \[97], 98, 99, 333, 1042.
+\:\\{old\_l}, \[840], 846, 861.
+\:\\{old\_mode}, \[1383], 1384.
+\:\\{old\_rover}, \[132].
+\:\\{old\_setting}, 251, \[252], \[317], 318, \[476], \[481], \[545], 628, %
+\[649], \[1270], \[1292], \[1381], \[1383], \[1386], 1387.
+\:\\{omit}, \[214], 271, 272, 799, 800, 1138.
+\:\9{omit\_}{\.{\\omit} primitive}, \[271].
+\:\\{omit\_error}, 1138, \[1141].
+\:\\{omit\_template}, \[168], 800, 801.
+\:\.{Only one \# is allowed...}, 795.
+\:\\{op\_byte}, \[556], 568, 752, 763, 764, 920, 922, 1052, 1472.
+\:\\{op\_noad}, \[693], 701, 707, 709, 737, 739, 744, 760, 772, 1168, 1169,
+1171.
+\:\\{op\_start}, 931, \[932], 935, 956, 1338.
+\:\\{open\_area}, \[1354], 1364, 1369, 1387.
+\:\\{open\_ext}, \[1354], 1364, 1369, 1387.
+\:\\{open\_fmt\_file}, \[535], 1350.
+\:\9{open\_in\_}{\.{\\openin} primitive}, \[1285].
+\:\\{open\_input}, 548, 1288.
+\:\\{open\_log\_file}, 79, 93, 368, 482, 543, \[545], 546, 548, 1270, 1348,
+1383.
+\:\\{open\_name}, \[1354], 1364, 1369, 1387.
+\:\\{open\_noad}, \[693], 701, 707, 709, 739, 744, 772, 773, 1168, 1169.
+\:\\{open\_node}, \[1354], 1357, 1359, 1361, 1369, 1370, 1371, 1386.
+\:\\{open\_node\_size}, \[1354], 1364, 1370, 1371.
+\:\\{open\_or\_close\_in}, 1287, \[1288].
+\:\9{open\_out\_}{\.{\\openout} primitive}, \[1357].
+\:\\{open\_parens}, \[310], 337, 370, 548, 1348.
+\:\9{or\_}{\.{\\or} primitive}, \[502].
+\:\\{or\_code}, \[500], 502, 503, 511, 520.
+\:\\{ord}, 20.
+\:\\{ord\_noad}, 692, \[693], 697, 698, 701, 707, 709, 739, 740, 744, 763, 764,
+772, 775, 776, 1087, 1167, 1168, 1169, 1198, 1468.
+\:\\{order}, \[183].
+\:{oriental characters}, 135, 596.
+\:\\{orig\_char\_info}, \[565], 581, 584, 587, 593, 631, 719, 726, 733, 751,
+760, 852, 853, 878, 881, 882, 1159, 1407, 1408, 1418, 1419, 1469.
+\:\\{orig\_char\_info\_end}, \[565].
+\:\\{other\_A\_token}, \[456].
+\:\\{other\_char}, \[213], 238, 295, 297, 300, 304, 353, 456, 475, 537, 946,
+972, 1041, 1049, 1102, 1136, 1163, 1166, 1172, 1469.
+\:\\{other\_kchar}, \[213], 238, 300, 304, 353, 362, 364, 373, 391, 392, 453,
+482, 517, 537, 1041, 1049, 1102, 1136, 1163, 1166, 1469.
+\:\\{other\_token}, \[295], 416, 449, 452, 456, 475, 514, 1077, 1233.
+\:\&{othercases}, \[10].
+\:\\{others}, 10.
+\:\.{Ouch...clobbered}, 1345.
+\:\\{out\_param}, \[213], 295, 297, 300, 365.
+\:\\{out\_param\_token}, \[295], 490.
+\:\\{out\_what}, 1379, 1380, \[1386], 1388.
+\:\9{outer\_}{\.{\\outer} primitive}, \[1220].
+\:\\{outer\_call}, \[216], 281, 345, 359, 361, 362, 365, 374, 398, 402, 407,
+791, 1164, 1308, 1382.
+\:\\{outer\_doing\_leaders}, \[630], 639, \[640], 648.
+\:\.{Output loop...}, 1035.
+\:\.{Output routine didn't use...}, 1039.
+\:\.{Output written on x}, 653.
+\:\9{output\_}{\.{\\output} primitive}, \[236].
+\:\\{output\_active}, 432, 674, 686, 997, \[1000], 1001, 1005, 1016, 1036, 1037.
+\:\\{output\_comment}, 628, \[1394].
+\:\\{output\_file\_name}, \[543], 544, 653.
+\:\\{output\_group}, \[275], 1036, 1112.
+\:\\{output\_penalty}, \[242].
+\:\9{output\_penalty\_}{\.{\\outputpenalty} primitive}, \[244].
+\:\\{output\_penalty\_code}, \[242], 243, 244, 1024.
+\:\\{output\_routine}, \[236], 1023, 1036.
+\:\\{output\_routine\_loc}, \[236], 237, 238, 313, 329, 1238.
+\:\\{output\_text}, \[313], 320, 329, 1036, 1037.
+\:\9{over\_}{\.{\\over} primitive}, \[1190].
+\:\\{over\_code}, \[1190], 1191, 1194.
+\:\\{over\_noad}, \[698], 701, 707, 709, 744, 772, 1168.
+\:\9{over\_with\_delims\_}{\.{\\overwithdelims} primitive}, \[1190].
+\:\\{overbar}, \[716], 745, 748.
+\:\\{overflow}, 36, 43, 44, \[95], 121, 126, 222, 266, 279, 280, 327, 334, 377,
+385, 401, 528, 591, 951, 955, 965, 975, 1346.
+\:{overflow in arithmetic}, 9, 105.
+\:\.{Overfull \\hbox...}, 677.
+\:\.{Overfull \\vbox...}, 688.
+\:{overfull boxes}, 865.
+\:\\{overfull\_rule}, \[253], 677, 811, 815.
+\:\9{overfull\_rule\_}{\.{\\overfullrule} primitive}, \[254].
+\:\\{overfull\_rule\_code}, \[253], 254.
+\:\9{overline\_}{\.{\\overline} primitive}, \[1168].
+\:\|{p}, \[121], \[124], \[126], \[131], \[132], \[137], \[139], \[144], %
+\[150], \[151], \[153], \[157], \[158], \[159], \[160], \[162], \[164], \[173],
+\[178], \[180], \[182], \[184], \[188], \[204], \[206], \[207], \[208], \[210],
+\[224], \[265], \[268], \[269], \[282], \[283], \[284], \[285], \[287], \[290],
+\[298], \[301], \[312], \[321], \[329], \[331], \[342], \[377], \[400], \[418],
+\[424], \[461], \[475], \[476], \[484], \[493], \[508], \[509], \[593], \[618],
+\[626], \[630], \[640], \[649], \[660], \[679], \[690], \[697], \[699], \[700],
+\[702], \[703], \[715], \[716], \[720], \[722], \[726], \[727], \[728], \[731],
+\[737], \[746], \[749], \[754], \[760], \[763], \[767], \[783], \[785], \[798],
+\[802], \[810], \[811], \[837], \[917], \[945], \[959], \[960], \[964], \[968],
+\[970], \[971], \[977], \[979], \[981], \[1004], \[1005], \[1023], \[1076], %
+\[1080], \[1087], \[1091], \[1098], \[1105], \[1113], \[1117], \[1122], %
+\[1125], \[1131], \[1135], \[1150], \[1163], \[1167], \[1172], \[1186], %
+\[1188], \[1196], \[1203], \[1206], \[1223], \[1249], \[1257], \[1260], %
+\[1301], \[1306], \[1315], \[1316], \[1361], \[1362], \[1368], \[1381], %
+\[1383], \[1386], \[1435], \[1440], \[1450], \[1468].
+\:\\{pack\_begin\_line}, \[672], 673, 674, 686, 815, 826.
+\:\\{pack\_buffered\_name}, \[534], 535.
+\:\\{pack\_cur\_name}, \[540], 541, 548, 1288, 1387.
+\:\\{pack\_file\_name}, \[530], 540, 574.
+\:\\{pack\_job\_name}, \[540], 543, 545, 1341.
+\:\\{pack\_lig}, \[1046], 1050.
+\:\\{package}, 1097, \[1098].
+\:\\{packed\_ASCII\_code}, \[39], 40, 958, 1323, 1345, 1350.
+\:\\{page}, \[310].
+\:\\{page\_contents}, 221, 432, \[991], 997, 998, 1002, 1011, 1012, 1019.
+\:\\{page\_depth}, 221, \[993], 998, 1002, 1013, 1014, 1015, 1019, 1021.
+\:\9{page\_depth\_}{\.{\\pagedepth} primitive}, \[994].
+\:\\{page\_dir}, 1028, 1085, \[1446], 1447.
+\:\9{page\_fil\_stretch\_}{\.{\\pagefilstretch} primitive}, \[994].
+\:\9{page\_fill\_stretch\_}{\.{\\pagefillstretch} primitive}, \[994].
+\:\9{page\_filll\_stretch\_}{\.{\\pagefilllstretch} primitive}, \[994].
+\:\\{page\_goal}, 991, \[993], 997, 998, 1016, 1017, 1018, 1019, 1020, 1021.
+\:\9{page\_goal\_}{\.{\\pagegoal} primitive}, \[994].
+\:\\{page\_head}, \[168], 221, 991, 997, 999, 1002, 1025, 1028, 1034, 1037,
+1066, 1321.
+\:\\{page\_ins\_head}, \[168], 992, 997, 1016, 1019, 1029, 1030, 1031.
+\:\\{page\_ins\_node\_size}, \[992], 1020, 1030.
+\:\\{page\_loc}, \[649], 651.
+\:\\{page\_max\_depth}, 221, \[991], 993, 998, 1002, 1014, 1028.
+\:\\{page\_shrink}, \[993], 996, 1015, 1018, 1019, 1020.
+\:\9{page\_shrink\_}{\.{\\pageshrink} primitive}, \[994].
+\:\\{page\_so\_far}, 432, \[993], 996, 998, 1015, 1018, 1020, 1258.
+\:\\{page\_stack}, \[310].
+\:\9{page\_stretch\_}{\.{\\pagestretch} primitive}, \[994].
+\:\\{page\_tail}, 221, \[991], 997, 1002, 1009, 1011, 1028, 1034, 1037, 1066,
+1321.
+\:\\{page\_total}, \[993], 996, 1013, 1014, 1015, 1018, 1019, 1021.
+\:\9{page\_total\_}{\.{\\pagetotal} primitive}, \[994].
+\:\\{panicking}, \[171], 172, 1042, 1352.
+\:\9{par\_}{\.{\\par} primitive}, \[340].
+\:\\{par\_end}, \[213], 340, 341, 1058, 1106.
+\:\\{par\_fill\_skip}, \[230], 827.
+\:\9{par\_fill\_skip\_}{\.{\\parfillskip} primitive}, \[232].
+\:\\{par\_fill\_skip\_code}, \[230], 231, 232, 827.
+\:\\{par\_indent}, \[253], 1103, 1105.
+\:\9{par\_indent\_}{\.{\\parindent} primitive}, \[254].
+\:\\{par\_indent\_code}, \[253], 254.
+\:\\{par\_loc}, \[339], 340, 359, 1326, 1327.
+\:\9{par\_shape\_}{\.{\\parshape} primitive}, \[271].
+\:\\{par\_shape\_loc}, \[236], 238, 239, 1082, 1261.
+\:\\{par\_shape\_ptr}, \[236], 238, 239, 434, 825, 858, 859, 861, 900, 1082,
+1161, 1262.
+\:\\{par\_skip}, \[230], 1103.
+\:\9{par\_skip\_}{\.{\\parskip} primitive}, \[232].
+\:\\{par\_skip\_code}, \[230], 231, 232, 1103.
+\:\\{par\_token}, \[339], 340, 345, 403, 406, 410, 1107, 1327.
+\:\.{Paragraph ended before...}, 407.
+\:\\{param}, 553, 558, \[569].
+\:\\{param\_base}, \[561], 569, 577, 585, 586, 587, 589, 591, 711, 712, 1054,
+1335, 1336, 1350.
+\:\\{param\_end}, \[569].
+\:\\{param\_ptr}, \[314], 329, 330, 337, 401.
+\:\\{param\_size}, \[33], 314, 401, 1345, 1347.
+\:\\{param\_stack}, 313, \[314], 330, 367, 399, 400, 401, 1345.
+\:\\{param\_start}, \[313], 329, 330, 367.
+\:\\{parameter}, \[313], 320, 367.
+\:{parameters for symbols}, 711, 712.
+\:\.{Parameters...consecutively}, 487.
+\:\\{parse\_first\_line\_p}, \[33], 62, 547.
+\:\9{PASCAL H}{\ph}, \[3], 9, 10.
+\:\9{PASCAL}{\PASCAL}, 1, 10, 704, 775.
+\:\\{pass\_number}, \[832], 856, 875.
+\:\\{pass\_text}, 377, \[505], 511, 520, 521.
+\:\\{passive}, \[832], 856, 857, 875, 876.
+\:\\{passive\_node\_size}, \[832], 856, 876.
+\:\.{Patterns can be...}, 1265.
+\:\9{patterns\_}{\.{\\patterns} primitive}, \[1263].
+\:\\{pause\_for\_instructions}, 97, \[99].
+\:\\{pausing}, \[242], 371.
+\:\9{pausing\_}{\.{\\pausing} primitive}, \[244].
+\:\\{pausing\_code}, \[242], 243, 244.
+\:\\{pc}, 192.
+\:\.{pc}, 469.
+\:\\{pdisp}, \[1091], 1092, \[1117].
+\:\\{pdisp\_field}, \[218], 219.
+\:\\{pen}, \[737], 772, 778, \[888], 901.
+\:{penalties}, 1114.
+\:\\{penalties}, \[737], 778.
+\:\\{penalty}, \[163], 164, 200, 435, 827, 877, 984, 1007, 1011, 1021, 1022,
+1024, 1443, 1444, 1463.
+\:\9{penalty\_}{\.{\\penalty} primitive}, \[271].
+\:\\{penalty\_node}, \[163], 164, 189, 208, 212, 435, 741, 772, 778, 827, 828,
+848, 867, 877, 890, 907, 910, 979, 984, 1007, 1011, 1021, 1022, 1024, 1119,
+1122, 1133, 1443, 1444, 1450, 1451, 1463, 1464.
+\:\\{pf}, 1451.
+\:\\{pg\_field}, \[218], 219, 224, 225, 433, 1257.
+\:\\{pi}, \[840], 842, 862, 867, 870, \[981], 983, 984, 985, \[1005], 1011,
+1016, 1017.
+\:\.{plain}, 532, 535, 1344.
+\:{Plass, Michael Frederick}, 2, 824.
+\:\.{Please type...}, 368, 541.
+\:\.{Please use \\mathaccent...}, 1178.
+\:\.{PLtoTF}, 572.
+\:\.{plus}, 473.
+\:\\{pnode\_field}, \[218], 219.
+\:\\{point\_token}, \[449], 451, 459, 463.
+\:\\{pointer}, \[116], 117, 119, 121, 124, 125, 126, 131, 132, 137, 139, 144,
+150, 151, 153, 157, 158, 159, 160, 162, 164, 171, 173, 178, 204, 206, 207, 208,
+210, 218, 224, 258, 262, 265, 269, 281, 282, 283, 284, 285, 287, 290, 301, 303,
+311, 312, 314, 317, 329, 331, 339, 342, 377, 393, 399, 400, 418, 424, 461, 472,
+474, 475, 476, 484, 493, 500, 508, 509, 560, 571, 593, 603, 616, 618, 626, 630,
+640, 649, 658, 660, 679, 690, 697, 699, 700, 702, 703, 715, 716, 717, 720, 722,
+726, 727, 728, 730, 731, 733, 737, 745, 746, 747, 748, 749, 754, 760, 763, 767,
+773, 781, 783, 785, 798, 802, 810, 811, 825, 832, 837, 839, 840, 841, 844, 873,
+883, 888, 903, 911, 912, 917, 918, 923, 937, 945, 979, 981, 988, 991, 993,
+1004, 1005, 1023, 1041, 1043, 1055, 1076, 1080, 1086, 1087, 1091, 1098, 1105,
+1113, 1117, 1122, 1125, 1131, 1135, 1150, 1163, 1167, 1172, 1186, 1188, 1196,
+1203, 1206, 1210, 1223, 1249, 1260, 1270, 1301, 1306, 1315, 1316, 1358, 1361,
+1362, 1368, 1381, 1383, 1386, 1416, 1435, 1440, 1449, 1450, 1451, 1465, 1468,
+1475.
+\:{Poirot, Hercule}, 1296.
+\:\\{pool\_file}, 48, \[51], 52, 53, 54.
+\:\\{pool\_free}, \[33], 1323, 1345.
+\:\\{pool\_name}, \[11], 52, 53, 54, 1321.
+\:\\{pool\_pointer}, \[39], 40, 46, 47, 60, 61, 70, 71, 270, 418, 475, 476,
+481, 524, 528, 529, 530, 536, 613, 649, 940, 945, 1323, 1345, 1381, 1392, 1394.
+\:\\{pool\_ptr}, 39, \[40], 42, 43, 44, 45, 48, 53, 59, 71, 204, 266, 475, 476,
+481, 527, 528, 536, 628, 1322, 1323, 1345, 1347, 1352, 1381, 1383.
+\:\\{pool\_size}, \[33], 43, 53, 59, 204, 536, 1323, 1345, 1347, 1352, 1381.
+\:\\{pop}, 595, 596, \[597], 601, 612, 619, 653, 1413.
+\:\\{pop\_alignment}, \[783], 811.
+\:\\{pop\_input}, \[328], 330, 335.
+\:\\{pop\_lig\_stack}, \[921], 922.
+\:\\{pop\_nest}, \[223], 807, 810, 823, 827, 1037, 1098, 1108, 1112, 1131,
+1157, 1180, 1196, 1218.
+\:\\{positive}, \[108].
+\:\\{post}, 594, 596, \[597], 601, 602, 653.
+\:\\{post\_break}, \[151], 181, 201, 208, 212, 851, 869, 893, 895, 927, 1131.
+\:\9{post\_break\_penalty\_}{\.{\\postbreakpenalty} primitive}, \[1438].
+\:\\{post\_break\_penalty\_code}, \[1438], 1439, 1441, 1443, 1445.
+\:\\{post\_disc\_break}, \[888], 892, 895.
+\:\\{post\_display\_penalty}, \[242], 1217, 1218.
+\:\9{post\_display\_penalty\_}{\.{\\postdisplaypenalty} primitive}, \[244].
+\:\\{post\_display\_penalty\_code}, \[242], 243, 244.
+\:\\{post\_f}, \[873], 878.
+\:\\{post\_line\_break}, 887, \[888].
+\:\\{post\_p}, \[873], 878.
+\:\\{post\_post}, 596, \[597], 601, 602, 653.
+\:\\{pre}, 594, 596, \[597], 628.
+\:\\{pre\_break}, \[151], 181, 201, 208, 212, 869, 880, 893, 896, 926, 1129,
+1131.
+\:\9{pre\_break\_penalty\_}{\.{\\prebreakpenalty} primitive}, \[1438].
+\:\\{pre\_break\_penalty\_code}, \[1438], 1439, 1441, 1443, 1444.
+\:\\{pre\_display\_penalty}, \[242], 1215, 1218.
+\:\9{pre\_display\_penalty\_}{\.{\\predisplaypenalty} primitive}, \[244].
+\:\\{pre\_display\_penalty\_code}, \[242], 243, 244.
+\:\\{pre\_display\_size}, \[253], 1150, 1157, 1160, 1215.
+\:\9{pre\_display\_size\_}{\.{\\predisplaysize} primitive}, \[254].
+\:\\{pre\_display\_size\_code}, \[253], 254, 1157.
+\:{preamble}, 779, 785.
+\:\\{preamble}, \[781], 782, 783, 788, 797, 812, 815.
+\:{preamble of \.{DVI} file}, 628.
+\:\\{precedes\_break}, \[154], 879, 984, 1011.
+\:\\{prefix}, \[215], 1220, 1221, 1222, 1223.
+\:\\{prefixed\_command}, 1222, \[1223], 1283.
+\:\\{prepare\_mag}, \[294], 468, 628, 653, 1346.
+\:\\{pretolerance}, \[242], 839, 874.
+\:\9{pretolerance\_}{\.{\\pretolerance} primitive}, \[244].
+\:\\{pretolerance\_code}, \[242], 243, 244.
+\:\\{prev\_append}, \[220], 1073, 1112, 1113, 1115.
+\:\\{prev\_break}, \[832], 856, 857, 888, 889.
+\:\\{prev\_char}, \[55], 526, 527.
+\:\\{prev\_depth}, 218, \[219], 221, 429, 690, 786, 797, 798, 1036, 1068, 1095,
+1111, 1179, 1218, 1255, 1256.
+\:\9{prev\_depth\_}{\.{\\prevdepth} primitive}, \[427].
+\:\\{prev\_disp}, \[219], 221, 222, 1092, 1122, 1132, 1470, 1471.
+\:\\{prev\_dp}, \[981], 983, 984, 985, 987.
+\:\\{prev\_graf}, 218, \[219], 221, 222, 433, 825, 827, 875, 888, 901, 1103,
+1161, 1212, 1255.
+\:\9{prev\_graf\_}{\.{\\prevgraf} primitive}, \[271].
+\:\\{prev\_node}, \[219], 220, 221, 222, 435, 827, 1053, 1055, 1073, 1092,
+1122, 1125, 1132, 1470, 1471.
+\:\\{prev\_p}, \[873], 874, 877, 878, 879, 880, \[979], 980, \[981], 984, %
+\[1023], 1025, 1028, 1033.
+\:\\{prev\_prev\_r}, \[841], 843, 854, 855, 871.
+\:\\{prev\_r}, \[840], 841, 843, 854, 855, 856, 862, 865, 871.
+\:\\{prev\_s}, \[873], 905, 907.
+\:\\{primitive}, 232, 236, 244, 254, \[270], 271, 272, 304, 340, 387, 395, 422,
+427, 479, 498, 502, 564, 791, 994, 1064, 1070, 1083, 1100, 1119, 1126, 1153,
+1168, 1181, 1190, 1200, 1220, 1231, 1234, 1242, 1263, 1267, 1275, 1285, 1290,
+1299, 1304, 1344, 1345, 1357, 1421, 1426, 1433, 1438.
+\:\\{print}, 55, \[60], 61, 63, 64, 69, 71, 72, 74, 86, 87, 90, 92, 95, 96,
+181, 183, 184, 188, 189, 190, 191, 192, 193, 194, 196, 197, 198, 199, 200, 201,
+217, 224, 225, 231, 239, 240, 241, 243, 253, 257, 258, 268, 269, 290, 294, 300,
+304, 305, 323, 324, 329, 342, 344, 345, 371, 384, 406, 407, 409, 411, 439, 465,
+467, 470, 476, 483, 513, 520, 529, 541, 545, 547, 572, 578, 590, 592, 628, 649,
+650, 653, 671, 674, 677, 685, 686, 688, 703, 705, 708, 734, 787, 857, 867, 947,
+989, 996, 997, 998, 1017, 1022, 1026, 1035, 1076, 1085, 1107, 1144, 1178, 1225,
+1236, 1244, 1250, 1270, 1272, 1274, 1308, 1309, 1311, 1322, 1324, 1331, 1333,
+1335, 1337, 1341, 1347, 1348, 1351, 1352, 1359, 1369, 1383, 1387, 1398, 1407,
+1411, 1412, 1427, 1429, 1440, 1441, 1467.
+\:\\{print\_ASCII}, \[69], 180, 182, 304, 592, 702, 734, 1236, 1407, 1411, 1412.
+\:\\{print\_c\_string}, 541.
+\:\\{print\_char}, \[59], 60, 61, 65, 66, 67, 68, 70, 71, 83, 92, 95, 96, 104,
+115, 177, 178, 180, 181, 182, 183, 184, 190, 192, 193, 194, 195, 196, 197, 199,
+224, 229, 235, 239, 240, 241, 248, 257, 258, 261, 268, 290, 291, 300, 302, 305,
+312, 319, 323, 370, 483, 520, 529, 547, 548, 572, 592, 628, 649, 650, 702, 734,
+857, 867, 944, 1017, 1022, 1077, 1081, 1224, 1225, 1236, 1293, 1307, 1309,
+1324, 1335, 1341, 1346, 1348, 1352, 1353, 1368, 1369, 1383, 1407, 1411, 1412,
+1423, 1436, 1441, 1467, 1473.
+\:\\{print\_cmd\_chr}, 229, 239, 272, 302, \[304], 305, 329, 342, 429, 439,
+514, 521, 1061, 1078, 1085, 1140, 1224, 1225, 1250, 1348, 1352.
+\:\\{print\_cs}, \[268], 299, 320, 412.
+\:\\{print\_csnames}, 1332, \[1395].
+\:\\{print\_current\_string}, \[71], 188, 703.
+\:\\{print\_delimiter}, \[702], 707, 708.
+\:\\{print\_dir}, 194, \[1467].
+\:\\{print\_direction}, 190, 224, \[1467].
+\:\\{print\_err}, 73, \[74], 94, 95, 96, 99, 294, 342, 344, 352, 381, 384, 406,
+407, 409, 414, 419, 426, 429, 439, 444, 445, 446, 447, 448, 453, 456, 457, 465,
+467, 470, 471, 486, 487, 490, 497, 511, 514, 521, 541, 572, 588, 590, 652, 734,
+787, 794, 795, 803, 837, 947, 948, 971, 972, 973, 974, 987, 989, 1004, 1015,
+1020, 1026, 1031, 1035, 1038, 1039, 1059, 1061, 1076, 1078, 1080, 1081, 1085,
+1090, 1094, 1096, 1107, 1111, 1112, 1122, 1132, 1133, 1139, 1140, 1141, 1144,
+1147, 1163, 1167, 1171, 1173, 1178, 1189, 1195, 1204, 1207, 1209, 1219, 1224,
+1225, 1227, 1237, 1244, 1249, 1250, 1254, 1256, 1257, 1265, 1271, 1272, 1296,
+1311, 1317, 1385, 1399, 1423, 1436, 1441, 1468.
+\:\\{print\_esc}, \[64], 87, 182, 189, 190, 193, 194, 195, 196, 197, 198, 200,
+201, 202, 203, 231, 233, 235, 237, 239, 240, 241, 243, 245, 248, 253, 255, 257,
+268, 269, 272, 273, 298, 299, 300, 329, 341, 384, 388, 396, 423, 428, 439, 480,
+497, 499, 503, 511, 590, 702, 705, 706, 707, 708, 710, 787, 792, 803, 867, 947,
+971, 972, 989, 995, 997, 1020, 1026, 1039, 1065, 1071, 1077, 1081, 1084, 1101,
+1107, 1111, 1120, 1127, 1132, 1141, 1144, 1147, 1155, 1169, 1178, 1191, 1201,
+1204, 1221, 1225, 1232, 1235, 1243, 1254, 1257, 1264, 1268, 1276, 1286, 1291,
+1300, 1305, 1308, 1335, 1348, 1359, 1368, 1369, 1422, 1427, 1434, 1439.
+\:\\{print\_fam\_and\_char}, \[702], 703, 707.
+\:\\{print\_file\_line}, 74, \[1398].
+\:\\{print\_file\_name}, \[529], 541, 572, 653, 1335, 1346, 1369, 1387.
+\:\\{print\_font\_and\_char}, \[182], 189, 199.
+\:\\{print\_glue}, \[183], 184, 191, 192.
+\:\\{print\_hex}, \[68], 702, 1235, 1423, 1436, 1441.
+\:\\{print\_in\_mode}, \[217], 1061.
+\:\\{print\_int}, \[66], 92, 95, 104, 115, 174, 175, 176, 177, 178, 191, 194,
+200, 201, 224, 225, 233, 235, 237, 239, 240, 241, 245, 248, 255, 257, 261, 291,
+294, 319, 342, 411, 476, 483, 520, 547, 572, 590, 628, 649, 650, 653, 671, 674,
+678, 685, 686, 689, 702, 734, 857, 867, 944, 997, 1017, 1020, 1022, 1035, 1039,
+1111, 1244, 1309, 1322, 1324, 1331, 1333, 1337, 1341, 1348, 1352, 1368, 1369,
+1387, 1398, 1423, 1440.
+\:\\{print\_kanji}, 180, 182, 300, 304, 483, 702, 1425, \[1473].
+\:\\{print\_kansuji}, 483, 1424, \[1425].
+\:\\{print\_lc\_hex}, \[592].
+\:\\{print\_length\_param}, \[253], 255, 257.
+\:\\{print\_ln}, \[58], 59, 60, 62, 63, 72, 87, 90, 91, 115, 188, 204, 224,
+242, 251, 302, 312, 320, 323, 336, 368, 371, 412, 495, 541, 545, 548, 649, 650,
+671, 674, 677, 678, 685, 686, 688, 689, 703, 997, 1278, 1293, 1322, 1324, 1331,
+1333, 1337, 1346, 1353, 1383, 1387, 1440.
+\:\\{print\_locs}, \[173].
+\:\\{print\_mark}, \[182], 202, 1369.
+\:\\{print\_meaning}, \[302], 483, 1307.
+\:\\{print\_mode}, \[217], 224, 305.
+\:\\{print\_nl}, \[63], 74, 83, 86, 91, 174, 175, 176, 177, 178, 224, 225, 251,
+261, 291, 294, 305, 312, 317, 319, 320, 329, 368, 411, 541, 545, 592, 649, 650,
+652, 653, 671, 677, 678, 685, 688, 689, 857, 867, 868, 874, 944, 997, 998,
+1003, 1017, 1022, 1133, 1236, 1307, 1309, 1310, 1335, 1337, 1341, 1346, 1348,
+1351, 1383, 1387, 1398, 1407, 1411, 1412, 1429.
+\:\\{print\_param}, \[243], 245, 248.
+\:\\{print\_plus}, \[996].
+\:\\{print\_plus\_end}, \[996].
+\:\\{print\_quoted}, \[529].
+\:\\{print\_roman\_int}, \[70], 483.
+\:\\{print\_rule\_dimen}, \[182], 193.
+\:\\{print\_scaled}, \[104], 115, 182, 183, 184, 189, 190, 194, 197, 198, 225,
+257, 476, 483, 572, 677, 688, 708, 996, 997, 998, 1017, 1022, 1272, 1274, 1335,
+1352.
+\:\\{print\_size}, \[710], 734, 1243.
+\:\\{print\_skip\_param}, 195, \[231], 233, 235.
+\:\\{print\_spec}, \[184], 194, 195, 196, 235, 476.
+\:\\{print\_style}, 701, \[705], 1182.
+\:\\{print\_subsidiary\_data}, \[703], 707, 708.
+\:\\{print\_the\_digs}, \[65], 66, 68.
+\:\\{print\_totals}, 224, \[996], 997, 1017.
+\:\\{print\_two}, \[67], 547, 628.
+\:\\{print\_word}, \[115], 1352.
+\:\\{print\_write\_whatsit}, \[1368], 1369.
+\:\\{printed\_node}, \[832], 867, 868, 869, 875.
+\:\\{privileged}, \[1063], 1066, 1142, 1152.
+\:\\{prompt\_file\_name}, \[541], 543, 546, 548, 1341, 1387.
+\:\\{prompt\_file\_name\_help\_msg}, 541.
+\:\\{prompt\_input}, \[72], 84, 88, 368, 371, 495, 541.
+\:\\{prune\_movements}, \[626], 630, 640.
+\:\\{prune\_page\_top}, \[979], 988, 1032.
+\:\\{pseudo}, \[55], 58, 59, 60, 322.
+\:\\{pstack}, \[399], 401, 407, 411.
+\:\.{pt}, 464.
+\:\\{pTeX\_banner}, \[2].
+\:\\{pTeX\_banner\_k}, \[2].
+\:\\{ptex\_convert\_codes}, \[479].
+\:\\{pTeX\_version\_string}, \[2].
+\:\\{punct\_noad}, \[693], 701, 707, 709, 739, 763, 772, 1168, 1169.
+\:\\{push}, 595, 596, \[597], 601, 603, 612, 619, 627, 630, 640, 1413.
+\:\\{push\_alignment}, \[783], 785.
+\:\\{push\_input}, \[327], 329, 331, 334.
+\:\\{push\_math}, \[1148], 1151, 1157, 1165, 1184, 1186, 1203.
+\:\\{push\_nest}, \[222], 785, 797, 798, 1036, 1095, 1103, 1111, 1129, 1131,
+1148, 1179, 1212.
+\:\\{put}, 26, 30.
+\:\\{put\_byte}, 1395.
+\:\\{put\_rule}, 596, \[597], 644.
+\:\\{put1}, \[596].
+\:\\{put2}, \[596].
+\:\\{put3}, \[596].
+\:\\{put4}, \[596].
+\:\|{q}, \[124], \[126], \[131], \[132], \[150], \[157], \[158], \[159], %
+\[173], \[178], \[208], \[210], \[224], \[281], \[298], \[321], \[342], \[377],
+\[400], \[418], \[424], \[461], \[472], \[474], \[475], \[476], \[484], \[493],
+\[508], \[509], \[618], \[660], \[716], \[717], \[720], \[723], \[731], \[737],
+\[745], \[746], \[747], \[748], \[749], \[754], \[760], \[763], \[767], \[773],
+\[802], \[811], \[837], \[841], \[873], \[888], \[912], \[917], \[945], \[959],
+\[964], \[968], \[970], \[971], \[979], \[981], \[1005], \[1023], \[1055], %
+\[1080], \[1091], \[1105], \[1117], \[1131], \[1135], \[1150], \[1163], %
+\[1196], \[1210], \[1223], \[1249], \[1315], \[1316], \[1383], \[1451], \[1475].
+\:\\{qi}, \[113], 136, 556, 560, 575, 581, 584, 587, 593, 631, 733, 763, 764,
+918, 919, 922, 924, 934, 969, 970, 992, 1019, 1020, 1045, 1046, 1047, 1049,
+1051, 1052, 1112, 1163, 1167, 1172, 1177, 1322, 1338, 1407, 1408, 1411, 1418,
+1419, 1468, 1469, 1472.
+\:\\{qo}, \[113], 136, 165, 180, 182, 191, 194, 565, 581, 587, 593, 613, 631,
+702, 719, 733, 734, 752, 763, 766, 907, 908, 909, 914, 920, 934, 956, 992, 997,
+1019, 1029, 1031, 1032, 1047, 1051, 1323, 1337, 1338, 1407, 1408, 1411, 1412,
+1452, 1454, 1455, 1456, 1457, 1458, 1469, 1472.
+\:\\{qqqq}, 111, 115, 561, 565, 580, 584, 585, 694, 724, 752, 763, 920, 1051,
+1193, 1352, 1472.
+\:\\{quad}, 558, \[569], 1158.
+\:\\{quad\_code}, \[558], 569.
+\:\\{quarterword}, 111, \[114], 150, 259, 270, 277, 282, 283, 285, 287, 304,
+306, 329, 593, 603, 692, 717, 720, 722, 723, 735, 749, 760, 888, 932, 1073,
+1091, 1117, 1338, 1350, 1407, 1408.
+\:\\{quoted\_filename}, \[33], 526, 527.
+\:\\{qw}, \[571], 575, 581, 584, 587.
+\:\\{qx}, \[424], 431.
+\:\|{r}, \[109], \[124], \[126], \[132], \[210], \[224], \[377], \[400], %
+\[424], \[476], \[493], \[509], \[660], \[679], \[717], \[731], \[737], \[763],
+\[802], \[811], \[840], \[873], \[888], \[912], \[964], \[977], \[981], %
+\[1005], \[1023], \[1080], \[1091], \[1117], \[1135], \[1172], \[1210], %
+\[1249], \[1383].
+\:\\{r\_count}, \[923], 925, 929.
+\:\\{r\_hyf}, 902, \[903], 905, 910, 913, 934, 1375.
+\:\\{r\_type}, \[737], 738, 739, 740, 771, 777, 778.
+\:\\{radical}, \[214], 271, 272, 1058, 1174.
+\:\9{radical\_}{\.{\\radical} primitive}, \[271].
+\:\\{radical\_noad}, \[694], 701, 707, 709, 744, 772, 1175.
+\:\\{radical\_noad\_size}, \[694], 709, 772, 1175.
+\:\\{radix}, 377, \[449], 450, 451, 455, 456, 459.
+\:\\{radix\_backup}, \[377].
+\:\9{raise\_}{\.{\\raise} primitive}, \[1083].
+\:{Ramshaw, Lyle Harold}, 550.
+\:\\{rbrace\_ptr}, \[400], 410, 411.
+\:\\{read}, 53, 54, 1351, 1352.
+\:\9{read\_}{\.{\\read} primitive}, \[271].
+\:\\{read\_file}, \[491], 496, 497, 1288.
+\:\\{read\_font\_info}, \[571], 575, 1052, 1270.
+\:\\{read\_ln}, 53.
+\:\\{read\_open}, \[491], 492, 494, 496, 497, 512, 1288.
+\:\\{read\_sixteen}, \[575], 576, 579, 580.
+\:\\{read\_tcx\_file}, 24.
+\:\\{read\_to\_cs}, \[215], 271, 272, 1222, 1237.
+\:\\{read\_toks}, 309, \[493], 1237.
+\:\\{ready\_already}, 82, \[1344], 1345.
+\:\\{real}, 3, 110, 111, 188, 192, 630, 640, 1135, 1137, 1410.
+\:{real addition}, 1137, 1413.
+\:{real division}, 669, 675, 684, 687, 821, 822, 1135, 1137, 1413.
+\:{real multiplication}, 115, 192, 631, 636, 645, 820, 1137, 1413.
+\:\\{rebox}, \[726], 755, 761.
+\:\\{reconstitute}, 916, \[917], 924, 926, 927, 928, 1043.
+\:\\{recorder\_change\_filename}, 545.
+\:{recursion}, 77, 79, 179, 186, 204, 208, 209, 377, 413, 418, 509, 538, 603,
+629, 703, 730, 731, 736, 765, 960, 968, 970, 1346, 1388, 1449.
+\:\\{ref\_count}, \[400], 401, 412.
+\:{reference counts}, 156, 206, 207, 209, 281, 297, 313.
+\:\\{register}, \[215], 422, 423, 424, 1222, 1248, 1249, 1250.
+\:\\{rel\_noad}, \[693], 701, 707, 709, 739, 772, 778, 1168, 1169.
+\:\\{rel\_penalty}, \[242], 693, 772.
+\:\9{rel\_penalty\_}{\.{\\relpenalty} primitive}, \[244].
+\:\\{rel\_penalty\_code}, \[242], 243, 244.
+\:\\{relax}, \[213], 271, 272, 366, 383, 415, 517, 1057, 1236.
+\:\9{relax\_}{\.{\\relax} primitive}, \[271].
+\:\\{rem\_byte}, \[556], 565, 568, 581, 719, 724, 751, 760, 763, 764, 922,
+1052, 1472.
+\:\\{remainder}, \[105], 107, 108, 468, 469, \[554], 555, 556, 727, 728.
+\:\\{remember\_source\_info}, 1475.
+\:\\{remove\_item}, \[214], 1116, 1119, 1120.
+\:\\{rep}, \[557].
+\:\\{replace\_c}, \[1410].
+\:\\{replace\_count}, \[151], 181, 201, 851, 869, 880, 893, 894, 929, 1092,
+1132.
+\:\\{report\_illegal\_case}, 1057, \[1062], 1063, 1256, 1390.
+\:\\{reset}, 26.
+\:\\{reset\_auto\_spacing\_code}, \[1426].
+\:\\{reset\_auto\_xspacing\_code}, \[1426].
+\:\\{restart}, \[15], 126, 127, 347, 352, 365, 367, 368, 370, 391, 763, 764,
+793, 796, 800, 1163, 1227.
+\:\\{restore\_old\_value}, \[274], 282, 288.
+\:\\{restore\_trace}, 289, \[290].
+\:\\{restore\_zero}, \[274], 282, 284.
+\:\\{restrictedshell}, 62, 547, \[1394].
+\:\\{result}, \[46], \[47], \[1402], \[1407].
+\:\\{resume\_after\_display}, 811, 1211, \[1212], 1218.
+\:\\{reswitch}, \[15], 347, 349, 360, 474, 630, 631, 660, 662, 663, 737, 739,
+945, 946, 1040, 1041, 1047, 1057, 1150, 1159, 1163, 1469.
+\:\&{return}, 15, \[16].
+\:\\{rewrite}, 26.
+\:\\{rh}, 111, 115, 119, 219, 225, 227, 240, 262, 274, 565, 580, 696.
+\:\9{right\_}{\.{\\right} primitive}, \[1200].
+\:\\{right\_brace}, \[213], 295, 300, 304, 353, 365, 400, 453, 485, 488, 796,
+946, 972, 1079, 1265.
+\:\\{right\_brace\_limit}, \[295], 331, 403, 410, 411, 485, 488.
+\:\\{right\_brace\_token}, \[295], 345, 1077, 1139, 1238, 1384, 1475.
+\:\\{right\_delimiter}, \[694], 708, 759, 1193, 1194.
+\:\\{right\_hyphen\_min}, \[242], 1103, 1212, 1389, 1390.
+\:\9{right\_hyphen\_min\_}{\.{\\righthyphenmin} primitive}, \[244].
+\:\\{right\_hyphen\_min\_code}, \[242], 243, 244.
+\:\\{right\_noad}, \[698], 701, 707, 709, 736, 739, 771, 772, 773, 1196, 1200,
+1203.
+\:\\{right\_ptr}, \[616], 617, 618, 626.
+\:\\{right\_skip}, \[230], 838, 891, 892.
+\:\9{right\_skip\_}{\.{\\rightskip} primitive}, \[232].
+\:\\{right\_skip\_code}, \[230], 231, 232, 892, 897.
+\:\\{right1}, 596, \[597], 618, 621, 627.
+\:\\{right2}, 596, 621.
+\:\\{right3}, 596, 621.
+\:\\{right4}, 596, 621.
+\:\\{rlink}, \[125], 126, 127, 128, 130, 131, 132, 133, 151, 155, 170, 175,
+783, 830, 832, 1324, 1325.
+\:\9{roman\_numeral\_}{\.{\\romannumeral} primitive}, \[479].
+\:\\{roman\_numeral\_code}, \[479], 480, 482, 483.
+\:\\{round}, 3, 115, 192, 631, 636, 645, 820, 1137, 1413.
+\:\\{round\_decimals}, \[103], 104, 463.
+\:\\{rover}, \[125], 126, 127, 128, 129, 130, 131, 132, 133, 170, 175, 1324,
+1325.
+\:\\{rr}, \[763].
+\:\\{rt\_hit}, 917, \[918], 921, 922, 1044, 1046, 1050, 1052.
+\:\\{rule\_dp}, \[603], 633, 635, 637, 642, 644, 646.
+\:\\{rule\_ht}, \[603], 633, 635, 637, 642, 644, 645, 646, 647.
+\:\\{rule\_node}, \[143], 144, 154, 181, 189, 208, 212, 633, 637, 642, 646,
+662, 664, 680, 681, 741, 772, 816, 852, 853, 877, 878, 881, 882, 979, 984,
+1011, 1086, 1099, 1133, 1159.
+\:\\{rule\_node\_size}, \[143], 144, 208, 212.
+\:\\{rule\_save}, \[811], 815.
+\:\\{rule\_wd}, \[603], 633, 635, 636, 637, 638, 642, 644, 646.
+\:{rules aligning with characters}, 600.
+\:\\{runaway}, 121, \[312], 344, 407, 497.
+\:\.{Runaway...}, 312.
+\:\\{runsystem}, 1383.
+\:\\{runsystem\_ret}, \[1383].
+\:\|{s}, \[46], \[47], \[59], \[60], \[61], \[63], \[64], \[94], \[95], \[96], %
+\[104], \[109], \[126], \[131], \[153], \[183], \[184], \[270], \[290], \[317],
+\[400], \[418], \[484], \[493], \[528], \[540], \[541], \[571], \[649], \[656],
+\[660], \[679], \[699], \[710], \[717], \[731], \[737], \[749], \[802], \[811],
+\[841], \[873], \[888], \[912], \[945], \[977], \[998], \[1023], \[1072], %
+\[1073], \[1135], \[1150], \[1210], \[1249], \[1270], \[1292], \[1362], %
+\[1368], \[1402], \[1403], \[1473].
+\:\\{save\_area\_delimiter}, 536.
+\:\\{save\_cond\_ptr}, \[509], 511, 520.
+\:\\{save\_cs\_ptr}, \[785], 788.
+\:\\{save\_cur\_val}, \[461], 466.
+\:\\{save\_dir}, \[630], 634, 639, \[640], 643, 648.
+\:\\{save\_ext\_delimiter}, 536.
+\:\\{save\_for\_after}, \[286], 1284.
+\:\\{save\_h}, \[630], 634, 638, 639, \[640], 643, 648.
+\:\\{save\_index}, \[274], 280, 282, 286, 288.
+\:\\{save\_level}, \[274], 275, 280, 282, 286, 288.
+\:\\{save\_link}, \[841], 868.
+\:\\{save\_loc}, \[630], \[640].
+\:\\{save\_name\_in\_progress}, 536.
+\:\\{save\_pool\_ptr}, \[1394].
+\:\\{save\_ptr}, 274, \[277], 278, 279, 280, 282, 286, 288, 289, 291, 656, 815,
+1098, 1111, 1112, 1129, 1132, 1154, 1165, 1180, 1184, 1186, 1198, 1206, 1317.
+\:\\{save\_scanner\_status}, \[377], 380, \[400], \[481], 482, \[505], \[509],
+518.
+\:\\{save\_size}, \[33], 112, 277, 279, 1345, 1347.
+\:\\{save\_split\_top\_skip}, \[1023], 1025.
+\:\\{save\_stack}, 209, 274, 276, \[277], 279, 280, 281, 282, 283, 287, 288,
+289, 291, 306, 383, 500, 656, 779, 1074, 1083, 1143, 1152, 1162, 1165, 1345,
+1352.
+\:\\{save\_stop\_at\_space}, 536.
+\:\\{save\_str\_ptr}, \[1394].
+\:\\{save\_style}, \[731], \[737], 765.
+\:\\{save\_type}, \[274], 280, 282, 286, 288.
+\:\\{save\_v}, \[630], 634, 639, \[640], 643, 647, 648.
+\:\\{save\_vbadness}, \[1023], 1028.
+\:\\{save\_vfuzz}, \[1023], 1028.
+\:\\{save\_warning\_index}, \[400].
+\:\\{saved}, \[280], 656, 815, 1095, 1098, 1111, 1112, 1129, 1131, 1154, 1165,
+1180, 1184, 1186, 1198, 1206.
+\:\\{saved\_cur\_area}, \[541].
+\:\\{saved\_cur\_ext}, \[541].
+\:\\{saved\_cur\_name}, \[541].
+\:\\{sc}, 111, \[114], 115, 136, 146, 156, 165, 170, 219, 225, 253, 256, 257,
+424, 431, 436, 561, 565, 568, 569, 582, 584, 585, 586, 591, 711, 712, 763, 786,
+833, 834, 843, 854, 855, 859, 861, 871, 872, 900, 1054, 1161, 1218, 1260, 1261,
+1266, 1350, 1352, 1472.
+\:\\{scaled}, \[102], 103, 104, 105, 106, 107, 108, 109, 111, 114, 153, 156,
+162, 182, 183, 218, 458, 459, 461, 464, 559, 560, 571, 595, 603, 618, 627, 630,
+640, 657, 658, 660, 679, 690, 715, 716, 717, 723, 726, 727, 728, 730, 737, 746,
+747, 748, 749, 754, 760, 767, 773, 802, 811, 834, 841, 850, 858, 888, 917, 981,
+982, 988, 991, 993, 1005, 1023, 1041, 1080, 1091, 1098, 1117, 1122, 1135, 1150,
+1206, 1210, 1270, 1336, 1350, 1410, 1448.
+\:\.{scaled}, 1271.
+\:\\{scaled\_base}, \[253], 255, 257, 1236, 1250.
+\:\\{scan\_box}, 1085, \[1096], 1254.
+\:\\{scan\_char\_num}, 425, \[445], 946, 1041, 1049, 1135, 1136, 1163, 1166,
+1236, 1244, 1469.
+\:\\{scan\_delimiter}, \[1172], 1175, 1194, 1195, 1203, 1204.
+\:\\{scan\_dimen}, 421, 451, 458, \[459], 472, 473, 1073.
+\:\\{scan\_eight\_bit\_int}, 426, 431, 438, \[444], 516, 1091, 1094, 1111,
+1122, 1236, 1238, 1239, 1250, 1254, 1260, 1309.
+\:\\{scan\_fifteen\_bit\_int}, \[447], 1163, 1166, 1177, 1236.
+\:\\{scan\_file\_name}, 271, 340, \[537], 538, 548, 1270, 1288, 1364.
+\:\\{scan\_font\_ident}, 426, 437, 482, \[588], 589, 1247, 1266.
+\:\\{scan\_four\_bit\_int}, \[446], 588, 1247, 1288, 1363, 1399.
+\:\\{scan\_four\_bit\_int\_or\_18}, 512, \[1399].
+\:\\{scan\_glue}, 421, \[472], 793, 1072, 1240, 1251.
+\:\\{scan\_int}, 420, 421, 443, 444, 445, 446, 447, 448, 449, \[451], 458, 459,
+472, 482, 514, 515, 520, 589, 1115, 1237, 1240, 1244, 1251, 1253, 1256, 1257,
+1259, 1261, 1266, 1271, 1363, 1390, 1399, 1423, 1436, 1437, 1441, 1442.
+\:\\{scan\_keyword}, 168, \[418], 464, 465, 466, 467, 469, 473, 474, 656, 1094,
+1237, 1249, 1271.
+\:\\{scan\_left\_brace}, \[414], 484, 656, 796, 945, 971, 1036, 1111, 1129,
+1131, 1165, 1184, 1186.
+\:\\{scan\_math}, 1162, \[1163], 1170, 1175, 1177, 1188.
+\:\\{scan\_normal\_dimen}, \[459], 474, 514, 656, 1085, 1094, 1194, 1195, 1240,
+1251, 1256, 1258, 1260, 1261, 1266, 1272.
+\:\\{scan\_optional\_equals}, \[416], 793, 1236, 1238, 1240, 1244, 1247, 1249,
+1254, 1256, 1257, 1258, 1259, 1260, 1261, 1266, 1270, 1288, 1364, 1423, 1436,
+1441.
+\:\\{scan\_rule\_spec}, \[474], 1068, 1096.
+\:\\{scan\_something\_internal}, 420, 421, \[424], 443, 451, 460, 462, 466,
+472, 476.
+\:\\{scan\_spec}, \[656], 779, 785, 1083, 1095, 1179.
+\:\\{scan\_toks}, 297, 475, \[484], 971, 1113, 1230, 1238, 1292, 1301, 1365,
+1367, 1384.
+\:\\{scan\_twenty\_seven\_bit\_int}, \[448], 1163, 1166, 1172.
+\:\\{scanned\_result}, \[424], 425, 426, 429, 433, 436, 437, 439, 1442.
+\:\\{scanned\_result\_end}, \[424].
+\:\\{scanner\_status}, \[311], 312, 337, 342, 345, 377, 380, 400, 402, 481,
+482, 484, 493, 505, 509, 518, 788, 800.
+\:\9{script\_font\_}{\.{\\scriptfont} primitive}, \[1242].
+\:\\{script\_mlist}, \[700], 706, 709, 742, 1186.
+\:\9{script\_script\_font\_}{\.{\\scriptscriptfont} primitive}, \[1242].
+\:\\{script\_script\_mlist}, \[700], 706, 709, 742, 1186.
+\:\\{script\_script\_size}, \[710], 767, 1207, 1242.
+\:\\{script\_script\_style}, \[699], 705, 742, 1181.
+\:\9{script\_script\_style\_}{\.{\\scriptscriptstyle} primitive}, \[1181].
+\:\\{script\_size}, \[710], 767, 1207, 1242.
+\:\\{script\_space}, \[253], 768, 769, 770.
+\:\9{script\_space\_}{\.{\\scriptspace} primitive}, \[254].
+\:\\{script\_space\_code}, \[253], 254.
+\:\\{script\_style}, \[699], 705, 713, 714, 742, 767, 773, 777, 1181.
+\:\9{script\_style\_}{\.{\\scriptstyle} primitive}, \[1181].
+\:\\{scripts\_allowed}, \[698], 1188.
+\:\\{scroll\_mode}, 72, \[74], 85, 87, 94, 541, 1275, 1276, 1294.
+\:\9{scroll\_mode\_}{\.{\\scrollmode} primitive}, \[1275].
+\:\\{search}, \[1402].
+\:\\{search\_mem}, 171, \[178], 261, 1352.
+\:\\{search\_string}, 528, 548, \[1402], 1403.
+\:\\{second\_indent}, \[858], 859, 860, 900.
+\:\\{second\_pass}, \[839], 874, 877.
+\:\\{second\_width}, \[858], 859, 860, 861, 900.
+\:{Sedgewick, Robert}, 2.
+\:\.{see the transcript file...}, 1348.
+\:\\{selector}, \[55], 56, 58, 59, 60, 63, 72, 76, 87, 91, 93, 99, 251, 317,
+318, 322, 368, 476, 481, 545, 546, 628, 649, 1270, 1278, 1292, 1311, 1341,
+1346, 1348, 1381, 1383, 1387.
+\:\\{semi\_simple\_group}, \[275], 1075, 1077, 1080, 1081.
+\:\\{serial}, \[832], 856, 857, 867.
+\:\\{set\_auto\_spacing}, \[215], 1222, 1426, 1427, 1428.
+\:\\{set\_auto\_spacing\_code}, \[1426].
+\:\\{set\_auto\_xspacing\_code}, \[1426].
+\:\\{set\_aux}, \[215], 424, 427, 428, 429, 1222, 1255.
+\:\\{set\_box}, \[215], 271, 272, 1222, 1254.
+\:\9{set\_box\_}{\.{\\setbox} primitive}, \[271].
+\:\\{set\_box\_allowed}, \[77], 78, 1254, 1283.
+\:\\{set\_box\_dimen}, \[215], 424, 427, 428, 1222, 1255.
+\:\\{set\_box\_dir}, \[136], 139, 818, 820, 821, 822, 988, 1028, 1031, 1032,
+1093, 1098, 1112, 1180.
+\:\\{set\_box\_dir\_end}, \[136].
+\:\\{set\_break\_width\_to\_background}, \[848].
+\:\\{set\_char\_0}, 596, \[597], 631.
+\:\\{set\_conversion}, \[469].
+\:\\{set\_conversion\_end}, \[469].
+\:\\{set\_cur\_lang}, \[945], 971, 1103, 1212.
+\:\\{set\_cur\_r}, \[919], 921, 922.
+\:\\{set\_font}, \[215], 424, 564, 588, 1222, 1229, 1270, 1274.
+\:\\{set\_glue\_ratio\_one}, \[110], 675, 687, 821, 822.
+\:\\{set\_glue\_ratio\_zero}, \[110], 137, 668, 669, 675, 683, 684, 687, 821,
+822.
+\:\\{set\_height\_zero}, \[981].
+\:\\{set\_interaction}, \[215], 1222, 1275, 1276, 1277.
+\:\\{set\_kansuji\_char}, \[215], 1222, 1421, 1422, 1423.
+\:\9{set\_language\_}{\.{\\setlanguage} primitive}, \[1357].
+\:\\{set\_language\_code}, \[1357], 1359, 1361.
+\:\\{set\_math\_char}, 1166, \[1167], 1468.
+\:\\{set\_math\_kchar}, 1166, \[1468].
+\:\\{set\_page\_dimen}, \[215], 424, 993, 994, 995, 1222, 1255.
+\:\\{set\_page\_int}, \[215], 424, 427, 428, 1222, 1255.
+\:\\{set\_page\_so\_far\_zero}, \[998].
+\:\\{set\_prev\_graf}, \[215], 271, 272, 424, 1222, 1255.
+\:\\{set\_rule}, 594, 596, \[597], 635.
+\:\\{set\_shape}, \[215], 271, 272, 424, 1222, 1261.
+\:\\{set\_trick\_count}, \[322], 323, 324, 326.
+\:\\{setup\_bound\_var}, \[1345].
+\:\\{setup\_bound\_var\_end}, \[1345].
+\:\\{setup\_bound\_var\_end\_end}, \[1345].
+\:\\{setup\_bound\_variable}, 1345.
+\:\\{set1}, 596, \[597], 631, 1413.
+\:\\{set2}, \[596], \[597], 631.
+\:\\{set3}, \[596].
+\:\\{set4}, \[596].
+\:\\{sf\_code}, \[236], 238, 1045.
+\:\9{sf\_code\_}{\.{\\sfcode} primitive}, \[1242].
+\:\\{sf\_code\_base}, \[236], 241, 1242, 1243, 1246.
+\:\\{shape\_ref}, \[216], 238, 281, 1082, 1261.
+\:\\{shellenabledp}, 62, 512, 547, 1383, \[1394].
+\:\\{shift\_amount}, \[136], 137, 165, 190, 634, 639, 643, 648, 660, 664, 679,
+681, 692, 717, 731, 748, 749, 760, 761, 767, 768, 770, 810, 817, 818, 819, 900,
+1088, 1093, 1137, 1158, 1215, 1216, 1217, 1450, 1453.
+\:\\{shift\_case}, 1298, \[1301].
+\:\\{shift\_down}, \[754], 755, 756, 757, 758, \[760], 762, \[767], 768, 770.
+\:\\{shift\_up}, \[754], 755, 756, 757, 758, \[760], 762, \[767], 769, 770.
+\:\\{ship\_out}, 217, 603, \[649], 655, 1034, 1087, 1409.
+\:\9{ship\_out\_}{\.{\\shipout} primitive}, \[1083].
+\:\\{ship\_out\_flag}, \[1083], 1087.
+\:\\{short\_display}, 179, \[180], 181, 199, 674, 868, 1352.
+\:\\{short\_real}, 110, 111.
+\:\\{shortcut}, 458, \[459].
+\:\\{shortfall}, \[841], 862, 863, 864.
+\:\\{shorthand\_def}, \[215], 1222, 1234, 1235, 1236.
+\:\9{show\_}{\.{\\show} primitive}, \[1304].
+\:\\{show\_activities}, \[224], 1306.
+\:\\{show\_box}, 186, 188, \[204], 224, 225, 242, 649, 652, 674, 686, 997,
+1003, 1133, 1309, 1352.
+\:\9{show\_box\_}{\.{\\showbox} primitive}, \[1304].
+\:\\{show\_box\_breadth}, \[242], 1352.
+\:\9{show\_box\_breadth\_}{\.{\\showboxbreadth} primitive}, \[244].
+\:\\{show\_box\_breadth\_code}, \[242], 243, 244.
+\:\\{show\_box\_code}, \[1304], 1305, 1306.
+\:\\{show\_box\_depth}, \[242], 1352.
+\:\9{show\_box\_depth\_}{\.{\\showboxdepth} primitive}, \[244].
+\:\\{show\_box\_depth\_code}, \[242], 243, 244.
+\:\\{show\_code}, \[1304], 1306.
+\:\\{show\_context}, 55, 79, 83, 89, 316, \[317], 324, 541, 546, 548.
+\:\\{show\_cur\_cmd\_chr}, \[305], 378, 1042.
+\:\\{show\_eqtb}, \[258], 290.
+\:\\{show\_info}, 703, \[704].
+\:\\{show\_lists}, \[1304], 1305, 1306.
+\:\9{show\_lists\_}{\.{\\showlists} primitive}, \[1304].
+\:\\{show\_mode}, \[1304], 1305, 1306.
+\:\9{show\_mode\_}{\.{\\showmode} primitive}, \[1304].
+\:\\{show\_node\_list}, 179, 182, 186, 187, \[188], 201, 204, 239, 701, 703,
+704, 706, 1352.
+\:\9{show\_the\_}{\.{\\showthe} primitive}, \[1304].
+\:\\{show\_the\_code}, \[1304], 1305.
+\:\\{show\_token\_list}, 182, 229, 239, \[298], 301, 312, 325, 326, 411, 1352,
+1381.
+\:\\{show\_whatever}, 1303, \[1306].
+\:\\{shown\_mode}, \[219], 221, 305.
+\:\\{shrink}, \[156], 157, 170, 184, 442, 473, 631, 636, 645, 665, 667, 682,
+727, 763, 820, 836, 838, 848, 849, 878, 879, 987, 1015, 1020, 1054, 1056, 1160,
+1241, 1252, 1253, 1472.
+\:\\{shrink\_order}, \[156], 170, 184, 473, 631, 636, 645, 665, 667, 682, 727,
+820, 836, 837, 987, 1015, 1020, 1160, 1252.
+\:\\{shrinking}, \[136], 192, 630, 640, 675, 687, 820, 821, 822, 1160.
+\:\\{si}, \[39], 43, 70, 975, 1323, 1350.
+\:\\{simple\_group}, \[275], 1075, 1080.
+\:{Single-character primitives}, \[273].
+\:\9{Single-character primitives -}{\quad\.{\\-}}, \[1126].
+\:\9{Single-character primitives /}{\quad\.{\\/}}, \[271].
+\:\9{Single-character primitives /}{\quad\.{\\\ }}, \[271].
+\:\\{single\_base}, \[228], 268, 269, 270, 362, 385, 453, 1270, 1302.
+\:\\{sixteen\_bits}, \[25].
+\:\9{sjis\_}{\.{\\sjis} primitive}, \[479].
+\:\\{sjis\_code}, \[479], 480, 482, 483.
+\:\\{skew\_char}, 437, \[560], 587, 752, 1266, 1335, 1336, 1350.
+\:\9{skew\_char\_}{\.{\\skewchar} primitive}, \[1267].
+\:\\{skip}, \[230], 438, 1020.
+\:\9{skip\_}{\.{\\skip} primitive}, \[422].
+\:\\{skip\_base}, \[230], 233, 235, 1236, 1250.
+\:\\{skip\_blanks}, \[309], 350, 351, 353, 357, 362.
+\:\\{skip\_byte}, \[556], 568, 752, 763, 764, 920, 1051, 1472.
+\:\\{skip\_code}, \[1070], 1071, 1072.
+\:\9{skip\_def\_}{\.{\\skipdef} primitive}, \[1234].
+\:\\{skip\_def\_code}, \[1234], 1235, 1236.
+\:\\{skip\_line}, 342, \[504], 505.
+\:\\{skip\_loop}, \[1041], 1472.
+\:\\{skip\_mode}, 353, 354, 355, 453, 537.
+\:\\{skipping}, \[311], 312, 342, 505.
+\:\\{slant}, 558, \[569], 586, 1135, 1137, 1413.
+\:\\{slant\_code}, \[558], 569.
+\:\\{slow\_make\_string}, 528, 952, \[1403].
+\:\\{slow\_print}, \[61], 62, 64, 547, 548, 592, 1274, 1293, 1296, 1341, 1352,
+1407, 1411, 1412.
+\:\\{small\_char}, \[694], 702, 708, 717, 1172.
+\:\\{small\_fam}, \[694], 702, 708, 717, 1172.
+\:\\{small\_node\_size}, \[147], 150, 151, 153, 158, 159, 162, 164, 208, 212,
+666, 732, 763, 827, 898, 914, 921, 925, 1048, 1092, 1112, 1113, 1122, 1132,
+1133, 1370, 1371, 1389, 1390, 1451, 1470, 1471, 1472.
+\:\\{small\_number}, \[102], 103, 153, 158, 160, 270, 377, 400, 424, 449, 451,
+461, 472, 481, 493, 500, 505, 508, 509, 534, 618, 660, 679, 699, 702, 717, 730,
+731, 737, 767, 773, 840, 903, 904, 916, 917, 932, 945, 955, 971, 981, 998,
+1072, 1098, 1103, 1188, 1193, 1203, 1210, 1223, 1249, 1260, 1270, 1348, 1362,
+1363, 1383, 1386, 1435, 1440.
+\:\\{small\_op}, \[954].
+\:\\{so}, \[39], 46, 60, 61, 70, 71, 270, 418, 475, 529, 530, 614, 628, 777,
+942, 964, 966, 967, 970, 974, 1322, 1381, 1383.
+\:\.{Sorry, I can't find...}, 535.
+\:\\{sort\_avail}, \[132], 1324.
+\:\\{source\_filename\_stack}, \[310], 334, 337, 548, 1345, 1475.
+\:{sp}, 105, 598.
+\:\.{sp}, 469.
+\:\\{sp}, \[1416].
+\:\\{space}, 558, \[569], 763, 766, 1054.
+\:\\{space\_code}, \[558], 569, 589, 1054.
+\:\\{space\_factor}, 218, \[219], 429, 797, 798, 810, 1041, 1045, 1055, 1056,
+1068, 1088, 1095, 1103, 1105, 1129, 1131, 1135, 1208, 1212, 1255, 1256, 1469.
+\:\9{space\_factor\_}{\.{\\spacefactor} primitive}, \[427].
+\:\\{space\_offset}, \[136].
+\:\\{space\_ptr}, \[136], 137, 208, 212, 223, 431, 630, 649, 660, 679, 726,
+737, 738, 762, 767, 807, 810, 815, 827, 988, 989, 1004, 1032, 1088, 1090, 1112,
+1122, 1213, 1451.
+\:\\{space\_shrink}, 558, \[569], 1054.
+\:\\{space\_shrink\_code}, \[558], 569, 589.
+\:\\{space\_skip}, \[230], 1053, 1055.
+\:\9{space\_skip\_}{\.{\\spaceskip} primitive}, \[232].
+\:\\{space\_skip\_code}, \[230], 231, 232, 1053.
+\:\\{space\_stretch}, 558, \[569], 1054.
+\:\\{space\_stretch\_code}, \[558], 569.
+\:\\{space\_token}, \[295], 404, 475, 1227.
+\:\\{spacer}, \[213], 214, 238, 295, 297, 300, 304, 309, 343, 351, 353, 356,
+357, 362, 415, 417, 418, 454, 455, 463, 475, 794, 946, 972, 1041, 1057, 1233.
+\:\9{span\_}{\.{\\span} primitive}, \[791].
+\:\\{span\_code}, \[791], 792, 793, 800, 802.
+\:\\{span\_count}, 137, \[165], 191, 807, 812, 819.
+\:\\{span\_node\_size}, \[808], 809, 814.
+\:\\{spec\_code}, \[656].
+\:\9{special\_}{\.{\\special} primitive}, \[1357].
+\:\\{special\_node}, \[1354], 1357, 1359, 1361, 1367, 1369, 1370, 1371, 1386,
+1475.
+\:\\{special\_out}, \[1381], 1386.
+\:\.{split}, 1022.
+\:\\{split\_bot\_mark}, \[393], 394, 988, 990.
+\:\9{split\_bot\_mark\_}{\.{\\splitbotmark} primitive}, \[395].
+\:\\{split\_bot\_mark\_code}, \[393], 395, 396, 1348.
+\:\\{split\_first\_mark}, \[393], 394, 988, 990.
+\:\9{split\_first\_mark\_}{\.{\\splitfirstmark} primitive}, \[395].
+\:\\{split\_first\_mark\_code}, \[393], 395, 396.
+\:\\{split\_max\_depth}, 145, \[253], 988, 1080, 1112.
+\:\9{split\_max\_depth\_}{\.{\\splitmaxdepth} primitive}, \[254].
+\:\\{split\_max\_depth\_code}, \[253], 254.
+\:\\{split\_top\_ptr}, \[145], 194, 208, 212, 1032, 1033, 1112.
+\:\\{split\_top\_skip}, 145, \[230], 979, 988, 1023, 1025, 1032, 1112.
+\:\9{split\_top\_skip\_}{\.{\\splittopskip} primitive}, \[232].
+\:\\{split\_top\_skip\_code}, \[230], 231, 232, 980.
+\:\\{split\_up}, \[992], 997, 1019, 1021, 1031, 1032.
+\:\\{spotless}, \[77], 78, 82, 251, 1345, 1348.
+\:\.{spread}, 656.
+\:\\{sprint\_cs}, 229, \[269], 344, 406, 407, 409, 483, 490, 495, 572, 1307.
+\:{square roots}, 748.
+\:\\{src\_specials}, 33.
+\:\\{src\_specials\_p}, \[33], 62, 547.
+\:\\{ss\_code}, \[1070], 1071, 1072.
+\:\\{ss\_glue}, \[168], 170, 726, 1072.
+\:\\{ssup\_error\_line}, \[11], 55, 1345.
+\:\\{ssup\_hyph\_size}, \[11], 936.
+\:\\{ssup\_max\_strings}, \[11], 39.
+\:\\{ssup\_trie\_opcode}, \[11], 931.
+\:\\{ssup\_trie\_size}, \[11], 931, 1345.
+\:{stack conventions}, 306.
+\:\\{stack\_into\_box}, \[722], 724.
+\:\\{stack\_size}, \[33], 307, 316, 327, 1345, 1347.
+\:\\{start}, 306, \[308], 309, 313, 324, 325, 329, 330, 331, 334, 335, 337,
+368, 370, 371, 380, 494, 549.
+\:\\{start\_cs}, \[347], 362, 363.
+\:\\{start\_eq\_no}, 1152, \[1154].
+\:\\{start\_field}, \[306], 308.
+\:\\{start\_font\_error\_message}, \[572], 578.
+\:\\{start\_here}, 5, \[1345].
+\:\\{start\_input}, 377, 387, 389, \[548], 1350.
+\:\\{start\_of\_TEX}, \[6], 1345.
+\:\\{start\_par}, \[214], 1100, 1101, 1102, 1104.
+\:\&{stat}, \[7], \[118], \[121], \[122], \[123], \[124], \[126], \[131], %
+\[258], \[266], \[289], \[290], \[650], \[840], \[856], \[866], \[874], \[998],
+\[1016], \[1021], \[1346].
+\:\\{state}, 88, 306, \[308], 309, 313, 317, 318, 329, 331, 334, 336, 337, 343,
+347, 349, 350, 352, 353, 357, 360, 361, 362, 401, 494, 537, 548, 1348.
+\:\\{state\_field}, \[306], 308, 1143.
+\:\\{stderr}, 1319, 1395.
+\:\\{stdin}, 33.
+\:\\{stdout}, 33, 62, 535.
+\:{stomach}, 413.
+\:\\{stop}, \[213], 1057, 1058, 1064, 1065, 1066, 1106.
+\:\\{stop\_at\_space}, 527, 536, \[1392], 1393.
+\:\\{stop\_flag}, \[556], 568, 752, 763, 764, 920, 1051, 1472.
+\:\\{store\_background}, \[875].
+\:\\{store\_break\_width}, \[854].
+\:\\{store\_fmt\_file}, \[1315], 1348.
+\:\\{store\_four\_quarters}, \[575], 579, 580, 584, 585.
+\:\\{store\_new\_token}, \[382], 383, 404, 408, 410, 418, 475, 477, 484, 485,
+487, 488, 493, 494.
+\:\\{store\_scaled}, \[582], 584, 585, 586.
+\:\\{str\_eq\_buf}, \[46], 265.
+\:\\{str\_eq\_str}, \[47], 1273, 1402.
+\:\\{str\_number}, \[39], 40, 44, 46, 47, 48, 63, 64, 80, 94, 95, 96, 183, 184,
+270, 290, 310, 418, 523, 528, 530, 536, 538, 540, 541, 543, 548, 560, 571, 937,
+940, 945, 1270, 1292, 1312, 1336, 1345, 1350, 1368, 1394, 1402, 1403, 1476.
+\:\\{str\_pool}, 39, \[40], 43, 44, 46, 47, 48, 60, 61, 70, 71, 262, 266, 270,
+309, 418, 475, 528, 529, 530, 613, 614, 628, 649, 775, 777, 940, 942, 945, 952,
+1321, 1322, 1323, 1345, 1346, 1347, 1381, 1383, 1393, 1395.
+\:\\{str\_ptr}, 39, \[40], 42, 44, 45, 48, 60, 61, 71, 266, 268, 528, 536, 548,
+628, 1322, 1323, 1336, 1338, 1340, 1345, 1347, 1381, 1383.
+\:\\{str\_room}, \[43], 186, 266, 475, 527, 528, 536, 537, 950, 1270, 1292,
+1341, 1346, 1381, 1383.
+\:\\{str\_start}, 39, \[40], 41, 42, 44, 45, 46, 47, 48, 60, 61, 70, 71, 85,
+262, 266, 270, 418, 528, 529, 530, 614, 628, 776, 940, 942, 945, 952, 1321,
+1322, 1323, 1345, 1381, 1383, 1395.
+\:\\{str\_toks}, \[475], 476, 481, 1475.
+\:\\{strcmp}, 1321.
+\:\\{strcpy}, 52, 1320.
+\:\\{stretch}, \[156], 157, 170, 184, 442, 473, 631, 636, 645, 665, 667, 682,
+727, 763, 820, 838, 848, 849, 878, 879, 987, 1015, 1020, 1054, 1056, 1160,
+1241, 1252, 1253, 1472.
+\:\\{stretch\_order}, \[156], 170, 184, 473, 631, 636, 645, 665, 667, 682, 727,
+820, 838, 848, 849, 878, 879, 987, 1015, 1020, 1160, 1252.
+\:\\{stretching}, \[136], 631, 636, 645, 669, 684, 820, 821, 822, 1160.
+\:{string pool}, 48, 1321.
+\:\9{string\_}{\.{\\string} primitive}, \[479].
+\:\\{string\_code}, \[479], 480, 482, 483.
+\:\\{string\_vacancies}, \[33], 53, 1345.
+\:\\{stringcast}, 52, 535, 545, 548, 1288, 1320, 1321, 1387.
+\:\\{strings\_free}, \[33], 1323, 1345.
+\:\\{strlen}, 52, 628, 1320.
+\:\\{style}, \[737], 771, 772, \[773].
+\:\\{style\_node}, 166, \[699], 701, 709, 741, 742, 772, 1181.
+\:\\{style\_node\_size}, \[699], 700, 709, 774.
+\:\\{sub\_box}, \[692], 698, 703, 709, 731, 745, 746, 748, 749, 760, 765, 1088,
+1105, 1180.
+\:\\{sub\_drop}, \[711], 767.
+\:\\{sub\_mark}, \[213], 300, 304, 353, 1058, 1187.
+\:\\{sub\_mlist}, \[692], 694, 703, 731, 753, 765, 1163, 1193, 1197, 1198, 1203.
+\:\\{sub\_style}, \[713], 761, 768, 770.
+\:\\{sub\_sup}, 1187, \[1188].
+\:\\{subscr}, \[692], 694, 697, 698, 701, 707, 709, 749, 753, 760, 761, 762,
+763, 764, 765, 766, 767, 768, 770, 1163, 1175, 1177, 1187, 1188, 1189, 1198.
+\:{subscripts}, 765, 1187.
+\:\\{subtype}, \[134], 135, 136, 137, 144, 145, 149, 150, 151, 152, 153, 155,
+156, 158, 159, 160, 161, 162, 163, 164, 165, 194, 195, 196, 197, 198, 199, 200,
+435, 500, 506, 507, 636, 638, 645, 647, 660, 667, 679, 682, 692, 693, 697, 699,
+700, 701, 707, 728, 741, 742, 743, 744, 760, 774, 777, 779, 797, 806, 820, 830,
+831, 833, 848, 854, 855, 877, 879, 890, 892, 907, 908, 909, 910, 914, 921, 992,
+997, 999, 1019, 1020, 1029, 1031, 1032, 1046, 1072, 1073, 1090, 1112, 1113,
+1122, 1125, 1133, 1137, 1160, 1171, 1175, 1177, 1183, 1193, 1348, 1354, 1362,
+1369, 1370, 1371, 1375, 1386, 1387, 1443, 1444, 1445, 1450, 1451, 1456, 1459,
+1460, 1461, 1462, 1463, 1472.
+\:\\{sub1}, \[711], 768.
+\:\\{sub2}, \[711], 770.
+\:\\{succumb}, \[94], 95, 96, 1317.
+\:\\{sup}, 1345.
+\:\\{sup\_buf\_size}, \[11].
+\:\\{sup\_drop}, \[711], 767.
+\:\\{sup\_dvi\_buf\_size}, \[11].
+\:\\{sup\_expand\_depth}, \[11].
+\:\\{sup\_font\_max}, \[11].
+\:\\{sup\_font\_mem\_size}, \[11], 1334.
+\:\\{sup\_hash\_extra}, \[11], 1321.
+\:\\{sup\_hyph\_size}, \[11].
+\:\\{sup\_main\_memory}, \[11], 112, 1345.
+\:\\{sup\_mark}, \[213], 300, 304, 350, 363, 364, 1058, 1187, 1188, 1189.
+\:\\{sup\_max\_in\_open}, \[11].
+\:\\{sup\_max\_strings}, \[11], 1323.
+\:\\{sup\_mem\_bot}, \[11].
+\:\\{sup\_nest\_size}, \[11].
+\:\\{sup\_param\_size}, \[11].
+\:\\{sup\_pool\_free}, \[11].
+\:\\{sup\_pool\_size}, \[11], 1323.
+\:\\{sup\_save\_size}, \[11].
+\:\\{sup\_stack\_size}, \[11].
+\:\\{sup\_string\_vacancies}, \[11].
+\:\\{sup\_strings\_free}, \[11].
+\:\\{sup\_style}, \[713], 761, 769.
+\:\\{sup\_trie\_size}, \[11].
+\:{superscripts}, 765, 1187.
+\:\\{supscr}, \[692], 694, 697, 698, 701, 707, 709, 749, 753, 761, 762, 763,
+764, 765, 767, 769, 1163, 1175, 1177, 1187, 1188, 1189, 1198.
+\:\\{sup1}, \[711], 769.
+\:\\{sup2}, \[711], 769.
+\:\\{sup3}, \[711], 769.
+\:\\{sw}, \[571], 582, 586.
+\:\\{switch}, \[347], 349, 350, 352, 358.
+\:\\{synch\_dir}, 630, 640, 1446, \[1448].
+\:\\{synch\_h}, \[627], 631, 635, 639, 644, 648, 1381, 1413, 1448.
+\:\\{synch\_v}, \[627], 631, 635, 639, 643, 644, 648, 1381, 1413, 1448.
+\:\\{system}, 1383.
+\:{system dependencies}, 2, \[3], 9, 10, 11, 12, 19, 21, 23, 26, 33, 35, 36,
+38, 39, 50, 57, 60, 73, 82, 85, 97, 110, 111, 113, 114, 167, 192, 247, 310,
+319, 334, 375, 496, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 534,
+536, 549, 568, 575, 602, 606, 608, 809, 931, 1344, 1345, 1346, 1351, 1353, 1474.
+\:\\{s1}, \[83], 89.
+\:\\{s2}, \[83], 89.
+\:\\{s3}, \[83], 89.
+\:\\{s4}, \[83], 89.
+\:\|{t}, \[47], \[108], \[109], \[126], \[224], \[283], \[285], \[286], \[287],
+\[329], \[347], \[377], \[400], \[475], \[484], \[528], \[702], \[715], \[716],
+\[737], \[767], \[811], \[841], \[888], \[917], \[977], \[981], \[1041], %
+\[1135], \[1188], \[1203], \[1210], \[1270], \[1301], \[1403], \[1417].
+\:\\{t\_baseline\_shift}, \[253], 1045, 1136, 1208, 1469.
+\:\9{t\_baseline\_shift\_}{\.{\\tbaselineshift} primitive}, \[254].
+\:\\{t\_baseline\_shift\_code}, \[253], 254.
+\:\\{t\_open\_in}, 34, 38.
+\:\\{t\_open\_out}, \[34], 1345.
+\:\\{tab\_mark}, \[213], 295, 300, 348, 353, 791, 792, 793, 794, 795, 799, 1138.
+\:\\{tab\_skip}, \[230].
+\:\9{tab\_skip\_}{\.{\\tabskip} primitive}, \[232].
+\:\\{tab\_skip\_code}, \[230], 231, 232, 789, 793, 797, 806, 820.
+\:\\{tab\_token}, \[295], 1140.
+\:\\{tag}, \[554], 555, 565.
+\:\\{tail}, 218, \[219], 220, 221, 222, 435, 690, 729, 787, 797, 806, 807, 810,
+823, 827, 899, 901, 1006, 1028, 1034, 1037, 1045, 1046, 1047, 1048, 1052, 1053,
+1055, 1066, 1072, 1073, 1085, 1088, 1090, 1092, 1103, 1108, 1112, 1113, 1115,
+1117, 1122, 1125, 1129, 1131, 1132, 1135, 1137, 1157, 1162, 1167, 1170, 1171,
+1175, 1177, 1180, 1183, 1186, 1188, 1189, 1193, 1196, 1198, 1199, 1203, 1208,
+1217, 1218, 1321, 1362, 1363, 1364, 1365, 1366, 1367, 1388, 1389, 1390, 1443,
+1444, 1445, 1468, 1469, 1470, 1471, 1472, 1475.
+\:\\{tail\_append}, \[220], 797, 806, 827, 1046, 1048, 1052, 1066, 1068, 1072,
+1073, 1103, 1105, 1112, 1113, 1115, 1124, 1125, 1129, 1132, 1162, 1170, 1175,
+1177, 1180, 1183, 1184, 1189, 1203, 1208, 1215, 1217, 1218, 1443, 1444, 1445,
+1470, 1471, 1472.
+\:\\{tail\_field}, \[218], 219, 1006.
+\:\\{tally}, \[55], 56, 58, 59, 298, 318, 321, 322, 323.
+\:\9{tate\_}{\.{\\tate} primitive}, \[1083].
+\:\\{tate\_jfm\_id}, \[551], 576.
+\:\&{tats}, \[7].
+\:\\{temp\_head}, \[168], 312, 402, 407, 411, 475, 477, 478, 481, 489, 730,
+731, 737, 765, 771, 827, 873, 874, 875, 888, 890, 891, 892, 898, 979, 1076,
+1077, 1206, 1208, 1211, 1310, 1475.
+\:\\{temp\_ptr}, \[116], 160, 629, 630, 634, 639, 640, 643, 648, 651, 690, 703,
+704, 980, 1012, 1032, 1048, 1053, 1348, 1465.
+\:\\{temp\_str}, \[528], \[548].
+\:\\{term\_and\_log}, \[55], 58, 59, 72, 76, 93, 251, 545, 1311, 1341, 1348,
+1383, 1387.
+\:\\{term\_in}, \[33], 37, 38, 72, 1351, 1352.
+\:\\{term\_input}, \[72], 79.
+\:\\{term\_offset}, \[55], 56, 58, 59, 62, 63, 72, 548, 649, 1293.
+\:\\{term\_only}, \[55], 56, 58, 59, 72, 76, 93, 546, 1311, 1346, 1348, 1383.
+\:\\{term\_out}, \[33], 35, 37, 38, 52, 57.
+\:\\{terminal\_input}, \[310], 319, 334, 336, 368.
+\:\\{test\_char}, \[917], 920.
+\:\\{TEX}, \[4].
+\:\.{TeX capacity exceeded ...}, 95.
+\:\9{TeX capacity exceeded buffer size}{\quad buffer size}, 36, 334, 385.
+\:\9{TeX capacity exceeded exception dictionary}{\quad exception dictionary},
+951.
+\:\9{TeX capacity exceeded font memory}{\quad font memory}, 591.
+\:\9{TeX capacity exceeded grouping levels}{\quad grouping levels}, 280.
+\:\9{TeX capacity exceeded hash size}{\quad hash size}, 266.
+\:\9{TeX capacity exceeded input stack size}{\quad input stack size}, 327.
+\:\9{TeX capacity exceeded main memory size}{\quad main memory size}, 121, 126.
+\:\9{TeX capacity exceeded number of strings}{\quad number of strings}, 44, 528.
+\:\9{TeX capacity exceeded parameter stack size}{\quad parameter stack size},
+401.
+\:\9{TeX capacity exceeded pattern memory}{\quad pattern memory}, 965, 975.
+\:\9{TeX capacity exceeded pool size}{\quad pool size}, 43.
+\:\9{TeX capacity exceeded save size}{\quad save size}, 279.
+\:\9{TeX capacity exceeded semantic nest size}{\quad semantic nest size}, 222.
+\:\9{TeX capacity exceeded text input levels}{\quad text input levels}, 334.
+\:\.{TEX.POOL check sum...}, 54.
+\:\.{TEX.POOL doesn't match}, 54.
+\:\.{TEX.POOL has no check sum}, 53.
+\:\.{TEX.POOL line doesn't...}, 53.
+\:\\{TEX\_area}, 525.
+\:\\{TeX\_banner}, \[2].
+\:\\{TeX\_banner\_k}, \[2].
+\:\\{TEX\_font\_area}, 525.
+\:\\{TEX\_format\_default}, \[531], 534, 535.
+\:\\{tex\_input\_type}, 548, 1288.
+\:\\{tex\_remainder}, 105.
+\:\9{TeXbook}{\sl The \TeX book}, 1, 23, 50, 109, 213, 426, 457, 467, 470, 694,
+699, 775, 1227, 1344.
+\:\.{TeXformats}, 11, 532.
+\:\\{TEXMF\_ENGINE\_NAME}, 11.
+\:\\{texmf\_log\_name}, 543.
+\:\\{TEXMF\_POOL\_NAME}, 11.
+\:\.{texput}, 36, 545, 1270.
+\:\\{text}, \[262], 264, 265, 266, 268, 269, 270, 271, 502, 564, 791, 1200,
+1228, 1270, 1321, 1331, 1345, 1357, 1382, 1395.
+\:\.{Text line contains...}, 352.
+\:\\{text\_char}, \[19], 20, 25, 26, 48, 1315, 1316, 1320, 1321.
+\:\9{text\_font\_}{\.{\\textfont} primitive}, \[1242].
+\:\\{text\_mlist}, \[700], 706, 709, 742, 1186.
+\:\\{text\_size}, \[710], 714, 743, 773, 1207, 1211.
+\:\\{text\_style}, \[699], 705, 714, 742, 748, 755, 756, 757, 759, 760, 769,
+773, 1181, 1206, 1208.
+\:\9{text\_style\_}{\.{\\textstyle} primitive}, \[1181].
+\:\9{TeX82}{\TeX82}, \[1], 100.
+\:\9{TFM files}{\.{TFM} files}, 550.
+\:\\{tfm\_file}, \[550], 571, 574, 575, 586.
+\:\\{tfm\_temp}, 575.
+\:\9{tfont\_}{\.{\\tfont} primitive}, \[271].
+\:\.{TFtoPL}, 572.
+\:\.{That makes 100 errors...}, 83.
+\:\\{the}, \[216], 271, 272, 374, 378, 489.
+\:\.{The following...deleted}, 652, 1003, 1133.
+\:\9{the\_}{\.{\\the} primitive}, \[271].
+\:\\{the\_toks}, \[476], 477, 478, 489, 1310.
+\:\\{thick\_mu\_skip}, \[230].
+\:\9{thick\_mu\_skip\_}{\.{\\thickmuskip} primitive}, \[232].
+\:\\{thick\_mu\_skip\_code}, \[230], 231, 232, 777.
+\:\\{thickness}, \[694], 708, 736, 754, 755, 757, 758, 1194.
+\:\\{thin\_mu\_skip}, \[230].
+\:\9{thin\_mu\_skip\_}{\.{\\thinmuskip} primitive}, \[232].
+\:\\{thin\_mu\_skip\_code}, \[230], 231, 232, 235, 777.
+\:\.{This can't happen}, 96.
+\:\9{this can't happen align}{\quad align}, 811.
+\:\9{this can't happen copying}{\quad copying}, 212.
+\:\9{this can't happen curlevel}{\quad curlevel}, 287.
+\:\9{this can't happen disc1}{\quad disc1}, 852.
+\:\9{this can't happen disc2}{\quad disc2}, 853.
+\:\9{this can't happen disc3}{\quad disc3}, 881.
+\:\9{this can't happen disc4}{\quad disc4}, 882.
+\:\9{this can't happen display}{\quad display}, 1212.
+\:\9{this can't happen endv}{\quad endv}, 802.
+\:\9{this can't happen ext1}{\quad ext1}, 1361.
+\:\9{this can't happen ext2}{\quad ext2}, 1370.
+\:\9{this can't happen ext3}{\quad ext3}, 1371.
+\:\9{this can't happen ext4}{\quad ext4}, 1386.
+\:\9{this can't happen flushing}{\quad flushing}, 208.
+\:\9{this can't happen if}{\quad if}, 508.
+\:\9{this can't happen kinsoku}{\quad kinsoku}, 1441.
+\:\9{this can't happen line breaking}{\quad line breaking}, 888.
+\:\9{this can't happen mlist1}{\quad mlist1}, 739.
+\:\9{this can't happen mlist2}{\quad mlist2}, 765.
+\:\9{this can't happen mlist3}{\quad mlist3}, 772.
+\:\9{this can't happen mlist4}{\quad mlist4}, 777.
+\:\9{this can't happen page}{\quad page}, 1011.
+\:\9{this can't happen paragraph}{\quad paragraph}, 877.
+\:\9{this can't happen prefix}{\quad prefix}, 1223.
+\:\9{this can't happen pruning}{\quad pruning}, 979.
+\:\9{this can't happen right}{\quad right}, 1197.
+\:\9{this can't happen rightbrace}{\quad rightbrace}, 1080.
+\:\9{this can't happen vcenter}{\quad vcenter}, 747.
+\:\9{this can't happen vertbreak}{\quad vertbreak}, 984.
+\:\9{this can't happen vlistout}{\quad vlistout}, 641.
+\:\9{this can't happen vpack}{\quad vpack}, 680.
+\:\9{this can't happen 256 spans}{\quad 256 spans}, 809.
+\:\\{this\_box}, \[630], 631, 635, 636, \[640], 644, 645, \[1465].
+\:\\{this\_if}, \[509], 512, 514, 516, 517.
+\:\\{three\_codes}, \[656].
+\:\\{threshold}, \[839], 862, 865, 874.
+\:\.{Tight \\hbox...}, 678.
+\:\.{Tight \\vbox...}, 689.
+\:\\{tight\_fit}, \[828], 830, 841, 844, 845, 847, 864.
+\:\\{time}, \[242], 247, 547, 628.
+\:\9{time\_}{\.{\\time} primitive}, \[244].
+\:\\{time\_code}, \[242], 243, 244.
+\:\&{tini}, \[8].
+\:\&{Tini}, \[8].
+\:\\{tmp}, \[1448].
+\:\.{to}, 656, 1094, 1237.
+\:\\{toDVI}, 238, 631, 1416, 1423.
+\:\\{tok\_val}, \[421], 426, 429, 439, 476.
+\:\\{tokanji}, \[113], 580, 1423, 1436, 1437, 1441, 1442.
+\:{token}, 295.
+\:\\{token\_list}, \[313], 317, 318, 329, 331, 336, 343, 347, 352, 401, 537,
+1143, 1348.
+\:\\{token\_ref\_count}, \[206], 209, 297, 484, 493, 990, 1475.
+\:\\{token\_show}, \[301], 302, 329, 412, 1292, 1297, 1310, 1383.
+\:\\{token\_type}, \[313], 317, 318, 320, 325, 329, 330, 331, 333, 390, 401,
+1037, 1107.
+\:\\{toklist}, \[1475].
+\:\\{toks}, \[236].
+\:\9{toks\_}{\.{\\toks} primitive}, \[271].
+\:\\{toks\_base}, \[236], 237, 238, 239, 426, 1236, 1238, 1239.
+\:\9{toks\_def\_}{\.{\\toksdef} primitive}, \[1234].
+\:\\{toks\_def\_code}, \[1234], 1236.
+\:\\{toks\_register}, \[215], 271, 272, 424, 426, 1222, 1238, 1239.
+\:\\{tolerance}, \[242], 246, 839, 874.
+\:\9{tolerance\_}{\.{\\tolerance} primitive}, \[244].
+\:\\{tolerance\_code}, \[242], 243, 244.
+\:\\{tonum}, \[113], 453, 580.
+\:\.{Too many \}'s}, 1080.
+\:\\{too\_small}, \[1316], 1319.
+\:\\{top}, \[557].
+\:\\{top\_bot\_mark}, \[216], 302, 374, 378, 395, 396, 397.
+\:\\{top\_edge}, \[640], 647.
+\:\\{top\_mark}, \[393], 394, 1023.
+\:\9{top\_mark\_}{\.{\\topmark} primitive}, \[395].
+\:\\{top\_mark\_code}, \[393], 395, 397, 1348.
+\:\\{top\_skip}, \[230].
+\:\9{top\_skip\_}{\.{\\topskip} primitive}, \[232].
+\:\\{top\_skip\_code}, \[230], 231, 232, 1012.
+\:\\{total\_demerits}, \[830], 856, 857, 866, 875, 885, 886.
+\:\9{total\_height}{\.{total height}}, 997.
+\:\\{total\_mathex\_params}, \[712], 1207.
+\:\\{total\_mathsy\_params}, \[711], 1207.
+\:\\{total\_pages}, \[603], 604, 628, 651, 653.
+\:\\{total\_shrink}, \[657], 661, 665, 667, 675, 676, 677, 678, 682, 687, 688,
+689, 807, 1213.
+\:\\{total\_stretch}, \[657], 661, 665, 667, 669, 670, 671, 682, 684, 685, 807.
+\:{Trabb Pardo, Luis Isidoro}, 2.
+\:\\{tracing\_char\_sub\_def}, \[242], 246, 1236.
+\:\9{tracing\_char\_sub\_def\_}{\.{\\tracingcharsubdef} primitive}, \[244].
+\:\\{tracing\_char\_sub\_def\_code}, \[242], 243, 244.
+\:\\{tracing\_commands}, \[242], 378, 509, 520, 1042.
+\:\9{tracing\_commands\_}{\.{\\tracingcommands} primitive}, \[244].
+\:\\{tracing\_commands\_code}, \[242], 243, 244.
+\:\\{tracing\_lost\_chars}, \[242], 592, 1412.
+\:\9{tracing\_lost\_chars\_}{\.{\\tracinglostchars} primitive}, \[244].
+\:\\{tracing\_lost\_chars\_code}, \[242], 243, 244.
+\:\\{tracing\_macros}, \[242], 329, 400, 411.
+\:\9{tracing\_macros\_}{\.{\\tracingmacros} primitive}, \[244].
+\:\\{tracing\_macros\_code}, \[242], 243, 244.
+\:\\{tracing\_online}, \[242], 251, 1306, 1311, 1383, 1387.
+\:\9{tracing\_online\_}{\.{\\tracingonline} primitive}, \[244].
+\:\\{tracing\_online\_code}, \[242], 243, 244.
+\:\\{tracing\_output}, \[242], 649, 652.
+\:\9{tracing\_output\_}{\.{\\tracingoutput} primitive}, \[244].
+\:\\{tracing\_output\_code}, \[242], 243, 244.
+\:\\{tracing\_pages}, \[242], 998, 1016, 1021.
+\:\9{tracing\_pages\_}{\.{\\tracingpages} primitive}, \[244].
+\:\\{tracing\_pages\_code}, \[242], 243, 244.
+\:\\{tracing\_paragraphs}, \[242], 856, 866, 874.
+\:\9{tracing\_paragraphs\_}{\.{\\tracingparagraphs} primitive}, \[244].
+\:\\{tracing\_paragraphs\_code}, \[242], 243, 244.
+\:\\{tracing\_restores}, \[242], 289.
+\:\9{tracing\_restores\_}{\.{\\tracingrestores} primitive}, \[244].
+\:\\{tracing\_restores\_code}, \[242], 243, 244.
+\:\\{tracing\_stats}, 118, \[242], 650, 1339, 1346.
+\:\9{tracing\_stats\_}{\.{\\tracingstats} primitive}, \[244].
+\:\\{tracing\_stats\_code}, \[242], 243, 244.
+\:\\{tracinglostchars}, 1412.
+\:\.{Transcript written...}, 1346.
+\:\\{translate\_filename}, 24, 62, 547, 1401.
+\:\\{trap\_zero\_glue}, 1240, \[1241], 1249.
+\:\\{trick\_buf}, \[55], 59, 321, 323.
+\:\\{trick\_buf2}, \[55], 59, 322, 323.
+\:\\{trick\_count}, \[55], 59, 321, 322, 323.
+\:{Trickey, Howard Wellington}, 2.
+\:\\{trie}, 931, 932, 933, 961, 963, 964, 965, 969, 970, 977.
+\:\\{trie\_back}, \[961], 965, 967.
+\:\\{trie\_c}, \[958], 959, 964, 966, 967, 970, 974, 975, 1350.
+\:\\{trie\_char}, 931, \[932], 934, 969, 970.
+\:\\{trie\_fix}, 969, \[970].
+\:\\{trie\_hash}, \[958], 959, 960, 961, 963, 1350.
+\:\\{trie\_l}, \[958], 959, 960, 968, 970, 971, 974, 975, 1350.
+\:\\{trie\_link}, 931, \[932], 934, 961, 963, 964, 965, 966, 967, 969, 970.
+\:\\{trie\_max}, \[961], 963, 965, 969, 1337, 1338.
+\:\\{trie\_min}, \[961], 963, 964, 967.
+\:\\{trie\_node}, \[959], 960.
+\:\\{trie\_not\_ready}, 902, \[961], 962, 971, 977, 1337, 1338, 1350.
+\:\\{trie\_o}, \[958], 959, 970, 974, 975, 1350.
+\:\\{trie\_op}, 931, \[932], 934, 935, 954, 969, 970.
+\:\\{trie\_op\_hash}, 11, \[954], 955, 956, 957, 959, 963.
+\:\\{trie\_op\_lang}, \[954], 955, 956, 963.
+\:\\{trie\_op\_ptr}, \[954], 955, 956, 957, 1337, 1338.
+\:\\{trie\_op\_size}, \[11], 932, 954, 955, 957, 1337, 1338.
+\:\\{trie\_op\_val}, \[954], 955, 956, 963.
+\:\\{trie\_opcode}, \[931], 932, 954, 955, 958, 971, 1350.
+\:\\{trie\_pack}, \[968], 977.
+\:\\{trie\_pointer}, \[931], 932, 933, 958, 959, 960, 961, 964, 968, 970, 971,
+977, 1338, 1350.
+\:\\{trie\_ptr}, \[958], 963, 975, 1350.
+\:\\{trie\_r}, \[958], 959, 960, 966, 967, 968, 970, 974, 975, 1350.
+\:\\{trie\_ref}, \[961], 963, 964, 967, 968, 970.
+\:\\{trie\_root}, \[958], 960, 963, 969, 977, 1350.
+\:\\{trie\_size}, \[33], 959, 963, 965, 975, 1338, 1345, 1350.
+\:\\{trie\_taken}, \[961], 963, 964, 965, 967, 1350.
+\:\\{trie\_trc}, \[932], 1337, 1338, 1350.
+\:\\{trie\_trl}, \[932], 1337, 1338, 1350.
+\:\\{trie\_tro}, \[932], 961, 1337, 1338, 1350.
+\:\\{trie\_used}, \[954], 955, 956, 957, 1337, 1338.
+\:\\{true}, 4, 16, 32, 38, 46, 47, 50, 52, 54, 72, 78, 89, 98, 99, 105, 106,
+107, 108, 174, 175, 244, 262, 263, 265, 317, 333, 334, 342, 352, 355, 369, 370,
+373, 385, 389, 418, 424, 441, 451, 453, 455, 458, 464, 472, 473, 497, 512, 519,
+523, 527, 535, 536, 537, 545, 565, 574, 589, 603, 631, 632, 639, 648, 649, 652,
+665, 674, 686, 717, 730, 802, 827, 838, 839, 840, 862, 865, 874, 878, 891, 893,
+895, 914, 916, 921, 922, 962, 967, 973, 974, 1003, 1031, 1032, 1036, 1041,
+1046, 1048, 1049, 1050, 1052, 1063, 1066, 1092, 1095, 1102, 1108, 1113, 1133,
+1157, 1175, 1206, 1207, 1230, 1266, 1271, 1283, 1292, 1296, 1311, 1316, 1349,
+1355, 1367, 1383, 1384, 1387, 1393, 1397, 1407, 1415, 1432, 1448, 1450, 1453,
+1459, 1460, 1469, 1472.
+\:\.{true}, 464.
+\:\\{try\_break}, 839, \[840], 850, 862, 869, 873, 877, 878, 879, 880, 884, 890.
+\:\\{two}, \[102], 103.
+\:\\{two\_choices}, \[114].
+\:\\{two\_halves}, 119, 125, 178, 227, 262, 695, 1321, 1345.
+\:\\{tx}, \[424], 435, \[1091], 1092, 1093, \[1117].
+\:\\{type}, \[4], \[134], 135, 136, 137, 138, 139, 143, 144, 145, 146, 147,
+148, 149, 150, 151, 152, 153, 154, 155, 156, 158, 159, 161, 162, 163, 164, 165,
+166, 181, 189, 190, 208, 212, 435, 500, 506, 507, 508, 516, 633, 634, 637, 639,
+642, 643, 646, 648, 649, 651, 660, 662, 664, 666, 679, 680, 681, 691, 692, 693,
+694, 697, 698, 699, 700, 707, 709, 724, 726, 731, 732, 737, 738, 739, 740, 742,
+743, 747, 758, 761, 763, 772, 773, 778, 779, 807, 810, 812, 816, 818, 820, 821,
+822, 827, 830, 831, 833, 841, 843, 848, 852, 853, 854, 855, 856, 867, 869, 870,
+871, 872, 873, 875, 876, 877, 878, 879, 881, 882, 885, 886, 890, 892, 898, 907,
+908, 910, 914, 925, 979, 981, 983, 984, 987, 989, 990, 992, 997, 999, 1004,
+1007, 1008, 1011, 1015, 1019, 1020, 1021, 1022, 1024, 1025, 1032, 1053, 1055,
+1073, 1086, 1090, 1092, 1093, 1099, 1112, 1113, 1115, 1117, 1122, 1125, 1132,
+1133, 1159, 1167, 1170, 1171, 1175, 1177, 1180, 1193, 1197, 1198, 1203, 1214,
+1215, 1354, 1362, 1443, 1444, 1450, 1451, 1454, 1455, 1463, 1464, 1465, 1468,
+1469, 1470, 1471, 1472.
+\:\.{Type <return> to proceed...}, 86.
+\:\|{u}, \[70], \[108], \[400], \[571], \[717], \[737], \[802], \[811], \[940],
+\[945], \[955], \[1270].
+\:\\{u\_part}, 779, \[780], 790, 799, 805, 812.
+\:\\{u\_template}, \[313], 320, 330, 799.
+\:\\{uc\_code}, \[236], 238, 418.
+\:\9{uc\_code\_}{\.{\\uccode} primitive}, \[1242].
+\:\\{uc\_code\_base}, \[236], 241, 1242, 1243, 1299, 1301.
+\:\\{uc\_hyph}, \[242], 902, 907.
+\:\9{uc\_hyph\_}{\.{\\uchyph} primitive}, \[244].
+\:\\{uc\_hyph\_code}, \[242], 243, 244.
+\:\\{ucharcast}, 534.
+\:\\{uexit}, 82.
+\:\\{un\_hbox}, \[214], 1102, 1119, 1120, 1121.
+\:\9{un\_hbox\_}{\.{\\unhbox} primitive}, \[1119].
+\:\9{un\_hcopy\_}{\.{\\unhcopy} primitive}, \[1119].
+\:\9{un\_kern\_}{\.{\\unkern} primitive}, \[1119].
+\:\9{un\_penalty\_}{\.{\\unpenalty} primitive}, \[1119].
+\:\9{un\_skip\_}{\.{\\unskip} primitive}, \[1119].
+\:\\{un\_vbox}, \[214], 1058, 1106, 1119, 1120, 1121.
+\:\9{un\_vbox\_}{\.{\\unvbox} primitive}, \[1119].
+\:\9{un\_vcopy\_}{\.{\\unvcopy} primitive}, \[1119].
+\:\\{unbalance}, \[400], 402, 407, 410, \[484], 488.
+\:\.{Unbalanced output routine}, 1038.
+\:\.{Unbalanced write...}, 1385.
+\:\.{Undefined control sequence}, 381.
+\:\\{undefined\_control\_sequence}, \[228], 238, 265, 268, 274, 288, 1321,
+1331, 1332, 1345.
+\:\\{undefined\_cs}, \[216], 228, 374, 383, 1238, 1239, 1308, 1321.
+\:\\{under\_noad}, \[698], 701, 707, 709, 744, 772, 1168, 1169.
+\:\.{Underfull \\hbox...}, 671.
+\:\.{Underfull \\vbox...}, 685.
+\:\9{underline\_}{\.{\\underline} primitive}, \[1168].
+\:\\{undump}, \[1319], 1325, 1327, 1332, 1338, 1340.
+\:\\{undump\_checked\_things}, 1323, 1336.
+\:\\{undump\_end}, \[1319].
+\:\\{undump\_end\_end}, \[1319].
+\:\\{undump\_four\_ASCII}, \[1323].
+\:\\{undump\_hh}, 1332.
+\:\\{undump\_int}, 1319, 1321, 1325, 1330, 1332, 1338, 1340, 1415.
+\:\\{undump\_qqqq}, 1323.
+\:\\{undump\_size}, \[1319], 1323, 1334, 1338.
+\:\\{undump\_size\_end}, \[1319].
+\:\\{undump\_size\_end\_end}, \[1319].
+\:\\{undump\_things}, 1321, 1323, 1325, 1330, 1332, 1334, 1336, 1338, 1401.
+\:\\{undump\_upper\_check\_things}, 1336, 1338.
+\:\\{unfloat}, \[110], 669, 675, 684, 687, 821, 822.
+\:\\{unhyphenated}, \[830], 840, 848, 875, 877, 878, 879.
+\:\\{unity}, \[102], 104, 115, 170, 192, 464, 579, 1272.
+\:\\{unpackage}, 1121, \[1122].
+\:\\{unsave}, \[287], 289, 802, 811, 1037, 1075, 1080, 1098, 1112, 1131, 1145,
+1180, 1186, 1198, 1203, 1206, 1208, 1212.
+\:\\{unset\_node}, 137, \[165], 181, 189, 190, 208, 212, 662, 680, 693, 699,
+700, 779, 807, 810, 812, 816.
+\:\\{unsigned}, 1336.
+\:\\{unspecified\_mode}, \[74], 75, 1340.
+\:\\{update\_active}, \[872].
+\:\\{update\_heights}, \[981], 983, 984, 1005, 1008, 1011.
+\:\\{update\_terminal}, \[35], 38, 62, 72, 82, 87, 370, 535, 548, 649, 1293,
+1351.
+\:\\{update\_width}, \[843], 871.
+\:\9{uppercase\_}{\.{\\uppercase} primitive}, \[1299].
+\:\.{Use of x doesn't match...}, 409.
+\:\\{use\_err\_help}, \[80], 81, 90, 91, 1296.
+\:\\{ustringcast}, 349, 362, 364, 475.
+\:\|{v}, \[70], \[108], \[400], \[461], \[717], \[726], \[747], \[754], \[760],
+\[811], \[841], \[933], \[945], \[955], \[971], \[988], \[1150].
+\:\\{v\_offset}, \[253], 651, 652.
+\:\9{v\_offset\_}{\.{\\voffset} primitive}, \[254].
+\:\\{v\_offset\_code}, \[253], 254.
+\:\\{v\_part}, 779, \[780], 790, 800, 805, 812.
+\:\\{v\_template}, \[313], 320, 331, 401, 800, 1143.
+\:\\{vacuous}, \[451], 455, 456.
+\:\\{vadjust}, \[214], 271, 272, 1109, 1110, 1111, 1112.
+\:\9{vadjust\_}{\.{\\vadjust} primitive}, \[271].
+\:\\{valign}, \[214], 271, 272, 1058, 1102, 1142.
+\:\9{valign\_}{\.{\\valign} primitive}, \[271].
+\:\\{var\_code}, \[238], 1163, 1167, 1177.
+\:\\{var\_delimiter}, \[717], 748, 759, 773.
+\:\\{var\_used}, \[118], 126, 131, 170, 650, 1324, 1325.
+\:\\{vbadness}, \[242], 685, 688, 689, 1023, 1028.
+\:\9{vbadness\_}{\.{\\vbadness} primitive}, \[244].
+\:\\{vbadness\_code}, \[242], 243, 244.
+\:\9{vbox\_}{\.{\\vbox} primitive}, \[1083].
+\:\\{vbox\_group}, \[275], 1095, 1097.
+\:\\{vcenter}, \[214], 271, 272, 1058, 1179.
+\:\9{vcenter\_}{\.{\\vcenter} primitive}, \[271].
+\:\\{vcenter\_group}, \[275], 1179, 1180.
+\:\\{vcenter\_noad}, \[698], 701, 707, 709, 744, 772, 1180.
+\:\\{version\_string}, 62, 547.
+\:\\{vert\_break}, \[981], 982, 987, 988, 991, 993, 1021.
+\:\\{very\_loose\_fit}, \[828], 830, 841, 844, 845, 847, 863.
+\:\\{vet\_glue}, \[636], 645.
+\:\9{vfil\_}{\.{\\vfil} primitive}, \[1070].
+\:\9{vfil\_neg\_}{\.{\\vfilneg} primitive}, \[1070].
+\:\9{vfill\_}{\.{\\vfill} primitive}, \[1070].
+\:\\{vfuzz}, \[253], 688, 1023, 1028.
+\:\9{vfuzz\_}{\.{\\vfuzz} primitive}, \[254].
+\:\\{vfuzz\_code}, \[253], 254.
+\:\.{VIRTEX}, 1344.
+\:{virtual memory}, 127.
+\:{Vitter, Jeffrey Scott}, 267.
+\:\\{vlist\_node}, \[138], 139, 154, 165, 181, 189, 190, 208, 212, 516, 629,
+633, 634, 639, 640, 642, 643, 648, 651, 655, 662, 679, 680, 692, 724, 747, 758,
+761, 818, 820, 822, 852, 853, 877, 878, 881, 882, 979, 984, 989, 1004, 1011,
+1086, 1092, 1099, 1122, 1159, 1465.
+\:\\{vlist\_out}, 603, 626, 627, 629, 630, 634, 639, \[640], 643, 648, 649,
+651, 704, 1386, 1446, 1465.
+\:\\{vmode}, \[217], 221, 427, 428, 429, 433, 435, 512, 786, 796, 797, 815,
+818, 819, 820, 823, 1036, 1040, 1057, 1058, 1060, 1068, 1069, 1083, 1084, 1085,
+1088, 1090, 1091, 1092, 1095, 1102, 1103, 1106, 1110, 1111, 1115, 1117, 1121,
+1122, 1123, 1142, 1179, 1256, 1257.
+\:\\{vmove}, \[214], 1060, 1083, 1084, 1085.
+\:\\{vpack}, 242, 655, 656, 657, \[679], 716, 746, 749, 770, 810, 815, 988,
+1032, 1112, 1180.
+\:\\{vpackage}, \[679], 807, 988, 1028, 1098.
+\:\\{vrule}, \[214], 271, 272, 474, 1068, 1096, 1102.
+\:\9{vrule\_}{\.{\\vrule} primitive}, \[271].
+\:\\{vsize}, \[253], 991, 998.
+\:\9{vsize\_}{\.{\\vsize} primitive}, \[254].
+\:\\{vsize\_code}, \[253], 254.
+\:\\{vskip}, \[214], 1058, 1069, 1070, 1071, 1090, 1106.
+\:\9{vskip\_}{\.{\\vskip} primitive}, \[1070].
+\:\\{vsplit}, 978, \[988], 989, 991, 1094.
+\:\9{vsplit\_}{\.{\\vsplit needs a \\vbox}}, 989.
+\:\9{vsplit\_}{\.{\\vsplit} primitive}, \[1083].
+\:\\{vsplit\_code}, \[1083], 1084, 1091.
+\:\9{vss\_}{\.{\\vss} primitive}, \[1070].
+\:\9{vtop\_}{\.{\\vtop} primitive}, \[1083].
+\:\\{vtop\_code}, \[1083], 1084, 1095, 1097, 1098.
+\:\\{vtop\_group}, \[275], 1095, 1097.
+\:\|{w}, \[115], \[153], \[162], \[281], \[284], \[285], \[618], \[660], %
+\[679], \[717], \[726], \[749], \[802], \[811], \[917], \[1005], \[1135], %
+\[1150], \[1210], \[1362], \[1363].
+\:\\{w\_close}, 1342, 1350.
+\:\\{w\_make\_name\_string}, \[536], 1341.
+\:\\{w\_open\_in}, 535.
+\:\\{w\_open\_out}, 1341.
+\:\\{wait}, \[1023], 1031, 1032, 1033.
+\:\\{wake\_up\_terminal}, \[35], 38, 52, 72, 74, 371, 495, 535, 541, 1307,
+1310, 1316, 1321, 1346, 1351.
+\:\\{warning\_index}, \[311], 337, 344, 400, 401, 406, 407, 409, 412, 484, 490,
+493, 785, 788.
+\:\\{warning\_issued}, \[77], 82, 251, 1348.
+\:\\{was\_free}, \[171], 173, 177.
+\:\\{was\_hi\_min}, \[171], 172, 173, 177.
+\:\\{was\_lo\_max}, \[171], 172, 173, 177.
+\:\\{was\_mem\_end}, \[171], 172, 173, 177.
+\:\\{wchar\_token}, 299, 325, 365, 373, 385, 453, 482.
+\:\9{wd\_}{\.{\\wd} primitive}, \[427].
+\:\.{WEB}, 1, 4, 39, 41, 51, 1321.
+\:\\{what\_lang}, \[1354], 1369, 1375, 1389, 1390.
+\:\\{what\_lhm}, \[1354], 1369, 1375, 1389, 1390.
+\:\\{what\_rhm}, \[1354], 1369, 1375, 1389, 1390.
+\:\\{whatsit\_node}, \[152], 154, 181, 189, 208, 212, 633, 642, 662, 680, 741,
+772, 877, 907, 910, 979, 984, 1011, 1159, 1354, 1362, 1450, 1451, 1464.
+\:\\{widow\_pena}, \[163], 200, 1122, 1463.
+\:\\{widow\_penalty}, \[242], 1108.
+\:\9{widow\_penalty\_}{\.{\\widowpenalty} primitive}, \[244].
+\:\\{widow\_penalty\_code}, \[242], 243, 244.
+\:\.{width}, 474.
+\:\\{width}, \[136], 137, 140, 141, 142, 143, 144, 153, 156, 157, 161, 162,
+184, 190, 193, 197, 198, 435, 440, 442, 462, 473, 474, 565, 616, 618, 622, 631,
+633, 634, 636, 637, 642, 644, 645, 646, 652, 662, 664, 665, 667, 668, 677, 679,
+680, 681, 682, 690, 694, 699, 717, 720, 725, 726, 727, 728, 742, 749, 755, 758,
+760, 761, 763, 768, 769, 770, 779, 790, 804, 807, 808, 809, 812, 813, 814, 815,
+817, 818, 819, 820, 821, 822, 838, 848, 849, 852, 853, 877, 878, 879, 881, 882,
+892, 980, 987, 1007, 1012, 1015, 1020, 1054, 1056, 1066, 1103, 1105, 1159,
+1160, 1211, 1213, 1217, 1241, 1252, 1253, 1465, 1472.
+\:\\{width\_base}, \[561], 565, 577, 580, 582, 587, 1335, 1336, 1350.
+\:\\{width\_index}, \[554], 561.
+\:\\{width\_offset}, \[136], 427, 428, 1260.
+\:{Wirth, Niklaus}, 10.
+\:\\{wlog}, \[57], 58, 59, 545, 547, 1347.
+\:\\{wlog\_cr}, \[57], 58, 59, 545, 547, 1346.
+\:\\{wlog\_ln}, \[57], 1347.
+\:\\{word\_define}, \[1226], 1236, 1240, 1244, 1249, 1441.
+\:\\{word\_file}, 25, \[114], 536, 1318.
+\:\\{words}, \[210], 211, 212, 1370.
+\:\\{wrap\_lig}, \[921], 922.
+\:\\{wrapup}, \[1046], 1052.
+\:\\{write}, 38, 57, 59, 608, 1319.
+\:\9{write\_}{\.{\\write} primitive}, \[1357].
+\:\\{write\_dvi}, 608, 609, 610, 651.
+\:\\{write\_file}, 58, 59, \[1355], 1387, 1391.
+\:\\{write\_ln}, 38, 52, 57, 58, 1319, 1395.
+\:\\{write\_loc}, 1326, 1327, 1357, \[1358], 1384.
+\:\\{write\_node}, \[1354], 1357, 1359, 1361, 1369, 1370, 1371, 1386, 1387.
+\:\\{write\_node\_size}, \[1354], 1363, 1365, 1366, 1367, 1370, 1371, 1475.
+\:\\{write\_open}, \[1355], 1356, 1383, 1387, 1391.
+\:\\{write\_out}, \[1383], 1387.
+\:\\{write\_stream}, \[1354], 1363, 1367, 1368, 1383, 1387, 1475.
+\:\\{write\_text}, \[313], 320, 329, 1353, 1384.
+\:\\{write\_tokens}, \[1354], 1365, 1366, 1367, 1369, 1370, 1371, 1381, 1384,
+1475.
+\:\\{writing}, \[589].
+\:\\{wterm}, \[57], 58, 59, 62, 535.
+\:\\{wterm\_cr}, \[57], 58, 59.
+\:\\{wterm\_ln}, \[57], 62, 535, 1316, 1321, 1345, 1350.
+\:{Wyatt, Douglas Kirk}, 2.
+\:\\{w0}, 596, \[597], 615, 620.
+\:\\{w1}, 596, \[597], 618.
+\:\\{w2}, \[596].
+\:\\{w3}, \[596].
+\:\\{w4}, \[596].
+\:\|{x}, \[101], \[106], \[107], \[108], \[598], \[611], \[660], \[679], %
+\[717], \[731], \[737], \[746], \[748], \[749], \[754], \[760], \[767], %
+\[1135], \[1315], \[1316].
+\:\\{x\_height}, 558, \[569], 570, 749, 1135, 1413.
+\:\\{x\_height\_code}, \[558], 569.
+\:\\{x\_leaders}, \[155], 196, 638, 1083, 1084.
+\:\9{x\_leaders\_}{\.{\\xleaders} primitive}, \[1083].
+\:\\{x\_over\_n}, \[107], 714, 727, 728, 997, 1019, 1020, 1021, 1253.
+\:\\{x\_token}, 372, \[392], 489, 1049, 1164, 1469.
+\:\\{xchr}, 20, 21, 23, 24, 39, 50, 59, 530, 1383, 1400, 1401.
+\:\&{xclause}, 16.
+\:\9{xdef\_}{\.{\\xdef} primitive}, \[1220].
+\:\\{xeq\_level}, \[259], 260, 274, 284, 285, 289, 1317.
+\:\\{xkanji\_skip}, \[230], 1098, 1206, 1451.
+\:\9{xkanji\_skip\_}{\.{\\xkanjiskip} primitive}, \[232].
+\:\\{xkanji\_skip\_code}, \[230], 231, 232, 1122, 1459, 1460.
+\:\\{xmalloc\_array}, 52, 530, 534, 1320, 1321, 1323, 1334, 1336, 1338, 1345,
+1350.
+\:\\{xn\_over\_d}, \[108], 466, 468, 469, 579, 727, 1056, 1273.
+\:\\{xord}, \[20], 24, 53, 54, 534, 536, 1400, 1401.
+\:\\{xpand}, \[484], 488, 490.
+\:\\{xprn}, 20, 24, 50, 1400, 1401.
+\:\\{xray}, \[214], 1303, 1304, 1305.
+\:\\{xspace\_ptr}, \[136], 137, 208, 212, 223, 431, 649, 660, 679, 726, 737,
+738, 762, 767, 807, 810, 815, 827, 988, 989, 1004, 1032, 1088, 1090, 1112,
+1122, 1213, 1451.
+\:\\{xspace\_skip}, \[230], 1055.
+\:\9{xspace\_skip\_}{\.{\\xspaceskip} primitive}, \[232].
+\:\\{xspace\_skip\_code}, \[230], 231, 232, 1055.
+\:\\{xxx1}, 596, \[597], 1381.
+\:\\{xxx2}, \[596].
+\:\\{xxx3}, \[596].
+\:\\{xxx4}, 596, \[597], 1381.
+\:\\{x0}, 596, \[597], 615, 620.
+\:\\{x1}, 596, \[597], 618.
+\:\\{x2}, \[596].
+\:\\{x3}, \[596].
+\:\\{x4}, \[596].
+\:\|{y}, \[106], \[717], \[737], \[746], \[748], \[749], \[754], \[760], \[767].
+\:\\{y\_baseline\_shift}, \[253], 1045, 1136, 1208, 1469.
+\:\9{y\_baseline\_shift\_}{\.{\\ybaselineshift} primitive}, \[254].
+\:\\{y\_baseline\_shift\_code}, \[253], 254.
+\:\\{y\_here}, \[619], 620, 622, 623, 624.
+\:\\{y\_OK}, \[619], 620, 623.
+\:\\{y\_seen}, \[622], 623.
+\:\\{year}, \[242], 247, 547, 628, 1341.
+\:\9{year\_}{\.{\\year} primitive}, \[244].
+\:\\{year\_code}, \[242], 243, 244.
+\:\\{yhash}, \[262], 1321, 1345.
+\:\9{yoko\_}{\.{\\yoko} primitive}, \[1083].
+\:\\{yoko\_jfm\_id}, \[551], 576.
+\:\.{You already have nine...}, 487.
+\:\.{You can't \\insert255}, 1111.
+\:\.{You can't dump...}, 1317.
+\:\.{You can't use \\hrule...}, 1107.
+\:\.{You can't use \\long...}, 1225.
+\:\.{You can't use a prefix with x}, 1224.
+\:\.{You can't use x after ...}, 439, 1250.
+\:\.{You can't use x in y mode}, 1061.
+\:\.{You have to increase POOLSIZE}, 53.
+\:\\{you\_cant}, \[1061], 1062, 1092, 1118.
+\:\\{yz\_OK}, \[619], 620, 621, 623.
+\:\\{yzmem}, \[117], 1321, 1345.
+\:\\{y0}, 596, \[597], 605, 615, 620.
+\:\\{y1}, 596, \[597], 618, 624.
+\:\\{y2}, \[596], 605.
+\:\\{y3}, \[596].
+\:\\{y4}, \[596].
+\:\|{z}, \[571], \[717], \[737], \[754], \[760], \[767], \[811], \[933], %
+\[938], \[964], \[970], \[1210].
+\:\\{z\_here}, \[619], 620, 622, 623, 625.
+\:\\{z\_OK}, \[619], 620, 623.
+\:\\{z\_seen}, \[622], 623.
+\:{Zabala Salelles, Ignacio Andr\'es}, 2.
+\:\.{ze}, 466.
+\:\\{zeqtb}, \[259], 1321, 1345, 1350.
+\:\\{zero\_glue}, 137, \[168], 181, 230, 234, 435, 473, 659, 679, 743, 763,
+813, 898, 1053, 1054, 1055, 1098, 1137, 1183, 1206, 1241, 1451, 1472.
+\:\\{zero\_token}, \[456], 463, 484, 487, 490.
+\:\.{zh}, 466.
+\:\\{zmem}, \[117], 1321, 1345.
+\:\\{z0}, 596, \[597], 615, 620.
+\:\\{z1}, 596, \[597], 618, 625.
+\:\\{z2}, \[596].
+\:\\{z3}, \[596].
+\:\\{z4}, \[596].
+\fin
+\:\X456:Accumulate the constant until \\{cur\_tok} is not a suitable digit\X
+\U455.
+\:\X882:Add the width of node \|s to \\{act\_width}\X
+\U880.
+\:\X853:Add the width of node \|s to \\{break\_width}\X
+\U851.
+\:\X881:Add the width of node \|s to \\{disc\_width}\X
+\U880.
+\:\X468:Adjust \(f)for the magnification ratio\X
+\U464.
+\:\X1226:Adjust \(f)for the setting of \.{\\globaldefs}\X
+\U1223.
+\:\X757:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of a fraction
+line\X
+\U754.
+\:\X756:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of no
+fraction line\X
+\U754.
+\:\X878:Advance \(c)\\{cur\_p} to the node following the present string of
+characters\X
+\U877.
+\:\X1375:Advance \(p)past a whatsit node in the \(l)\\{line\_break} loop\X
+\U877.
+\:\X1376:Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop\X
+\U907.
+\:\X405:Advance \(r)\|r; \&{goto} \\{found} if the parameter delimiter has been
+fully matched, otherwise \&{goto} \\{continue}\X
+\U403.
+\:\X130:Allocate entire node \|p and \&{goto} \\{found}\X
+\U128.
+\:\X129:Allocate from the top of node \|p and \&{goto} \\{found}\X
+\U128.
+\:\X1118:Apologize for inability to do the operation now, unless \.{\\unskip}
+follows non-glue\X
+\U1117.
+\:\X578:Apologize for not loading the font, \&{goto} \\{done}\X
+\U577.
+\:\X1462:Append KANJI-KANJI spacing\X
+\U1455.
+\:\X1469:Append KANJI-character \\{cur\_chr} to the current hlist in the
+current font; \&{goto} \\{reswitch} when a non-character has been fetched\X
+\U1041.
+\:\X921:Append a ligature and/or kern to the translation; \&{goto} \\{continue}
+if the stack of inserted ligatures is nonempty\X
+\U917.
+\:\X1090:Append a new leader node that uses \\{cur\_box}\X
+\U1087.
+\:\X973:Append a new letter or a hyphen level\X
+\U972.
+\:\X948:Append a new letter or hyphen\X
+\U946.
+\:\X1053:Append a normal inter-word space to the current list, then \&{goto} %
+\\{big\_switch}\X
+\U1041.
+\:\X901:Append a penalty node, if a nonzero penalty is appropriate\X
+\U891.
+\:\X1019:Append an insertion to the current page and \&{goto} \\{contribute}\X
+\U1011.
+\:\X778:Append any \\{new\_hlist} entries for \|q, and any appropriate
+penalties\X
+\U771.
+\:\X1088:Append box \\{cur\_box} to the current list, shifted by \\{box%
+\_context}\X
+\U1087.
+\:\X1045:Append character \\{cur\_chr} and the following characters (if~any) to
+the current hlist in the current font; \&{goto} \\{reswitch} when a
+non-character has been fetched\X
+\U1041.
+\:\X928:Append characters of $\\{hu}[\|j\to\,]$ to \\{major\_tail}, advancing~%
+\|j\X
+\U927.
+\:\X777:Append inter-element spacing based on \\{r\_type} and \|t\X
+\U771.
+\:\X820:Append tabskip glue and an empty box to list \|u, and update \|s and %
+\|t as the prototype nodes are passed\X
+\U819.
+\:\X1137:Append the accent with appropriate kerns, then set $\|p\K\|q$\X
+\U1135.
+\:\X789:Append the current tabskip glue to the preamble list\X
+\U788.
+\:\X1216:Append the display and perhaps also the equation number\X
+\U1211.
+\:\X1217:Append the glue or equation number following the display\X
+\U1211.
+\:\X1215:Append the glue or equation number preceding the display\X
+\U1211.
+\:\X899:Append the new box to the current vertical list, followed by the list
+of special nodes taken out of the box by the packager\X
+\U891.
+\:\X949:Append the value \|n to list \|p\X
+\U948.
+\:\X1470:Append \\{disp\_node} at begin of displace area\X
+\Us1045, 1136\ETs1208.
+\:\X1471:Append \\{disp\_node} at end of displace area\X
+\Us1047, 1135, 1208\ETs1469.
+\:\X242:Assign the values $\\{depth\_threshold}\K\\{show\_box\_depth}$ and $%
+\\{breadth\_max}\K\\{show\_box\_breadth}$\X
+\U204.
+\:\X1229, 1230, 1233, 1236, 1237, 1238, 1240, 1244, 1247, 1248, 1254, 1255,
+1261, 1265, 1266, 1269, 1277, 1423, 1428, 1436, 1441:Assignments\X
+\U1223.
+\:\X1132:Attach list \|p to the current list, and record its length; then
+finish up and \&{return}\X
+\U1131.
+\:\X762:Attach the limits to \|y and adjust $\\{height}(\|v)$, $\\{depth}(\|v)$
+to account for their presence\X
+\U761.
+\:\X343:Back up an outer control sequence so that it can be reread\X
+\U342.
+\:\X58, 59, 60, 61, 63, 64, 65, 66, 268, 269, 529, 710, 1368, 1395, 1398, 1467,
+1473:Basic printing procedures\X
+\U4.
+\:\X1028:Break the current page at node \|p, put it in box~255, and put the
+remaining nodes on the contribution list\X
+\U1025.
+\:\X887:Break the paragraph at the chosen breakpoints, justify the resulting
+lines to the correct widths, and append them to the current vertical list\X
+\U826.
+\:\X1161:Calculate the length, \|l, and the shift amount, \|s, of the display
+lines\X
+\U1157.
+\:\X1158:Calculate the natural width, \|w, by which the characters of the final
+line extend to the right of the reference point, plus two ems; or set $\|w\K%
+\\{max\_dimen}$ if the non-blank information on that line is affected by
+stretching or shrinking\X
+\U1157.
+\:\X900:Call the packaging subroutine, setting \\{just\_box} to the justified
+box\X
+\U891.
+\:\X877:Call \\{try\_break} if \\{cur\_p} is a legal breakpoint; on the second
+pass, also try to hyphenate the next word, if \\{cur\_p} is a glue node; then
+advance \\{cur\_p} to the next node of the paragraph that could possibly be a
+legal breakpoint\X
+\U874.
+\:\X922:Carry out a ligature replacement, updating the cursor structure and
+possibly advancing~\|j; \&{goto} \\{continue} if the cursor doesn't advance,
+otherwise \&{goto} \\{done}\X
+\U920.
+\:\X212:Case statement to copy different types and set \\{words} to the number
+of initial words not yet copied\X
+\U211.
+\:\X744:Cases for noads that can follow a \\{bin\_noad}\X
+\U739.
+\:\X741:Cases for nodes that can appear in an mlist, after which we \&{goto} %
+\\{done\_with\_node}\X
+\U739.
+\:\X709:Cases of \\{flush\_node\_list} that arise in mlists only\X
+\U208.
+\:\X1097, 1112, 1130, 1144, 1145, 1180, 1185, 1198:Cases of \\{handle\_right%
+\_brace} where a \\{right\_brace} triggers a delayed action\X
+\U1080.
+\:\X1360:Cases of \\{main\_control} that are for extensions to \TeX\X
+\U1057.
+\:\X1057:Cases of \\{main\_control} that are not part of the inner loop\X
+\U1041.
+\:\X1068, 1069, 1075, 1079, 1085, 1102, 1104, 1106, 1109, 1114, 1116, 1121,
+1124, 1128, 1134, 1138, 1142, 1146, 1149, 1152, 1162, 1166, 1170, 1174, 1176,
+1179, 1183, 1187, 1192, 1202, 1205:Cases of \\{main\_control} that build boxes
+and lists\X
+\U1057.
+\:\X1222, 1281, 1284, 1287, 1289, 1298, 1303, 1432:Cases of \\{main\_control}
+that don't depend on \\{mode}\X
+\U1057.
+\:\X233, 237, 245, 255, 272, 341, 388, 396, 423, 428, 480, 499, 503, 792, 995,
+1065, 1071, 1084, 1101, 1120, 1127, 1155, 1169, 1182, 1191, 1201, 1221, 1232,
+1235, 1243, 1264, 1268, 1274, 1276, 1286, 1291, 1300, 1305, 1308, 1359, 1422,
+1427, 1434, 1439:Cases of \\{print\_cmd\_chr} for symbolic printing of
+primitives\X
+\U304.
+\:\X701:Cases of \\{show\_node\_list} that arise in mlists only\X
+\U189.
+\:\X351:Cases where character is ignored\X
+\U350.
+\:\X624:Change buffered instruction to \|y or \|w and \&{goto} \\{found}\X
+\U623.
+\:\X625:Change buffered instruction to \|z or \|x and \&{goto} \\{found}\X
+\U623.
+\:\X786:Change current mode to $-\\{vmode}$ for \.{\\halign}, $-\\{hmode}$ for %
+\.{\\valign}\X
+\U785.
+\:\X893:Change discretionary to compulsory and set $\\{disc\_break}\K\\{true}$\X
+\U892.
+\:\X632:Change font \\{dvi\_f} to \|f\X
+\U631.
+\:\X350:Change state if necessary, and \&{goto} \\{switch} if the current
+character should be ignored, or \&{goto} \\{reswitch} if the current character
+changes to another\X
+\U349.
+\:\X1302:Change the case of the token in \|p, if a change is appropriate\X
+\U1301.
+\:\X774:Change the current style and \&{goto} \\{delete\_q}\X
+\U772.
+\:\X87:Change the interaction level and \&{return}\X
+\U85.
+\:\X742:Change this node to a style node followed by the correct choice, then %
+\&{goto} \\{done\_with\_node}\X
+\U741.
+\:\X50:Character \|k cannot be printed\X
+\U49.
+\:\X250:Character \|s is the current new-line character\X
+\Us59\ET60.
+\:\X176:Check flags of unavailable nodes\X
+\U173.
+\:\X581:Check for charlist cycle\X
+\U580.
+\:\X787:Check for improper alignment in displayed math\X
+\U785.
+\:\X985:Check if node \|p is a new champion breakpoint; then \(go)\&{goto} %
+\\{done} if \|p is a forced break or if the page-so-far is already too full\X
+\U983.
+\:\X1016:Check if node \|p is a new champion breakpoint; then \(if)if it is
+time for a page break, prepare for output, and either fire up the user's output
+routine and \&{return} or ship out the page and \&{goto} \\{done}\X
+\U1008.
+\:\X174:Check single-word \\{avail} list\X
+\U173.
+\:\X1209:Check that another \.\$ follows\X
+\Us1206, 1206\ETs1218.
+\:\X1207:Check that the necessary fonts for math symbols are present; if not,
+flush the current math lists and set $\\{danger}\K\\{true}$\X
+\Us1206\ET1206.
+\:\X910:Check that the nodes following \\{hb} permit hyphenation and that at
+least $\\{l\_hyf}+\\{r\_hyf}$ letters have been found, otherwise \&{goto} %
+\\{done1}\X
+\U905.
+\:\X14, 112, 296, 533, 1262:Check the ``constant'' values for consistency\X
+\U1345.
+\:\X54:Check the pool check sum\X
+\U53.
+\:\X175:Check variable-size \\{avail} list\X
+\U173.
+\:\X876:Clean up the memory by removing the break nodes\X
+\Us826\ET874.
+\:\X661:Clear dimensions to zero\X
+\Us660\ET679.
+\:\X288:Clear off top level from \\{save\_stack}\X
+\U287.
+\:\X1342:Close the format file\X
+\U1315.
+\:\X462:Coerce glue to a dimension\X
+\Us460\ET466.
+\:\X9:Compiler directives\X
+\U4.
+\:\X734:Complain about an undefined family and set \\{cur\_i} null\X
+\U733.
+\:\X381:Complain about an undefined macro\X
+\U378.
+\:\X384:Complain about missing \.{\\endcsname}\X
+\U383.
+\:\X470:Complain about unknown unit and \&{goto} \\{done2}\X
+\U469.
+\:\X439:Complain that \.{\\the} can't do this; give zero result\X
+\U424.
+\:\X1178:Complain that the user should have said \.{\\mathaccent}\X
+\U1177.
+\:\X1197:Compleat the incompleat noad\X
+\U1196.
+\:\X1311:Complete a potentially long \.{\\show} command\X
+\U1306.
+\:\X1253:Compute result of \\{multiply} or \\{divide}, put it in \\{cur\_val}\X
+\U1249.
+\:\X1251:Compute result of \\{register} or \\{advance}, put it in \\{cur\_val}\X
+\U1249.
+\:\X752:Compute the amount of skew\X
+\U749.
+\:\X1018:Compute the badness, \|b, of the current page, using \\{awful\_bad} if
+the box is too full\X
+\U1016.
+\:\X986:Compute the badness, \|b, using \\{awful\_bad} if the box is too full\X
+\U985.
+\:\X870:Compute the demerits, \|d, from \|r to \\{cur\_p}\X
+\U866.
+\:\X851:Compute the discretionary \\{break\_width} values\X
+\U848.
+\:\X267:Compute the hash code \|h\X
+\U265.
+\:\X776:Compute the magic offset\X
+\U1350.
+\:\X725:Compute the minimum suitable height, \|w, and the corresponding number
+of extension steps, \|n; also set $\\{width}(\|b)$\X
+\U724.
+\:\X861:Compute the new line width\X
+\U846.
+\:\X1250:Compute the register location \|l and its type \|p; but \&{return} if
+invalid\X
+\U1249.
+\:\X1252:Compute the sum of two glue specs\X
+\U1251.
+\:\X976:Compute the trie op code, \|v, and set $\|l\K0$\X
+\U974.
+\:\X848:Compute the values of \\{break\_width}\X
+\U847.
+\:\X623:Consider a node with matching width; \&{goto} \\{found} if it's a hit\X
+\U622.
+\:\X862:Consider the demerits for a line from \|r to \\{cur\_p}; deactivate
+node \|r if it should no longer be active; then \&{goto} \\{continue} if a line
+from \|r to \\{cur\_p} is infeasible, otherwise record a new feasible break\X
+\U840.
+\:\X11:Constants in the outer block\X
+\U4.
+\:\X761:Construct a box with limits above and below it, skewed by \\{delta}\X
+\U760.
+\:\X770:Construct a sub/superscript combination box \|x, with the superscript
+offset by \\{delta}\X
+\U767.
+\:\X768:Construct a subscript box \|x when there is no superscript\X
+\U767.
+\:\X769:Construct a superscript box \|x\X
+\U767.
+\:\X758:Construct a vlist box for the fraction, according to \\{shift\_up} and %
+\\{shift\_down}\X
+\U754.
+\:\X724:Construct an extensible character in a new box \|b, using recipe $%
+\\{rem\_byte}(\|q)$ and font \|f\X
+\U721.
+\:\X410:Contribute an entire group to the current parameter\X
+\U403.
+\:\X408:Contribute the recently matched tokens to the current parameter, and %
+\&{goto} \\{continue} if a partial match is still in effect; but abort if $\|s=%
+\\{null}$\X
+\U403.
+\:\X740:Convert \(a)a final \\{bin\_noad} to an \\{ord\_noad}\X
+\Us737\ET739.
+\:\X440:Convert \(c)\\{cur\_val} to a lower level\X
+\U424.
+\:\X743:Convert \(m)math glue to ordinary glue\X
+\U741.
+\:\X765:Convert \(n)$\\{nucleus}(\|q)$ to an hlist and attach the
+sub/superscripts\X
+\U739.
+\:\X806:Copy the tabskip glue between columns\X
+\U802.
+\:\X805:Copy the templates from node \\{cur\_loop} into node \|p\X
+\U804.
+\:\X477:Copy the token list\X
+\U476.
+\:\X766:Create a character node \|p for $\\{nucleus}(\|q)$, possibly followed
+by a kern node for the italic correction, and set \\{delta} to the italic
+correction if a subscript is present\X
+\U765.
+\:\X1136:Create a character node \|q for the next character, but set $\|q\K%
+\\{null}$ if problems arise\X
+\U1135.
+\:\X473:Create a new glue specification whose width is \\{cur\_val}; scan for
+its stretch and shrink components\X
+\U472.
+\:\X1020:Create a page insertion node with $\\{subtype}(\|r)=\\{qi}(\|n)$, and
+include the glue correction for box \|n in the current page state\X
+\U1019.
+\:\X875:Create an active breakpoint representing the beginning of the paragraph%
+\X
+\U874.
+\:\X925:Create and append a discretionary node as an alternative to the
+unhyphenated word, and continue to develop both branches until they become
+equivalent\X
+\U924.
+\:\X755:Create equal-width boxes \|x and \|z for the numerator and denominator,
+and compute the default amounts \\{shift\_up} and \\{shift\_down} by which they
+are displaced from the baseline\X
+\U754.
+\:\X847:Create new active nodes for the best feasible breaks just found\X
+\U846.
+\:\X1341:Create the \\{format\_ident}, open the format file, and inform the
+user that dumping has begun\X
+\U1315.
+\:\X230:Current \\{mem} equivalent of glue parameter number \|n\X
+\Us158\ET160.
+\:\X871:Deactivate node \|r\X
+\U862.
+\:\X1055, 1059, 1061, 1062, 1063, 1066, 1072, 1073, 1076, 1081, 1082, 1087,
+1091, 1096, 1098, 1103, 1105, 1107, 1108, 1111, 1113, 1115, 1117, 1122, 1125,
+1129, 1131, 1135, 1139, 1141, 1143, 1147, 1148, 1150, 1154, 1163, 1167, 1171,
+1172, 1175, 1177, 1184, 1186, 1188, 1193, 1203, 1206, 1212, 1223, 1283, 1288,
+1292, 1301, 1306, 1315, 1361, 1389, 1468, 1475:Declare action procedures for
+use by \\{main\_control}\X
+\U1041.
+\:\X1407, 1408:Declare additional functions for ML\TeX\X
+\U571.
+\:\X1402, 1403:Declare additional routines for string recycling\X
+\U48.
+\:\X745, 746, 747, 748, 749, 754, 760, 763, 767, 773:Declare math construction
+procedures\X
+\U737.
+\:\X955, 959, 960, 964, 968, 970, 971, 977:Declare procedures for preprocessing
+hyphenation patterns\X
+\U953.
+\:\X702, 703, 705:Declare procedures needed for displaying the elements of
+mlists\X
+\U185.
+\:\X1362, 1363:Declare procedures needed in \\{do\_extension}\X
+\U1361.
+\:\X1381, 1383, 1386, 1448, 1450, 1451, 1465:Declare procedures needed in %
+\\{hlist\_out}, \\{vlist\_out}\X
+\U630.
+\:\X1425, 1435, 1440:Declare procedures needed in \\{scan\_something\_internal}%
+\X
+\U424.
+\:\X588, 589, 1416:Declare procedures that scan font-related stuff\X
+\U420.
+\:\X444, 445, 446, 447, 448, 1399:Declare procedures that scan restricted
+classes of integers\X
+\U420.
+\:\X837, 840, 888, 906, 953:Declare subprocedures for \\{line\_break}\X
+\U826.
+\:\X1227, 1241, 1249, 1256, 1257, 1258, 1259, 1260, 1270, 1278:Declare
+subprocedures for \\{prefixed\_command}\X
+\U1223.
+\:\X720, 722, 723:Declare subprocedures for \\{var\_delimiter}\X
+\U717.
+\:\X1196:Declare the function called \\{fin\_mlist}\X
+\U1186.
+\:\X535:Declare the function called \\{open\_fmt\_file}\X
+\U1316.
+\:\X917:Declare the function called \\{reconstitute}\X
+\U906.
+\:\X796:Declare the procedure called \\{align\_peek}\X
+\U811.
+\:\X1023:Declare the procedure called \\{fire\_up}\X
+\U1005.
+\:\X793:Declare the procedure called \\{get\_preamble\_token}\X
+\U785.
+\:\X1080:Declare the procedure called \\{handle\_right\_brace}\X
+\U1041.
+\:\X798:Declare the procedure called \\{init\_span}\X
+\U797.
+\:\X390:Declare the procedure called \\{insert\_relax}\X
+\U377.
+\:\X400:Declare the procedure called \\{macro\_call}\X
+\U377.
+\:\X304:Declare the procedure called \\{print\_cmd\_chr}\X
+\U258.
+\:\X231:Declare the procedure called \\{print\_skip\_param}\X
+\U185.
+\:\X290:Declare the procedure called \\{restore\_trace}\X
+\U287.
+\:\X312:Declare the procedure called \\{runaway}\X
+\U120.
+\:\X298:Declare the procedure called \\{show\_token\_list}\X
+\U120.
+\:\X352:Decry the invalid character and \&{goto} \\{restart}\X
+\U350.
+\:\X89:Delete \(c)$\|c-\.{"0"}$ tokens and \&{goto} \\{continue}\X
+\U85.
+\:\X1030:Delete \(t)the page-insertion nodes\X
+\U1025.
+\:\X894:Destroy the \|t nodes following \|q, and make \|r point to the
+following node\X
+\U893.
+\:\X675:Determine horizontal glue shrink setting, then \&{return} or \hbox{%
+\&{goto} \\{common\_ending}}\X
+\U668.
+\:\X669:Determine horizontal glue stretch setting, then \&{return} or \hbox{%
+\&{goto} \\{common\_ending}}\X
+\U668.
+\:\X1214:Determine the displacement, \|d, of the left edge of the equation,
+with respect to the line size \|z, assuming that $\|l=\\{false}$\X
+\U1211.
+\:\X676:Determine the shrink order\X
+\Us675, 687\ETs807.
+\:\X670:Determine the stretch order\X
+\Us669, 684\ETs807.
+\:\X683:Determine the value of $\\{height}(\|r)$ and the appropriate glue
+setting; then \&{return} or \&{goto} \\{common\_ending}\X
+\U679.
+\:\X668:Determine the value of $\\{width}(\|r)$ and the appropriate glue
+setting; then \&{return} or \&{goto} \\{common\_ending}\X
+\U660.
+\:\X687:Determine vertical glue shrink setting, then \&{return} or \hbox{%
+\&{goto} \\{common\_ending}}\X
+\U683.
+\:\X684:Determine vertical glue stretch setting, then \&{return} or \hbox{%
+\&{goto} \\{common\_ending}}\X
+\U683.
+\:\X1224:Discard erroneous prefixes and \&{return}\X
+\U1223.
+\:\X1225:Discard the prefixes \.{\\long} and \.{\\outer} if they are irrelevant%
+\X
+\U1223.
+\:\X989:Dispense with trivial cases of void or bad boxes\X
+\U988.
+\:\X203:Display adjustment \|p\X
+\U189.
+\:\X190:Display box \|p\X
+\U189.
+\:\X706:Display choice node \|p\X
+\U701.
+\:\X201:Display discretionary \|p\X
+\U189.
+\:\X708:Display fraction noad \|p\X
+\U701.
+\:\X195:Display glue \|p\X
+\U189.
+\:\X194:Display insertion \|p\X
+\U189.
+\:\X197:Display kern \|p\X
+\U189.
+\:\X196:Display leaders \|p\X
+\U195.
+\:\X199:Display ligature \|p\X
+\U189.
+\:\X202:Display mark \|p\X
+\U189.
+\:\X198:Display math node \|p\X
+\U189.
+\:\X189:Display node \|p\X
+\U188.
+\:\X707:Display normal noad \|p\X
+\U701.
+\:\X200:Display penalty \|p\X
+\U189.
+\:\X193:Display rule \|p\X
+\U189.
+\:\X191:Display special fields of the unset node \|p\X
+\U190.
+\:\X318:Display the current context\X
+\U317.
+\:\X1022:Display the insertion split cost\X
+\U1021.
+\:\X1017:Display the page break cost\X
+\U1016.
+\:\X300:Display the token $(\|m,\|c)$\X
+\U299.
+\:\X513:Display the value of \|b\X
+\U509.
+\:\X192:Display the value of $\\{glue\_set}(\|p)$\X
+\U190.
+\:\X1369:Display the whatsit node \|p\X
+\U189.
+\:\X299:Display token \|p, and \&{return} if there are problems\X
+\U298.
+\:\X739:Do first-pass processing based on $\\{type}(\|q)$; \&{goto} \\{done%
+\_with\_noad} if a noad has been fully processed, \&{goto} \\{check%
+\_dimensions} if it has been translated into $\\{new\_hlist}(\|q)$, or \&{goto}
+\\{done\_with\_node} if a node has been fully processed\X
+\U738.
+\:\X1052:Do ligature or kern command, returning to \\{main\_lig\_loop} or %
+\\{main\_loop\_wrapup} or \\{main\_loop\_move}\X
+\U1051.
+\:\X326:Do magic computation\X
+\U298.
+\:\X1387:Do some work that has been queued up for \.{\\write}\X
+\U1386.
+\:\X1078:Drop current token and complain that it was unmatched\X
+\U1076.
+\:\X142:DtoU to other direction\X
+\U139.
+\:\X1414:Dump ML\TeX-specific data\X
+\U1315.
+\:\X1339:Dump a couple more things and the closing check word\X
+\U1315.
+\:\X1320:Dump constants for consistency check\X
+\U1315.
+\:\X1328:Dump regions 1 to 4 of \\{eqtb}\X
+\U1326.
+\:\X1329:Dump regions 5 and 6 of \\{eqtb}\X
+\U1326.
+\:\X1335:Dump the array info for internal font number \|k\X
+\U1333.
+\:\X1324:Dump the dynamic memory\X
+\U1315.
+\:\X1333:Dump the font information\X
+\U1315.
+\:\X1331:Dump the hash table\X
+\U1326.
+\:\X1337:Dump the hyphenation tables\X
+\U1315.
+\:\X1322:Dump the string pool\X
+\U1315.
+\:\X1326:Dump the table of equivalents\X
+\U1315.
+\:\X1400:Dump \\{xord}, \\{xchr}, and \\{xprn}\X
+\U1320.
+\:\X1033:Either append the insertion node \|p after node \|q, and remove it
+from the current page, or delete $\\{node}(\|p)$\X
+\U1031.
+\:\X1031:Either insert the material specified by node \|p into the appropriate
+box, or hold it for the next page; also delete node \|p from the current page\X
+\U1025.
+\:\X512:Either process \.{\\ifcase} or set \|b to the value of a boolean
+condition\X
+\U509.
+\:\X610:Empty the last bytes out of \\{dvi\_buf}\X
+\U653.
+\:\X1039:Ensure that box 255 is empty after output\X
+\U1037.
+\:\X1026:Ensure that box 255 is empty before output\X
+\U1025.
+\:\X965:Ensure that $\\{trie\_max}\G\|h+256$\X
+\U964.
+\:\X950:Enter a hyphenation exception\X
+\U946.
+\:\X972:Enter all of the patterns into a linked trie, until coming to a right
+brace\X
+\U971.
+\:\X946:Enter as many hyphenation exceptions as are listed, until coming to a
+right brace; then \&{return}\X
+\U945.
+\:\X357:Enter \\{skip\_blanks} state, emit a space\X
+\U353.
+\:\X79, 82, 83, 94, 95, 96:Error handling procedures\X
+\U4.
+\:\X662:Examine node \|p in the hlist, taking account of its effect on the
+dimensions of the new box, or moving it to the adjustment list; then advance %
+\|p to the next node\X
+\U660.
+\:\X680:Examine node \|p in the vlist, taking account of its effect on the
+dimensions of the new box; then advance \|p to the next node\X
+\U679.
+\:\X378:Expand a nonmacro\X
+\U377.
+\:\X1384:Expand macros in the token list and make $\\{link}(\\{def\_ref})$
+point to the result\X
+\U1383.
+\:\X489:Expand the next part of the input\X
+\U488.
+\:\X379:Expand the token after the next token\X
+\U378.
+\:\X1035:Explain that too many dead cycles have occurred in a row\X
+\U1023.
+\:\X457:Express astonishment that no number was here\X
+\U455.
+\:\X1140:Express consternation over the fact that no alignment is in progress\X
+\U1139.
+\:\X486:Express shock at the missing left brace; \&{goto} \\{found}\X
+\U485.
+\:\X401:Feed the macro body and its parameters to the scanner\X
+\U400.
+\:\X431:Fetch a box dimension\X
+\U424.
+\:\X425:Fetch a character code from some table\X
+\U424.
+\:\X436:Fetch a font dimension\X
+\U424.
+\:\X437:Fetch a font integer\X
+\U424.
+\:\X438:Fetch a register\X
+\U424.
+\:\X426:Fetch a token list or font identifier, provided that $\\{level}=\\{tok%
+\_val}$\X
+\U424.
+\:\X460:Fetch an internal dimension and \&{goto} \\{attach\_sign}, or fetch an
+internal integer\X
+\U459.
+\:\X435:Fetch an item in the current node, if appropriate\X
+\U424.
+\:\X1442:Fetch breaking penalty from some table\X
+\U424.
+\:\X1437:Fetch inhibit type from some table\X
+\U424.
+\:\X432:Fetch something on the \\{page\_so\_far}\X
+\U424.
+\:\X430:Fetch the \\{dead\_cycles} or the \\{insert\_penalties}\X
+\U424.
+\:\X434:Fetch the \\{par\_shape} size\X
+\U424.
+\:\X433:Fetch the \\{prev\_graf}\X
+\U424.
+\:\X429:Fetch the \\{space\_factor} or the \\{prev\_depth}\X
+\U424.
+\:\X885:Find an active node with fewest demerits\X
+\U884.
+\:\X934:Find hyphen locations for the word in \\{hc}, or \&{return}\X
+\U906.
+\:\X874:Find optimal breakpoints\X
+\U826.
+\:\X886:Find the best active node for the desired looseness\X
+\U884.
+\:\X1021:Find the best way to split the insertion, and change $\\{type}(\|r)$
+to \\{split\_up}\X
+\U1019.
+\:\X1054:Find the glue specification, \\{main\_p}, for text spaces in the
+current font\X
+\Us1053\ET1055.
+\:\X1218:Finish an alignment in a display\X
+\U823.
+\:\X1211:Finish displayed math\X
+\U1206.
+\:\X674:Finish issuing a diagnostic message for an overfull or underfull hbox\X
+\U660.
+\:\X686:Finish issuing a diagnostic message for an overfull or underfull vbox\X
+\U679.
+\:\X359:Finish line, emit a \.{\\par}\X
+\U353.
+\:\X356:Finish line, emit a space\X
+\Us353\ET353.
+\:\X358:Finish line, \&{goto} \\{switch}\X
+\Us353\ET353.
+\:\X1208:Finish math in text\X
+\U1206.
+\:\X653:Finish the \.{DVI} file\X
+\U1346.
+\:\X1391:Finish the extensions\X
+\U1346.
+\:\X1036:Fire up the user's output routine and \&{return}\X
+\U1023.
+\:\X441:Fix the reference count, if any, and negate \\{cur\_val} if %
+\\{negative}\X
+\U424.
+\:\X650:Flush the box from memory, showing statistics if requested\X
+\U649.
+\:\X1060, 1110, 1123, 1156:Forbidden cases detected in \\{main\_control}\X
+\U1057.
+\:\X621:Generate a \\{down} or \\{right} command for \|w and \&{return}\X
+\U618.
+\:\X620:Generate a \\{y0} or \\{z0} command in order to reuse a previous
+appearance of~\|w\X
+\U618.
+\:\X963:Get ready to compress the trie\X
+\U977.
+\:\X827, 838, 845, 859:Get ready to start line breaking\X
+\U826.
+\:\X1411:Get substitution information, check it, goto \\{found} if all is ok,
+otherwise goto \\{continue}\X
+\U1409.
+\:\X1350:Get the first line of input and prepare to start\X
+\U1345.
+\:\X417:Get the next non-blank non-call token\X
+\Us416, 452, 466, 514, 537, 588, 796, 802\ETs1057.
+\:\X415:Get the next non-blank non-relax non-call token\X
+\Us414, 1090, 1096, 1163, 1172, 1223, 1238\ETs1283.
+\:\X452:Get the next non-blank non-sign token; set \\{negative} appropriately\X
+\Us451, 459\ETs472.
+\:\X366:Get the next token, suppressing expansion\X
+\U365.
+\:\X84:Get user's advice and \&{return}\X
+\U83.
+\:\X1042:Give diagnostic information, if requested\X
+\U1041.
+\:\X947:Give improper \.{\\hyphenation} error\X
+\U946.
+\:\X13, 20, 26, 31, 33, 40, 51, 55, 74, 77, 80, 97, 105, 116, 117, 118, 119,
+125, 171, 179, 187, 219, 252, 259, 262, 277, 292, 303, 307, 310, 311, 314, 315,
+316, 339, 354, 369, 375, 393, 398, 399, 421, 449, 458, 491, 500, 504, 523, 524,
+531, 538, 543, 550, 560, 561, 566, 603, 606, 616, 627, 657, 658, 672, 695, 730,
+735, 775, 781, 825, 832, 834, 836, 839, 844, 850, 858, 883, 903, 911, 916, 918,
+932, 937, 954, 958, 961, 982, 991, 993, 1000, 1043, 1086, 1279, 1294, 1312,
+1318, 1344, 1355, 1358, 1392, 1394, 1396, 1404, 1405, 1410, 1430, 1446,
+1449:Global variables\X
+\U4.
+\:\X1157:Go into display math mode\X
+\U1150.
+\:\X1151:Go into ordinary math mode\X
+\Us1150\ET1154.
+\:\X812:Go through the preamble list, determining the column widths and
+changing the alignrecords to dummy unset boxes\X
+\U811.
+\:\X127:Grow more variable-size memory and \&{goto} \\{restart}\X
+\U126.
+\:\X353:Handle situations involving spaces, braces, changes of state\X
+\U350.
+\:\X846:If a line number class has ended, create new active nodes for the best
+feasible breaks in that class; then \&{return} if $\|r=\\{last\_active}$,
+otherwise compute the new \\{line\_width}\X
+\U840.
+\:\X966:If all characters of the family fit relative to \|h, then \&{goto} %
+\\{found},\30\ otherwise \&{goto} \\{not\_found}\X
+\U964.
+\:\X348:If an alignment entry has just ended, take appropriate action\X
+\U347.
+\:\X363:If an expanded code is present, reduce it and \&{goto} \\{start\_cs}\X
+\U362.
+\:\X1317:If dumping is not allowed, abort\X
+\U1315.
+\:\X764:If instruction \\{cur\_i} is a kern with \\{cur\_c}, attach the kern
+after~\|q; or if it is a ligature with \\{cur\_c}, combine noads \|q and~\|p
+appropriately; then \&{return} if the cursor has moved past a noad, or \&{goto}
+\\{restart}\X
+\U763.
+\:\X913:If no hyphens were found, \&{return}\X
+\U906.
+\:\X879:If node \\{cur\_p} is a legal breakpoint, call \\{try\_break}; then
+update the active widths by including the glue in $\\{glue\_ptr}(\\{cur\_p})$\X
+\U877.
+\:\X983:If node \|p is a legal breakpoint, check if this break is the best
+known, and \&{goto} \\{done} if \|p is null or if the page-so-far is already
+too full to accept more stuff\X
+\U981.
+\:\X772:If node \|q is a style node, change the style and \&{goto} \\{delete%
+\_q}; otherwise if it is not a noad, put it into the hlist, advance \|q, and %
+\&{goto} \\{done}; otherwise set \|s to the size of noad \|q, set \|t to the
+associated type ($\\{ord\_noad}\to\\{inner\_noad}$), and set \\{pen} to the
+associated penalty\X
+\U771.
+\:\X843:If node \|r is of type \\{delta\_node}, update \\{cur\_active\_width},
+set \\{prev\_r} and \\{prev\_prev\_r}, then \&{goto} \\{continue}\X
+\U840.
+\:\X1092:If the current list ends with a box node, delete it from the list and
+make \\{cur\_box} point to it; otherwise set $\\{cur\_box}\K\\{null}$\X
+\U1091.
+\:\X1011:If the current page is empty and node \|p is to be deleted, \&{goto} %
+\\{done1}; otherwise use node \|p to update the state of the current page; if
+this node is an insertion, \&{goto} \\{contribute}; otherwise if this node is
+not a legal breakpoint, \&{goto} \\{contribute} or \\{update\_heights};
+otherwise set \\{pi} to the penalty associated with this breakpoint\X
+\U1008.
+\:\X1047:If the cursor is immediately followed by the right boundary, \&{goto} %
+\\{reswitch}; if it's followed by an invalid character, \&{goto} \\{big%
+\_switch}; otherwise move the cursor one step to the right and \&{goto} \\{main%
+\_lig\_loop}\X
+\U1045.
+\:\X487:If the next character is a parameter number, make \\{cur\_tok} a %
+\\{match} token; but if it is a left brace, store `\\{left\_brace}, \\{end%
+\_match}', set \\{hash\_brace}, and \&{goto} \\{done}\X
+\U485.
+\:\X803:If the preamble list has been traversed, check that the row has ended\X
+\U802.
+\:\X1239:If the right-hand side is a token parameter or token register, finish
+the assignment and \&{goto} \\{done}\X
+\U1238.
+\:\X942:If the string $\\{hyph\_word}[\|h]$ is less than \(hc)$\\{hc}[1\to%
+\\{hn}]$, \&{goto} \\{not\_found}; but if the two strings are equal, set %
+\\{hyf} to the hyphen positions and \&{goto} \\{found}\X
+\U941.
+\:\X952:If the string $\\{hyph\_word}[\|h]$ is less than \(or)or equal to \|s,
+interchange $(\\{hyph\_word}[\|h],\\{hyph\_list}[\|h])$ with $(\|s,\|p)$\X
+\U951.
+\:\X920:If there's a ligature or kern at the cursor position, update the data
+structures, possibly advancing~\|j; continue until the cursor moves\X
+\U917.
+\:\X1051:If there's a ligature/kern command relevant to \\{cur\_l} and \\{cur%
+\_r}, adjust the text appropriately; exit to \\{main\_loop\_wrapup}\X
+\U1045.
+\:\X1273:If this font has already been loaded, set \|f to the internal font
+number and \&{goto} \\{common\_ending}\X
+\U1270.
+\:\X360:If this \\{sup\_mark} starts an expanded character like~\.{\^\^A} or~%
+\.{\^\^df}, then \&{goto} \\{reswitch}, otherwise set $\\{state}\K\\{mid%
+\_line}$\X
+\U350.
+\:\X1195:Ignore the fraction operation and complain about this ambiguous case\X
+\U1193.
+\:\X1366:Implement \.{\\closeout}\X
+\U1361.
+\:\X1388:Implement \.{\\immediate}\X
+\U1361.
+\:\X1364:Implement \.{\\openout}\X
+\U1361.
+\:\X1390:Implement \.{\\setlanguage}\X
+\U1361.
+\:\X1367:Implement \.{\\special}\X
+\U1361.
+\:\X1365:Implement \.{\\write}\X
+\U1361.
+\:\X1372:Incorporate a whatsit node into a vbox\X
+\U680.
+\:\X1373:Incorporate a whatsit node into an hbox\X
+\U662.
+\:\X664:Incorporate box dimensions into the dimensions of the hbox that will
+contain~it\X
+\U662.
+\:\X681:Incorporate box dimensions into the dimensions of the vbox that will
+contain~it\X
+\U680.
+\:\X665:Incorporate character dimensions into the dimensions of the hbox that
+will contain~it, then move to the next node\X
+\U662.
+\:\X667:Incorporate glue into the horizontal totals\X
+\U662.
+\:\X682:Incorporate glue into the vertical totals\X
+\U680.
+\:\X591:Increase the number of parameters in the last font\X
+\U589.
+\:\X902:Initialize for hyphenating a paragraph\X
+\U874.
+\:\X170, 228, 234, 238, 246, 256, 264, 563, 957, 962, 1228, 1314,
+1382:Initialize table entries (done by \.{INITEX} only)\X
+\U8.
+\:\X1012:Initialize the current page, insert the \.{\\topskip} glue ahead of %
+\|p, and \&{goto} \\{continue}\X
+\U1011.
+\:\X337:Initialize the input routines\X
+\U1350.
+\:\X56, 62, 539, 544:Initialize the output routines\X
+\U1345.
+\:\X76:Initialize the print \\{selector} based on \\{interaction}\X
+\Us1278\ET1350.
+\:\X801, 808, 831, 992, 999:Initialize the special list heads and constant
+nodes\X
+\U170.
+\:\X628:Initialize variables as \\{ship\_out} begins\X
+\U651.
+\:\X8:Initialize whatever \TeX\ might access\X
+\U4.
+\:\X389:Initiate or terminate input from a file\X
+\U378.
+\:\X1095:Initiate the construction of an hbox or vbox, then \&{return}\X
+\U1091.
+\:\X494:Input and store tokens from the next line of the file\X
+\U493.
+\:\X495:Input for \.{\\read} from the terminal\X
+\U494.
+\:\X349:Input from external file, \&{goto} \\{restart} if no input found\X
+\U347.
+\:\X365:Input from token list, \&{goto} \\{restart} if end of list or if a
+parameter needs to be expanded\X
+\U347.
+\:\X496:Input the first line of $\\{read\_file}[\|m]$\X
+\U494.
+\:\X497:Input the next line of $\\{read\_file}[\|m]$\X
+\U494.
+\:\X1459:Insert ASCII-KANJI spacing\X
+\Us1452, 1454\ETs1458.
+\:\X1460:Insert KANJI-ASCII spacing\X
+\Us1452, 1454, 1454, 1456, 1457\ETs1458.
+\:\X1461:Insert KANJI-KANJI spacing\X
+\Us1454\ET1458.
+\:\X854:Insert a delta node to prepare for breaks at \\{cur\_p}\X
+\U847.
+\:\X855:Insert a delta node to prepare for the next active node\X
+\U847.
+\:\X1189:Insert a dummy noad to be sub/superscripted\X
+\U1188.
+\:\X856:Insert a new active node from $\\{best\_place}[\\{fit\_class}]$ to %
+\\{cur\_p}\X
+\U847.
+\:\X266:Insert a new control sequence after \|p, then make \|p point to it\X
+\U265.
+\:\X974:Insert a new pattern into the linked trie\X
+\U972.
+\:\X975:Insert a new trie node between \|q and \|p, and make \|p point to it\X
+\U974.
+\:\X1455:Insert a space after the \\{last\_char}\X
+\U1453.
+\:\X1452:Insert a space around the character \|p\X
+\Us1451\ET1451.
+\:\X1454:Insert a space before the \\{first\_char}\X
+\U1453.
+\:\X386:Insert a token containing \\{frozen\_endv}\X
+\U377.
+\:\X1282:Insert a token saved by \.{\\afterassignment}, if any\X
+\U1223.
+\:\X980:Insert glue for \\{split\_top\_skip} and set~$\|p\K\\{null}$\X
+\U979.
+\:\X1453:Insert hbox surround spacing\X
+\U1451.
+\:\X943:Insert hyphens as specified in $\\{hyph\_list}[\|h]$\X
+\U942.
+\:\X1443:Insert kinsoku penalty\X
+\Us1050\ET1469.
+\:\X1457:Insert ligature surround spacing\X
+\U1451.
+\:\X367:Insert macro parameter and \&{goto} \\{restart}\X
+\U365.
+\:\X1456:Insert math surround spacing\X
+\U1451.
+\:\X1458:Insert penalty or displace surround spacing\X
+\U1451.
+\:\X397:Insert the \(a)appropriate mark text into the scanner\X
+\U378.
+\:\X823:Insert the \(c)current list into its environment\X
+\U811.
+\:\X951:Insert the \(p)pair $(\|s,\|p)$ into the exception table\X
+\U950.
+\:\X800:Insert the \(v)\<v_j> template and \&{goto} \\{restart}\X
+\U348.
+\:\X332:Insert token \|p into \TeX's input\X
+\U288.
+\:\X1445:Insert \\{post\_break\_penalty}\X
+\Us1469\ET1469.
+\:\X1444:Insert \\{pre\_break\_penalty} of \\{cur\_chr}\X
+\U1469.
+\:\X85:Interpret code \|c and \&{return} if done\X
+\U84.
+\:\X88:Introduce new material from the terminal and \&{return}\X
+\U85.
+\:\X590:Issue an error message if $\\{cur\_val}=\\{fmem\_ptr}$\X
+\U589.
+\:\X891:Justify the line ending at breakpoint \\{cur\_p}, and append it to the
+current vertical list, together with associated penalties and other insertions\X
+\U888.
+\:\X1346, 1348, 1349, 1351:Last-minute procedures\X
+\U1343.
+\:\X804:Lengthen the preamble periodically\X
+\U803.
+\:\X638:Let \\{cur\_h} be the position of the first box, and set $\\{leader%
+\_wd}+\\{lx}$ to the spacing between corresponding parts of boxes\X
+\U637.
+\:\X647:Let \\{cur\_v} be the position of the first box, and set $\\{leader%
+\_ht}+\\{lx}$ to the spacing between corresponding parts of boxes\X
+\U646.
+\:\X1159:Let \|d be the natural width of node \|p; if the node is ``visible,'' %
+\&{goto} \\{found}; if the node is glue that stretches or shrinks, set $\|v\K%
+\\{max\_dimen}$\X
+\U1158.
+\:\X1160:Let \|d be the natural width of this glue; if stretching or shrinking,
+set $\|v\K\\{max\_dimen}$; \&{goto} \\{found} in the case of leaders\X
+\U1159.
+\:\X1374:Let \|d be the width of the whatsit \|p\X
+\U1159.
+\:\X1245:Let \|m be the minimal legal code value, based on \\{cur\_chr}\X
+\U1244.
+\:\X1246:Let \|n be the largest legal code value, based on \\{cur\_chr}\X
+\U1244.
+\:\X1009:Link node \|p into the current page and \&{goto} \\{done}\X
+\U1008.
+\:\X461, 1417:Local variables for dimension calculations\X
+\U459.
+\:\X1210:Local variables for finishing a displayed formula\X
+\U1206.
+\:\X321:Local variables for formatting calculations\X
+\U317.
+\:\X912, 923, 933, 940:Local variables for hyphenation\X
+\U906.
+\:\X19, 169, 938:Local variables for initialization\X
+\U4.
+\:\X873, 904:Local variables for line breaking\X
+\U826.
+\:\X1049:Look ahead for another character, or leave \\{lig\_stack} empty if
+there's none there\X
+\U1045.
+\:\X1472:Look ahead for glue or kerning\X
+\U1469.
+\:\X990:Look at all the marks in nodes before the break, and set the final link
+to \\{null} at the break\X
+\U988.
+\:\X719:Look at the list of characters starting with \|x in font \|g; set \|f
+and \|c whenever a better character is found; \&{goto} \\{found} as soon as a
+large enough variant is encountered\X
+\U718.
+\:\X622:Look at the other stack entries until deciding what sort of \.{DVI}
+command to generate; \&{goto} \\{found} if node \|p is a ``hit''\X
+\U618.
+\:\X718:Look at the variants of $(\|z,\|x)$; set \|f and \|c whenever a better
+character is found; \&{goto} \\{found} as soon as a large enough variant is
+encountered\X
+\U717.
+\:\X490:Look for parameter number or \.{\#\#}\X
+\U488.
+\:\X941:Look for the word $\\{hc}[1\to\\{hn}]$ in the exception table, and %
+\&{goto} \\{found} (with \\{hyf} containing the hyphens) if an entry is found\X
+\U934.
+\:\X385:Look up the characters of list \|r in the hash table, and set \\{cur%
+\_cs}\X
+\U383.
+\:\X211:Make a copy of node \|p in node \|r\X
+\U210.
+\:\X1046:Make a ligature node, if \\{ligature\_present}; insert a null
+discretionary, if appropriate\X
+\U1045.
+\:\X1370:Make a partial copy of the whatsit node \|p and make \|r point to it;
+set \\{words} to the number of initial words not yet copied\X
+\U212.
+\:\X771:Make a second pass over the mlist, removing all noads and inserting the
+proper spacing and penalties\X
+\U737.
+\:\X587:Make final adjustments and \&{goto} \\{done}\X
+\U573.
+\:\X663:Make node \|p look like a \\{char\_node} and \&{goto} \\{reswitch}\X
+\Us633, 662\ETs1159.
+\:\X1014:Make sure that \\{page\_max\_depth} is not exceeded\X
+\U1008.
+\:\X842:Make sure that \\{pi} is in the proper range\X
+\U840.
+\:\X1006:Make the contribution list empty by setting its tail to \\{contrib%
+\_head}\X
+\U1005.
+\:\X49:Make the first 256 strings\X
+\U48.
+\:\X750:Make the height of box \|y equal to \|h\X
+\U749.
+\:\X817:Make the running dimensions in rule \|q extend to the boundaries of the
+alignment\X
+\U816.
+\:\X822:Make the unset node \|r into a \\{vlist\_node} of height \|w, setting
+the glue as if the height were \|t\X
+\U819.
+\:\X821:Make the unset node \|r into an \\{hlist\_node} of width \|w, setting
+the glue as if the width were \|t\X
+\U819.
+\:\X721:Make variable \|b point to a box for $(\|f,\|c)$\X
+\U717.
+\:\X1463:Make \\{jchr\_widow\_penalty} node\X
+\U1451.
+\:\X383:Manufacture a control sequence name\X
+\U378.
+\:\X1058:Math-only cases in non-math modes, or vice versa\X
+\U1057.
+\:\X814:Merge the widths in the span nodes of \|q with those of \|p, destroying
+the span nodes of \|q\X
+\U812.
+\:\X892:Modify the end of the line to reflect the nature of the break and to
+include \.{\\rightskip}; also set the proper value of \\{disc\_break}\X
+\U891.
+\:\X1056:Modify the glue specification in \\{main\_p} according to the space
+factor\X
+\U1055.
+\:\X645:Move down or output leaders\X
+\U642.
+\:\X1008:Move node \|p to the current page; if it is time for a page break, put
+the nodes following the break back onto the contribution list, and \&{return}
+to the user's output routine if there is one\X
+\U1005.
+\:\X929:Move pointer \|s to the end of the current list, and set $\\{replace%
+\_count}(\|r)$ appropriately\X
+\U925.
+\:\X636:Move right or output leaders\X
+\U633.
+\:\X909:Move the characters of a ligature node to \\{hu} and \\{hc}; but %
+\&{goto} \\{done3} if they are not all letters\X
+\U908.
+\:\X1048:Move the cursor past a pseudo-ligature, then \&{goto} \\{main\_loop%
+\_lookahead} or \\{main\_lig\_loop}\X
+\U1045.
+\:\X969:Move the data into \\{trie}\X
+\U977.
+\:\X368:Move to next line of file, or \&{goto} \\{restart} if there is no next
+line, or \&{return} if a \.{\\read} line has finished\X
+\U349.
+\:\X442:Negate all three glue components of \\{cur\_val}\X
+\U441.
+\:\X813:Nullify $\\{width}(\|q)$ and the tabskip glue following this column\X
+\U812.
+\:\X1352:Numbered cases for \\{debug\_help}\X
+\U1351.
+\:\X574:Open \\{tfm\_file} for input\X
+\U573.
+\:\X841:Other local variables for \\{try\_break}\X
+\U840.
+\:\X643:Output a box in a vlist\X
+\U642.
+\:\X634:Output a box in an hlist\X
+\U633.
+\:\X639:Output a leader box at \\{cur\_h}, then advance \\{cur\_h} by $%
+\\{leader\_wd}+\\{lx}$\X
+\U637.
+\:\X648:Output a leader box at \\{cur\_v}, then advance \\{cur\_v} by $%
+\\{leader\_ht}+\\{lx}$\X
+\U646.
+\:\X644:Output a rule in a vlist, \&{goto} \\{next\_p}\X
+\U642.
+\:\X635:Output a rule in an hlist\X
+\U633.
+\:\X1409:Output a substitution, \&{goto} \\{continue} if not possible\X
+\U631.
+\:\X646:Output leaders in a vlist, \&{goto} \\{fin\_rule} if a rule or to %
+\\{next\_p} if done\X
+\U645.
+\:\X637:Output leaders in an hlist, \&{goto} \\{fin\_rule} if a rule or to %
+\\{next\_p} if done\X
+\U636.
+\:\X631:Output node \|p for \\{hlist\_out} and move to the next node,
+maintaining the condition $\\{cur\_v}=\\{base\_line}$\X
+\U630.
+\:\X641:Output node \|p for \\{vlist\_out} and move to the next node,
+maintaining the condition $\\{cur\_h}=\\{left\_edge}$\X
+\U640.
+\:\X1347:Output statistics about this job\X
+\U1346.
+\:\X654:Output the font definitions for all fonts that were used\X
+\U653.
+\:\X614:Output the font name whose internal number is \|f\X
+\U613.
+\:\X633:Output the non-\\{char\_node} \|p for \\{hlist\_out} and move to the
+next node\X
+\U631.
+\:\X642:Output the non-\\{char\_node} \|p for \\{vlist\_out}\X
+\U641.
+\:\X1379:Output the whatsit node \|p in a vlist\X
+\U642.
+\:\X1380:Output the whatsit node \|p in an hlist\X
+\U633.
+\:\X967:Pack the family into \\{trie} relative to \|h\X
+\U964.
+\:\X807:Package an unset box for the current column and record its width\X
+\U802.
+\:\X815:Package the preamble list, to determine the actual tabskip glue
+amounts, and let \|p point to this prototype box\X
+\U811.
+\:\X1034:Perform the default output routine\X
+\U1023.
+\:\X1219:Pontificate about improper alignment in display\X
+\U1218.
+\:\X507:Pop the condition stack\X
+\Us509, 511, 520\ETs521.
+\:\X1029:Prepare all the boxes involved in insertions to act as queues\X
+\U1025.
+\:\X865:Prepare to deactivate node~\|r, and \&{goto} \\{deactivate} unless
+there is a reason to consider lines of text from \|r to \\{cur\_p}\X
+\U862.
+\:\X1077:Prepare to insert a token that matches \\{cur\_group}, and print what
+it is\X
+\U1076.
+\:\X1013:Prepare to move a box or rule node to the current page, then \&{goto} %
+\\{contribute}\X
+\U1011.
+\:\X1377:Prepare to move whatsit \|p to the current page, then \&{goto} %
+\\{contribute}\X
+\U1011.
+\:\X181:Print a short indication of the contents of node \|p\X
+\U180.
+\:\X857:Print a symbolic description of the new break node\X
+\U856.
+\:\X867:Print a symbolic description of this feasible break\X
+\U866.
+\:\X1412:Print character substition tracing log\X
+\U1409.
+\:\X345:Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `%
+\.{text}', and insert tokens that should lead to recovery\X
+\U344.
+\:\X319:Print location of current line\X
+\U318.
+\:\X177:Print newly busy locations\X
+\U173.
+\:\X1296:Print string \|s as an error message\X
+\U1292.
+\:\X1293:Print string \|s on the terminal\X
+\U1292.
+\:\X547:Print the banner line, including the date and time\X
+\U545.
+\:\X273:Print the font identifier for $\\{font}(\|p)$\X
+\Us180\ET182.
+\:\X90:Print the help information and \&{goto} \\{continue}\X
+\U85.
+\:\X868:Print the list between \\{printed\_node} and \\{cur\_p}, then set $%
+\\{printed\_node}\K\\{cur\_p}$\X
+\U867.
+\:\X86:Print the menu of available options\X
+\U85.
+\:\X483:Print the result of command \|c\X
+\U481.
+\:\X323:Print two lines using the tricky pseudoprinted information\X
+\U318.
+\:\X320:Print type of token list\X
+\U318.
+\:\X361:Process an active-character control sequence and set $\\{state}\K\\{mid%
+\_line}$\X
+\U350.
+\:\X738:Process node-or-noad \|q as much as possible in preparation for the
+second pass of \\{mlist\_to\_hlist}, then move to the next item in the mlist\X
+\U737.
+\:\X1378:Process whatsit \|p in \\{vert\_break} loop, \&{goto} \\{not\_found}\X
+\U984.
+\:\X1133:Prune the current list, if necessary, until it contains only \\{char%
+\_node}, \\{kern\_node}, \\{hlist\_node}, \\{vlist\_node}, \\{rule\_node}, and %
+\\{ligature\_node} items; set \|n to the length of the list, and set \|q to the
+list's tail\X
+\U1131.
+\:\X890:Prune unwanted nodes at the beginning of the next line\X
+\U888.
+\:\X324:Pseudoprint the line\X
+\U318.
+\:\X325:Pseudoprint the token list\X
+\U318.
+\:\X506:Push the condition stack\X
+\U509.
+\:\X232, 236, 244, 254, 271, 340, 387, 395, 422, 427, 479, 498, 502, 564, 791,
+994, 1064, 1070, 1083, 1100, 1119, 1126, 1153, 1168, 1181, 1190, 1200, 1220,
+1231, 1234, 1242, 1263, 1267, 1275, 1285, 1290, 1299, 1304, 1357, 1421, 1426,
+1433, 1438:Put each of \TeX's primitives into the hash table\X
+\U1349.
+\:\X91:Put help message on the transcript file\X
+\U83.
+\:\X927:Put the \(c)characters $\\{hu}[\|i+1\to\,]$ into $\\{post\_break}(%
+\|r)$, appending to this list and to \\{major\_tail} until synchronization has
+been achieved\X
+\U925.
+\:\X926:Put the \(c)characters $\\{hu}[\|l\to\|i]$ and a hyphen into $\\{pre%
+\_break}(\|r)$\X
+\U925.
+\:\X759:Put the \(f)fraction into a box with its delimiters, and make $\\{new%
+\_hlist}(\|q)$ point to it\X
+\U754.
+\:\X898:Put the \(l)\.{\\leftskip} glue at the left and detach this line\X
+\U891.
+\:\X1025:Put the \(o)optimal current page into box 255, update \\{first\_mark}
+and \\{bot\_mark}, append insertions to their boxes, and put the remaining
+nodes back on the contribution list\X
+\U1023.
+\:\X1272:Put the \(p)(positive) `at' size into \|s\X
+\U1271.
+\:\X897:Put the \(r)\.{\\rightskip} glue after node \|q\X
+\U892.
+\:\X573:Read and check the font data; \\{abort} if the \.{TFM} file is
+malformed; if there's no room for this font, say so and \&{goto} \\{done};
+otherwise $\\{incr}(\\{font\_ptr})$ and \&{goto} \\{done}\X
+\U571.
+\:\X582:Read box dimensions\X
+\U573.
+\:\X580:Read character data\X
+\U573.
+\:\X585:Read extensible character recipes\X
+\U573.
+\:\X586:Read font parameters\X
+\U573.
+\:\X584:Read ligature/kern program\X
+\U573.
+\:\X370:Read next line of file into \\{buffer}, or \&{goto} \\{restart} if the
+file has ended\X
+\U368.
+\:\X53:Read one string, but return \\{false} if the string memory space is
+getting too tight for comfort\X
+\U52.
+\:\X549:Read the first line of the new file\X
+\U548.
+\:\X52:Read the other strings from the \.{TEX.POOL} file and return \\{true},
+or give an error message and return \\{false}\X
+\U48.
+\:\X579:Read the {\.{TFM}} header\X
+\U573.
+\:\X576:Read the {\.{TFM}} size fields\X
+\U573.
+\:\X1099:Readjust the height and depth of \\{cur\_box}, for \.{\\vtop}\X
+\U1098.
+\:\X1413:Rebuild character using substitution information\X
+\U1409.
+\:\X924:Reconstitute nodes for the hyphenated word, inserting discretionary
+hyphens\X
+\U914.
+\:\X866:Record a new feasible break\X
+\U862.
+\:\X1038:Recover from an unbalanced output routine\X
+\U1037.
+\:\X1385:Recover from an unbalanced write command\X
+\U1384.
+\:\X1010:Recycle node \|p\X
+\U1008.
+\:\X1093:Remove the last box, unless it's part of a discretionary\X
+\U1092.
+\:\X914:Replace nodes $\\{ha}\to\\{hb}$ by a sequence of nodes that includes
+the discretionary hyphens\X
+\U906.
+\:\X1199:Replace the tail of the list by \|p\X
+\U1198.
+\:\X583:Replace \|z by $\|z^\prime$ and compute $\alpha,\beta$\X
+\U582.
+\:\X407:Report a runaway argument and abort\X
+\Us403\ET410.
+\:\X678:Report a tight hbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X
+\U675.
+\:\X689:Report a tight vbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X
+\U687.
+\:\X406:Report an extra right brace and \&{goto} \\{continue}\X
+\U403.
+\:\X409:Report an improper use of the macro and abort\X
+\U408.
+\:\X677:Report an overfull hbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X
+\U675.
+\:\X688:Report an overfull vbox and \&{goto} \\{common\_ending}, if this box is
+sufficiently bad\X
+\U687.
+\:\X671:Report an underfull hbox and \&{goto} \\{common\_ending}, if this box
+is sufficiently bad\X
+\U669.
+\:\X685:Report an underfull vbox and \&{goto} \\{common\_ending}, if this box
+is sufficiently bad\X
+\U684.
+\:\X36:Report overflow of the input buffer, and abort\X
+\U32.
+\:\X1173:Report that an invalid delimiter code is being changed to null; set~$%
+\\{cur\_val}\K0$\X
+\U1172.
+\:\X572:Report that the font won't be loaded\X
+\U571.
+\:\X471:Report that this dimension is out of range\X
+\U459.
+\:\X1037:Resume the page builder after an output routine has come to an end\X
+\U1112.
+\:\X889:Reverse the links of the relevant passive nodes, setting \\{cur\_p} to
+the first breakpoint\X
+\U888.
+\:\X362:Scan a control sequence and set $\\{state}\K\\{skip\_blanks}$ or \\{mid%
+\_line}\X
+\U350.
+\:\X455:Scan a numeric constant\X
+\U451.
+\:\X403:Scan a parameter until its delimiter string has been found; or, if $%
+\|s=\\{null}$, simply scan the delimiter string\X
+\U402.
+\:\X1165:Scan a subformula enclosed in braces and \&{return}\X
+\U1163.
+\:\X364:Scan ahead in the buffer until finding a nonletter; if an expanded code
+is encountered, reduce it and \&{goto} \\{start\_cs}; otherwise if a
+multiletter control sequence is found, adjust \\{cur\_cs} and \\{loc}, and %
+\&{goto} \\{found}\X
+\U362.
+\:\X453:Scan an alphabetic character code into \\{cur\_val}\X
+\U451.
+\:\X454:Scan an optional space\X
+\Us453, 459, 466\ETs1212.
+\:\X488:Scan and build the body of the token list; \&{goto} \\{found} when
+finished\X
+\U484.
+\:\X485:Scan and build the parameter part of the macro definition\X
+\U484.
+\:\X463:Scan decimal fraction\X
+\U459.
+\:\X542:Scan file name in the buffer\X
+\U541.
+\:\X469:Scan for \(a)all other units and adjust \\{cur\_val} and \|f
+accordingly; \&{goto} \\{done} in the case of scaled points\X
+\U464.
+\:\X465:Scan for \(f)\.{fil} units; \&{goto} \\{attach\_fraction} if found\X
+\U464.
+\:\X467:Scan for \(m)\.{mu} units and \&{goto} \\{attach\_fraction}\X
+\U464.
+\:\X466:Scan for \(u)units that are internal dimensions; \&{goto} \\{attach%
+\_sign} with \\{cur\_val} set if found\X
+\U464.
+\:\X790:Scan preamble text until \\{cur\_cmd} is \\{tab\_mark} or \\{car\_ret},
+looking for changes in the tabskip glue; append an alignrecord to the preamble
+list\X
+\U788.
+\:\X482:Scan the argument for command \|c\X
+\U481.
+\:\X1271:Scan the font size specification\X
+\U1270.
+\:\X402:Scan the parameters and make $\\{link}(\|r)$ point to the macro body;
+but \&{return} if an illegal \.{\\par} is detected\X
+\U400.
+\:\X788:Scan the preamble and record it in the \\{preamble} list\X
+\U785.
+\:\X794:Scan the template \<u_j>, putting the resulting token list in \\{hold%
+\_head}\X
+\U790.
+\:\X795:Scan the template \<v_j>, putting the resulting token list in \\{hold%
+\_head}\X
+\U790.
+\:\X464:Scan units and set \\{cur\_val} to $x\cdot(\\{cur\_val}+f/2^{16})$,
+where there are \|x sp per unit; \&{goto} \\{attach\_sign} if the units are
+internal\X
+\U459.
+\:\X261:Search \\{eqtb} for equivalents equal to \|p\X
+\U178.
+\:\X944:Search \\{hyph\_list} for pointers to \|p\X
+\U178.
+\:\X291:Search \\{save\_stack} for equivalents that point to \|p\X
+\U178.
+\:\X1464:Seek list and make \|t pointing widow penalty position\X
+\U1463.
+\:\X520:Select the appropriate case and \&{return} or \&{goto} \\{common%
+\_ending}\X
+\U512.
+\:\X21, 23, 24, 75, 78, 81, 98, 172, 221, 260, 263, 278, 293, 355, 376, 394,
+450, 492, 501, 562, 567, 604, 607, 617, 659, 673, 696, 782, 939, 1001, 1044,
+1280, 1295, 1313, 1356, 1393, 1397, 1406, 1431, 1447:Set initial values of key
+variables\X
+\U8.
+\:\X860:Set line length parameters in preparation for hanging indentation\X
+\U859.
+\:\X816:Set the glue in all the unset boxes of the current list\X
+\U811.
+\:\X819:Set the glue in node \|r and change it from an unset node\X
+\U818.
+\:\X818:Set the unset box \|q and the unset boxes in it\X
+\U816.
+\:\X864:Set the value of \|b to the badness for shrinking the line, and compute
+the corresponding \\{fit\_class}\X
+\U862.
+\:\X863:Set the value of \|b to the badness for stretching the line, and
+compute the corresponding \\{fit\_class}\X
+\U862.
+\:\X1024:Set the value of \\{output\_penalty}\X
+\U1023.
+\:\X919:Set up data structures with the cursor following position \|j\X
+\U917.
+\:\X714:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur%
+\_style}\X
+\Us731, 737, 741, 765, 771\ETs774.
+\:\X249:Set variable \|c to the current escape character\X
+\U64.
+\:\X651:Ship box \|p out\X
+\U649.
+\:\X229:Show equivalent \|n, in region 1 or 2\X
+\U258.
+\:\X235:Show equivalent \|n, in region 3\X
+\U258.
+\:\X239:Show equivalent \|n, in region 4\X
+\U258.
+\:\X248:Show equivalent \|n, in region 5\X
+\U258.
+\:\X257:Show equivalent \|n, in region 6\X
+\U258.
+\:\X225:Show the auxiliary field, \|a\X
+\U224.
+\:\X1309:Show the current contents of a box\X
+\U1306.
+\:\X1429:Show the current japanese processing mode\X
+\U1306.
+\:\X1307:Show the current meaning of a token, then \&{goto} \\{common\_ending}\X
+\U1306.
+\:\X1310:Show the current value of some parameter or register, then \&{goto} %
+\\{common\_ending}\X
+\U1306.
+\:\X240:Show the font identifier in $\\{eqtb}[\|n]$\X
+\U239.
+\:\X241:Show the halfword code in $\\{eqtb}[\|n]$\X
+\U239.
+\:\X997:Show the status of the current page\X
+\U224.
+\:\X412:Show the text of the macro being expanded\X
+\U400.
+\:\X732:Simplify a trivial box\X
+\U731.
+\:\X511:Skip to \.{\\else} or \.{\\fi}, then \&{goto} \\{common\_ending}\X
+\U509.
+\:\X907:Skip to node \\{ha}, or \&{goto} \\{done1} if no hyphenation should be
+attempted\X
+\U905.
+\:\X908:Skip to node \\{hb}, putting letters into \\{hu} and \\{hc}\X
+\U905.
+\:\X133:Sort \(p)\|p into the list starting at \\{rover} and advance \|p to $%
+\\{rlink}(\|p)$\X
+\U132.
+\:\X956:Sort \(t)the hyphenation op tables into proper order\X
+\U963.
+\:\X1094:Split off part of a vertical box, make \\{cur\_box} point to it\X
+\U1091.
+\:\X1213:Squeeze the equation as much as possible; if there is an equation
+number that should go on a separate line by itself, set~$\|e\K0$\X
+\U1211.
+\:\X1002:Start a new current page\X
+\U1028.
+\:\X1089:Store \(c)\\{cur\_box} in a box register\X
+\U1087.
+\:\X935:Store \(m)maximum values in the \\{hyf} table\X
+\U934.
+\:\X289:Store \(s)$\\{save\_stack}[\\{save\_ptr}]$ in $\\{eqtb}[\|p]$, unless $%
+\\{eqtb}[\|p]$ holds a global value\X
+\U288.
+\:\X404:Store the current token, but \&{goto} \\{continue} if it is a blank
+space that would become an undelimited parameter\X
+\U403.
+\:\X849:Subtract glue from \\{break\_width}\X
+\U848.
+\:\X852:Subtract the width of node \|v from \\{break\_width}\X
+\U851.
+\:\X380:Suppress expansion of the next token\X
+\U378.
+\:\X753:Swap the subscript and superscript into box \|x\X
+\U749.
+\:\X751:Switch to a larger accent if available and appropriate\X
+\U749.
+\:\X141:Tate to other direction\X
+\U139.
+\:\X344:Tell the user what has run away and try to recover\X
+\U342.
+\:\X521:Terminate the current conditional and skip to \.{\\fi}\X
+\U378.
+\:\X516:Test box register status\X
+\U512.
+\:\X515:Test if an integer is odd\X
+\U512.
+\:\X517:Test if two characters match\X
+\U512.
+\:\X519:Test if two macro texts match\X
+\U518.
+\:\X518:Test if two tokens match\X
+\U512.
+\:\X514:Test relation between integers or dimensions\X
+\U512.
+\:\X1419:The KANJI height for \\{cur\_jfont}\X
+\U466.
+\:\X1418:The KANJI width for \\{cur\_jfont}\X
+\U466.
+\:\X569:The em width for \\{cur\_font}\X
+\U466.
+\:\X570:The x-height for \\{cur\_font}\X
+\U466.
+\:\X411:Tidy up the parameter just scanned, and tuck it away\X
+\U403.
+\:\X666:Transfer node \|p to the adjustment list\X
+\U662.
+\:\X895:Transplant the post-break list\X
+\U893.
+\:\X896:Transplant the pre-break list\X
+\U893.
+\:\X1164:Treat \\{cur\_chr} as an active character\X
+\Us1163\ET1167.
+\:\X884:Try the final line break at the end of the paragraph, and \&{goto} %
+\\{done} if the desired breakpoints have been found\X
+\U874.
+\:\X128:Try to allocate within node \|p and its physical successors, and %
+\&{goto} \\{found} if allocation was possible\X
+\U126.
+\:\X880:Try to break after a discretionary fragment, then \&{goto} \\{done5}\X
+\U877.
+\:\X546:Try to get a different log file name\X
+\U545.
+\:\X905:Try to hyphenate the following word\X
+\U877.
+\:\X1204:Try to recover from mismatched \.{\\right}\X
+\U1203.
+\:\X18, 25, 39, 102, 110, 114, 156, 218, 275, 306, 559, 605, 931, 936:Types in
+the outer block\X
+\U4.
+\:\X1415:Undump ML\TeX-specific data\X
+\U1316.
+\:\X1340:Undump a couple more things and the closing check word\X
+\U1316.
+\:\X1321:Undump constants for consistency check\X
+\U1316.
+\:\X1330:Undump regions 1 to 6 of \\{eqtb}\X
+\U1327.
+\:\X1336:Undump the array info for internal font number \|k\X
+\U1334.
+\:\X1325:Undump the dynamic memory\X
+\U1316.
+\:\X1334:Undump the font information\X
+\U1316.
+\:\X1332:Undump the hash table\X
+\U1327.
+\:\X1338:Undump the hyphenation tables\X
+\U1316.
+\:\X1323:Undump the string pool\X
+\U1316.
+\:\X1327:Undump the table of equivalents\X
+\U1316.
+\:\X1401:Undump \\{xord}, \\{xchr}, and \\{xprn}\X
+\U1321.
+\:\X872:Update the active widths, since the first active node has been deleted\X
+\U871.
+\:\X987:Update the current height and depth measurements with respect to a glue
+or kern node~\|p\X
+\U983.
+\:\X1015:Update the current page measurements with respect to the glue or kern
+specified by node~\|p\X
+\U1008.
+\:\X869:Update the value of \\{printed\_node} for symbolic displays\X
+\U840.
+\:\X1027:Update the values of \\{first\_mark} and \\{bot\_mark}\X
+\U1025.
+\:\X1007:Update the values of \\{last\_glue}, \\{last\_penalty}, and \\{last%
+\_kern}\X
+\U1005.
+\:\X652:Update the values of \\{max\_h} and \\{max\_v}; but if the page is too
+large, \&{goto} \\{done}\X
+\U651.
+\:\X809:Update width entry for spanned columns\X
+\U807.
+\:\X1194:Use code \|c to distinguish between generalized fractions\X
+\U1193.
+\:\X984:Use node \|p to update the current height and depth measurements; if
+this node is not a legal breakpoint, \&{goto} \\{not\_found} or \\{update%
+\_heights}, otherwise set \\{pi} to the associated penalty at the break\X
+\U983.
+\:\X577:Use size fields to allocate font information\X
+\U573.
+\:\X1371:Wipe out the whatsit node \|p and \&{goto} \\{done}\X
+\U208.
+\:\X1032:Wrap up the box specified by node \|r, splitting node \|p if called
+for; set $\\{wait}\K\\{true}$ if node \|p holds a remainder after splitting\X
+\U1031.
+\:\X140:Yoko to other direction\X
+\U139.
+\:\X1050:goto \\{main\_lig\_loop}\X
+\Us1049, 1049, 1049, 1049\ETs1049.
+\con
diff --git a/doc/ptex.web b/doc/ptex.web
new file mode 100644 (file)
index 0000000..2a21b35
--- /dev/null
@@ -0,0 +1,28897 @@
+% This program is copyright (C) 1982 by D. E. Knuth; all rights are reserved.
+% Copying of this file is authorized only if (1) you are D. E. Knuth, or if
+% (2) you make absolutely no changes to your copy. (The WEB system provides
+% for alterations via an auxiliary file; the master file should stay intact.)
+% See Appendix H of the WEB manual for hints on how to install this program.
+% And see Appendix A of the TRIP manual for details about how to validate it.
+
+% TeX is a trademark of the American Mathematical Society.
+% METAFONT is a trademark of Addison-Wesley Publishing Company.
+
+% Version 0 was released in September 1982 after it passed a variety of tests.
+% Version 1 was released in November 1983 after thorough testing.
+% Version 1.1 fixed ``disappearing font identifiers'' et alia (July 1984).
+% Version 1.2 allowed `0' in response to an error, et alia (October 1984).
+% Version 1.3 made memory allocation more flexible and local (November 1984).
+% Version 1.4 fixed accents right after line breaks, et alia (April 1985).
+% Version 1.5 fixed \the\toks after other expansion in \edefs (August 1985).
+% Version 2.0 (almost identical to 1.5) corresponds to "Volume B" (April 1986).
+% Version 2.1 corrected anomalies in discretionary breaks (January 1987).
+% Version 2.2 corrected "(Please type...)" with null \endlinechar (April 1987).
+% Version 2.3 avoided incomplete page in premature termination (August 1987).
+% Version 2.4 fixed \noaligned rules in indented displays (August 1987).
+% Version 2.5 saved cur_order when expanding tokens (September 1987).
+% Version 2.6 added 10sp slop when shipping leaders (November 1987).
+% Version 2.7 improved rounding of negative-width characters (November 1987).
+% Version 2.8 fixed weird bug if no \patterns are used (December 1987).
+% Version 2.9 made \csname\endcsname's "relax" local (December 1987).
+% Version 2.91 fixed \outer\def\a0{}\a\a bug (April 1988).
+% Version 2.92 fixed \patterns, also file names with complex macros (May 1988).
+% Version 2.93 fixed negative halving in allocator when mem_min<0 (June 1988).
+% Version 2.94 kept open_log_file from calling fatal_error (November 1988).
+% Version 2.95 solved that problem a better way (December 1988).
+% Version 2.96 corrected bug in "Infinite shrinkage" recovery (January 1989).
+% Version 2.97 corrected blunder in creating 2.95 (February 1989).
+% Version 2.98 omitted save_for_after at outer level (March 1989).
+% Version 2.99 caught $$\begingroup\halign..$$ (June 1989).
+% Version 2.991 caught .5\ifdim.6... (June 1989).
+% Version 2.992 introduced major changes for 8-bit extensions (September 1989).
+% Version 2.993 fixed a save_stack synchronization bug et alia (December 1989).
+% Version 3.0 fixed unusual displays; was more \output robust (March 1990).
+% Version 3.1 fixed nullfont, disabled \write{\the\prevgraf} (September 1990).
+% Version 3.14 fixed unprintable font names and corrected typos (March 1991).
+% Version 3.141 more of same; reconstituted ligatures better (March 1992).
+% Version 3.1415 preserved nonexplicit kerns, tidied up (February 1993).
+% Version 3.14159 allowed fontmemsize to change; bulletproofing (March 1995).
+% Version 3.141592 fixed \xleaders, glueset, weird alignments (December 2002).
+% Version 3.1415926 was a general cleanup with minor fixes (February 2008).
+
+% A reward of $327.68 will be paid to the first finder of any remaining bug.
+
+% Although considerable effort has been expended to make the TeX program
+% correct and reliable, no warranty is implied; the author disclaims any
+% obligation or liability for damages, including but not limited to
+% special, indirect, or consequential damages arising out of or in
+% connection with the use or performance of this software. This work has
+% been a ``labor of love'' and the author hopes that users enjoy it.
+
+% Here is TeX material that gets inserted after \input webmac
+\def\hang{\hangindent 3em\noindent\ignorespaces}
+\def\hangg#1 {\hang\hbox{#1 }}
+\def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps for names like SAIL
+\def\PASCAL{Pascal}
+\def\ph{\hbox{Pascal-H}}
+\def\pct!{{\char`\%}} % percent sign in ordinary text
+\font\logo=logo10 % font used for the METAFONT logo
+\def\MF{{\logo META}\-{\logo FONT}}
+\def\<#1>{$\langle#1\rangle$}
+\def\section{\mathhexbox278}
+
+\def\(#1){} % this is used to make section names sort themselves better
+\def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
+
+\outer\def\N#1. \[#2]#3.{\MN#1.\vfil\eject % begin starred section
+  \def\rhead{PART #2:\uppercase{#3}} % define running headline
+  \message{*\modno} % progress report
+  \edef\next{\write\cont{\Z{\?#2]#3}{\modno}{\the\pageno}}}\next
+  \ifon\startsection{\bf\ignorespaces#3.\quad}\ignorespaces}
+\let\?=\relax % we want to be able to \write a \?
+
+\def\title{\TeX82}
+\def\topofcontents{\hsize 5.5in
+  \vglue 0pt plus 1fil minus 1.5in
+  \def\?##1]{\hbox{Changes to \hbox to 1em{\hfil##1}.\ }}
+  }
+\let\maybe=\iffalse
+\def\botofcontents{\vskip 0pt plus 1fil minus 1.5in}
+\pageno=3
+\def\glob{13} % this should be the section number of "<Global...>"
+\def\gglob{20, 26} % this should be the next two sections of "<Global...>"
+
+@* \[1] Introduction.
+This is \TeX, a document compiler intended to produce typesetting of high
+quality.
+The \PASCAL\ program that follows is the definition of \TeX82, a standard
+@:PASCAL}{\PASCAL@>
+@!@:TeX82}{\TeX82@>
+version of \TeX\ that is designed to be highly portable so that identical output
+will be obtainable on a great variety of computers.
+
+The main purpose of the following program is to explain the algorithms of \TeX\
+as clearly as possible. As a result, the program will not necessarily be very
+efficient when a particular \PASCAL\ compiler has translated it into a
+particular machine language. However, the program has been written so that it
+can be tuned to run efficiently in a wide variety of operating environments
+by making comparatively few changes. Such flexibility is possible because
+the documentation that follows is written in the \.{WEB} language, which is
+at a higher level than \PASCAL; the preprocessing step that converts \.{WEB}
+to \PASCAL\ is able to introduce most of the necessary refinements.
+Semi-automatic translation to other languages is also feasible, because the
+program below does not make extensive use of features that are peculiar to
+\PASCAL.
+
+A large piece of software like \TeX\ has inherent complexity that cannot
+be reduced below a certain level of difficulty, although each individual
+part is fairly simple by itself. The \.{WEB} language is intended to make
+the algorithms as readable as possible, by reflecting the way the
+individual program pieces fit together and by providing the
+cross-references that connect different parts. Detailed comments about
+what is going on, and about why things were done in certain ways, have
+been liberally sprinkled throughout the program.  These comments explain
+features of the implementation, but they rarely attempt to explain the
+\TeX\ language itself, since the reader is supposed to be familiar with
+{\sl The \TeX book}.
+@.WEB@>
+@:TeXbook}{\sl The \TeX book@>
+
+@ The present implementation has a long ancestry, beginning in the summer
+of~1977, when Michael~F. Plass and Frank~M. Liang designed and coded
+a prototype
+@^Plass, Michael Frederick@>
+@^Liang, Franklin Mark@>
+@^Knuth, Donald Ervin@>
+based on some specifications that the author had made in May of that year.
+This original proto\TeX\ included macro definitions and elementary
+manipulations on boxes and glue, but it did not have line-breaking,
+page-breaking, mathematical formulas, alignment routines, error recovery,
+or the present semantic nest; furthermore,
+it used character lists instead of token lists, so that a control sequence
+like \.{\\halign} was represented by a list of seven characters. A
+complete version of \TeX\ was designed and coded by the author in late
+1977 and early 1978; that program, like its prototype, was written in the
+{\mc SAIL} language, for which an excellent debugging system was
+available. Preliminary plans to convert the {\mc SAIL} code into a form
+somewhat like the present ``web'' were developed by Luis Trabb~Pardo and
+@^Trabb Pardo, Luis Isidoro@>
+the author at the beginning of 1979, and a complete implementation was
+created by Ignacio~A. Zabala in 1979 and 1980. The \TeX82 program, which
+@^Zabala Salelles, Ignacio Andr\'es@>
+was written by the author during the latter part of 1981 and the early
+part of 1982, also incorporates ideas from the 1979 implementation of
+@^Guibas, Leonidas Ioannis@>
+@^Sedgewick, Robert@>
+@^Wyatt, Douglas Kirk@>
+\TeX\ in {\mc MESA} that was written by Leonidas Guibas, Robert Sedgewick,
+and Douglas Wyatt at the Xerox Palo Alto Research Center.  Several hundred
+refinements were introduced into \TeX82 based on the experiences gained with
+the original implementations, so that essentially every part of the system
+has been substantially improved. After the appearance of ``Version 0'' in
+September 1982, this program benefited greatly from the comments of
+many other people, notably David~R. Fuchs and Howard~W. Trickey.
+A final revision in September 1989 extended the input character set to
+eight-bit codes and introduced the ability to hyphenate words from
+different languages, based on some ideas of Michael~J. Ferguson.
+@^Fuchs, David Raymond@>
+@^Trickey, Howard Wellington@>
+@^Ferguson, Michael John@>
+
+No doubt there still is plenty of room for improvement, but the author
+is firmly committed to keeping \TeX82 ``frozen'' from now on; stability
+and reliability are to be its main virtues.
+
+On the other hand, the \.{WEB} description can be extended without changing
+the core of \TeX82 itself, and the program has been designed so that such
+extensions are not extremely difficult to make.
+The |banner| string defined here should be changed whenever \TeX\
+undergoes any modifications, so that it will be clear which version of
+\TeX\ might be the guilty party when a problem arises.
+@^extensions to \TeX@>
+@^system dependencies@>
+
+If this program is changed, the resulting system should not be called
+`\TeX'; the official name `\TeX' by itself is reserved
+for software systems that are fully compatible with each other.
+A special test suite called the ``\.{TRIP} test'' is available for
+helping to determine whether a particular implementation deserves to be
+known as `\TeX' [cf.~Stanford Computer Science report CS1027,
+November 1984].
+
+ML\TeX{} will add new primitives changing the behaviour of \TeX.  The
+|banner| string has to be changed.  We do not change the |banner|
+string, but will output an additional line to make clear that this is
+a modified \TeX{} version.
+
+
+@d TeX_banner_k=='This is TeXk, Version 3.1415926' {printed when \TeX\ starts}
+@d TeX_banner=='This is TeX, Version 3.1415926' {printed when \TeX\ starts}
+@#
+@d pTeX_version_string=='-p3.5' {current p\TeX\ version}
+@#
+@d pTeX_banner=='This is pTeX, Version 3.14159265',pTeX_version_string
+@d pTeX_banner_k==pTeX_banner
+  {printed when p\TeX\ starts}
+@#
+@d banner==pTeX_banner
+@d banner_k==pTeX_banner_k
+
+@ Different \PASCAL s have slightly different conventions, and the present
+@!@:PASCAL H}{\ph@>
+program expresses \TeX\ in terms of the \PASCAL\ that was
+available to the author in 1982. Constructions that apply to
+this particular compiler, which we shall call \ph, should help the
+reader see how to make an appropriate interface for other systems
+if necessary. (\ph\ is Charles Hedrick's modification of a compiler
+@^Hedrick, Charles Locke@>
+for the DECsystem-10 that was originally developed at the University of
+Hamburg; cf.\ {\sl SOFTWARE---Practice \AM\ Experience \bf6} (1976),
+29--42. The \TeX\ program below is intended to be adaptable, without
+extensive changes, to most other versions of \PASCAL, so it does not fully
+use the admirable features of \ph. Indeed, a conscious effort has been
+made here to avoid using several idiosyncratic features of standard
+\PASCAL\ itself, so that most of the code can be translated mechanically
+into other high-level languages. For example, the `\&{with}' and `\\{new}'
+features are not used, nor are pointer types, set types, or enumerated
+scalar types; there are no `\&{var}' parameters, except in the case of files;
+there are no tag fields on variant records; there are no assignments
+|real:=integer|; no procedures are declared local to other procedures.)
+
+The portions of this program that involve system-dependent code, where
+changes might be necessary because of differences between \PASCAL\ compilers
+and/or differences between
+operating systems, can be identified by looking at the sections whose
+numbers are listed under `system dependencies' in the index. Furthermore,
+the index entries for `dirty \PASCAL' list all places where the restrictions
+of \PASCAL\ have not been followed perfectly, for one reason or another.
+@!@^system dependencies@>
+@!@^dirty \PASCAL@>
+
+Incidentally, \PASCAL's standard |round| function can be problematical,
+because it disagrees with the IEEE floating-point standard.
+Many implementors have
+therefore chosen to substitute their own home-grown rounding procedure.
+
+@ The program begins with a normal \PASCAL\ program heading, whose
+components will be filled in later, using the conventions of \.{WEB}.
+@.WEB@>
+For example, the portion of the program called `\X\glob:Global
+variables\X' below will be replaced by a sequence of variable declarations
+that starts in $\section\glob$ of this documentation. In this way, we are able
+to define each individual global variable when we are prepared to
+understand what it means; we do not have to define all of the globals at
+once.  Cross references in $\section\glob$, where it says ``See also
+sections \gglob, \dots,'' also make it possible to look at the set of
+all global variables, if desired.  Similar remarks apply to the other
+portions of the program heading.
+
+
+@d mtype==t@&y@&p@&e {this is a \.{WEB} coding trick:}
+@f mtype==type {`\&{mtype}' will be equivalent to `\&{type}'}
+@f type==true {but `|type|' will not be treated as a reserved word}
+
+@p @t\4@>@<Compiler directives@>@/
+program TEX; {all file names are defined dynamically}
+const @<Constants in the outer block@>@/
+mtype @<Types in the outer block@>@/
+var @<Global variables@>@/
+@#
+procedure initialize; {this procedure gets things started properly}
+  var @<Local variables for initialization@>@/
+  begin @<Initialize whatever \TeX\ might access@>@;
+  end;@#
+@t\4@>@<Basic printing procedures@>@/
+@t\4@>@<Error handling procedures@>@/
+
+@ The overall \TeX\ program begins with the heading just shown, after which
+comes a bunch of procedure declarations and function declarations.
+Finally we will get to the main program, which begins with the
+comment `|start_here|'. If you want to skip down to the
+main program now, you can look up `|start_here|' in the index.
+But the author suggests that the best way to understand this program
+is to follow pretty much the order of \TeX's components as they appear in the
+\.{WEB} description you are now reading, since the present ordering is
+intended to combine the advantages of the ``bottom up'' and ``top down''
+approaches to the problem of understanding a somewhat complicated system.
+
+@ For Web2c, labels are not declared in the main program, but
+we still have to declare the symbolic names.
+
+@d start_of_TEX=1 {go here when \TeX's variables are initialized}
+@d final_end=9999 {this label marks the ending of the program}
+
+@ Some of the code below is intended to be used only when diagnosing the
+strange behavior that sometimes occurs when \TeX\ is being installed or
+when system wizards are fooling around with \TeX\ without quite knowing
+what they are doing. Such code will not normally be compiled; it is
+delimited by the codewords `$|debug|\ldots|gubed|$', with apologies
+to people who wish to preserve the purity of English.
+
+Similarly, there is some conditional code delimited by
+`$|stat|\ldots|tats|$' that is intended for use when statistics are to be
+kept about \TeX's memory usage.  The |stat| $\ldots$ |tats| code also
+implements diagnostic information for \.{\\tracingparagraphs} and
+\.{\\tracingpages}.
+@^debugging@>
+
+@d debug==ifdef('TEXMF_DEBUG')
+@d gubed==endif('TEXMF_DEBUG')
+@f debug==begin
+@f gubed==end
+@#
+@d stat==ifdef('STAT')
+@d tats==endif('STAT')
+@f stat==begin
+@f tats==end
+
+@ This program has two important variations: (1) There is a long and slow
+version called \.{INITEX}, which does the extra calculations needed to
+@.INITEX@>
+initialize \TeX's internal tables; and (2)~there is a shorter and faster
+production version, which cuts the initialization to a bare minimum.
+Parts of the program that are needed in (1) but not in (2) are delimited by
+the codewords `$|init|\ldots|tini|$' for declarations and by the codewords
+`$|Init|\ldots|Tini|$' for executable code.  This distinction is helpful for
+implementations where a run-time switch differentiates between the two
+versions of the program.
+
+@d init==ifdef('INITEX')
+@d tini==endif('INITEX')
+@d Init==init if ini_version then begin
+@d Tini==end;@+tini
+@f Init==begin
+@f Tini==end
+@f init==begin
+@f tini==end
+
+@<Initialize whatever...@>=
+@<Set initial values of key variables@>@/
+@!Init @<Initialize table entries (done by \.{INITEX} only)@>@;@+Tini
+
+@ If the first character of a \PASCAL\ comment is a dollar sign,
+\ph\ treats the comment as a list of ``compiler directives'' that will
+affect the translation of this program into machine language.  The
+directives shown below specify full checking and inclusion of the \PASCAL\
+debugger when \TeX\ is being debugged, but they cause range checking and other
+redundant code to be eliminated when the production system is being generated.
+Arithmetic overflow will be detected in all cases.
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+@^overflow in arithmetic@>
+
+@<Compiler directives@>=
+@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead}
+@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging}
+
+@ This \TeX\ implementation conforms to the rules of the {\sl Pascal User
+@:PASCAL}{\PASCAL@>
+@^system dependencies@>
+Manual} published by Jensen and Wirth in 1975, except where system-dependent
+@^Wirth, Niklaus@>
+@^Jensen, Kathleen@>
+code is necessary to make a useful system program, and except in another
+respect where such conformity would unnecessarily obscure the meaning
+and clutter up the code: We assume that |case| statements may include a
+default case that applies if no matching label is found. Thus, we shall use
+constructions like
+$$\vbox{\halign{\ignorespaces#\hfil\cr
+|case x of|\cr
+1: $\langle\,$code for $x=1\,\rangle$;\cr
+3: $\langle\,$code for $x=3\,\rangle$;\cr
+|othercases| $\langle\,$code for |x<>1| and |x<>3|$\,\rangle$\cr
+|endcases|\cr}}$$
+since most \PASCAL\ compilers have plugged this hole in the language by
+incorporating some sort of default mechanism. For example, the \ph\
+compiler allows `|others|:' as a default label, and other \PASCAL s allow
+syntaxes like `\&{else}' or `\&{otherwise}' or `\\{otherwise}:', etc. The
+definitions of |othercases| and |endcases| should be changed to agree with
+local conventions.  Note that no semicolon appears before |endcases| in
+this program, so the definition of |endcases| should include a semicolon
+if the compiler wants one. (Of course, if no default mechanism is
+available, the |case| statements of \TeX\ will have to be laboriously
+extended by listing all remaining cases. People who are stuck with such
+\PASCAL s have, in fact, done this, successfully but not happily!)
+@:PASCAL H}{\ph@>
+
+@d othercases == others: {default for cases not listed explicitly}
+@d endcases == @+end {follows the default case in an extended |case| statement}
+@f othercases == else
+@f endcases == end
+
+@ The following parameters can be changed at compile time to extend or
+reduce \TeX's capacity. They may have different values in \.{INITEX} and
+in production versions of \TeX.
+@.INITEX@>
+@^system dependencies@>
+
+@d file_name_size == maxint
+@d ssup_error_line = 255
+@d ssup_max_strings == 2097151
+{Larger values than 65536 cause the arrays to consume much more memory.}
+@d ssup_trie_opcode == 65535
+@d ssup_trie_size == @"3FFFFF
+
+@d ssup_hyph_size == 65535 {Changing this requires changing (un)dumping!}
+@d iinf_hyphen_size == 610 {Must be not less than |hyph_prime|!}
+
+@d max_font_max=9000 {maximum number of internal fonts; this can be
+                      increased, but |hash_size+max_font_max|
+                      should not exceed 29000.}
+@d font_base=0 {smallest internal font number; must be
+                |>= min_quarterword|; do not change this without
+                modifying the dynamic definition of the font arrays.}
+
+
+@<Constants...@>=
+@!hash_offset=514; {smallest index in hash array, i.e., |hash_base| }
+  {Use |hash_offset=0| for compilers which cannot decrement pointers.}
+@!trie_op_size=35111; {space for ``opcodes'' in the hyphenation patterns;
+  best if relatively prime to 313, 361, and 1009.}
+@!neg_trie_op_size=-35111; {for lower |trie_op_hash| array bound;
+  must be equal to |-trie_op_size|.}
+@!min_trie_op=0; {first possible trie op code for any language}
+@!max_trie_op=ssup_trie_opcode; {largest possible trie opcode for any language}
+@!pool_name=TEXMF_POOL_NAME; {this is configurable, for the sake of ML-\TeX}
+  {string of length |file_name_size|; tells where the string pool appears}
+@!engine_name=TEXMF_ENGINE_NAME; {the name of this engine}
+@#
+@!inf_mem_bot = 0;
+@!sup_mem_bot = 1;
+
+@!inf_main_memory = 3000;
+@!sup_main_memory = 256000000;
+
+@!inf_trie_size = 8000;
+@!sup_trie_size = ssup_trie_size;
+
+@!inf_max_strings = 3000;
+@!sup_max_strings = ssup_max_strings;
+@!inf_strings_free = 100;
+@!sup_strings_free = sup_max_strings;
+
+@!inf_buf_size = 500;
+@!sup_buf_size = 30000000;
+
+@!inf_nest_size = 40;
+@!sup_nest_size = 4000;
+
+@!inf_max_in_open = 6;
+@!sup_max_in_open = 127;
+
+@!inf_param_size = 60;
+@!sup_param_size = 32767;
+
+@!inf_save_size = 600;
+@!sup_save_size = 80000;
+
+@!inf_stack_size = 200;
+@!sup_stack_size = 30000;
+
+@!inf_dvi_buf_size = 800;
+@!sup_dvi_buf_size = 65536;
+
+@!inf_font_mem_size = 20000;
+@!sup_font_mem_size = 147483647; {|integer|-limited, so 2 could be prepended?}
+
+@!sup_font_max = max_font_max;
+@!inf_font_max = 50; {could be smaller, but why?}
+
+@!inf_pool_size = 32000;
+@!sup_pool_size = 40000000;
+@!inf_pool_free = 1000;
+@!sup_pool_free = sup_pool_size;
+@!inf_string_vacancies = 8000;
+@!sup_string_vacancies = sup_pool_size - 23000;
+
+@!sup_hash_extra = sup_max_strings;
+@!inf_hash_extra = 0;
+
+@!sup_hyph_size = ssup_hyph_size;
+@!inf_hyph_size = iinf_hyphen_size; {Must be not less than |hyph_prime|!}
+
+@!inf_expand_depth = 10;
+@!sup_expand_depth = 10000000;
+@.TeXformats@>
+
+@ Like the preceding parameters, the following quantities can be changed
+at compile time to extend or reduce \TeX's capacity. But if they are changed,
+it is necessary to rerun the initialization program \.{INITEX}
+@.INITEX@>
+to generate new tables for the production \TeX\ program.
+One can't simply make helter-skelter changes to the following constants,
+since certain rather complex initialization
+numbers are computed from them. They are defined here using
+\.{WEB} macros, instead of being put into \PASCAL's |const| list, in order to
+emphasize this distinction.
+
+@d hash_size=15000 {maximum number of control sequences; it should be at most
+  about |(mem_max-mem_min)/10|; see also |font_max|}
+@d hash_prime=8501 {a prime number equal to about 85\pct! of |hash_size|}
+@d hyph_prime=607 {another prime for hashing \.{\\hyphenation} exceptions;
+                if you change this, you should also change |iinf_hyphen_size|.}
+@^system dependencies@>
+
+@ In case somebody has inadvertently made bad settings of the ``constants,''
+\TeX\ checks them using a global variable called |bad|.
+
+This is the first of many sections of \TeX\ where global variables are
+defined.
+
+@<Glob...@>=
+@!bad:integer; {is some ``constant'' wrong?}
+
+@ Later on we will say `\ignorespaces|if mem_max>=max_halfword then bad:=14|',
+or something similar. (We can't do that until |max_halfword| has been defined.)
+
+@<Check the ``constant'' values for consistency@>=
+bad:=0;
+if (half_error_line<30)or(half_error_line>error_line-15) then bad:=1;
+if max_print_line<60 then bad:=2;
+if dvi_buf_size mod 8<>0 then bad:=3;
+if mem_bot+1100>mem_top then bad:=4;
+if hash_prime>hash_size then bad:=5;
+if max_in_open>=128 then bad:=6;
+if mem_top<256+11 then bad:=7; {we will want |null_list>255|}
+
+@ Labels are given symbolic names by the following definitions, so that
+occasional |goto| statements will be meaningful. We insert the label
+`|exit|' just before the `\ignorespaces|end|\unskip' of a procedure in
+which we have used the `|return|' statement defined below; the label
+`|restart|' is occasionally used at the very beginning of a procedure; and
+the label `|reswitch|' is occasionally used just prior to a |case|
+statement in which some cases change the conditions and we wish to branch
+to the newly applicable case.  Loops that are set up with the |loop|
+construction defined below are commonly exited by going to `|done|' or to
+`|found|' or to `|not_found|', and they are sometimes repeated by going to
+`|continue|'.  If two or more parts of a subroutine start differently but
+end up the same, the shared code may be gathered together at
+`|common_ending|'.
+
+Incidentally, this program never declares a label that isn't actually used,
+because some fussy \PASCAL\ compilers will complain about redundant labels.
+
+@d exit=10 {go here to leave a procedure}
+@d restart=20 {go here to start a procedure again}
+@d reswitch=21 {go here to start a case statement again}
+@d continue=22 {go here to resume a loop}
+@d done=30 {go here to exit a loop}
+@d done1=31 {like |done|, when there is more than one loop}
+@d done2=32 {for exiting the second loop in a long block}
+@d done3=33 {for exiting the third loop in a very long block}
+@d done4=34 {for exiting the fourth loop in an extremely long block}
+@d done5=35 {for exiting the fifth loop in an immense block}
+@d done6=36 {for exiting the sixth loop in a block}
+@d found=40 {go here when you've found it}
+@d found1=41 {like |found|, when there's more than one per routine}
+@d found2=42 {like |found|, when there's more than two per routine}
+@d not_found=45 {go here when you've found nothing}
+@d common_ending=50 {go here when you want to merge with another branch}
+
+@ Here are some macros for common programming idioms.
+
+@d negate(#) == #:=-# {change the sign of a variable}
+@d loop == @+ while true do@+ {repeat over and over until a |goto| happens}
+@f loop == xclause
+  {\.{WEB}'s |xclause| acts like `\ignorespaces|while true do|\unskip'}
+@d do_nothing == {empty statement}
+@d return == goto exit {terminate a procedure call}
+@f return == nil
+@d empty=0 {symbolic name for a null constant}
+
+@* \[2] The character set.
+In order to make \TeX\ readily portable to a wide variety of
+computers, all of its input text is converted to an internal eight-bit
+code that includes standard ASCII, the ``American Standard Code for
+Information Interchange.''  This conversion is done immediately when each
+character is read in. Conversely, characters are converted from ASCII to
+the user's external representation just before they are output to a
+text file.
+
+Such an internal code is relevant to users of \TeX\ primarily because it
+governs the positions of characters in the fonts. For example, the
+character `\.A' has ASCII code $65=@'101$, and when \TeX\ typesets
+this letter it specifies character number 65 in the current font.
+If that font actually has `\.A' in a different position, \TeX\ doesn't
+know what the real position is; the program that does the actual printing from
+\TeX's device-independent files is responsible for converting from ASCII to
+a particular font encoding.
+@^ASCII code@>
+
+\TeX's internal code also defines the value of constants
+that begin with a reverse apostrophe; and it provides an index to the
+\.{\\catcode}, \.{\\mathcode}, \.{\\uccode}, \.{\\lccode}, and \.{\\delcode}
+tables.
+
+@ Characters of text that have been converted to \TeX's internal form
+are said to be of type |ASCII_code|, which is a subrange of the integers.
+
+@<Types...@>=
+@!ASCII_code=0..255; {eight-bit numbers}
+@!KANJI_code=0..65535; {sixteen-bit numbers}
+
+@ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
+character sets were common, so it did not make provision for lowercase
+letters. Nowadays, of course, we need to deal with both capital and small
+letters in a convenient way, especially in a program for typesetting;
+so the present specification of \TeX\ has been written under the assumption
+that the \PASCAL\ compiler and run-time system permit the use of text files
+with more than 64 distinguishable characters. More precisely, we assume that
+the character set contains at least the letters and symbols associated
+with ASCII codes @'40 through @'176; all of these characters are now
+available on most computer terminals.
+
+Since we are dealing with more characters than were present in the first
+\PASCAL\ compilers, we have to decide what to call the associated data
+type. Some \PASCAL s use the original name |char| for the
+characters in text files, even though there now are more than 64 such
+characters, while other \PASCAL s consider |char| to be a 64-element
+subrange of a larger data type that has some other name.
+
+In order to accommodate this difference, we shall use the name |text_char|
+to stand for the data type of the characters that are converted to and
+from |ASCII_code| when they are input and output. We shall also assume
+that |text_char| consists of the elements |chr(first_text_char)| through
+|chr(last_text_char)|, inclusive. The following definitions should be
+adjusted if necessary.
+@^system dependencies@>
+
+@d text_char == ASCII_code {the data type of characters in text files}
+@d first_text_char=0 {ordinal number of the smallest element of |text_char|}
+@d last_text_char=255 {ordinal number of the largest element of |text_char|}
+
+@<Local variables for init...@>=
+@!i:integer;
+
+@ The \TeX\ processor converts between ASCII code and
+the user's external character set by means of arrays |xord| and |xchr|
+that are analogous to \PASCAL's |ord| and |chr| functions.
+
+@<Glob...@>=
+@!xord: array [text_char] of ASCII_code;
+  {specifies conversion of input characters}
+xchr: array [ASCII_code] of text_char;
+   { specifies conversion of output characters }
+xprn: array [ASCII_code] of ASCII_code;
+   { non zero iff character is printable }
+
+@ Since we are assuming that our \PASCAL\ system is able to read and
+write the visible characters of standard ASCII (although not
+necessarily using the ASCII codes to represent them), the following
+assignment statements initialize the standard part of the |xchr| array
+properly, without needing any system-dependent changes. On the other
+hand, it is possible to implement \TeX\ with less complete character
+sets, and in such cases it will be necessary to change something here.
+@^system dependencies@>
+
+@<Set init...@>=
+xchr[@'40]:=' ';
+xchr[@'41]:='!';
+xchr[@'42]:='"';
+xchr[@'43]:='#';
+xchr[@'44]:='$';
+xchr[@'45]:='%';
+xchr[@'46]:='&';
+xchr[@'47]:='''';@/
+xchr[@'50]:='(';
+xchr[@'51]:=')';
+xchr[@'52]:='*';
+xchr[@'53]:='+';
+xchr[@'54]:=',';
+xchr[@'55]:='-';
+xchr[@'56]:='.';
+xchr[@'57]:='/';@/
+xchr[@'60]:='0';
+xchr[@'61]:='1';
+xchr[@'62]:='2';
+xchr[@'63]:='3';
+xchr[@'64]:='4';
+xchr[@'65]:='5';
+xchr[@'66]:='6';
+xchr[@'67]:='7';@/
+xchr[@'70]:='8';
+xchr[@'71]:='9';
+xchr[@'72]:=':';
+xchr[@'73]:=';';
+xchr[@'74]:='<';
+xchr[@'75]:='=';
+xchr[@'76]:='>';
+xchr[@'77]:='?';@/
+xchr[@'100]:='@@';
+xchr[@'101]:='A';
+xchr[@'102]:='B';
+xchr[@'103]:='C';
+xchr[@'104]:='D';
+xchr[@'105]:='E';
+xchr[@'106]:='F';
+xchr[@'107]:='G';@/
+xchr[@'110]:='H';
+xchr[@'111]:='I';
+xchr[@'112]:='J';
+xchr[@'113]:='K';
+xchr[@'114]:='L';
+xchr[@'115]:='M';
+xchr[@'116]:='N';
+xchr[@'117]:='O';@/
+xchr[@'120]:='P';
+xchr[@'121]:='Q';
+xchr[@'122]:='R';
+xchr[@'123]:='S';
+xchr[@'124]:='T';
+xchr[@'125]:='U';
+xchr[@'126]:='V';
+xchr[@'127]:='W';@/
+xchr[@'130]:='X';
+xchr[@'131]:='Y';
+xchr[@'132]:='Z';
+xchr[@'133]:='[';
+xchr[@'134]:='\';
+xchr[@'135]:=']';
+xchr[@'136]:='^';
+xchr[@'137]:='_';@/
+xchr[@'140]:='`';
+xchr[@'141]:='a';
+xchr[@'142]:='b';
+xchr[@'143]:='c';
+xchr[@'144]:='d';
+xchr[@'145]:='e';
+xchr[@'146]:='f';
+xchr[@'147]:='g';@/
+xchr[@'150]:='h';
+xchr[@'151]:='i';
+xchr[@'152]:='j';
+xchr[@'153]:='k';
+xchr[@'154]:='l';
+xchr[@'155]:='m';
+xchr[@'156]:='n';
+xchr[@'157]:='o';@/
+xchr[@'160]:='p';
+xchr[@'161]:='q';
+xchr[@'162]:='r';
+xchr[@'163]:='s';
+xchr[@'164]:='t';
+xchr[@'165]:='u';
+xchr[@'166]:='v';
+xchr[@'167]:='w';@/
+xchr[@'170]:='x';
+xchr[@'171]:='y';
+xchr[@'172]:='z';
+xchr[@'173]:='{';
+xchr[@'174]:='|';
+xchr[@'175]:='}';
+xchr[@'176]:='~';@/
+
+@ Some of the ASCII codes without visible characters have been given symbolic
+names in this program because they are used with a special meaning.
+
+@d null_code=@'0 {ASCII code that might disappear}
+@d carriage_return=@'15 {ASCII code used at end of line}
+@d invalid_code=@'177 {ASCII code that many systems prohibit in text files}
+
+@ The ASCII code is ``standard'' only to a certain extent, since many
+computer installations have found it advantageous to have ready access
+to more than 94 printing characters. Appendix~C of {\sl The \TeX book\/}
+gives a complete specification of the intended correspondence between
+characters and \TeX's internal representation.
+@:TeXbook}{\sl The \TeX book@>
+
+If \TeX\ is being used
+on a garden-variety \PASCAL\ for which only standard ASCII
+codes will appear in the input and output files, it doesn't really matter
+what codes are specified in |xchr[0..@'37]|, but the safest policy is to
+blank everything out by using the code shown below.
+
+However, other settings of |xchr| will make \TeX\ more friendly on
+computers that have an extended character set, so that users can type things
+like `\.^^Z' instead of `\.{\\ne}'. People with extended character sets can
+assign codes arbitrarily, giving an |xchr| equivalent to whatever
+characters the users of \TeX\ are allowed to have in their input files.
+It is best to make the codes correspond to the intended interpretations as
+shown in Appendix~C whenever possible; but this is not necessary. For
+example, in countries with an alphabet of more than 26 letters, it is
+usually best to map the additional letters into codes less than~@'40.
+To get the most ``permissive'' character set, change |' '| on the
+right of these assignment statements to |chr(i)|.
+@^character set dependencies@>
+@^system dependencies@>
+
+@<Set init...@>=
+{Initialize |xchr| to the identity mapping.}
+for i:=0 to @'37 do xchr[i]:=i;
+for i:=@'177 to @'377 do xchr[i]:=i;
+
+@ The following system-independent code makes the |xord| array contain a
+suitable inverse to the information in |xchr|. Note that if |xchr[i]=xchr[j]|
+where |i<j<@'177|, the value of |xord[xchr[i]]| will turn out to be
+|j| or more; hence, standard ASCII code numbers will be used instead of
+codes below @'40 in case there is a coincidence.
+
+@<Set init...@>=
+for i:=first_text_char to last_text_char do xord[chr(i)]:=invalid_code;
+for i:=@'200 to @'377 do xord[xchr[i]]:=i;
+for i:=0 to @'176 do xord[xchr[i]]:=i;
+{Set |xprn| for printable ASCII, unless |eight_bit_p| is set.}
+for i:=0 to 255 do xprn[i]:=(eight_bit_p or ((i>=" ")and(i<="~")));
+
+{The idea for this dynamic translation comes from the patch by
+ Libor Skarvada \.{<libor@@informatics.muni.cz>}
+ and Petr Sojka \.{<sojka@@informatics.muni.cz>}. I didn't use any of the
+ actual code, though, preferring a more general approach.}
+
+{This updates the |xchr|, |xord|, and |xprn| arrays from the provided
+ |translate_filename|.  See the function definition in \.{texmfmp.c} for
+ more comments.}
+if translate_filename then read_tcx_file;
+
+@* \[3] Input and output.
+The bane of portability is the fact that different operating systems treat
+input and output quite differently, perhaps because computer scientists
+have not given sufficient attention to this problem. People have felt somehow
+that input and output are not part of ``real'' programming. Well, it is true
+that some kinds of programming are more fun than others. With existing
+input/output conventions being so diverse and so messy, the only sources of
+joy in such parts of the code are the rare occasions when one can find a
+way to make the program a little less bad than it might have been. We have
+two choices, either to attack I/O now and get it over with, or to postpone
+I/O until near the end. Neither prospect is very attractive, so let's
+get it over with.
+
+The basic operations we need to do are (1)~inputting and outputting of
+text, to or from a file or the user's terminal; (2)~inputting and
+outputting of eight-bit bytes, to or from a file; (3)~instructing the
+operating system to initiate (``open'') or to terminate (``close'') input or
+output from a specified file; (4)~testing whether the end of an input
+file has been reached.
+
+\TeX\ needs to deal with two kinds of files.
+We shall use the term |alpha_file| for a file that contains textual data,
+and the term |byte_file| for a file that contains eight-bit binary information.
+These two types turn out to be the same on many computers, but
+sometimes there is a significant distinction, so we shall be careful to
+distinguish between them. Standard protocols for transferring
+such files from computer to computer, via high-speed networks, are
+now becoming available to more and more communities of users.
+
+The program actually makes use also of a third kind of file, called a
+|word_file|, when dumping and reloading base information for its own
+initialization.  We shall define a word file later; but it will be possible
+for us to specify simple operations on word files before they are defined.
+
+@<Types...@>=
+@!eight_bits=0..255; {unsigned one-byte quantity}
+@!sixteen_bits=0..65535; {unsigned two-bytes quantity}
+@!alpha_file=packed file of text_char; {files that contain textual data}
+@!byte_file=packed file of eight_bits; {files that contain binary data}
+
+@ Most of what we need to do with respect to input and output can be handled
+by the I/O facilities that are standard in \PASCAL, i.e., the routines
+called |get|, |put|, |eof|, and so on. But
+standard \PASCAL\ does not allow file variables to be associated with file
+names that are determined at run time, so it cannot be used to implement
+\TeX; some sort of extension to \PASCAL's ordinary |reset| and |rewrite|
+is crucial for our purposes. We shall assume that |name_of_file| is a variable
+of an appropriate type such that the \PASCAL\ run-time system being used to
+implement \TeX\ can open a file whose external name is specified by
+|name_of_file|.
+@^system dependencies@>
+
+@<Glob...@>=
+@!name_of_file:^text_char;
+@!name_length:0..file_name_size;@/{this many characters are actually
+  relevant in |name_of_file| (the rest are blank)}
+
+@ All of the file opening functions are defined in C.
+
+@ Kanji code handling.
+
+@ And all the file closing routines as well.
+
+@ Binary input and output are done with \PASCAL's ordinary |get| and |put|
+procedures, so we don't have to make any other special arrangements for
+binary~I/O. Text output is also easy to do with standard \PASCAL\ routines.
+The treatment of text input is more difficult, however, because
+of the necessary translation to |ASCII_code| values.
+\TeX's conventions should be efficient, and they should
+blend nicely with the user's operating environment.
+
+@ Input from text files is read one line at a time, using a routine called
+|input_ln|. This function is defined in terms of global variables called
+|buffer|, |first|, and |last| that will be described in detail later; for
+now, it suffices for us to know that |buffer| is an array of |ASCII_code|
+values, and that |first| and |last| are indices into this array
+representing the beginning and ending of a line of text.
+
+@<Glob...@>=
+@!buffer:^ASCII_code; {lines of characters being read}
+@!first:0..buf_size; {the first unused position in |buffer|}
+@!last:0..buf_size; {end of the line just input to |buffer|}
+@!max_buf_stack:0..buf_size; {largest index used in |buffer|}
+
+@ The |input_ln| function brings the next line of input from the specified
+file into available positions of the buffer array and returns the value
+|true|, unless the file has already been entirely read, in which case it
+returns |false| and sets |last:=first|.  In general, the |ASCII_code|
+numbers that represent the next line of the file are input into
+|buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the
+global variable |last| is set equal to |first| plus the length of the
+line. Trailing blanks are removed from the line; thus, either |last=first|
+(in which case the line was entirely blank) or |buffer[last-1]<>" "|.
+
+An overflow error is given, however, if the normal actions of |input_ln|
+would make |last>=buf_size|; this is done so that other parts of \TeX\
+can safely look at the contents of |buffer[last+1]| without overstepping
+the bounds of the |buffer| array. Upon entry to |input_ln|, the condition
+|first<buf_size| will always hold, so that there is always room for an
+``empty'' line.
+
+The variable |max_buf_stack|, which is used to keep track of how large
+the |buf_size| parameter must be to accommodate the present job, is
+also kept up to date by |input_ln|.
+
+If the |bypass_eoln| parameter is |true|, |input_ln| will do a |get|
+before looking at the first character of the line; this skips over
+an |eoln| that was in |f^|. The procedure does not do a |get| when it
+reaches the end of the line; therefore it can be used to acquire input
+from the user's terminal as well as from ordinary text files.
+
+Standard \PASCAL\ says that a file should have |eoln| immediately
+before |eof|, but \TeX\ needs only a weaker restriction: If |eof|
+occurs in the middle of a line, the system function |eoln| should return
+a |true| result (even though |f^| will be undefined).
+
+Since the inner loop of |input_ln| is part of \TeX's ``inner loop''---each
+character of input comes in at this place---it is wise to reduce system
+overhead by making use of special routines that read in an entire array
+of characters at once, if such routines are available. The following
+code uses standard \PASCAL\ to illustrate what needs to be done, but
+finer tuning is often possible at well-developed \PASCAL\ sites.
+@^inner loop@>
+
+We define |input_ln| in C, for efficiency. Nevertheless we quote the module
+`Report overflow of the input buffer, and abort' here in order to make
+\.{WEAVE} happy, since part of that module is needed by e-TeX.
+
+@p @{ @<Report overflow of the input buffer, and abort@> @}
+
+@ The user's terminal acts essentially like other files of text, except
+that it is used both for input and for output. When the terminal is
+considered an input file, the file variable is called |term_in|, and when it
+is considered an output file the file variable is |term_out|.
+@^system dependencies@>
+
+@d term_in==stdin {the terminal as an input file}
+@d term_out==stdout {the terminal as an output file}
+
+@<Glob...@>=
+@!init
+@!ini_version:boolean; {are we \.{INITEX}?}
+@!dump_option:boolean; {was the dump name option used?}
+@!dump_line:boolean; {was a \.{\%\AM format} line seen?}
+tini@/
+@#
+@!bound_default:integer; {temporary for setup}
+@!bound_name:const_cstring; {temporary for setup}
+@#
+@!mem_bot:integer;{smallest index in the |mem| array dumped by \.{INITEX};
+  must not be less than |mem_min|}
+@!main_memory:integer; {total memory words allocated in initex}
+@!extra_mem_bot:integer; {|mem_min:=mem_bot-extra_mem_bot| except in \.{INITEX}}
+@!mem_min:integer; {smallest index in \TeX's internal |mem| array;
+  must be |min_halfword| or more;
+  must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
+@!mem_top:integer; {largest index in the |mem| array dumped by \.{INITEX};
+  must be substantially larger than |mem_bot|,
+  equal to |mem_max| in \.{INITEX}, else not greater than |mem_max|}
+@!extra_mem_top:integer; {|mem_max:=mem_top+extra_mem_top| except in \.{INITEX}}
+@!mem_max:integer; {greatest index in \TeX's internal |mem| array;
+  must be strictly less than |max_halfword|;
+  must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
+@!error_line:integer; {width of context lines on terminal error messages}
+@!half_error_line:integer; {width of first lines of contexts in terminal
+  error messages; should be between 30 and |error_line-15|}
+@!max_print_line:integer;
+  {width of longest text lines output; should be at least 60}
+@!max_strings:integer; {maximum number of strings; must not exceed |max_halfword|}
+@!strings_free:integer; {strings available after format loaded}
+@!string_vacancies:integer; {the minimum number of characters that should be
+  available for the user's control sequences and font names,
+  after \TeX's own error messages are stored}
+@!pool_size:integer; {maximum number of characters in strings, including all
+  error messages and help texts, and the names of all fonts and
+  control sequences; must exceed |string_vacancies| by the total
+  length of \TeX's own strings, which is currently about 23000}
+@!pool_free:integer;{pool space free after format loaded}
+@!font_mem_size:integer; {number of words of |font_info| for all fonts}
+@!font_max:integer; {maximum internal font number; ok to exceed |max_quarterword|
+  and must be at most |font_base|+|max_font_max|}
+@!font_k:integer; {loop variable for initialization}
+@!hyph_size:integer; {maximun number of hyphen exceptions}
+@!trie_size:integer; {space for hyphenation patterns; should be larger for
+  \.{INITEX} than it is in production versions of \TeX.  50000 is
+  needed for English, German, and Portuguese.}
+@!buf_size:integer; {maximum number of characters simultaneously present in
+  current lines of open files and in control sequences between
+  \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
+@!stack_size:integer; {maximum number of simultaneous input sources}
+@!max_in_open:integer; {maximum number of input files and error insertions that
+  can be going on simultaneously}
+@!param_size:integer; {maximum number of simultaneous macro parameters}
+@!nest_size:integer; {maximum number of semantic levels simultaneously active}
+@!save_size:integer; {space for saving values outside of current group; must be
+  at most |max_halfword|}
+@!dvi_buf_size:integer; {size of the output buffer; must be a multiple of 8}
+@!expand_depth:integer; {limits recursive calls to the |expand| procedure}
+@!parse_first_line_p:cinttype; {parse the first line for options}
+@!file_line_error_style_p:cinttype; {format messages as file:line:error}
+@!eight_bit_p:cinttype; {make all characters printable by default}
+@!halt_on_error_p:cinttype; {stop at first error}
+@!quoted_filename:boolean; {current filename is quoted}
+{Variables for source specials}
+@!src_specials_p : boolean;{Whether |src_specials| are enabled at all}
+@!insert_src_special_auto : boolean;
+@!insert_src_special_every_par : boolean;
+@!insert_src_special_every_parend : boolean;
+@!insert_src_special_every_cr : boolean;
+@!insert_src_special_every_math : boolean;
+@!insert_src_special_every_hbox : boolean;
+@!insert_src_special_every_vbox : boolean;
+@!insert_src_special_every_display : boolean;
+
+@ Here is how to open the terminal files.  |t_open_out| does nothing.
+|t_open_in|, on the other hand, does the work of ``rescanning,'' or getting
+any command line arguments the user has provided.  It's defined in C.
+
+@d t_open_out == {output already open for text output}
+
+@ Sometimes it is necessary to synchronize the input/output mixture that
+happens on the user's terminal, and three system-dependent
+procedures are used for this
+purpose. The first of these, |update_terminal|, is called when we want
+to make sure that everything we have output to the terminal so far has
+actually left the computer's internal buffers and been sent.
+The second, |clear_terminal|, is called when we wish to cancel any
+input that the user may have typed ahead (since we are about to
+issue an unexpected error message). The third, |wake_up_terminal|,
+is supposed to revive the terminal if the user has disabled it by
+some instruction to the operating system.  The following macros show how
+these operations can be specified with {\mc UNIX}.  |update_terminal|
+does an |fflush|. |clear_terminal| is redefined
+to do nothing, since the user should control the terminal.
+@^system dependencies@>
+
+@d update_terminal == fflush (term_out)
+@d clear_terminal == do_nothing
+@d wake_up_terminal == do_nothing {cancel the user's cancellation of output}
+
+@ We need a special routine to read the first line of \TeX\ input from
+the user's terminal. This line is different because it is read before we
+have opened the transcript file; there is sort of a ``chicken and
+egg'' problem here. If the user types `\.{\\input paper}' on the first
+line, or if some macro invoked by that line does such an \.{\\input},
+the transcript file will be named `\.{paper.log}'; but if no \.{\\input}
+commands are performed during the first line of terminal input, the transcript
+file will acquire its default name `\.{texput.log}'. (The transcript file
+will not contain error messages generated by the first line before the
+first \.{\\input} command.)
+@.texput@>
+
+The first line is even more special if we are lucky enough to have an operating
+system that treats \TeX\ differently from a run-of-the-mill \PASCAL\ object
+program. It's nice to let the user start running a \TeX\ job by typing
+a command line like `\.{tex paper}'; in such a case, \TeX\ will operate
+as if the first line of input were `\.{paper}', i.e., the first line will
+consist of the remainder of the command line, after the part that invoked
+\TeX.
+
+The first line is special also because it may be read before \TeX\ has
+input a format file. In such cases, normal error messages cannot yet
+be given. The following code uses concepts that will be explained later.
+(If the \PASCAL\ compiler does not support non-local |@!goto|\unskip, the
+@^system dependencies@>
+statement `|goto final_end|' should be replaced by something that
+quietly terminates the program.)
+
+Routine is implemented in C; part of module is, however, needed for e-TeX.
+
+@<Report overflow of the input buffer, and abort@>=
+  begin cur_input.loc_field:=first; cur_input.limit_field:=last-1;
+  overflow("buffer size",buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+  end
+
+@ Different systems have different ways to get started. But regardless of
+what conventions are adopted, the routine that initializes the terminal
+should satisfy the following specifications:
+
+\yskip\textindent{1)}It should open file |term_in| for input from the
+  terminal. (The file |term_out| will already be open for output to the
+  terminal.)
+
+\textindent{2)}If the user has given a command line, this line should be
+  considered the first line of terminal input. Otherwise the
+  user should be prompted with `\.{**}', and the first line of input
+  should be whatever is typed in response.
+
+\textindent{3)}The first line of input, which might or might not be a
+  command line, should appear in locations |first| to |last-1| of the
+  |buffer| array.
+
+\textindent{4)}The global variable |loc| should be set so that the
+  character to be read next by \TeX\ is in |buffer[loc]|. This
+  character should not be blank, and we should have |loc<last|.
+
+\yskip\noindent(It may be necessary to prompt the user several times
+before a non-blank line comes in. The prompt is `\.{**}' instead of the
+later `\.*' because the meaning is slightly different: `\.{\\input}' need
+not be typed immediately after~`\.{**}'.)
+
+@d loc==cur_input.loc_field {location of first unread character in |buffer|}
+
+@ The following program does the required initialization.
+Iff anything has been specified on the command line, then |t_open_in|
+will return with |last > first|.
+@^system dependencies@>
+
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+begin t_open_in;
+if last > first then
+  begin loc := first;
+  while (loc < last) and (buffer[loc]=' ') do incr(loc);
+  if loc < last then
+    begin init_terminal := true; goto exit;
+    end;
+  end;
+loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
+@.**@>
+  if not input_ln(term_in,true) then {this shouldn't happen}
+    begin write_ln(term_out);
+    write_ln(term_out,'! End of file on the terminal... why?');
+@.End of file on the terminal@>
+    init_terminal:=false; return;
+    end;
+  loc:=first;
+  while (loc<last)and(buffer[loc]=" ") do incr(loc);
+  if loc<last then
+    begin init_terminal:=true;
+    return; {return unless the line was all blank}
+    end;
+  write_ln(term_out,'Please type the name of your input file.');
+  end;
+exit:end;
+
+@* \[4] String handling.
+Control sequence names and diagnostic messages are variable-length strings
+of eight-bit characters. Since \PASCAL\ does not have a well-developed string
+mechanism, \TeX\ does all of its string processing by homegrown methods.
+
+Elaborate facilities for dynamic strings are not needed, so all of the
+necessary operations can be handled with a simple data structure.
+The array |str_pool| contains all of the (eight-bit) ASCII codes in all
+of the strings, and the array |str_start| contains indices of the starting
+points of each string. Strings are referred to by integer numbers, so that
+string number |s| comprises the characters |str_pool[j]| for
+|str_start[s]<=j<str_start[s+1]|. Additional integer variables
+|pool_ptr| and |str_ptr| indicate the number of entries used so far
+in |str_pool| and |str_start|, respectively; locations
+|str_pool[pool_ptr]| and |str_start[str_ptr]| are
+ready for the next string to be allocated.
+
+String numbers 0 to 255 are reserved for strings that correspond to single
+ASCII characters. This is in accordance with the conventions of \.{WEB},
+@.WEB@>
+which converts single-character strings into the ASCII code number of the
+single character involved, while it converts other strings into integers
+and builds a string pool file. Thus, when the string constant \.{"."} appears
+in the program below, \.{WEB} converts it into the integer 46, which is the
+ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"}
+into some integer greater than~255. String number 46 will presumably be the
+single character `\..'; but some ASCII codes have no standard visible
+representation, and \TeX\ sometimes needs to be able to print an arbitrary
+ASCII character, so the first 256 strings are used to specify exactly what
+should be printed for each of the 256 possibilities.
+
+Elements of the |str_pool| array must be ASCII codes that can actually
+be printed; i.e., they must have an |xchr| equivalent in the local
+character set. (This restriction applies only to preloaded strings,
+not to those generated dynamically by the user.)
+
+Some \PASCAL\ compilers won't pack integers into a single byte unless the
+integers lie in the range |-128..127|. To accommodate such systems
+we access the string pool only via macros that can easily be redefined.
+@^system dependencies@>
+
+@d si(#) == # {convert from |ASCII_code| to |packed_ASCII_code|}
+@d so(#) == # {convert from |packed_ASCII_code| to |ASCII_code|}
+
+@<Types...@>=
+@!pool_pointer = integer; {for variables that point into |str_pool|}
+@!str_number = 0..ssup_max_strings; {for variables that point into |str_start|}
+@!packed_ASCII_code = 0..255; {elements of |str_pool| array}
+
+@ @<Glob...@>=
+@!str_pool: ^packed_ASCII_code; {the characters}
+@!str_start : ^pool_pointer; {the starting pointers}
+@!pool_ptr : pool_pointer; {first unused position in |str_pool|}
+@!str_ptr : str_number; {number of the current string being created}
+@!init_pool_ptr : pool_pointer; {the starting value of |pool_ptr|}
+@!init_str_ptr : str_number; {the starting value of |str_ptr|}
+
+@ Several of the elementary string operations are performed using \.{WEB}
+macros instead of \PASCAL\ procedures, because many of the
+operations are done quite frequently and we want to avoid the
+overhead of procedure calls. For example, here is
+a simple macro that computes the length of a string.
+@.WEB@>
+
+@d length(#)==(str_start[#+1]-str_start[#]) {the number of characters
+  in string number \#}
+
+@ The length of the current string is called |cur_length|:
+
+@d cur_length == (pool_ptr - str_start[str_ptr])
+
+@ Strings are created by appending character codes to |str_pool|.
+The |append_char| macro, defined here, does not check to see if the
+value of |pool_ptr| has gotten too high; this test is supposed to be
+made before |append_char| is used. There is also a |flush_char|
+macro, which erases the last character appended.
+
+To test if there is room to append |l| more characters to |str_pool|,
+we shall write |str_room(l)|, which aborts \TeX\ and gives an
+apologetic error message if there isn't enough room.
+
+@d append_char(#) == {put |ASCII_code| \# at the end of |str_pool|}
+begin str_pool[pool_ptr]:=si(#); incr(pool_ptr);
+end
+@d flush_char == decr(pool_ptr) {forget the last character in the pool}
+@d str_room(#) == {make sure that the pool hasn't overflowed}
+  begin if pool_ptr+# > pool_size then
+  overflow("pool size",pool_size-init_pool_ptr);
+@:TeX capacity exceeded pool size}{\quad pool size@>
+  end
+
+@ Once a sequence of characters has been appended to |str_pool|, it
+officially becomes a string when the function |make_string| is called.
+This function returns the identification number of the new string as its
+value.
+
+@p function make_string : str_number; {current string enters the pool}
+begin if str_ptr=max_strings then
+  overflow("number of strings",max_strings-init_str_ptr);
+@:TeX capacity exceeded number of strings}{\quad number of strings@>
+incr(str_ptr); str_start[str_ptr]:=pool_ptr;
+make_string:=str_ptr-1;
+end;
+
+@ To destroy the most recently made string, we say |flush_string|.
+
+@d flush_string==begin decr(str_ptr); pool_ptr:=str_start[str_ptr];
+  end
+
+@ The following subroutine compares string |s| with another string of the
+same length that appears in |buffer| starting at position |k|;
+the result is |true| if and only if the strings are equal.
+Empirical tests indicate that |str_eq_buf| is used in such a way that
+it tends to return |true| about 80 percent of the time.
+
+@p function str_eq_buf(@!s:str_number;@!k:integer):boolean;
+  {test equality of strings}
+label not_found; {loop exit}
+var j: pool_pointer; {running index}
+@!result: boolean; {result of comparison}
+begin j:=str_start[s];
+while j<str_start[s+1] do
+  begin if so(str_pool[j])<>buffer[k] then
+    begin result:=false; goto not_found;
+    end;
+  incr(j); incr(k);
+  end;
+result:=true;
+not_found: str_eq_buf:=result;
+end;
+
+@ Here is a similar routine, but it compares two strings in the string pool,
+and it does not assume that they have the same length.
+
+@p function str_eq_str(@!s,@!t:str_number):boolean;
+  {test equality of strings}
+label not_found; {loop exit}
+var j,@!k: pool_pointer; {running indices}
+@!result: boolean; {result of comparison}
+begin result:=false;
+if length(s)<>length(t) then goto not_found;
+j:=str_start[s]; k:=str_start[t];
+while j<str_start[s+1] do
+  begin if str_pool[j]<>str_pool[k] then goto not_found;
+  incr(j); incr(k);
+  end;
+result:=true;
+not_found: str_eq_str:=result;
+end;
+
+@ The initial values of |str_pool|, |str_start|, |pool_ptr|,
+and |str_ptr| are computed by the \.{INITEX} program, based in part
+on the information that \.{WEB} has output while processing \TeX.
+@.INITEX@>
+@^string pool@>
+
+@p @t\4@>@<Declare additional routines for string recycling@>@/
+
+@!init function get_strings_started:boolean; {initializes the string pool,
+  but returns |false| if something goes wrong}
+label done,exit;
+var k,@!l:KANJI_code; {small indices or counters}
+@!m,@!n:text_char; {characters input from |pool_file|}
+@!g:str_number; {garbage}
+@!a:integer; {accumulator for check sum}
+@!c:boolean; {check sum has been checked}
+begin pool_ptr:=0; str_ptr:=0; str_start[0]:=0;
+@<Make the first 256 strings@>;
+@<Read the other strings from the \.{TEX.POOL} file and return |true|,
+  or give an error message and return |false|@>;
+exit:end;
+tini
+
+@ @d app_lc_hex(#)==l:=#;
+  if l<10 then append_char(l+"0")@+else append_char(l-10+"a")
+
+@<Make the first 256...@>=
+for k:=0 to 255 do
+  begin if (@<Character |k| cannot be printed@>) then
+    begin append_char("^"); append_char("^");
+    if k<@'100 then append_char(k+@'100)
+    else if k<@'200 then append_char(k-@'100)
+    else begin app_lc_hex(k div 16); app_lc_hex(k mod 16);
+      end;
+    end
+  else append_char(k);
+  g:=make_string;
+  end
+
+@ The first 128 strings will contain 95 standard ASCII characters, and the
+other 33 characters will be printed in three-symbol form like `\.{\^\^A}'
+unless a system-dependent change is made here. Installations that have
+an extended character set, where for example |xchr[@'32]=@t\.{\'^^Z\'}@>|,
+would like string @'32 to be printed as the single character @'32
+instead of the
+three characters @'136, @'136, @'132 (\.{\^\^Z}). On the other hand,
+even people with an extended character set will want to represent string
+@'15 by \.{\^\^M}, since @'15 is |carriage_return|; the idea is to
+produce visible strings instead of tabs or line-feeds or carriage-returns
+or bell-rings or characters that are treated anomalously in text files.
+
+Unprintable characters of codes 128--255 are, similarly, rendered
+\.{\^\^80}--\.{\^\^ff}.
+
+The boolean expression defined here should be |true| unless \TeX\
+internal code number~|k| corresponds to a non-troublesome visible
+symbol in the local character set.  An appropriate formula for the
+extended character set recommended in {\sl The \TeX book\/} would, for
+example, be `|k in [0,@'10..@'12,@'14,@'15,@'33,@'177..@'377]|'.
+If character |k| cannot be printed, and |k<@'200|, then character |k+@'100| or
+|k-@'100| must be printable; moreover, ASCII codes |[@'41..@'46,
+@'60..@'71, @'136, @'141..@'146, @'160..@'171]| must be printable.
+Thus, at least 81 printable characters are needed.
+@:TeXbook}{\sl The \TeX book@>
+@^character set dependencies@>
+@^system dependencies@>
+
+@<Character |k| cannot be printed@>=
+   not (ismultiprn(k) or xprn[k])
+
+@ When the \.{WEB} system program called \.{TANGLE} processes the \.{TEX.WEB}
+description that you are now reading, it outputs the \PASCAL\ program
+\.{TEX.PAS} and also a string pool file called \.{TEX.POOL}. The \.{INITEX}
+@.WEB@>@.INITEX@>
+program reads the latter file, where each string appears as a two-digit decimal
+length followed by the string itself, and the information is recorded in
+\TeX's string memory.
+
+@<Glob...@>=
+@!init @!pool_file:alpha_file; {the string-pool file output by \.{TANGLE}}
+tini
+
+@ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#);
+  a_close(pool_file); get_strings_started:=false; return;
+  end
+@<Read the other strings...@>=
+name_length := strlen (pool_name);
+name_of_file := xmalloc_array (ASCII_code, name_length + 1);
+strcpy (stringcast(name_of_file+1), pool_name); {copy the string}
+if a_open_in (pool_file, kpse_texpool_format) then
+  begin c:=false;
+  repeat @<Read one string, but return |false| if the
+    string memory space is getting too tight for comfort@>;
+  until c;
+  a_close(pool_file); get_strings_started:=true;
+  end
+else  bad_pool('! I can''t read ', pool_name, '; bad path?')
+@.I can't read TEX.POOL@>
+
+@ @<Read one string...@>=
+begin if eof(pool_file) then bad_pool('! ', pool_name, ' has no check sum.');
+@.TEX.POOL has no check sum@>
+read(pool_file,m); read(pool_file,n); {read two digits of string length}
+if m='*' then @<Check the pool check sum@>
+else  begin if (xord[m]<"0")or(xord[m]>"9")or@|
+      (xord[n]<"0")or(xord[n]>"9") then
+    bad_pool('! ', pool_name, ' line doesn''t begin with two digits.');
+@.TEX.POOL line doesn't...@>
+  l:=xord[m]*10+xord[n]-"0"*11; {compute the length}
+  if pool_ptr+l+string_vacancies>pool_size then
+    bad_pool('! You have to increase POOLSIZE.');
+@.You have to increase POOLSIZE@>
+  for k:=1 to l do
+    begin if eoln(pool_file) then m:=' '@+else read(pool_file,m);
+    append_char(xord[m]);
+    end;
+  read_ln(pool_file); g:=make_string;
+  end;
+end
+
+@ The \.{WEB} operation \.{@@\$} denotes the value that should be at the
+end of this \.{TEX.POOL} file; any other value means that the wrong pool
+file has been loaded.
+@^check sum@>
+
+@<Check the pool check sum@>=
+begin a:=0; k:=1;
+loop@+  begin if (xord[n]<"0")or(xord[n]>"9") then
+  bad_pool('! ', pool_name, ' check sum doesn''t have nine digits.');
+@.TEX.POOL check sum...@>
+  a:=10*a+xord[n]-"0";
+  if k=9 then goto done;
+  incr(k); read(pool_file,n);
+  end;
+done: if a<>@$ then
+  bad_pool('! ', pool_name, ' doesn''t match; tangle me again (or fix the path).');
+@.TEX.POOL doesn't match@>
+c:=true;
+end
+
+@* \[5] On-line and off-line printing.
+Messages that are sent to a user's terminal and to the transcript-log file
+are produced by several `|print|' procedures. These procedures will
+direct their output to a variety of places, based on the setting of
+the global variable |selector|, which has the following possible
+values:
+
+\yskip
+\hang |term_and_log|, the normal setting, prints on the terminal and on the
+  transcript file.
+
+\hang |log_only|, prints only on the transcript file.
+
+\hang |term_only|, prints only on the terminal.
+
+\hang |no_print|, doesn't print at all. This is used only in rare cases
+  before the transcript file is open.
+
+\hang |pseudo|, puts output into a cyclic buffer that is used
+  by the |show_context| routine; when we get to that routine we shall discuss
+  the reasoning behind this curious mode.
+
+\hang |new_string|, appends the output to the current string in the
+  string pool.
+
+\hang 0 to 15, prints on one of the sixteen files for \.{\\write} output.
+
+\yskip
+\noindent The symbolic names `|term_and_log|', etc., have been assigned
+numeric codes that satisfy the convenient relations |no_print+1=term_only|,
+|no_print+2=log_only|, |term_only+2=log_only+1=term_and_log|.
+
+Three additional global variables, |tally| and |term_offset| and
+|file_offset|, record the number of characters that have been printed
+since they were most recently cleared to zero. We use |tally| to record
+the length of (possibly very long) stretches of printing; |term_offset|
+and |file_offset|, on the other hand, keep track of how many characters
+have appeared so far on the current line that has been output to the
+terminal or to the transcript file, respectively.
+
+@d no_print=16 {|selector| setting that makes data disappear}
+@d term_only=17 {printing is destined for the terminal only}
+@d log_only=18 {printing is destined for the transcript file only}
+@d term_and_log=19 {normal |selector| setting}
+@d pseudo=20 {special |selector| setting for |show_context|}
+@d new_string=21 {printing is deflected to the string pool}
+@d max_selector=21 {highest selector setting}
+
+@<Glob...@>=
+@!log_file : alpha_file; {transcript of \TeX\ session}
+@!selector : 0..max_selector; {where to print a message}
+@!dig : array[0..22] of 0..15; {digits in a number being output}
+@!tally : integer; {the number of characters recently printed}
+@!term_offset : 0..max_print_line;
+  {the number of characters on the current terminal line}
+@!file_offset : 0..max_print_line;
+  {the number of characters on the current file line}
+@!trick_buf:array[0..ssup_error_line] of ASCII_code; {circular buffer for
+  pseudoprinting}
+@!trick_buf2:array[0..ssup_error_line] of 0..2; {pTeX: buffer for KANJI}
+@!kcode_pos: 0..2; {pTeX: denotes whether first byte or second byte of KANJI}
+@!prev_char: ASCII_code;
+@!trick_count: integer; {threshold for pseudoprinting, explained later}
+@!first_count: integer; {another variable for pseudoprinting}
+
+@ @<Initialize the output routines@>=
+selector:=term_only; tally:=0; term_offset:=0; file_offset:=0;
+kcode_pos:=0;
+
+@ Macro abbreviations for output to the terminal and to the log file are
+defined here for convenience. Some systems need special conventions
+for terminal output, and it is possible to adhere to those conventions
+by changing |wterm|, |wterm_ln|, and |wterm_cr| in this section.
+@^system dependencies@>
+
+@d wterm(#)==write(term_out,#)
+@d wterm_ln(#)==write_ln(term_out,#)
+@d wterm_cr==write_ln(term_out)
+@d wlog(#)==write(log_file,#)
+@d wlog_ln(#)==write_ln(log_file,#)
+@d wlog_cr==write_ln(log_file)
+
+@ To end a line of text output, we call |print_ln|.
+
+@<Basic print...@>=
+procedure print_ln; {prints an end-of-line}
+begin case selector of
+term_and_log: begin
+  if kcode_pos=1 then begin wterm(' '); wlog(' '); end;
+  wterm_cr; wlog_cr; term_offset:=0; file_offset:=0;
+  end;
+log_only: begin if kcode_pos=1 then wlog(' ');
+  wlog_cr; file_offset:=0;
+  end;
+term_only: begin if kcode_pos=1 then wterm(' ');
+  wterm_cr; term_offset:=0;
+  end;
+no_print,pseudo,new_string: do_nothing;
+othercases write_ln(write_file[selector])
+endcases;@/
+kcode_pos:=0;
+end; {|tally| is not affected}
+
+@ The |print_char| procedure sends one character to the desired destination,
+using the |xchr| array to map it into an external character compatible with
+|input_ln|. All printing comes through |print_ln| or |print_char|.
+
+@<Basic printing...@>=
+procedure print_char(@!s:ASCII_code); {prints a single character}
+label exit; {label is not used but nonetheless kept (for other changes?)}
+begin if @<Character |s| is the current new-line character@> then
+ if selector<pseudo then
+  begin print_ln; return;
+  end;
+if kcode_pos=1 then kcode_pos:=2
+else if iskanji1(xchr[s]) then
+  begin kcode_pos:=1;
+  if (selector=term_and_log)or(selector=log_only) then
+    if file_offset>=max_print_line-1 then
+       begin wlog_cr; file_offset:=0;
+       end;
+  if (selector=term_and_log)or(selector=term_only) then
+    if term_offset>=max_print_line-1 then
+       begin wterm_cr; term_offset:=0;
+       end;
+  end
+else kcode_pos:=0;
+case selector of
+term_and_log: begin wterm(xchr[s]); incr(term_offset);
+  if term_offset=max_print_line then
+    begin wterm_cr; term_offset:=0;
+    end;
+  wlog(xchr[s]); incr(file_offset);
+  if file_offset=max_print_line then
+    begin wlog_cr; file_offset:=0;
+    end;
+  end;
+log_only: begin wlog(xchr[s]); incr(file_offset);
+  if file_offset=max_print_line then print_ln;
+  end;
+term_only: begin wterm(xchr[s]); incr(term_offset);
+  if term_offset=max_print_line then print_ln;
+  end;
+no_print: do_nothing;
+pseudo: if tally<trick_count then
+  begin trick_buf[tally mod error_line]:=s;
+  trick_buf2[tally mod error_line]:=kcode_pos;
+  end;
+new_string: begin if pool_ptr<pool_size then append_char(s);
+  end; {we drop characters if the string space is full}
+othercases write(write_file[selector],xchr[s])
+endcases;@/
+incr(tally);
+exit:end;
+
+@ An entire string is output by calling |print|. Note that if we are outputting
+the single standard ASCII character \.c, we could call |print("c")|, since
+|"c"=99| is the number of a single-character string, as explained above. But
+|print_char("c")| is quicker, so \TeX\ goes directly to the |print_char|
+routine when it knows that this is safe. (The present implementation
+assumes that it is always safe to print a visible ASCII character.)
+@^system dependencies@>
+
+@<Basic print...@>=
+procedure print(@!s:integer); {prints string |s|}
+label exit;
+var j:pool_pointer; {current character code position}
+@!nl:integer; {new-line character to restore}
+begin if s>=str_ptr then s:="???" {this can't happen}
+@.???@>
+else if s<256 then
+  if s<0 then s:="???" {can't happen}
+  else begin if selector>pseudo then
+      begin print_char(s); return; {internal strings are not expanded}
+      end;
+    if (@<Character |s| is the current new-line character@>) then
+      if selector<pseudo then
+        begin print_ln; return;
+        end;
+    nl:=new_line_char; new_line_char:=-1;
+      {temporarily disable new-line character}
+    j:=str_start[s];
+    while j<str_start[s+1] do
+      begin print_char(so(str_pool[j])); incr(j);
+      end;
+    new_line_char:=nl; return;
+    end;
+j:=str_start[s];
+while j<str_start[s+1] do
+  begin print_char(so(str_pool[j])); incr(j);
+  end;
+exit:end;
+
+@ Control sequence names, file names, and strings constructed with
+\.{\\string} might contain |ASCII_code| values that can't
+be printed using |print_char|. Therefore we use |slow_print| for them:
+
+@<Basic print...@>=
+procedure slow_print(@!s:integer); {prints string |s|}
+var j:pool_pointer; {current character code position}
+begin if (s>=str_ptr) or (s<256) then print(s)
+else begin j:=str_start[s];
+  while j<str_start[s+1] do
+    begin print(so(str_pool[j])); incr(j);
+    end;
+  end;
+end;
+
+@ Here is the very first thing that \TeX\ prints: a headline that identifies
+the version number and format package. The |term_offset| variable is temporarily
+incorrect, but the discrepancy is not serious since we assume that the banner
+and format identifier together will occupy at most |max_print_line|
+character positions.
+
+@<Initialize the output...@>=
+if src_specials_p or file_line_error_style_p or parse_first_line_p then
+  wterm(banner_k)
+else
+  wterm(banner);
+  wterm(' (');
+  wterm(conststringcast(get_enc_string));
+  wterm(')');
+wterm(version_string);
+if format_ident>0 then slow_print(format_ident);
+print_ln;
+if shellenabledp then begin
+  wterm(' ');
+  if restrictedshell then begin
+    wterm('restricted ');
+  end;
+  wterm_ln('\write18 enabled.');
+end;
+if src_specials_p then begin
+  wterm_ln(' Source specials enabled.')
+end;
+if translate_filename then begin
+  wterm(' (');
+  fputs(translate_filename, stdout);
+  wterm_ln(')');
+end;
+update_terminal;
+
+@ The procedure |print_nl| is like |print|, but it makes sure that the
+string appears at the beginning of a new line.
+
+@<Basic print...@>=
+procedure print_nl(@!s:str_number); {prints string |s| at beginning of line}
+begin if ((term_offset>0)and(odd(selector)))or@|
+  ((file_offset>0)and(selector>=log_only)) then print_ln;
+print(s);
+end;
+
+@ The procedure |print_esc| prints a string that is preceded by
+the user's escape character (which is usually a backslash).
+
+@<Basic print...@>=
+procedure print_esc(@!s:str_number); {prints escape character, then |s|}
+var c:integer; {the escape character code}
+begin  @<Set variable |c| to the current escape character@>;
+if c>=0 then if c<256 then print(c);
+slow_print(s);
+end;
+
+@ An array of digits in the range |0..15| is printed by |print_the_digs|.
+
+@<Basic print...@>=
+procedure print_the_digs(@!k:eight_bits);
+  {prints |dig[k-1]|$\,\ldots\,$|dig[0]|}
+begin while k>0 do
+  begin decr(k);
+  if dig[k]<10 then print_char("0"+dig[k])
+  else print_char("A"-10+dig[k]);
+  end;
+end;
+
+@ The following procedure, which prints out the decimal representation of a
+given integer |n|, has been written carefully so that it works properly
+if |n=0| or if |(-n)| would cause overflow. It does not apply |mod| or |div|
+to negative arguments, since such operations are not implemented consistently
+by all \PASCAL\ compilers.
+
+@<Basic print...@>=
+procedure print_int(@!n:integer); {prints an integer in decimal form}
+var k:0..23; {index to current digit; we assume that $|n|<10^{23}$}
+@!m:integer; {used to negate |n| in possibly dangerous cases}
+begin k:=0;
+if n<0 then
+  begin print_char("-");
+  if n>-100000000 then negate(n)
+  else  begin m:=-1-n; n:=m div 10; m:=(m mod 10)+1; k:=1;
+    if m<10 then dig[0]:=m
+    else  begin dig[0]:=0; incr(n);
+      end;
+    end;
+  end;
+repeat dig[k]:=n mod 10; n:=n div 10; incr(k);
+until n=0;
+print_the_digs(k);
+end;
+
+@ Here is a trivial procedure to print two digits; it is usually called with
+a parameter in the range |0<=n<=99|.
+
+@p procedure print_two(@!n:integer); {prints two least significant digits}
+begin n:=abs(n) mod 100; print_char("0"+(n div 10));
+print_char("0"+(n mod 10));
+end;
+
+@ Hexadecimal printing of nonnegative integers is accomplished by |print_hex|.
+
+@p procedure print_hex(@!n:integer);
+  {prints a positive integer in hexadecimal form}
+var k:0..22; {index to current digit; we assume that $0\L n<16^{22}$}
+begin k:=0; print_char("""");
+repeat dig[k]:=n mod 16; n:=n div 16; incr(k);
+until n=0;
+print_the_digs(k);
+end;
+
+@ Old versions of \TeX\ needed a procedure called |print_ASCII| whose function
+is now subsumed by |print|. We retain the old name here as a possible aid to
+future software arch\ae ologists.
+
+@d print_ASCII == print
+
+@ Roman numerals are produced by the |print_roman_int| routine.  Readers
+who like puzzles might enjoy trying to figure out how this tricky code
+works; therefore no explanation will be given. Notice that 1990 yields
+\.{mcmxc}, not \.{mxm}.
+
+@p procedure print_roman_int(@!n:integer);
+label exit;
+var j,@!k: pool_pointer; {mysterious indices into |str_pool|}
+@!u,@!v: nonnegative_integer; {mysterious numbers}
+begin j:=str_start["m2d5c2l5x2v5i"]; v:=1000;
+loop@+  begin while n>=v do
+    begin print_char(so(str_pool[j])); n:=n-v;
+    end;
+  if n<=0 then return; {nonpositive input produces no output}
+  k:=j+2; u:=v div (so(str_pool[k-1])-"0");
+  if str_pool[k-1]=si("2") then
+    begin k:=k+2; u:=u div (so(str_pool[k-1])-"0");
+    end;
+  if n+u>=v then
+    begin print_char(so(str_pool[k])); n:=n+u;
+    end
+  else  begin j:=j+2; v:=v div (so(str_pool[j-1])-"0");
+    end;
+  end;
+exit:end;
+
+@ The |print| subroutine will not print a string that is still being
+created. The following procedure will.
+
+@p procedure print_current_string; {prints a yet-unmade string}
+var j:pool_pointer; {points to current character code}
+begin j:=str_start[str_ptr];
+while j<pool_ptr do
+  begin print_char(so(str_pool[j])); incr(j);
+  end;
+end;
+
+@ Here is a procedure that asks the user to type a line of input,
+assuming that the |selector| setting is either |term_only| or |term_and_log|.
+The input is placed into locations |first| through |last-1| of the
+|buffer| array, and echoed on the transcript file if appropriate.
+
+This procedure is never called when |interaction<scroll_mode|.
+
+@d prompt_input(#)==begin wake_up_terminal; print(#); term_input;
+    end {prints a string and gets a line of input}
+
+@p procedure term_input; {gets a line from the terminal}
+var k:0..buf_size; {index into |buffer|}
+begin update_terminal; {now the user sees the prompt for sure}
+if not input_ln(term_in,true) then fatal_error("End of file on the terminal!");
+@.End of file on the terminal@>
+term_offset:=0; {the user's line ended with \<\rm return>}
+decr(selector); {prepare to echo the input}
+if last<>first then for k:=first to last-1 do print(buffer[k]);
+print_ln; incr(selector); {restore previous status}
+end;
+
+@* \[6] Reporting errors.
+When something anomalous is detected, \TeX\ typically does something like this:
+$$\vbox{\halign{#\hfil\cr
+|print_err("Something anomalous has been detected");|\cr
+|help3("This is the first line of my offer to help.")|\cr
+|("This is the second line. I'm trying to")|\cr
+|("explain the best way for you to proceed.");|\cr
+|error;|\cr}}$$
+A two-line help message would be given using |help2|, etc.; these informal
+helps should use simple vocabulary that complements the words used in the
+official error message that was printed. (Outside the U.S.A., the help
+messages should preferably be translated into the local vernacular. Each
+line of help is at most 60 characters long, in the present implementation,
+so that |max_print_line| will not be exceeded.)
+
+The |print_err| procedure supplies a `\.!' before the official message,
+and makes sure that the terminal is awake if a stop is going to occur.
+The |error| procedure supplies a `\..' after the official message, then it
+shows the location of the error; and if |interaction=error_stop_mode|,
+it also enters into a dialog with the user, during which time the help
+message may be printed.
+@^system dependencies@>
+
+@ The global variable |interaction| has four settings, representing increasing
+amounts of user interaction:
+
+@d batch_mode=0 {omits all stops and omits terminal output}
+@d nonstop_mode=1 {omits all stops}
+@d scroll_mode=2 {omits error stops}
+@d error_stop_mode=3 {stops at every opportunity to interact}
+@d unspecified_mode=4 {extra value for command-line switch}
+@d print_err(#)==begin if interaction=error_stop_mode then wake_up_terminal;
+  if file_line_error_style_p then print_file_line
+  else print_nl("! ");
+  print(#);
+  end
+
+@<Glob...@>=
+@!interaction:batch_mode..error_stop_mode; {current level of interaction}
+@!interaction_option:batch_mode..unspecified_mode; {set from command line}
+
+@ @<Set init...@>=if interaction_option=unspecified_mode then
+  interaction:=error_stop_mode
+else
+  interaction:=interaction_option;
+
+@ \TeX\ is careful not to call |error| when the print |selector| setting
+might be unusual. The only possible values of |selector| at the time of
+error messages are
+
+\yskip\hang|no_print| (when |interaction=batch_mode|
+  and |log_file| not yet open);
+
+\hang|term_only| (when |interaction>batch_mode| and |log_file| not yet open);
+
+\hang|log_only| (when |interaction=batch_mode| and |log_file| is open);
+
+\hang|term_and_log| (when |interaction>batch_mode| and |log_file| is open).
+
+@<Initialize the print |selector| based on |interaction|@>=
+if interaction=batch_mode then selector:=no_print@+else selector:=term_only
+
+@ A global variable |deletions_allowed| is set |false| if the |get_next|
+routine is active when |error| is called; this ensures that |get_next|
+and related routines like |get_token| will never be called recursively.
+A similar interlock is provided by |set_box_allowed|.
+@^recursion@>
+
+The global variable |history| records the worst level of error that
+has been detected. It has four possible values: |spotless|, |warning_issued|,
+|error_message_issued|, and |fatal_error_stop|.
+
+Another global variable, |error_count|, is increased by one when an
+|error| occurs without an interactive dialog, and it is reset to zero at
+the end of every paragraph.  If |error_count| reaches 100, \TeX\ decides
+that there is no point in continuing further.
+
+@d spotless=0 {|history| value when nothing has been amiss yet}
+@d warning_issued=1 {|history| value when |begin_diagnostic| has been called}
+@d error_message_issued=2 {|history| value when |error| has been called}
+@d fatal_error_stop=3 {|history| value when termination was premature}
+
+@<Glob...@>=
+@!deletions_allowed:boolean; {is it safe for |error| to call |get_token|?}
+@!set_box_allowed:boolean; {is it safe to do a \.{\\setbox} assignment?}
+@!history:spotless..fatal_error_stop; {has the source input been clean so far?}
+@!error_count:-1..100; {the number of scrolled errors since the
+  last paragraph ended}
+
+@ The value of |history| is initially |fatal_error_stop|, but it will
+be changed to |spotless| if \TeX\ survives the initialization process.
+
+@<Set init...@>=
+deletions_allowed:=true; set_box_allowed:=true;
+error_count:=0; {|history| is initialized elsewhere}
+
+@ Since errors can be detected almost anywhere in \TeX, we want to declare the
+error procedures near the beginning of the program. But the error procedures
+in turn use some other procedures, which need to be declared |forward|
+before we get to |error| itself.
+
+It is possible for |error| to be called recursively if some error arises
+when |get_token| is being used to delete a token, and/or if some fatal error
+occurs while \TeX\ is trying to fix a non-fatal one. But such recursion
+@^recursion@>
+is never more than two levels deep.
+
+@<Error handling...@>=
+procedure@?normalize_selector; forward;@t\2@>@/
+procedure@?get_token; forward;@t\2@>@/
+procedure@?term_input; forward;@t\2@>@/
+procedure@?show_context; forward;@t\2@>@/
+procedure@?begin_file_reading; forward;@t\2@>@/
+procedure@?open_log_file; forward;@t\2@>@/
+procedure@?close_files_and_terminate; forward;@t\2@>@/
+procedure@?clear_for_error_prompt; forward;@t\2@>@/
+procedure@?give_err_help; forward;@t\2@>@/
+@t\4\hskip-\fontdimen2\font@>@;@+@!debug@+procedure@?debug_help;
+  forward;@;@+gubed
+
+@ Individual lines of help are recorded in the array |help_line|, which
+contains entries in positions |0..(help_ptr-1)|. They should be printed
+in reverse order, i.e., with |help_line[0]| appearing last.
+
+@d hlp1(#)==help_line[0]:=#;@+end
+@d hlp2(#)==help_line[1]:=#; hlp1
+@d hlp3(#)==help_line[2]:=#; hlp2
+@d hlp4(#)==help_line[3]:=#; hlp3
+@d hlp5(#)==help_line[4]:=#; hlp4
+@d hlp6(#)==help_line[5]:=#; hlp5
+@d help0==help_ptr:=0 {sometimes there might be no help}
+@d help1==@+begin help_ptr:=1; hlp1 {use this with one help line}
+@d help2==@+begin help_ptr:=2; hlp2 {use this with two help lines}
+@d help3==@+begin help_ptr:=3; hlp3 {use this with three help lines}
+@d help4==@+begin help_ptr:=4; hlp4 {use this with four help lines}
+@d help5==@+begin help_ptr:=5; hlp5 {use this with five help lines}
+@d help6==@+begin help_ptr:=6; hlp6 {use this with six help lines}
+
+@<Glob...@>=
+@!help_line:array[0..5] of str_number; {helps for the next |error|}
+@!help_ptr:0..6; {the number of help lines present}
+@!use_err_help:boolean; {should the |err_help| list be shown?}
+
+@ @<Set init...@>=
+help_ptr:=0; use_err_help:=false;
+
+@ The |jump_out| procedure just cuts across all active procedure levels and
+goes to |end_of_TEX|. This is the only nontrivial |@!goto| statement in the
+whole program. It is used when there is no recovery from a particular error.
+
+Some \PASCAL\ compilers do not implement non-local |goto| statements.
+@^system dependencies@>
+In such cases the body of |jump_out| should simply be
+`|close_files_and_terminate|;\thinspace' followed by a call on some system
+procedure that quietly terminates the program.
+
+@d do_final_end==begin
+   update_terminal;
+   ready_already:=0;
+   if (history <> spotless) and (history <> warning_issued) then
+       uexit(1)
+   else
+       uexit(0);
+   end
+
+@<Error hand...@>=
+noreturn procedure jump_out;
+begin
+close_files_and_terminate;
+do_final_end;
+end;
+
+@ Here now is the general |error| routine.
+
+@<Error hand...@>=
+procedure error; {completes the job of error reporting}
+label continue,exit;
+var c:ASCII_code; {what the user types}
+@!s1,@!s2,@!s3,@!s4:integer;
+  {used to save global variables when deleting tokens}
+begin if history<error_message_issued then history:=error_message_issued;
+print_char("."); show_context;
+if (halt_on_error_p) then begin
+  history:=fatal_error_stop; jump_out;
+end;
+if interaction=error_stop_mode then @<Get user's advice and |return|@>;
+incr(error_count);
+if error_count=100 then
+  begin print_nl("(That makes 100 errors; please try again.)");
+@.That makes 100 errors...@>
+  history:=fatal_error_stop; jump_out;
+  end;
+@<Put help message on the transcript file@>;
+exit:end;
+
+@ @<Get user's advice...@>=
+loop@+begin continue: clear_for_error_prompt; prompt_input("? ");
+@.?\relax@>
+  if last=first then return;
+  c:=buffer[first];
+  if c>="a" then c:=c+"A"-"a"; {convert to uppercase}
+  @<Interpret code |c| and |return| if done@>;
+  end
+
+@ It is desirable to provide an `\.E' option here that gives the user
+an easy way to return from \TeX\ to the system editor, with the offending
+line ready to be edited.
+We do this by calling the external procedure |call_edit| with a pointer to
+the filename, its length, and the line number.
+However, here we just set up the variables that will be used as arguments,
+since we don't want to do the switch-to-editor until after TeX has closed
+its files.
+@^system dependencies@>
+
+There is a secret `\.D' option available when the debugging routines haven't
+been commented~out.
+@^debugging@>
+@d edit_file==input_stack[base_ptr]
+
+@<Interpret code |c| and |return| if done@>=
+case c of
+"0","1","2","3","4","5","6","7","8","9": if deletions_allowed then
+  @<Delete \(c)|c-"0"| tokens and |goto continue|@>;
+@t\4\4@>@;@+@!debug "D": begin debug_help; goto continue;@+end;@+gubed@/
+"E": if base_ptr>0 then
+    begin edit_name_start:=str_start[edit_file.name_field];
+    edit_name_length:=str_start[edit_file.name_field+1] -
+                      str_start[edit_file.name_field];
+    edit_line:=line;
+    jump_out;
+  end;
+"H": @<Print the help information and |goto continue|@>;
+"I":@<Introduce new material from the terminal and |return|@>;
+"Q","R","S":@<Change the interaction level and |return|@>;
+"X":begin interaction:=scroll_mode; jump_out;
+  end;
+othercases do_nothing
+endcases;@/
+@<Print the menu of available options@>
+
+@ @<Print the menu...@>=
+begin print("Type <return> to proceed, S to scroll future error messages,");@/
+@.Type <return> to proceed...@>
+print_nl("R to run without stopping, Q to run quietly,");@/
+print_nl("I to insert something, ");
+if base_ptr>0 then print("E to edit your file,");
+if deletions_allowed then
+  print_nl("1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
+print_nl("H for help, X to quit.");
+end
+
+@ Here the author of \TeX\ apologizes for making use of the numerical
+relation between |"Q"|, |"R"|, |"S"|, and the desired interaction settings
+|batch_mode|, |nonstop_mode|, |scroll_mode|.
+@^Knuth, Donald Ervin@>
+
+@<Change the interaction...@>=
+begin error_count:=0; interaction:=batch_mode+c-"Q";
+print("OK, entering ");
+case c of
+"Q":begin print_esc("batchmode"); decr(selector);
+  end;
+"R":print_esc("nonstopmode");
+"S":print_esc("scrollmode");
+end; {there are no other cases}
+print("..."); print_ln; update_terminal; return;
+end
+
+@ When the following code is executed, |buffer[(first+1)..(last-1)]| may
+contain the material inserted by the user; otherwise another prompt will
+be given. In order to understand this part of the program fully, you need
+to be familiar with \TeX's input stacks.
+
+@<Introduce new material...@>=
+begin begin_file_reading; {enter a new syntactic level for terminal input}
+{now |state=mid_line|, so an initial blank space will count as a blank}
+if last>first+1 then
+  begin loc:=first+1; buffer[first]:=" ";
+  end
+else  begin prompt_input("insert>"); loc:=first;
+@.insert>@>
+  end;
+first:=last;
+cur_input.limit_field:=last-1; {no |end_line_char| ends this line}
+return;
+end
+
+@ We allow deletion of up to 99 tokens at a time.
+
+@<Delete \(c)|c-"0"| tokens...@>=
+begin s1:=cur_tok; s2:=cur_cmd; s3:=cur_chr; s4:=align_state;
+align_state:=1000000; OK_to_interrupt:=false;
+if (last>first+1) and (buffer[first+1]>="0")and(buffer[first+1]<="9") then
+  c:=c*10+buffer[first+1]-"0"*11
+else c:=c-"0";
+while c>0 do
+  begin get_token; {one-level recursive call of |error| is possible}
+  decr(c);
+  end;
+cur_tok:=s1; cur_cmd:=s2; cur_chr:=s3; align_state:=s4; OK_to_interrupt:=true;
+help2("I have just deleted some text, as you asked.")@/
+("You can now delete more, or insert, or whatever.");
+show_context; goto continue;
+end
+
+@ @<Print the help info...@>=
+begin if use_err_help then
+  begin give_err_help; use_err_help:=false;
+  end
+else  begin if help_ptr=0 then
+    help2("Sorry, I don't know how to help in this situation.")@/
+    @t\kern1em@>("Maybe you should try asking a human?");
+  repeat decr(help_ptr); print(help_line[help_ptr]); print_ln;
+  until help_ptr=0;
+  end;
+help4("Sorry, I already gave what help I could...")@/
+  ("Maybe you should try asking a human?")@/
+  ("An error might have occurred before I noticed any problems.")@/
+  ("``If all else fails, read the instructions.''");@/
+goto continue;
+end
+
+@ @<Put help message on the transcript file@>=
+if interaction>batch_mode then decr(selector); {avoid terminal output}
+if use_err_help then
+  begin print_ln; give_err_help;
+  end
+else while help_ptr>0 do
+  begin decr(help_ptr); print_nl(help_line[help_ptr]);
+  end;
+print_ln;
+if interaction>batch_mode then incr(selector); {re-enable terminal output}
+print_ln
+
+@ A dozen or so error messages end with a parenthesized integer, so we
+save a teeny bit of program space by declaring the following procedure:
+
+@p procedure int_error(@!n:integer);
+begin print(" ("); print_int(n); print_char(")"); error;
+end;
+
+@ In anomalous cases, the print selector might be in an unknown state;
+the following subroutine is called to fix things just enough to keep
+running a bit longer.
+
+@p procedure normalize_selector;
+begin if log_opened then selector:=term_and_log
+else selector:=term_only;
+if job_name=0 then open_log_file;
+if interaction=batch_mode then decr(selector);
+end;
+
+@ The following procedure prints \TeX's last words before dying.
+
+@d succumb==begin if interaction=error_stop_mode then
+    interaction:=scroll_mode; {no more interaction}
+  if log_opened then error;
+  @!debug if interaction>batch_mode then debug_help;@+gubed@;@/
+  history:=fatal_error_stop; jump_out; {irrecoverable error}
+  end
+
+@<Error hand...@>=
+noreturn procedure fatal_error(@!s:str_number); {prints |s|, and that's it}
+begin normalize_selector;@/
+print_err("Emergency stop"); help1(s); succumb;
+@.Emergency stop@>
+end;
+
+@ Here is the most dreaded error message.
+
+@<Error hand...@>=
+noreturn procedure overflow(@!s:str_number;@!n:integer); {stop due to finiteness}
+begin normalize_selector;
+print_err("TeX capacity exceeded, sorry [");
+@.TeX capacity exceeded ...@>
+print(s); print_char("="); print_int(n); print_char("]");
+help2("If you really absolutely need more capacity,")@/
+  ("you can ask a wizard to enlarge me.");
+succumb;
+end;
+
+@ The program might sometime run completely amok, at which point there is
+no choice but to stop. If no previous error has been detected, that's bad
+news; a message is printed that is really intended for the \TeX\
+maintenance person instead of the user (unless the user has been
+particularly diabolical).  The index entries for `this can't happen' may
+help to pinpoint the problem.
+@^dry rot@>
+
+@<Error hand...@>=
+noreturn procedure confusion(@!s:str_number);
+  {consistency check violated; |s| tells where}
+begin normalize_selector;
+if history<error_message_issued then
+  begin print_err("This can't happen ("); print(s); print_char(")");
+@.This can't happen@>
+  help1("I'm broken. Please show this to someone who can fix can fix");
+  end
+else  begin print_err("I can't go on meeting you like this");
+@.I can't go on...@>
+  help2("One of your faux pas seems to have wounded me deeply...")@/
+    ("in fact, I'm barely conscious. Please fix it and try again.");
+  end;
+succumb;
+end;
+
+@ Users occasionally want to interrupt \TeX\ while it's running.
+If the \PASCAL\ runtime system allows this, one can implement
+a routine that sets the global variable |interrupt| to some nonzero value
+when such an interrupt is signalled. Otherwise there is probably at least
+a way to make |interrupt| nonzero using the \PASCAL\ debugger.
+@^system dependencies@>
+@^debugging@>
+
+@d check_interrupt==begin if interrupt<>0 then pause_for_instructions;
+  end
+
+@<Global...@>=
+@!interrupt:integer; {should \TeX\ pause for instructions?}
+@!OK_to_interrupt:boolean; {should interrupts be observed?}
+
+@ @<Set init...@>=
+interrupt:=0; OK_to_interrupt:=true;
+
+@ When an interrupt has been detected, the program goes into its
+highest interaction level and lets the user have nearly the full flexibility of
+the |error| routine.  \TeX\ checks for interrupts only at times when it is
+safe to do this.
+
+@p procedure pause_for_instructions;
+begin if OK_to_interrupt then
+  begin interaction:=error_stop_mode;
+  if (selector=log_only)or(selector=no_print) then
+    incr(selector);
+  print_err("Interruption");
+@.Interruption@>
+  help3("You rang?")@/
+  ("Try to insert some instructions for me (e.g.,`I\showlists'),")@/
+  ("unless you just want to quit by typing `X'.");
+  deletions_allowed:=false; error; deletions_allowed:=true;
+  interrupt:=0;
+  end;
+end;
+
+@* \[7] Arithmetic with scaled dimensions.
+The principal computations performed by \TeX\ are done entirely in terms of
+integers less than $2^{31}$ in magnitude; and divisions are done only when both
+dividend and divisor are nonnegative. Thus, the arithmetic specified in this
+program can be carried out in exactly the same way on a wide variety of
+computers, including some small ones. Why? Because the arithmetic
+calculations need to be spelled out precisely in order to guarantee that
+\TeX\ will produce identical output on different machines. If some
+quantities were rounded differently in different implementations, we would
+find that line breaks and even page breaks might occur in different places.
+Hence the arithmetic of \TeX\ has been designed with care, and systems that
+claim to be implementations of \TeX82 should follow precisely the
+@:TeX82}{\TeX82@>
+calculations as they appear in the present program.
+
+(Actually there are three places where \TeX\ uses |div| with a possibly negative
+numerator. These are harmless; see |div| in the index. Also if the user
+sets the \.{\\time} or the \.{\\year} to a negative value, some diagnostic
+information will involve negative-numerator division. The same remarks
+apply for |mod| as well as for |div|.)
+
+@ Here is a routine that calculates half of an integer, using an
+unambiguous convention with respect to signed odd numbers.
+
+@p function half(@!x:integer):integer;
+begin if odd(x) then half:=(x+1) div 2
+else half:=x @!div 2;
+end;
+
+@ Fixed-point arithmetic is done on {\sl scaled integers\/} that are multiples
+of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit
+positions from the right end of a binary computer word.
+
+@d unity == @'200000 {$2^{16}$, represents 1.00000}
+@d two == @'400000 {$2^{17}$, represents 2.00000}
+
+@<Types...@>=
+@!scaled = integer; {this type is used for scaled integers}
+@!nonnegative_integer=0..@'17777777777; {$0\L x<2^{31}$}
+@!small_number=0..63; {this type is self-explanatory}
+
+@ The following function is used to create a scaled integer from a given decimal
+fraction $(.d_0d_1\ldots d_{k-1})$, where |0<=k<=17|. The digit $d_i$ is
+given in |dig[i]|, and the calculation produces a correctly rounded result.
+
+@p function round_decimals(@!k:small_number) : scaled;
+  {converts a decimal fraction}
+var a:integer; {the accumulator}
+begin a:=0;
+while k>0 do
+  begin decr(k); a:=(a+dig[k]*two) div 10;
+  end;
+round_decimals:=(a+1) div 2;
+end;
+
+@ Conversely, here is a procedure analogous to |print_int|. If the output
+of this procedure is subsequently read by \TeX\ and converted by the
+|round_decimals| routine above, it turns out that the original value will
+be reproduced exactly; the ``simplest'' such decimal number is output,
+but there is always at least one digit following the decimal point.
+
+The invariant relation in the \&{repeat} loop is that a sequence of
+decimal digits yet to be printed will yield the original number if and only if
+they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$.
+We can stop if and only if $f=0$ satisfies this condition; the loop will
+terminate before $s$ can possibly become zero.
+
+@p procedure print_scaled(@!s:scaled); {prints scaled real, rounded to five
+  digits}
+var delta:scaled; {amount of allowable inaccuracy}
+begin if s<0 then
+  begin print_char("-"); negate(s); {print the sign, if negative}
+  end;
+print_int(s div unity); {print the integer part}
+print_char(".");
+s:=10*(s mod unity)+5; delta:=10;
+repeat if delta>unity then s:=s+@'100000-50000; {round the last digit}
+print_char("0"+(s div unity)); s:=10*(s mod unity); delta:=delta*10;
+until s<=delta;
+end;
+
+@ Physical sizes that a \TeX\ user specifies for portions of documents are
+represented internally as scaled points. Thus, if we define an `sp' (scaled
+@^sp@>
+point) as a unit equal to $2^{-16}$ printer's points, every dimension
+inside of \TeX\ is an integer number of sp. There are exactly
+4,736,286.72 sp per inch.  Users are not allowed to specify dimensions
+larger than $2^{30}-1$ sp, which is a distance of about 18.892 feet (5.7583
+meters); two such quantities can be added without overflow on a 32-bit
+computer.
+
+The present implementation of \TeX\ does not check for overflow when
+@^overflow in arithmetic@>
+dimensions are added or subtracted. This could be done by inserting a
+few dozen tests of the form `\ignorespaces|if x>=@'10000000000 then
+@t\\{report\_overflow}@>|', but the chance of overflow is so remote that
+such tests do not seem worthwhile.
+
+\TeX\ needs to do only a few arithmetic operations on scaled quantities,
+other than addition and subtraction, and the following subroutines do most of
+the work. A single computation might use several subroutine calls, and it is
+desirable to avoid producing multiple error messages in case of arithmetic
+overflow; so the routines set the global variable |arith_error| to |true|
+instead of reporting errors directly to the user. Another global variable,
+|remainder|, holds the remainder after a division.
+
+@d remainder==tex_remainder
+
+@<Glob...@>=
+@!arith_error:boolean; {has arithmetic overflow occurred recently?}
+@!remainder:scaled; {amount subtracted to get an exact division}
+
+@ The first arithmetical subroutine we need computes $nx+y$, where |x|
+and~|y| are |scaled| and |n| is an integer. We will also use it to
+multiply integers.
+
+@d nx_plus_y(#)==mult_and_add(#,@'7777777777)
+@d mult_integers(#)==mult_and_add(#,0,@'17777777777)
+
+@p function mult_and_add(@!n:integer;@!x,@!y,@!max_answer:scaled):scaled;
+begin if n<0 then
+  begin negate(x); negate(n);
+  end;
+if n=0 then mult_and_add:=y
+else if ((x<=(max_answer-y) div n)and(-x<=(max_answer+y) div n)) then
+  mult_and_add:=n*x+y
+else  begin arith_error:=true; mult_and_add:=0;
+  end;
+end;
+
+@ We also need to divide scaled dimensions by integers.
+
+@p function x_over_n(@!x:scaled;@!n:integer):scaled;
+var negative:boolean; {should |remainder| be negated?}
+begin negative:=false;
+if n=0 then
+  begin arith_error:=true; x_over_n:=0; remainder:=x;
+  end
+else  begin if n<0 then
+    begin negate(x); negate(n); negative:=true;
+    end;
+  if x>=0 then
+    begin x_over_n:=x div n; remainder:=x mod n;
+    end
+  else  begin x_over_n:=-((-x) div n); remainder:=-((-x) mod n);
+    end;
+  end;
+if negative then negate(remainder);
+end;
+
+@ Then comes the multiplication of a scaled number by a fraction |n/d|,
+where |n| and |d| are nonnegative integers |<=@t$2^{16}$@>| and |d| is
+positive. It would be too dangerous to multiply by~|n| and then divide
+by~|d|, in separate operations, since overflow might well occur; and it
+would be too inaccurate to divide by |d| and then multiply by |n|. Hence
+this subroutine simulates 1.5-precision arithmetic.
+
+@p function xn_over_d(@!x:scaled; @!n,@!d:integer):scaled;
+var positive:boolean; {was |x>=0|?}
+@!t,@!u,@!v:nonnegative_integer; {intermediate quantities}
+begin if x>=0 then positive:=true
+else  begin negate(x); positive:=false;
+  end;
+t:=(x mod @'100000)*n;
+u:=(x div @'100000)*n+(t div @'100000);
+v:=(u mod d)*@'100000 + (t mod @'100000);
+if u div d>=@'100000 then arith_error:=true
+else u:=@'100000*(u div d) + (v div d);
+if positive then
+  begin xn_over_d:=u; remainder:=v mod d;
+  end
+else  begin xn_over_d:=-u; remainder:=-(v mod d);
+  end;
+end;
+
+@ The next subroutine is used to compute the ``badness'' of glue, when a
+total~|t| is supposed to be made from amounts that sum to~|s|.  According
+to {\sl The \TeX book}, the badness of this situation is $100(t/s)^3$;
+however, badness is simply a heuristic, so we need not squeeze out the
+last drop of accuracy when computing it. All we really want is an
+approximation that has similar properties.
+@:TeXbook}{\sl The \TeX book@>
+
+The actual method used to compute the badness is easier to read from the
+program than to describe in words. It produces an integer value that is a
+reasonably close approximation to $100(t/s)^3$, and all implementations
+of \TeX\ should use precisely this method. Any badness of $2^{13}$ or more is
+treated as infinitely bad, and represented by 10000.
+
+It is not difficult to prove that $$\hbox{|badness(t+1,s)>=badness(t,s)
+>=badness(t,s+1)|}.$$ The badness function defined here is capable of
+computing at most 1095 distinct values, but that is plenty.
+
+@d inf_bad = 10000 {infinitely bad value}
+
+@p function badness(@!t,@!s:scaled):halfword; {compute badness, given |t>=0|}
+var r:integer; {approximation to $\alpha t/s$, where $\alpha^3\approx
+  100\cdot2^{18}$}
+begin if t=0 then badness:=0
+else if s<=0 then badness:=inf_bad
+else  begin if t<=7230584 then  r:=(t*297) div s {$297^3=99.94\times2^{18}$}
+  else if s>=1663497 then r:=t div (s div 297)
+  else r:=t;
+  if r>1290 then badness:=inf_bad {$1290^3<2^{31}<1291^3$}
+  else badness:=(r*r*r+@'400000) div @'1000000;
+  end; {that was $r^3/2^{18}$, rounded to the nearest integer}
+end;
+
+@ When \TeX\ ``packages'' a list into a box, it needs to calculate the
+proportionality ratio by which the glue inside the box should stretch
+or shrink. This calculation does not affect \TeX's decision making,
+so the precise details of rounding, etc., in the glue calculation are not
+of critical importance for the consistency of results on different computers.
+
+We shall use the type |glue_ratio| for such proportionality ratios.
+A glue ratio should take the same amount of memory as an
+|integer| (usually 32 bits) if it is to blend smoothly with \TeX's
+other data structures. Thus |glue_ratio| should be equivalent to
+|short_real| in some implementations of \PASCAL. Alternatively,
+it is possible to deal with glue ratios using nothing but fixed-point
+arithmetic; see {\sl TUGboat \bf3},1 (March 1982), 10--27. (But the
+routines cited there must be modified to allow negative glue ratios.)
+@^system dependencies@>
+
+@d set_glue_ratio_zero(#) == #:=0.0 {store the representation of zero ratio}
+@d set_glue_ratio_one(#) == #:=1.0 {store the representation of unit ratio}
+@d float(#) == # {convert from |glue_ratio| to type |real|}
+@d unfloat(#) == # {convert from |real| to type |glue_ratio|}
+@d float_constant(#) == #.0 {convert |integer| constant to |real|}
+
+@<Types...@>=
+
+@* \[8] Packed data.
+In order to make efficient use of storage space, \TeX\ bases its major data
+structures on a |memory_word|, which contains either a (signed) integer,
+possibly scaled, or a (signed) |glue_ratio|, or a small number of
+fields that are one half or one quarter of the size used for storing
+integers.
+
+If |x| is a variable of type |memory_word|, it contains up to four
+fields that can be referred to as follows:
+$$\vbox{\halign{\hfil#&#\hfil&#\hfil\cr
+|x|&.|int|&(an |integer|)\cr
+|x|&.|sc|\qquad&(a |scaled| integer)\cr
+|x|&.|gr|&(a |glue_ratio|)\cr
+|x.hh.lh|, |x.hh|&.|rh|&(two halfword fields)\cr
+|x.hh.b0|, |x.hh.b1|, |x.hh|&.|rh|&(two quarterword fields, one halfword
+  field)\cr
+|x.qqqq.b0|, |x.qqqq.b1|, |x.qqqq|&.|b2|, |x.qqqq.b3|\hskip-100pt
+  &\qquad\qquad\qquad(four quarterword fields)\cr}}$$
+This is somewhat cumbersome to write, and not very readable either, but
+macros will be used to make the notation shorter and more transparent.
+The \PASCAL\ code below gives a formal definition of |memory_word| and
+its subsidiary types, using packed variant records. \TeX\ makes no
+assumptions about the relative positions of the fields within a word.
+
+Since we are assuming 32-bit integers, a halfword must contain at least
+16 bits, and a quarterword must contain at least 8 bits.
+@^system dependencies@>
+But it doesn't hurt to have more bits; for example, with enough 36-bit
+words you might be able to have |mem_max| as large as 262142, which is
+eight times as much memory as anybody had during the first four years of
+\TeX's existence.
+
+N.B.: Valuable memory space will be dreadfully wasted unless \TeX\ is compiled
+by a \PASCAL\ that packs all of the |memory_word| variants into
+the space of a single integer. This means, for example, that |glue_ratio|
+words should be |short_real| instead of |real| on some computers. Some
+\PASCAL\ compilers will pack an integer whose subrange is `|0..255|' into
+an eight-bit field, but others insist on allocating space for an additional
+sign bit; on such systems you can get 256 values into a quarterword only
+if the subrange is `|-128..127|'.
+
+The present implementation tries to accommodate as many variations as possible,
+so it makes few assumptions. If integers having the subrange
+`|min_quarterword..max_quarterword|' can be packed into a quarterword,
+and if integers having the subrange `|min_halfword..max_halfword|'
+can be packed into a halfword, everything should work satisfactorily.
+
+It is usually most efficient to have |min_quarterword=min_halfword=0|,
+so one should try to achieve this unless it causes a severe problem.
+The values defined here are recommended for most 32-bit computers.
+
+@d min_quarterword=0 {smallest allowable value in a |quarterword|}
+@d max_quarterword=255 {largest allowable value in a |quarterword|}
+@d min_halfword==-@"FFFFFFF {smallest allowable value in a |halfword|}
+@d max_halfword==@"FFFFFFF {largest allowable value in a |halfword|}
+
+@ Here are the inequalities that the quarterword and halfword values
+must satisfy (or rather, the inequalities that they mustn't satisfy):
+
+@<Check the ``constant''...@>=
+init if (mem_min<>mem_bot)or(mem_max<>mem_top) then bad:=10;@+tini@;@/
+if (mem_min>mem_bot)or(mem_max<mem_top) then bad:=10;
+if (min_quarterword>0)or(max_quarterword<127) then bad:=11;
+if (min_halfword>0)or(max_halfword<32767) then bad:=12;
+if (min_quarterword<min_halfword)or@|
+  (max_quarterword>max_halfword) then bad:=13;
+if (mem_bot-sup_main_memory<min_halfword)or@|
+  (mem_top+sup_main_memory>=max_halfword)or@|
+  (hi(0)<>0) then bad:=14;
+if (max_font_max<min_halfword)or(max_font_max>max_halfword) then bad:=15;
+if font_max>font_base+max_font_max then bad:=16;
+if (save_size>max_halfword)or(max_strings>max_halfword) then bad:=17;
+if buf_size>max_halfword then bad:=18;
+if max_quarterword-min_quarterword<255 then bad:=19;
+
+@ The operation of adding or subtracting |min_quarterword| occurs quite
+frequently in \TeX, so it is convenient to abbreviate this operation
+by using the macros |qi| and |qo| for input and output to and from
+quarterword format.
+
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `|x+0|' and `|x-0|', if these
+macros are simplified in the obvious way when |min_quarterword=0|.
+So they have been simplified here in the obvious way.
+@^inner loop@>@^system dependencies@>
+
+The \.{WEB} source for \TeX\ defines |hi(#)==#+min_halfword| which can be
+simplified when |min_halfword=0|.  The Web2C implemetation of \TeX\ can use
+|hi(#)==#| together with |min_halfword<0| as long as |max_halfword| is
+sufficiently large and this is required for p\TeX.
+
+@d qi(#)==# {to put an |eight_bits| item into a quarterword}
+@d qo(#)==# {to take an |eight_bits| item from a quarterword}
+@d hi(#)==# {to put a sixteen-bit item into a halfword}
+@d ho(#)==# {to take a sixteen-bit item from a halfword}
+@d KANJI(#)==# {pTeX: to output a KANJI code}
+@d tokanji(#)==# {pTeX: to take a KANJI code from a halfword}
+@d tonum(#)==# {pTeX: to put a KANJI code into a halfword}
+
+@ The reader should study the following definitions closely:
+@^system dependencies@>
+
+@d sc==int {|scaled| data is equivalent to |integer|}
+
+@<Types...@>=
+@!quarterword = min_quarterword..max_quarterword;
+@!halfword = min_halfword..max_halfword;
+@!two_choices = 1..2; {used when there are two variants in a record}
+@!four_choices = 1..4; {used when there are four variants in a record}
+@=#include "texmfmem.h";@>
+@!word_file = file of memory_word;
+
+@ When debugging, we may want to print a |memory_word| without knowing
+what type it is; so we print it in all modes.
+@^dirty \PASCAL@>@^debugging@>
+
+@p @!debug procedure print_word(@!w:memory_word);
+  {prints |w| in all ways}
+begin print_int(w.int); print_char(" ");@/
+print_scaled(w.sc); print_char(" ");@/
+print_scaled(round(unity*float(w.gr))); print_ln;@/
+@^real multiplication@>
+print_int(w.hh.lh); print_char("="); print_int(w.hh.b0); print_char(":");
+print_int(w.hh.b1); print_char(";"); print_int(w.hh.rh); print_char(" ");@/
+print_int(w.qqqq.b0); print_char(":"); print_int(w.qqqq.b1); print_char(":");
+print_int(w.qqqq.b2); print_char(":"); print_int(w.qqqq.b3);
+end;
+gubed
+
+@* \[9] Dynamic memory allocation.
+The \TeX\ system does nearly all of its own memory allocation, so that it
+can readily be transported into environments that do not have automatic
+facilities for strings, garbage collection, etc., and so that it can be in
+control of what error messages the user receives. The dynamic storage
+requirements of \TeX\ are handled by providing a large array |mem| in
+which consecutive blocks of words are used as nodes by the \TeX\ routines.
+
+Pointer variables are indices into this array, or into another array
+called |eqtb| that will be explained later. A pointer variable might
+also be a special flag that lies outside the bounds of |mem|, so we
+allow pointers to assume any |halfword| value. The minimum halfword
+value represents a null pointer. \TeX\ does not assume that |mem[null]| exists.
+
+@d pointer==halfword {a flag or a location in |mem| or |eqtb|}
+@d null==min_halfword {the null pointer}
+
+@<Glob...@>=
+@!temp_ptr:pointer; {a pointer variable for occasional emergency use}
+
+@ The |mem| array is divided into two regions that are allocated separately,
+but the dividing line between these two regions is not fixed; they grow
+together until finding their ``natural'' size in a particular job.
+Locations less than or equal to |lo_mem_max| are used for storing
+variable-length records consisting of two or more words each. This region
+is maintained using an algorithm similar to the one described in exercise
+2.5--19 of {\sl The Art of Computer Programming}. However, no size field
+appears in the allocated nodes; the program is responsible for knowing the
+relevant size when a node is freed. Locations greater than or equal to
+|hi_mem_min| are used for storing one-word records; a conventional
+\.{AVAIL} stack is used for allocation in this region.
+
+Locations of |mem| between |mem_bot| and |mem_top| may be dumped as part
+of preloaded format files, by the \.{INITEX} preprocessor.
+@.INITEX@>
+Production versions of \TeX\ may extend the memory at both ends in order to
+provide more space; locations between |mem_min| and |mem_bot| are always
+used for variable-size nodes, and locations between |mem_top| and |mem_max|
+are always used for single-word nodes.
+
+The key pointers that govern |mem| allocation have a prescribed order:
+$$\advance\thickmuskip-2mu
+\hbox{|null<=mem_min<=mem_bot<lo_mem_max<
+  hi_mem_min<mem_top<=mem_end<=mem_max|.}$$
+
+Empirical tests show that the present implementation of \TeX\ tends to
+spend about 9\pct! of its running time allocating nodes, and about 6\pct!
+deallocating them after their use.
+
+@<Glob...@>=
+@!yzmem : ^memory_word; {the big dynamic storage area}
+@!zmem : ^memory_word; {the big dynamic storage area}
+@!lo_mem_max : pointer; {the largest location of variable-size memory in use}
+@!hi_mem_min : pointer; {the smallest location of one-word memory in use}
+
+@ In order to study the memory requirements of particular applications, it
+is possible to prepare a version of \TeX\ that keeps track of current and
+maximum memory usage. When code between the delimiters |@!stat| $\ldots$
+|tats| is not ``commented out,'' \TeX\ will run a bit slower but it will
+report these statistics when |tracing_stats| is sufficiently large.
+
+@<Glob...@>=
+@!var_used, @!dyn_used : integer; {how much memory is in use}
+
+@ Let's consider the one-word memory region first, since it's the
+simplest. The pointer variable |mem_end| holds the highest-numbered location
+of |mem| that has ever been used. The free locations of |mem| that
+occur between |hi_mem_min| and |mem_end|, inclusive, are of type
+|two_halves|, and we write |info(p)| and |link(p)| for the |lh|
+and |rh| fields of |mem[p]| when it is of this type. The single-word
+free locations form a linked list
+$$|avail|,\;\hbox{|link(avail)|},\;\hbox{|link(link(avail))|},\;\ldots$$
+terminated by |null|.
+
+@d link(#) == mem[#].hh.rh {the |link| field of a memory word}
+@d info(#) == mem[#].hh.lh {the |info| field of a memory word}
+
+@<Glob...@>=
+@!avail : pointer; {head of the list of available one-word nodes}
+@!mem_end : pointer; {the last one-word node used in |mem|}
+
+@ If memory is exhausted, it might mean that the user has forgotten
+a right brace. We will define some procedures later that try to help
+pinpoint the trouble.
+
+@p @<Declare the procedure called |show_token_list|@>@/
+@<Declare the procedure called |runaway|@>
+
+@ The function |get_avail| returns a pointer to a new one-word node whose
+|link| field is null. However, \TeX\ will halt if there is no more room left.
+@^inner loop@>
+
+If the available-space list is empty, i.e., if |avail=null|,
+we try first to increase |mem_end|. If that cannot be done, i.e., if
+|mem_end=mem_max|, we try to decrease |hi_mem_min|. If that cannot be
+done, i.e., if |hi_mem_min=lo_mem_max+1|, we have to quit.
+
+@p function get_avail : pointer; {single-word node allocation}
+var p:pointer; {the new node being got}
+begin p:=avail; {get top location in the |avail| stack}
+if p<>null then avail:=link(avail) {and pop it off}
+else if mem_end<mem_max then {or go into virgin territory}
+  begin incr(mem_end); p:=mem_end;
+  end
+else   begin decr(hi_mem_min); p:=hi_mem_min;
+  if hi_mem_min<=lo_mem_max then
+    begin runaway; {if memory is exhausted, display possible runaway text}
+    overflow("main memory size",mem_max+1-mem_min);
+      {quit; all one-word nodes are busy}
+@:TeX capacity exceeded main memory size}{\quad main memory size@>
+    end;
+  end;
+link(p):=null; {provide an oft-desired initialization of the new node}
+@!stat incr(dyn_used);@+tats@;{maintain statistics}
+get_avail:=p;
+end;
+
+@ Conversely, a one-word node is recycled by calling |free_avail|.
+This routine is part of \TeX's ``inner loop,'' so we want it to be fast.
+@^inner loop@>
+
+@d free_avail(#)== {single-word node liberation}
+  begin link(#):=avail; avail:=#;
+  @!stat decr(dyn_used);@+tats@/
+  end
+
+@ There's also a |fast_get_avail| routine, which saves the procedure-call
+overhead at the expense of extra programming. This routine is used in
+the places that would otherwise account for the most calls of |get_avail|.
+@^inner loop@>
+
+@d fast_get_avail(#)==@t@>@;@/
+  begin #:=avail; {avoid |get_avail| if possible, to save time}
+  if #=null then #:=get_avail
+  else  begin avail:=link(#); link(#):=null;
+    @!stat incr(dyn_used);@+tats@/
+    end;
+  end
+
+@ The procedure |flush_list(p)| frees an entire linked list of
+one-word nodes that starts at position |p|.
+@^inner loop@>
+
+@p procedure flush_list(@!p:pointer); {makes list of single-word nodes
+  available}
+var @!q,@!r:pointer; {list traversers}
+begin if p<>null then
+  begin r:=p;
+  repeat q:=r; r:=link(r); @!stat decr(dyn_used);@+tats@/
+  until r=null; {now |q| is the last node on the list}
+  link(q):=avail; avail:=p;
+  end;
+end;
+
+@ The available-space list that keeps track of the variable-size portion
+of |mem| is a nonempty, doubly-linked circular list of empty nodes,
+pointed to by the roving pointer |rover|.
+
+Each empty node has size 2 or more; the first word contains the special
+value |max_halfword| in its |link| field and the size in its |info| field;
+the second word contains the two pointers for double linking.
+
+Each nonempty node also has size 2 or more. Its first word is of type
+|two_halves|\kern-1pt, and its |link| field is never equal to |max_halfword|.
+Otherwise there is complete flexibility with respect to the contents
+of its other fields and its other words.
+
+(We require |mem_max<max_halfword| because terrible things can happen
+when |max_halfword| appears in the |link| field of a nonempty node.)
+
+@d empty_flag == max_halfword {the |link| of an empty variable-size node}
+@d is_empty(#) == (link(#)=empty_flag) {tests for empty node}
+@d node_size == info {the size field in empty variable-size nodes}
+@d llink(#) == info(#+1) {left link in doubly-linked list of empty nodes}
+@d rlink(#) == link(#+1) {right link in doubly-linked list of empty nodes}
+
+@<Glob...@>=
+@!rover : pointer; {points to some node in the list of empties}
+
+@ A call to |get_node| with argument |s| returns a pointer to a new node
+of size~|s|, which must be 2~or more. The |link| field of the first word
+of this new node is set to null. An overflow stop occurs if no suitable
+space exists.
+
+If |get_node| is called with $s=2^{30}$, it simply merges adjacent free
+areas and returns the value |max_halfword|.
+
+@p function get_node(@!s:integer):pointer; {variable-size node allocation}
+label found,exit,restart;
+var p:pointer; {the node currently under inspection}
+@!q:pointer; {the node physically after node |p|}
+@!r:integer; {the newly allocated node, or a candidate for this honor}
+@!t:integer; {temporary register}
+begin restart: p:=rover; {start at some free node in the ring}
+repeat @<Try to allocate within node |p| and its physical successors,
+  and |goto found| if allocation was possible@>;
+@^inner loop@>
+p:=rlink(p); {move to the next node in the ring}
+until p=rover; {repeat until the whole list has been traversed}
+if s=@'10000000000 then
+  begin get_node:=max_halfword; return;
+  end;
+if lo_mem_max+2<hi_mem_min then if lo_mem_max+2<=mem_bot+max_halfword then
+  @<Grow more variable-size memory and |goto restart|@>;
+overflow("main memory size",mem_max+1-mem_min);
+  {sorry, nothing satisfactory is left}
+@:TeX capacity exceeded main memory size}{\quad main memory size@>
+found: link(r):=null; {this node is now nonempty}
+@!stat var_used:=var_used+s; {maintain usage statistics}
+tats@;@/
+get_node:=r;
+exit:end;
+
+@ The lower part of |mem| grows by 1000 words at a time, unless
+we are very close to going under. When it grows, we simply link
+a new node into the available-space list. This method of controlled
+growth helps to keep the |mem| usage consecutive when \TeX\ is
+implemented on ``virtual memory'' systems.
+@^virtual memory@>
+
+@<Grow more variable-size memory and |goto restart|@>=
+begin if hi_mem_min-lo_mem_max>=1998 then t:=lo_mem_max+1000
+else t:=lo_mem_max+1+(hi_mem_min-lo_mem_max) div 2;
+  {|lo_mem_max+2<=t<hi_mem_min|}
+p:=llink(rover); q:=lo_mem_max; rlink(p):=q; llink(rover):=q;@/
+if t>mem_bot+max_halfword then t:=mem_bot+max_halfword;
+rlink(q):=rover; llink(q):=p; link(q):=empty_flag; node_size(q):=t-lo_mem_max;@/
+lo_mem_max:=t; link(lo_mem_max):=null; info(lo_mem_max):=null;
+rover:=q; goto restart;
+end
+
+@ Empirical tests show that the routine in this section performs a
+node-merging operation about 0.75 times per allocation, on the average,
+after which it finds that |r>p+1| about 95\pct! of the time.
+
+@<Try to allocate...@>=
+q:=p+node_size(p); {find the physical successor}
+@^inner loop@>
+while is_empty(q) do {merge node |p| with node |q|}
+  begin t:=rlink(q);
+  if q=rover then rover:=t;
+  llink(t):=llink(q); rlink(llink(q)):=t;@/
+  q:=q+node_size(q);
+  end;
+r:=q-s;
+if r>intcast(p+1) then @<Allocate from the top of node |p| and |goto found|@>;
+if r=p then if rlink(p)<>p then
+  @<Allocate entire node |p| and |goto found|@>;
+node_size(p):=q-p {reset the size in case it grew}
+
+@ @<Allocate from the top...@>=
+begin node_size(p):=r-p; {store the remaining size}
+@^inner loop@>
+rover:=p; {start searching here next time}
+goto found;
+end
+
+@ Here we delete node |p| from the ring, and let |rover| rove around.
+
+@<Allocate entire...@>=
+begin rover:=rlink(p); t:=llink(p);
+llink(rover):=t; rlink(t):=rover;
+goto found;
+end
+
+@ Conversely, when some variable-size node |p| of size |s| is no longer needed,
+the operation |free_node(p,s)| will make its words available, by inserting
+|p| as a new empty node just before where |rover| now points.
+@^inner loop@>
+
+@p procedure free_node(@!p:pointer; @!s:halfword); {variable-size node
+  liberation}
+var q:pointer; {|llink(rover)|}
+begin node_size(p):=s; link(p):=empty_flag;
+q:=llink(rover); llink(p):=q; rlink(p):=rover; {set both links}
+llink(rover):=p; rlink(q):=p; {insert |p| into the ring}
+@!stat var_used:=var_used-s;@+tats@;{maintain statistics}
+end;
+
+@ Just before \.{INITEX} writes out the memory, it sorts the doubly linked
+available space list. The list is probably very short at such times, so a
+simple insertion sort is used. The smallest available location will be
+pointed to by |rover|, the next-smallest by |rlink(rover)|, etc.
+
+@p @!init procedure sort_avail; {sorts the available variable-size nodes
+  by location}
+var p,@!q,@!r: pointer; {indices into |mem|}
+@!old_rover:pointer; {initial |rover| setting}
+begin p:=get_node(@'10000000000); {merge adjacent free areas}
+p:=rlink(rover); rlink(rover):=max_halfword; old_rover:=rover;
+while p<>old_rover do @<Sort \(p)|p| into the list starting at |rover|
+  and advance |p| to |rlink(p)|@>;
+p:=rover;
+while rlink(p)<>max_halfword do
+  begin llink(rlink(p)):=p; p:=rlink(p);
+  end;
+rlink(p):=rover; llink(rover):=p;
+end;
+tini
+
+@ The following |while| loop is guaranteed to
+terminate, since the list that starts at
+|rover| ends with |max_halfword| during the sorting procedure.
+
+@<Sort \(p)|p|...@>=
+if p<rover then
+  begin q:=p; p:=rlink(q); rlink(q):=rover; rover:=q;
+  end
+else  begin q:=rover;
+  while rlink(q)<p do q:=rlink(q);
+  r:=rlink(p); rlink(p):=rlink(q); rlink(q):=p; p:=r;
+  end
+
+@* \[10] Data structures for boxes and their friends.
+From the computer's standpoint, \TeX's chief mission is to create
+horizontal and vertical lists. We shall now investigate how the elements
+of these lists are represented internally as nodes in the dynamic memory.
+
+A horizontal or vertical list is linked together by |link| fields in
+the first word of each node. Individual nodes represent boxes, glue,
+penalties, or special things like discretionary hyphens; because of this
+variety, some nodes are longer than others, and we must distinguish different
+kinds of nodes. We do this by putting a `|type|' field in the first word,
+together with the link and an optional `|subtype|'.
+
+@d type(#) == mem[#].hh.b0 {identifies what kind of node this is}
+@d subtype(#) == mem[#].hh.b1 {secondary identification in some cases}
+
+@ A |@!char_node|, which represents a single character, is the most important
+kind of node because it accounts for the vast majority of all boxes.
+Special precautions are therefore taken to ensure that a |char_node| does
+not take up much memory space. Every such node is one word long, and in fact
+it is identifiable by this property, since other kinds of nodes have at least
+two words, and they appear in |mem| locations less than |hi_mem_min|.
+This makes it possible to omit the |type| field in a |char_node|, leaving
+us room for two bytes that identify a |font| and a |character| within
+that font.
+
+Note that the format of a |char_node| allows for up to 256 different
+fonts and up to 256 characters per font; but most implementations will
+probably limit the total number of fonts to fewer than 75 per job,
+and most fonts will stick to characters whose codes are
+less than 128 (since higher codes
+are more difficult to access on most keyboards).
+
+Extensions of \TeX\ intended for oriental languages will need even more
+than $256\times256$ possible characters, when we consider different sizes
+@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
+and styles of type.  It is suggested that Chinese and Japanese fonts be
+handled by representing such characters in two consecutive |char_node|
+entries: The first of these has |font=font_base|, and its |link| points
+to the second;
+the second identifies the font and the character dimensions.
+The saving feature about oriental characters is that most of them have
+the same box dimensions. The |character| field of the first |char_node|
+is a ``\\{charext}'' that distinguishes between graphic symbols whose
+dimensions are identical for typesetting purposes. (See the \MF\ manual.)
+Such an extension of \TeX\ would not be difficult; further details are
+left to the reader.
+
+In order to make sure that the |character| code fits in a quarterword,
+\TeX\ adds the quantity |min_quarterword| to the actual code.
+
+Character nodes appear only in horizontal lists, never in vertical lists.
+
+@d is_char_node(#) == (#>=hi_mem_min)
+  {does the argument point to a |char_node|?}
+@d font == type {the font code in a |char_node|}
+@d character == subtype {the character code in a |char_node|}
+
+@ An |hlist_node| stands for a box that was made from a horizontal list.
+Each |hlist_node| is seven words long, and contains the following fields
+(in addition to the mandatory |type| and |link|, which we shall not
+mention explicitly when discussing the other node types): The |height| and
+|width| and |depth| are scaled integers denoting the dimensions of the
+box.  There is also a |shift_amount| field, a scaled integer indicating
+how much this box should be lowered (if it appears in a horizontal list),
+or how much it should be moved to the right (if it appears in a vertical
+list). There is a |list_ptr| field, which points to the beginning of the
+list from which this box was fabricated; if |list_ptr| is |null|, the box
+is empty. Finally, there are three fields that represent the setting of
+the glue:  |glue_set(p)| is a word of type |glue_ratio| that represents
+the proportionality constant for glue setting; |glue_sign(p)| is
+|stretching| or |shrinking| or |normal| depending on whether or not the
+glue should stretch or shrink or remain rigid; and |glue_order(p)|
+specifies the order of infinity to which glue setting applies (|normal|,
+|fil|, |fill|, or |filll|). The |subtype| field is not used in \TeX.
+In p\TeX\ the |subtype| field records the box direction |box_dir|.
+
+@d hlist_node=0 {|type| of hlist nodes}
+@d box_node_size=8 {number of words to allocate for a box node}
+@#
+@d box_dir(#) == (qo(subtype(#))) {direction of a box}
+@d set_box_dir(#) == subtype(#):=set_box_dir_end
+@d set_box_dir_end(#) == qi(#)
+@#
+@d dir_default = 0 {direction of the box, default Left to Right}
+@d dir_dtou = 1 {direction of the box, Bottom to Top}
+@d dir_tate = 3 {direction of the box, Top to Bottom}
+@d dir_yoko = 4 {direction of the box, equal default}
+@d any_dir == dir_yoko,dir_tate,dir_dtou
+@#
+@d width_offset=1 {position of |width| field in a box node}
+@d depth_offset=2 {position of |depth| field in a box node}
+@d height_offset=3 {position of |height| field in a box node}
+@d width(#) == mem[#+width_offset].sc {width of the box, in sp}
+@d depth(#) == mem[#+depth_offset].sc {depth of the box, in sp}
+@d height(#) == mem[#+height_offset].sc {height of the box, in sp}
+@d shift_amount(#) == mem[#+4].sc {repositioning distance, in sp}
+@d list_offset=5 {position of |list_ptr| field in a box node}
+@d list_ptr(#) == link(#+list_offset) {beginning of the list inside the box}
+@d glue_order(#) == subtype(#+list_offset) {applicable order of infinity}
+@d glue_sign(#) == type(#+list_offset) {stretching or shrinking}
+@d normal=0 {the most common case when several cases are named}
+@d stretching = 1 {glue setting applies to the stretch components}
+@d shrinking = 2 {glue setting applies to the shrink components}
+@d glue_offset = 6 {position of |glue_set| in a box node}
+@d glue_set(#) == mem[#+glue_offset].gr
+  {a word of type |glue_ratio| for glue setting}
+@d space_offset = 7 {position of |glue_set| in a box node}
+@d space_ptr(#) == link(#+space_offset)
+@d xspace_ptr(#) == info(#+space_offset)
+
+@ The |new_null_box| function returns a pointer to an |hlist_node| in
+which all subfields have the values corresponding to `\.{\\hbox\{\}}'.
+The |subtype| field is set to |min_quarterword|, since that's the desired
+|span_count| value if this |hlist_node| is changed to an |unset_node|.
+
+@p function new_null_box:pointer; {creates a new box node}
+var p:pointer; {the new node}
+begin p:=get_node(box_node_size); type(p):=hlist_node;
+subtype(p):=min_quarterword;
+width(p):=0; depth(p):=0; height(p):=0; shift_amount(p):=0; list_ptr(p):=null;
+glue_sign(p):=normal; glue_order(p):=normal; set_glue_ratio_zero(glue_set(p));
+space_ptr(p):=zero_glue; xspace_ptr(p):=zero_glue;
+add_glue_ref(zero_glue); add_glue_ref(zero_glue);
+new_null_box:=p;
+end;
+
+@ A |vlist_node| is like an |hlist_node| in all respects except that it
+contains a vertical list.
+
+@d vlist_node=1 {|type| of vlist nodes}
+
+@ A |dir_node| stands for direction change.
+
+@d dir_node=2 {|type| of dir nodes}
+
+@p function new_dir_node(b:pointer; dir:eight_bits):pointer;
+var p:pointer; {the new node}
+begin if type(b)>vlist_node then confusion("new_dir_node:not box");
+p:=new_null_box; type(p):=dir_node; set_box_dir(p)(dir);
+case box_dir(b) of
+  dir_yoko: @<Yoko to other direction@>;
+  dir_tate: @<Tate to other direction@>;
+  dir_dtou: @<DtoU to other direction@>;
+  othercases confusion("new_dir_node:illegal dir");
+endcases;
+link(b):=null; list_ptr(p):=b;
+new_dir_node:=p;
+end;
+
+@ @<Yoko to other direction@>=
+  case dir of
+  dir_tate: begin width(p):=height(b)+depth(b);
+      depth(p):=width(b)/2; height(p):=width(b)-depth(p);
+      end;
+  dir_dtou: begin width(p):=height(b)+depth(b);
+      depth(p):=0; height(p):=width(b);
+      end;
+  othercases confusion("new_dir_node:y->?");
+  endcases
+
+@ @<Tate to other direction@>=
+  case dir of
+  dir_yoko: begin width(p):=height(b)+depth(b);
+      depth(p):=0; height(p):=width(b);
+      end;
+  dir_dtou: begin width(p):=width(b);
+      depth(p):=height(b); height(p):=depth(b);
+      end;
+  othercases confusion("new_dir_node:t->?");
+  endcases
+
+@ @<DtoU to other direction@>=
+  case dir of
+  dir_yoko: begin width(p):=height(b)+depth(b);
+      depth(p):=0; height(p):=width(b);
+      end;
+  dir_tate: begin width(p):=width(b);
+      depth(p):=height(b); height(p):=depth(b);
+      end;
+  othercases confusion("new_dir_node:d->?");
+  endcases
+
+@ A |rule_node| stands for a solid black rectangle; it has |width|,
+|depth|, and |height| fields just as in an |hlist_node|. However, if
+any of these dimensions is $-2^{30}$, the actual value will be determined
+by running the rule up to the boundary of the innermost enclosing box.
+This is called a ``running dimension.'' The |width| is never running in
+an hlist; the |height| and |depth| are never running in a~vlist.
+
+@d rule_node=3 {|type| of rule nodes}
+@d rule_node_size=4 {number of words to allocate for a rule node}
+@d null_flag==-@'10000000000 {$-2^{30}$, signifies a missing item}
+@d is_running(#) == (#=null_flag) {tests for a running dimension}
+
+@ A new rule node is delivered by the |new_rule| function. It
+makes all the dimensions ``running,'' so you have to change the
+ones that are not allowed to run.
+
+@p function new_rule:pointer;
+var p:pointer; {the new node}
+begin p:=get_node(rule_node_size); type(p):=rule_node;
+subtype(p):=0; {the |subtype| is not used}
+width(p):=null_flag; depth(p):=null_flag; height(p):=null_flag;
+new_rule:=p;
+end;
+
+@ Insertions are represented by |ins_node| records, where the |subtype|
+indicates the corresponding box number. For example, `\.{\\insert 250}'
+leads to an |ins_node| whose |subtype| is |250+min_quarterword|.
+The |height| field of an |ins_node| is slightly misnamed; it actually holds
+the natural height plus depth of the vertical list being inserted.
+The |depth| field holds the |split_max_depth| to be used in case this
+insertion is split, and the |split_top_ptr| points to the corresponding
+|split_top_skip|. The |float_cost| field holds the |floating_penalty| that
+will be used if this insertion floats to a subsequent page after a
+split insertion of the same class.  There is one more field, the
+|ins_ptr|, which points to the beginning of the vlist for the insertion.
+
+@d ins_node=4 {|type| of insertion nodes}
+@d ins_node_size=6 {number of words to allocate for an insertion}
+@d float_cost(#)==mem[#+1].int {the |floating_penalty| to be used}
+@d ins_ptr(#)==info(#+4) {the vertical list to be inserted}
+@d split_top_ptr(#)==link(#+4) {the |split_top_skip| to be used}
+@d ins_dir(#)==subtype(#+5) {direction of |ins_node|}
+
+@ A |disp_node| has a |disp_dimen| field that points to the displacement
+distance of the baselineshift between Latin characters and Kanji chatacters.
+
+@d disp_node=5 {|type| of a displace node}
+@d disp_dimen(#)==mem[#+1].sc
+
+@ A |mark_node| has a |mark_ptr| field that points to the reference count
+of a token list that contains the user's \.{\\mark} text.
+This field occupies a full word instead of a halfword, because
+there's nothing to put in the other halfword; it is easier in \PASCAL\ to
+use the full word than to risk leaving garbage in the unused half.
+
+@d mark_node=6 {|type| of a mark node}
+@d small_node_size=2 {number of words to allocate for most node types}
+@d mark_ptr(#)==mem[#+1].int {head of the token list for a mark}
+
+@ An |adjust_node|, which occurs only in horizontal lists,
+specifies material that will be moved out into the surrounding
+vertical list; i.e., it is used to implement \TeX's `\.{\\vadjust}'
+operation.  The |adjust_ptr| field points to the vlist containing this
+material.
+
+@d adjust_node=7 {|type| of an adjust node}
+@d adjust_ptr==mark_ptr {vertical list to be moved out of horizontal list}
+
+@ A |ligature_node|, which occurs only in horizontal lists, specifies
+a character that was fabricated from the interaction of two or more
+actual characters.  The second word of the node, which is called the
+|lig_char| word, contains |font| and |character| fields just as in a
+|char_node|. The characters that generated the ligature have not been
+forgotten, since they are needed for diagnostic messages and for
+hyphenation; the |lig_ptr| field points to a linked list of character
+nodes for all original characters that have been deleted. (This list
+might be empty if the characters that generated the ligature were
+retained in other nodes.)
+
+The |subtype| field is 0, plus 2 and/or 1 if the original source of the
+ligature included implicit left and/or right boundaries.
+
+@d ligature_node=8 {|type| of a ligature node}
+@d lig_char(#)==#+1 {the word where the ligature is to be found}
+@d lig_ptr(#)==link(lig_char(#)) {the list of characters}
+
+@ The |new_ligature| function creates a ligature node having given
+contents of the |font|, |character|, and |lig_ptr| fields. We also have
+a |new_lig_item| function, which returns a two-word node having a given
+|character| field. Such nodes are used for temporary processing as ligatures
+are being created.
+
+@p function new_ligature(@!f:internal_font_number; @!c:quarterword;
+                         @!q:pointer):pointer;
+var p:pointer; {the new node}
+begin p:=get_node(small_node_size); type(p):=ligature_node;
+font(lig_char(p)):=f; character(lig_char(p)):=c; lig_ptr(p):=q;
+subtype(p):=0; new_ligature:=p;
+end;
+@#
+function new_lig_item(@!c:quarterword):pointer;
+var p:pointer; {the new node}
+begin p:=get_node(small_node_size); character(p):=c; lig_ptr(p):=null;
+new_lig_item:=p;
+end;
+
+@ A |disc_node|, which occurs only in horizontal lists, specifies a
+``dis\-cretion\-ary'' line break. If such a break occurs at node |p|, the text
+that starts at |pre_break(p)| will precede the break, the text that starts at
+|post_break(p)| will follow the break, and text that appears in the next
+|replace_count(p)| nodes will be ignored. For example, an ordinary
+discretionary hyphen, indicated by `\.{\\-}', yields a |disc_node| with
+|pre_break| pointing to a |char_node| containing a hyphen, |post_break=null|,
+and |replace_count=0|. All three of the discretionary texts must be
+lists that consist entirely of character, kern, box, rule, and ligature nodes.
+
+If |pre_break(p)=null|, the |ex_hyphen_penalty| will be charged for this
+break.  Otherwise the |hyphen_penalty| will be charged.  The texts will
+actually be substituted into the list by the line-breaking algorithm if it
+decides to make the break, and the discretionary node will disappear at
+that time; thus, the output routine sees only discretionaries that were
+not chosen.
+
+@d disc_node=9 {|type| of a discretionary node}
+@d replace_count==subtype {how many subsequent nodes to replace}
+@d pre_break==llink {text that precedes a discretionary break}
+@d post_break==rlink {text that follows a discretionary break}
+
+@p function new_disc:pointer; {creates an empty |disc_node|}
+var p:pointer; {the new node}
+begin p:=get_node(small_node_size); type(p):=disc_node;
+replace_count(p):=0; pre_break(p):=null; post_break(p):=null;
+new_disc:=p;
+end;
+
+@ A |whatsit_node| is a wild card reserved for extensions to \TeX. The
+|subtype| field in its first word says what `\\{whatsit}' it is, and
+implicitly determines the node size (which must be 2 or more) and the
+format of the remaining words. When a |whatsit_node| is encountered
+in a list, special actions are invoked; knowledgeable people who are
+careful not to mess up the rest of \TeX\ are able to make \TeX\ do new
+things by adding code at the end of the program. For example, there
+might be a `\TeX nicolor' extension to specify different colors of ink,
+@^extensions to \TeX@>
+and the whatsit node might contain the desired parameters.
+
+The present implementation of \TeX\ treats the features associated with
+`\.{\\write}' and `\.{\\special}' as if they were extensions, in order to
+illustrate how such routines might be coded. We shall defer further
+discussion of extensions until the end of this program.
+
+@d whatsit_node=10 {|type| of special extension nodes}
+
+@ A |math_node|, which occurs only in horizontal lists, appears before and
+after mathematical formulas. The |subtype| field is |before| before the
+formula and |after| after it. There is a |width| field, which represents
+the amount of surrounding space inserted by \.{\\mathsurround}.
+
+@d math_node=11 {|type| of a math node}
+@d before=0 {|subtype| for math node that introduces a formula}
+@d after=1 {|subtype| for math node that winds up a formula}
+
+@p function new_math(@!w:scaled;@!s:small_number):pointer;
+var p:pointer; {the new node}
+begin p:=get_node(small_node_size); type(p):=math_node;
+subtype(p):=s; width(p):=w; new_math:=p;
+end;
+
+@ \TeX\ makes use of the fact that |hlist_node|, |vlist_node|,
+|rule_node|, |ins_node|, |mark_node|, |adjust_node|, |ligature_node|,
+|disc_node|, |whatsit_node|, and |math_node| are at the low end of the
+type codes, by permitting a break at glue in a list if and only if the
+|type| of the previous node is less than |math_node|. Furthermore, a
+node is discarded after a break if its type is |math_node| or~more.
+
+@d precedes_break(#)==(type(#)<math_node)
+@d non_discardable(#)==(type(#)<math_node)
+
+@ A |glue_node| represents glue in a list. However, it is really only
+a pointer to a separate glue specification, since \TeX\ makes use of the
+fact that many essentially identical nodes of glue are usually present.
+If |p| points to a |glue_node|, |glue_ptr(p)| points to
+another packet of words that specify the stretch and shrink components, etc.
+
+Glue nodes also serve to represent leaders; the |subtype| is used to
+distinguish between ordinary glue (which is called |normal|) and the three
+kinds of leaders (which are called |a_leaders|, |c_leaders|, and |x_leaders|).
+The |leader_ptr| field points to a rule node or to a box node containing the
+leaders; it is set to |null| in ordinary glue nodes.
+
+Many kinds of glue are computed from \TeX's ``skip'' parameters, and
+it is helpful to know which parameter has led to a particular glue node.
+Therefore the |subtype| is set to indicate the source of glue, whenever
+it originated as a parameter. We will be defining symbolic names for the
+parameter numbers later (e.g., |line_skip_code=0|, |baseline_skip_code=1|,
+etc.); it suffices for now to say that the |subtype| of parametric glue
+will be the same as the parameter number, plus~one.
+
+In math formulas there are two more possibilities for the |subtype| in a
+glue node: |mu_glue| denotes an \.{\\mskip} (where the units are scaled \.{mu}
+instead of scaled \.{pt}); and |cond_math_glue| denotes the `\.{\\nonscript}'
+feature that cancels the glue node immediately following if it appears
+in a subscript.
+
+@d glue_node=12 {|type| of node that points to a glue specification}
+@d cond_math_glue=98 {special |subtype| to suppress glue in the next node}
+@d mu_glue=99 {|subtype| for math glue}
+@d a_leaders=100 {|subtype| for aligned leaders}
+@d c_leaders=101 {|subtype| for centered leaders}
+@d x_leaders=102 {|subtype| for expanded leaders}
+@d glue_ptr==llink {pointer to a glue specification}
+@d leader_ptr==rlink {pointer to box or rule node for leaders}
+
+@ A glue specification has a halfword reference count in its first word,
+@^reference counts@>
+representing |null| plus the number of glue nodes that point to it (less one).
+Note that the reference count appears in the same position as
+the |link| field in list nodes; this is the field that is initialized
+to |null| when a node is allocated, and it is also the field that is flagged
+by |empty_flag| in empty nodes.
+
+Glue specifications also contain three |scaled| fields, for the |width|,
+|stretch|, and |shrink| dimensions. Finally, there are two one-byte
+fields called |stretch_order| and |shrink_order|; these contain the
+orders of infinity (|normal|, |fil|, |fill|, or |filll|)
+corresponding to the stretch and shrink values.
+
+@d glue_spec_size=4 {number of words to allocate for a glue specification}
+@d glue_ref_count(#) == link(#) {reference count of a glue specification}
+@d stretch(#) == mem[#+2].sc {the stretchability of this glob of glue}
+@d shrink(#) == mem[#+3].sc {the shrinkability of this glob of glue}
+@d stretch_order == type {order of infinity for stretching}
+@d shrink_order == subtype {order of infinity for shrinking}
+@d fil=1 {first-order infinity}
+@d fill=2 {second-order infinity}
+@d filll=3 {third-order infinity}
+
+@<Types...@>=
+@!glue_ord=normal..filll; {infinity to the 0, 1, 2, or 3 power}
+
+@ Here is a function that returns a pointer to a copy of a glue spec.
+The reference count in the copy is |null|, because there is assumed
+to be exactly one reference to the new specification.
+
+@p function new_spec(@!p:pointer):pointer; {duplicates a glue specification}
+var q:pointer; {the new spec}
+begin q:=get_node(glue_spec_size);@/
+mem[q]:=mem[p]; glue_ref_count(q):=null;@/
+width(q):=width(p); stretch(q):=stretch(p); shrink(q):=shrink(p);
+new_spec:=q;
+end;
+
+@ And here's a function that creates a glue node for a given parameter
+identified by its code number; for example,
+|new_param_glue(line_skip_code)| returns a pointer to a glue node for the
+current \.{\\lineskip}.
+
+@p function new_param_glue(@!n:small_number):pointer;
+var p:pointer; {the new node}
+@!q:pointer; {the glue specification}
+begin p:=get_node(small_node_size); type(p):=glue_node; subtype(p):=n+1;
+leader_ptr(p):=null;@/
+q:=@<Current |mem| equivalent of glue parameter number |n|@>@t@>;
+glue_ptr(p):=q; incr(glue_ref_count(q));
+new_param_glue:=p;
+end;
+
+@ Glue nodes that are more or less anonymous are created by |new_glue|,
+whose argument points to a glue specification.
+
+@p function new_glue(@!q:pointer):pointer;
+var p:pointer; {the new node}
+begin p:=get_node(small_node_size); type(p):=glue_node; subtype(p):=normal;
+leader_ptr(p):=null; glue_ptr(p):=q; incr(glue_ref_count(q));
+new_glue:=p;
+end;
+
+@ Still another subroutine is needed: This one is sort of a combination
+of |new_param_glue| and |new_glue|. It creates a glue node for one of
+the current glue parameters, but it makes a fresh copy of the glue
+specification, since that specification will probably be subject to change,
+while the parameter will stay put. The global variable |temp_ptr| is
+set to the address of the new spec.
+
+@p function new_skip_param(@!n:small_number):pointer;
+var p:pointer; {the new node}
+begin temp_ptr:=new_spec(@<Current |mem| equivalent of glue parameter...@>);
+p:=new_glue(temp_ptr); glue_ref_count(temp_ptr):=null; subtype(p):=n+1;
+new_skip_param:=p;
+end;
+
+@ A |kern_node| has a |width| field to specify a (normally negative)
+amount of spacing. This spacing correction appears in horizontal lists
+between letters like A and V when the font designer said that it looks
+better to move them closer together or further apart. A kern node can
+also appear in a vertical list, when its `|width|' denotes additional
+spacing in the vertical direction. The |subtype| is either |normal| (for
+kerns inserted from font information or math mode calculations) or |explicit|
+(for kerns inserted from \.{\\kern} and \.{\\/} commands) or |acc_kern|
+(for kerns inserted from non-math accents) or |mu_glue| (for kerns
+inserted from \.{\\mkern} specifications in math formulas).
+
+@d kern_node=13 {|type| of a kern node}
+@d explicit=1 {|subtype| of kern nodes from \.{\\kern}}
+@d acc_kern=2 {|subtype| of kern nodes from accents}
+@d ita_kern=3 {|subtype| of kern nodes from \.{\\/}}
+
+@ The |new_kern| function creates a kern node having a given width.
+
+@p function new_kern(@!w:scaled):pointer;
+var p:pointer; {the new node}
+begin p:=get_node(small_node_size); type(p):=kern_node;
+subtype(p):=normal;
+width(p):=w;
+new_kern:=p;
+end;
+
+@ A |penalty_node| specifies the penalty associated with line or page
+breaking, in its |penalty| field. This field is a fullword integer, but
+the full range of integer values is not used: Any penalty |>=10000| is
+treated as infinity, and no break will be allowed for such high values.
+Similarly, any penalty |<=-10000| is treated as negative infinity, and a
+break will be forced.
+
+@d penalty_node=14 {|type| of a penalty node}
+@d widow_pena=1 {|subtype| of penalty nodes from \.{\\jchrwidowpenalty}}
+@d kinsoku_pena=2 {|subtype| of penalty nodes from kinsoku}
+@d inf_penalty=inf_bad {``infinite'' penalty value}
+@d eject_penalty=-inf_penalty {``negatively infinite'' penalty value}
+@d penalty(#) == mem[#+1].int {the added cost of breaking a list here}
+
+@ Anyone who has been reading the last few sections of the program will
+be able to guess what comes next.
+
+@p function new_penalty(@!m:integer):pointer;
+var p:pointer; {the new node}
+begin p:=get_node(small_node_size); type(p):=penalty_node;
+subtype(p):=0; {the |subtype| is not used}
+penalty(p):=m; new_penalty:=p;
+end;
+
+@ You might think that we have introduced enough node types by now. Well,
+almost, but there is one more: An |unset_node| has nearly the same format
+as an |hlist_node| or |vlist_node|; it is used for entries in \.{\\halign}
+or \.{\\valign} that are not yet in their final form, since the box
+dimensions are their ``natural'' sizes before any glue adjustment has been
+made. The |glue_set| word is not present; instead, we have a |glue_stretch|
+field, which contains the total stretch of order |glue_order| that is
+present in the hlist or vlist being boxed.
+Similarly, the |shift_amount| field is replaced by a |glue_shrink| field,
+containing the total shrink of order |glue_sign| that is present.
+The |subtype| field is called |span_count|; an unset box typically
+contains the data for |qo(span_count)+1| columns.
+Unset nodes will be changed to box nodes when alignment is completed.
+
+@d unset_node=15 {|type| for an unset node}
+@d glue_stretch(#)==mem[#+glue_offset].sc {total stretch in an unset node}
+@d glue_shrink==shift_amount {total shrink in an unset node}
+@d span_count==subtype {indicates the number of spanned columns}
+
+@ In fact, there are still more types coming. When we get to math formula
+processing we will see that a |style_node| has |type=16|; and a number
+of larger type codes will also be defined, for use in math mode only.
+
+@ Warning: If any changes are made to these data structure layouts, such as
+changing any of the node sizes or even reordering the words of nodes,
+the |copy_node_list| procedure and the memory initialization code
+below may have to be changed. Such potentially dangerous parts of the
+program are listed in the index under `data structure assumptions'.
+@!@^data structure assumptions@>
+However, other references to the nodes are made symbolically in terms of
+the \.{WEB} macro definitions above, so that format changes will leave
+\TeX's other algorithms intact.
+@^system dependencies@>
+
+@* \[11] Memory layout.
+Some areas of |mem| are dedicated to fixed usage, since static allocation is
+more efficient than dynamic allocation when we can get away with it. For
+example, locations |mem_bot| to |mem_bot+3| are always used to store the
+specification for glue that is `\.{0pt plus 0pt minus 0pt}'. The
+following macro definitions accomplish the static allocation by giving
+symbolic names to the fixed positions. Static variable-size nodes appear
+in locations |mem_bot| through |lo_mem_stat_max|, and static single-word nodes
+appear in locations |hi_mem_stat_min| through |mem_top|, inclusive. It is
+harmless to let |lig_trick| and |garbage| share the same location of |mem|.
+
+@d zero_glue==mem_bot {specification for \.{0pt plus 0pt minus 0pt}}
+@d fil_glue==zero_glue+glue_spec_size {\.{0pt plus 1fil minus 0pt}}
+@d fill_glue==fil_glue+glue_spec_size {\.{0pt plus 1fill minus 0pt}}
+@d ss_glue==fill_glue+glue_spec_size {\.{0pt plus 1fil minus 1fil}}
+@d fil_neg_glue==ss_glue+glue_spec_size {\.{0pt plus -1fil minus 0pt}}
+@d lo_mem_stat_max==fil_neg_glue+glue_spec_size-1 {largest statically
+  allocated word in the variable-size |mem|}
+@#
+@d page_ins_head==mem_top {list of insertion data for current page}
+@d contrib_head==mem_top-1 {vlist of items not yet on current page}
+@d page_head==mem_top-2 {vlist for current page}
+@d temp_head==mem_top-3 {head of a temporary list of some kind}
+@d hold_head==mem_top-4 {head of a temporary list of another kind}
+@d adjust_head==mem_top-5 {head of adjustment list returned by |hpack|}
+@d active==mem_top-7 {head of active list in |line_break|, needs two words}
+@d align_head==mem_top-8 {head of preamble list for alignments}
+@d end_span==mem_top-9 {tail of spanned-width lists}
+@d omit_template==mem_top-10 {a constant token list}
+@d null_list==mem_top-11 {permanently empty list}
+@d lig_trick==mem_top-12 {a ligature masquerading as a |char_node|}
+@d garbage==mem_top-12 {used for scrap information}
+@d backup_head==mem_top-13 {head of token list built by |scan_keyword|}
+@d hi_mem_stat_min==mem_top-13 {smallest statically allocated word in
+  the one-word |mem|}
+@d hi_mem_stat_usage=14 {the number of one-word nodes always present}
+
+@ The following code gets |mem| off to a good start, when \TeX\ is
+initializing itself the slow~way.
+
+@<Local variables for init...@>=
+@!k:integer; {index into |mem|, |eqtb|, etc.}
+
+@ @<Initialize table entries...@>=
+for k:=mem_bot+1 to lo_mem_stat_max do mem[k].sc:=0;
+  {all glue dimensions are zeroed}
+@^data structure assumptions@>
+k:=mem_bot;@+while k<=lo_mem_stat_max do
+    {set first words of glue specifications}
+  begin glue_ref_count(k):=null+1;
+  stretch_order(k):=normal; shrink_order(k):=normal;
+  k:=k+glue_spec_size;
+  end;
+stretch(fil_glue):=unity; stretch_order(fil_glue):=fil;@/
+stretch(fill_glue):=unity; stretch_order(fill_glue):=fill;@/
+stretch(ss_glue):=unity; stretch_order(ss_glue):=fil;@/
+shrink(ss_glue):=unity; shrink_order(ss_glue):=fil;@/
+stretch(fil_neg_glue):=-unity; stretch_order(fil_neg_glue):=fil;@/
+rover:=lo_mem_stat_max+1;
+link(rover):=empty_flag; {now initialize the dynamic memory}
+node_size(rover):=1000; {which is a 1000-word available node}
+llink(rover):=rover; rlink(rover):=rover;@/
+lo_mem_max:=rover+1000; link(lo_mem_max):=null; info(lo_mem_max):=null;@/
+for k:=hi_mem_stat_min to mem_top do
+  mem[k]:=mem[lo_mem_max]; {clear list heads}
+@<Initialize the special list heads and constant nodes@>;
+avail:=null; mem_end:=mem_top;
+hi_mem_min:=hi_mem_stat_min; {initialize the one-word memory}
+var_used:=lo_mem_stat_max+1-mem_bot; dyn_used:=hi_mem_stat_usage;
+  {initialize statistics}
+
+@ If \TeX\ is extended improperly, the |mem| array might get screwed up.
+For example, some pointers might be wrong, or some ``dead'' nodes might not
+have been freed when the last reference to them disappeared. Procedures
+|check_mem| and |search_mem| are available to help diagnose such
+problems. These procedures make use of two arrays called |free| and
+|was_free| that are present only if \TeX's debugging routines have
+been included. (You may want to decrease the size of |mem| while you
+@^debugging@>
+are debugging.)
+
+@d free==free_arr
+
+@<Glob...@>=
+ {The debug memory arrays have not been mallocated yet.}
+@!debug @!free: packed array [0..9] of boolean; {free cells}
+@t\hskip10pt@>@!was_free: packed array [0..9] of boolean;
+  {previously free cells}
+@t\hskip10pt@>@!was_mem_end,@!was_lo_max,@!was_hi_min: pointer;
+  {previous |mem_end|, |lo_mem_max|, and |hi_mem_min|}
+@t\hskip10pt@>@!panicking:boolean; {do we want to check memory constantly?}
+gubed
+
+@ @<Set initial...@>=
+@!debug was_mem_end:=mem_min; {indicate that everything was previously free}
+was_lo_max:=mem_min; was_hi_min:=mem_max;
+panicking:=false;
+gubed
+
+@ Procedure |check_mem| makes sure that the available space lists of
+|mem| are well formed, and it optionally prints out all locations
+that are reserved now but were free the last time this procedure was called.
+
+@p @!debug procedure check_mem(@!print_locs : boolean);
+label done1,done2; {loop exits}
+var p,@!q:pointer; {current locations of interest in |mem|}
+@!clobbered:boolean; {is something amiss?}
+begin for p:=mem_min to lo_mem_max do free[p]:=false; {you can probably
+  do this faster}
+for p:=hi_mem_min to mem_end do free[p]:=false; {ditto}
+@<Check single-word |avail| list@>;
+@<Check variable-size |avail| list@>;
+@<Check flags of unavailable nodes@>;
+if print_locs then @<Print newly busy locations@>;
+for p:=mem_min to lo_mem_max do was_free[p]:=free[p];
+for p:=hi_mem_min to mem_end do was_free[p]:=free[p];
+  {|was_free:=free| might be faster}
+was_mem_end:=mem_end; was_lo_max:=lo_mem_max; was_hi_min:=hi_mem_min;
+end;
+gubed
+
+@ @<Check single-word...@>=
+p:=avail; q:=null; clobbered:=false;
+while p<>null do
+  begin if (p>mem_end)or(p<hi_mem_min) then clobbered:=true
+  else if free[p] then clobbered:=true;
+  if clobbered then
+    begin print_nl("AVAIL list clobbered at ");
+@.AVAIL list clobbered...@>
+    print_int(q); goto done1;
+    end;
+  free[p]:=true; q:=p; p:=link(q);
+  end;
+done1:
+
+@ @<Check variable-size...@>=
+p:=rover; q:=null; clobbered:=false;
+repeat if (p>=lo_mem_max)or(p<mem_min) then clobbered:=true
+  else if (rlink(p)>=lo_mem_max)or(rlink(p)<mem_min) then clobbered:=true
+  else if  not(is_empty(p))or(node_size(p)<2)or@|
+   (p+node_size(p)>lo_mem_max)or@| (llink(rlink(p))<>p) then clobbered:=true;
+  if clobbered then
+  begin print_nl("Double-AVAIL list clobbered at ");
+  print_int(q); goto done2;
+  end;
+for q:=p to p+node_size(p)-1 do {mark all locations free}
+  begin if free[q] then
+    begin print_nl("Doubly free location at ");
+@.Doubly free location...@>
+    print_int(q); goto done2;
+    end;
+  free[q]:=true;
+  end;
+q:=p; p:=rlink(p);
+until p=rover;
+done2:
+
+@ @<Check flags...@>=
+p:=mem_min;
+while p<=lo_mem_max do {node |p| should not be empty}
+  begin if is_empty(p) then
+    begin print_nl("Bad flag at "); print_int(p);
+@.Bad flag...@>
+    end;
+  while (p<=lo_mem_max) and not free[p] do incr(p);
+  while (p<=lo_mem_max) and free[p] do incr(p);
+  end
+
+@ @<Print newly busy...@>=
+begin print_nl("New busy locs:");
+for p:=mem_min to lo_mem_max do
+  if not free[p] and ((p>was_lo_max) or was_free[p]) then
+    begin print_char(" "); print_int(p);
+    end;
+for p:=hi_mem_min to mem_end do
+  if not free[p] and
+   ((p<was_hi_min) or (p>was_mem_end) or was_free[p]) then
+    begin print_char(" "); print_int(p);
+    end;
+end
+
+@ The |search_mem| procedure attempts to answer the question ``Who points
+to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem|
+that might not be of type |two_halves|. Strictly speaking, this is
+@^dirty \PASCAL@>
+undefined in \PASCAL, and it can lead to ``false drops'' (words that seem to
+point to |p| purely by coincidence). But for debugging purposes, we want
+to rule out the places that do {\sl not\/} point to |p|, so a few false
+drops are tolerable.
+
+@p @!debug procedure search_mem(@!p:pointer); {look for pointers to |p|}
+var q:integer; {current position being searched}
+begin for q:=mem_min to lo_mem_max do
+  begin if link(q)=p then
+    begin print_nl("LINK("); print_int(q); print_char(")");
+    end;
+  if info(q)=p then
+    begin print_nl("INFO("); print_int(q); print_char(")");
+    end;
+  end;
+for q:=hi_mem_min to mem_end do
+  begin if link(q)=p then
+    begin print_nl("LINK("); print_int(q); print_char(")");
+    end;
+  if info(q)=p then
+    begin print_nl("INFO("); print_int(q); print_char(")");
+    end;
+  end;
+@<Search |eqtb| for equivalents equal to |p|@>;
+@<Search |save_stack| for equivalents that point to |p|@>;
+@<Search |hyph_list| for pointers to |p|@>;
+end;
+gubed
+
+@* \[12] Displaying boxes.
+We can reinforce our knowledge of the data structures just introduced
+by considering two procedures that display a list in symbolic form.
+The first of these, called |short_display|, is used in ``overfull box''
+messages to give the top-level description of a list. The other one,
+called |show_node_list|, prints a detailed description of exactly what
+is in the data structure.
+
+The philosophy of |short_display| is to ignore the fine points about exactly
+what is inside boxes, except that ligatures and discretionary breaks are
+expanded. As a result, |short_display| is a recursive procedure, but the
+recursion is never more than one level deep.
+@^recursion@>
+
+A global variable |font_in_short_display| keeps track of the font code that
+is assumed to be present when |short_display| begins; deviations from this
+font will be printed.
+
+@<Glob...@>=
+@!font_in_short_display:integer; {an internal font number}
+
+@ Boxes, rules, inserts, whatsits, marks, and things in general that are
+sort of ``complicated'' are indicated only by printing `\.{[]}'.
+
+@p procedure short_display(@!p:integer); {prints highlights of list |p|}
+var n:integer; {for replacement counts}
+begin while p>mem_min do
+  begin if is_char_node(p) then
+    begin if p<=mem_end then
+      begin if font(p)<>font_in_short_display then
+        begin if (font(p)>font_max) then
+          print_char("*")
+@.*\relax@>
+        else @<Print the font identifier for |font(p)|@>;
+        print_char(" "); font_in_short_display:=font(p);
+        end;
+      if font_dir[font(p)]<>dir_default then
+        begin p:=link(p); print_kanji(info(p));
+        end
+      else print_ASCII(qo(character(p)));
+      end;
+    end
+  else @<Print a short indication of the contents of node |p|@>;
+  p:=link(p);
+  end;
+end;
+
+@ @<Print a short indication of the contents of node |p|@>=
+case type(p) of
+hlist_node,vlist_node,dir_node,ins_node,whatsit_node,
+  mark_node,adjust_node,unset_node: print("[]");
+rule_node: print_char("|");
+glue_node: if glue_ptr(p)<>zero_glue then print_char(" ");
+math_node: print_char("$");
+ligature_node: short_display(lig_ptr(p));
+disc_node: begin short_display(pre_break(p));
+  short_display(post_break(p));@/
+  n:=replace_count(p);
+  while n>0 do
+    begin if link(p)<>null then p:=link(p);
+    decr(n);
+    end;
+  end;
+othercases do_nothing
+endcases
+
+@ The |show_node_list| routine requires some auxiliary subroutines: one to
+print a font-and-character combination, one to print a token list without
+its reference count, and one to print a rule dimension.
+
+@p procedure print_font_and_char(@!p:integer); {prints |char_node| data}
+begin if p>mem_end then print_esc("CLOBBERED.")
+else  begin if (font(p)>font_max) then print_char("*")
+@.*\relax@>
+  else @<Print the font identifier for |font(p)|@>;
+  print_char(" ");
+  if font_dir[font(p)]<>dir_default then
+    begin p:=link(p); print_kanji(info(p));
+    end
+  else print_ASCII(qo(character(p)));
+  end;
+end;
+@#
+procedure print_mark(@!p:integer); {prints token list data in braces}
+begin print_char("{");
+if (p<hi_mem_min)or(p>mem_end) then print_esc("CLOBBERED.")
+else show_token_list(link(p),null,max_print_line-10);
+print_char("}");
+end;
+@#
+procedure print_rule_dimen(@!d:scaled); {prints dimension in rule node}
+begin if is_running(d) then print_char("*") else print_scaled(d);
+@.*\relax@>
+end;
+
+@ Then there is a subroutine that prints glue stretch and shrink, possibly
+followed by the name of finite units:
+
+@p procedure print_glue(@!d:scaled;@!order:integer;@!s:str_number);
+  {prints a glue component}
+begin print_scaled(d);
+if (order<normal)or(order>filll) then print("foul")
+else if order>normal then
+  begin print("fil");
+  while order>fil do
+    begin print_char("l"); decr(order);
+    end;
+  end
+else if s<>0 then print(s);
+end;
+
+@ The next subroutine prints a whole glue specification.
+
+@p procedure print_spec(@!p:integer;@!s:str_number);
+  {prints a glue specification}
+begin if (p<mem_min)or(p>=lo_mem_max) then print_char("*")
+@.*\relax@>
+else  begin print_scaled(width(p));
+  if s<>0 then print(s);
+  if stretch(p)<>0 then
+    begin print(" plus "); print_glue(stretch(p),stretch_order(p),s);
+    end;
+  if shrink(p)<>0 then
+    begin print(" minus "); print_glue(shrink(p),shrink_order(p),s);
+    end;
+  end;
+end;
+
+@ We also need to declare some procedures that appear later in this
+documentation.
+
+@p @<Declare procedures needed for displaying the elements of mlists@>@;
+@<Declare the procedure called |print_skip_param|@>
+
+@ Since boxes can be inside of boxes, |show_node_list| is inherently recursive,
+@^recursion@>
+up to a given maximum number of levels.  The history of nesting is indicated
+by the current string, which will be printed at the beginning of each line;
+the length of this string, namely |cur_length|, is the depth of nesting.
+
+Recursive calls on |show_node_list| therefore use the following pattern:
+
+@d node_list_display(#)==
+  begin append_char("."); show_node_list(#); flush_char;
+  end {|str_room| need not be checked; see |show_box| below}
+
+@ A global variable called |depth_threshold| is used to record the maximum
+depth of nesting for which |show_node_list| will show information.  If we
+have |depth_threshold=0|, for example, only the top level information will
+be given and no sublists will be traversed. Another global variable, called
+|breadth_max|, tells the maximum number of items to show at each level;
+|breadth_max| had better be positive, or you won't see anything.
+
+@<Glob...@>=
+@!depth_threshold : integer; {maximum nesting depth in box displays}
+@!breadth_max : integer; {maximum number of items shown at the same list level}
+
+@ Now we are ready for |show_node_list| itself. This procedure has been
+written to be ``extra robust'' in the sense that it should not crash or get
+into a loop even if the data structures have been messed up by bugs in
+the rest of the program. You can safely call its parent routine
+|show_box(p)| for arbitrary values of |p| when you are debugging \TeX.
+However, in the presence of bad data, the procedure may
+@^dirty \PASCAL@>@^debugging@>
+fetch a |memory_word| whose variant is different from the way it was stored;
+for example, it might try to read |mem[p].hh| when |mem[p]|
+contains a scaled integer, if |p| is a pointer that has been
+clobbered or chosen at random.
+
+@p procedure show_node_list(@!p:integer); {prints a node list symbolically}
+label exit;
+var n:integer; {the number of items already printed at this level}
+@!g:real; {a glue ratio, as a floating point number}
+begin if cur_length>depth_threshold then
+  begin if p>null then print(" []");
+    {indicate that there's been some truncation}
+  return;
+  end;
+n:=0;
+while p>mem_min do
+  begin print_ln; print_current_string; {display the nesting history}
+  if p>mem_end then {pointer out of range}
+    begin print("Bad link, display aborted."); return;
+@.Bad link...@>
+    end;
+  incr(n); if n>breadth_max then {time to stop}
+    begin print("etc."); return;
+@.etc@>
+    end;
+  @<Display node |p|@>;
+  p:=link(p);
+  end;
+exit:
+end;
+
+@ @<Display node |p|@>=
+if is_char_node(p) then
+  begin print_font_and_char(p);
+  if font_dir[font(p)]<>dir_default then p:=link(p)
+  end
+else  case type(p) of
+  hlist_node,vlist_node,dir_node,unset_node: @<Display box |p|@>;
+  rule_node: @<Display rule |p|@>;
+  ins_node: @<Display insertion |p|@>;
+  whatsit_node: @<Display the whatsit node |p|@>;
+  disp_node: begin print_esc("displace "); print_scaled(disp_dimen(p));
+    end;
+  glue_node: @<Display glue |p|@>;
+  kern_node: @<Display kern |p|@>;
+  math_node: @<Display math node |p|@>;
+  ligature_node: @<Display ligature |p|@>;
+  penalty_node: @<Display penalty |p|@>;
+  disc_node: @<Display discretionary |p|@>;
+  mark_node: @<Display mark |p|@>;
+  adjust_node: @<Display adjustment |p|@>;
+  @t\4@>@<Cases of |show_node_list| that arise in mlists only@>@;
+  othercases print("Unknown node type!")
+  endcases
+
+@ @<Display box |p|@>=
+begin case type(p) of
+  hlist_node: print_esc("h");
+  vlist_node: print_esc("v");
+  dir_node: print_esc("dir");
+  othercases print_esc("unset")
+  endcases@/;
+print("box("); print_scaled(height(p)); print_char("+");
+print_scaled(depth(p)); print(")x"); print_scaled(width(p));
+if type(p)=unset_node then
+  @<Display special fields of the unset node |p|@>
+else  begin @<Display the value of |glue_set(p)|@>;
+  if shift_amount(p)<>0 then
+    begin print(", shifted "); print_scaled(shift_amount(p));
+    end;
+  if box_dir(p)<>dir_default then
+    begin print(", "); print_direction(box_dir(p));
+    end;
+  end;
+node_list_display(list_ptr(p)); {recursive call}
+end
+
+@ @<Display special fields of the unset node |p|@>=
+begin if span_count(p)<>min_quarterword then
+  begin print(" ("); print_int(qo(span_count(p))+1);
+  print(" columns)");
+  end;
+if glue_stretch(p)<>0 then
+  begin print(", stretch "); print_glue(glue_stretch(p),glue_order(p),0);
+  end;
+if glue_shrink(p)<>0 then
+  begin print(", shrink "); print_glue(glue_shrink(p),glue_sign(p),0);
+  end;
+end
+
+@ The code will have to change in this place if |glue_ratio| is
+a structured type instead of an ordinary |real|. Note that this routine
+should avoid arithmetic errors even if the |glue_set| field holds an
+arbitrary random value. The following code assumes that a properly
+formed nonzero |real| number has absolute value $2^{20}$ or more when
+it is regarded as an integer; this precaution was adequate to prevent
+floating point underflow on the author's computer.
+@^system dependencies@>
+@^dirty \PASCAL@>
+
+@<Display the value of |glue_set(p)|@>=
+g:=float(glue_set(p));
+if (g<>float_constant(0))and(glue_sign(p)<>normal) then
+  begin print(", glue set ");
+  if glue_sign(p)=shrinking then print("- ");
+  { The Unix |pc| folks removed this restriction with a remark that
+    invalid bit patterns were vanishingly improbable, so we follow
+    their example without really understanding it.
+  |if abs(mem[p+glue_offset].int)<@'4000000 then print('?.?')|
+  |else| }
+  if fabs(g)>float_constant(20000) then
+    begin if g>float_constant(0) then print_char(">")
+    else print("< -");
+    print_glue(20000*unity,glue_order(p),0);
+    end
+  else print_glue(round(unity*g),glue_order(p),0);
+@^real multiplication@>
+  end
+
+@ @<Display rule |p|@>=
+begin print_esc("rule("); print_rule_dimen(height(p)); print_char("+");
+print_rule_dimen(depth(p)); print(")x"); print_rule_dimen(width(p));
+end
+
+@ @<Display insertion |p|@>=
+begin print_esc("insert"); print_int(qo(subtype(p)));
+print_dir(ins_dir(p));
+print(", natural size "); print_scaled(height(p));
+print("; split("); print_spec(split_top_ptr(p),0);
+print_char(","); print_scaled(depth(p));
+print("); float cost "); print_int(float_cost(p));
+node_list_display(ins_ptr(p)); {recursive call}
+end
+
+@ @<Display glue |p|@>=
+if subtype(p)>=a_leaders then @<Display leaders |p|@>
+else  begin print_esc("glue");
+  if subtype(p)<>normal then
+    begin print_char("(");
+    if subtype(p)<cond_math_glue then
+      print_skip_param(subtype(p)-1)
+    else if subtype(p)=cond_math_glue then print_esc("nonscript")
+    else print_esc("mskip");
+    print_char(")");
+    end;
+  if subtype(p)<>cond_math_glue then
+    begin print_char(" ");
+    if subtype(p)<cond_math_glue then print_spec(glue_ptr(p),0)
+    else print_spec(glue_ptr(p),"mu");
+    end;
+  end
+
+@ @<Display leaders |p|@>=
+begin print_esc("");
+if subtype(p)=c_leaders then print_char("c")
+else if subtype(p)=x_leaders then print_char("x");
+print("leaders "); print_spec(glue_ptr(p),0);
+node_list_display(leader_ptr(p)); {recursive call}
+end
+
+@ An ``explicit'' kern value is indicated implicitly by an explicit space.
+
+@<Display kern |p|@>=
+if subtype(p)<>mu_glue then
+  begin print_esc("kern");
+  if subtype(p)<>normal then print_char(" ");
+  print_scaled(width(p));
+  if subtype(p)=acc_kern then print(" (for accent)");
+@.for accent@>
+  end
+else  begin print_esc("mkern"); print_scaled(width(p)); print("mu");
+  end
+
+@ @<Display math node |p|@>=
+begin print_esc("math");
+if subtype(p)=before then print("on")
+else print("off");
+if width(p)<>0 then
+  begin print(", surrounded "); print_scaled(width(p));
+  end;
+end
+
+@ @<Display ligature |p|@>=
+begin print_font_and_char(lig_char(p)); print(" (ligature ");
+if subtype(p)>1 then print_char("|");
+font_in_short_display:=font(lig_char(p)); short_display(lig_ptr(p));
+if odd(subtype(p)) then print_char("|");
+print_char(")");
+end
+
+@ @<Display penalty |p|@>=
+begin print_esc("penalty "); print_int(penalty(p));
+if subtype(p)=widow_pena then print("(for \jchrwidowpenalty)")
+else if subtype(p)=kinsoku_pena then print("(for kinsoku)");
+end
+
+@ The |post_break| list of a discretionary node is indicated by a prefixed
+`\.{\char'174}' instead of the `\..' before the |pre_break| list.
+
+@<Display discretionary |p|@>=
+begin print_esc("discretionary");
+if replace_count(p)>0 then
+  begin print(" replacing "); print_int(replace_count(p));
+  end;
+node_list_display(pre_break(p)); {recursive call}
+append_char("|"); show_node_list(post_break(p)); flush_char; {recursive call}
+end
+
+@ @<Display mark |p|@>=
+begin print_esc("mark"); print_mark(mark_ptr(p));
+end
+
+@ @<Display adjustment |p|@>=
+begin print_esc("vadjust"); node_list_display(adjust_ptr(p)); {recursive call}
+end
+
+@ The recursive machinery is started by calling |show_box|.
+@^recursion@>
+
+@p procedure show_box(@!p:pointer);
+begin @<Assign the values |depth_threshold:=show_box_depth| and
+  |breadth_max:=show_box_breadth|@>;
+if breadth_max<=0 then breadth_max:=5;
+if pool_ptr+depth_threshold>=pool_size then
+  depth_threshold:=pool_size-pool_ptr-1;
+  {now there's enough room for prefix string}
+show_node_list(p); {the show starts at |p|}
+print_ln;
+end;
+
+@* \[13] Destroying boxes.
+When we are done with a node list, we are obliged to return it to free
+storage, including all of its sublists. The recursive procedure
+|flush_node_list| does this for us.
+
+@ First, however, we shall consider two non-recursive procedures that do
+simpler tasks. The first of these, |delete_token_ref|, is called when
+a pointer to a token list's reference count is being removed. This means
+that the token list should disappear if the reference count was |null|,
+otherwise the count should be decreased by one.
+@^reference counts@>
+
+@d token_ref_count(#) == info(#) {reference count preceding a token list}
+
+@p procedure delete_token_ref(@!p:pointer); {|p| points to the reference count
+  of a token list that is losing one reference}
+begin if token_ref_count(p)=null then flush_list(p)
+else decr(token_ref_count(p));
+end;
+
+@ Similarly, |delete_glue_ref| is called when a pointer to a glue
+specification is being withdrawn.
+@^reference counts@>
+@d fast_delete_glue_ref(#)==@t@>@;@/
+  begin if glue_ref_count(#)=null then free_node(#,glue_spec_size)
+  else decr(glue_ref_count(#));
+  end
+
+@p procedure delete_glue_ref(@!p:pointer); {|p| points to a glue specification}
+fast_delete_glue_ref(p);
+
+@ Now we are ready to delete any node list, recursively.
+In practice, the nodes deleted are usually charnodes (about 2/3 of the time),
+and they are glue nodes in about half of the remaining cases.
+@^recursion@>
+
+@p procedure flush_node_list(@!p:pointer); {erase list of nodes starting at |p|}
+label done; {go here when node |p| has been freed}
+var q:pointer; {successor to node |p|}
+begin while p<>null do
+@^inner loop@>
+  begin q:=link(p);
+  if is_char_node(p) then free_avail(p)
+  else  begin case type(p) of
+    hlist_node,vlist_node,dir_node,unset_node:
+      begin flush_node_list(list_ptr(p));
+      fast_delete_glue_ref(space_ptr(p));
+      fast_delete_glue_ref(xspace_ptr(p));
+      free_node(p,box_node_size); goto done;
+      end;
+    rule_node: begin free_node(p,rule_node_size); goto done;
+      end;
+    ins_node: begin flush_node_list(ins_ptr(p));
+      delete_glue_ref(split_top_ptr(p));
+      free_node(p,ins_node_size); goto done;
+      end;
+    whatsit_node: @<Wipe out the whatsit node |p| and |goto done|@>;
+    glue_node: begin fast_delete_glue_ref(glue_ptr(p));
+      if leader_ptr(p)<>null then flush_node_list(leader_ptr(p));
+      end;
+    disp_node,
+    kern_node,math_node,penalty_node: do_nothing;
+    ligature_node: flush_node_list(lig_ptr(p));
+    mark_node: delete_token_ref(mark_ptr(p));
+    disc_node: begin flush_node_list(pre_break(p));
+      flush_node_list(post_break(p));
+      end;
+    adjust_node: flush_node_list(adjust_ptr(p));
+    @t\4@>@<Cases of |flush_node_list| that arise in mlists only@>@;
+    othercases confusion("flushing")
+@:this can't happen flushing}{\quad flushing@>
+    endcases;@/
+    free_node(p,small_node_size);
+    done:end;
+  p:=q;
+  end;
+end;
+
+@* \[14] Copying boxes.
+Another recursive operation that acts on boxes is sometimes needed: The
+procedure |copy_node_list| returns a pointer to another node list that has
+the same structure and meaning as the original. Note that since glue
+specifications and token lists have reference counts, we need not make
+copies of them. Reference counts can never get too large to fit in a
+halfword, since each pointer to a node is in a different memory address,
+and the total number of memory addresses fits in a halfword.
+@^recursion@>
+@^reference counts@>
+
+(Well, there actually are also references from outside |mem|; if the
+|save_stack| is made arbitrarily large, it would theoretically be possible
+to break \TeX\ by overflowing a reference count. But who would want to do that?)
+
+@d add_token_ref(#)==incr(token_ref_count(#)) {new reference to a token list}
+@d add_glue_ref(#)==incr(glue_ref_count(#)) {new reference to a glue spec}
+
+@ The copying procedure copies words en masse without bothering
+to look at their individual fields. If the node format changes---for
+example, if the size is altered, or if some link field is moved to another
+relative position---then this code may need to be changed too.
+@^data structure assumptions@>
+
+@p function copy_node_list(@!p:pointer):pointer; {makes a duplicate of the
+  node list that starts at |p| and returns a pointer to the new list}
+var h:pointer; {temporary head of copied list}
+@!q:pointer; {previous position in new list}
+@!r:pointer; {current node being fabricated for new list}
+@!words:0..5; {number of words remaining to be copied}
+begin h:=get_avail; q:=h;
+while p<>null do
+  begin @<Make a copy of node |p| in node |r|@>;
+  link(q):=r; q:=r; p:=link(p);
+  end;
+link(q):=null; q:=link(h); free_avail(h);
+copy_node_list:=q;
+end;
+
+@ @<Make a copy of node |p|...@>=
+words:=1; {this setting occurs in more branches than any other}
+if is_char_node(p) then r:=get_avail
+else @<Case statement to copy different types and set |words| to the number
+  of initial words not yet copied@>;
+while words>0 do
+  begin decr(words); mem[r+words]:=mem[p+words];
+  end
+
+@ @<Case statement to copy...@>=
+case type(p) of
+dir_node,
+hlist_node,vlist_node,unset_node: begin r:=get_node(box_node_size);
+  mem[r+7]:=mem[p+7];
+  mem[r+6]:=mem[p+6]; mem[r+5]:=mem[p+5]; {copy the last three words}
+  add_glue_ref(space_ptr(r)); add_glue_ref(xspace_ptr(r));
+  list_ptr(r):=copy_node_list(list_ptr(p)); {this affects |mem[r+5]|}
+  words:=5;
+  end;
+rule_node: begin r:=get_node(rule_node_size); words:=rule_node_size;
+  end;
+ins_node: begin r:=get_node(ins_node_size);
+  mem[r+5]:=mem[p+5]; mem[r+4]:=mem[p+4];
+  add_glue_ref(split_top_ptr(p));
+  ins_ptr(r):=copy_node_list(ins_ptr(p)); {this affects |mem[r+4]|}
+  words:=ins_node_size-2;
+  end;
+whatsit_node:@<Make a partial copy of the whatsit node |p| and make |r|
+  point to it; set |words| to the number of initial words not yet copied@>;
+glue_node: begin r:=get_node(small_node_size); add_glue_ref(glue_ptr(p));
+  glue_ptr(r):=glue_ptr(p); leader_ptr(r):=copy_node_list(leader_ptr(p));
+  end;
+disp_node,
+kern_node,math_node,penalty_node: begin r:=get_node(small_node_size);
+  words:=small_node_size;
+  end;
+ligature_node: begin r:=get_node(small_node_size);
+  mem[lig_char(r)]:=mem[lig_char(p)]; {copy |font| and |character|}
+  lig_ptr(r):=copy_node_list(lig_ptr(p));
+  end;
+disc_node: begin r:=get_node(small_node_size);
+  pre_break(r):=copy_node_list(pre_break(p));
+  post_break(r):=copy_node_list(post_break(p));
+  end;
+mark_node: begin r:=get_node(small_node_size); add_token_ref(mark_ptr(p));
+  words:=small_node_size;
+  end;
+adjust_node: begin r:=get_node(small_node_size);
+  adjust_ptr(r):=copy_node_list(adjust_ptr(p));
+  end; {|words=1=small_node_size-1|}
+othercases confusion("copying")
+@:this can't happen copying}{\quad copying@>
+endcases
+
+@* \[15] The command codes.
+Before we can go any further, we need to define symbolic names for the internal
+code numbers that represent the various commands obeyed by \TeX. These codes
+are somewhat arbitrary, but not completely so. For example, the command
+codes for character types are fixed by the language, since a user says,
+e.g., `\.{\\catcode \`\\\${} = 3}' to make \.{\char'44} a math delimiter,
+and the command code |math_shift| is equal to~3. Some other codes have
+been made adjacent so that |case| statements in the program need not consider
+cases that are widely spaced, or so that |case| statements can be replaced
+by |if| statements.
+
+At any rate, here is the list, for future reference. First come the
+``catcode'' commands, several of which share their numeric codes with
+ordinary commands when the catcode cannot emerge from \TeX's scanning routine.
+
+@d escape=0 {escape delimiter (called \.\\ in {\sl The \TeX book\/})}
+@:TeXbook}{\sl The \TeX book@>
+@d relax=0 {do nothing ( \.{\\relax} )}
+@d left_brace=1 {beginning of a group ( \.\{ )}
+@d right_brace=2 {ending of a group ( \.\} )}
+@d math_shift=3 {mathematics shift character ( \.\$ )}
+@d tab_mark=4 {alignment delimiter ( \.\&, \.{\\span} )}
+@d car_ret=5 {end of line ( |carriage_return|, \.{\\cr}, \.{\\crcr} )}
+@d out_param=5 {output a macro parameter}
+@d mac_param=6 {macro parameter symbol ( \.\# )}
+@d sup_mark=7 {superscript ( \.{\char'136} )}
+@d sub_mark=8 {subscript ( \.{\char'137} )}
+@d ignore=9 {characters to ignore ( \.{\^\^@@} )}
+@d endv=9 {end of \<v_j> list in alignment template}
+@d spacer=10 {characters equivalent to blank space ( \.{\ } )}
+@d letter=11 {characters regarded as letters ( \.{A..Z}, \.{a..z} )}
+@d other_char=12 {none of the special character types}
+@d active_char=13 {characters that invoke macros ( \.{\char`\~} )}
+@d par_end=13 {end of paragraph ( \.{\\par} )}
+@d match=13 {match a macro parameter}
+@d comment=14 {characters that introduce comments ( \.\% )}
+@d end_match=14 {end of parameters to macro}
+@d stop=14 {end of job ( \.{\\end}, \.{\\dump} )}
+@d invalid_char=15 {characters that shouldn't appear ( \.{\^\^?} )}
+@d delim_num=15 {specify delimiter numerically ( \.{\\delimiter} )}
+@d kanji=16 {kanji}
+@d kana=17 {hiragana, katakana, alphabet}
+@d other_kchar=18 {kanji codes}
+@d max_char_code=18 {largest catcode for individual characters}
+
+@ Next are the ordinary run-of-the-mill command codes.  Codes that are
+|min_internal| or more represent internal quantities that might be
+expanded by `\.{\\the}'.
+
+@d char_num=max_char_code+1 {character specified numerically ( \.{\\char} )}
+@d math_char_num=char_num+1 {explicit math code ( \.{\\mathchar} )}
+@d mark=math_char_num+1 {mark definition ( \.{\\mark} )}
+@d xray=mark+1 {peek inside of \TeX\ ( \.{\\show}, \.{\\showbox}, etc.~)}
+@d make_box=xray+1 {make a box ( \.{\\box}, \.{\\copy}, \.{\\hbox}, etc.~)}
+@d hmove=make_box+1 {horizontal motion ( \.{\\moveleft}, \.{\\moveright} )}
+@d vmove=hmove+1 {vertical motion ( \.{\\raise}, \.{\\lower} )}
+@d un_hbox=vmove+1 {unglue a box ( \.{\\unhbox}, \.{\\unhcopy} )}
+@d un_vbox=un_hbox+1 {unglue a box ( \.{\\unvbox}, \.{\\unvcopy} )}
+@d remove_item=un_vbox+1 {nullify last item ( \.{\\unpenalty},
+  \.{\\unkern}, \.{\\unskip} )}
+@d hskip=remove_item+1 {horizontal glue ( \.{\\hskip}, \.{\\hfil}, etc.~)}
+@d vskip=hskip+1 {vertical glue ( \.{\\vskip}, \.{\\vfil}, etc.~)}
+@d mskip=vskip+1 {math glue ( \.{\\mskip} )}
+@d kern=mskip+1 {fixed space ( \.{\\kern})}
+@d mkern=kern+1 {math kern ( \.{\\mkern} )}
+@d leader_ship=mkern+1 {use a box ( \.{\\shipout}, \.{\\leaders}, etc.~)}
+@d halign=leader_ship+1 {horizontal table alignment ( \.{\\halign} )}
+@d valign=halign+1 {vertical table alignment ( \.{\\valign} )}
+@d no_align=valign+1 {temporary escape from alignment ( \.{\\noalign} )}
+@d vrule=no_align+1 {vertical rule ( \.{\\vrule} )}
+@d hrule=vrule+1 {horizontal rule ( \.{\\hrule} )}
+@d insert=hrule+1 {vlist inserted in box ( \.{\\insert} )}
+@d vadjust=insert+1 {vlist inserted in enclosing paragraph ( \.{\\vadjust} )}
+@d ignore_spaces=vadjust+1 {gobble |spacer| tokens ( \.{\\ignorespaces} )}
+@d after_assignment=ignore_spaces+1 {save till assignment is done ( \.{\\afterassignment} )}
+@d after_group=after_assignment+1 {save till group is done ( \.{\\aftergroup} )}
+@d break_penalty=after_group+1 {additional badness ( \.{\\penalty} )}
+@d start_par=break_penalty+1 {begin paragraph ( \.{\\indent}, \.{\\noindent} )}
+@d ital_corr=start_par+1 {italic correction ( \.{\\/} )}
+@d accent=ital_corr+1 {attach accent in text ( \.{\\accent} )}
+@d math_accent=accent+1 {attach accent in math ( \.{\\mathaccent} )}
+@d discretionary=math_accent+1 {discretionary texts ( \.{\\-}, \.{\\discretionary} )}
+@d eq_no=discretionary+1 {equation number ( \.{\\eqno}, \.{\\leqno} )}
+@d left_right=eq_no+1 {variable delimiter ( \.{\\left}, \.{\\right} )}
+@d math_comp=left_right+1 {component of formula ( \.{\\mathbin}, etc.~)}
+@d limit_switch=math_comp+1 {diddle limit conventions ( \.{\\displaylimits}, etc.~)}
+@d above=limit_switch+1 {generalized fraction ( \.{\\above}, \.{\\atop}, etc.~)}
+@d math_style=above+1 {style specification ( \.{\\displaystyle}, etc.~)}
+@d math_choice=math_style+1 {choice specification ( \.{\\mathchoice} )}
+@d non_script=math_choice+1 {conditional math glue ( \.{\\nonscript} )}
+@d vcenter=non_script+1 {vertically center a vbox ( \.{\\vcenter} )}
+@d case_shift=vcenter+1 {force specific case ( \.{\\lowercase}, \.{\\uppercase}~)}
+@d message=case_shift+1 {send to user ( \.{\\message}, \.{\\errmessage} )}
+@d extension=message+1 {extensions to \TeX\ ( \.{\\write}, \.{\\special}, etc.~)}
+@d in_stream=extension+1 {files for reading ( \.{\\openin}, \.{\\closein} )}
+@d begin_group=in_stream+1 {begin local grouping ( \.{\\begingroup} )}
+@d end_group=begin_group+1 {end local grouping ( \.{\\endgroup} )}
+@d omit=end_group+1 {omit alignment template ( \.{\\omit} )}
+@d ex_space=omit+1 {explicit space ( \.{\\\ } )}
+@d no_boundary=ex_space+1 {suppress boundary ligatures ( \.{\\noboundary} )}
+@d radical=no_boundary+1 {square root and similar signs ( \.{\\radical} )}
+@d end_cs_name=radical+1 {end control sequence ( \.{\\endcsname} )}
+@d min_internal=end_cs_name+1 {the smallest code that can follow \.{\\the}}
+@d char_given=min_internal {character code defined by \.{\\chardef}}
+@d math_given=char_given+1 {math code defined by \.{\\mathchardef}}
+@d last_item=math_given+1 {most recent item ( \.{\\lastpenalty},
+  \.{\\lastkern}, \.{\\lastskip} )}
+@d inhibit_glue=last_item+1 {inhibit adjust glue ( \.{\\inhibitglue} )}
+@d chg_dir=inhibit_glue+1 {change dir mode by \.{\\tate}, \.{\\yoko}}
+@d max_non_prefixed_command=chg_dir {largest command code that can't be \.{\\global}}
+
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+@d toks_register=max_non_prefixed_command+1 {token list register ( \.{\\toks} )}
+@d assign_toks=toks_register+1
+  {special token list ( \.{\\output}, \.{\\everypar}, etc.~)}
+@d assign_int=assign_toks+1
+  {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)}
+@d assign_dimen=assign_int+1 {user-defined length ( \.{\\hsize}, etc.~)}
+@d assign_glue=assign_dimen+1 {user-defined glue ( \.{\\baselineskip}, etc.~)}
+@d assign_mu_glue=assign_glue+1 {user-defined muglue ( \.{\\thinmuskip}, etc.~)}
+@d assign_font_dimen=assign_mu_glue+1
+  {user-defined font dimension ( \.{\\fontdimen} )}
+@d assign_font_int=assign_font_dimen+1
+  {user-defined font integer ( \.{\\hyphenchar}, \.{\\skewchar} )}
+@d assign_kinsoku=assign_font_int+1
+  {user-defined kinsoku character ( \.{\\prebreakpenalty},
+   \.{\\postbreakpenalty} )}
+@d assign_inhibit_xsp_code=assign_kinsoku+1
+  {user-defined inhibit xsp character ( \.{\\inhibitxspcode} )}
+@d set_kansuji_char=assign_inhibit_xsp_code+1
+  {user-defined kansuji character ( \.{\\kansujichar} )}
+@d set_aux=set_kansuji_char+1
+  {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )}
+@d set_prev_graf=set_aux+1 {specify state info ( \.{\\prevgraf} )}
+@d set_page_dimen=set_prev_graf+1 {specify state info ( \.{\\pagegoal}, etc.~)}
+@d set_page_int=set_page_dimen+1 {specify state info ( \.{\\deadcycles},
+  \.{\\insertpenalties} )}
+@d set_box_dimen=set_page_int+1 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )}
+@d set_shape=set_box_dimen+1 {specify fancy paragraph shape ( \.{\\parshape} )}
+@d def_code=set_shape+1 {define a character code ( \.{\\catcode}, etc.~)}
+@d def_family=def_code+1 {declare math fonts ( \.{\\textfont}, etc.~)}
+@d set_font=def_family+1 {set current font ( font identifiers )}
+@d def_font=set_font+1 {define a font file ( \.{\\font} )}
+@d def_jfont=def_font+1 {define a font file ( \.{\\jfont} )}
+@d def_tfont=def_jfont+1 {define a font file ( \.{\\tfont} )}
+@d register=def_tfont+1 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
+@d max_internal=register {the largest code that can follow \.{\\the}}
+@d advance=max_internal+1 {advance a register or parameter ( \.{\\advance} )}
+@d multiply=advance+1 {multiply a register or parameter ( \.{\\multiply} )}
+@d divide=multiply+1 {divide a register or parameter ( \.{\\divide} )}
+@d prefix=divide+1 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
+@d let=prefix+1 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
+@d shorthand_def=let+1 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
+  {or \.{\\charsubdef}}
+@d read_to_cs=shorthand_def+1 {read into a control sequence ( \.{\\read} )}
+@d def=read_to_cs+1 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
+@d set_box=def+1 {set a box ( \.{\\setbox} )}
+@d hyph_data=set_box+1 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
+@d set_interaction=hyph_data+1 {define level of interaction ( \.{\\batchmode}, etc.~)}
+@d set_auto_spacing=set_interaction+1 {set auto spaceing mode
+  ( \.{\\autospacing}, \.{\\noautospacing}, ( \.{\\autoxspacing}, \.{\\noautoxspacing} )}
+@d max_command=set_auto_spacing {the largest command code seen at |big_switch|}
+
+@ The remaining command codes are extra special, since they cannot get through
+\TeX's scanner to the main control routine. They have been given values higher
+than |max_command| so that their special nature is easily discernible.
+The ``expandable'' commands come first.
+
+@d undefined_cs=max_command+1 {initial state of most |eq_type| fields}
+@d expand_after=max_command+2 {special expansion ( \.{\\expandafter} )}
+@d no_expand=max_command+3 {special nonexpansion ( \.{\\noexpand} )}
+@d input=max_command+4 {input a source file ( \.{\\input}, \.{\\endinput} )}
+@d if_test=max_command+5 {conditional text ( \.{\\if}, \.{\\ifcase}, etc.~)}
+@d fi_or_else=max_command+6 {delimiters for conditionals ( \.{\\else}, etc.~)}
+@d cs_name=max_command+7 {make a control sequence from tokens ( \.{\\csname} )}
+@d convert=max_command+8 {convert to text ( \.{\\number}, \.{\\string}, etc.~)}
+@d the=max_command+9 {expand an internal quantity ( \.{\\the} )}
+@d top_bot_mark=max_command+10 {inserted mark ( \.{\\topmark}, etc.~)}
+@d call=max_command+11 {non-long, non-outer control sequence}
+@d long_call=max_command+12 {long, non-outer control sequence}
+@d outer_call=max_command+13 {non-long, outer control sequence}
+@d long_outer_call=max_command+14 {long, outer control sequence}
+@d end_template=max_command+15 {end of an alignment template}
+@d dont_expand=max_command+16 {the following token was marked by \.{\\noexpand}}
+@d glue_ref=max_command+17 {the equivalent points to a glue specification}
+@d shape_ref=max_command+18 {the equivalent points to a parshape specification}
+@d box_ref=max_command+19 {the equivalent points to a box node, or is |null|}
+@d data=max_command+20 {the equivalent is simply a halfword number}
+
+@* \[16] The semantic nest.
+\TeX\ is typically in the midst of building many lists at once. For example,
+when a math formula is being processed, \TeX\ is in math mode and
+working on an mlist; this formula has temporarily interrupted \TeX\ from
+being in horizontal mode and building the hlist of a paragraph; and this
+paragraph has temporarily interrupted \TeX\ from being in vertical mode
+and building the vlist for the next page of a document. Similarly, when a
+\.{\\vbox} occurs inside of an \.{\\hbox}, \TeX\ is temporarily
+interrupted from working in restricted horizontal mode, and it enters
+internal vertical mode.  The ``semantic nest'' is a stack that
+keeps track of what lists and modes are currently suspended.
+
+At each level of processing we are in one of six modes:
+
+\yskip\hang|vmode| stands for vertical mode (the page builder);
+
+\hang|hmode| stands for horizontal mode (the paragraph builder);
+
+\hang|mmode| stands for displayed formula mode;
+
+\hang|-vmode| stands for internal vertical mode (e.g., in a \.{\\vbox});
+
+\hang|-hmode| stands for restricted horizontal mode (e.g., in an \.{\\hbox});
+
+\hang|-mmode| stands for math formula mode (not displayed).
+
+\yskip\noindent The mode is temporarily set to zero while processing \.{\\write}
+texts in the |ship_out| routine.
+
+Numeric values are assigned to |vmode|, |hmode|, and |mmode| so that
+\TeX's ``big semantic switch'' can select the appropriate thing to
+do by computing the value |abs(mode)+cur_cmd|, where |mode| is the current
+mode and |cur_cmd| is the current command code.
+
+@d vmode=1 {vertical mode}
+@d hmode=vmode+max_command+1 {horizontal mode}
+@d mmode=hmode+max_command+1 {math mode}
+
+@p procedure print_mode(@!m:integer); {prints the mode represented by |m|}
+begin if m>0 then
+  case m div (max_command+1) of
+  0:print("vertical mode");
+  1:print("horizontal mode");
+  2:print("display math mode");
+  end
+else if m=0 then print("no mode")
+else  case (-m) div (max_command+1) of
+  0:print("internal vertical mode");
+  1:print("restricted horizontal mode");
+  2:print("math mode");
+  end;
+end;
+
+procedure print_in_mode(@!m:integer); {prints the mode represented by |m|}
+begin if m>0 then
+  case m div (max_command+1) of
+  0:print("' in vertical mode");
+  1:print("' in horizontal mode");
+  2:print("' in display math mode");
+  end
+else if m=0 then print("' in no mode")
+else  case (-m) div (max_command+1) of
+  0:print("' in internal vertical mode");
+  1:print("' in restricted horizontal mode");
+  2:print("' in math mode");
+  end;
+end;
+
+@ The state of affairs at any semantic level can be represented by
+five values:
+
+\yskip\hang|mode| is the number representing the semantic mode, as
+just explained.
+
+\yskip\hang|head| is a |pointer| to a list head for the list being built;
+|link(head)| therefore points to the first element of the list, or
+to |null| if the list is empty.
+
+\yskip\hang|tail| is a |pointer| to the final node of the list being
+built; thus, |tail=head| if and only if the list is empty.
+
+\yskip\hang|prev_graf| is the number of lines of the current paragraph that
+have already been put into the present vertical list.
+
+\yskip\hang|aux| is an auxiliary |memory_word| that gives further information
+that is needed to characterize the situation.
+
+\yskip\noindent
+In vertical mode, |aux| is also known as |prev_depth|; it is the scaled
+value representing the depth of the previous box, for use in baseline
+calculations, or it is |<=-1000|pt if the next box on the vertical list is to
+be exempt from baseline calculations.  In horizontal mode, |aux| is also
+known as |space_factor| and |clang|; it holds the current space factor used in
+spacing calculations, and the current language used for hyphenation.
+(The value of |clang| is undefined in restricted horizontal mode.)
+In math mode, |aux| is also known as |incompleat_noad|; if
+not |null|, it points to a record that represents the numerator of a
+generalized fraction for which the denominator is currently being formed
+in the current list.
+
+There is also a sixth quantity, |mode_line|, which correlates
+the semantic nest with the user's input; |mode_line| contains the source
+line number at which the current level of nesting was entered. The negative
+of this line number is the |mode_line| at the level of the
+user's output routine.
+
+In horizontal mode, the |prev_graf| field is used for initial language data.
+
+The semantic nest is an array called |nest| that holds the |mode|, |head|,
+|tail|, |prev_graf|, |aux|, and |mode_line| values for all semantic levels
+below the currently active one. Information about the currently active
+level is kept in the global quantities |mode|, |head|, |tail|, |prev_graf|,
+|aux|, and |mode_line|, which live in a \PASCAL\ record that is ready to
+be pushed onto |nest| if necessary.
+
+@d ignore_depth==-65536000 {|prev_depth| value that is ignored}
+
+@<Types...@>=
+@!list_state_record=record@!mode_field:-mmode..mmode;@+
+  @!dir_field,@!adj_dir_field: -dir_yoko..dir_yoko;
+  @!pdisp_field: scaled;
+  @!head_field,@!tail_field,@!pnode_field,@!last_jchr_field: pointer;
+  @!pg_field,@!ml_field: integer;@+
+  @!aux_field: memory_word;
+  end;
+
+@ @d mode==cur_list.mode_field {current mode}
+@d direction==cur_list.dir_field {current direction}
+@d adjust_dir==cur_list.adj_dir_field {current adjust direction}
+@d head==cur_list.head_field {header node of current list}
+@d tail==cur_list.tail_field {final node on current list}
+@d prev_node==cur_list.pnode_field {previous to last |disp_node|}
+@d prev_disp==cur_list.pdisp_field {displacemant at |prev_node|}
+@d last_jchr==cur_list.last_jchr_field {final jchar node on current list}
+@d prev_graf==cur_list.pg_field {number of paragraph lines accumulated}
+@d aux==cur_list.aux_field {auxiliary data about the current list}
+@d prev_depth==aux.sc {the name of |aux| in vertical mode}
+@d space_factor==aux.hh.lh {part of |aux| in horizontal mode}
+@d clang==aux.hh.rh {the other part of |aux| in horizontal mode}
+@d incompleat_noad==aux.int {the name of |aux| in math mode}
+@d mode_line==cur_list.ml_field {source file line number at beginning of list}
+
+@<Glob...@>=
+@!nest:^list_state_record;
+@!nest_ptr:0..nest_size; {first unused location of |nest|}
+@!max_nest_stack:0..nest_size; {maximum of |nest_ptr| when pushing}
+@!cur_list:list_state_record; {the ``top'' semantic state}
+@!shown_mode:-mmode..mmode; {most recent mode shown by \.{\\tracingcommands}}
+
+@ Here is a common way to make the current list grow:
+
+@d tail_append(#)==begin link(tail):=#; tail:=link(tail);
+  end
+@d prev_append(#)==begin link(prev_node):=#;
+  link(link(prev_node)):=tail; prev_node:=link(prev_node);
+  end
+
+@ We will see later that the vertical list at the bottom semantic level is split
+into two parts; the ``current page'' runs from |page_head| to |page_tail|,
+and the ``contribution list'' runs from |contrib_head| to |tail| of
+semantic level zero. The idea is that contributions are first formed in
+vertical mode, then ``contributed'' to the current page (during which time
+the page-breaking decisions are made). For now, we don't need to know
+any more details about the page-building process.
+
+@<Set init...@>=
+nest_ptr:=0; max_nest_stack:=0;
+mode:=vmode; head:=contrib_head; tail:=contrib_head; prev_node:=tail;
+direction:=dir_yoko; adjust_dir:=direction; prev_disp:=0; last_jchr:=null;
+prev_depth:=ignore_depth; mode_line:=0;
+prev_graf:=0; shown_mode:=0;
+@/{The following piece of code is a copy of module 991:}
+page_contents:=empty; page_tail:=page_head; {|link(page_head):=null;|}@/
+last_glue:=max_halfword; last_penalty:=0; last_kern:=0;
+page_depth:=0; page_max_depth:=0;
+
+@ When \TeX's work on one level is interrupted, the state is saved by
+calling |push_nest|. This routine changes |head| and |tail| so that
+a new (empty) list is begun; it does not change |mode| or |aux|.
+
+@p procedure push_nest; {enter a new semantic level, save the old}
+begin if nest_ptr>max_nest_stack then
+  begin max_nest_stack:=nest_ptr;
+  if nest_ptr=nest_size then overflow("semantic nest size",nest_size);
+@:TeX capacity exceeded semantic nest size}{\quad semantic nest size@>
+  end;
+nest[nest_ptr]:=cur_list; {stack the record}
+incr(nest_ptr); head:=new_null_box; tail:=head; prev_node:=tail;
+prev_graf:=0; prev_disp:=0; last_jchr:=null; mode_line:=line;
+end;
+
+@ Conversely, when \TeX\ is finished on the current level, the former
+state is restored by calling |pop_nest|. This routine will never be
+called at the lowest semantic level, nor will it be called unless |head|
+is a node that should be returned to free memory.
+
+@p procedure pop_nest; {leave a semantic level, re-enter the old}
+begin
+fast_delete_glue_ref(space_ptr(head)); fast_delete_glue_ref(xspace_ptr(head));
+free_node(head,box_node_size); decr(nest_ptr); cur_list:=nest[nest_ptr];
+end;
+
+@ Here is a procedure that displays what \TeX\ is working on, at all levels.
+
+@p procedure@?print_totals; forward;@t\2@>
+procedure show_activities;
+var p:0..nest_size; {index into |nest|}
+@!m:-mmode..mmode; {mode}
+@!a:memory_word; {auxiliary}
+@!q,@!r:pointer; {for showing the current page}
+@!t:integer; {ditto}
+begin nest[nest_ptr]:=cur_list; {put the top level into the array}
+print_nl(""); print_ln;
+for p:=nest_ptr downto 0 do
+  begin m:=nest[p].mode_field; a:=nest[p].aux_field;
+  print_nl("### "); print_direction(nest[p].dir_field);
+  print(", "); print_mode(m);
+  print(" entered at line "); print_int(abs(nest[p].ml_field));
+  if m=hmode then if nest[p].pg_field <> @'40600000 then
+    begin print(" (language"); print_int(nest[p].pg_field mod @'200000);
+    print(":hyphenmin"); print_int(nest[p].pg_field div @'20000000);
+    print_char(","); print_int((nest[p].pg_field div @'200000) mod @'100);
+    print_char(")");
+    end;
+  if nest[p].ml_field<0 then print(" (\output routine)");
+  if p=0 then
+    begin @<Show the status of the current page@>;
+    if link(contrib_head)<>null then
+      print_nl("### recent contributions:");
+    end;
+  show_box(link(nest[p].head_field));
+  @<Show the auxiliary field, |a|@>;
+  end;
+end;
+
+@ @<Show the auxiliary...@>=
+case abs(m) div (max_command+1) of
+0: begin print_nl("prevdepth ");
+  if a.sc<=ignore_depth then print("ignored")
+  else print_scaled(a.sc);
+  if nest[p].pg_field<>0 then
+    begin print(", prevgraf ");
+    print_int(nest[p].pg_field);
+    if nest[p].pg_field<>1 then print(" lines")
+    else print(" line");
+    end;
+  end;
+1: begin print_nl("spacefactor "); print_int(a.hh.lh);
+  if m>0 then@+ if a.hh.rh>0 then
+    begin print(", current language "); print_int(a.hh.rh);@+
+    end;
+  end;
+2: if a.int<>null then
+  begin print("this will be denominator of:"); show_box(a.int);@+
+  end;
+end {there are no other cases}
+
+@* \[17] The table of equivalents.
+Now that we have studied the data structures for \TeX's semantic routines,
+we ought to consider the data structures used by its syntactic routines. In
+other words, our next concern will be
+the tables that \TeX\ looks at when it is scanning
+what the user has written.
+
+The biggest and most important such table is called |eqtb|. It holds the
+current ``equivalents'' of things; i.e., it explains what things mean
+or what their current values are, for all quantities that are subject to
+the nesting structure provided by \TeX's grouping mechanism. There are six
+parts to |eqtb|:
+
+\yskip\hangg 1) |eqtb[active_base..(hash_base-1)]| holds the current
+equivalents of single-character control sequences.
+
+\yskip\hangg 2) |eqtb[hash_base..(glue_base-1)]| holds the current
+equivalents of multiletter control sequences.
+
+\yskip\hangg 3) |eqtb[glue_base..(local_base-1)]| holds the current
+equivalents of glue parameters like the current baselineskip.
+
+\yskip\hangg 4) |eqtb[local_base..(int_base-1)]| holds the current
+equivalents of local halfword quantities like the current box registers,
+the current ``catcodes,'' the current font, and a pointer to the current
+paragraph shape.
+Additionally region~4 contains the table with ML\TeX's character
+substitution definitions.
+
+\yskip\hangg 5) |eqtb[int_base..(dimen_base-1)]| holds the current
+equivalents of fullword integer parameters like the current hyphenation
+penalty.
+
+\yskip\hangg 6) |eqtb[dimen_base..eqtb_size]| holds the current equivalents
+of fullword dimension parameters like the current hsize or amount of
+hanging indentation.
+
+\yskip\noindent Note that, for example, the current amount of
+baselineskip glue is determined by the setting of a particular location
+in region~3 of |eqtb|, while the current meaning of the control sequence
+`\.{\\baselineskip}' (which might have been changed by \.{\\def} or
+\.{\\let}) appears in region~2.
+
+@ Each entry in |eqtb| is a |memory_word|. Most of these words are of type
+|two_halves|, and subdivided into three fields:
+
+\yskip\hangg 1) The |eq_level| (a quarterword) is the level of grouping at
+which this equivalent was defined. If the level is |level_zero|, the
+equivalent has never been defined; |level_one| refers to the outer level
+(outside of all groups), and this level is also used for global
+definitions that never go away. Higher levels are for equivalents that
+will disappear at the end of their group.  @^global definitions@>
+
+\yskip\hangg 2) The |eq_type| (another quarterword) specifies what kind of
+entry this is. There are many types, since each \TeX\ primitive like
+\.{\\hbox}, \.{\\def}, etc., has its own special code. The list of
+command codes above includes all possible settings of the |eq_type| field.
+
+\yskip\hangg 3) The |equiv| (a halfword) is the current equivalent value.
+This may be a font number, a pointer into |mem|, or a variety of other
+things.
+
+@d eq_level_field(#)==#.hh.b1
+@d eq_type_field(#)==#.hh.b0
+@d equiv_field(#)==#.hh.rh
+@d eq_level(#)==eq_level_field(eqtb[#]) {level of definition}
+@d eq_type(#)==eq_type_field(eqtb[#]) {command code for equivalent}
+@d equiv(#)==equiv_field(eqtb[#]) {equivalent value}
+@d level_zero=min_quarterword {level for undefined quantities}
+@d level_one=level_zero+1 {outermost level for defined quantities}
+
+@ Many locations in |eqtb| have symbolic names. The purpose of the next
+paragraphs is to define these names, and to set up the initial values of the
+equivalents.
+
+In the first region we have 256 equivalents for ``active characters'' that
+act as control sequences, followed by 256 equivalents for single-character
+control sequences.
+
+Then comes region~2, which corresponds to the hash table that we will
+define later.  The maximum address in this region is used for a dummy
+control sequence that is perpetually undefined. There also are several
+locations for control sequences that are perpetually defined
+(since they are used in error recovery).
+
+@d active_base=1 {beginning of region 1, for active character equivalents}
+@d single_base=active_base+256 {equivalents of one-character control sequences}
+@d null_cs=single_base+256 {equivalent of \.{\\csname\\endcsname}}
+@d hash_base=null_cs+1 {beginning of region 2, for the hash table}
+@d frozen_control_sequence=hash_base+hash_size {for error recovery}
+@d frozen_protection=frozen_control_sequence {inaccessible but definable}
+@d frozen_cr=frozen_control_sequence+1 {permanent `\.{\\cr}'}
+@d frozen_end_group=frozen_control_sequence+2 {permanent `\.{\\endgroup}'}
+@d frozen_right=frozen_control_sequence+3 {permanent `\.{\\right}'}
+@d frozen_fi=frozen_control_sequence+4 {permanent `\.{\\fi}'}
+@d frozen_end_template=frozen_control_sequence+5 {permanent `\.{\\endtemplate}'}
+@d frozen_endv=frozen_control_sequence+6 {second permanent `\.{\\endtemplate}'}
+@d frozen_relax=frozen_control_sequence+7 {permanent `\.{\\relax}'}
+@d end_write=frozen_control_sequence+8 {permanent `\.{\\endwrite}'}
+@d frozen_dont_expand=frozen_control_sequence+9
+  {permanent `\.{\\notexpanded:}'}
+@d frozen_special=frozen_control_sequence+10
+  {permanent `\.{\\special}'}
+@d frozen_null_font=frozen_control_sequence+11
+  {permanent `\.{\\nullfont}'}
+@d font_id_base=frozen_null_font-font_base
+  {begins table of 257 permanent font identifiers}
+@d undefined_control_sequence=frozen_null_font+max_font_max+1 {dummy location}
+@d glue_base=undefined_control_sequence+1 {beginning of region 3}
+
+@<Initialize table entries...@>=
+eq_type(undefined_control_sequence):=undefined_cs;
+equiv(undefined_control_sequence):=null;
+eq_level(undefined_control_sequence):=level_zero;
+for k:=active_base to eqtb_top do
+  eqtb[k]:=eqtb[undefined_control_sequence];
+
+@ Here is a routine that displays the current meaning of an |eqtb| entry
+in region 1 or~2. (Similar routines for the other regions will appear
+below.)
+
+@<Show equivalent |n|, in region 1 or 2@>=
+begin sprint_cs(n); print_char("="); print_cmd_chr(eq_type(n),equiv(n));
+if eq_type(n)>=call then
+  begin print_char(":"); show_token_list(link(equiv(n)),null,32);
+  end;
+end
+
+@ Region 3 of |eqtb| contains the 256 \.{\\skip} registers, as well as the
+glue parameters defined here. It is important that the ``muskip''
+parameters have larger numbers than the others.
+
+@d line_skip_code=0 {interline glue if |baseline_skip| is infeasible}
+@d baseline_skip_code=1 {desired glue between baselines}
+@d par_skip_code=2 {extra glue just above a paragraph}
+@d above_display_skip_code=3 {extra glue just above displayed math}
+@d below_display_skip_code=4 {extra glue just below displayed math}
+@d above_display_short_skip_code=5
+  {glue above displayed math following short lines}
+@d below_display_short_skip_code=6
+  {glue below displayed math following short lines}
+@d left_skip_code=7 {glue at left of justified lines}
+@d right_skip_code=8 {glue at right of justified lines}
+@d top_skip_code=9 {glue at top of main pages}
+@d split_top_skip_code=10 {glue at top of split pages}
+@d tab_skip_code=11 {glue between aligned entries}
+@d space_skip_code=12 {glue between words (if not |zero_glue|)}
+@d xspace_skip_code=13 {glue after sentences (if not |zero_glue|)}
+@d par_fill_skip_code=14 {glue on last line of paragraph}
+@d kanji_skip_code=15 {between kanji-kanji space}
+@d xkanji_skip_code=16 {between latin-kanji or kanji-latin space}
+@d thin_mu_skip_code=17 {thin space in math formula}
+@d med_mu_skip_code=18 {medium space in math formula}
+@d thick_mu_skip_code=19 {thick space in math formula}
+@d jfm_skip=20 {space refer from JFM}
+@d glue_pars=21 {total number of glue parameters}
+@d skip_base=glue_base+glue_pars {table of 256 ``skip'' registers}
+@d mu_skip_base=skip_base+256 {table of 256 ``muskip'' registers}
+@d local_base=mu_skip_base+256 {beginning of region 4}
+@#
+@d skip(#)==equiv(skip_base+#) {|mem| location of glue specification}
+@d mu_skip(#)==equiv(mu_skip_base+#) {|mem| location of math glue spec}
+@d glue_par(#)==equiv(glue_base+#) {|mem| location of glue specification}
+@d line_skip==glue_par(line_skip_code)
+@d baseline_skip==glue_par(baseline_skip_code)
+@d par_skip==glue_par(par_skip_code)
+@d above_display_skip==glue_par(above_display_skip_code)
+@d below_display_skip==glue_par(below_display_skip_code)
+@d above_display_short_skip==glue_par(above_display_short_skip_code)
+@d below_display_short_skip==glue_par(below_display_short_skip_code)
+@d left_skip==glue_par(left_skip_code)
+@d right_skip==glue_par(right_skip_code)
+@d top_skip==glue_par(top_skip_code)
+@d split_top_skip==glue_par(split_top_skip_code)
+@d tab_skip==glue_par(tab_skip_code)
+@d space_skip==glue_par(space_skip_code)
+@d xspace_skip==glue_par(xspace_skip_code)
+@d par_fill_skip==glue_par(par_fill_skip_code)
+@d thin_mu_skip==glue_par(thin_mu_skip_code)
+@d med_mu_skip==glue_par(med_mu_skip_code)
+@d thick_mu_skip==glue_par(thick_mu_skip_code)
+@d kanji_skip==glue_par(kanji_skip_code)
+@d xkanji_skip==glue_par(xkanji_skip_code)
+
+@<Current |mem| equivalent of glue parameter number |n|@>=glue_par(n)
+
+@ Sometimes we need to convert \TeX's internal code numbers into symbolic
+form. The |print_skip_param| routine gives the symbolic name of a glue
+parameter.
+
+@<Declare the procedure called |print_skip_param|@>=
+procedure print_skip_param(@!n:integer);
+begin case n of
+line_skip_code: print_esc("lineskip");
+baseline_skip_code: print_esc("baselineskip");
+par_skip_code: print_esc("parskip");
+above_display_skip_code: print_esc("abovedisplayskip");
+below_display_skip_code: print_esc("belowdisplayskip");
+above_display_short_skip_code: print_esc("abovedisplayshortskip");
+below_display_short_skip_code: print_esc("belowdisplayshortskip");
+left_skip_code: print_esc("leftskip");
+right_skip_code: print_esc("rightskip");
+top_skip_code: print_esc("topskip");
+split_top_skip_code: print_esc("splittopskip");
+tab_skip_code: print_esc("tabskip");
+space_skip_code: print_esc("spaceskip");
+xspace_skip_code: print_esc("xspaceskip");
+par_fill_skip_code: print_esc("parfillskip");
+thin_mu_skip_code: print_esc("thinmuskip");
+med_mu_skip_code: print_esc("medmuskip");
+thick_mu_skip_code: print_esc("thickmuskip");
+kanji_skip_code: print_esc("kanjiskip");
+xkanji_skip_code: print_esc("xkanjiskip");
+jfm_skip: print("refer from jfm");
+othercases print("[unknown glue parameter!]")
+endcases;
+end;
+
+@ The symbolic names for glue parameters are put into \TeX's hash table
+by using the routine called |primitive|, defined below. Let us enter them
+now, so that we don't have to list all those parameter names anywhere else.
+
+@<Put each of \TeX's primitives into the hash table@>=
+primitive("lineskip",assign_glue,glue_base+line_skip_code);@/
+@!@:line_skip_}{\.{\\lineskip} primitive@>
+primitive("baselineskip",assign_glue,glue_base+baseline_skip_code);@/
+@!@:baseline_skip_}{\.{\\baselineskip} primitive@>
+primitive("parskip",assign_glue,glue_base+par_skip_code);@/
+@!@:par_skip_}{\.{\\parskip} primitive@>
+primitive("abovedisplayskip",assign_glue,glue_base+above_display_skip_code);@/
+@!@:above_display_skip_}{\.{\\abovedisplayskip} primitive@>
+primitive("belowdisplayskip",assign_glue,glue_base+below_display_skip_code);@/
+@!@:below_display_skip_}{\.{\\belowdisplayskip} primitive@>
+primitive("abovedisplayshortskip",
+  assign_glue,glue_base+above_display_short_skip_code);@/
+@!@:above_display_short_skip_}{\.{\\abovedisplayshortskip} primitive@>
+primitive("belowdisplayshortskip",
+  assign_glue,glue_base+below_display_short_skip_code);@/
+@!@:below_display_short_skip_}{\.{\\belowdisplayshortskip} primitive@>
+primitive("leftskip",assign_glue,glue_base+left_skip_code);@/
+@!@:left_skip_}{\.{\\leftskip} primitive@>
+primitive("rightskip",assign_glue,glue_base+right_skip_code);@/
+@!@:right_skip_}{\.{\\rightskip} primitive@>
+primitive("topskip",assign_glue,glue_base+top_skip_code);@/
+@!@:top_skip_}{\.{\\topskip} primitive@>
+primitive("splittopskip",assign_glue,glue_base+split_top_skip_code);@/
+@!@:split_top_skip_}{\.{\\splittopskip} primitive@>
+primitive("tabskip",assign_glue,glue_base+tab_skip_code);@/
+@!@:tab_skip_}{\.{\\tabskip} primitive@>
+primitive("spaceskip",assign_glue,glue_base+space_skip_code);@/
+@!@:space_skip_}{\.{\\spaceskip} primitive@>
+primitive("xspaceskip",assign_glue,glue_base+xspace_skip_code);@/
+@!@:xspace_skip_}{\.{\\xspaceskip} primitive@>
+primitive("parfillskip",assign_glue,glue_base+par_fill_skip_code);@/
+@!@:par_fill_skip_}{\.{\\parfillskip} primitive@>
+primitive("thinmuskip",assign_mu_glue,glue_base+thin_mu_skip_code);@/
+@!@:thin_mu_skip_}{\.{\\thinmuskip} primitive@>
+primitive("medmuskip",assign_mu_glue,glue_base+med_mu_skip_code);@/
+@!@:med_mu_skip_}{\.{\\medmuskip} primitive@>
+primitive("thickmuskip",assign_mu_glue,glue_base+thick_mu_skip_code);@/
+@!@:thick_mu_skip_}{\.{\\thickmuskip} primitive@>
+primitive("kanjiskip",assign_glue,glue_base+kanji_skip_code);@/
+@!@:kanji_skip_}{\.{\\kanjiskip} primitive@>
+primitive("xkanjiskip",assign_glue,glue_base+xkanji_skip_code);@/
+@!@:xkanji_skip_}{\.{\\xkanjiskip} primitive@>
+
+@ @<Cases of |print_cmd_chr| for symbolic printing of primitives@>=
+assign_glue,assign_mu_glue: if chr_code<skip_base then
+    print_skip_param(chr_code-glue_base)
+  else if chr_code<mu_skip_base then
+    begin print_esc("skip"); print_int(chr_code-skip_base);
+    end
+  else  begin print_esc("muskip"); print_int(chr_code-mu_skip_base);
+    end;
+
+@ All glue parameters and registers are initially `\.{0pt plus0pt minus0pt}'.
+
+@<Initialize table entries...@>=
+equiv(glue_base):=zero_glue; eq_level(glue_base):=level_one;
+eq_type(glue_base):=glue_ref;
+for k:=glue_base+1 to local_base-1 do eqtb[k]:=eqtb[glue_base];
+glue_ref_count(zero_glue):=glue_ref_count(zero_glue)+local_base-glue_base;
+
+@ @<Show equivalent |n|, in region 3@>=
+if n<skip_base then
+  begin print_skip_param(n-glue_base); print_char("=");
+  if n<glue_base+thin_mu_skip_code then print_spec(equiv(n),"pt")
+  else print_spec(equiv(n),"mu");
+  end
+else if n<mu_skip_base then
+  begin print_esc("skip"); print_int(n-skip_base); print_char("=");
+  print_spec(equiv(n),"pt");
+  end
+else  begin print_esc("muskip"); print_int(n-mu_skip_base); print_char("=");
+  print_spec(equiv(n),"mu");
+  end
+
+@ Region 4 of |eqtb| contains the local quantities defined here. The
+bulk of this region is taken up by five tables that are indexed by eight-bit
+characters; these tables are important to both the syntactic and semantic
+portions of \TeX. There are also a bunch of special things like font and
+token parameters, as well as the tables of \.{\\toks} and \.{\\box}
+registers.
+
+@d par_shape_loc=local_base {specifies paragraph shape}
+@d output_routine_loc=local_base+1 {points to token list for \.{\\output}}
+@d every_par_loc=local_base+2 {points to token list for \.{\\everypar}}
+@d every_math_loc=local_base+3 {points to token list for \.{\\everymath}}
+@d every_display_loc=local_base+4 {points to token list for \.{\\everydisplay}}
+@d every_hbox_loc=local_base+5 {points to token list for \.{\\everyhbox}}
+@d every_vbox_loc=local_base+6 {points to token list for \.{\\everyvbox}}
+@d every_job_loc=local_base+7 {points to token list for \.{\\everyjob}}
+@d every_cr_loc=local_base+8 {points to token list for \.{\\everycr}}
+@d err_help_loc=local_base+9 {points to token list for \.{\\errhelp}}
+@d toks_base=local_base+10 {table of 256 token list registers}
+@d box_base=toks_base+256 {table of 256 box registers}
+@d cur_font_loc=box_base+256 {internal font number outside math mode}
+@d math_font_base=cur_font_loc+1 {table of 48 math font numbers}
+@d cur_jfont_loc=math_font_base+48
+@d cur_tfont_loc=cur_jfont_loc+1
+@d auto_spacing_code=cur_tfont_loc+1
+@d auto_xspacing_code=auto_spacing_code+1
+@d cat_code_base=auto_xspacing_code+1
+  {table of 256 command codes (the ``catcodes'')}
+@d kcat_code_base=cat_code_base+256
+  {table of 256 command codes for the wchar's catcodes }
+@d auto_xsp_code_base=kcat_code_base+256 {table of 256 auto spacer flag}
+@d inhibit_xsp_code_base=auto_xsp_code_base+256
+@d kinsoku_base=inhibit_xsp_code_base+256 {table of 256 kinsoku mappings}
+@d kansuji_base=kinsoku_base+256 {table of 10 kansuji mappings}
+@d lc_code_base=kansuji_base+10 {table of 256 lowercase mappings}
+@d uc_code_base=lc_code_base+256 {table of 256 uppercase mappings}
+@d sf_code_base=uc_code_base+256 {table of 256 spacefactor mappings}
+@d math_code_base=sf_code_base+256 {table of 256 math mode mappings}
+@d char_sub_code_base=math_code_base+256 {table of character substitutions}
+@d int_base=char_sub_code_base+256 {beginning of region 5}
+@#
+@d par_shape_ptr==equiv(par_shape_loc)
+@d output_routine==equiv(output_routine_loc)
+@d every_par==equiv(every_par_loc)
+@d every_math==equiv(every_math_loc)
+@d every_display==equiv(every_display_loc)
+@d every_hbox==equiv(every_hbox_loc)
+@d every_vbox==equiv(every_vbox_loc)
+@d every_job==equiv(every_job_loc)
+@d every_cr==equiv(every_cr_loc)
+@d err_help==equiv(err_help_loc)
+@d toks(#)==equiv(toks_base+#)
+@d box(#)==equiv(box_base+#)
+@d cur_font==equiv(cur_font_loc)
+@d fam_fnt(#)==equiv(math_font_base+#)
+@d cat_code(#)==equiv(cat_code_base+#)
+@d lc_code(#)==equiv(lc_code_base+#)
+@d uc_code(#)==equiv(uc_code_base+#)
+@d sf_code(#)==equiv(sf_code_base+#)
+@d math_code(#)==equiv(math_code_base+#)
+  {Note: |math_code(c)| is the true math code plus |min_halfword|}
+@d char_sub_code(#)==equiv(char_sub_code_base+#)
+  {Note: |char_sub_code(c)| is the true substitution info plus |min_halfword|}
+@#
+@d cur_jfont==equiv(cur_jfont_loc) {pTeX: }
+@d cur_tfont==equiv(cur_tfont_loc)
+@d auto_spacing==equiv(auto_spacing_code)
+@d auto_xspacing==equiv(auto_xspacing_code)
+@d kcat_code(#)==equiv(kcat_code_base+#)
+@d auto_xsp_code(#)==equiv(auto_xsp_code_base+#)
+@d inhibit_xsp_type(#)==eq_type(inhibit_xsp_code_base+#)
+@d inhibit_xsp_code(#)==equiv(inhibit_xsp_code_base+#)
+@d kinsoku_type(#)==eq_type(kinsoku_base+#)
+@d kinsoku_code(#)==equiv(kinsoku_base+#)
+@d kansuji_char(#)==equiv(kansuji_base+#)
+
+@<Put each...@>=
+primitive("output",assign_toks,output_routine_loc);
+@!@:output_}{\.{\\output} primitive@>
+primitive("everypar",assign_toks,every_par_loc);
+@!@:every_par_}{\.{\\everypar} primitive@>
+primitive("everymath",assign_toks,every_math_loc);
+@!@:every_math_}{\.{\\everymath} primitive@>
+primitive("everydisplay",assign_toks,every_display_loc);
+@!@:every_display_}{\.{\\everydisplay} primitive@>
+primitive("everyhbox",assign_toks,every_hbox_loc);
+@!@:every_hbox_}{\.{\\everyhbox} primitive@>
+primitive("everyvbox",assign_toks,every_vbox_loc);
+@!@:every_vbox_}{\.{\\everyvbox} primitive@>
+primitive("everyjob",assign_toks,every_job_loc);
+@!@:every_job_}{\.{\\everyjob} primitive@>
+primitive("everycr",assign_toks,every_cr_loc);
+@!@:every_cr_}{\.{\\everycr} primitive@>
+primitive("errhelp",assign_toks,err_help_loc);
+@!@:err_help_}{\.{\\errhelp} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+assign_toks: if chr_code>=toks_base then
+  begin print_esc("toks"); print_int(chr_code-toks_base);
+  end
+else  case chr_code of
+  output_routine_loc: print_esc("output");
+  every_par_loc: print_esc("everypar");
+  every_math_loc: print_esc("everymath");
+  every_display_loc: print_esc("everydisplay");
+  every_hbox_loc: print_esc("everyhbox");
+  every_vbox_loc: print_esc("everyvbox");
+  every_job_loc: print_esc("everyjob");
+  every_cr_loc: print_esc("everycr");
+  othercases print_esc("errhelp")
+  endcases;
+
+@ We initialize most things to null or undefined values. An undefined font
+is represented by the internal code |font_base|.
+
+However, the character code tables are given initial values based on the
+conventional interpretation of ASCII code. These initial values should
+not be changed when \TeX\ is adapted for use with non-English languages;
+all changes to the initialization conventions should be made in format
+packages, not in \TeX\ itself, so that global interchange of formats is
+possible.
+
+@d null_font==font_base
+@d var_code==@'70000 {math code meaning ``use the current family''}
+
+@<Initialize table entries...@>=
+par_shape_ptr:=null; eq_type(par_shape_loc):=shape_ref;
+eq_level(par_shape_loc):=level_one;@/
+for k:=output_routine_loc to toks_base+255 do
+  eqtb[k]:=eqtb[undefined_control_sequence];
+box(0):=null; eq_type(box_base):=box_ref; eq_level(box_base):=level_one;
+for k:=box_base+1 to box_base+255 do eqtb[k]:=eqtb[box_base];
+cur_font:=null_font; eq_type(cur_font_loc):=data;
+eq_level(cur_font_loc):=level_one;@/
+cur_jfont:=null_font; eq_type(cur_jfont_loc):=data;
+eq_level(cur_jfont_loc):=level_one;@/
+cur_tfont:=null_font; eq_type(cur_tfont_loc):=data;
+eq_level(cur_tfont_loc):=level_one;@/
+for k:=math_font_base to math_font_base+47 do eqtb[k]:=eqtb[cur_font_loc];
+equiv(cat_code_base):=0; eq_type(cat_code_base):=data;
+eq_level(cat_code_base):=level_one;@/
+for k:=cat_code_base+1 to int_base-1 do eqtb[k]:=eqtb[cat_code_base];
+eqtb[auto_spacing_code]:=eqtb[cat_code_base];
+eqtb[auto_xspacing_code]:=eqtb[cat_code_base];
+for k:=0 to 255 do
+  begin cat_code(k):=other_char; kcat_code(k):=other_kchar;
+  math_code(k):=hi(k); sf_code(k):=1000;
+  auto_xsp_code(k):=0; inhibit_xsp_code(k):=0; inhibit_xsp_type(k):=0;
+  kinsoku_code(k):=0; kinsoku_type(k):=0;
+  end;
+cat_code(carriage_return):=car_ret; cat_code(" "):=spacer;
+cat_code("\"):=escape; cat_code("%"):=comment;
+cat_code(invalid_code):=invalid_char; cat_code(null_code):=ignore;
+for k:="0" to "9" do
+  begin math_code(k):=hi(k+var_code);
+  auto_xsp_code(k):=3;
+  end;
+kansuji_char(0):=toDVI(fromJIS(@"213B));
+kansuji_char(1):=toDVI(fromJIS(@"306C));
+kansuji_char(2):=toDVI(fromJIS(@"4673));
+kansuji_char(3):=toDVI(fromJIS(@"3B30));
+kansuji_char(4):=toDVI(fromJIS(@"3B4D));
+kansuji_char(5):=toDVI(fromJIS(@"385E));
+kansuji_char(6):=toDVI(fromJIS(@"4F3B));
+kansuji_char(7):=toDVI(fromJIS(@"3C37));
+kansuji_char(8):=toDVI(fromJIS(@"482C));
+kansuji_char(9):=toDVI(fromJIS(@"3665));
+for k:="A" to "Z" do
+  begin cat_code(k):=letter; cat_code(k+"a"-"A"):=letter;@/
+  math_code(k):=hi(k+var_code+@"100);
+  math_code(k+"a"-"A"):=hi(k+"a"-"A"+var_code+@"100);@/
+  lc_code(k):=k+"a"-"A"; lc_code(k+"a"-"A"):=k+"a"-"A";@/
+  uc_code(k):=k; uc_code(k+"a"-"A"):=k;@/
+  auto_xsp_code(k):=3; auto_xsp_code(k+"a"-"A"):=3;@/
+  sf_code(k):=999;
+  end;
+@t\hskip10pt@>kcat_code(@"20+1):=other_kchar; {1 ku}
+@t\hskip10pt@>kcat_code(@"20+2):=other_kchar; {2 ku}
+@+@t\1@>for k:=3 to 6 do kcat_code(@"20+k):=kana; {3 ku ... 6 ku}
+@+@t\1@>for k:=7 to 8 do kcat_code(@"20+k):=other_kchar; {7 ku ... 8 ku}
+@+@t\1@>for k:=16 to 84 do kcat_code(@"20+k):=kanji; {16 ku ... 84 ku}
+{ $\.{@@"20}+|k| = |kcatcodekey|(|fromKUTEN|(|HILO|(k,1))$ }
+
+@ @<Show equivalent |n|, in region 4@>=
+if n=par_shape_loc then
+  begin print_esc("parshape"); print_char("=");
+  if par_shape_ptr=null then print_char("0")
+  else print_int(info(par_shape_ptr));
+  end
+else if n<toks_base then
+  begin print_cmd_chr(assign_toks,n); print_char("=");
+  if equiv(n)<>null then show_token_list(link(equiv(n)),null,32);
+  end
+else if n<box_base then
+  begin print_esc("toks"); print_int(n-toks_base); print_char("=");
+  if equiv(n)<>null then show_token_list(link(equiv(n)),null,32);
+  end
+else if n<cur_font_loc then
+  begin print_esc("box"); print_int(n-box_base); print_char("=");
+  if equiv(n)=null then print("void")
+  else  begin depth_threshold:=0; breadth_max:=1; show_node_list(equiv(n));
+    end;
+  end
+else if n<cat_code_base then @<Show the font identifier in |eqtb[n]|@>
+else @<Show the halfword code in |eqtb[n]|@>
+
+@ @<Show the font identifier in |eqtb[n]|@>=
+begin if n=cur_font_loc then print("current font")
+else if n<math_font_base+16 then
+  begin print_esc("textfont"); print_int(n-math_font_base);
+  end
+else if n<math_font_base+32 then
+  begin print_esc("scriptfont"); print_int(n-math_font_base-16);
+  end
+else  begin print_esc("scriptscriptfont"); print_int(n-math_font_base-32);
+  end;
+print_char("=");@/
+print_esc(hash[font_id_base+equiv(n)].rh);
+  {that's |font_id_text(equiv(n))|}
+end
+
+@ @<Show the halfword code in |eqtb[n]|@>=
+if n<math_code_base then
+  begin if n<kcat_code_base then
+    begin print_esc("catcode"); print_int(n-cat_code_base);
+    end
+  else if n<auto_xsp_code_base then
+    begin print_esc("kcatcode"); print_int(n-kcat_code_base);
+    end
+  else if n<inhibit_xsp_code_base then
+    begin print_esc("xspcode"); print_int(n-auto_xsp_code_base);
+    end
+  else if n<kinsoku_base then
+    begin print("(inhibitxspcode table) "); print_int(n-inhibit_xsp_code_base);
+    end
+  else if n<kansuji_base then
+    begin print("(kinsoku table) "); print_int(n-kinsoku_base);
+    end
+  else if n<lc_code_base then
+    begin print_esc("kansujichar"); print_int(n-kansuji_base);
+    end
+  else if n<uc_code_base then
+    begin print_esc("lccode"); print_int(n-lc_code_base);
+    end
+  else if n<sf_code_base then
+    begin print_esc("uccode"); print_int(n-uc_code_base);
+    end
+  else  begin print_esc("sfcode"); print_int(n-sf_code_base);
+    end;
+  print_char("="); print_int(equiv(n));
+  end
+else  begin print_esc("mathcode"); print_int(n-math_code_base);
+  print_char("="); print_int(ho(equiv(n)));
+  end
+
+@ Region 5 of |eqtb| contains the integer parameters and registers defined
+here, as well as the |del_code| table. The latter table differs from the
+|cat_code..math_code| tables that precede it, since delimiter codes are
+fullword integers while the other kinds of codes occupy at most a
+halfword. This is what makes region~5 different from region~4. We will
+store the |eq_level| information in an auxiliary array of quarterwords
+that will be defined later.
+
+@d pretolerance_code=0 {badness tolerance before hyphenation}
+@d tolerance_code=1 {badness tolerance after hyphenation}
+@d line_penalty_code=2 {added to the badness of every line}
+@d hyphen_penalty_code=3 {penalty for break after discretionary hyphen}
+@d ex_hyphen_penalty_code=4 {penalty for break after explicit hyphen}
+@d club_penalty_code=5 {penalty for creating a club line}
+@d widow_penalty_code=6 {penalty for creating a widow line}
+@d display_widow_penalty_code=7 {ditto, just before a display}
+@d broken_penalty_code=8 {penalty for breaking a page at a broken line}
+@d bin_op_penalty_code=9 {penalty for breaking after a binary operation}
+@d rel_penalty_code=10 {penalty for breaking after a relation}
+@d pre_display_penalty_code=11
+  {penalty for breaking just before a displayed formula}
+@d post_display_penalty_code=12
+  {penalty for breaking just after a displayed formula}
+@d inter_line_penalty_code=13 {additional penalty between lines}
+@d double_hyphen_demerits_code=14 {demerits for double hyphen break}
+@d final_hyphen_demerits_code=15 {demerits for final hyphen break}
+@d adj_demerits_code=16 {demerits for adjacent incompatible lines}
+@d mag_code=17 {magnification ratio}
+@d delimiter_factor_code=18 {ratio for variable-size delimiters}
+@d looseness_code=19 {change in number of lines for a paragraph}
+@d time_code=20 {current time of day}
+@d day_code=21 {current day of the month}
+@d month_code=22 {current month of the year}
+@d year_code=23 {current year of our Lord}
+@d show_box_breadth_code=24 {nodes per level in |show_box|}
+@d show_box_depth_code=25 {maximum level in |show_box|}
+@d hbadness_code=26 {hboxes exceeding this badness will be shown by |hpack|}
+@d vbadness_code=27 {vboxes exceeding this badness will be shown by |vpack|}
+@d pausing_code=28 {pause after each line is read from a file}
+@d tracing_online_code=29 {show diagnostic output on terminal}
+@d tracing_macros_code=30 {show macros as they are being expanded}
+@d tracing_stats_code=31 {show memory usage if \TeX\ knows it}
+@d tracing_paragraphs_code=32 {show line-break calculations}
+@d tracing_pages_code=33 {show page-break calculations}
+@d tracing_output_code=34 {show boxes when they are shipped out}
+@d tracing_lost_chars_code=35 {show characters that aren't in the font}
+@d tracing_commands_code=36 {show command codes at |big_switch|}
+@d tracing_restores_code=37 {show equivalents when they are restored}
+@d uc_hyph_code=38 {hyphenate words beginning with a capital letter}
+@d output_penalty_code=39 {penalty found at current page break}
+@d max_dead_cycles_code=40 {bound on consecutive dead cycles of output}
+@d hang_after_code=41 {hanging indentation changes after this many lines}
+@d floating_penalty_code=42 {penalty for insertions heldover after a split}
+@d global_defs_code=43 {override \.{\\global} specifications}
+@d cur_fam_code=44 {current family}
+@d cur_jfam_code=45 {current kanji family}
+@d escape_char_code=46 {escape character for token output}
+@d default_hyphen_char_code=47 {value of \.{\\hyphenchar} when a font is loaded}
+@d default_skew_char_code=48 {value of \.{\\skewchar} when a font is loaded}
+@d end_line_char_code=49 {character placed at the right end of the buffer}
+@d new_line_char_code=50 {character that prints as |print_ln|}
+@d language_code=51 {current hyphenation table}
+@d left_hyphen_min_code=52 {minimum left hyphenation fragment size}
+@d right_hyphen_min_code=53 {minimum right hyphenation fragment size}
+@d holding_inserts_code=54 {do not remove insertion nodes from \.{\\box255}}
+@d error_context_lines_code=55 {maximum intermediate line pairs shown}
+@d jchr_widow_penalty_code=56
+                       {penalty for creating a widow KANJI character line}
+@d char_sub_def_min_code=57 {smallest value in the charsubdef list}
+@d char_sub_def_max_code=58 {largest value in the charsubdef list}
+@d tracing_char_sub_def_code=59 {traces changes to a charsubdef def}
+@d int_pars=60 {total number of integer parameters}
+@d count_base=int_base+int_pars {256 user \.{\\count} registers}
+@d del_code_base=count_base+256 {256 delimiter code mappings}
+@d dimen_base=del_code_base+256 {beginning of region 6}
+@#
+@d del_code(#)==eqtb[del_code_base+#].int
+@d count(#)==eqtb[count_base+#].int
+@d int_par(#)==eqtb[int_base+#].int {an integer parameter}
+@d pretolerance==int_par(pretolerance_code)
+@d tolerance==int_par(tolerance_code)
+@d line_penalty==int_par(line_penalty_code)
+@d hyphen_penalty==int_par(hyphen_penalty_code)
+@d ex_hyphen_penalty==int_par(ex_hyphen_penalty_code)
+@d club_penalty==int_par(club_penalty_code)
+@d widow_penalty==int_par(widow_penalty_code)
+@d display_widow_penalty==int_par(display_widow_penalty_code)
+@d broken_penalty==int_par(broken_penalty_code)
+@d bin_op_penalty==int_par(bin_op_penalty_code)
+@d rel_penalty==int_par(rel_penalty_code)
+@d pre_display_penalty==int_par(pre_display_penalty_code)
+@d post_display_penalty==int_par(post_display_penalty_code)
+@d inter_line_penalty==int_par(inter_line_penalty_code)
+@d double_hyphen_demerits==int_par(double_hyphen_demerits_code)
+@d final_hyphen_demerits==int_par(final_hyphen_demerits_code)
+@d adj_demerits==int_par(adj_demerits_code)
+@d mag==int_par(mag_code)
+@d delimiter_factor==int_par(delimiter_factor_code)
+@d looseness==int_par(looseness_code)
+@d time==int_par(time_code)
+@d day==int_par(day_code)
+@d month==int_par(month_code)
+@d year==int_par(year_code)
+@d show_box_breadth==int_par(show_box_breadth_code)
+@d show_box_depth==int_par(show_box_depth_code)
+@d hbadness==int_par(hbadness_code)
+@d vbadness==int_par(vbadness_code)
+@d pausing==int_par(pausing_code)
+@d tracing_online==int_par(tracing_online_code)
+@d tracing_macros==int_par(tracing_macros_code)
+@d tracing_stats==int_par(tracing_stats_code)
+@d tracing_paragraphs==int_par(tracing_paragraphs_code)
+@d tracing_pages==int_par(tracing_pages_code)
+@d tracing_output==int_par(tracing_output_code)
+@d tracing_lost_chars==int_par(tracing_lost_chars_code)
+@d tracing_commands==int_par(tracing_commands_code)
+@d tracing_restores==int_par(tracing_restores_code)
+@d uc_hyph==int_par(uc_hyph_code)
+@d output_penalty==int_par(output_penalty_code)
+@d max_dead_cycles==int_par(max_dead_cycles_code)
+@d hang_after==int_par(hang_after_code)
+@d floating_penalty==int_par(floating_penalty_code)
+@d global_defs==int_par(global_defs_code)
+@d cur_fam==int_par(cur_fam_code)
+@d cur_jfam==int_par(cur_jfam_code)
+@d escape_char==int_par(escape_char_code)
+@d jchr_widow_penalty==int_par(jchr_widow_penalty_code)
+@d default_hyphen_char==int_par(default_hyphen_char_code)
+@d default_skew_char==int_par(default_skew_char_code)
+@d end_line_char==int_par(end_line_char_code)
+@d new_line_char==int_par(new_line_char_code)
+@d language==int_par(language_code)
+@d left_hyphen_min==int_par(left_hyphen_min_code)
+@d right_hyphen_min==int_par(right_hyphen_min_code)
+@d holding_inserts==int_par(holding_inserts_code)
+@d error_context_lines==int_par(error_context_lines_code)
+@#
+@d char_sub_def_min==int_par(char_sub_def_min_code)
+@d char_sub_def_max==int_par(char_sub_def_max_code)
+@d tracing_char_sub_def==int_par(tracing_char_sub_def_code)
+
+@<Assign the values |depth_threshold:=show_box_depth|...@>=
+depth_threshold:=show_box_depth;
+breadth_max:=show_box_breadth
+
+@ We can print the symbolic name of an integer parameter as follows.
+
+@p procedure print_param(@!n:integer);
+begin case n of
+pretolerance_code:print_esc("pretolerance");
+tolerance_code:print_esc("tolerance");
+line_penalty_code:print_esc("linepenalty");
+hyphen_penalty_code:print_esc("hyphenpenalty");
+ex_hyphen_penalty_code:print_esc("exhyphenpenalty");
+club_penalty_code:print_esc("clubpenalty");
+widow_penalty_code:print_esc("widowpenalty");
+display_widow_penalty_code:print_esc("displaywidowpenalty");
+broken_penalty_code:print_esc("brokenpenalty");
+bin_op_penalty_code:print_esc("binoppenalty");
+rel_penalty_code:print_esc("relpenalty");
+pre_display_penalty_code:print_esc("predisplaypenalty");
+post_display_penalty_code:print_esc("postdisplaypenalty");
+inter_line_penalty_code:print_esc("interlinepenalty");
+double_hyphen_demerits_code:print_esc("doublehyphendemerits");
+final_hyphen_demerits_code:print_esc("finalhyphendemerits");
+adj_demerits_code:print_esc("adjdemerits");
+mag_code:print_esc("mag");
+delimiter_factor_code:print_esc("delimiterfactor");
+looseness_code:print_esc("looseness");
+time_code:print_esc("time");
+day_code:print_esc("day");
+month_code:print_esc("month");
+year_code:print_esc("year");
+show_box_breadth_code:print_esc("showboxbreadth");
+show_box_depth_code:print_esc("showboxdepth");
+hbadness_code:print_esc("hbadness");
+vbadness_code:print_esc("vbadness");
+pausing_code:print_esc("pausing");
+tracing_online_code:print_esc("tracingonline");
+tracing_macros_code:print_esc("tracingmacros");
+tracing_stats_code:print_esc("tracingstats");
+tracing_paragraphs_code:print_esc("tracingparagraphs");
+tracing_pages_code:print_esc("tracingpages");
+tracing_output_code:print_esc("tracingoutput");
+tracing_lost_chars_code:print_esc("tracinglostchars");
+tracing_commands_code:print_esc("tracingcommands");
+tracing_restores_code:print_esc("tracingrestores");
+uc_hyph_code:print_esc("uchyph");
+output_penalty_code:print_esc("outputpenalty");
+max_dead_cycles_code:print_esc("maxdeadcycles");
+hang_after_code:print_esc("hangafter");
+floating_penalty_code:print_esc("floatingpenalty");
+global_defs_code:print_esc("globaldefs");
+cur_fam_code:print_esc("fam");
+escape_char_code:print_esc("escapechar");
+default_hyphen_char_code:print_esc("defaulthyphenchar");
+default_skew_char_code:print_esc("defaultskewchar");
+end_line_char_code:print_esc("endlinechar");
+new_line_char_code:print_esc("newlinechar");
+cur_jfam_code:print_esc("jfam");
+jchr_widow_penalty_code:print_esc("jcharwidowpenalty");
+language_code:print_esc("language");
+left_hyphen_min_code:print_esc("lefthyphenmin");
+right_hyphen_min_code:print_esc("righthyphenmin");
+holding_inserts_code:print_esc("holdinginserts");
+error_context_lines_code:print_esc("errorcontextlines");
+char_sub_def_min_code:print_esc("charsubdefmin");
+char_sub_def_max_code:print_esc("charsubdefmax");
+tracing_char_sub_def_code:print_esc("tracingcharsubdef");
+othercases print("[unknown integer parameter!]")
+endcases;
+end;
+
+@ The integer parameter names must be entered into the hash table.
+
+@<Put each...@>=
+primitive("pretolerance",assign_int,int_base+pretolerance_code);@/
+@!@:pretolerance_}{\.{\\pretolerance} primitive@>
+primitive("tolerance",assign_int,int_base+tolerance_code);@/
+@!@:tolerance_}{\.{\\tolerance} primitive@>
+primitive("linepenalty",assign_int,int_base+line_penalty_code);@/
+@!@:line_penalty_}{\.{\\linepenalty} primitive@>
+primitive("hyphenpenalty",assign_int,int_base+hyphen_penalty_code);@/
+@!@:hyphen_penalty_}{\.{\\hyphenpenalty} primitive@>
+primitive("exhyphenpenalty",assign_int,int_base+ex_hyphen_penalty_code);@/
+@!@:ex_hyphen_penalty_}{\.{\\exhyphenpenalty} primitive@>
+primitive("clubpenalty",assign_int,int_base+club_penalty_code);@/
+@!@:club_penalty_}{\.{\\clubpenalty} primitive@>
+primitive("widowpenalty",assign_int,int_base+widow_penalty_code);@/
+@!@:widow_penalty_}{\.{\\widowpenalty} primitive@>
+primitive("displaywidowpenalty",
+  assign_int,int_base+display_widow_penalty_code);@/
+@!@:display_widow_penalty_}{\.{\\displaywidowpenalty} primitive@>
+primitive("brokenpenalty",assign_int,int_base+broken_penalty_code);@/
+@!@:broken_penalty_}{\.{\\brokenpenalty} primitive@>
+primitive("binoppenalty",assign_int,int_base+bin_op_penalty_code);@/
+@!@:bin_op_penalty_}{\.{\\binoppenalty} primitive@>
+primitive("relpenalty",assign_int,int_base+rel_penalty_code);@/
+@!@:rel_penalty_}{\.{\\relpenalty} primitive@>
+primitive("predisplaypenalty",assign_int,int_base+pre_display_penalty_code);@/
+@!@:pre_display_penalty_}{\.{\\predisplaypenalty} primitive@>
+primitive("postdisplaypenalty",assign_int,int_base+post_display_penalty_code);@/
+@!@:post_display_penalty_}{\.{\\postdisplaypenalty} primitive@>
+primitive("interlinepenalty",assign_int,int_base+inter_line_penalty_code);@/
+@!@:inter_line_penalty_}{\.{\\interlinepenalty} primitive@>
+primitive("doublehyphendemerits",
+  assign_int,int_base+double_hyphen_demerits_code);@/
+@!@:double_hyphen_demerits_}{\.{\\doublehyphendemerits} primitive@>
+primitive("finalhyphendemerits",
+  assign_int,int_base+final_hyphen_demerits_code);@/
+@!@:final_hyphen_demerits_}{\.{\\finalhyphendemerits} primitive@>
+primitive("adjdemerits",assign_int,int_base+adj_demerits_code);@/
+@!@:adj_demerits_}{\.{\\adjdemerits} primitive@>
+primitive("mag",assign_int,int_base+mag_code);@/
+@!@:mag_}{\.{\\mag} primitive@>
+primitive("delimiterfactor",assign_int,int_base+delimiter_factor_code);@/
+@!@:delimiter_factor_}{\.{\\delimiterfactor} primitive@>
+primitive("looseness",assign_int,int_base+looseness_code);@/
+@!@:looseness_}{\.{\\looseness} primitive@>
+primitive("time",assign_int,int_base+time_code);@/
+@!@:time_}{\.{\\time} primitive@>
+primitive("day",assign_int,int_base+day_code);@/
+@!@:day_}{\.{\\day} primitive@>
+primitive("month",assign_int,int_base+month_code);@/
+@!@:month_}{\.{\\month} primitive@>
+primitive("year",assign_int,int_base+year_code);@/
+@!@:year_}{\.{\\year} primitive@>
+primitive("showboxbreadth",assign_int,int_base+show_box_breadth_code);@/
+@!@:show_box_breadth_}{\.{\\showboxbreadth} primitive@>
+primitive("showboxdepth",assign_int,int_base+show_box_depth_code);@/
+@!@:show_box_depth_}{\.{\\showboxdepth} primitive@>
+primitive("hbadness",assign_int,int_base+hbadness_code);@/
+@!@:hbadness_}{\.{\\hbadness} primitive@>
+primitive("vbadness",assign_int,int_base+vbadness_code);@/
+@!@:vbadness_}{\.{\\vbadness} primitive@>
+primitive("pausing",assign_int,int_base+pausing_code);@/
+@!@:pausing_}{\.{\\pausing} primitive@>
+primitive("tracingonline",assign_int,int_base+tracing_online_code);@/
+@!@:tracing_online_}{\.{\\tracingonline} primitive@>
+primitive("tracingmacros",assign_int,int_base+tracing_macros_code);@/
+@!@:tracing_macros_}{\.{\\tracingmacros} primitive@>
+primitive("tracingstats",assign_int,int_base+tracing_stats_code);@/
+@!@:tracing_stats_}{\.{\\tracingstats} primitive@>
+primitive("tracingparagraphs",assign_int,int_base+tracing_paragraphs_code);@/
+@!@:tracing_paragraphs_}{\.{\\tracingparagraphs} primitive@>
+primitive("tracingpages",assign_int,int_base+tracing_pages_code);@/
+@!@:tracing_pages_}{\.{\\tracingpages} primitive@>
+primitive("tracingoutput",assign_int,int_base+tracing_output_code);@/
+@!@:tracing_output_}{\.{\\tracingoutput} primitive@>
+primitive("tracinglostchars",assign_int,int_base+tracing_lost_chars_code);@/
+@!@:tracing_lost_chars_}{\.{\\tracinglostchars} primitive@>
+primitive("tracingcommands",assign_int,int_base+tracing_commands_code);@/
+@!@:tracing_commands_}{\.{\\tracingcommands} primitive@>
+primitive("tracingrestores",assign_int,int_base+tracing_restores_code);@/
+@!@:tracing_restores_}{\.{\\tracingrestores} primitive@>
+primitive("uchyph",assign_int,int_base+uc_hyph_code);@/
+@!@:uc_hyph_}{\.{\\uchyph} primitive@>
+primitive("outputpenalty",assign_int,int_base+output_penalty_code);@/
+@!@:output_penalty_}{\.{\\outputpenalty} primitive@>
+primitive("maxdeadcycles",assign_int,int_base+max_dead_cycles_code);@/
+@!@:max_dead_cycles_}{\.{\\maxdeadcycles} primitive@>
+primitive("hangafter",assign_int,int_base+hang_after_code);@/
+@!@:hang_after_}{\.{\\hangafter} primitive@>
+primitive("floatingpenalty",assign_int,int_base+floating_penalty_code);@/
+@!@:floating_penalty_}{\.{\\floatingpenalty} primitive@>
+primitive("globaldefs",assign_int,int_base+global_defs_code);@/
+@!@:global_defs_}{\.{\\globaldefs} primitive@>
+primitive("fam",assign_int,int_base+cur_fam_code);@/
+@!@:fam_}{\.{\\fam} primitive@>
+primitive("escapechar",assign_int,int_base+escape_char_code);@/
+@!@:escape_char_}{\.{\\escapechar} primitive@>
+primitive("defaulthyphenchar",assign_int,int_base+default_hyphen_char_code);@/
+@!@:default_hyphen_char_}{\.{\\defaulthyphenchar} primitive@>
+primitive("defaultskewchar",assign_int,int_base+default_skew_char_code);@/
+@!@:default_skew_char_}{\.{\\defaultskewchar} primitive@>
+primitive("endlinechar",assign_int,int_base+end_line_char_code);@/
+@!@:end_line_char_}{\.{\\endlinechar} primitive@>
+primitive("newlinechar",assign_int,int_base+new_line_char_code);@/
+@!@:new_line_char_}{\.{\\newlinechar} primitive@>
+primitive("jfam",assign_int,int_base+cur_jfam_code);@/
+@!@:cur_jfam_}{\.{\\jfam} primitive@>
+primitive("jcharwidowpenalty",assign_int,int_base+jchr_widow_penalty_code);@/
+@!@:jchr_widow_penalty}{\.{\\jcharwidowpenalty} primitive@>
+primitive("language",assign_int,int_base+language_code);@/
+@!@:language_}{\.{\\language} primitive@>
+primitive("lefthyphenmin",assign_int,int_base+left_hyphen_min_code);@/
+@!@:left_hyphen_min_}{\.{\\lefthyphenmin} primitive@>
+primitive("righthyphenmin",assign_int,int_base+right_hyphen_min_code);@/
+@!@:right_hyphen_min_}{\.{\\righthyphenmin} primitive@>
+primitive("holdinginserts",assign_int,int_base+holding_inserts_code);@/
+@!@:holding_inserts_}{\.{\\holdinginserts} primitive@>
+primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/
+@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@>
+if mltex_p then
+  begin mltex_enabled_p:=true;  {enable character substitution}
+  if false then {remove the if-clause to enable \.{\\charsubdefmin}}
+  primitive("charsubdefmin",assign_int,int_base+char_sub_def_min_code);@/
+@!@:char_sub_def_min_}{\.{\\charsubdefmin} primitive@>
+  primitive("charsubdefmax",assign_int,int_base+char_sub_def_max_code);@/
+@!@:char_sub_def_max_}{\.{\\charsubdefmax} primitive@>
+  primitive("tracingcharsubdef",assign_int,int_base+tracing_char_sub_def_code);@/
+@!@:tracing_char_sub_def_}{\.{\\tracingcharsubdef} primitive@>
+  end;
+
+@ @<Cases of |print_cmd_chr|...@>=
+assign_int: if chr_code<count_base then print_param(chr_code-int_base)
+  else  begin print_esc("count"); print_int(chr_code-count_base);
+    end;
+
+@ The integer parameters should really be initialized by a macro package;
+the following initialization does the minimum to keep \TeX\ from
+complete failure.
+@^null delimiter@>
+
+@<Initialize table entries...@>=
+for k:=int_base to del_code_base-1 do eqtb[k].int:=0;
+char_sub_def_min:=256; char_sub_def_max:=-1;
+{allow \.{\\charsubdef} for char 0}@/
+{|tracing_char_sub_def:=0| is already done}@/
+mag:=1000; tolerance:=10000; hang_after:=1; max_dead_cycles:=25;
+escape_char:="\"; end_line_char:=carriage_return;
+for k:=0 to 255 do del_code(k):=-1;
+del_code("."):=0; {this null delimiter is used in error recovery}
+
+@ The following procedure, which is called just before \TeX\ initializes its
+input and output, establishes the initial values of the date and time.
+It calls a macro-defined |date_and_time| routine.  |date_and_time|
+in turn is a C macro, which calls |get_date_and_time|, passing
+it the addresses of the day, month, etc., so they can be set by the
+routine.  |get_date_and_time| also sets up interrupt catching if that
+is conditionally compiled in the C code.
+@^system dependencies@>
+
+@d fix_date_and_time==date_and_time(time,day,month,year)
+
+@ @<Show equivalent |n|, in region 5@>=
+begin if n<count_base then print_param(n-int_base)
+else if  n<del_code_base then
+  begin print_esc("count"); print_int(n-count_base);
+  end
+else  begin print_esc("delcode"); print_int(n-del_code_base);
+  end;
+print_char("="); print_int(eqtb[n].int);
+end
+
+@ @<Set variable |c| to the current escape character@>=c:=escape_char
+
+@ @<Character |s| is the current new-line character@>=s=new_line_char
+
+@ \TeX\ is occasionally supposed to print diagnostic information that
+goes only into the transcript file, unless |tracing_online| is positive.
+Here are two routines that adjust the destination of print commands:
+
+@p procedure begin_diagnostic; {prepare to do some tracing}
+begin old_setting:=selector;
+if (tracing_online<=0)and(selector=term_and_log) then
+  begin decr(selector);
+  if history=spotless then history:=warning_issued;
+  end;
+end;
+@#
+procedure end_diagnostic(@!blank_line:boolean);
+  {restore proper conditions after tracing}
+begin print_nl("");
+if blank_line then print_ln;
+selector:=old_setting;
+end;
+
+@ Of course we had better declare another global variable, if the previous
+routines are going to work.
+
+@<Glob...@>=
+@!old_setting:0..max_selector;
+
+@ The final region of |eqtb| contains the dimension parameters defined
+here, and the 256 \.{\\dimen} registers.
+
+@d par_indent_code=0 {indentation of paragraphs}
+@d math_surround_code=1 {space around math in text}
+@d line_skip_limit_code=2 {threshold for |line_skip| instead of |baseline_skip|}
+@d hsize_code=3 {line width in horizontal mode}
+@d vsize_code=4 {page height in vertical mode}
+@d max_depth_code=5 {maximum depth of boxes on main pages}
+@d split_max_depth_code=6 {maximum depth of boxes on split pages}
+@d box_max_depth_code=7 {maximum depth of explicit vboxes}
+@d hfuzz_code=8 {tolerance for overfull hbox messages}
+@d vfuzz_code=9 {tolerance for overfull vbox messages}
+@d delimiter_shortfall_code=10 {maximum amount uncovered by variable delimiters}
+@d null_delimiter_space_code=11 {blank space in null delimiters}
+@d script_space_code=12 {extra space after subscript or superscript}
+@d pre_display_size_code=13 {length of text preceding a display}
+@d display_width_code=14 {length of line for displayed equation}
+@d display_indent_code=15 {indentation of line for displayed equation}
+@d overfull_rule_code=16 {width of rule that identifies overfull hboxes}
+@d hang_indent_code=17 {amount of hanging indentation}
+@d h_offset_code=18 {amount of horizontal offset when shipping pages out}
+@d v_offset_code=19 {amount of vertical offset when shipping pages out}
+@d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking}
+@d t_baseline_shift_code=21 {shift amount when mixing TATE-kumi and Alphabet}
+@d y_baseline_shift_code=22 {shift amount when mixing YOKO-kumi and Alphabet}
+@d dimen_pars=23 {total number of dimension parameters}
+@d scaled_base=dimen_base+dimen_pars
+  {table of 256 user-defined \.{\\dimen} registers}
+@d kinsoku_penalty_base=scaled_base+256 {table of 256 kinsoku registers}
+@d eqtb_size=kinsoku_penalty_base+255 {largest subscript of |eqtb|}
+@#
+@d dimen(#)==eqtb[scaled_base+#].sc
+@d dimen_par(#)==eqtb[dimen_base+#].sc {a scaled quantity}
+@d kinsoku_penalty(#)==eqtb[kinsoku_penalty_base+#].int
+@d par_indent==dimen_par(par_indent_code)
+@d math_surround==dimen_par(math_surround_code)
+@d line_skip_limit==dimen_par(line_skip_limit_code)
+@d hsize==dimen_par(hsize_code)
+@d vsize==dimen_par(vsize_code)
+@d max_depth==dimen_par(max_depth_code)
+@d split_max_depth==dimen_par(split_max_depth_code)
+@d box_max_depth==dimen_par(box_max_depth_code)
+@d hfuzz==dimen_par(hfuzz_code)
+@d vfuzz==dimen_par(vfuzz_code)
+@d delimiter_shortfall==dimen_par(delimiter_shortfall_code)
+@d null_delimiter_space==dimen_par(null_delimiter_space_code)
+@d script_space==dimen_par(script_space_code)
+@d pre_display_size==dimen_par(pre_display_size_code)
+@d display_width==dimen_par(display_width_code)
+@d display_indent==dimen_par(display_indent_code)
+@d overfull_rule==dimen_par(overfull_rule_code)
+@d hang_indent==dimen_par(hang_indent_code)
+@d h_offset==dimen_par(h_offset_code)
+@d v_offset==dimen_par(v_offset_code)
+@d t_baseline_shift==dimen_par(t_baseline_shift_code)
+@d y_baseline_shift==dimen_par(y_baseline_shift_code)
+@d emergency_stretch==dimen_par(emergency_stretch_code)
+
+@p procedure print_length_param(@!n:integer);
+begin case n of
+par_indent_code:print_esc("parindent");
+math_surround_code:print_esc("mathsurround");
+line_skip_limit_code:print_esc("lineskiplimit");
+hsize_code:print_esc("hsize");
+vsize_code:print_esc("vsize");
+max_depth_code:print_esc("maxdepth");
+split_max_depth_code:print_esc("splitmaxdepth");
+box_max_depth_code:print_esc("boxmaxdepth");
+hfuzz_code:print_esc("hfuzz");
+vfuzz_code:print_esc("vfuzz");
+delimiter_shortfall_code:print_esc("delimitershortfall");
+null_delimiter_space_code:print_esc("nulldelimiterspace");
+script_space_code:print_esc("scriptspace");
+pre_display_size_code:print_esc("predisplaysize");
+display_width_code:print_esc("displaywidth");
+display_indent_code:print_esc("displayindent");
+overfull_rule_code:print_esc("overfullrule");
+hang_indent_code:print_esc("hangindent");
+h_offset_code:print_esc("hoffset");
+v_offset_code:print_esc("voffset");
+t_baseline_shift_code:print_esc("tbaselineshift");
+y_baseline_shift_code:print_esc("ybaselineshift");
+emergency_stretch_code:print_esc("emergencystretch");
+othercases print("[unknown dimen parameter!]")
+endcases;
+end;
+
+@ @<Put each...@>=
+primitive("parindent",assign_dimen,dimen_base+par_indent_code);@/
+@!@:par_indent_}{\.{\\parindent} primitive@>
+primitive("mathsurround",assign_dimen,dimen_base+math_surround_code);@/
+@!@:math_surround_}{\.{\\mathsurround} primitive@>
+primitive("lineskiplimit",assign_dimen,dimen_base+line_skip_limit_code);@/
+@!@:line_skip_limit_}{\.{\\lineskiplimit} primitive@>
+primitive("hsize",assign_dimen,dimen_base+hsize_code);@/
+@!@:hsize_}{\.{\\hsize} primitive@>
+primitive("vsize",assign_dimen,dimen_base+vsize_code);@/
+@!@:vsize_}{\.{\\vsize} primitive@>
+primitive("maxdepth",assign_dimen,dimen_base+max_depth_code);@/
+@!@:max_depth_}{\.{\\maxdepth} primitive@>
+primitive("splitmaxdepth",assign_dimen,dimen_base+split_max_depth_code);@/
+@!@:split_max_depth_}{\.{\\splitmaxdepth} primitive@>
+primitive("boxmaxdepth",assign_dimen,dimen_base+box_max_depth_code);@/
+@!@:box_max_depth_}{\.{\\boxmaxdepth} primitive@>
+primitive("hfuzz",assign_dimen,dimen_base+hfuzz_code);@/
+@!@:hfuzz_}{\.{\\hfuzz} primitive@>
+primitive("vfuzz",assign_dimen,dimen_base+vfuzz_code);@/
+@!@:vfuzz_}{\.{\\vfuzz} primitive@>
+primitive("delimitershortfall",
+  assign_dimen,dimen_base+delimiter_shortfall_code);@/
+@!@:delimiter_shortfall_}{\.{\\delimitershortfall} primitive@>
+primitive("nulldelimiterspace",
+  assign_dimen,dimen_base+null_delimiter_space_code);@/
+@!@:null_delimiter_space_}{\.{\\nulldelimiterspace} primitive@>
+primitive("scriptspace",assign_dimen,dimen_base+script_space_code);@/
+@!@:script_space_}{\.{\\scriptspace} primitive@>
+primitive("predisplaysize",assign_dimen,dimen_base+pre_display_size_code);@/
+@!@:pre_display_size_}{\.{\\predisplaysize} primitive@>
+primitive("displaywidth",assign_dimen,dimen_base+display_width_code);@/
+@!@:display_width_}{\.{\\displaywidth} primitive@>
+primitive("displayindent",assign_dimen,dimen_base+display_indent_code);@/
+@!@:display_indent_}{\.{\\displayindent} primitive@>
+primitive("overfullrule",assign_dimen,dimen_base+overfull_rule_code);@/
+@!@:overfull_rule_}{\.{\\overfullrule} primitive@>
+primitive("hangindent",assign_dimen,dimen_base+hang_indent_code);@/
+@!@:hang_indent_}{\.{\\hangindent} primitive@>
+primitive("hoffset",assign_dimen,dimen_base+h_offset_code);@/
+@!@:h_offset_}{\.{\\hoffset} primitive@>
+primitive("voffset",assign_dimen,dimen_base+v_offset_code);@/
+@!@:v_offset_}{\.{\\voffset} primitive@>
+primitive("tbaselineshift",assign_dimen,dimen_base+t_baseline_shift_code);@/
+@!@:t_baseline_shift_}{\.{\\tbaselineshift} primitive@>
+primitive("ybaselineshift",assign_dimen,dimen_base+y_baseline_shift_code);@/
+@!@:y_baseline_shift_}{\.{\\ybaselineshift} primitive@>
+primitive("emergencystretch",assign_dimen,dimen_base+emergency_stretch_code);@/
+@!@:emergency_stretch_}{\.{\\emergencystretch} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+assign_dimen: if chr_code<scaled_base then
+    print_length_param(chr_code-dimen_base)
+  else  begin print_esc("dimen"); print_int(chr_code-scaled_base);
+    end;
+
+@ @<Initialize table entries...@>=
+for k:=dimen_base to eqtb_size do eqtb[k].sc:=0;
+
+@ @<Show equivalent |n|, in region 6@>=
+begin if n<scaled_base then print_length_param(n-dimen_base)
+else  begin print_esc("dimen"); print_int(n-scaled_base);
+  end;
+print_char("="); print_scaled(eqtb[n].sc); print("pt");
+end
+
+@ Here is a procedure that displays the contents of |eqtb[n]|
+symbolically.
+
+@p@t\4@>@<Declare the procedure called |print_cmd_chr|@>@;@/
+@!stat procedure show_eqtb(@!n:pointer);
+begin if n<active_base then print_char("?") {this can't happen}
+else if (n<glue_base) or ((n>eqtb_size)and(n<=eqtb_top)) then
+  @<Show equivalent |n|, in region 1 or 2@>
+else if n<local_base then @<Show equivalent |n|, in region 3@>
+else if n<int_base then @<Show equivalent |n|, in region 4@>
+else if n<dimen_base then @<Show equivalent |n|, in region 5@>
+else if n<kinsoku_penalty_base then @<Show equivalent |n|, in region 6@>
+else if n<=eqtb_size then print("kinsoku")
+else print_char("?"); {this can't happen either}
+end;
+tats
+
+@ The last two regions of |eqtb| have fullword values instead of the
+three fields |eq_level|, |eq_type|, and |equiv|. An |eq_type| is unnecessary,
+but \TeX\ needs to store the |eq_level| information in another array
+called |xeq_level|.
+
+@<Glob...@>=
+@!zeqtb:^memory_word;
+@!xeq_level:array[int_base..eqtb_size] of quarterword;
+
+@ @<Set init...@>=
+for k:=int_base to eqtb_size do xeq_level[k]:=level_one;
+
+@ When the debugging routine |search_mem| is looking for pointers having a
+given value, it is interested only in regions 1 to~3 of~|eqtb|, and in the
+first part of region~4.
+
+@<Search |eqtb| for equivalents equal to |p|@>=
+for q:=active_base to box_base+255 do
+  begin if equiv(q)=p then
+    begin print_nl("EQUIV("); print_int(q); print_char(")");
+    end;
+  end
+
+@* \[18] The hash table.
+Control sequences are stored and retrieved by means of a fairly standard hash
+table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
+in {\sl The Art of Computer Programming\/}). Once a control sequence enters the
+table, it is never removed, because there are complicated situations
+involving \.{\\gdef} where the removal of a control sequence at the end of
+a group would be a mistake preventable only by the introduction of a
+complicated reference-count mechanism.
+
+The actual sequence of letters forming a control sequence identifier is
+stored in the |str_pool| array together with all the other strings. An
+auxiliary array |hash| consists of items with two halfword fields per
+word. The first of these, called |next(p)|, points to the next identifier
+belonging to the same coalesced list as the identifier corresponding to~|p|;
+and the other, called |text(p)|, points to the |str_start| entry for
+|p|'s identifier. If position~|p| of the hash table is empty, we have
+|text(p)=0|; if position |p| is either empty or the end of a coalesced
+hash list, we have |next(p)=0|. An auxiliary pointer variable called
+|hash_used| is maintained in such a way that all locations |p>=hash_used|
+are nonempty. The global variable |cs_count| tells how many multiletter
+control sequences have been defined, if statistics are being kept.
+
+A global boolean variable called |no_new_control_sequence| is set to
+|true| during the time that new hash table entries are forbidden.
+
+@d next(#) == hash[#].lh {link for coalesced lists}
+@d text(#) == hash[#].rh {string number for control sequence name}
+@d hash_is_full == (hash_used=hash_base) {test if all positions are occupied}
+@d font_id_text(#) == text(font_id_base+#) {a frozen font identifier's name}
+
+@<Glob...@>=
+@!hash: ^two_halves; {the hash table}
+@!yhash: ^two_halves; {auxiliary pointer for freeing hash}
+@!hash_used:pointer; {allocation pointer for |hash|}
+@!hash_extra:pointer; {|hash_extra=hash| above |eqtb_size|}
+@!hash_top:pointer; {maximum of the hash array}
+@!eqtb_top:pointer; {maximum of the |eqtb|}
+@!hash_high:pointer; {pointer to next high hash location}
+@!no_new_control_sequence:boolean; {are new identifiers legal?}
+@!cs_count:integer; {total number of known identifiers}
+
+@ @<Set init...@>=
+no_new_control_sequence:=true; {new identifiers are usually forbidden}
+
+@ @<Initialize table entries...@>=
+hash_used:=frozen_control_sequence; {nothing is used}
+hash_high:=0;
+cs_count:=0;
+eq_type(frozen_dont_expand):=dont_expand;
+text(frozen_dont_expand):="notexpanded:";
+@.notexpanded:@>
+
+@ Here is the subroutine that searches the hash table for an identifier
+that matches a given string of length |l>1| appearing in |buffer[j..
+(j+l-1)]|. If the identifier is found, the corresponding hash table address
+is returned. Otherwise, if the global variable |no_new_control_sequence|
+is |true|, the dummy address |undefined_control_sequence| is returned.
+Otherwise the identifier is inserted into the hash table and its location
+is returned.
+
+@p function id_lookup(@!j,@!l:integer):pointer; {search the hash table}
+label found; {go here if you found it}
+var h:integer; {hash code}
+@!d:integer; {number of characters in incomplete current string}
+@!p:pointer; {index in |hash| array}
+@!k:pointer; {index in |buffer| array}
+begin @<Compute the hash code |h|@>;
+p:=h+hash_base; {we start searching here; note that |0<=h<hash_prime|}
+loop@+begin if text(p)>0 then if length(text(p))=l then
+    if str_eq_buf(text(p),j) then goto found;
+  if next(p)=0 then
+    begin if no_new_control_sequence then
+      p:=undefined_control_sequence
+    else @<Insert a new control sequence after |p|, then make
+      |p| point to it@>;
+    goto found;
+    end;
+  p:=next(p);
+  end;
+found: id_lookup:=p;
+end;
+
+@ @<Insert a new control...@>=
+begin if text(p)>0 then
+  begin if hash_high<hash_extra then
+      begin incr(hash_high);
+      next(p):=hash_high+eqtb_size; p:=hash_high+eqtb_size;
+      end
+    else begin
+      repeat if hash_is_full then overflow("hash size",hash_size+hash_extra);
+@:TeX capacity exceeded hash size}{\quad hash size@>
+      decr(hash_used);
+      until text(hash_used)=0; {search for an empty location in |hash|}
+    next(p):=hash_used; p:=hash_used;
+    end;
+  end;
+str_room(l); d:=cur_length;
+while pool_ptr>str_start[str_ptr] do
+  begin decr(pool_ptr); str_pool[pool_ptr+l]:=str_pool[pool_ptr];
+  end; {move current string up to make room for another}
+for k:=j to j+l-1 do append_char(buffer[k]);
+text(p):=make_string; pool_ptr:=pool_ptr+d;
+@!stat incr(cs_count);@+tats@;@/
+end
+
+@ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
+should be a prime number.  The theory of hashing tells us to expect fewer
+than two table probes, on the average, when the search is successful.
+[See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
+@^Vitter, Jeffrey Scott@>
+
+@<Compute the hash code |h|@>=
+h:=buffer[j];
+for k:=j+1 to j+l-1 do
+  begin h:=h+h+buffer[k];
+  while h>=hash_prime do h:=h-hash_prime;
+  end
+
+@ Single-character control sequences do not need to be looked up in a hash
+table, since we can use the character code itself as a direct address.
+The procedure |print_cs| prints the name of a control sequence, given
+a pointer to its address in |eqtb|. A space is printed after the name
+unless it is a single nonletter or an active character. This procedure
+might be invoked with invalid data, so it is ``extra robust.'' The
+individual characters must be printed one at a time using |print|, since
+they may be unprintable.
+
+@<Basic printing...@>=
+procedure print_cs(@!p:integer); {prints a purported control sequence}
+begin if p<hash_base then {single character}
+  if p>=single_base then
+    if p=null_cs then
+      begin print_esc("csname"); print_esc("endcsname");
+      end
+    else  begin print_esc(p-single_base);
+      if cat_code(p-single_base)=letter then print_char(" ");
+      end
+  else if p<active_base then print_esc("IMPOSSIBLE.")
+@.IMPOSSIBLE@>
+  else print(p-active_base)
+else if ((p>=undefined_control_sequence)and(p<=eqtb_size))or(p>eqtb_top) then
+  print_esc("IMPOSSIBLE.")
+else if (text(p)>=str_ptr) then print_esc("NONEXISTENT.")
+@.NONEXISTENT@>
+else  begin print_esc(text(p));
+  print_char(" ");
+  end;
+end;
+
+@ Here is a similar procedure; it avoids the error checks, and it never
+prints a space after the control sequence.
+
+@<Basic printing procedures@>=
+procedure sprint_cs(@!p:pointer); {prints a control sequence}
+begin if p<hash_base then
+  if p<single_base then print(p-active_base)
+  else  if p<null_cs then print_esc(p-single_base)
+    else  begin print_esc("csname"); print_esc("endcsname");
+      end
+else print_esc(text(p));
+end;
+
+@ We need to put \TeX's ``primitive'' control sequences into the hash
+table, together with their command code (which will be the |eq_type|)
+and an operand (which will be the |equiv|). The |primitive| procedure
+does this, in a way that no \TeX\ user can. The global value |cur_val|
+contains the new |eqtb| pointer after |primitive| has acted.
+
+@p @!init procedure primitive(@!s:str_number;@!c:quarterword;@!o:halfword);
+var k:pool_pointer; {index into |str_pool|}
+@!j:small_number; {index into |buffer|}
+@!l:small_number; {length of the string}
+begin if s<256 then cur_val:=s+single_base
+else  begin k:=str_start[s]; l:=str_start[s+1]-k;
+    {we will move |s| into the (empty) |buffer|}
+  for j:=0 to l-1 do buffer[j]:=so(str_pool[k+j]);
+  cur_val:=id_lookup(0,l); {|no_new_control_sequence| is |false|}
+  flush_string; text(cur_val):=s; {we don't want to have the string twice}
+  end;
+eq_level(cur_val):=level_one; eq_type(cur_val):=c; equiv(cur_val):=o;
+end;
+tini
+
+@ Many of \TeX's primitives need no |equiv|, since they are identifiable
+by their |eq_type| alone. These primitives are loaded into the hash table
+as follows:
+
+@<Put each of \TeX's primitives into the hash table@>=
+primitive(" ",ex_space,0);@/
+@!@:Single-character primitives /}{\quad\.{\\\ }@>
+primitive("/",ital_corr,0);@/
+@!@:Single-character primitives /}{\quad\.{\\/}@>
+primitive("accent",accent,0);@/
+@!@:accent_}{\.{\\accent} primitive@>
+primitive("advance",advance,0);@/
+@!@:advance_}{\.{\\advance} primitive@>
+primitive("afterassignment",after_assignment,0);@/
+@!@:after_assignment_}{\.{\\afterassignment} primitive@>
+primitive("aftergroup",after_group,0);@/
+@!@:after_group_}{\.{\\aftergroup} primitive@>
+primitive("begingroup",begin_group,0);@/
+@!@:begin_group_}{\.{\\begingroup} primitive@>
+primitive("char",char_num,0);@/
+@!@:char_}{\.{\\char} primitive@>
+primitive("csname",cs_name,0);@/
+@!@:cs_name_}{\.{\\csname} primitive@>
+primitive("delimiter",delim_num,0);@/
+@!@:delimiter_}{\.{\\delimiter} primitive@>
+primitive("divide",divide,0);@/
+@!@:divide_}{\.{\\divide} primitive@>
+primitive("endcsname",end_cs_name,0);@/
+@!@:end_cs_name_}{\.{\\endcsname} primitive@>
+primitive("endgroup",end_group,0);
+@!@:end_group_}{\.{\\endgroup} primitive@>
+text(frozen_end_group):="endgroup"; eqtb[frozen_end_group]:=eqtb[cur_val];@/
+primitive("expandafter",expand_after,0);@/
+@!@:expand_after_}{\.{\\expandafter} primitive@>
+primitive("font",def_font,0);@/
+@!@:font_}{\.{\\font} primitive@>
+primitive("jfont",def_jfont,0);@/
+@!@:jfont_}{\.{\\jfont} primitive@>
+primitive("tfont",def_tfont,0);@/
+@!@:tfont_}{\.{\\tfont} primitive@>
+primitive("fontdimen",assign_font_dimen,0);@/
+@!@:font_dimen_}{\.{\\fontdimen} primitive@>
+primitive("halign",halign,0);@/
+@!@:halign_}{\.{\\halign} primitive@>
+primitive("hrule",hrule,0);@/
+@!@:hrule_}{\.{\\hrule} primitive@>
+primitive("ignorespaces",ignore_spaces,0);@/
+@!@:ignore_spaces_}{\.{\\ignorespaces} primitive@>
+primitive("insert",insert,0);@/
+@!@:insert_}{\.{\\insert} primitive@>
+primitive("mark",mark,0);@/
+@!@:mark_}{\.{\\mark} primitive@>
+primitive("mathaccent",math_accent,0);@/
+@!@:math_accent_}{\.{\\mathaccent} primitive@>
+primitive("mathchar",math_char_num,0);@/
+@!@:math_char_}{\.{\\mathchar} primitive@>
+primitive("mathchoice",math_choice,0);@/
+@!@:math_choice_}{\.{\\mathchoice} primitive@>
+primitive("multiply",multiply,0);@/
+@!@:multiply_}{\.{\\multiply} primitive@>
+primitive("noalign",no_align,0);@/
+@!@:no_align_}{\.{\\noalign} primitive@>
+primitive("noboundary",no_boundary,0);@/
+@!@:no_boundary_}{\.{\\noboundary} primitive@>
+primitive("noexpand",no_expand,0);@/
+@!@:no_expand_}{\.{\\noexpand} primitive@>
+primitive("nonscript",non_script,0);@/
+@!@:non_script_}{\.{\\nonscript} primitive@>
+primitive("omit",omit,0);@/
+@!@:omit_}{\.{\\omit} primitive@>
+primitive("parshape",set_shape,0);@/
+@!@:par_shape_}{\.{\\parshape} primitive@>
+primitive("penalty",break_penalty,0);@/
+@!@:penalty_}{\.{\\penalty} primitive@>
+primitive("prevgraf",set_prev_graf,0);@/
+@!@:prev_graf_}{\.{\\prevgraf} primitive@>
+primitive("radical",radical,0);@/
+@!@:radical_}{\.{\\radical} primitive@>
+primitive("read",read_to_cs,0);@/
+@!@:read_}{\.{\\read} primitive@>
+primitive("relax",relax,256); {cf.\ |scan_file_name|}
+@!@:relax_}{\.{\\relax} primitive@>
+text(frozen_relax):="relax"; eqtb[frozen_relax]:=eqtb[cur_val];@/
+primitive("setbox",set_box,0);@/
+@!@:set_box_}{\.{\\setbox} primitive@>
+primitive("the",the,0);@/
+@!@:the_}{\.{\\the} primitive@>
+primitive("toks",toks_register,0);@/
+@!@:toks_}{\.{\\toks} primitive@>
+primitive("vadjust",vadjust,0);@/
+@!@:vadjust_}{\.{\\vadjust} primitive@>
+primitive("valign",valign,0);@/
+@!@:valign_}{\.{\\valign} primitive@>
+primitive("vcenter",vcenter,0);@/
+@!@:vcenter_}{\.{\\vcenter} primitive@>
+primitive("vrule",vrule,0);@/
+@!@:vrule_}{\.{\\vrule} primitive@>
+
+@ Each primitive has a corresponding inverse, so that it is possible to
+display the cryptic numeric contents of |eqtb| in symbolic form.
+Every call of |primitive| in this program is therefore accompanied by some
+straightforward code that forms part of the |print_cmd_chr| routine
+below.
+
+@<Cases of |print_cmd_chr|...@>=
+accent: print_esc("accent");
+advance: print_esc("advance");
+after_assignment: print_esc("afterassignment");
+after_group: print_esc("aftergroup");
+assign_font_dimen: print_esc("fontdimen");
+begin_group: print_esc("begingroup");
+break_penalty: print_esc("penalty");
+char_num: print_esc("char");
+cs_name: print_esc("csname");
+def_font: print_esc("font");
+def_jfont: print_esc("jfont");
+def_tfont: print_esc("tfont");
+delim_num: print_esc("delimiter");
+divide: print_esc("divide");
+end_cs_name: print_esc("endcsname");
+end_group: print_esc("endgroup");
+ex_space: print_esc(" ");
+expand_after: print_esc("expandafter");
+halign: print_esc("halign");
+hrule: print_esc("hrule");
+ignore_spaces: print_esc("ignorespaces");
+insert: print_esc("insert");
+ital_corr: print_esc("/");
+mark: print_esc("mark");
+math_accent: print_esc("mathaccent");
+math_char_num: print_esc("mathchar");
+math_choice: print_esc("mathchoice");
+multiply: print_esc("multiply");
+no_align: print_esc("noalign");
+no_boundary:print_esc("noboundary");
+no_expand: print_esc("noexpand");
+non_script: print_esc("nonscript");
+omit: print_esc("omit");
+radical: print_esc("radical");
+read_to_cs: print_esc("read");
+relax: print_esc("relax");
+set_box: print_esc("setbox");
+set_prev_graf: print_esc("prevgraf");
+set_shape: print_esc("parshape");
+the: print_esc("the");
+toks_register: print_esc("toks");
+vadjust: print_esc("vadjust");
+valign: print_esc("valign");
+vcenter: print_esc("vcenter");
+vrule: print_esc("vrule");
+
+@ We will deal with the other primitives later, at some point in the program
+where their |eq_type| and |equiv| values are more meaningful.  For example,
+the primitives for math mode will be loaded when we consider the routines
+that deal with formulas. It is easy to find where each particular
+primitive was treated by looking in the index at the end; for example, the
+section where |"radical"| entered |eqtb| is listed under `\.{\\radical}
+primitive'. (Primitives consisting of a single nonalphabetic character,
+@!like `\.{\\/}', are listed under `Single-character primitives'.)
+@!@^Single-character primitives@>
+
+Meanwhile, this is a convenient place to catch up on something we were unable
+to do before the hash table was defined:
+
+@<Print the font identifier for |font(p)|@>=
+print_esc(font_id_text(font(p)))
+
+@* \[19] Saving and restoring equivalents.
+The nested structure provided by `$\.{\char'173}\ldots\.{\char'175}$' groups
+in \TeX\ means that |eqtb| entries valid in outer groups should be saved
+and restored later if they are overridden inside the braces. When a new |eqtb|
+value is being assigned, the program therefore checks to see if the previous
+entry belongs to an outer level. In such a case, the old value is placed
+on the |save_stack| just before the new value enters |eqtb|. At the
+end of a grouping level, i.e., when the right brace is sensed, the
+|save_stack| is used to restore the outer values, and the inner ones are
+destroyed.
+
+Entries on the |save_stack| are of type |memory_word|. The top item on
+this stack is |save_stack[p]|, where |p=save_ptr-1|; it contains three
+fields called |save_type|, |save_level|, and |save_index|, and it is
+interpreted in one of four ways:
+
+\yskip\hangg 1) If |save_type(p)=restore_old_value|, then
+|save_index(p)| is a location in |eqtb| whose current value should
+be destroyed at the end of the current group and replaced by |save_stack[p-1]|.
+Furthermore if |save_index(p)>=int_base|, then |save_level(p)|
+should replace the corresponding entry in |xeq_level|.
+
+\yskip\hangg 2) If |save_type(p)=restore_zero|, then |save_index(p)|
+is a location in |eqtb| whose current value should be destroyed at the end
+of the current group, when it should be
+replaced by the current value of |eqtb[undefined_control_sequence]|.
+
+\yskip\hangg 3) If |save_type(p)=insert_token|, then |save_index(p)|
+is a token that should be inserted into \TeX's input when the current
+group ends.
+
+\yskip\hangg 4) If |save_type(p)=level_boundary|, then |save_level(p)|
+is a code explaining what kind of group we were previously in, and
+|save_index(p)| points to the level boundary word at the bottom of
+the entries for that group.
+
+@d save_type(#)==save_stack[#].hh.b0 {classifies a |save_stack| entry}
+@d save_level(#)==save_stack[#].hh.b1
+  {saved level for regions 5 and 6, or group code}
+@d save_index(#)==save_stack[#].hh.rh
+  {|eqtb| location or token or |save_stack| location}
+@d restore_old_value=0 {|save_type| when a value should be restored later}
+@d restore_zero=1 {|save_type| when an undefined entry should be restored}
+@d insert_token=2 {|save_type| when a token is being saved for later use}
+@d level_boundary=3 {|save_type| corresponding to beginning of group}
+
+@ Here are the group codes that are used to discriminate between different
+kinds of groups. They allow \TeX\ to decide what special actions, if any,
+should be performed when a group ends.
+\def\grp{\.{\char'173...\char'175}}
+
+Some groups are not supposed to be ended by right braces. For example,
+the `\.\$' that begins a math formula causes a |math_shift_group| to
+be started, and this should be terminated by a matching `\.\$'. Similarly,
+a group that starts with \.{\\left} should end with \.{\\right}, and
+one that starts with \.{\\begingroup} should end with \.{\\endgroup}.
+
+@d bottom_level=0 {group code for the outside world}
+@d simple_group=1 {group code for local structure only}
+@d hbox_group=2 {code for `\.{\\hbox}\grp'}
+@d adjusted_hbox_group=3 {code for `\.{\\hbox}\grp' in vertical mode}
+@d vbox_group=4 {code for `\.{\\vbox}\grp'}
+@d vtop_group=5 {code for `\.{\\vtop}\grp'}
+@d align_group=6 {code for `\.{\\halign}\grp', `\.{\\valign}\grp'}
+@d no_align_group=7 {code for `\.{\\noalign}\grp'}
+@d output_group=8 {code for output routine}
+@d math_group=9 {code for, e.g., `\.{\char'136}\grp'}
+@d disc_group=10 {code for `\.{\\discretionary}\grp\grp\grp'}
+@d insert_group=11 {code for `\.{\\insert}\grp', `\.{\\vadjust}\grp'}
+@d vcenter_group=12 {code for `\.{\\vcenter}\grp'}
+@d math_choice_group=13 {code for `\.{\\mathchoice}\grp\grp\grp\grp'}
+@d semi_simple_group=14 {code for `\.{\\begingroup...\\endgroup}'}
+@d math_shift_group=15 {code for `\.{\$...\$}'}
+@d math_left_group=16 {code for `\.{\\left...\\right}'}
+@d max_group_code=16
+
+@<Types...@>=
+@!group_code=0..max_group_code; {|save_level| for a level boundary}
+
+@ The global variable |cur_group| keeps track of what sort of group we are
+currently in. Another global variable, |cur_boundary|, points to the
+topmost |level_boundary| word.  And |cur_level| is the current depth of
+nesting. The routines are designed to preserve the condition that no entry
+in the |save_stack| or in |eqtb| ever has a level greater than |cur_level|.
+
+@ @<Glob...@>=
+@!save_stack : ^memory_word;
+@!save_ptr : 0..save_size; {first unused entry on |save_stack|}
+@!max_save_stack:0..save_size; {maximum usage of save stack}
+@!cur_level: quarterword; {current nesting level for groups}
+@!cur_group: group_code; {current group type}
+@!cur_boundary: 0..save_size; {where the current level begins}
+
+@ At this time it might be a good idea for the reader to review the introduction
+to |eqtb| that was given above just before the long lists of parameter names.
+Recall that the ``outer level'' of the program is |level_one|, since
+undefined control sequences are assumed to be ``defined'' at |level_zero|.
+
+@<Set init...@>=
+save_ptr:=0; cur_level:=level_one; cur_group:=bottom_level; cur_boundary:=0;
+max_save_stack:=0;
+
+@ The following macro is used to test if there is room for up to six more
+entries on |save_stack|. By making a conservative test like this, we can
+get by with testing for overflow in only a few places.
+
+@d check_full_save_stack==if save_ptr>max_save_stack then
+  begin max_save_stack:=save_ptr;
+  if max_save_stack>save_size-6 then overflow("save size",save_size);
+@:TeX capacity exceeded save size}{\quad save size@>
+  end
+
+@ Procedure |new_save_level| is called when a group begins. The
+argument is a group identification code like `|hbox_group|'. After
+calling this routine, it is safe to put five more entries on |save_stack|.
+
+In some cases integer-valued items are placed onto the
+|save_stack| just below a |level_boundary| word, because this is a
+convenient place to keep information that is supposed to ``pop up'' just
+when the group has finished.
+For example, when `\.{\\hbox to 100pt}\grp' is being treated, the 100pt
+dimension is stored on |save_stack| just before |new_save_level| is
+called.
+
+We use the notation |saved(k)| to stand for an integer item that
+appears in location |save_ptr+k| of the save stack.
+
+@d saved(#)==save_stack[save_ptr+#].int
+
+@p procedure new_save_level(@!c:group_code); {begin a new level of grouping}
+begin check_full_save_stack;
+save_type(save_ptr):=level_boundary; save_level(save_ptr):=cur_group;
+save_index(save_ptr):=cur_boundary;
+if cur_level=max_quarterword then overflow("grouping levels",
+@:TeX capacity exceeded grouping levels}{\quad grouping levels@>
+  max_quarterword-min_quarterword);
+  {quit if |(cur_level+1)| is too big to be stored in |eqtb|}
+cur_boundary:=save_ptr; incr(cur_level); incr(save_ptr); cur_group:=c;
+end;
+
+@ Just before an entry of |eqtb| is changed, the following procedure should
+be called to update the other data structures properly. It is important
+to keep in mind that reference counts in |mem| include references from
+within |save_stack|, so these counts must be handled carefully.
+@^reference counts@>
+
+@p procedure eq_destroy(@!w:memory_word); {gets ready to forget |w|}
+var q:pointer; {|equiv| field of |w|}
+begin case eq_type_field(w) of
+call,long_call,outer_call,long_outer_call: delete_token_ref(equiv_field(w));
+glue_ref: delete_glue_ref(equiv_field(w));
+shape_ref: begin q:=equiv_field(w); {we need to free a \.{\\parshape} block}
+  if q<>null then free_node(q,info(q)+info(q)+1);
+  end; {such a block is |2n+1| words long, where |n=info(q)|}
+box_ref: flush_node_list(equiv_field(w));
+othercases do_nothing
+endcases;
+end;
+
+@ To save a value of |eqtb[p]| that was established at level |l|, we
+can use the following subroutine.
+
+@p procedure eq_save(@!p:pointer;@!l:quarterword); {saves |eqtb[p]|}
+begin check_full_save_stack;
+if l=level_zero then save_type(save_ptr):=restore_zero
+else  begin save_stack[save_ptr]:=eqtb[p]; incr(save_ptr);
+  save_type(save_ptr):=restore_old_value;
+  end;
+save_level(save_ptr):=l; save_index(save_ptr):=p; incr(save_ptr);
+end;
+
+@ The procedure |eq_define| defines an |eqtb| entry having specified
+|eq_type| and |equiv| fields, and saves the former value if appropriate.
+This procedure is used only for entries in the first four regions of |eqtb|,
+i.e., only for entries that have |eq_type| and |equiv| fields.
+After calling this routine, it is safe to put four more entries on
+|save_stack|, provided that there was room for four more entries before
+the call, since |eq_save| makes the necessary test.
+
+@p procedure eq_define(@!p:pointer;@!t:quarterword;@!e:halfword);
+  {new data for |eqtb|}
+begin if eq_level(p)=cur_level then eq_destroy(eqtb[p])
+else if cur_level>level_one then eq_save(p,eq_level(p));
+eq_level(p):=cur_level; eq_type(p):=t; equiv(p):=e;
+end;
+
+@ The counterpart of |eq_define| for the remaining (fullword) positions in
+|eqtb| is called |eq_word_define|. Since |xeq_level[p]>=level_one| for all
+|p|, a `|restore_zero|' will never be used in this case.
+
+@p procedure eq_word_define(@!p:pointer;@!w:integer);
+begin if xeq_level[p]<>cur_level then
+  begin eq_save(p,xeq_level[p]); xeq_level[p]:=cur_level;
+  end;
+eqtb[p].int:=w;
+end;
+
+@ The |eq_define| and |eq_word_define| routines take care of local definitions.
+@^global definitions@>
+Global definitions are done in almost the same way, but there is no need
+to save old values, and the new value is associated with |level_one|.
+
+@p procedure geq_define(@!p:pointer;@!t:quarterword;@!e:halfword);
+  {global |eq_define|}
+begin eq_destroy(eqtb[p]);
+eq_level(p):=level_one; eq_type(p):=t; equiv(p):=e;
+end;
+@#
+procedure geq_word_define(@!p:pointer;@!w:integer); {global |eq_word_define|}
+begin eqtb[p].int:=w; xeq_level[p]:=level_one;
+end;
+
+@ Subroutine |save_for_after| puts a token on the stack for save-keeping.
+
+@p procedure save_for_after(@!t:halfword);
+begin if cur_level>level_one then
+  begin check_full_save_stack;
+  save_type(save_ptr):=insert_token; save_level(save_ptr):=level_zero;
+  save_index(save_ptr):=t; incr(save_ptr);
+  end;
+end;
+
+@ The |unsave| routine goes the other way, taking items off of |save_stack|.
+This routine takes care of restoration when a level ends; everything
+belonging to the topmost group is cleared off of the save stack.
+
+@p@t\4@>@<Declare the procedure called |restore_trace|@>@;@/
+procedure@?back_input; forward; @t\2@>
+procedure unsave; {pops the top level off the save stack}
+label done;
+var p:pointer; {position to be restored}
+@!l:quarterword; {saved level, if in fullword regions of |eqtb|}
+@!t:halfword; {saved value of |cur_tok|}
+begin if cur_level>level_one then
+  begin decr(cur_level);
+  @<Clear off top level from |save_stack|@>;
+  end
+else confusion("curlevel"); {|unsave| is not used when |cur_group=bottom_level|}
+@:this can't happen curlevel}{\quad curlevel@>
+end;
+
+@ @<Clear off...@>=
+loop@+begin decr(save_ptr);
+  if save_type(save_ptr)=level_boundary then goto done;
+  p:=save_index(save_ptr);
+  if save_type(save_ptr)=insert_token then
+    @<Insert token |p| into \TeX's input@>
+  else  begin if save_type(save_ptr)=restore_old_value then
+      begin l:=save_level(save_ptr); decr(save_ptr);
+      end
+    else save_stack[save_ptr]:=eqtb[undefined_control_sequence];
+    @<Store \(s)|save_stack[save_ptr]| in |eqtb[p]|, unless
+      |eqtb[p]| holds a global value@>;
+    end;
+  end;
+done: cur_group:=save_level(save_ptr); cur_boundary:=save_index(save_ptr)
+
+@ A global definition, which sets the level to |level_one|,
+@^global definitions@>
+will not be undone by |unsave|. If at least one global definition of
+|eqtb[p]| has been carried out within the group that just ended, the
+last such definition will therefore survive.
+
+@<Store \(s)|save...@>=
+if (p<int_base)or(p>eqtb_size) then
+  if eq_level(p)=level_one then
+    begin eq_destroy(save_stack[save_ptr]); {destroy the saved value}
+    @!stat if tracing_restores>0 then restore_trace(p,"retaining");@+tats@;@/
+    end
+  else  begin eq_destroy(eqtb[p]); {destroy the current value}
+    eqtb[p]:=save_stack[save_ptr]; {restore the saved value}
+    @!stat if tracing_restores>0 then restore_trace(p,"restoring");@+tats@;@/
+    end
+else if xeq_level[p]<>level_one then
+  begin eqtb[p]:=save_stack[save_ptr]; xeq_level[p]:=l;
+  @!stat if tracing_restores>0 then restore_trace(p,"restoring");@+tats@;@/
+  end
+else  begin
+  @!stat if tracing_restores>0 then restore_trace(p,"retaining");@+tats@;@/
+  end
+
+@ @<Declare the procedure called |restore_trace|@>=
+@!stat procedure restore_trace(@!p:pointer;@!s:str_number);
+  {|eqtb[p]| has just been restored or retained}
+begin begin_diagnostic; print_char("{"); print(s); print_char(" ");
+show_eqtb(p); print_char("}");
+end_diagnostic(false);
+end;
+tats
+
+@ When looking for possible pointers to a memory location, it is helpful
+to look for references from |eqtb| that might be waiting on the
+save stack. Of course, we might find spurious pointers too; but this
+routine is merely an aid when debugging, and at such times we are
+grateful for any scraps of information, even if they prove to be irrelevant.
+@^dirty \PASCAL@>
+
+@<Search |save_stack| for equivalents that point to |p|@>=
+if save_ptr>0 then for q:=0 to save_ptr-1 do
+  begin if equiv_field(save_stack[q])=p then
+    begin print_nl("SAVE("); print_int(q); print_char(")");
+    end;
+  end
+
+@ Most of the parameters kept in |eqtb| can be changed freely, but there's
+an exception:  The magnification should not be used with two different
+values during any \TeX\ job, since a single magnification is applied to an
+entire run. The global variable |mag_set| is set to the current magnification
+whenever it becomes necessary to ``freeze'' it at a particular value.
+
+@<Glob...@>=
+@!mag_set:integer; {if nonzero, this magnification should be used henceforth}
+
+@ @<Set init...@>=
+mag_set:=0;
+
+@ The |prepare_mag| subroutine is called whenever \TeX\ wants to use |mag|
+for magnification.
+
+@p procedure prepare_mag;
+begin if (mag_set>0)and(mag<>mag_set) then
+  begin print_err("Incompatible magnification ("); print_int(mag);
+@.Incompatible magnification@>
+  print(");"); print_nl(" the previous value will be retained");
+  help2("I can handle only one magnification ratio per job. So I've")@/
+  ("reverted to the magnification you used earlier on this run.");@/
+  int_error(mag_set);
+  geq_word_define(int_base+mag_code,mag_set); {|mag:=mag_set|}
+  end;
+if (mag<=0)or(mag>32768) then
+  begin print_err("Illegal magnification has been changed to 1000");@/
+@.Illegal magnification...@>
+  help1("The magnification ratio must be between 1 and 32768.");
+  int_error(mag); geq_word_define(int_base+mag_code,1000);
+  end;
+mag_set:=mag;
+end;
+
+@* \[20] Token lists.
+A \TeX\ token is either a character or a control sequence, and it is
+@^token@>
+represented internally in one of two ways: (1)~A character whose ASCII
+code number is |c| and whose command code is |m| is represented as the
+number $2^8m+c$; the command code is in the range |1<=m<=14|. (2)~A control
+sequence whose |eqtb| address is |p| is represented as the number
+|cs_token_flag+p|. Here |cs_token_flag=@t$2^{12}-1$@>| is larger than
+$2^8m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|;
+thus, a token fits comfortably in a halfword.
+
+A token |t| represents a |left_brace| command if and only if
+|t<left_brace_limit|; it represents a |right_brace| command if and only if
+we have |left_brace_limit<=t<right_brace_limit|; and it represents a |match| or
+|end_match| command if and only if |match_token<=t<=end_match_token|.
+The following definitions take care of these token-oriented constants
+and a few others.
+
+@d cs_token_flag==@"FFFF {amount added to the |eqtb| location in a
+token that stands for a control sequence; is a multiple of~256, less~1}
+@d left_brace_token=@'0400 {$2^8\cdot|left_brace|$}
+@d left_brace_limit=@'1000 {$2^8\cdot(|left_brace|+1)$}
+@d right_brace_token=@'1000 {$2^8\cdot|right_brace|$}
+@d right_brace_limit=@'1400 {$2^8\cdot(|right_brace|+1)$}
+@d math_shift_token=@'1400 {$2^8\cdot|math_shift|$}
+@d tab_token=@'2000 {$2^8\cdot|tab_mark|$}
+@d out_param_token=@'2400 {$2^8\cdot|out_param|$}
+@d space_token=@'5040 {$2^8\cdot|spacer|+|" "|$}
+@d letter_token=@'5400 {$2^8\cdot|letter|$}
+@d other_token=@'6000 {$2^8\cdot|other_char|$}
+@d match_token=@'6400 {$2^8\cdot|match|$}
+@d end_match_token=@'7000 {$2^8\cdot|end_match|$}
+
+@ @<Check the ``constant''...@>=
+if cs_token_flag+eqtb_size+hash_extra>max_halfword then bad:=21;
+if (hash_offset<0)or(hash_offset>hash_base) then bad:=42;
+
+@ A token list is a singly linked list of one-word nodes in |mem|, where
+each word contains a token and a link. Macro definitions, output-routine
+definitions, marks, \.{\\write} texts, and a few other things
+are remembered by \TeX\ in the form
+of token lists, usually preceded by a node with a reference count in its
+|token_ref_count| field. The token stored in location |p| is called
+|info(p)|.
+
+Three special commands appear in the token lists of macro definitions.
+When |m=match|, it means that \TeX\ should scan a parameter
+for the current macro; when |m=end_match|, it means that parameter
+matching should end and \TeX\ should start reading the macro text; and
+when |m=out_param|, it means that \TeX\ should insert parameter
+number |c| into the text at this point.
+
+The enclosing \.{\char'173} and \.{\char'175} characters of a macro
+definition are omitted, but the final right brace of an output routine
+is included at the end of its token list.
+
+Here is an example macro definition that illustrates these conventions.
+After \TeX\ processes the text
+$$\.{\\def\\mac a\#1\#2 \\b \{\#1\\-a \#\#1\#2 \#2\}}$$
+the definition of \.{\\mac} is represented as a token list containing
+$$\def\,{\hskip2pt}
+\vbox{\halign{\hfil#\hfil\cr
+(reference count), |letter|\,\.a, |match|\,\#, |match|\,\#, |spacer|\,\.\ ,
+\.{\\b}, |end_match|,\cr
+|out_param|\,1, \.{\\-}, |letter|\,\.a, |spacer|\,\.\ , |mac_param|\,\#,
+|other_char|\,\.1,\cr
+|out_param|\,2, |spacer|\,\.\ , |out_param|\,2.\cr}}$$
+The procedure |scan_toks| builds such token lists, and |macro_call|
+does the parameter matching.
+@^reference counts@>
+
+Examples such as
+$$\.{\\def\\m\{\\def\\m\{a\}\ b\}}$$
+explain why reference counts would be needed even if \TeX\ had no \.{\\let}
+operation: When the token list for \.{\\m} is being read, the redefinition of
+\.{\\m} changes the |eqtb| entry before the token list has been fully
+consumed, so we dare not simply destroy a token list when its
+control sequence is being redefined.
+
+If the parameter-matching part of a definition ends with `\.{\#\{}',
+the corresponding token list will have `\.\{' just before the `|end_match|'
+and also at the very end. The first `\.\{' is used to delimit the parameter; the
+second one keeps the first from disappearing.
+
+@ The procedure |show_token_list|, which prints a symbolic form of
+the token list that starts at a given node |p|, illustrates these
+conventions. The token list being displayed should not begin with a reference
+count. However, the procedure is intended to be robust, so that if the
+memory links are awry or if |p| is not really a pointer to a token list,
+nothing catastrophic will happen.
+
+An additional parameter |q| is also given; this parameter is either null
+or it points to a node in the token list where a certain magic computation
+takes place that will be explained later. (Basically, |q| is non-null when
+we are printing the two-line context information at the time of an error
+message; |q| marks the place corresponding to where the second line
+should begin.)
+
+For example, if |p| points to the node containing the first \.a in the
+token list above, then |show_token_list| will print the string
+$$\hbox{`\.{a\#1\#2\ \\b\ ->\#1\\-a\ \#\#1\#2\ \#2}';}$$
+and if |q| points to the node containing the second \.a,
+the magic computation will be performed just before the second \.a is printed.
+
+The generation will stop, and `\.{\\ETC.}' will be printed, if the length
+of printing exceeds a given limit~|l|. Anomalous entries are printed in the
+form of control sequences that are not followed by a blank space, e.g.,
+`\.{\\BAD.}'; this cannot be confused with actual control sequences because
+a real control sequence named \.{BAD} would come out `\.{\\BAD\ }'.
+
+@<Declare the procedure called |show_token_list|@>=
+procedure show_token_list(@!p,@!q:integer;@!l:integer);
+label exit;
+var m,@!c:integer; {pieces of a token}
+@!match_chr:ASCII_code; {character used in a `|match|'}
+@!n:ASCII_code; {the highest parameter number, as an ASCII digit}
+begin match_chr:="#"; n:="0"; tally:=0;
+while (p<>null) and (tally<l) do
+  begin if p=q then @<Do magic computation@>;
+  @<Display token |p|, and |return| if there are problems@>;
+  p:=link(p);
+  end;
+if p<>null then print_esc("ETC.");
+@.ETC@>
+exit:
+end;
+
+@ @<Display token |p|...@>=
+if (p<hi_mem_min) or (p>mem_end) then
+  begin print_esc("CLOBBERED."); return;
+@.CLOBBERED@>
+  end;
+if info(p)>=cs_token_flag then print_cs(info(p)-cs_token_flag) {|wchar_token|}
+else  begin
+  if check_kanji(info(p)) then {|wchar_token|}
+    begin m:=kcat_code(kcatcodekey(info(p))); c:=info(p);
+    end
+  else  begin m:=Hi(info(p)); c:=Lo(info(p));
+    end;
+  if (m<kanji)and(c>256) then print_esc("BAD.")
+@.BAD@>
+  else @<Display the token $(|m|,|c|)$@>;
+end
+
+@ The procedure usually ``learns'' the character code used for macro
+parameters by seeing one in a |match| command before it runs into any
+|out_param| commands.
+
+@<Display the token ...@>=
+case m of
+kanji,kana,other_kchar: print_kanji(KANJI(c));
+left_brace,right_brace,math_shift,tab_mark,sup_mark,sub_mark,spacer,
+  letter,other_char: print(c);
+mac_param: begin print(c); print(c);
+  end;
+out_param: begin print(match_chr);
+  if c<=9 then print_char(c+"0")
+  else  begin print_char("!"); return;
+    end;
+  end;
+match: begin match_chr:=c; print(c); incr(n); print_char(n);
+  if n>"9" then return;
+  end;
+end_match: print("->");
+@.->@>
+othercases print_esc("BAD.")
+@.BAD@>
+endcases
+
+@ Here's the way we sometimes want to display a token list, given a pointer
+to its reference count; the pointer may be null.
+
+@p procedure token_show(@!p:pointer);
+begin if p<>null then show_token_list(link(p),null,10000000);
+end;
+
+@ The |print_meaning| subroutine displays |cur_cmd| and |cur_chr| in
+symbolic form, including the expansion of a macro or mark.
+
+@p procedure print_meaning;
+begin print_cmd_chr(cur_cmd,cur_chr);
+if cur_cmd>=call then
+  begin print_char(":"); print_ln; token_show(cur_chr);
+  end
+else if cur_cmd=top_bot_mark then
+  begin print_char(":"); print_ln;
+  token_show(cur_mark[cur_chr]);
+  end;
+end;
+
+@* \[21] Introduction to the syntactic routines.
+Let's pause a moment now and try to look at the Big Picture.
+The \TeX\ program consists of three main parts: syntactic routines,
+semantic routines, and output routines. The chief purpose of the
+syntactic routines is to deliver the user's input to the semantic routines,
+one token at a time. The semantic routines act as an interpreter
+responding to these tokens, which may be regarded as commands. And the
+output routines are periodically called on to convert box-and-glue
+lists into a compact set of instructions that will be sent
+to a typesetter. We have discussed the basic data structures and utility
+routines of \TeX, so we are good and ready to plunge into the real activity by
+considering the syntactic routines.
+
+Our current goal is to come to grips with the |get_next| procedure,
+which is the keystone of \TeX's input mechanism. Each call of |get_next|
+sets the value of three variables |cur_cmd|, |cur_chr|, and |cur_cs|,
+representing the next input token.
+$$\vbox{\halign{#\hfil\cr
+  \hbox{|cur_cmd| denotes a command code from the long list of codes
+   given above;}\cr
+  \hbox{|cur_chr| denotes a character code or other modifier of the command
+   code;}\cr
+  \hbox{|cur_cs| is the |eqtb| location of the current control sequence,}\cr
+  \hbox{\qquad if the current token was a control sequence,
+   otherwise it's zero.}\cr}}$$
+Underlying this external behavior of |get_next| is all the machinery
+necessary to convert from character files to tokens. At a given time we
+may be only partially finished with the reading of several files (for
+which \.{\\input} was specified), and partially finished with the expansion
+of some user-defined macros and/or some macro parameters, and partially
+finished with the generation of some text in a template for \.{\\halign},
+and so on. When reading a character file, special characters must be
+classified as math delimiters, etc.; comments and extra blank spaces must
+be removed, paragraphs must be recognized, and control sequences must be
+found in the hash table. Furthermore there are occasions in which the
+scanning routines have looked ahead for a word like `\.{plus}' but only
+part of that word was found, hence a few characters must be put back
+into the input and scanned again.
+
+To handle these situations, which might all be present simultaneously,
+\TeX\ uses various stacks that hold information about the incomplete
+activities, and there is a finite state control for each level of the
+input mechanism. These stacks record the current state of an implicitly
+recursive process, but the |get_next| procedure is not recursive.
+Therefore it will not be difficult to translate these algorithms into
+low-level languages that do not support recursion.
+
+@<Glob...@>=
+@!cur_cmd: eight_bits; {current command set by |get_next|}
+@!cur_chr: halfword; {operand of current command}
+@!cur_cs: pointer; {control sequence found here, zero if none found}
+@!cur_tok: halfword; {packed representative of |cur_cmd| and |cur_chr|}
+
+@ The |print_cmd_chr| routine prints a symbolic interpretation of a
+command code and its modifier. This is used in certain `\.{You can\'t}'
+error messages, and in the implementation of diagnostic routines like
+\.{\\show}.
+
+The body of |print_cmd_chr| is a rather tedious listing of print
+commands, and most of it is essentially an inverse to the |primitive|
+routine that enters a \TeX\ primitive into |eqtb|. Therefore much of
+this procedure appears elsewhere in the program,
+together with the corresponding |primitive| calls.
+
+@d chr_cmd(#)==begin print(#); print_ASCII(chr_code);
+  end
+
+@<Declare the procedure called |print_cmd_chr|@>=
+procedure print_cmd_chr(@!cmd:quarterword;@!chr_code:halfword);
+begin case cmd of
+left_brace: chr_cmd("begin-group character ");
+right_brace: chr_cmd("end-group character ");
+math_shift: chr_cmd("math shift character ");
+mac_param: chr_cmd("macro parameter character ");
+sup_mark: chr_cmd("superscript character ");
+sub_mark: chr_cmd("subscript character ");
+endv: print("end of alignment template");
+spacer: chr_cmd("blank space ");
+letter: chr_cmd("the letter ");
+other_char: chr_cmd("the character ");
+kanji,kana,other_kchar: begin print("kanji character ");
+  print_kanji(KANJI(chr_code)); end;
+@t\4@>@<Cases of |print_cmd_chr| for symbolic printing of primitives@>@/
+othercases print("[unknown command code!]")
+endcases;
+end;
+
+@ Here is a procedure that displays the current command.
+
+@p procedure show_cur_cmd_chr;
+begin begin_diagnostic; print_nl("{");
+if mode<>shown_mode then
+  begin print_mode(mode); print(": "); shown_mode:=mode;
+  end;
+print_cmd_chr(cur_cmd,cur_chr); print_char("}");
+end_diagnostic(false);
+end;
+
+@* \[22] Input stacks and states.
+This implementation of
+\TeX\ uses two different conventions for representing sequential stacks.
+@^stack conventions@>@^conventions for representing stacks@>
+
+\yskip\hangg 1) If there is frequent access to the top entry, and if the
+stack is essentially never empty, then the top entry is kept in a global
+variable (even better would be a machine register), and the other entries
+appear in the array $\\{stack}[0\to(\\{ptr}-1)]$. For example, the
+semantic stack described above is handled this way, and so is the input
+stack that we are about to study.
+
+\yskip\hangg 2) If there is infrequent top access, the entire stack contents
+are in the array $\\{stack}[0\to(\\{ptr}-1)]$. For example, the |save_stack|
+is treated this way, as we have seen.
+
+\yskip\noindent
+The state of \TeX's input mechanism appears in the input stack, whose
+entries are records with six fields, called |state|, |index|, |start|, |loc|,
+|limit|, and |name|. This stack is maintained with
+convention~(1), so it is declared in the following way:
+
+@<Types...@>=
+@!in_state_record = record
+  @!state_field, @!index_field: quarterword;
+  @!start_field,@!loc_field, @!limit_field, @!name_field: halfword;
+  end;
+
+@ @<Glob...@>=
+@!input_stack : ^in_state_record;
+@!input_ptr : 0..stack_size; {first unused location of |input_stack|}
+@!max_in_stack: 0..stack_size; {largest value of |input_ptr| when pushing}
+@!cur_input : in_state_record;
+  {the ``top'' input state, according to convention (1)}
+
+@ We've already defined the special variable |loc==cur_input.loc_field|
+in our discussion of basic input-output routines. The other components of
+|cur_input| are defined in the same way:
+
+@d state==cur_input.state_field {current scanner state}
+@d index==cur_input.index_field {reference for buffer information}
+@d start==cur_input.start_field {starting position in |buffer|}
+@d limit==cur_input.limit_field {end of current line in |buffer|}
+@d name==cur_input.name_field {name of the current file}
+
+@ Let's look more closely now at the control variables
+(|state|,~|index|,~|start|,~|loc|,~|limit|,~|name|),
+assuming that \TeX\ is reading a line of characters that have been input
+from some file or from the user's terminal. There is an array called
+|buffer| that acts as a stack of all lines of characters that are
+currently being read from files, including all lines on subsidiary
+levels of the input stack that are not yet completed. \TeX\ will return to
+the other lines when it is finished with the present input file.
+
+(Incidentally, on a machine with byte-oriented addressing, it might be
+appropriate to combine |buffer| with the |str_pool| array,
+letting the buffer entries grow downward from the top of the string pool
+and checking that these two tables don't bump into each other.)
+
+The line we are currently working on begins in position |start| of the
+buffer; the next character we are about to read is |buffer[loc]|; and
+|limit| is the location of the last character present.  If |loc>limit|,
+the line has been completely read. Usually |buffer[limit]| is the
+|end_line_char|, denoting the end of a line, but this is not
+true if the current line is an insertion that was entered on the user's
+terminal in response to an error message.
+
+The |name| variable is a string number that designates the name of
+the current file, if we are reading a text file. It is zero if we
+are reading from the terminal; it is |n+1| if we are reading from
+input stream |n|, where |0<=n<=16|. (Input stream 16 stands for
+an invalid stream number; in such cases the input is actually from
+the terminal, under control of the procedure |read_toks|.)
+
+The |state| variable has one of three values, when we are scanning such
+files:
+$$\baselineskip 15pt\vbox{\halign{#\hfil\cr
+1) |state=mid_line| is the normal state.\cr
+2) |state=mid_kanji| is like |mid_line|, and internal KANJI string.\cr
+3) |state=skip_blanks| is like |mid_line|, but blanks are ignored.\cr
+4) |state=new_line| is the state at the beginning of a line.\cr}}$$
+These state values are assigned numeric codes so that if we add the state
+code to the next character's command code, we get distinct values. For
+example, `|mid_line+spacer|' stands for the case that a blank
+space character occurs in the middle of a line when it is not being
+ignored; after this case is processed, the next value of |state| will
+be |skip_blanks|.
+
+@d mid_line=1 {|state| code when scanning a line of characters}
+@d mid_kanji=2+max_char_code {|state| code when scanning a line of characters}
+@d skip_blanks=3+max_char_code+max_char_code {|state| code when ignoring blanks}
+@d new_line=4+max_char_code+max_char_code+max_char_code
+   {|state| code at start of line}
+
+@ Additional information about the current line is available via the
+|index| variable, which counts how many lines of characters are present
+in the buffer below the current level. We have |index=0| when reading
+from the terminal and prompting the user for each line; then if the user types,
+e.g., `\.{\\input paper}', we will have |index=1| while reading
+the file \.{paper.tex}. However, it does not follow that |index| is the
+same as the input stack pointer, since many of the levels on the input
+stack may come from token lists. For example, the instruction `\.{\\input
+paper}' might occur in a token list.
+
+The global variable |in_open| is equal to the |index|
+value of the highest non-token-list level. Thus, the number of partially read
+lines in the buffer is |in_open+1|, and we have |in_open=index|
+when we are not reading a token list.
+
+If we are not currently reading from the terminal, or from an input
+stream, we are reading from the file variable |input_file[index]|. We use
+the notation |terminal_input| as a convenient abbreviation for |name=0|,
+and |cur_file| as an abbreviation for |input_file[index]|.
+
+The global variable |line| contains the line number in the topmost
+open file, for use in error messages. If we are not reading from
+the terminal, |line_stack[index]| holds the line number for the
+enclosing level, so that |line| can be restored when the current
+file has been read. Line numbers should never be negative, since the
+negative of the current line number is used to identify the user's output
+routine in the |mode_line| field of the semantic nest entries.
+
+If more information about the input state is needed, it can be
+included in small arrays like those shown here. For example,
+the current page or segment number in the input file might be
+put into a variable |@!page|, maintained for enclosing levels in
+`\ignorespaces|@!page_stack:array[1..max_in_open] of integer|\unskip'
+by analogy with |line_stack|.
+@^system dependencies@>
+
+@d terminal_input==(name=0) {are we reading from the terminal?}
+@d cur_file==input_file[index] {the current |alpha_file| variable}
+
+@<Glob...@>=
+@!in_open : 0..max_in_open; {the number of lines in the buffer, less one}
+@!open_parens : 0..max_in_open; {the number of open text files}
+@!input_file : ^alpha_file;
+@!line : integer; {current line number in the current source file}
+@!line_stack : ^integer;
+@!source_filename_stack : ^str_number;
+@!full_source_filename_stack : ^str_number;
+
+@ Users of \TeX\ sometimes forget to balance left and right braces properly,
+and one of the ways \TeX\ tries to spot such errors is by considering an
+input file as broken into subfiles by control sequences that
+are declared to be \.{\\outer}.
+
+A variable called |scanner_status| tells \TeX\ whether or not to complain
+when a subfile ends. This variable has six possible values:
+
+\yskip\hang|normal|, means that a subfile can safely end here without incident.
+
+\yskip\hang|skipping|, means that a subfile can safely end here, but not a file,
+because we're reading past some conditional text that was not selected.
+
+\yskip\hang|defining|, means that a subfile shouldn't end now because a
+macro is being defined.
+
+\yskip\hang|matching|, means that a subfile shouldn't end now because a
+macro is being used and we are searching for the end of its arguments.
+
+\yskip\hang|aligning|, means that a subfile shouldn't end now because we are
+not finished with the preamble of an \.{\\halign} or \.{\\valign}.
+
+\yskip\hang|absorbing|, means that a subfile shouldn't end now because we are
+reading a balanced token list for \.{\\message}, \.{\\write}, etc.
+
+\yskip\noindent
+If the |scanner_status| is not |normal|, the variable |warning_index| points
+to the |eqtb| location for the relevant control sequence name to print
+in an error message.
+
+@d skipping=1 {|scanner_status| when passing conditional text}
+@d defining=2 {|scanner_status| when reading a macro definition}
+@d matching=3 {|scanner_status| when reading macro arguments}
+@d aligning=4 {|scanner_status| when reading an alignment preamble}
+@d absorbing=5 {|scanner_status| when reading a balanced text}
+
+@<Glob...@>=
+@!scanner_status : normal..absorbing; {can a subfile end now?}
+@!warning_index : pointer; {identifier relevant to non-|normal| scanner status}
+@!def_ref : pointer; {reference count of token list being defined}
+
+@ Here is a procedure that uses |scanner_status| to print a warning message
+when a subfile has ended, and at certain other crucial times:
+
+@<Declare the procedure called |runaway|@>=
+procedure runaway;
+var p:pointer; {head of runaway list}
+begin if scanner_status>skipping then
+  begin
+@.Runaway...@>
+  case scanner_status of
+  defining: begin print_nl("Runaway definition"); p:=def_ref;
+    end;
+  matching: begin print_nl("Runaway argument"); p:=temp_head;
+    end;
+  aligning: begin print_nl("Runaway preamble"); p:=hold_head;
+    end;
+  absorbing: begin print_nl("Runaway text"); p:=def_ref;
+    end;
+  end; {there are no other cases}
+  print_char("?");print_ln; show_token_list(link(p),null,error_line-10);
+  end;
+end;
+
+@ However, all this discussion about input state really applies only to the
+case that we are inputting from a file. There is another important case,
+namely when we are currently getting input from a token list. In this case
+|state=token_list|, and the conventions about the other state variables
+are different:
+
+\yskip\hang|loc| is a pointer to the current node in the token list, i.e.,
+the node that will be read next. If |loc=null|, the token list has been
+fully read.
+
+\yskip\hang|start| points to the first node of the token list; this node
+may or may not contain a reference count, depending on the type of token
+list involved.
+
+\yskip\hang|token_type|, which takes the place of |index| in the
+discussion above, is a code number that explains what kind of token list
+is being scanned.
+
+\yskip\hang|name| points to the |eqtb| address of the control sequence
+being expanded, if the current token list is a macro.
+
+\yskip\hang|param_start|, which takes the place of |limit|, tells where
+the parameters of the current macro begin in the |param_stack|, if the
+current token list is a macro.
+
+\yskip\noindent The |token_type| can take several values, depending on
+where the current token list came from:
+
+\yskip\hang|parameter|, if a parameter is being scanned;
+
+\hang|u_template|, if the \<u_j> part of an alignment
+template is being scanned;
+
+\hang|v_template|, if the \<v_j> part of an alignment
+template is being scanned;
+
+\hang|backed_up|, if the token list being scanned has been inserted as
+`to be read again'.
+
+\hang|inserted|, if the token list being scanned has been inserted as
+the text expansion of a \.{\\count} or similar variable;
+
+\hang|macro|, if a user-defined control sequence is being scanned;
+
+\hang|output_text|, if an \.{\\output} routine is being scanned;
+
+\hang|every_par_text|, if the text of \.{\\everypar} is being scanned;
+
+\hang|every_math_text|, if the text of \.{\\everymath} is being scanned;
+
+\hang|every_display_text|, if the text of \.{\\everydisplay} is being scanned;
+
+\hang|every_hbox_text|, if the text of \.{\\everyhbox} is being scanned;
+
+\hang|every_vbox_text|, if the text of \.{\\everyvbox} is being scanned;
+
+\hang|every_job_text|, if the text of \.{\\everyjob} is being scanned;
+
+\hang|every_cr_text|, if the text of \.{\\everycr} is being scanned;
+
+\hang|mark_text|, if the text of a \.{\\mark} is being scanned;
+
+\hang|write_text|, if the text of a \.{\\write} is being scanned.
+
+\yskip\noindent
+The codes for |output_text|, |every_par_text|, etc., are equal to a constant
+plus the corresponding codes for token list parameters |output_routine_loc|,
+|every_par_loc|, etc.  The token list begins with a reference count if and
+only if |token_type>=macro|.
+@^reference counts@>
+
+@d token_list=0 {|state| code when scanning a token list}
+@d token_type==index {type of current token list}
+@d param_start==limit {base of macro parameters in |param_stack|}
+@d parameter=0 {|token_type| code for parameter}
+@d u_template=1 {|token_type| code for \<u_j> template}
+@d v_template=2 {|token_type| code for \<v_j> template}
+@d backed_up=3 {|token_type| code for text to be reread}
+@d inserted=4 {|token_type| code for inserted texts}
+@d macro=5 {|token_type| code for defined control sequences}
+@d output_text=6 {|token_type| code for output routines}
+@d every_par_text=7 {|token_type| code for \.{\\everypar}}
+@d every_math_text=8 {|token_type| code for \.{\\everymath}}
+@d every_display_text=9 {|token_type| code for \.{\\everydisplay}}
+@d every_hbox_text=10 {|token_type| code for \.{\\everyhbox}}
+@d every_vbox_text=11 {|token_type| code for \.{\\everyvbox}}
+@d every_job_text=12 {|token_type| code for \.{\\everyjob}}
+@d every_cr_text=13 {|token_type| code for \.{\\everycr}}
+@d mark_text=14 {|token_type| code for \.{\\topmark}, etc.}
+@d write_text=15 {|token_type| code for \.{\\write}}
+
+@ The |param_stack| is an auxiliary array used to hold pointers to the token
+lists for parameters at the current level and subsidiary levels of input.
+This stack is maintained with convention (2), and it grows at a different
+rate from the others.
+
+@<Glob...@>=
+@!param_stack: ^pointer;
+  {token list pointers for parameters}
+@!param_ptr:0..param_size; {first unused entry in |param_stack|}
+@!max_param_stack:integer;
+  {largest value of |param_ptr|, will be |<=param_size+9|}
+
+@ The input routines must also interact with the processing of
+\.{\\halign} and \.{\\valign}, since the appearance of tab marks and
+\.{\\cr} in certain places is supposed to trigger the beginning of special
+\<v_j> template text in the scanner. This magic is accomplished by an
+|align_state| variable that is increased by~1 when a `\.{\char'173}' is
+scanned and decreased by~1 when a `\.{\char'175}' is scanned. The |align_state|
+is nonzero during the \<u_j> template, after which it is set to zero; the
+\<v_j> template begins when a tab mark or \.{\\cr} occurs at a time that
+|align_state=0|.
+
+@<Glob...@>=
+@!align_state:integer; {group level with respect to current alignment}
+
+@ Thus, the ``current input state'' can be very complicated indeed; there
+can be many levels and each level can arise in a variety of ways. The
+|show_context| procedure, which is used by \TeX's error-reporting routine to
+print out the current input state on all levels down to the most recent
+line of characters from an input file, illustrates most of these conventions.
+The global variable |base_ptr| contains the lowest level that was
+displayed by this procedure.
+
+@<Glob...@>=
+@!base_ptr:0..stack_size; {shallowest level shown by |show_context|}
+
+@ The status at each level is indicated by printing two lines, where the first
+line indicates what was read so far and the second line shows what remains
+to be read. The context is cropped, if necessary, so that the first line
+contains at most |half_error_line| characters, and the second contains
+at most |error_line|. Non-current input levels whose |token_type| is
+`|backed_up|' are shown only if they have not been fully read.
+
+@p procedure show_context; {prints where the scanner is}
+label done, done1;
+var old_setting:0..max_selector; {saved |selector| setting}
+@!s: pointer; {temporary pointer}
+@!nn:integer; {number of contexts shown so far, less one}
+@!bottom_line:boolean; {have we reached the final context to be shown?}
+@<Local variables for formatting calculations@>@/
+begin base_ptr:=input_ptr; input_stack[base_ptr]:=cur_input;
+  {store current state}
+nn:=-1; bottom_line:=false;
+loop@+begin cur_input:=input_stack[base_ptr]; {enter into the context}
+  if (state<>token_list) then
+    if (name>17) or (base_ptr=0) then bottom_line:=true;
+  if (base_ptr=input_ptr)or bottom_line or(nn<error_context_lines) then
+    @<Display the current context@>
+  else if nn=error_context_lines then
+    begin print_nl("..."); incr(nn); {omitted if |error_context_lines<0|}
+    end;
+  if bottom_line then goto done;
+  decr(base_ptr);
+  end;
+done: cur_input:=input_stack[input_ptr]; {restore original state}
+end;
+
+@ @<Display the current context@>=
+begin if (base_ptr=input_ptr) or (state<>token_list) or
+   (token_type<>backed_up) or (loc<>null) then
+    {we omit backed-up token lists that have already been read}
+  begin tally:=0; {get ready to count characters}
+  old_setting:=selector;
+  if state<>token_list then
+    begin @<Print location of current line@>;
+    @<Pseudoprint the line@>;
+    end
+  else  begin @<Print type of token list@>;
+    @<Pseudoprint the token list@>;
+    end;
+  selector:=old_setting; {stop pseudoprinting}
+  @<Print two lines using the tricky pseudoprinted information@>;
+  incr(nn);
+  end;
+end
+
+@ This routine should be changed, if necessary, to give the best possible
+indication of where the current line resides in the input file.
+For example, on some systems it is best to print both a page and line number.
+@^system dependencies@>
+
+@<Print location of current line@>=
+if name<=17 then
+  if terminal_input then
+    if base_ptr=0 then print_nl("<*>") else print_nl("<insert> ")
+  else  begin print_nl("<read ");
+    if name=17 then print_char("*")@+else print_int(name-1);
+@.*\relax@>
+    print_char(">");
+    end
+else  begin print_nl("l."); print_int(line);
+  end;
+print_char(" ")
+
+@ @<Print type of token list@>=
+case token_type of
+parameter: print_nl("<argument> ");
+u_template,v_template: print_nl("<template> ");
+backed_up: if loc=null then print_nl("<recently read> ")
+  else print_nl("<to be read again> ");
+inserted: print_nl("<inserted text> ");
+macro: begin print_ln; print_cs(name);
+  end;
+output_text: print_nl("<output> ");
+every_par_text: print_nl("<everypar> ");
+every_math_text: print_nl("<everymath> ");
+every_display_text: print_nl("<everydisplay> ");
+every_hbox_text: print_nl("<everyhbox> ");
+every_vbox_text: print_nl("<everyvbox> ");
+every_job_text: print_nl("<everyjob> ");
+every_cr_text: print_nl("<everycr> ");
+mark_text: print_nl("<mark> ");
+write_text: print_nl("<write> ");
+othercases print_nl("?") {this should never happen}
+endcases
+
+@ Here it is necessary to explain a little trick. We don't want to store a long
+string that corresponds to a token list, because that string might take up
+lots of memory; and we are printing during a time when an error message is
+being given, so we dare not do anything that might overflow one of \TeX's
+tables. So `pseudoprinting' is the answer: We enter a mode of printing
+that stores characters into a buffer of length |error_line|, where character
+$k+1$ is placed into \hbox{|trick_buf[k mod error_line]|} if
+|k<trick_count|, otherwise character |k| is dropped. Initially we set
+|tally:=0| and |trick_count:=1000000|; then when we reach the
+point where transition from line 1 to line 2 should occur, we
+set |first_count:=tally| and |trick_count:=@tmax@>(error_line,
+tally+1+error_line-half_error_line)|. At the end of the
+pseudoprinting, the values of |first_count|, |tally|, and
+|trick_count| give us all the information we need to print the two lines,
+and all of the necessary text is in |trick_buf|.
+
+Namely, let |l| be the length of the descriptive information that appears
+on the first line. The length of the context information gathered for that
+line is |k=first_count|, and the length of the context information
+gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k<=h|,
+where |h=half_error_line|, we print |trick_buf[0..k-1]| after the
+descriptive information on line~1, and set |n:=l+k|; here |n| is the
+length of line~1. If $l+k>h$, some cropping is necessary, so we set |n:=h|
+and print `\.{...}' followed by
+$$\hbox{|trick_buf[(l+k-h+3)..k-1]|,}$$
+where subscripts of |trick_buf| are circular modulo |error_line|. The
+second line consists of |n|~spaces followed by |trick_buf[k..(k+m-1)]|,
+unless |n+m>error_line|; in the latter case, further cropping is done.
+This is easier to program than to explain.
+
+@<Local variables for formatting...@>=
+@!i:0..buf_size; {index into |buffer|}
+@!j:0..buf_size; {end of current line in |buffer|}
+@!l:0..half_error_line; {length of descriptive information on line 1}
+@!m:integer; {context information gathered for line 2}
+@!n:0..error_line; {length of line 1}
+@!p: integer; {starting or ending place in |trick_buf|}
+@!q: integer; {temporary index}
+
+@ The following code sets up the print routines so that they will gather
+the desired information.
+
+@d begin_pseudoprint==
+  begin l:=tally; tally:=0; selector:=pseudo; kcode_pos:=0;
+  trick_count:=1000000;
+  end
+@d set_trick_count==
+  begin first_count:=tally;
+  if (first_count>0)and(trick_buf2[(first_count-1)mod error_line]=1) then
+      incr(first_count);
+  trick_count:=first_count+1+error_line-half_error_line;
+  if trick_count<error_line then trick_count:=error_line;
+  end
+
+@ And the following code uses the information after it has been gathered.
+
+@<Print two lines using the tricky pseudoprinted information@>=
+if trick_count=1000000 then set_trick_count;
+  {|set_trick_count| must be performed}
+if tally<trick_count then m:=tally-first_count
+else m:=trick_count-first_count; {context on line 2}
+if l+first_count<=half_error_line then
+  begin p:=0; n:=l+first_count;
+  end
+else  begin print("..."); p:=l+first_count-half_error_line+3;
+  n:=half_error_line;
+  end;
+if trick_buf2[p mod error_line]=2 then
+  begin p:=p+1; n:=n-1;
+  end;
+for q:=p to first_count-1 do print_char(trick_buf[q mod error_line]);
+print_ln;
+for q:=1 to n do print_char(" "); {print |n| spaces to begin line~2}
+if m+n<=error_line then p:=first_count+m else p:=first_count+(error_line-n-3);
+if trick_buf2[(p-1) mod error_line]=1 then p:=p-1;
+for q:=first_count to p-1 do print_char(trick_buf[q mod error_line]);
+if m+n>error_line then print("...")
+
+@ But the trick is distracting us from our current goal, which is to
+understand the input state. So let's concentrate on the data structures that
+are being pseudoprinted as we finish up the |show_context| procedure.
+
+@<Pseudoprint the line@>=
+begin_pseudoprint;
+if buffer[limit]=end_line_char then j:=limit
+else j:=limit+1; {determine the effective end of the line}
+if j>0 then for i:=start to j-1 do
+  begin if i=loc then set_trick_count;
+  print(buffer[i]);
+  end
+
+@ @<Pseudoprint the token list@>=
+begin_pseudoprint;
+if token_type<macro then
+  begin  if (token_type=backed_up)and(loc<>null) then
+    begin  if (link(start)=null)and(check_kanji(info(start))) then {|wchar_token|}
+      begin cur_input:=input_stack[base_ptr-1];
+      s:=get_avail; info(s):=Lo(info(loc));
+      cur_input:=input_stack[base_ptr];
+      link(start):=s;
+      show_token_list(start,loc,100000);
+      free_avail(s);link(start):=null;
+      goto done1;
+      end;
+    end;
+  show_token_list(start,loc,100000);
+  end
+else show_token_list(link(start),loc,100000); {avoid reference count}
+done1:
+
+@ Here is the missing piece of |show_token_list| that is activated when the
+token beginning line~2 is about to be shown:
+
+@<Do magic computation@>=set_trick_count
+
+@* \[23] Maintaining the input stacks.
+The following subroutines change the input status in commonly needed ways.
+
+First comes |push_input|, which stores the current state and creates a
+new level (having, initially, the same properties as the old).
+
+@d push_input==@t@> {enter a new input level, save the old}
+  begin if input_ptr>max_in_stack then
+    begin max_in_stack:=input_ptr;
+    if input_ptr=stack_size then overflow("input stack size",stack_size);
+@:TeX capacity exceeded input stack size}{\quad input stack size@>
+    end;
+  input_stack[input_ptr]:=cur_input; {stack the record}
+  incr(input_ptr);
+  end
+
+@ And of course what goes up must come down.
+
+@d pop_input==@t@> {leave an input level, re-enter the old}
+  begin decr(input_ptr); cur_input:=input_stack[input_ptr];
+  end
+
+@ Here is a procedure that starts a new level of token-list input, given
+a token list |p| and its type |t|. If |t=macro|, the calling routine should
+set |name| and |loc|.
+
+@d back_list(#)==begin_token_list(#,backed_up) {backs up a simple token list}
+@d ins_list(#)==begin_token_list(#,inserted) {inserts a simple token list}
+
+@p procedure begin_token_list(@!p:pointer;@!t:quarterword);
+begin push_input; state:=token_list; start:=p; token_type:=t;
+if t>=macro then {the token list starts with a reference count}
+  begin add_token_ref(p);
+  if t=macro then param_start:=param_ptr
+  else  begin loc:=link(p);
+    if tracing_macros>1 then
+      begin begin_diagnostic; print_nl("");
+      case t of
+      mark_text:print_esc("mark");
+      write_text:print_esc("write");
+      othercases print_cmd_chr(assign_toks,t-output_text+output_routine_loc)
+      endcases;@/
+      print("->"); token_show(p); end_diagnostic(false);
+      end;
+    end;
+  end
+else loc:=p;
+end;
+
+@ When a token list has been fully scanned, the following computations
+should be done as we leave that level of input. The |token_type| tends
+to be equal to either |backed_up| or |inserted| about 2/3 of the time.
+@^inner loop@>
+
+@p procedure end_token_list; {leave a token-list input level}
+begin if token_type>=backed_up then {token list to be deleted}
+  begin if token_type<=inserted then flush_list(start)
+  else  begin delete_token_ref(start); {update reference count}
+    if token_type=macro then {parameters must be flushed}
+      while param_ptr>param_start do
+        begin decr(param_ptr);
+        flush_list(param_stack[param_ptr]);
+        end;
+    end;
+  end
+else if token_type=u_template then
+  if align_state>500000 then align_state:=0
+  else fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+pop_input;
+check_interrupt;
+end;
+
+@ Sometimes \TeX\ has read too far and wants to ``unscan'' what it has
+seen. The |back_input| procedure takes care of this by putting the token
+just scanned back into the input stream, ready to be read again. This
+procedure can be used only if |cur_tok| represents the token to be
+replaced. Some applications of \TeX\ use this procedure a lot,
+so it has been slightly optimized for speed.
+@^inner loop@>
+
+@p procedure back_input; {undoes one token of input}
+var p:pointer; {a token list of length one}
+begin while (state=token_list)and(loc=null)and(token_type<>v_template) do
+  end_token_list; {conserve stack space}
+p:=get_avail; info(p):=cur_tok;
+if cur_tok<right_brace_limit then
+  if cur_tok<left_brace_limit then decr(align_state)
+  else incr(align_state);
+push_input; state:=token_list; start:=p; token_type:=backed_up;
+loc:=p; {that was |back_list(p)|, without procedure overhead}
+end;
+
+@ @<Insert token |p| into \TeX's input@>=
+begin t:=cur_tok; cur_tok:=p; back_input; cur_tok:=t;
+end
+
+@ The |back_error| routine is used when we want to replace an offending token
+just before issuing an error message. This routine, like |back_input|,
+requires that |cur_tok| has been set. We disable interrupts during the
+call of |back_input| so that the help message won't be lost.
+
+@p procedure back_error; {back up one token and call |error|}
+begin OK_to_interrupt:=false; back_input; OK_to_interrupt:=true; error;
+end;
+@#
+procedure ins_error; {back up one inserted token and call |error|}
+begin OK_to_interrupt:=false; back_input; token_type:=inserted;
+OK_to_interrupt:=true; error;
+end;
+
+@ The |begin_file_reading| procedure starts a new level of input for lines
+of characters to be read from a file, or as an insertion from the
+terminal. It does not take care of opening the file, nor does it set |loc|
+or |limit| or |line|.
+@^system dependencies@>
+
+@p procedure begin_file_reading;
+begin if in_open=max_in_open then overflow("text input levels",max_in_open);
+@:TeX capacity exceeded text input levels}{\quad text input levels@>
+if first=buf_size then overflow("buffer size",buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+incr(in_open); push_input; index:=in_open;
+source_filename_stack[index]:=0;full_source_filename_stack[index]:=0;
+line_stack[index]:=line; start:=first; state:=mid_line;
+name:=0; {|terminal_input| is now |true|}
+end;
+
+@ Conversely, the variables must be downdated when such a level of input
+is finished:
+
+@p procedure end_file_reading;
+begin first:=start; line:=line_stack[index];
+if name>17 then a_close(cur_file); {forget it}
+pop_input; decr(in_open);
+end;
+
+@ In order to keep the stack from overflowing during a long sequence of
+inserted `\.{\\show}' commands, the following routine removes completed
+error-inserted lines from memory.
+
+@p procedure clear_for_error_prompt;
+begin while (state<>token_list)and terminal_input and@|
+  (input_ptr>0)and(loc>limit) do end_file_reading;
+print_ln; clear_terminal;
+end;
+
+@ To get \TeX's whole input mechanism going, we perform the following
+actions.
+
+@<Initialize the input routines@>=
+begin input_ptr:=0; max_in_stack:=0;
+source_filename_stack[0]:=0;full_source_filename_stack[0]:=0;
+in_open:=0; open_parens:=0; max_buf_stack:=0;
+param_ptr:=0; max_param_stack:=0;
+first:=buf_size; repeat buffer[first]:=0; decr(first); until first=0;
+scanner_status:=normal; warning_index:=null; first:=1;
+state:=new_line; start:=1; index:=0; line:=0; name:=0;
+force_eof:=false;
+align_state:=1000000;@/
+if not init_terminal then goto final_end;
+limit:=last; first:=last+1; {|init_terminal| has set |loc| and |last|}
+end
+
+@* \[24] Getting the next token.
+The heart of \TeX's input mechanism is the |get_next| procedure, which
+we shall develop in the next few sections of the program. Perhaps we
+shouldn't actually call it the ``heart,'' however, because it really acts
+as \TeX's eyes and mouth, reading the source files and gobbling them up.
+And it also helps \TeX\ to regurgitate stored token lists that are to be
+processed again.
+@^eyes and mouth@>
+
+The main duty of |get_next| is to input one token and to set |cur_cmd|
+and |cur_chr| to that token's command code and modifier. Furthermore, if
+the input token is a control sequence, the |eqtb| location of that control
+sequence is stored in |cur_cs|; otherwise |cur_cs| is set to zero.
+
+Underlying this simple description is a certain amount of complexity
+because of all the cases that need to be handled.
+However, the inner loop of |get_next| is reasonably short and fast.
+
+When |get_next| is asked to get the next token of a \.{\\read} line,
+it sets |cur_cmd=cur_chr=cur_cs=0| in the case that no more tokens
+appear on that line. (There might not be any tokens at all, if the
+|end_line_char| has |ignore| as its catcode.)
+
+@ The value of |par_loc| is the |eqtb| address of `\.{\\par}'. This quantity
+is needed because a blank line of input is supposed to be exactly equivalent
+to the appearance of \.{\\par}; we must set |cur_cs:=par_loc|
+when detecting a blank line.
+
+@<Glob...@>=
+@!par_loc:pointer; {location of `\.{\\par}' in |eqtb|}
+@!par_token:halfword; {token representing `\.{\\par}'}
+
+@ @<Put each...@>=
+primitive("par",par_end,256); {cf.\ |scan_file_name|}
+@!@:par_}{\.{\\par} primitive@>
+par_loc:=cur_val; par_token:=cs_token_flag+par_loc;
+
+@ @<Cases of |print_cmd_chr|...@>=
+par_end:print_esc("par");
+
+@ Before getting into |get_next|, let's consider the subroutine that
+is called when an `\.{\\outer}' control sequence has been scanned or
+when the end of a file has been reached. These two cases are distinguished
+by |cur_cs|, which is zero at the end of a file.
+
+@p procedure check_outer_validity;
+var p:pointer; {points to inserted token list}
+@!q:pointer; {auxiliary pointer}
+begin if scanner_status<>normal then
+  begin deletions_allowed:=false;
+  @<Back up an outer control sequence so that it can be reread@>;
+  if scanner_status>skipping then
+    @<Tell the user what has run away and try to recover@>
+  else  begin print_err("Incomplete "); print_cmd_chr(if_test,cur_if);
+@.Incomplete \\if...@>
+    print("; all text was ignored after line "); print_int(skip_line);
+    help3("A forbidden control sequence occurred in skipped text.")@/
+    ("This kind of error happens when you say `\if...' and forget")@/
+    ("the matching `\fi'. I've inserted a `\fi'; this might work.");
+    if cur_cs<>0 then cur_cs:=0
+    else help_line[2]:=@|
+      "The file ended while I was skipping conditional text.";
+    cur_tok:=cs_token_flag+frozen_fi; ins_error;
+    end;
+  deletions_allowed:=true;
+  end;
+end;
+
+@ An outer control sequence that occurs in a \.{\\read} will not be reread,
+since the error recovery for \.{\\read} is not very powerful.
+
+@<Back up an outer control sequence so that it can be reread@>=
+if cur_cs<>0 then
+  begin if (state=token_list)or(name<1)or(name>17) then
+    begin p:=get_avail; info(p):=cs_token_flag+cur_cs;
+    back_list(p); {prepare to read the control sequence again}
+    end;
+  cur_cmd:=spacer; cur_chr:=" "; {replace it by a space}
+  end
+
+@ @<Tell the user what has run away...@>=
+begin runaway; {print a definition, argument, or preamble}
+if cur_cs=0 then print_err("File ended")
+@.File ended while scanning...@>
+else  begin cur_cs:=0; print_err("Forbidden control sequence found");
+@.Forbidden control sequence...@>
+  end;
+@<Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `\.{text}',
+  and insert tokens that should lead to recovery@>;
+print(" of "); sprint_cs(warning_index);
+help4("I suspect you have forgotten a `}', causing me")@/
+("to read past where you wanted me to stop.")@/
+("I'll try to recover; but if the error is serious,")@/
+("you'd better type `E' or `X' now and fix your file.");@/
+error;
+end
+
+@ The recovery procedure can't be fully understood without knowing more
+about the \TeX\ routines that should be aborted, but we can sketch the
+ideas here:  For a runaway definition we will insert a right brace; for a
+runaway preamble, we will insert a special \.{\\cr} token and a right
+brace; and for a runaway argument, we will set |long_state| to
+|outer_call| and insert \.{\\par}.
+
+@<Print either `\.{definition}' or ...@>=
+p:=get_avail;
+case scanner_status of
+defining:begin print(" while scanning definition"); info(p):=right_brace_token+"}";
+  end;
+matching:begin print(" while scanning use"); info(p):=par_token; long_state:=outer_call;
+  end;
+aligning:begin print(" while scanning preamble"); info(p):=right_brace_token+"}"; q:=p;
+  p:=get_avail; link(p):=q; info(p):=cs_token_flag+frozen_cr;
+  align_state:=-1000000;
+  end;
+absorbing:begin print(" while scanning text"); info(p):=right_brace_token+"}";
+  end;
+end; {there are no other cases}
+ins_list(p)
+
+@ We need to mention a procedure here that may be called by |get_next|.
+
+@p procedure@?firm_up_the_line; forward;
+
+@ Now we're ready to take the plunge into |get_next| itself. Parts of
+this routine are executed more often than any other instructions of \TeX.
+@^mastication@>@^inner loop@>
+
+@d switch=25 {a label in |get_next|}
+@d start_cs=26 {another}
+
+@p procedure get_next; {sets |cur_cmd|, |cur_chr|, |cur_cs| to next token}
+label restart, {go here to get the next input token}
+  switch, {go here to eat the next character from a file}
+  reswitch, {go here to digest it again}
+  start_cs, {go here to start looking for a control sequence}
+  found, {go here when a control sequence has been found}
+  exit; {go here when the next input token has been got}
+var k:0..buf_size; {an index into |buffer|}
+@!t:halfword; {a token}
+@!cat:escape..max_char_code; {|cat_code(cur_chr)|, usually}
+@!l:0..buf_size; {temporary index into |buffer|}
+@!c,@!cc:ASCII_code; {constituents of a possible expanded code}
+@!d:2..3; {number of excess characters in an expanded code}
+begin restart: cur_cs:=0;
+if state<>token_list then
+@<Input from external file, |goto restart| if no input found@>
+else @<Input from token list, |goto restart| if end of list or
+  if a parameter needs to be expanded@>;
+@<If an alignment entry has just ended, take appropriate action@>;
+exit:end;
+
+@ An alignment entry ends when a tab or \.{\\cr} occurs, provided that the
+current level of braces is the same as the level that was present at the
+beginning of that alignment entry; i.e., provided that |align_state| has
+returned to the value it had after the \<u_j> template for that entry.
+@^inner loop@>
+
+@<If an alignment entry has just ended, take appropriate action@>=
+if cur_cmd<=car_ret then if cur_cmd>=tab_mark then if align_state=0 then
+  @<Insert the \(v)\<v_j> template and |goto restart|@>
+
+@ @<Input from external file, |goto restart| if no input found@>=
+@^inner loop@>
+begin switch: if loc<=limit then {current line not yet finished}
+  begin cur_chr:=buffer[loc]; incr(loc);
+    if multistrlen(ustringcast(buffer), limit+1, loc-1)=2 then
+      begin cur_chr:=fromBUFF(ustringcast(buffer), limit+1, loc-1);
+      cur_cmd:=kcat_code(kcatcodekey(cur_chr));
+      incr(loc);
+      end
+    else reswitch: cur_cmd:=cat_code(cur_chr);
+  @<Change state if necessary, and |goto switch| if the
+    current character should be ignored,
+    or |goto reswitch| if the current character
+    changes to another@>;
+  end
+else  begin state:=new_line;@/
+  @<Move to next line of file,
+    or |goto restart| if there is no next line,
+    or |return| if a \.{\\read} line has finished@>;
+  check_interrupt;
+  goto switch;
+  end;
+end
+
+@ The following 48-way switch accomplishes the scanning quickly, assuming
+that a decent \PASCAL\ compiler has translated the code. Note that the numeric
+values for |mid_line|, |skip_blanks|, and |new_line| are spaced
+apart from each other by |max_char_code+1|, so we can add a character's
+command code to the state to get a single number that characterizes both.
+
+@d any_state_plus(#) == mid_line+#,mid_kanji+#,skip_blanks+#,new_line+#
+
+@<Change state if necessary...@>=
+case state+cur_cmd of
+@<Cases where character is ignored@>: goto switch;
+any_state_plus(escape): @<Scan a control sequence
+  and set |state:=skip_blanks| or |mid_line|@>;
+any_state_plus(active_char): @<Process an active-character control sequence
+  and set |state:=mid_line|@>;
+any_state_plus(sup_mark): @<If this |sup_mark| starts an expanded character
+  like~\.{\^\^A} or~\.{\^\^df}, then |goto reswitch|,
+  otherwise set |state:=mid_line|@>;
+any_state_plus(invalid_char): @<Decry the invalid character and
+  |goto restart|@>;
+@t\4@>@<Handle situations involving spaces, braces, changes of state@>@;
+othercases do_nothing
+endcases
+
+@ @<Cases where character is ignored@>=
+any_state_plus(ignore),skip_blanks+spacer,new_line+spacer
+
+@ We go to |restart| instead of to |switch|, because |state| might equal
+|token_list| after the error has been dealt with
+(cf.\ |clear_for_error_prompt|).
+
+@<Decry the invalid...@>=
+begin print_err("Text line contains an invalid character");
+@.Text line contains...@>
+help2("A funny symbol that I can't read has just been input.")@/
+("Continue, and I'll forget that it ever happened.");@/
+deletions_allowed:=false; error; deletions_allowed:=true;
+goto restart;
+end
+
+@ @d add_delims_to(#)==#+math_shift,#+tab_mark,#+mac_param,
+  #+sub_mark,#+letter,#+other_char
+@d all_jcode(#)==#+kanji,#+kana,#+other_kchar
+
+@<Handle situations involving spaces, braces, changes of state@>=
+mid_kanji+spacer,mid_line+spacer:@<Enter |skip_blanks| state, emit a space@>;
+mid_line+car_ret:@<Finish line, emit a space@>;
+mid_kanji+car_ret: if skip_mode then @<Finish line, |goto switch|@>
+  else @<Finish line, emit a space@>;
+skip_blanks+car_ret,any_state_plus(comment):
+  @<Finish line, |goto switch|@>;
+new_line+car_ret:@<Finish line, emit a \.{\\par}@>;
+mid_line+left_brace,mid_kanji+left_brace: incr(align_state);
+skip_blanks+left_brace,new_line+left_brace: begin
+  state:=mid_line; incr(align_state);
+  end;
+mid_line+right_brace,mid_kanji+right_brace: decr(align_state);
+skip_blanks+right_brace,new_line+right_brace: begin
+  state:=mid_line; decr(align_state);
+  end;
+add_delims_to(skip_blanks),add_delims_to(new_line),add_delims_to(mid_kanji):
+  state:=mid_line;
+all_jcode(skip_blanks),all_jcode(new_line),all_jcode(mid_line):
+  state:=mid_kanji;
+
+@ @<Global...@>=
+skip_mode:boolean;
+
+@ @<Set init...@>=
+skip_mode:=true;
+
+@ When a character of type |spacer| gets through, its character code is
+changed to $\.{"\ "}=@'40$. This means that the ASCII codes for tab and space,
+and for the space inserted at the end of a line, will
+be treated alike when macro parameters are being matched. We do this
+since such characters are indistinguishable on most computer terminal displays.
+
+@<Finish line, emit a space@>=
+begin loc:=limit+1; cur_cmd:=spacer; cur_chr:=" ";
+end
+
+@ The following code is performed only when |cur_cmd=spacer|.
+
+@<Enter |skip_blanks| state, emit a space@>=
+begin state:=skip_blanks; cur_chr:=" ";
+end
+
+@ @<Finish line, |goto switch|@>=
+begin loc:=limit+1; goto switch;
+end
+
+@ @<Finish line, emit a \.{\\par}@>=
+begin loc:=limit+1; cur_cs:=par_loc; cur_cmd:=eq_type(cur_cs);
+cur_chr:=equiv(cur_cs);
+if cur_cmd>=outer_call then check_outer_validity;
+end
+
+@ Notice that a code like \.{\^\^8} becomes \.x if not followed by a hex digit.
+
+@d is_hex(#)==(((#>="0")and(#<="9"))or((#>="a")and(#<="f")))
+@d hex_to_cur_chr==
+  if c<="9" then cur_chr:=c-"0" @+else cur_chr:=c-"a"+10;
+  if cc<="9" then cur_chr:=16*cur_chr+cc-"0"
+  else cur_chr:=16*cur_chr+cc-"a"+10
+
+@<If this |sup_mark| starts an expanded character...@>=
+begin if cur_chr=buffer[loc] then if loc<limit then
+  begin c:=buffer[loc+1]; @+if c<@'200 then {yes we have an expanded char}
+    begin loc:=loc+2;
+    if is_hex(c) then if loc<=limit then
+      begin cc:=buffer[loc]; @+if is_hex(cc) then
+        begin incr(loc); hex_to_cur_chr; goto reswitch;
+        end;
+      end;
+    if c<@'100 then cur_chr:=c+@'100 @+else cur_chr:=c-@'100;
+    goto reswitch;
+    end;
+  end;
+state:=mid_line;
+end
+
+@ @<Process an active-character...@>=
+begin cur_cs:=cur_chr+active_base;
+cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs); state:=mid_line;
+if cur_cmd>=outer_call then check_outer_validity;
+end
+
+@ Control sequence names are scanned only when they appear in some line of
+a file; once they have been scanned the first time, their |eqtb| location
+serves as a unique identification, so \TeX\ doesn't need to refer to the
+original name any more except when it prints the equivalent in symbolic form.
+
+The program that scans a control sequence has been written carefully
+in order to avoid the blowups that might otherwise occur if a malicious
+user tried something like `\.{\\catcode\'15=0}'. The algorithm might
+look at |buffer[limit+1]|, but it never looks at |buffer[limit+2]|.
+
+If expanded characters like `\.{\^\^A}' or `\.{\^\^df}'
+appear in or just following
+a control sequence name, they are converted to single characters in the
+buffer and the process is repeated, slowly but surely.
+
+@<Scan a control...@>=
+begin if loc>limit then cur_cs:=null_cs {|state| is irrelevant in this case}
+else  begin k:=loc; cur_chr:=buffer[k]; incr(k);
+  if multistrlen(ustringcast(buffer), limit+1, k-1)=2 then
+    begin cat:=kcat_code(kcatcodekey(fromBUFF(ustringcast(buffer), limit+1, k-1))); incr(k);
+    end
+  else cat:=cat_code(cur_chr);
+start_cs:
+  if (cat=letter)or(cat=kanji)or(cat=kana) then state:=skip_blanks
+  else if cat=spacer then state:=skip_blanks
+  else state:=mid_line;
+  if cat=other_kchar then
+    begin cur_cs:=id_lookup(loc,k-loc); loc:=k; goto found;
+    end
+  else if ((cat=letter)or(cat=kanji)or(cat=kana))and(k<=limit) then
+    @<Scan ahead in the buffer until finding a nonletter;
+    if an expanded code is encountered, reduce it
+    and |goto start_cs|; otherwise if a multiletter control
+    sequence is found, adjust |cur_cs| and |loc|, and
+    |goto found|@>
+  else @<If an expanded code is present, reduce it and |goto start_cs|@>;
+  cur_cs:=single_base+buffer[loc]; incr(loc);
+  end;
+found: cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs);
+if cur_cmd>=outer_call then check_outer_validity;
+end
+
+@ Whenever we reach the following piece of code, we will have
+|cur_chr=buffer[k-1]| and |k<=limit+1| and |cat=cat_code(cur_chr)|. If an
+expanded code like \.{\^\^A} or \.{\^\^df} appears in |buffer[(k-1)..(k+1)]|
+or |buffer[(k-1)..(k+2)]|, we
+will store the corresponding code in |buffer[k-1]| and shift the rest of
+the buffer left two or three places.
+
+@<If an expanded...@>=
+begin if buffer[k]=cur_chr then @+if cat=sup_mark then @+if k<limit then
+  begin c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present}
+    begin d:=2;
+    if is_hex(c) then @+if k+2<=limit then
+      begin cc:=buffer[k+2]; @+if is_hex(cc) then incr(d);
+      end;
+    if d>2 then
+      begin hex_to_cur_chr; buffer[k-1]:=cur_chr;
+      end
+    else if c<@'100 then buffer[k-1]:=c+@'100
+    else buffer[k-1]:=c-@'100;
+    limit:=limit-d; first:=first-d;
+    l:=k; cur_chr:=buffer[k-1]; cat:=cat_code(cur_chr);
+    while l<=limit do
+      begin buffer[l]:=buffer[l+d]; incr(l);
+      end;
+    goto start_cs;
+    end;
+  end;
+end
+
+@ @<Scan ahead in the buffer...@>=
+begin repeat cur_chr:=buffer[k]; incr(k);
+  if multistrlen(ustringcast(buffer), limit+1, k-1)=2 then
+    begin cat:=kcat_code(kcatcodekey(fromBUFF(ustringcast(buffer), limit+1, k-1))); incr(k);
+    end
+  else cat:=cat_code(cur_chr);
+  while (buffer[k]=cur_chr)and(cat=sup_mark)and(k<limit) do
+    begin c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present}
+      begin d:=2;
+      if is_hex(c) then @+if k+2<=limit then
+        begin cc:=buffer[k+2]; @+if is_hex(cc) then incr(d);
+        end;
+      if d>2 then
+        begin hex_to_cur_chr;
+        end
+      else if c<@'100 then cur_chr:=c+@'100
+      else cur_chr:=c-@'100;
+      cat:=cat_code(cur_chr);
+      if (cat=letter)or(cat=sup_mark) then
+        begin buffer[k-1]:=cur_chr;
+        limit:=limit-d; first:=first-d;
+        l:=k;
+        while l<=limit do
+          begin buffer[l]:=buffer[l+d]; incr(l);
+          end;
+        end;
+      end;
+    end;
+until not((cat=letter)or(cat=kanji)or(cat=kana))or(k>limit);
+{@@<If an expanded...@@>;}
+if not((cat=letter)or(cat=kanji)or(cat=kana)) then decr(k);
+if cat=other_kchar then decr(k); {now |k| points to first nonletter}
+if k>loc+1 then {multiletter control sequence has been scanned}
+  begin cur_cs:=id_lookup(loc,k-loc); loc:=k; goto found;
+  end;
+end
+
+@ Let's consider now what happens when |get_next| is looking at a token list.
+
+@<Input from token list, |goto restart| if end of list or
+  if a parameter needs to be expanded@>=
+if loc<>null then {list not exhausted}
+@^inner loop@>
+  begin t:=info(loc); loc:=link(loc); {move to next}
+  if t>=cs_token_flag then {a control sequence token}
+    begin cur_cs:=t-cs_token_flag;
+    cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs);
+    if cur_cmd>=outer_call then
+      if cur_cmd=dont_expand then
+        @<Get the next token, suppressing expansion@>
+      else check_outer_validity;
+    end
+  else if check_kanji(t) then {|wchar_token|}
+    begin cur_chr:=t; cur_cmd:=kcat_code(kcatcodekey(t));
+    end
+  else
+    begin cur_cmd:=Hi(t); cur_chr:=Lo(t);
+    case cur_cmd of
+    left_brace: incr(align_state);
+    right_brace: decr(align_state);
+    out_param: @<Insert macro parameter and |goto restart|@>;
+    othercases do_nothing
+    endcases;
+    end;
+  end
+else  begin {we are done with this token list}
+  end_token_list; goto restart; {resume previous level}
+  end
+
+@ The present point in the program is reached only when the |expand|
+routine has inserted a special marker into the input. In this special
+case, |info(loc)| is known to be a control sequence token, and |link(loc)=null|.
+
+@d no_expand_flag=257 {this characterizes a special variant of |relax|}
+
+@<Get the next token, suppressing expansion@>=
+begin cur_cs:=info(loc)-cs_token_flag; loc:=null;@/
+cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs);
+if cur_cmd>max_command then
+  begin cur_cmd:=relax; cur_chr:=no_expand_flag;
+  end;
+end
+
+@ @<Insert macro parameter...@>=
+begin begin_token_list(param_stack[param_start+cur_chr-1],parameter);
+goto restart;
+end
+
+@ All of the easy branches of |get_next| have now been taken care of.
+There is one more branch.
+
+@d end_line_char_inactive == (end_line_char<0)or(end_line_char>255)
+
+@<Move to next line of file, or |goto restart|...@>=
+if name>17 then @<Read next line of file into |buffer|, or
+  |goto restart| if the file has ended@>
+else  begin if not terminal_input then {\.{\\read} line has ended}
+    begin cur_cmd:=0; cur_chr:=0; return;
+    end;
+  if input_ptr>0 then {text was inserted during error recovery}
+    begin end_file_reading; goto restart; {resume previous level}
+    end;
+  if selector<log_only then open_log_file;
+  if interaction>nonstop_mode then
+    begin if end_line_char_inactive then incr(limit);
+    if limit=start then {previous line was empty}
+      print_nl("(Please type a command or say `\end')");
+@.Please type...@>
+    print_ln; first:=start;
+    prompt_input("*"); {input on-line into |buffer|}
+@.*\relax@>
+    limit:=last;
+    if end_line_char_inactive then decr(limit)
+    else  buffer[limit]:=end_line_char;
+    first:=limit+1;
+    loc:=start;
+    end
+  else fatal_error("*** (job aborted, no legal \end found)");
+@.job aborted@>
+    {nonstop mode, which is intended for overnight batch processing,
+    never waits for on-line input}
+  end
+
+@ The global variable |force_eof| is normally |false|; it is set |true|
+by an \.{\\endinput} command.
+
+@<Glob...@>=
+@!force_eof:boolean; {should the next \.{\\input} be aborted early?}
+
+@ @<Read next line of file into |buffer|, or
+  |goto restart| if the file has ended@>=
+begin incr(line); first:=start;
+if not force_eof then
+  begin if input_ln(cur_file,true) then {not end of file}
+    firm_up_the_line {this sets |limit|}
+  else force_eof:=true;
+  end;
+if force_eof then
+  begin print_char(")"); decr(open_parens);
+  update_terminal; {show user that file has been read}
+  force_eof:=false;
+  end_file_reading; {resume previous level}
+  check_outer_validity; goto restart;
+  end;
+if end_line_char_inactive then decr(limit)
+else  buffer[limit]:=end_line_char;
+first:=limit+1; loc:=start; {ready to read}
+end
+
+@ If the user has set the |pausing| parameter to some positive value,
+and if nonstop mode has not been selected, each line of input is displayed
+on the terminal and the transcript file, followed by `\.{=>}'.
+\TeX\ waits for a response. If the response is simply |carriage_return|, the
+line is accepted as it stands, otherwise the line typed is
+used instead of the line in the file.
+
+@p procedure firm_up_the_line;
+var k:0..buf_size; {an index into |buffer|}
+begin limit:=last;
+if pausing>0 then if interaction>nonstop_mode then
+  begin wake_up_terminal; print_ln;
+  if start<limit then for k:=start to limit-1 do print(buffer[k]);
+  first:=limit; prompt_input("=>"); {wait for user response}
+@.=>@>
+  if last>first then
+    begin for k:=first to last-1 do {move line down in buffer}
+      buffer[k+start-first]:=buffer[k];
+    limit:=start+last-first;
+    end;
+  end;
+end;
+
+@ Since |get_next| is used so frequently in \TeX, it is convenient
+to define three related procedures that do a little more:
+
+\yskip\hang|get_token| not only sets |cur_cmd| and |cur_chr|, it
+also sets |cur_tok|, a packed halfword version of the current token.
+
+\yskip\hang|get_x_token|, meaning ``get an expanded token,'' is like
+|get_token|, but if the current token turns out to be a user-defined
+control sequence (i.e., a macro call), or a conditional,
+or something like \.{\\topmark} or \.{\\expandafter} or \.{\\csname},
+it is eliminated from the input by beginning the expansion of the macro
+or the evaluation of the conditional.
+
+\yskip\hang|x_token| is like |get_x_token| except that it assumes that
+|get_next| has already been called.
+
+\yskip\noindent
+In fact, these three procedures account for almost every use of |get_next|.
+
+@ No new control sequences will be defined except during a call of
+|get_token|, or when \.{\\csname} compresses a token list, because
+|no_new_control_sequence| is always |true| at other times.
+
+@p procedure get_token; {sets |cur_cmd|, |cur_chr|, |cur_tok|}
+begin no_new_control_sequence:=false; get_next; no_new_control_sequence:=true;
+@^inner loop@>
+if cur_cs=0 then
+  if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then {|wchar_token|}
+    cur_tok:=cur_chr
+  else cur_tok:=(cur_cmd*@'400)+cur_chr
+else cur_tok:=cs_token_flag+cur_cs;
+end;
+
+@* \[25] Expanding the next token.
+Only a dozen or so command codes |>max_command| can possibly be returned by
+|get_next|; in increasing order, they are |undefined_cs|, |expand_after|,
+|no_expand|, |input|, |if_test|, |fi_or_else|, |cs_name|, |convert|, |the|,
+|top_bot_mark|, |call|, |long_call|, |outer_call|, |long_outer_call|, and
+|end_template|.{\emergencystretch=40pt\par}
+
+@ Sometimes, recursive calls to the following |expand| routine may
+cause exhaustion of the run-time calling stack, resulting in
+forced execution stops by the operating system. To diminish the chance
+of this happening, a counter is used to keep track of the recursion
+depth, in conjunction with a constant called |expand_depth|.
+
+This does not catch all possible infinite recursion loops, just the ones
+that exhaust the application calling stack. The actual maximum value of
+|expand_depth| is outside of our control, but the initial setting of
+|10000| should be enough to prevent problems.
+@^system dependencies@>
+
+@<Global...@>=
+expand_depth_count:integer;
+
+@ @<Set init...@>=
+expand_depth_count:=0;
+
+@ The |expand| subroutine is used when |cur_cmd>max_command|. It removes a
+``call'' or a conditional or one of the other special operations just
+listed.  It follows that |expand| might invoke itself recursively. In all
+cases, |expand| destroys the current token, but it sets things up so that
+the next |get_next| will deliver the appropriate next token. The value of
+|cur_tok| need not be known when |expand| is called.
+
+Since several of the basic scanning routines communicate via global variables,
+their values are saved as local variables of |expand| so that
+recursive calls don't invalidate them.
+@^recursion@>
+
+@p@t\4@>@<Declare the procedure called |macro_call|@>@;@/
+@t\4@>@<Declare the procedure called |insert_relax|@>@;@/
+procedure@?pass_text; forward;@t\2@>
+procedure@?start_input; forward;@t\2@>
+procedure@?conditional; forward;@t\2@>
+procedure@?get_x_token; forward;@t\2@>
+procedure@?conv_toks; forward;@t\2@>
+procedure@?ins_the_toks; forward;@t\2@>
+procedure expand;
+var t:halfword; {token that is being ``expanded after''}
+@!p,@!q,@!r:pointer; {for list manipulation}
+@!j:0..buf_size; {index into |buffer|}
+@!cv_backup:integer; {to save the global quantity |cur_val|}
+@!cvl_backup,@!radix_backup,@!co_backup:small_number;
+  {to save |cur_val_level|, etc.}
+@!backup_backup:pointer; {to save |link(backup_head)|}
+@!save_scanner_status:small_number; {temporary storage of |scanner_status|}
+begin
+incr(expand_depth_count);
+if expand_depth_count>=expand_depth then overflow("expansion depth",expand_depth);
+cv_backup:=cur_val; cvl_backup:=cur_val_level; radix_backup:=radix;
+co_backup:=cur_order; backup_backup:=link(backup_head);
+if cur_cmd<call then @<Expand a nonmacro@>
+else if cur_cmd<end_template then macro_call
+else @<Insert a token containing |frozen_endv|@>;
+cur_val:=cv_backup; cur_val_level:=cvl_backup; radix:=radix_backup;
+cur_order:=co_backup; link(backup_head):=backup_backup;
+decr(expand_depth_count);
+end;
+
+@ @<Expand a nonmacro@>=
+begin if tracing_commands>1 then show_cur_cmd_chr;
+case cur_cmd of
+top_bot_mark:@<Insert the \(a)appropriate mark text into the scanner@>;
+expand_after:@<Expand the token after the next token@>;
+no_expand:@<Suppress expansion of the next token@>;
+cs_name:@<Manufacture a control sequence name@>;
+convert:conv_toks; {this procedure is discussed in Part 27 below}
+the:ins_the_toks; {this procedure is discussed in Part 27 below}
+if_test:conditional; {this procedure is discussed in Part 28 below}
+fi_or_else:@<Terminate the current conditional and skip to \.{\\fi}@>;
+input:@<Initiate or terminate input from a file@>;
+othercases @<Complain about an undefined macro@>
+endcases;
+end
+
+@ It takes only a little shuffling to do what \TeX\ calls \.{\\expandafter}.
+
+@<Expand the token after...@>=
+begin get_token; t:=cur_tok; get_token;
+if cur_cmd>max_command then expand@+else back_input;
+cur_tok:=t; back_input;
+end
+
+@ The implementation of \.{\\noexpand} is a bit trickier, because it is
+necessary to insert a special `|dont_expand|' marker into \TeX's reading
+mechanism.  This special marker is processed by |get_next|, but it does
+not slow down the inner loop.
+
+Since \.{\\outer} macros might arise here, we must also
+clear the |scanner_status| temporarily.
+
+@<Suppress expansion...@>=
+begin save_scanner_status:=scanner_status; scanner_status:=normal;
+get_token; scanner_status:=save_scanner_status; t:=cur_tok;
+back_input; {now |start| and |loc| point to the backed-up token |t|}
+if t>=cs_token_flag then
+  begin p:=get_avail; info(p):=cs_token_flag+frozen_dont_expand;
+  link(p):=loc; start:=p; loc:=p;
+  end;
+end
+
+@ @<Complain about an undefined macro@>=
+begin print_err("Undefined control sequence");
+@.Undefined control sequence@>
+help5("The control sequence at the end of the top line")@/
+("of your error message was never \def'ed. If you have")@/
+("misspelled it (e.g., `\hobx'), type `I' and the correct")@/
+("spelling (e.g., `I\hbox'). Otherwise just continue,")@/
+("and I'll forget about whatever was undefined.");
+error;
+end
+
+@ The |expand| procedure and some other routines that construct token
+lists find it convenient to use the following macros, which are valid only if
+the variables |p| and |q| are reserved for token-list building.
+
+@d store_new_token(#)==begin q:=get_avail; link(p):=q; info(q):=#;
+  p:=q; {|link(p)| is |null|}
+  end
+@d fast_store_new_token(#)==begin fast_get_avail(q); link(p):=q; info(q):=#;
+  p:=q; {|link(p)| is |null|}
+  end
+
+@ @<Manufacture a control...@>=
+begin r:=get_avail; p:=r; {head of the list of characters}
+repeat get_x_token;
+if cur_cs=0 then store_new_token(cur_tok);
+until cur_cs<>0;
+if cur_cmd<>end_cs_name then @<Complain about missing \.{\\endcsname}@>;
+@<Look up the characters of list |r| in the hash table, and set |cur_cs|@>;
+flush_list(r);
+if eq_type(cur_cs)=undefined_cs then
+  begin eq_define(cur_cs,relax,256); {N.B.: The |save_stack| might change}
+  end; {the control sequence will now match `\.{\\relax}'}
+cur_tok:=cur_cs+cs_token_flag; back_input;
+end
+
+@ @<Complain about missing \.{\\endcsname}@>=
+begin print_err("Missing "); print_esc("endcsname"); print(" inserted");
+@.Missing \\endcsname...@>
+help2("The control sequence marked <to be read again> should")@/
+  ("not appear between \csname and \endcsname.");
+back_error;
+end
+
+@ @<Look up the characters of list |r| in the hash table...@>=
+j:=first; p:=link(r);
+while p<>null do
+  begin if j>=max_buf_stack then
+    begin max_buf_stack:=j+1;
+    if max_buf_stack=buf_size then
+      overflow("buffer size",buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+    end;
+  if check_kanji(info(p)) then {|wchar_token|}
+    begin buffer[j]:=Hi(info(p)); incr(j);
+    end;
+  buffer[j]:=Lo(info(p)); incr(j); p:=link(p);
+  end;
+if j>first+1 then
+  begin no_new_control_sequence:=false; cur_cs:=id_lookup(first,j-first);
+  no_new_control_sequence:=true;
+  end
+else if j=first then cur_cs:=null_cs {the list is empty}
+else cur_cs:=single_base+buffer[first] {the list has length one}
+
+@ An |end_template| command is effectively changed to an |endv| command
+by the following code. (The reason for this is discussed below; the
+|frozen_end_template| at the end of the template has passed the
+|check_outer_validity| test, so its mission of error detection has been
+accomplished.)
+
+@<Insert a token containing |frozen_endv|@>=
+begin cur_tok:=cs_token_flag+frozen_endv; back_input;
+end
+
+@ The processing of \.{\\input} involves the |start_input| subroutine,
+which will be declared later; the processing of \.{\\endinput} is trivial.
+
+@<Put each...@>=
+primitive("input",input,0);@/
+@!@:input_}{\.{\\input} primitive@>
+primitive("endinput",input,1);@/
+@!@:end_input_}{\.{\\endinput} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+input: if chr_code=0 then print_esc("input")@+else print_esc("endinput");
+
+@ @<Initiate or terminate input...@>=
+if cur_chr>0 then force_eof:=true
+else if name_in_progress then insert_relax
+else start_input
+
+@ Sometimes the expansion looks too far ahead, so we want to insert
+a harmless \.{\\relax} into the user's input.
+
+@<Declare the procedure called |insert_relax|@>=
+procedure insert_relax;
+begin cur_tok:=cs_token_flag+cur_cs; back_input;
+cur_tok:=cs_token_flag+frozen_relax; back_input; token_type:=inserted;
+end;
+
+@ Here is a recursive procedure that is \TeX's usual way to get the
+next token of input. It has been slightly optimized to take account of
+common cases.
+
+@p procedure get_x_token; {sets |cur_cmd|, |cur_chr|, |cur_tok|,
+  and expands macros}
+label restart,done;
+begin restart: get_next;
+@^inner loop@>
+if cur_cmd<=max_command then goto done;
+if cur_cmd>=call then
+  if cur_cmd<end_template then macro_call
+  else  begin cur_cs:=frozen_endv; cur_cmd:=endv;
+    goto done; {|cur_chr=null_list|}
+    end
+else expand;
+goto restart;
+done: if cur_cs=0 then
+  if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then
+    cur_tok:=cur_chr
+  else cur_tok:=(cur_cmd*@'400)+cur_chr
+else cur_tok:=cs_token_flag+cur_cs;
+end;
+
+@ The |get_x_token| procedure is equivalent to two consecutive
+procedure calls: |get_next; x_token|.
+
+@p procedure x_token; {|get_x_token| without the initial |get_next|}
+begin while cur_cmd>max_command do
+  begin expand;
+  get_next;
+  end;
+if cur_cs=0 then
+  if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then
+    cur_tok:=cur_chr
+  else cur_tok:=(cur_cmd*@'400)+cur_chr
+else cur_tok:=cs_token_flag+cur_cs;
+end;
+
+@ A control sequence that has been \.{\\def}'ed by the user is expanded by
+\TeX's |macro_call| procedure.
+
+Before we get into the details of |macro_call|, however, let's consider the
+treatment of primitives like \.{\\topmark}, since they are essentially
+macros without parameters. The token lists for such marks are kept in a
+global array of five pointers; we refer to the individual entries of this
+array by symbolic names |top_mark|, etc. The value of |top_mark| is either
+|null| or a pointer to the reference count of a token list.
+
+@d top_mark_code=0 {the mark in effect at the previous page break}
+@d first_mark_code=1 {the first mark between |top_mark| and |bot_mark|}
+@d bot_mark_code=2 {the mark in effect at the current page break}
+@d split_first_mark_code=3 {the first mark found by \.{\\vsplit}}
+@d split_bot_mark_code=4 {the last mark found by \.{\\vsplit}}
+@d top_mark==cur_mark[top_mark_code]
+@d first_mark==cur_mark[first_mark_code]
+@d bot_mark==cur_mark[bot_mark_code]
+@d split_first_mark==cur_mark[split_first_mark_code]
+@d split_bot_mark==cur_mark[split_bot_mark_code]
+
+@<Glob...@>=
+@!cur_mark:array[top_mark_code..split_bot_mark_code] of pointer;
+  {token lists for marks}
+
+@ @<Set init...@>=
+top_mark:=null; first_mark:=null; bot_mark:=null;
+split_first_mark:=null; split_bot_mark:=null;
+
+@ @<Put each...@>=
+primitive("topmark",top_bot_mark,top_mark_code);
+@!@:top_mark_}{\.{\\topmark} primitive@>
+primitive("firstmark",top_bot_mark,first_mark_code);
+@!@:first_mark_}{\.{\\firstmark} primitive@>
+primitive("botmark",top_bot_mark,bot_mark_code);
+@!@:bot_mark_}{\.{\\botmark} primitive@>
+primitive("splitfirstmark",top_bot_mark,split_first_mark_code);
+@!@:split_first_mark_}{\.{\\splitfirstmark} primitive@>
+primitive("splitbotmark",top_bot_mark,split_bot_mark_code);
+@!@:split_bot_mark_}{\.{\\splitbotmark} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+top_bot_mark: case chr_code of
+  first_mark_code: print_esc("firstmark");
+  bot_mark_code: print_esc("botmark");
+  split_first_mark_code: print_esc("splitfirstmark");
+  split_bot_mark_code: print_esc("splitbotmark");
+  othercases print_esc("topmark")
+  endcases;
+
+@ The following code is activated when |cur_cmd=top_bot_mark| and
+when |cur_chr| is a code like |top_mark_code|.
+
+@<Insert the \(a)appropriate mark text into the scanner@>=
+begin if cur_mark[cur_chr]<>null then
+  begin_token_list(cur_mark[cur_chr],mark_text);
+end
+
+@ Now let's consider |macro_call| itself, which is invoked when \TeX\ is
+scanning a control sequence whose |cur_cmd| is either |call|, |long_call|,
+|outer_call|, or |long_outer_call|.  The control sequence definition
+appears in the token list whose reference count is in location |cur_chr|
+of |mem|.
+
+The global variable |long_state| will be set to |call| or to |long_call|,
+depending on whether or not the control sequence disallows \.{\\par}
+in its parameters. The |get_next| routine will set |long_state| to
+|outer_call| and emit \.{\\par}, if a file ends or if an \.{\\outer}
+control sequence occurs in the midst of an argument.
+
+@<Glob...@>=
+@!long_state:call..long_outer_call; {governs the acceptance of \.{\\par}}
+
+@ The parameters, if any, must be scanned before the macro is expanded.
+Parameters are token lists without reference counts. They are placed on
+an auxiliary stack called |pstack| while they are being scanned, since
+the |param_stack| may be losing entries during the matching process.
+(Note that |param_stack| can't be gaining entries, since |macro_call| is
+the only routine that puts anything onto |param_stack|, and it
+is not recursive.)
+
+@<Glob...@>=
+@!pstack:array[0..8] of pointer; {arguments supplied to a macro}
+
+@ After parameter scanning is complete, the parameters are moved to the
+|param_stack|. Then the macro body is fed to the scanner; in other words,
+|macro_call| places the defined text of the control sequence at the
+top of\/ \TeX's input stack, so that |get_next| will proceed to read it
+next.
+
+The global variable |cur_cs| contains the |eqtb| address of the control sequence
+being expanded, when |macro_call| begins. If this control sequence has not been
+declared \.{\\long}, i.e., if its command code in the |eq_type| field is
+not |long_call| or |long_outer_call|, its parameters are not allowed to contain
+the control sequence \.{\\par}. If an illegal \.{\\par} appears, the macro
+call is aborted, and the \.{\\par} will be rescanned.
+
+@<Declare the procedure called |macro_call|@>=
+procedure macro_call; {invokes a user-defined control sequence}
+label exit, continue, done, done1, found;
+var r:pointer; {current node in the macro's token list}
+@!p:pointer; {current node in parameter token list being built}
+@!q:pointer; {new node being put into the token list}
+@!s:pointer; {backup pointer for parameter matching}
+@!t:pointer; {cycle pointer for backup recovery}
+@!u,@!v:pointer; {auxiliary pointers for backup recovery}
+@!rbrace_ptr:pointer; {one step before the last |right_brace| token}
+@!n:small_number; {the number of parameters scanned}
+@!unbalance:halfword; {unmatched left braces in current parameter}
+@!m:halfword; {the number of tokens or groups (usually)}
+@!ref_count:pointer; {start of the token list}
+@!save_scanner_status:small_number; {|scanner_status| upon entry}
+@!save_warning_index:pointer; {|warning_index| upon entry}
+@!match_chr:ASCII_code; {character used in parameter}
+begin save_scanner_status:=scanner_status; save_warning_index:=warning_index;
+warning_index:=cur_cs; ref_count:=cur_chr; r:=link(ref_count); n:=0;
+if tracing_macros>0 then @<Show the text of the macro being expanded@>;
+if info(r)<>end_match_token then
+  @<Scan the parameters and make |link(r)| point to the macro body; but
+    |return| if an illegal \.{\\par} is detected@>;
+@<Feed the macro body and its parameters to the scanner@>;
+exit:scanner_status:=save_scanner_status; warning_index:=save_warning_index;
+end;
+
+@ Before we put a new token list on the input stack, it is wise to clean off
+all token lists that have recently been depleted. Then a user macro that ends
+with a call to itself will not require unbounded stack space.
+
+@<Feed the macro body and its parameters to the scanner@>=
+while (state=token_list)and(loc=null)and(token_type<>v_template) do
+  end_token_list; {conserve stack space}
+begin_token_list(ref_count,macro); name:=warning_index; loc:=link(r);
+if n>0 then
+  begin if param_ptr+n>max_param_stack then
+    begin max_param_stack:=param_ptr+n;
+    if max_param_stack>param_size then
+      overflow("parameter stack size",param_size);
+@:TeX capacity exceeded parameter stack size}{\quad parameter stack size@>
+    end;
+  for m:=0 to n-1 do param_stack[param_ptr+m]:=pstack[m];
+  param_ptr:=param_ptr+n;
+  end
+
+@ At this point, the reader will find it advisable to review the explanation
+of token list format that was presented earlier, since many aspects of that
+format are of importance chiefly in the |macro_call| routine.
+
+The token list might begin with a string of compulsory tokens before the
+first |match| or |end_match|. In that case the macro name is supposed to be
+followed by those tokens; the following program will set |s=null| to
+represent this restriction. Otherwise |s| will be set to the first token of
+a string that will delimit the next parameter.
+
+@<Scan the parameters and make |link(r)| point to the macro body...@>=
+begin scanner_status:=matching; unbalance:=0;
+long_state:=eq_type(cur_cs);
+if long_state>=outer_call then long_state:=long_state-2;
+repeat link(temp_head):=null;
+if (info(r)>match_token+255)or(info(r)<match_token) then s:=null
+else  begin match_chr:=info(r)-match_token; s:=link(r); r:=s;
+  p:=temp_head; m:=0;
+  end;
+@<Scan a parameter until its delimiter string has been found; or, if |s=null|,
+  simply scan the delimiter string@>;@/
+{now |info(r)| is a token whose command code is either |match| or |end_match|}
+until info(r)=end_match_token;
+end
+
+@ If |info(r)| is a |match| or |end_match| command, it cannot be equal to
+any token found by |get_token|. Therefore an undelimited parameter---i.e.,
+a |match| that is immediately followed by |match| or |end_match|---will
+always fail the test `|cur_tok=info(r)|' in the following algorithm.
+
+@<Scan a parameter until its delimiter string has been found; or, ...@>=
+continue: get_token; {set |cur_tok| to the next token of input}
+if cur_tok=info(r) then
+  @<Advance \(r)|r|; |goto found| if the parameter delimiter has been
+    fully matched, otherwise |goto continue|@>;
+@<Contribute the recently matched tokens to the current parameter, and
+  |goto continue| if a partial match is still in effect;
+  but abort if |s=null|@>;
+if cur_tok=par_token then if long_state<>long_call then
+  @<Report a runaway argument and abort@>;
+if cur_tok<right_brace_limit then
+  if cur_tok<left_brace_limit then
+    @<Contribute an entire group to the current parameter@>
+  else @<Report an extra right brace and |goto continue|@>
+else @<Store the current token, but |goto continue| if it is
+   a blank space that would become an undelimited parameter@>;
+incr(m);
+if info(r)>end_match_token then goto continue;
+if info(r)<match_token then goto continue;
+found: if s<>null then @<Tidy up the parameter just scanned, and tuck it away@>
+
+@ @<Store the current token, but |goto continue| if it is...@>=
+begin if cur_tok=space_token then
+  if info(r)<=end_match_token then
+    if info(r)>=match_token then goto continue;
+store_new_token(cur_tok);
+end
+
+@ A slightly subtle point arises here: When the parameter delimiter ends
+with `\.{\#\{}', the token list will have a left brace both before and
+after the |end_match|\kern-.4pt. Only one of these should affect the
+|align_state|, but both will be scanned, so we must make a correction.
+
+@<Advance \(r)|r|; |goto found| if the parameter delimiter has been fully...@>=
+begin r:=link(r);
+if (info(r)>=match_token)and(info(r)<=end_match_token) then
+  begin if cur_tok<left_brace_limit then decr(align_state);
+  goto found;
+  end
+else goto continue;
+end
+
+@ @<Report an extra right brace and |goto continue|@>=
+begin back_input; print_err("Argument of "); sprint_cs(warning_index);
+@.Argument of \\x has...@>
+print(" has an extra }");
+help6("I've run across a `}' that doesn't seem to match anything.")@/
+  ("For example, `\def\a#1{...}' and `\a}' would produce")@/
+  ("this error. If you simply proceed now, the `\par' that")@/
+  ("I've just inserted will cause me to report a runaway")@/
+  ("argument that might be the root of the problem. But if")@/
+  ("your `}' was spurious, just type `2' and it will go away.");
+incr(align_state); long_state:=call; cur_tok:=par_token; ins_error;
+goto continue;
+end {a white lie; the \.{\\par} won't always trigger a runaway}
+
+@ If |long_state=outer_call|, a runaway argument has already been reported.
+
+@<Report a runaway argument and abort@>=
+begin if long_state=call then
+  begin runaway; print_err("Paragraph ended before ");
+@.Paragraph ended before...@>
+  sprint_cs(warning_index); print(" was complete");
+  help3("I suspect you've forgotten a `}', causing me to apply this")@/
+    ("control sequence to too much text. How can we recover?")@/
+    ("My plan is to forget the whole thing and hope for the best.");
+  back_error;
+  end;
+pstack[n]:=link(temp_head); align_state:=align_state-unbalance;
+for m:=0 to n do flush_list(pstack[m]);
+return;
+end
+
+@ When the following code becomes active, we have matched tokens from |s| to
+the predecessor of |r|, and we have found that |cur_tok<>info(r)|. An
+interesting situation now presents itself: If the parameter is to be
+delimited by a string such as `\.{ab}', and if we have scanned `\.{aa}',
+we want to contribute one `\.a' to the current parameter and resume
+looking for a `\.b'. The program must account for such partial matches and
+for others that can be quite complex.  But most of the time we have |s=r|
+and nothing needs to be done.
+
+Incidentally, it is possible for \.{\\par} tokens to sneak in to certain
+parameters of non-\.{\\long} macros. For example, consider a case like
+`\.{\\def\\a\#1\\par!\{...\}}' where the first \.{\\par} is not followed
+by an exclamation point. In such situations it does not seem appropriate
+to prohibit the \.{\\par}, so \TeX\ keeps quiet about this bending of
+the rules.
+
+@<Contribute the recently matched tokens to the current parameter...@>=
+if s<>r then
+  if s=null then @<Report an improper use of the macro and abort@>
+  else  begin t:=s;
+    repeat store_new_token(info(t)); incr(m); u:=link(t); v:=s;
+    loop@+  begin if u=r then
+        if cur_tok<>info(v) then goto done
+        else  begin r:=link(v); goto continue;
+          end;
+      if info(u)<>info(v) then goto done;
+      u:=link(u); v:=link(v);
+      end;
+    done: t:=link(t);
+    until t=r;
+    r:=s; {at this point, no tokens are recently matched}
+    end
+
+@ @<Report an improper use...@>=
+begin print_err("Use of "); sprint_cs(warning_index);
+@.Use of x doesn't match...@>
+print(" doesn't match its definition");
+help4("If you say, e.g., `\def\a1{...}', then you must always")@/
+  ("put `1' after `\a', since control sequence names are")@/
+  ("made up of letters only. The macro here has not been")@/
+  ("followed by the required stuff, so I'm ignoring it.");
+error; return;
+end
+
+@ @<Contribute an entire group to the current parameter@>=
+begin unbalance:=1;
+@^inner loop@>
+loop@+  begin fast_store_new_token(cur_tok); get_token;
+  if cur_tok=par_token then if long_state<>long_call then
+    @<Report a runaway argument and abort@>;
+  if cur_tok<right_brace_limit then
+    if cur_tok<left_brace_limit then incr(unbalance)
+    else  begin decr(unbalance);
+      if unbalance=0 then goto done1;
+      end;
+  end;
+done1: rbrace_ptr:=p; store_new_token(cur_tok);
+end
+
+@ If the parameter consists of a single group enclosed in braces, we must
+strip off the enclosing braces. That's why |rbrace_ptr| was introduced.
+
+@<Tidy up the parameter just scanned, and tuck it away@>=
+begin if (m=1)and(info(p)<right_brace_limit)and(p<>temp_head) then
+  begin link(rbrace_ptr):=null; free_avail(p);
+  p:=link(temp_head); pstack[n]:=link(p); free_avail(p);
+  end
+else pstack[n]:=link(temp_head);
+incr(n);
+if tracing_macros>0 then
+  begin begin_diagnostic; print_nl(match_chr); print_int(n);
+  print("<-"); show_token_list(pstack[n-1],null,1000);
+  end_diagnostic(false);
+  end;
+end
+
+@ @<Show the text of the macro being expanded@>=
+begin begin_diagnostic; print_ln; print_cs(warning_index);
+token_show(ref_count); end_diagnostic(false);
+end
+
+@* \[26] Basic scanning subroutines.
+Let's turn now to some procedures that \TeX\ calls upon frequently to digest
+certain kinds of patterns in the input. Most of these are quite simple;
+some are quite elaborate. Almost all of the routines call |get_x_token|,
+which can cause them to be invoked recursively.
+@^stomach@>
+@^recursion@>
+
+@ The |scan_left_brace| routine is called when a left brace is supposed to be
+the next non-blank token. (The term ``left brace'' means, more precisely,
+a character whose catcode is |left_brace|.) \TeX\ allows \.{\\relax} to
+appear before the |left_brace|.
+
+@p procedure scan_left_brace; {reads a mandatory |left_brace|}
+begin @<Get the next non-blank non-relax non-call token@>;
+if cur_cmd<>left_brace then
+  begin print_err("Missing { inserted");
+@.Missing \{ inserted@>
+  help4("A left brace was mandatory here, so I've put one in.")@/
+    ("You might want to delete and/or insert some corrections")@/
+    ("so that I will find a matching right brace soon.")@/
+    ("(If you're confused by all this, try typing `I}' now.)");
+  back_error; cur_tok:=left_brace_token+"{"; cur_cmd:=left_brace;
+  cur_chr:="{"; incr(align_state);
+  end;
+end;
+
+@ @<Get the next non-blank non-relax non-call token@>=
+repeat get_x_token;
+until (cur_cmd<>spacer)and(cur_cmd<>relax)
+
+@ The |scan_optional_equals| routine looks for an optional `\.=' sign preceded
+by optional spaces; `\.{\\relax}' is not ignored here.
+
+@p procedure scan_optional_equals;
+begin  @<Get the next non-blank non-call token@>;
+if cur_tok<>other_token+"=" then back_input;
+end;
+
+@ @<Get the next non-blank non-call token@>=
+repeat get_x_token;
+until cur_cmd<>spacer
+
+@ In case you are getting bored, here is a slightly less trivial routine:
+Given a string of lowercase letters, like `\.{pt}' or `\.{plus}' or
+`\.{width}', the |scan_keyword| routine checks to see whether the next
+tokens of input match this string. The match must be exact, except that
+uppercase letters will match their lowercase counterparts; uppercase
+equivalents are determined by subtracting |"a"-"A"|, rather than using the
+|uc_code| table, since \TeX\ uses this routine only for its own limited
+set of keywords.
+
+If a match is found, the characters are effectively removed from the input
+and |true| is returned. Otherwise |false| is returned, and the input
+is left essentially unchanged (except for the fact that some macros
+may have been expanded, etc.).
+@^inner loop@>
+
+@p function scan_keyword(@!s:str_number):boolean; {look for a given string}
+label exit;
+var p:pointer; {tail of the backup list}
+@!q:pointer; {new node being added to the token list via |store_new_token|}
+@!k:pool_pointer; {index into |str_pool|}
+begin p:=backup_head; link(p):=null; k:=str_start[s];
+while k<str_start[s+1] do
+  begin get_x_token; {recursion is possible here}
+@^recursion@>
+  if (cur_cs=0)and@|
+   ((cur_chr=so(str_pool[k]))or(cur_chr=so(str_pool[k])-"a"+"A")) then
+    begin store_new_token(cur_tok); incr(k);
+    end
+  else if (cur_cmd<>spacer)or(p<>backup_head) then
+    begin back_input;
+    if p<>backup_head then back_list(link(backup_head));
+    scan_keyword:=false; return;
+    end;
+  end;
+flush_list(link(backup_head)); scan_keyword:=true;
+exit:end;
+
+@ Here is a procedure that sounds an alarm when mu and non-mu units
+are being switched.
+
+@p procedure mu_error;
+begin print_err("Incompatible glue units");
+@.Incompatible glue units@>
+help1("I'm going to assume that 1mu=1pt when they're mixed.");
+error;
+end;
+
+@ The next routine `|scan_something_internal|' is used to fetch internal
+numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}'
+when expanding constructions like `\.{\\the\\toks0}' and
+`\.{\\the\\baselineskip}'. Soon we will be considering the |scan_int|
+procedure, which calls |scan_something_internal|; on the other hand,
+|scan_something_internal| also calls |scan_int|, for constructions like
+`\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we
+have to declare |scan_int| as a |forward| procedure. A few other
+procedures are also declared at this point.
+
+@p procedure@?scan_int; forward; {scans an integer value}
+@t\4\4@>@<Declare procedures that scan restricted classes of integers@>@;
+@t\4\4@>@<Declare procedures that scan font-related stuff@>
+
+@ \TeX\ doesn't know exactly what to expect when |scan_something_internal|
+begins.  For example, an integer or dimension or glue value could occur
+immediately after `\.{\\hskip}'; and one can even say \.{\\the} with
+respect to token lists in constructions like
+`\.{\\xdef\\o\{\\the\\output\}}'.  On the other hand, only integers are
+allowed after a construction like `\.{\\count}'. To handle the various
+possibilities, |scan_something_internal| has a |level| parameter, which
+tells the ``highest'' kind of quantity that |scan_something_internal| is
+allowed to produce. Six levels are distinguished, namely |int_val|,
+|dimen_val|, |glue_val|, |mu_val|, |ident_val|, and |tok_val|.
+
+The output of |scan_something_internal| (and of the other routines
+|scan_int|, |scan_dimen|, and |scan_glue| below) is put into the global
+variable |cur_val|, and its level is put into |cur_val_level|. The highest
+values of |cur_val_level| are special: |mu_val| is used only when
+|cur_val| points to something in a ``muskip'' register, or to one of the
+three parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip};
+|ident_val| is used only when |cur_val| points to a font identifier;
+|tok_val| is used only when |cur_val| points to |null| or to the reference
+count of a token list. The last two cases are allowed only when
+|scan_something_internal| is called with |level=tok_val|.
+
+If the output is glue, |cur_val| will point to a glue specification, and
+the reference count of that glue will have been updated to reflect this
+reference; if the output is a nonempty token list, |cur_val| will point to
+its reference count, but in this case the count will not have been updated.
+Otherwise |cur_val| will contain the integer or scaled value in question.
+
+@d int_val=0 {integer values}
+@d dimen_val=1 {dimension values}
+@d glue_val=2 {glue specifications}
+@d mu_val=3 {math glue specifications}
+@d ident_val=4 {font identifier}
+@d tok_val=5 {token lists}
+
+@<Glob...@>=
+@!cur_val:integer; {value returned by numeric scanners}
+@!cur_val_level:int_val..tok_val; {the ``level'' of this value}
+
+@ The hash table is initialized with `\.{\\count}', `\.{\\dimen}', `\.{\\skip}',
+and `\.{\\muskip}' all having |register| as their command code; they are
+distinguished by the |chr_code|, which is either |int_val|, |dimen_val|,
+|glue_val|, or |mu_val|.
+
+@<Put each...@>=
+primitive("count",register,int_val);
+@!@:count_}{\.{\\count} primitive@>
+primitive("dimen",register,dimen_val);
+@!@:dimen_}{\.{\\dimen} primitive@>
+primitive("skip",register,glue_val);
+@!@:skip_}{\.{\\skip} primitive@>
+primitive("muskip",register,mu_val);
+@!@:mu_skip_}{\.{\\muskip} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+register: if chr_code=int_val then print_esc("count")
+  else if chr_code=dimen_val then print_esc("dimen")
+  else if chr_code=glue_val then print_esc("skip")
+  else print_esc("muskip");
+
+@ OK, we're ready for |scan_something_internal| itself. A second parameter,
+|negative|, is set |true| if the value that is found should be negated.
+It is assumed that |cur_cmd| and |cur_chr| represent the first token of
+the internal quantity to be scanned; an error will be signalled if
+|cur_cmd<min_internal| or |cur_cmd>max_internal|.
+
+@d scanned_result_end(#)==cur_val_level:=#;@+end
+@d scanned_result(#)==@+begin cur_val:=#;scanned_result_end
+
+@p @t\4@>@<Declare procedures needed in |scan_something_internal|@>@t@>@/
+procedure scan_something_internal(@!level:small_number;@!negative:boolean);
+  {fetch an internal parameter}
+var m:halfword; {|chr_code| part of the operand token}
+@!tx:pointer; {effective tail node}
+@!qx:halfword; {general purpose index}
+@!p:0..nest_size; {index into |nest|}
+@!q,@!r:pointer;
+begin m:=cur_chr;
+case cur_cmd of
+assign_kinsoku: @<Fetch breaking penalty from some table@>;
+assign_inhibit_xsp_code: @<Fetch inhibit type from some table@>;
+def_code: @<Fetch a character code from some table@>;
+toks_register,assign_toks,def_family,set_font,def_font,def_jfont,def_tfont:
+  @<Fetch a token list or font identifier, provided that |level=tok_val|@>;
+assign_int: scanned_result(eqtb[m].int)(int_val);
+assign_dimen: scanned_result(eqtb[m].sc)(dimen_val);
+assign_glue: scanned_result(equiv(m))(glue_val);
+assign_mu_glue: scanned_result(equiv(m))(mu_val);
+set_aux: @<Fetch the |space_factor| or the |prev_depth|@>;
+set_prev_graf: @<Fetch the |prev_graf|@>;
+set_page_int:@<Fetch the |dead_cycles| or the |insert_penalties|@>;
+set_page_dimen: @<Fetch something on the |page_so_far|@>;
+set_shape: @<Fetch the |par_shape| size@>;
+set_box_dimen: @<Fetch a box dimension@>;
+char_given,math_given: scanned_result(cur_chr)(int_val);
+assign_font_dimen: @<Fetch a font dimension@>;
+assign_font_int: @<Fetch a font integer@>;
+register: @<Fetch a register@>;
+last_item: @<Fetch an item in the current node, if appropriate@>;
+othercases @<Complain that \.{\\the} can't do this; give zero result@>
+endcases;@/
+while cur_val_level>level do @<Convert \(c)|cur_val| to a lower level@>;
+@<Fix the reference count, if any, and negate |cur_val| if |negative|@>;
+end;
+
+@ @<Fetch a character code from some table@>=
+begin scan_char_num;
+if m=math_code_base then scanned_result(ho(math_code(cur_val)))(int_val)
+else if m=kcat_code_base then scanned_result(equiv(m+kcatcodekey(cur_val)))(int_val)
+else if m<math_code_base then { \.{\\lccode}, \.{\\uccode}, \.{\\sfcode}, \.{\\catcode} }
+  begin if not is_char_ascii(cur_val) then
+  scanned_result(equiv(m+Hi(cur_val)))(int_val)
+  else scanned_result(equiv(m+cur_val))(int_val)
+  end
+else { \.{\\delcode} }
+  begin if not is_char_ascii(cur_val) then
+  scanned_result(eqtb[m+Hi(cur_val)].int)(int_val)
+  else scanned_result(eqtb[m+cur_val].int)(int_val)
+  end;
+end
+
+@ @<Fetch a token list...@>=
+if level<>tok_val then
+  begin print_err("Missing number, treated as zero");
+@.Missing number...@>
+  help3("A number should have been here; I inserted `0'.")@/
+    ("(If you can't figure out why I needed to see a number,")@/
+    ("look up `weird error' in the index to The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+  back_error; scanned_result(0)(dimen_val);
+  end
+else if cur_cmd<=assign_toks then
+  begin if cur_cmd<assign_toks then {|cur_cmd=toks_register|}
+    begin scan_eight_bit_int; m:=toks_base+cur_val;
+    end;
+  scanned_result(equiv(m))(tok_val);
+  end
+else  begin back_input; scan_font_ident;
+  scanned_result(font_id_base+cur_val)(ident_val);
+  end
+
+@ Users refer to `\.{\\the\\spacefactor}' only in horizontal
+mode, and to `\.{\\the\\prevdepth}' only in vertical mode; so we put the
+associated mode in the modifier part of the |set_aux| command.
+The |set_page_int| command has modifier 0 or 1, for `\.{\\deadcycles}' and
+`\.{\\insertpenalties}', respectively. The |set_box_dimen| command is
+modified by either |width_offset|, |height_offset|, or |depth_offset|.
+And the |last_item| command is modified by either |int_val|, |dimen_val|,
+|glue_val|, |input_line_no_code|, or |badness_code|.
+
+@d input_line_no_code=glue_val+1 {code for \.{\\inputlineno}}
+@d badness_code=glue_val+2 {code for \.{\\badness}}
+
+@<Put each...@>=
+primitive("spacefactor",set_aux,hmode);
+@!@:space_factor_}{\.{\\spacefactor} primitive@>
+primitive("prevdepth",set_aux,vmode);@/
+@!@:prev_depth_}{\.{\\prevdepth} primitive@>
+primitive("deadcycles",set_page_int,0);
+@!@:dead_cycles_}{\.{\\deadcycles} primitive@>
+primitive("insertpenalties",set_page_int,1);
+@!@:insert_penalties_}{\.{\\insertpenalties} primitive@>
+primitive("wd",set_box_dimen,width_offset);
+@!@:wd_}{\.{\\wd} primitive@>
+primitive("ht",set_box_dimen,height_offset);
+@!@:ht_}{\.{\\ht} primitive@>
+primitive("dp",set_box_dimen,depth_offset);
+@!@:dp_}{\.{\\dp} primitive@>
+primitive("lastpenalty",last_item,int_val);
+@!@:last_penalty_}{\.{\\lastpenalty} primitive@>
+primitive("lastkern",last_item,dimen_val);
+@!@:last_kern_}{\.{\\lastkern} primitive@>
+primitive("lastskip",last_item,glue_val);
+@!@:last_skip_}{\.{\\lastskip} primitive@>
+primitive("inputlineno",last_item,input_line_no_code);
+@!@:input_line_no_}{\.{\\inputlineno} primitive@>
+primitive("badness",last_item,badness_code);
+@!@:badness_}{\.{\\badness} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+set_aux: if chr_code=vmode then print_esc("prevdepth")
+@+else print_esc("spacefactor");
+set_page_int: if chr_code=0 then print_esc("deadcycles")
+@+else print_esc("insertpenalties");
+set_box_dimen: if chr_code=width_offset then print_esc("wd")
+else if chr_code=height_offset then print_esc("ht")
+else print_esc("dp");
+last_item: case chr_code of
+  int_val: print_esc("lastpenalty");
+  dimen_val: print_esc("lastkern");
+  glue_val: print_esc("lastskip");
+  input_line_no_code: print_esc("inputlineno");
+  othercases print_esc("badness")
+  endcases;
+
+@ @<Fetch the |space_factor| or the |prev_depth|@>=
+if abs(mode)<>m then
+  begin print_err("Improper "); print_cmd_chr(set_aux,m);
+@.Improper \\spacefactor@>
+@.Improper \\prevdepth@>
+  help4("You can refer to \spacefactor only in horizontal mode;")@/
+    ("you can refer to \prevdepth only in vertical mode; and")@/
+    ("neither of these is meaningful inside \write. So")@/
+    ("I'm forgetting what you said and using zero instead.");
+  error;
+  if level<>tok_val then scanned_result(0)(dimen_val)
+  else scanned_result(0)(int_val);
+  end
+else if m=vmode then scanned_result(prev_depth)(dimen_val)
+else scanned_result(space_factor)(int_val)
+
+@ @<Fetch the |dead_cycles| or the |insert_penalties|@>=
+begin if m=0 then cur_val:=dead_cycles@+else cur_val:=insert_penalties;
+cur_val_level:=int_val;
+end
+
+@ @<Fetch a box dimension@>=
+begin scan_eight_bit_int; q:=box(cur_val);
+if q=null then cur_val:=0
+else  begin qx:=q;
+  while (q<>null)and(box_dir(q)<>abs(direction)) do q:=link(q);
+  if q=null then
+    begin r:=link(qx); link(qx):=null;
+    q:=new_dir_node(qx,abs(direction)); link(qx):=r;
+    cur_val:=mem[q+m].sc;
+    delete_glue_ref(space_ptr(q)); delete_glue_ref(xspace_ptr(q));
+    free_node(q,box_node_size);
+    end
+  else cur_val:=mem[q+m].sc;
+  end;
+cur_val_level:=dimen_val;
+end
+
+@ Inside an \.{\\output} routine, a user may wish to look at the page totals
+that were present at the moment when output was triggered.
+
+@d max_dimen==@'7777777777 {$2^{30}-1$}
+
+@<Fetch something on the |page_so_far|@>=
+begin if (page_contents=empty) and (not output_active) then
+  if m=0 then cur_val:=max_dimen@+else cur_val:=0
+else cur_val:=page_so_far[m];
+cur_val_level:=dimen_val;
+end
+
+@ @<Fetch the |prev_graf|@>=
+if mode=0 then scanned_result(0)(int_val) {|prev_graf=0| within \.{\\write}}
+else begin nest[nest_ptr]:=cur_list; p:=nest_ptr;
+  while abs(nest[p].mode_field)<>vmode do decr(p);
+  scanned_result(nest[p].pg_field)(int_val);
+  end
+
+@ @<Fetch the |par_shape| size@>=
+begin if par_shape_ptr=null then cur_val:=0
+else cur_val:=info(par_shape_ptr);
+cur_val_level:=int_val;
+end
+
+@ Here is where \.{\\lastpenalty}, \.{\\lastkern}, and \.{\\lastskip} are
+implemented. The reference count for \.{\\lastskip} will be updated later.
+
+We also handle \.{\\inputlineno} and \.{\\badness} here, because they are
+legal in similar contexts.
+
+The macro |find_effective_tail_pTeX| sets |tx| to the last non-|disp_node|
+of the current list.
+
+@d find_effective_tail_pTeX==
+tx:=tail;
+if not is_char_node(tx) then
+  if type(tx)=disp_node then
+    begin tx:=prev_node;
+    if not is_char_node(tx) then
+      if type(tx)=disp_node then {|disp_node| from a discretionary}
+        begin tx:=head; q:=link(head);
+        while q<>prev_node do
+          begin if is_char_node(q) then tx:=q
+          else if type(q)<>disp_node then tx:=q;
+          end;
+        q:=link(q);
+        end;
+    end
+@#
+@d find_effective_tail==find_effective_tail_pTeX
+
+@<Fetch an item in the current node...@>=
+if cur_chr>glue_val then
+  begin if cur_chr=input_line_no_code then cur_val:=line
+  else cur_val:=last_badness; {|cur_chr=badness_code|}
+  cur_val_level:=int_val;
+  end
+else begin if cur_chr=glue_val then cur_val:=zero_glue@+else cur_val:=0;
+  find_effective_tail;
+  cur_val_level:=cur_chr;
+  if not is_char_node(tx)and(tx<>head)and(mode<>0) then
+    case cur_chr of
+    int_val: if type(tx)=penalty_node then cur_val:=penalty(tx);
+    dimen_val: if type(tx)=kern_node then cur_val:=width(tx);
+    glue_val: if type(tx)=glue_node then
+      begin cur_val:=glue_ptr(tx);
+      if subtype(tx)=mu_glue then cur_val_level:=mu_val;
+      end;
+    end {there are no other cases}
+  else if (mode=vmode)and(tx=head) then
+    case cur_chr of
+    int_val: cur_val:=last_penalty;
+    dimen_val: cur_val:=last_kern;
+    glue_val: if last_glue<>max_halfword then cur_val:=last_glue;
+    end; {there are no other cases}
+  end
+
+@ @<Fetch a font dimension@>=
+begin find_font_dimen(false); font_info[fmem_ptr].sc:=0;
+scanned_result(font_info[cur_val].sc)(dimen_val);
+end
+
+@ @<Fetch a font integer@>=
+begin scan_font_ident;
+if m=0 then scanned_result(hyphen_char[cur_val])(int_val)
+else scanned_result(skew_char[cur_val])(int_val);
+end
+
+@ @<Fetch a register@>=
+begin scan_eight_bit_int;
+case m of
+int_val:cur_val:=count(cur_val);
+dimen_val:cur_val:=dimen(cur_val);
+glue_val: cur_val:=skip(cur_val);
+mu_val: cur_val:=mu_skip(cur_val);
+end; {there are no other cases}
+cur_val_level:=m;
+end
+
+@ @<Complain that \.{\\the} can't do this; give zero result@>=
+begin print_err("You can't use `"); print_cmd_chr(cur_cmd,cur_chr);
+@.You can't use x after ...@>
+print("' after "); print_esc("the");
+help1("I'm forgetting what you said and using zero instead.");
+error;
+if level<>tok_val then scanned_result(0)(dimen_val)
+else scanned_result(0)(int_val);
+end
+
+@ When a |glue_val| changes to a |dimen_val|, we use the width component
+of the glue; there is no need to decrease the reference count, since it
+has not yet been increased.  When a |dimen_val| changes to an |int_val|,
+we use scaled points so that the value doesn't actually change. And when a
+|mu_val| changes to a |glue_val|, the value doesn't change either.
+
+@<Convert \(c)|cur_val| to a lower level@>=
+begin if cur_val_level=glue_val then cur_val:=width(cur_val)
+else if cur_val_level=mu_val then mu_error;
+decr(cur_val_level);
+end
+
+@ If |cur_val| points to a glue specification at this point, the reference
+count for the glue does not yet include the reference by |cur_val|.
+If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|.
+
+@<Fix the reference count, if any, ...@>=
+if negative then
+  if cur_val_level>=glue_val then
+    begin cur_val:=new_spec(cur_val);
+    @<Negate all three glue components of |cur_val|@>;
+    end
+  else negate(cur_val)
+else if (cur_val_level>=glue_val)and(cur_val_level<=mu_val) then
+  add_glue_ref(cur_val)
+
+@ @<Negate all three...@>=
+begin negate(width(cur_val));
+negate(stretch(cur_val));
+negate(shrink(cur_val));
+end
+
+@ Our next goal is to write the |scan_int| procedure, which scans anything that
+\TeX\ treats as an integer. But first we might as well look at some simple
+applications of |scan_int| that have already been made inside of
+|scan_something_internal|.
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+procedure scan_eight_bit_int;
+begin scan_int;
+if (cur_val<0)or(cur_val>255) then
+  begin print_err("Bad register code");
+@.Bad register code@>
+  help2("A register number must be between 0 and 255.")@/
+    ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+  end;
+end;
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+procedure scan_char_num;
+begin scan_int;
+if not is_char_ascii(cur_val) and not is_char_kanji(cur_val) then
+  begin print_err("Bad character code");
+@.Bad character code@>
+  help2("A character number must be between 0 and 255, or KANJI code.")@/
+    ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+  end;
+end;
+
+@ While we're at it, we might as well deal with similar routines that
+will be needed later.
+
+@<Declare procedures that scan restricted classes of integers@>=
+procedure scan_four_bit_int;
+begin scan_int;
+if (cur_val<0)or(cur_val>15) then
+  begin print_err("Bad number");
+@.Bad number@>
+  help2("Since I expected to read a number between 0 and 15,")@/
+    ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+  end;
+end;
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+procedure scan_fifteen_bit_int;
+begin scan_int;
+if (cur_val<0)or(cur_val>@'77777) then
+  begin print_err("Bad mathchar");
+@.Bad mathchar@>
+  help2("A mathchar number must be between 0 and 32767.")@/
+    ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+  end;
+end;
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+procedure scan_twenty_seven_bit_int;
+begin scan_int;
+if (cur_val<0)or(cur_val>@'777777777) then
+  begin print_err("Bad delimiter code");
+@.Bad delimiter code@>
+  help2("A numeric delimiter code must be between 0 and 2^{27}-1.")@/
+    ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+  end;
+end;
+
+@ An integer number can be preceded by any number of spaces and `\.+' or
+`\.-' signs. Then comes either a decimal constant (i.e., radix 10), an
+octal constant (i.e., radix 8, preceded by~\.\'), a hexadecimal constant
+(radix 16, preceded by~\."), an alphabetic constant (preceded by~\.\`), or
+an internal variable. After scanning is complete,
+|cur_val| will contain the answer, which must be at most
+$2^{31}-1=2147483647$ in absolute value. The value of |radix| is set to
+10, 8, or 16 in the cases of decimal, octal, or hexadecimal constants,
+otherwise |radix| is set to zero. An optional space follows a constant.
+
+@d octal_token=other_token+"'" {apostrophe, indicates an octal constant}
+@d hex_token=other_token+"""" {double quote, indicates a hex constant}
+@d alpha_token=other_token+"`" {reverse apostrophe, precedes alpha constants}
+@d point_token=other_token+"." {decimal point}
+@d continental_point_token=other_token+"," {decimal point, Eurostyle}
+
+@<Glob...@>=
+@!radix:small_number; {|scan_int| sets this to 8, 10, 16, or zero}
+
+@ We initialize the following global variables just in case |expand|
+comes into action before any of the basic scanning routines has assigned
+them a value.
+
+@<Set init...@>=
+cur_val:=0; cur_val_level:=int_val; radix:=0; cur_order:=normal;
+
+@ The |scan_int| routine is used also to scan the integer part of a
+fraction; for example, the `\.3' in `\.{3.14159}' will be found by
+|scan_int|. The |scan_dimen| routine assumes that |cur_tok=point_token|
+after the integer part of such a fraction has been scanned by |scan_int|,
+and that the decimal point has been backed up to be scanned again.
+
+@p procedure scan_int; {sets |cur_val| to an integer}
+label done;
+var negative:boolean; {should the answer be negated?}
+@!m:integer; {|@t$2^{31}$@> div radix|, the threshold of danger}
+@!d:small_number; {the digit just scanned}
+@!vacuous:boolean; {have no digits appeared?}
+@!OK_so_far:boolean; {has an error message been issued?}
+begin radix:=0; OK_so_far:=true;@/
+@<Get the next non-blank non-sign token; set |negative| appropriately@>;
+if cur_tok=alpha_token then @<Scan an alphabetic character code into |cur_val|@>
+else if (cur_cmd>=min_internal)and(cur_cmd<=max_internal) then
+  scan_something_internal(int_val,false)
+else @<Scan a numeric constant@>;
+if negative then negate(cur_val);
+end;
+
+@ @<Get the next non-blank non-sign token...@>=
+negative:=false;
+repeat @<Get the next non-blank non-call token@>;
+if cur_tok=other_token+"-" then
+  begin negative := not negative; cur_tok:=other_token+"+";
+  end;
+until cur_tok<>other_token+"+"
+
+@ A space is ignored after an alphabetic character constant, so that
+such constants behave like numeric ones.
+
+@<Scan an alphabetic character code into |cur_val|@>=
+begin get_token; {suppress macro expansion}
+if cur_tok<cs_token_flag then
+  if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then {|wchar_token|}
+    begin skip_mode:=false; cur_val:=tonum(cur_chr);
+    end
+  else begin cur_val:=cur_chr;
+  if cur_cmd<=right_brace then
+    if cur_cmd=right_brace then incr(align_state)
+    else decr(align_state);
+  end
+else if cur_tok<cs_token_flag+single_base then
+  cur_val:=cur_tok-cs_token_flag-active_base
+else cur_val:=cur_tok-cs_token_flag-single_base;
+if (cur_val>255)and((cur_cmd<kanji)or(cur_cmd>max_char_code)) then
+  begin print_err("Improper alphabetic or KANJI constant");
+@.Improper alphabetic constant@>
+  help2("A one-character control sequence belongs after a ` mark.")@/
+    ("So I'm essentially inserting \0 here.");
+  cur_val:="0"; back_error;
+  end
+else @<Scan an optional space@>;
+skip_mode:=true;
+end
+
+@ @<Scan an optional space@>=
+begin get_x_token; if cur_cmd<>spacer then back_input;
+end
+
+@ @<Scan a numeric constant@>=
+begin radix:=10; m:=214748364;
+if cur_tok=octal_token then
+  begin radix:=8; m:=@'2000000000; get_x_token;
+  end
+else if cur_tok=hex_token then
+  begin radix:=16; m:=@'1000000000; get_x_token;
+  end;
+vacuous:=true; cur_val:=0;@/
+@<Accumulate the constant until |cur_tok| is not a suitable digit@>;
+if vacuous then @<Express astonishment that no number was here@>
+else if cur_cmd<>spacer then back_input;
+end
+
+@ @d infinity==@'17777777777 {the largest positive value that \TeX\ knows}
+@d zero_token=other_token+"0" {zero, the smallest digit}
+@d A_token=letter_token+"A" {the smallest special hex digit}
+@d other_A_token=other_token+"A" {special hex digit of type |other_char|}
+
+@<Accumulate the constant...@>=
+loop@+  begin if (cur_tok<zero_token+radix)and(cur_tok>=zero_token)and
+    (cur_tok<=zero_token+9) then d:=cur_tok-zero_token
+  else if radix=16 then
+    if (cur_tok<=A_token+5)and(cur_tok>=A_token) then d:=cur_tok-A_token+10
+    else if (cur_tok<=other_A_token+5)and(cur_tok>=other_A_token) then
+      d:=cur_tok-other_A_token+10
+    else goto done
+  else goto done;
+  vacuous:=false;
+  if (cur_val>=m)and((cur_val>m)or(d>7)or(radix<>10)) then
+    begin if OK_so_far then
+      begin print_err("Number too big");
+@.Number too big@>
+      help2("I can only go up to 2147483647='17777777777=""7FFFFFFF,")@/
+        ("so I'm using that number instead of yours.");
+      error; cur_val:=infinity; OK_so_far:=false;
+      end;
+    end
+  else cur_val:=cur_val*radix+d;
+  get_x_token;
+  end;
+done:
+
+@ @<Express astonishment...@>=
+begin print_err("Missing number, treated as zero");
+@.Missing number...@>
+help3("A number should have been here; I inserted `0'.")@/
+  ("(If you can't figure out why I needed to see a number,")@/
+  ("look up `weird error' in the index to The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+back_error;
+end
+
+@ The |scan_dimen| routine is similar to |scan_int|, but it sets |cur_val| to
+a |scaled| value, i.e., an integral number of sp. One of its main tasks
+is therefore to interpret the abbreviations for various kinds of units and
+to convert measurements to scaled points.
+
+There are three parameters: |mu| is |true| if the finite units must be
+`\.{mu}', while |mu| is |false| if `\.{mu}' units are disallowed;
+|inf| is |true| if the infinite units `\.{fil}', `\.{fill}', `\.{filll}'
+are permitted; and |shortcut| is |true| if |cur_val| already contains
+an integer and only the units need to be considered.
+
+The order of infinity that was found in the case of infinite glue is returned
+in the global variable |cur_order|.
+
+@<Glob...@>=
+@!cur_order:glue_ord; {order of infinity found by |scan_dimen|}
+
+@ Constructions like `\.{-\'77 pt}' are legal dimensions, so |scan_dimen|
+may begin with |scan_int|. This explains why it is convenient to use
+|scan_int| also for the integer part of a decimal fraction.
+
+Several branches of |scan_dimen| work with |cur_val| as an integer and
+with an auxiliary fraction |f|, so that the actual quantity of interest is
+$|cur_val|+|f|/2^{16}$. At the end of the routine, this ``unpacked''
+representation is put into the single word |cur_val|, which suddenly
+switches significance from |integer| to |scaled|.
+
+@d attach_fraction=88 {go here to pack |cur_val| and |f| into |cur_val|}
+@d attach_sign=89 {go here when |cur_val| is correct except perhaps for sign}
+@d scan_normal_dimen==scan_dimen(false,false,false)
+
+@p procedure scan_dimen(@!mu,@!inf,@!shortcut:boolean);
+  {sets |cur_val| to a dimension}
+label done, done1, done2, found, not_found, attach_fraction, attach_sign;
+var negative:boolean; {should the answer be negated?}
+@!f:integer; {numerator of a fraction whose denominator is $2^{16}$}
+@<Local variables for dimension calculations@>@;
+begin f:=0; arith_error:=false; cur_order:=normal; negative:=false;
+if not shortcut then
+  begin @<Get the next non-blank non-sign...@>;
+  if (cur_cmd>=min_internal)and(cur_cmd<=max_internal) then
+    @<Fetch an internal dimension and |goto attach_sign|,
+      or fetch an internal integer@>
+  else  begin back_input;
+    if cur_tok=continental_point_token then cur_tok:=point_token;
+    if cur_tok<>point_token then scan_int
+    else  begin radix:=10; cur_val:=0;
+      end;
+    if cur_tok=continental_point_token then cur_tok:=point_token;
+    if (radix=10)and(cur_tok=point_token) then @<Scan decimal fraction@>;
+    end;
+  end;
+if cur_val<0 then {in this case |f=0|}
+  begin negative := not negative; negate(cur_val);
+  end;
+@<Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there
+  are |x| sp per unit; |goto attach_sign| if the units are internal@>;
+@<Scan an optional space@>;
+attach_sign: if arith_error or(abs(cur_val)>=@'10000000000) then
+  @<Report that this dimension is out of range@>;
+if negative then negate(cur_val);
+end;
+
+@ @<Fetch an internal dimension and |goto attach_sign|...@>=
+if mu then
+  begin scan_something_internal(mu_val,false);
+  @<Coerce glue to a dimension@>;
+  if cur_val_level=mu_val then goto attach_sign;
+  if cur_val_level<>int_val then mu_error;
+  end
+else  begin scan_something_internal(dimen_val,false);
+  if cur_val_level=dimen_val then goto attach_sign;
+  end
+
+@ @<Local variables for dimension calculations@>=
+@!num,@!denom:1..65536; {conversion ratio for the scanned units}
+@!k,@!kk:small_number; {number of digits in a decimal fraction}
+@!p,@!q:pointer; {top of decimal digit stack}
+@!v:scaled; {an internal dimension}
+@!save_cur_val:integer; {temporary storage of |cur_val|}
+
+@ The following code is executed when |scan_something_internal| was
+called asking for |mu_val|, when we really wanted a ``mudimen'' instead
+of ``muglue.''
+
+@<Coerce glue to a dimension@>=
+if cur_val_level>=glue_val then
+  begin v:=width(cur_val); delete_glue_ref(cur_val); cur_val:=v;
+  end
+
+@ When the following code is executed, we have |cur_tok=point_token|, but this
+token has been backed up using |back_input|; we must first discard it.
+
+It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
+Let's hope people don't use that fact.
+
+@<Scan decimal fraction@>=
+begin k:=0; p:=null; get_token; {|point_token| is being re-scanned}
+loop@+  begin get_x_token;
+  if (cur_tok>zero_token+9)or(cur_tok<zero_token) then goto done1;
+  if k<17 then {digits for |k>=17| cannot affect the result}
+    begin q:=get_avail; link(q):=p; info(q):=cur_tok-zero_token;
+    p:=q; incr(k);
+    end;
+  end;
+done1: for kk:=k downto 1 do
+  begin dig[kk-1]:=info(p); q:=p; p:=link(p); free_avail(q);
+  end;
+f:=round_decimals(k);
+if cur_cmd<>spacer then back_input;
+end
+
+@ Now comes the harder part: At this point in the program, |cur_val| is a
+nonnegative integer and $f/2^{16}$ is a nonnegative fraction less than 1;
+we want to multiply the sum of these two quantities by the appropriate
+factor, based on the specified units, in order to produce a |scaled|
+result, and we want to do the calculation with fixed point arithmetic that
+does not overflow.
+
+@<Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$...@>=
+if inf then @<Scan for \(f)\.{fil} units; |goto attach_fraction| if found@>;
+@<Scan for \(u)units that are internal dimensions;
+  |goto attach_sign| with |cur_val| set if found@>;
+if mu then @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>;
+if scan_keyword("true") then @<Adjust \(f)for the magnification ratio@>;
+@.true@>
+if scan_keyword("pt") then goto attach_fraction; {the easy case}
+@.pt@>
+@<Scan for \(a)all other units and adjust |cur_val| and |f| accordingly;
+  |goto done| in the case of scaled points@>;
+attach_fraction: if cur_val>=@'40000 then arith_error:=true
+else cur_val:=cur_val*unity+f;
+done:
+
+@ A specification like `\.{filllll}' or `\.{fill L L L}' will lead to two
+error messages (one for each additional keyword \.{"l"}).
+
+@<Scan for \(f)\.{fil} units...@>=
+if scan_keyword("fil") then
+@.fil@>
+  begin cur_order:=fil;
+  while scan_keyword("l") do
+    begin if cur_order=filll then
+      begin print_err("Illegal unit of measure (");
+@.Illegal unit of measure@>
+      print("replaced by filll)");
+      help1("I dddon't go any higher than filll."); error;
+      end
+    else incr(cur_order);
+    end;
+  goto attach_fraction;
+  end
+
+@ @<Scan for \(u)units that are internal dimensions...@>=
+save_cur_val:=cur_val;
+@<Get the next non-blank non-call...@>;
+if (cur_cmd<min_internal)or(cur_cmd>max_internal) then back_input
+else  begin if mu then
+    begin scan_something_internal(mu_val,false); @<Coerce glue...@>;
+    if cur_val_level<>mu_val then mu_error;
+    end
+  else scan_something_internal(dimen_val,false);
+  v:=cur_val; goto found;
+  end;
+if mu then goto not_found;
+if scan_keyword("em") then v:=(@<The em width for |cur_font|@>)
+@.em@>
+else if scan_keyword("ex") then v:=(@<The x-height for |cur_font|@>)
+@.ex@>
+else if scan_keyword("zw") then @<The KANJI width for |cur_jfont|@>
+@.ze@>
+else if scan_keyword("zh") then @<The KANJI height for |cur_jfont|@>
+@.zh@>
+else goto not_found;
+@<Scan an optional space@>;
+found:cur_val:=nx_plus_y(save_cur_val,v,xn_over_d(v,f,@'200000));
+goto attach_sign;
+not_found:
+
+@ @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>=
+if scan_keyword("mu") then goto attach_fraction
+@.mu@>
+else  begin print_err("Illegal unit of measure ("); print("mu inserted)");
+@.Illegal unit of measure@>
+  help4("The unit of measurement in math glue must be mu.")@/
+    ("To recover gracefully from this error, it's best to")@/
+    ("delete the erroneous units; e.g., type `2' to delete")@/
+    ("two letters. (See Chapter 27 of The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+  error; goto attach_fraction;
+  end
+
+@ @<Adjust \(f)for the magnification ratio@>=
+begin prepare_mag;
+if mag<>1000 then
+  begin cur_val:=xn_over_d(cur_val,1000,mag);
+  f:=(1000*f+@'200000*remainder) div mag;
+  cur_val:=cur_val+(f div @'200000); f:=f mod @'200000;
+  end;
+end
+
+@ The necessary conversion factors can all be specified exactly as
+fractions whose numerator and denominator sum to 32768 or less.
+According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$;
+this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard
+@^Bosshard, Hans Rudolf@>
+in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980).
+
+@d set_conversion_end(#)== denom:=#; end
+@d set_conversion(#)==@+begin num:=#; set_conversion_end
+
+@<Scan for \(a)all other units and adjust |cur_val| and |f|...@>=
+if scan_keyword("in") then set_conversion(7227)(100)
+@.in@>
+else if scan_keyword("pc") then set_conversion(12)(1)
+@.pc@>
+else if scan_keyword("cm") then set_conversion(7227)(254)
+@.cm@>
+else if scan_keyword("mm") then set_conversion(7227)(2540)
+@.mm@>
+else if scan_keyword("bp") then set_conversion(7227)(7200)
+@.bp@>
+else if scan_keyword("dd") then set_conversion(1238)(1157)
+@.dd@>
+else if scan_keyword("cc") then set_conversion(14856)(1157)
+@.cc@>
+else if scan_keyword("H") then set_conversion(7227)(10160)
+@.H@>
+else if scan_keyword("Q") then set_conversion(7227)(10160)
+@.Q@>
+else if scan_keyword("sp") then goto done
+@.sp@>
+else @<Complain about unknown unit and |goto done2|@>;
+cur_val:=xn_over_d(cur_val,num,denom);
+f:=(num*f+@'200000*remainder) div denom;@/
+cur_val:=cur_val+(f div @'200000); f:=f mod @'200000;
+done2:
+
+@ @<Complain about unknown unit...@>=
+begin print_err("Illegal unit of measure ("); print("pt inserted)");
+@.Illegal unit of measure@>
+help6("Dimensions can be in units of em, ex, in, pt, pc,")@/
+  ("cm, mm, dd, cc, bp, or sp; but yours is a new one!")@/
+  ("I'll assume that you meant to say pt, for printer's points.")@/
+  ("To recover gracefully from this error, it's best to")@/
+  ("delete the erroneous units; e.g., type `2' to delete")@/
+  ("two letters. (See Chapter 27 of The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+error; goto done2;
+end
+
+
+@ @<Report that this dimension is out of range@>=
+begin print_err("Dimension too large");
+@.Dimension too large@>
+help2("I can't work with sizes bigger than about 19 feet.")@/
+  ("Continue and I'll use the largest value I can.");@/
+error; cur_val:=max_dimen; arith_error:=false;
+end
+
+@ The final member of \TeX's value-scanning trio is |scan_glue|, which
+makes |cur_val| point to a glue specification. The reference count of that
+glue spec will take account of the fact that |cur_val| is pointing to~it.
+
+The |level| parameter should be either |glue_val| or |mu_val|.
+
+Since |scan_dimen| was so much more complex than |scan_int|, we might expect
+|scan_glue| to be even worse. But fortunately, it is very simple, since
+most of the work has already been done.
+
+@p procedure scan_glue(@!level:small_number);
+  {sets |cur_val| to a glue spec pointer}
+label exit;
+var negative:boolean; {should the answer be negated?}
+@!q:pointer; {new glue specification}
+@!mu:boolean; {does |level=mu_val|?}
+begin mu:=(level=mu_val); @<Get the next non-blank non-sign...@>;
+if (cur_cmd>=min_internal)and(cur_cmd<=max_internal) then
+  begin scan_something_internal(level,negative);
+  if cur_val_level>=glue_val then
+    begin if cur_val_level<>level then mu_error;
+    return;
+    end;
+  if cur_val_level=int_val then scan_dimen(mu,false,true)
+  else if level=mu_val then mu_error;
+  end
+else  begin back_input; scan_dimen(mu,false,false);
+  if negative then negate(cur_val);
+  end;
+@<Create a new glue specification whose width is |cur_val|; scan for its
+  stretch and shrink components@>;
+exit:end;
+
+@ @<Create a new glue specification whose width is |cur_val|...@>=
+q:=new_spec(zero_glue); width(q):=cur_val;
+if scan_keyword("plus") then
+@.plus@>
+  begin scan_dimen(mu,true,false);
+  stretch(q):=cur_val; stretch_order(q):=cur_order;
+  end;
+if scan_keyword("minus") then
+@.minus@>
+  begin scan_dimen(mu,true,false);
+  shrink(q):=cur_val; shrink_order(q):=cur_order;
+  end;
+cur_val:=q
+
+@ Here's a similar procedure that returns a pointer to a rule node. This
+routine is called just after \TeX\ has seen \.{\\hrule} or \.{\\vrule};
+therefore |cur_cmd| will be either |hrule| or |vrule|. The idea is to store
+the default rule dimensions in the node, then to override them if
+`\.{height}' or `\.{width}' or `\.{depth}' specifications are
+found (in any order).
+
+@d default_rule=26214 {0.4\thinspace pt}
+
+@p function scan_rule_spec:pointer;
+label reswitch;
+var q:pointer; {the rule node being created}
+begin q:=new_rule; {|width|, |depth|, and |height| all equal |null_flag| now}
+if cur_cmd=vrule then width(q):=default_rule
+else  begin height(q):=default_rule; depth(q):=0;
+  end;
+reswitch: if scan_keyword("width") then
+@.width@>
+  begin scan_normal_dimen; width(q):=cur_val; goto reswitch;
+  end;
+if scan_keyword("height") then
+@.height@>
+  begin scan_normal_dimen; height(q):=cur_val; goto reswitch;
+  end;
+if scan_keyword("depth") then
+@.depth@>
+  begin scan_normal_dimen; depth(q):=cur_val; goto reswitch;
+  end;
+scan_rule_spec:=q;
+end;
+
+@* \[27] Building token lists.
+The token lists for macros and for other things like \.{\\mark} and \.{\\output}
+and \.{\\write} are produced by a procedure called |scan_toks|.
+
+Before we get into the details of |scan_toks|, let's consider a much
+simpler task, that of converting the current string into a token list.
+The |str_toks| function does this; it classifies spaces as type |spacer|
+and everything else as type |other_char|.
+
+The token list created by |str_toks| begins at |link(temp_head)| and ends
+at the value |p| that is returned. (If |p=temp_head|, the list is empty.)
+
+@p function str_toks(@!b:pool_pointer):pointer;
+  {changes the string |str_pool[b..pool_ptr]| to a token list}
+var p:pointer; {tail of the token list}
+@!q:pointer; {new node being added to the token list via |store_new_token|}
+@!t:halfword; {token being appended}
+@!k:pool_pointer; {index into |str_pool|}
+begin str_room(1);
+p:=temp_head; link(p):=null; k:=b;
+while k<pool_ptr do
+  begin t:=so(str_pool[k]);
+  if multistrlen(ustringcast(str_pool), pool_ptr, k)=2 then
+    begin t:=fromBUFF(ustringcast(str_pool), pool_ptr, k); incr(k);
+    end
+  else if t=" " then t:=space_token
+  else t:=other_token+t;
+  fast_store_new_token(t);
+  incr(k);
+  end;
+pool_ptr:=b; str_toks:=p;
+end;
+
+@ The main reason for wanting |str_toks| is the next function,
+|the_toks|, which has similar input/output characteristics.
+
+This procedure is supposed to scan something like `\.{\\skip\\count12}',
+i.e., whatever can follow `\.{\\the}', and it constructs a token list
+containing something like `\.{-3.0pt minus 0.5fill}'.
+
+@p function the_toks:pointer;
+var old_setting:0..max_selector; {holds |selector| setting}
+@!p,@!q,@!r:pointer; {used for copying a token list}
+@!b:pool_pointer; {base of temporary string}
+begin get_x_token; scan_something_internal(tok_val,false);
+if cur_val_level>=ident_val then @<Copy the token list@>
+else begin old_setting:=selector; selector:=new_string; b:=pool_ptr;
+  case cur_val_level of
+  int_val:print_int(cur_val);
+  dimen_val:begin print_scaled(cur_val); print("pt");
+    end;
+  glue_val: begin print_spec(cur_val,"pt"); delete_glue_ref(cur_val);
+    end;
+  mu_val: begin print_spec(cur_val,"mu"); delete_glue_ref(cur_val);
+    end;
+  end; {there are no other cases}
+  selector:=old_setting; the_toks:=str_toks(b);
+  end;
+end;
+
+@ @<Copy the token list@>=
+begin p:=temp_head; link(p):=null;
+if cur_val_level=ident_val then store_new_token(cs_token_flag+cur_val)
+else if cur_val<>null then
+  begin r:=link(cur_val); {do not copy the reference count}
+  while r<>null do
+    begin fast_store_new_token(info(r)); r:=link(r);
+    end;
+  end;
+the_toks:=p;
+end
+
+@ Here's part of the |expand| subroutine that we are now ready to complete:
+
+@p procedure ins_the_toks;
+begin link(garbage):=the_toks; ins_list(link(temp_head));
+end;
+
+@ The primitives \.{\\number}, \.{\\romannumeral}, \.{\\string}, \.{\\meaning},
+\.{\\fontname}, and \.{\\jobname} are defined as follows.
+
+@d number_code=0 {command code for \.{\\number}}
+@d roman_numeral_code=1 {command code for \.{\\romannumeral}}
+@d kansuji_code=2 {command code for \.{\\kansuji}}
+@d string_code=3 {command code for \.{\\string}}
+@d meaning_code=4 {command code for \.{\\meaning}}
+@d font_name_code=5 {command code for \.{\\fontname}}
+@d euc_code=6 {command code for \.{\\euc}}
+@d sjis_code=7 {command code for \.{\\sjis}}
+@d jis_code=8 {command code for \.{\\jis}}
+@d kuten_code=9 {command code for \.{\\kuten}}
+@d ptex_convert_codes=10 {end of \eTeX's command codes}
+@d job_name_code=ptex_convert_codes {command code for \.{\\jobname}}
+
+@<Put each...@>=
+primitive("number",convert,number_code);@/
+@!@:number_}{\.{\\number} primitive@>
+primitive("romannumeral",convert,roman_numeral_code);@/
+@!@:roman_numeral_}{\.{\\romannumeral} primitive@>
+primitive("string",convert,string_code);@/
+@!@:string_}{\.{\\string} primitive@>
+primitive("meaning",convert,meaning_code);@/
+@!@:meaning_}{\.{\\meaning} primitive@>
+primitive("fontname",convert,font_name_code);@/
+@!@:font_name_}{\.{\\fontname} primitive@>
+primitive("kansuji",convert,kansuji_code);
+@!@:kansuji_}{\.{\\kansuji} primitive@>
+primitive("euc",convert,euc_code);
+@!@:euc_}{\.{\\euc} primitive@>
+primitive("sjis",convert,sjis_code);
+@!@:sjis_}{\.{\\sjis} primitive@>
+primitive("jis",convert,jis_code);
+@!@:jis_}{\.{\\jis} primitive@>
+primitive("kuten",convert,kuten_code);
+@!@:kuten_}{\.{\\kuten} primitive@>
+primitive("jobname",convert,job_name_code);@/
+@!@:job_name_}{\.{\\jobname} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+convert: case chr_code of
+  number_code: print_esc("number");
+  roman_numeral_code: print_esc("romannumeral");
+  string_code: print_esc("string");
+  meaning_code: print_esc("meaning");
+  font_name_code: print_esc("fontname");
+  kansuji_code: print_esc("kansuji");
+  euc_code:print_esc("euc");
+  sjis_code:print_esc("sjis");
+  jis_code:print_esc("jis");
+  kuten_code:print_esc("kuten");
+  othercases print_esc("jobname")
+  endcases;
+
+@ The procedure |conv_toks| uses |str_toks| to insert the token list
+for |convert| functions into the scanner; `\.{\\outer}' control sequences
+are allowed to follow `\.{\\string}' and `\.{\\meaning}'.
+
+@p procedure conv_toks;
+var old_setting:0..max_selector; {holds |selector| setting}
+@!cx:KANJI_code; {temporary register for KANJI}
+@!c:number_code..job_name_code; {desired type of conversion}
+@!save_scanner_status:small_number; {|scanner_status| upon entry}
+@!b:pool_pointer; {base of temporary string}
+begin c:=cur_chr; @<Scan the argument for command |c|@>;
+old_setting:=selector; selector:=new_string; b:=pool_ptr;
+@<Print the result of command |c|@>;
+selector:=old_setting; link(garbage):=str_toks(b); ins_list(link(temp_head));
+end;
+
+@ @<Scan the argument for command |c|@>=
+KANJI(cx):=0;
+case c of
+number_code,roman_numeral_code,
+kansuji_code,euc_code,sjis_code,jis_code,kuten_code: scan_int;
+string_code, meaning_code: begin save_scanner_status:=scanner_status;
+  scanner_status:=normal; get_token;
+  if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then {|wchar_token|}
+    KANJI(cx):=cur_tok;
+  scanner_status:=save_scanner_status;
+  end;
+font_name_code: scan_font_ident;
+job_name_code: if job_name=0 then open_log_file;
+end {there are no other cases}
+
+@ @<Print the result of command |c|@>=
+case c of
+number_code: print_int(cur_val);
+roman_numeral_code: print_roman_int(cur_val);
+jis_code:   print_int(fromJIS(cur_val));
+euc_code:   print_int(fromEUC(cur_val));
+sjis_code:  print_int(fromSJIS(cur_val));
+kuten_code: print_int(fromKUTEN(cur_val));
+kansuji_code: print_kansuji(cur_val);
+string_code:if cur_cs<>0 then sprint_cs(cur_cs)
+  else if KANJI(cx)=0 then print_char(cur_chr)
+  else print_kanji(cx);
+meaning_code: print_meaning;
+font_name_code: begin print(font_name[cur_val]);
+  if font_size[cur_val]<>font_dsize[cur_val] then
+    begin print(" at "); print_scaled(font_size[cur_val]);
+    print("pt");
+    end;
+  end;
+job_name_code: print(job_name);
+end {there are no other cases}
+
+@ Now we can't postpone the difficulties any longer; we must bravely tackle
+|scan_toks|. This function returns a pointer to the tail of a new token
+list, and it also makes |def_ref| point to the reference count at the
+head of that list.
+
+There are two boolean parameters, |macro_def| and |xpand|. If |macro_def|
+is true, the goal is to create the token list for a macro definition;
+otherwise the goal is to create the token list for some other \TeX\
+primitive: \.{\\mark}, \.{\\output}, \.{\\everypar}, \.{\\lowercase},
+\.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\write}, or
+\.{\\special}. In the latter cases a left brace must be scanned next; this
+left brace will not be part of the token list, nor will the matching right
+brace that comes at the end. If |xpand| is false, the token list will
+simply be copied from the input using |get_token|. Otherwise all expandable
+tokens will be expanded until unexpandable tokens are left, except that
+the results of expanding `\.{\\the}' are not expanded further.
+If both |macro_def| and |xpand| are true, the expansion applies
+only to the macro body (i.e., to the material following the first
+|left_brace| character).
+
+The value of |cur_cs| when |scan_toks| begins should be the |eqtb|
+address of the control sequence to display in ``runaway'' error
+messages.
+
+@p function scan_toks(@!macro_def,@!xpand:boolean):pointer;
+label found,done,done1,done2;
+var t:halfword; {token representing the highest parameter number}
+@!s:halfword; {saved token}
+@!p:pointer; {tail of the token list being built}
+@!q:pointer; {new node being added to the token list via |store_new_token|}
+@!unbalance:halfword; {number of unmatched left braces}
+@!hash_brace:halfword; {possible `\.{\#\{}' token}
+begin if macro_def then scanner_status:=defining
+@+else scanner_status:=absorbing;
+warning_index:=cur_cs; def_ref:=get_avail; token_ref_count(def_ref):=null;
+p:=def_ref; hash_brace:=0; t:=zero_token;
+if macro_def then @<Scan and build the parameter part of the macro definition@>
+else scan_left_brace; {remove the compulsory left brace}
+@<Scan and build the body of the token list; |goto found| when finished@>;
+found: scanner_status:=normal;
+if hash_brace<>0 then store_new_token(hash_brace);
+scan_toks:=p;
+end;
+
+@ @<Scan and build the parameter part...@>=
+begin loop begin get_token; {set |cur_cmd|, |cur_chr|, |cur_tok|}
+  if cur_tok<right_brace_limit then goto done1;
+  if cur_cmd=mac_param then
+    @<If the next character is a parameter number, make |cur_tok|
+      a |match| token; but if it is a left brace, store
+      `|left_brace|, |end_match|', set |hash_brace|, and |goto done|@>;
+  store_new_token(cur_tok);
+  end;
+done1: store_new_token(end_match_token);
+if cur_cmd=right_brace then
+  @<Express shock at the missing left brace; |goto found|@>;
+done: end
+
+@ @<Express shock...@>=
+begin print_err("Missing { inserted"); incr(align_state);
+@.Missing \{ inserted@>
+help2("Where was the left brace? You said something like `\def\a}',")@/
+  ("which I'm going to interpret as `\def\a{}'."); error; goto found;
+end
+
+@ @<If the next character is a parameter number...@>=
+begin s:=match_token+cur_chr; get_token;
+if cur_cmd=left_brace then
+  begin hash_brace:=cur_tok;
+  store_new_token(cur_tok); store_new_token(end_match_token);
+  goto done;
+  end;
+if t=zero_token+9 then
+  begin print_err("You already have nine parameters");
+@.You already have nine...@>
+  help1("I'm going to ignore the # sign you just used."); error;
+  end
+else  begin incr(t);
+  if cur_tok<>t then
+    begin print_err("Parameters must be numbered consecutively");
+@.Parameters...consecutively@>
+    help2("I've inserted the digit you should have used after the #.")@/
+      ("Type `1' to delete what you did use."); back_error;
+    end;
+  cur_tok:=s;
+  end;
+end
+
+@ @<Scan and build the body of the token list; |goto found| when finished@>=
+unbalance:=1;
+loop@+  begin if xpand then @<Expand the next part of the input@>
+  else get_token;
+  if cur_tok<right_brace_limit then
+    if cur_cmd<right_brace then incr(unbalance)
+    else  begin decr(unbalance);
+      if unbalance=0 then goto found;
+      end
+  else if cur_cmd=mac_param then
+    if macro_def then @<Look for parameter number or \.{\#\#}@>;
+  store_new_token(cur_tok);
+  end
+
+@ Here we insert an entire token list created by |the_toks| without
+expanding it further.
+
+@<Expand the next part of the input@>=
+begin loop begin get_next;
+  if cur_cmd<=max_command then goto done2;
+  if cur_cmd<>the then expand
+  else  begin q:=the_toks;
+    if link(temp_head)<>null then
+      begin link(p):=link(temp_head); p:=q;
+      end;
+    end;
+  end;
+done2: x_token
+end
+
+@ @<Look for parameter number...@>=
+begin s:=cur_tok;
+if xpand then get_x_token else get_token;
+if cur_cmd<>mac_param then
+  if (cur_tok<=zero_token)or(cur_tok>t) then
+    begin print_err("Illegal parameter number in definition of ");
+@.Illegal parameter number...@>
+    sprint_cs(warning_index);
+    help3("You meant to type ## instead of #, right?")@/
+    ("Or maybe a } was forgotten somewhere earlier, and things")@/
+    ("are all screwed up? I'm going to assume that you meant ##.");
+    back_error; cur_tok:=s;
+    end
+  else cur_tok:=out_param_token-"0"+cur_chr;
+end
+
+@ Another way to create a token list is via the \.{\\read} command. The
+sixteen files potentially usable for reading appear in the following
+global variables. The value of |read_open[n]| will be |closed| if
+stream number |n| has not been opened or if it has been fully read;
+|just_open| if an \.{\\openin} but not a \.{\\read} has been done;
+and |normal| if it is open and ready to read the next line.
+
+@d closed=2 {not open, or at end of file}
+@d just_open=1 {newly opened, first line not yet read}
+
+@<Glob...@>=
+@!read_file:array[0..15] of alpha_file; {used for \.{\\read}}
+@!read_open:array[0..16] of normal..closed; {state of |read_file[n]|}
+
+@ @<Set init...@>=
+for k:=0 to 16 do read_open[k]:=closed;
+
+@ The |read_toks| procedure constructs a token list like that for any
+macro definition, and makes |cur_val| point to it. Parameter |r| points
+to the control sequence that will receive this token list.
+
+@p procedure read_toks(@!n:integer;@!r:pointer);
+label done;
+var p:pointer; {tail of the token list}
+@!q:pointer; {new node being added to the token list via |store_new_token|}
+@!s:integer; {saved value of |align_state|}
+@!m:small_number; {stream number}
+begin scanner_status:=defining; warning_index:=r;
+def_ref:=get_avail; token_ref_count(def_ref):=null;
+p:=def_ref; {the reference count}
+store_new_token(end_match_token);
+if (n<0)or(n>15) then m:=16@+else m:=n;
+s:=align_state; align_state:=1000000; {disable tab marks, etc.}
+repeat @<Input and store tokens from the next line of the file@>;
+until align_state=1000000;
+cur_val:=def_ref; scanner_status:=normal; align_state:=s;
+end;
+
+@ @<Input and store tokens from the next line of the file@>=
+begin_file_reading; name:=m+1;
+if read_open[m]=closed then @<Input for \.{\\read} from the terminal@>
+else if read_open[m]=just_open then @<Input the first line of |read_file[m]|@>
+else @<Input the next line of |read_file[m]|@>;
+limit:=last;
+if end_line_char_inactive then decr(limit)
+else  buffer[limit]:=end_line_char;
+first:=limit+1; loc:=start; state:=new_line;@/
+loop@+  begin get_token;
+  if cur_tok=0 then goto done;
+    {|cur_cmd=cur_chr=0| will occur at the end of the line}
+  if align_state<1000000 then {unmatched `\.\}' aborts the line}
+    begin repeat get_token; until cur_tok=0;
+    align_state:=1000000; goto done;
+    end;
+  store_new_token(cur_tok);
+  end;
+done: end_file_reading
+
+@ Here we input on-line into the |buffer| array, prompting the user explicitly
+if |n>=0|.  The value of |n| is set negative so that additional prompts
+will not be given in the case of multi-line input.
+
+@<Input for \.{\\read} from the terminal@>=
+if interaction>nonstop_mode then
+  if n<0 then prompt_input("")
+  else  begin wake_up_terminal;
+    print_ln; sprint_cs(r); prompt_input("="); n:=-1;
+    end
+else fatal_error("*** (cannot \read from terminal in nonstop modes)")
+@.cannot \\read@>
+
+@ The first line of a file must be treated specially, since |input_ln|
+must be told not to start with |get|.
+@^system dependencies@>
+
+@<Input the first line of |read_file[m]|@>=
+if input_ln(read_file[m],false) then read_open[m]:=normal
+else  begin a_close(read_file[m]); read_open[m]:=closed;
+  end
+
+@ An empty line is appended at the end of a |read_file|.
+@^empty line at end of file@>
+
+@<Input the next line of |read_file[m]|@>=
+begin if not input_ln(read_file[m],true) then
+  begin a_close(read_file[m]); read_open[m]:=closed;
+  if align_state<>1000000 then
+    begin runaway;
+    print_err("File ended within "); print_esc("read");
+@.File ended within \\read@>
+    help1("This \read has unbalanced braces.");
+    align_state:=1000000; error;
+    end;
+  end;
+end
+
+@* \[28] Conditional processing.
+We consider now the way \TeX\ handles various kinds of \.{\\if} commands.
+
+@d if_char_code=0 { `\.{\\if}' }
+@d if_cat_code=1 { `\.{\\ifcat}' }
+@d if_int_code=2 { `\.{\\ifnum}' }
+@d if_dim_code=3 { `\.{\\ifdim}' }
+@d if_odd_code=4 { `\.{\\ifodd}' }
+@d if_vmode_code=5 { `\.{\\ifvmode}' }
+@d if_hmode_code=6 { `\.{\\ifhmode}' }
+@d if_mmode_code=7 { `\.{\\ifmmode}' }
+@d if_inner_code=8 { `\.{\\ifinner}' }
+@d if_void_code=9 { `\.{\\ifvoid}' }
+@d if_hbox_code=10 { `\.{\\ifhbox}' }
+@d if_vbox_code=11 { `\.{\\ifvbox}' }
+@d ifx_code=12 { `\.{\\ifx}' }
+@d if_eof_code=13 { `\.{\\ifeof}' }
+@d if_true_code=14 { `\.{\\iftrue}' }
+@d if_false_code=15 { `\.{\\iffalse}' }
+@d if_case_code=16 { `\.{\\ifcase}' }
+@#
+@d if_tdir_code=if_case_code+1 { `\.{\\iftdir}' }
+@d if_ydir_code=if_tdir_code+1 { `\.{\\ifydir}' }
+@d if_ddir_code=if_ydir_code+1 { `\.{\\ifddir}' }
+@d if_mdir_code=if_ddir_code+1 { `\.{\\ifmdir}' }
+@d if_tbox_code=if_mdir_code+1 { `\.{\\iftbox}' }
+@d if_ybox_code=if_tbox_code+1 { `\.{\\ifybox}' }
+@d if_dbox_code=if_ybox_code+1 { `\.{\\ifdbox}' }
+
+@<Put each...@>=
+primitive("if",if_test,if_char_code);
+@!@:if_char_}{\.{\\if} primitive@>
+primitive("ifcat",if_test,if_cat_code);
+@!@:if_cat_code_}{\.{\\ifcat} primitive@>
+primitive("ifnum",if_test,if_int_code);
+@!@:if_int_}{\.{\\ifnum} primitive@>
+primitive("ifdim",if_test,if_dim_code);
+@!@:if_dim_}{\.{\\ifdim} primitive@>
+primitive("ifodd",if_test,if_odd_code);
+@!@:if_odd_}{\.{\\ifodd} primitive@>
+primitive("ifvmode",if_test,if_vmode_code);
+@!@:if_vmode_}{\.{\\ifvmode} primitive@>
+primitive("ifhmode",if_test,if_hmode_code);
+@!@:if_hmode_}{\.{\\ifhmode} primitive@>
+primitive("ifmmode",if_test,if_mmode_code);
+@!@:if_mmode_}{\.{\\ifmmode} primitive@>
+primitive("ifinner",if_test,if_inner_code);
+@!@:if_inner_}{\.{\\ifinner} primitive@>
+primitive("ifvoid",if_test,if_void_code);
+@!@:if_void_}{\.{\\ifvoid} primitive@>
+primitive("ifhbox",if_test,if_hbox_code);
+@!@:if_hbox_}{\.{\\ifhbox} primitive@>
+primitive("ifvbox",if_test,if_vbox_code);
+@!@:if_vbox_}{\.{\\ifvbox} primitive@>
+primitive("ifx",if_test,ifx_code);
+@!@:ifx_}{\.{\\ifx} primitive@>
+primitive("ifeof",if_test,if_eof_code);
+@!@:if_eof_}{\.{\\ifeof} primitive@>
+primitive("iftrue",if_test,if_true_code);
+@!@:if_true_}{\.{\\iftrue} primitive@>
+primitive("iffalse",if_test,if_false_code);
+@!@:if_false_}{\.{\\iffalse} primitive@>
+primitive("ifcase",if_test,if_case_code);
+@!@:if_case_}{\.{\\ifcase} primitive@>
+primitive("iftdir",if_test,if_tdir_code);
+@!@:if_tdir_}{\.{\\iftdir} primitive@>
+primitive("ifydir",if_test,if_ydir_code);
+@!@:if_ydir_}{\.{\\ifydir} primitive@>
+primitive("ifddir",if_test,if_ddir_code);
+@!@:if_ddir_}{\.{\\ifddir} primitive@>
+primitive("ifmdir",if_test,if_mdir_code);
+@!@:if_mdir_}{\.{\\ifmdir} primitive@>
+primitive("iftbox",if_test,if_tbox_code);
+@!@:if_tbox_}{\.{\\iftbox} primitive@>
+primitive("ifybox",if_test,if_ybox_code);
+@!@:if_ybox_}{\.{\\ifybox} primitive@>
+primitive("ifdbox",if_test,if_dbox_code);
+@!@:if_dbox_}{\.{\\ifdbox} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+if_test: case chr_code of
+  if_cat_code:print_esc("ifcat");
+  if_int_code:print_esc("ifnum");
+  if_dim_code:print_esc("ifdim");
+  if_odd_code:print_esc("ifodd");
+  if_vmode_code:print_esc("ifvmode");
+  if_hmode_code:print_esc("ifhmode");
+  if_mmode_code:print_esc("ifmmode");
+  if_inner_code:print_esc("ifinner");
+  if_void_code:print_esc("ifvoid");
+  if_hbox_code:print_esc("ifhbox");
+  if_vbox_code:print_esc("ifvbox");
+  ifx_code:print_esc("ifx");
+  if_eof_code:print_esc("ifeof");
+  if_true_code:print_esc("iftrue");
+  if_false_code:print_esc("iffalse");
+  if_case_code:print_esc("ifcase");
+  if_tdir_code:print_esc("iftdir");
+  if_ydir_code:print_esc("ifydir");
+  if_ddir_code:print_esc("ifddir");
+  if_mdir_code:print_esc("ifmdir");
+  if_tbox_code:print_esc("iftbox");
+  if_ybox_code:print_esc("ifybox");
+  if_dbox_code:print_esc("ifdbox");
+  othercases print_esc("if")
+  endcases;
+
+@ Conditions can be inside conditions, and this nesting has a stack
+that is independent of the |save_stack|.
+
+Four global variables represent the top of the condition stack:
+|cond_ptr| points to pushed-down entries, if any; |if_limit| specifies
+the largest code of a |fi_or_else| command that is syntactically legal;
+|cur_if| is the name of the current type of conditional; and |if_line|
+is the line number at which it began.
+
+If no conditions are currently in progress, the condition stack has the
+special state |cond_ptr=null|, |if_limit=normal|, |cur_if=0|, |if_line=0|.
+Otherwise |cond_ptr| points to a two-word node; the |type|, |subtype|, and
+|link| fields of the first word contain |if_limit|, |cur_if|, and
+|cond_ptr| at the next level, and the second word contains the
+corresponding |if_line|.
+
+@d if_node_size=2 {number of words in stack entry for conditionals}
+@d if_line_field(#)==mem[#+1].int
+@d if_code=1 {code for \.{\\if...} being evaluated}
+@d fi_code=2 {code for \.{\\fi}}
+@d else_code=3 {code for \.{\\else}}
+@d or_code=4 {code for \.{\\or}}
+
+@<Glob...@>=
+@!cond_ptr:pointer; {top of the condition stack}
+@!if_limit:normal..or_code; {upper bound on |fi_or_else| codes}
+@!cur_if:small_number; {type of conditional being worked on}
+@!if_line:integer; {line where that conditional began}
+
+@ @<Set init...@>=
+cond_ptr:=null; if_limit:=normal; cur_if:=0; if_line:=0;
+
+@ @<Put each...@>=
+primitive("fi",fi_or_else,fi_code);
+@!@:fi_}{\.{\\fi} primitive@>
+text(frozen_fi):="fi"; eqtb[frozen_fi]:=eqtb[cur_val];
+primitive("or",fi_or_else,or_code);
+@!@:or_}{\.{\\or} primitive@>
+primitive("else",fi_or_else,else_code);
+@!@:else_}{\.{\\else} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+fi_or_else: if chr_code=fi_code then print_esc("fi")
+  else if chr_code=or_code then print_esc("or")
+  else print_esc("else");
+
+@ When we skip conditional text, we keep track of the line number
+where skipping began, for use in error messages.
+
+@<Glob...@>=
+@!skip_line:integer; {skipping began here}
+
+@ Here is a procedure that ignores text until coming to an \.{\\or},
+\.{\\else}, or \.{\\fi} at level zero of $\.{\\if}\ldots\.{\\fi}$
+nesting. After it has acted, |cur_chr| will indicate the token that
+was found, but |cur_tok| will not be set (because this makes the
+procedure run faster).
+
+@p procedure pass_text;
+label done;
+var l:integer; {level of $\.{\\if}\ldots\.{\\fi}$ nesting}
+@!save_scanner_status:small_number; {|scanner_status| upon entry}
+begin save_scanner_status:=scanner_status; scanner_status:=skipping; l:=0;
+skip_line:=line;
+loop@+  begin get_next;
+  if cur_cmd=fi_or_else then
+    begin if l=0 then goto done;
+    if cur_chr=fi_code then decr(l);
+    end
+  else if cur_cmd=if_test then incr(l);
+  end;
+done: scanner_status:=save_scanner_status;
+end;
+
+@ When we begin to process a new \.{\\if}, we set |if_limit:=if_code|; then
+if\/ \.{\\or} or \.{\\else} or \.{\\fi} occurs before the current \.{\\if}
+condition has been evaluated, \.{\\relax} will be inserted.
+For example, a sequence of commands like `\.{\\ifvoid1\\else...\\fi}'
+would otherwise require something after the `\.1'.
+
+@<Push the condition stack@>=
+begin p:=get_node(if_node_size); link(p):=cond_ptr; type(p):=if_limit;
+subtype(p):=cur_if; if_line_field(p):=if_line;
+cond_ptr:=p; cur_if:=cur_chr; if_limit:=if_code; if_line:=line;
+end
+
+@ @<Pop the condition stack@>=
+begin p:=cond_ptr; if_line:=if_line_field(p);
+cur_if:=subtype(p); if_limit:=type(p); cond_ptr:=link(p);
+free_node(p,if_node_size);
+end
+
+@ Here's a procedure that changes the |if_limit| code corresponding to
+a given value of |cond_ptr|.
+
+@p procedure change_if_limit(@!l:small_number;@!p:pointer);
+label exit;
+var q:pointer;
+begin if p=cond_ptr then if_limit:=l {that's the easy case}
+else  begin q:=cond_ptr;
+  loop@+  begin if q=null then confusion("if");
+@:this can't happen if}{\quad if@>
+    if link(q)=p then
+      begin type(q):=l; return;
+      end;
+    q:=link(q);
+    end;
+  end;
+exit:end;
+
+@ A condition is started when the |expand| procedure encounters
+an |if_test| command; in that case |expand| reduces to |conditional|,
+which is a recursive procedure.
+@^recursion@>
+
+@p procedure conditional;
+label exit,common_ending;
+var b:boolean; {is the condition true?}
+@!r:"<"..">"; {relation to be evaluated}
+@!m,@!n:integer; {to be tested against the second operand}
+@!p,@!q:pointer; {for traversing token lists in \.{\\ifx} tests}
+@!save_scanner_status:small_number; {|scanner_status| upon entry}
+@!save_cond_ptr:pointer; {|cond_ptr| corresponding to this conditional}
+@!this_if:small_number; {type of this conditional}
+begin @<Push the condition stack@>;@+save_cond_ptr:=cond_ptr;this_if:=cur_chr;@/
+@<Either process \.{\\ifcase} or set |b| to the value of a boolean condition@>;
+if tracing_commands>1 then @<Display the value of |b|@>;
+if b then
+  begin change_if_limit(else_code,save_cond_ptr);
+  return; {wait for \.{\\else} or \.{\\fi}}
+  end;
+@<Skip to \.{\\else} or \.{\\fi}, then |goto common_ending|@>;
+common_ending: if cur_chr=fi_code then @<Pop the condition stack@>
+else if_limit:=fi_code; {wait for \.{\\fi}}
+exit:end;
+
+@ In a construction like `\.{\\if\\iftrue abc\\else d\\fi}', the first
+\.{\\else} that we come to after learning that the \.{\\if} is false is
+not the \.{\\else} we're looking for. Hence the following curious
+logic is needed.
+
+@ @<Skip to \.{\\else} or \.{\\fi}...@>=
+loop@+  begin pass_text;
+  if cond_ptr=save_cond_ptr then
+    begin if cur_chr<>or_code then goto common_ending;
+    print_err("Extra "); print_esc("or");
+@.Extra \\or@>
+    help1("I'm ignoring this; it doesn't match any \if.");
+    error;
+    end
+  else if cur_chr=fi_code then @<Pop the condition stack@>;
+  end
+
+@ @<Either process \.{\\ifcase} or set |b|...@>=
+case this_if of
+if_char_code, if_cat_code: @<Test if two characters match@>;
+if_int_code, if_dim_code: @<Test relation between integers or dimensions@>;
+if_odd_code: @<Test if an integer is odd@>;
+if_vmode_code: b:=(abs(mode)=vmode);
+if_hmode_code: b:=(abs(mode)=hmode);
+if_mmode_code: b:=(abs(mode)=mmode);
+if_inner_code: b:=(mode<0);
+if_tdir_code: b:=(abs(direction)=dir_tate);
+if_ydir_code: b:=(abs(direction)=dir_yoko);
+if_ddir_code: b:=(abs(direction)=dir_dtou);
+if_mdir_code: b:=(direction<0);
+if_void_code, if_hbox_code, if_vbox_code, if_tbox_code, if_ybox_code, if_dbox_code:
+  @<Test box register status@>;
+ifx_code: @<Test if two tokens match@>;
+if_eof_code: begin scan_four_bit_int_or_18;
+  if cur_val=18 then b:=not shellenabledp
+  else b:=(read_open[cur_val]=closed);
+  end;
+if_true_code: b:=true;
+if_false_code: b:=false;
+if_case_code: @<Select the appropriate case
+  and |return| or |goto common_ending|@>;
+end {there are no other cases}
+
+@ @<Display the value of |b|@>=
+begin begin_diagnostic;
+if b then print("{true}")@+else print("{false}");
+end_diagnostic(false);
+end
+
+@ Here we use the fact that |"<"|, |"="|, and |">"| are consecutive ASCII
+codes.
+@^ASCII code@>
+
+@<Test relation between integers or dimensions@>=
+begin if this_if=if_int_code then scan_int@+else scan_normal_dimen;
+n:=cur_val; @<Get the next non-blank non-call...@>;
+if (cur_tok>=other_token+"<")and(cur_tok<=other_token+">") then
+  r:=cur_tok-other_token
+else  begin print_err("Missing = inserted for ");
+@.Missing = inserted@>
+  print_cmd_chr(if_test,this_if);
+  help1("I was expecting to see `<', `=', or `>'. Didn't.");
+  back_error; r:="=";
+  end;
+if this_if=if_int_code then scan_int@+else scan_normal_dimen;
+case r of
+"<": b:=(n<cur_val);
+"=": b:=(n=cur_val);
+">": b:=(n>cur_val);
+end;
+end
+
+@ @<Test if an integer is odd@>=
+begin scan_int; b:=odd(cur_val);
+end
+
+@ @<Test box register status@>=
+begin scan_eight_bit_int; p:=box(cur_val);
+if this_if=if_void_code then b:=(p=null)
+else if p=null then b:=false
+else begin
+  if type(p)=dir_node then p:=list_ptr(p);
+  if this_if=if_hbox_code then b:=(type(p)=hlist_node)
+  else if this_if=if_vbox_code then b:=(type(p)=vlist_node)
+  else if this_if=if_tbox_code then b:=(box_dir(p)=dir_tate)
+  else if this_if=if_ybox_code then b:=(box_dir(p)=dir_yoko)
+  else b:=(box_dir(p)=dir_dtou);
+  end
+end
+
+@ An active character will be treated as category 13 following
+\.{\\if\\noexpand} or following \.{\\ifcat\\noexpand}. We use the fact that
+active characters have the smallest tokens, among all control sequences.
+
+@d get_x_token_or_active_char==@t@>@;
+  begin get_x_token;
+  if cur_cmd=relax then if cur_chr=no_expand_flag then
+    begin cur_cmd:=active_char;
+    cur_chr:=cur_tok-cs_token_flag-active_base;
+    end;
+  end
+
+@<Test if two characters match@>=
+begin get_x_token_or_active_char;
+if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then
+  begin m:=cur_cmd; n:=cur_chr;
+  end
+else if (cur_cmd>active_char)or(cur_chr>255) then
+  begin m:=relax; n:=256;
+  end
+else  begin m:=cur_cmd; n:=cur_chr;
+  end;
+get_x_token_or_active_char;
+if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then
+  begin cur_cmd:=cur_cmd;
+  end {dummy}
+else if (cur_cmd>active_char)or(cur_chr>255) then
+  begin cur_cmd:=relax; cur_chr:=256;
+  end;
+if this_if=if_char_code then b:=(n=cur_chr)@+else b:=(m=cur_cmd);
+end
+
+@ Note that `\.{\\ifx}' will declare two macros different if one is \\{long}
+or \\{outer} and the other isn't, even though the texts of the macros are
+the same.
+
+We need to reset |scanner_status|, since \.{\\outer} control sequences
+are allowed, but we might be scanning a macro definition or preamble.
+
+@<Test if two tokens match@>=
+begin save_scanner_status:=scanner_status; scanner_status:=normal;
+get_next; n:=cur_cs; p:=cur_cmd; q:=cur_chr;
+get_next; if cur_cmd<>p then b:=false
+else if cur_cmd<call then b:=(cur_chr=q)
+else @<Test if two macro texts match@>;
+scanner_status:=save_scanner_status;
+end
+
+@ Note also that `\.{\\ifx}' decides that macros \.{\\a} and \.{\\b} are
+different in examples like this:
+$$\vbox{\halign{\.{#}\hfil&\qquad\.{#}\hfil\cr
+  {}\\def\\a\{\\c\}&
+  {}\\def\\c\{\}\cr
+  {}\\def\\b\{\\d\}&
+  {}\\def\\d\{\}\cr}}$$
+
+@<Test if two macro texts match@>=
+begin p:=link(cur_chr); q:=link(equiv(n)); {omit reference counts}
+if p=q then b:=true
+else begin while (p<>null)and(q<>null) do
+    if info(p)<>info(q) then p:=null
+    else  begin p:=link(p); q:=link(q);
+      end;
+  b:=((p=null)and(q=null));
+  end;
+end
+
+@ @<Select the appropriate case and |return| or |goto common_ending|@>=
+begin scan_int; n:=cur_val; {|n| is the number of cases to pass}
+if tracing_commands>1 then
+  begin begin_diagnostic; print("{case "); print_int(n); print_char("}");
+  end_diagnostic(false);
+  end;
+while n<>0 do
+  begin pass_text;
+  if cond_ptr=save_cond_ptr then
+    if cur_chr=or_code then decr(n)
+    else goto common_ending
+  else if cur_chr=fi_code then @<Pop the condition stack@>;
+  end;
+change_if_limit(or_code,save_cond_ptr);
+return; {wait for \.{\\or}, \.{\\else}, or \.{\\fi}}
+end
+
+@ The processing of conditionals is complete except for the following
+code, which is actually part of |expand|. It comes into play when
+\.{\\or}, \.{\\else}, or \.{\\fi} is scanned.
+
+@<Terminate the current conditional and skip to \.{\\fi}@>=
+if cur_chr>if_limit then
+  if if_limit=if_code then insert_relax {condition not yet evaluated}
+  else  begin print_err("Extra "); print_cmd_chr(fi_or_else,cur_chr);
+@.Extra \\or@>
+@.Extra \\else@>
+@.Extra \\fi@>
+    help1("I'm ignoring this; it doesn't match any \if.");
+    error;
+    end
+else  begin while cur_chr<>fi_code do pass_text; {skip to \.{\\fi}}
+  @<Pop the condition stack@>;
+  end
+
+@* \[29] File names.
+It's time now to fret about file names.  Besides the fact that different
+operating systems treat files in different ways, we must cope with the
+fact that completely different naming conventions are used by different
+groups of people. The following programs show what is required for one
+particular operating system; similar routines for other systems are not
+difficult to devise.
+@^fingers@>
+@^system dependencies@>
+
+\TeX\ assumes that a file name has three parts: the name proper; its
+``extension''; and a ``file area'' where it is found in an external file
+system.  The extension of an input file or a write file is assumed to be
+`\.{.tex}' unless otherwise specified; it is `\.{.log}' on the
+transcript file that records each run of \TeX; it is `\.{.tfm}' on the font
+metric files that describe characters in the fonts \TeX\ uses; it is
+`\.{.dvi}' on the output files that specify typesetting information; and it
+is `\.{.fmt}' on the format files written by \.{INITEX} to initialize \TeX.
+The file area can be arbitrary on input files, but files are usually
+output to the user's current area.  If an input file cannot be
+found on the specified area, \TeX\ will look for it on a special system
+area; this special area is intended for commonly used input files like
+\.{webmac.tex}.
+
+Simple uses of \TeX\ refer only to file names that have no explicit
+extension or area. For example, a person usually says `\.{\\input} \.{paper}'
+or `\.{\\font\\tenrm} \.= \.{helvetica}' instead of `\.{\\input}
+\.{paper.new}' or `\.{\\font\\tenrm} \.= \.{<csd.knuth>test}'. Simple file
+names are best, because they make the \TeX\ source files portable;
+whenever a file name consists entirely of letters and digits, it should be
+treated in the same way by all implementations of \TeX. However, users
+need the ability to refer to other files in their environment, especially
+when responding to error messages concerning unopenable files; therefore
+we want to let them use the syntax that appears in their favorite
+operating system.
+
+The following procedures don't allow spaces to be part of
+file names; but some users seem to like names that are spaced-out.
+System-dependent changes to allow such things should probably
+be made with reluctance, and only when an entire file name that
+includes spaces is ``quoted'' somehow.
+
+@ In order to isolate the system-dependent aspects of file names, the
+@^system dependencies@>
+system-independent parts of \TeX\ are expressed in terms
+of three system-dependent
+procedures called |begin_name|, |more_name|, and |end_name|. In
+essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
+the system-independent driver program does the operations
+$$|begin_name|;\,|more_name|(c_1);\,\ldots\,;\,|more_name|(c_n);
+\,|end_name|.$$
+These three procedures communicate with each other via global variables.
+Afterwards the file name will appear in the string pool as three strings
+called |cur_name|\penalty10000\hskip-.05em,
+|cur_area|, and |cur_ext|; the latter two are null (i.e.,
+|""|), unless they were explicitly specified by the user.
+
+Actually the situation is slightly more complicated, because \TeX\ needs
+to know when the file name ends. The |more_name| routine is a function
+(with side effects) that returns |true| on the calls |more_name|$(c_1)$,
+\dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$
+returns |false|; or, it returns |true| and the token following $c_n$ is
+something like `\.{\\hbox}' (i.e., not a character). In other words,
+|more_name| is supposed to return |true| unless it is sure that the
+file name has been completely scanned; and |end_name| is supposed to be able
+to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of
+whether $|more_name|(c_n)$ returned |true| or |false|.
+
+@<Glob...@>=
+@!cur_name:str_number; {name of file just scanned}
+@!cur_area:str_number; {file area just scanned, or \.{""}}
+@!cur_ext:str_number; {file extension just scanned, or \.{""}}
+
+@ The file names we shall deal with have the
+following structure:  If the name contains `\./' or `\.:'
+(for Amiga only), the file area
+consists of all characters up to and including the final such character;
+otherwise the file area is null.  If the remaining file name contains
+`\..', the file extension consists of all such characters from the last
+`\..' to the end, otherwise the file extension is null.
+@^system dependencies@>
+
+We can scan such file names easily by using two global variables that keep track
+of the occurrences of area and extension delimiters:
+
+@<Glob...@>=
+@!area_delimiter:pool_pointer; {the most recent `\./', if any}
+@!ext_delimiter:pool_pointer; {the most recent `\..', if any}
+
+@ Input files that can't be found in the user's area may appear in a standard
+system area called |TEX_area|. Font metric files whose areas are not given
+explicitly are assumed to appear in a standard system area called
+|TEX_font_area|.  These system area names will, of course, vary from place
+to place.
+@^system dependencies@>
+
+In C, the default paths are specified separately.
+
+@ Here now is the first of the system-dependent routines for file name scanning.
+@^system dependencies@>
+
+@p procedure begin_name;
+begin area_delimiter:=0; ext_delimiter:=0; quoted_filename:=false; prev_char:=0;
+end;
+
+@ And here's the second. The string pool might change as the file name is
+being scanned, since a new \.{\\csname} might be entered; therefore we keep
+|area_delimiter| and |ext_delimiter| relative to the beginning of the current
+string, instead of assigning an absolute address like |pool_ptr| to them.
+@^system dependencies@>
+
+@p function more_name(@!c:ASCII_code):boolean;
+begin if (c=" ") and stop_at_space and (not quoted_filename) then
+  more_name:=false
+else  if c="""" then begin
+  quoted_filename:=not quoted_filename;
+  more_name:=true;
+  end
+else  begin str_room(1); append_char(c); {contribute |c| to the current string}
+  if (IS_DIR_SEP(c)and(not_kanji_char_seq(prev_char,c))) then
+    begin area_delimiter:=cur_length; ext_delimiter:=0;
+    end
+  else if c="." then ext_delimiter:=cur_length;
+  more_name:=true;
+  end;
+  prev_char:=c;
+end;
+
+@ The third.
+@^system dependencies@>
+If a string is already in the string pool, the function
+|slow_make_string| does not create a new string but returns this string
+number, thus saving string space.  Because of this new property of the
+returned string number it is not possible to apply |flush_string| to
+these strings.
+
+@p procedure end_name;
+var temp_str: str_number; {result of file name cache lookups}
+@!j,@!s,@!t: pool_pointer; {running indices}
+@!must_quote:boolean; {whether we need to quote a string}
+begin if str_ptr+3>max_strings then
+  overflow("number of strings",max_strings-init_str_ptr);
+@:TeX capacity exceeded number of strings}{\quad number of strings@>
+str_room(6); {Room for quotes, if needed.}
+{add quotes if needed}
+if area_delimiter<>0 then begin
+  {maybe quote |cur_area|}
+  must_quote:=false;
+  s:=str_start[str_ptr];
+  t:=str_start[str_ptr]+area_delimiter;
+  j:=s;
+  while (not must_quote) and (j<t) do begin
+    must_quote:=str_pool[j]=" "; incr(j);
+    end;
+  if must_quote then begin
+    for j:=pool_ptr-1 downto t do str_pool[j+2]:=str_pool[j];
+    str_pool[t+1]:="""";
+    for j:=t-1 downto s do str_pool[j+1]:=str_pool[j];
+    str_pool[s]:="""";
+    if ext_delimiter<>0 then ext_delimiter:=ext_delimiter+2;
+    area_delimiter:=area_delimiter+2;
+    pool_ptr:=pool_ptr+2;
+    end;
+  end;
+{maybe quote |cur_name|}
+s:=str_start[str_ptr]+area_delimiter;
+if ext_delimiter=0 then t:=pool_ptr else t:=str_start[str_ptr]+ext_delimiter-1;
+must_quote:=false;
+j:=s;
+while (not must_quote) and (j<t) do begin
+  must_quote:=str_pool[j]=" "; incr(j);
+  end;
+if must_quote then begin
+  for j:=pool_ptr-1 downto t do str_pool[j+2]:=str_pool[j];
+  str_pool[t+1]:="""";
+  for j:=t-1 downto s do str_pool[j+1]:=str_pool[j];
+  str_pool[s]:="""";
+  if ext_delimiter<>0 then ext_delimiter:=ext_delimiter+2;
+  pool_ptr:=pool_ptr+2;
+  end;
+if ext_delimiter<>0 then begin
+  {maybe quote |cur_ext|}
+  s:=str_start[str_ptr]+ext_delimiter-1;
+  t:=pool_ptr;
+  must_quote:=false;
+  j:=s;
+  while (not must_quote) and (j<t) do begin
+    must_quote:=str_pool[j]=" "; incr(j);
+    end;
+  if must_quote then begin
+    str_pool[t+1]:="""";
+    for j:=t-1 downto s do str_pool[j+1]:=str_pool[j];
+    str_pool[s]:="""";
+    pool_ptr:=pool_ptr+2;
+    end;
+  end;
+if area_delimiter=0 then cur_area:=""
+else  begin cur_area:=str_ptr;
+  str_start[str_ptr+1]:=str_start[str_ptr]+area_delimiter; incr(str_ptr);
+  temp_str:=search_string(cur_area);
+  if temp_str>0 then
+    begin cur_area:=temp_str;
+    decr(str_ptr);  {no |flush_string|, |pool_ptr| will be wrong!}
+    for j:=str_start[str_ptr+1] to pool_ptr-1 do
+      begin str_pool[j-area_delimiter]:=str_pool[j];
+      end;
+    pool_ptr:=pool_ptr-area_delimiter; {update |pool_ptr|}
+    end;
+  end;
+if ext_delimiter=0 then
+  begin cur_ext:=""; cur_name:=slow_make_string;
+  end
+else  begin cur_name:=str_ptr;
+  str_start[str_ptr+1]:=str_start[str_ptr]+ext_delimiter-area_delimiter-1;
+  incr(str_ptr); cur_ext:=make_string;
+  decr(str_ptr); {undo extension string to look at name part}
+  temp_str:=search_string(cur_name);
+  if temp_str>0 then
+    begin cur_name:=temp_str;
+    decr(str_ptr);  {no |flush_string|, |pool_ptr| will be wrong!}
+    for j:=str_start[str_ptr+1] to pool_ptr-1 do
+      begin str_pool[j-ext_delimiter+area_delimiter+1]:=str_pool[j];
+      end;
+    pool_ptr:=pool_ptr-ext_delimiter+area_delimiter+1;  {update |pool_ptr|}
+    end;
+  cur_ext:=slow_make_string;  {remake extension string}
+  end;
+end;
+
+@ Conversely, here is a routine that takes three strings and prints a file
+name that might have produced them. (The routine is system dependent, because
+some operating systems put the file area last instead of first.)
+@^system dependencies@>
+
+@d check_quoted(#) == {check if string |#| needs quoting}
+if #<>0 then begin
+  j:=str_start[#];
+  while (not must_quote) and (j<str_start[#+1]) do begin
+    must_quote:=str_pool[j]=" "; incr(j);
+  end;
+end
+@#
+@d print_quoted(#) == {print string |#|, omitting quotes}
+if #<>0 then
+  for j:=str_start[#] to str_start[#+1]-1 do
+    if so(str_pool[j])<>"""" then
+      print(so(str_pool[j]))
+
+@<Basic printing...@>=
+procedure print_file_name(@!n,@!a,@!e:integer);
+var must_quote: boolean; {whether to quote the filename}
+@!j:pool_pointer; {index into |str_pool|}
+begin
+must_quote:=false;
+check_quoted(a); check_quoted(n); check_quoted(e);
+{FIXME: Alternative is to assume that any filename that has to be quoted has
+ at least one quoted component...if we pick this, a number of insertions
+ of |print_file_name| should go away.
+|must_quote|:=((|a|<>0)and(|str_pool|[|str_start|[|a|]]=""""))or
+              ((|n|<>0)and(|str_pool|[|str_start|[|n|]]=""""))or
+              ((|e|<>0)and(|str_pool|[|str_start|[|e|]]=""""));}
+if must_quote then print_char("""");
+print_quoted(a); print_quoted(n); print_quoted(e);
+if must_quote then print_char("""");
+end;
+
+@ Another system-dependent routine is needed to convert three internal
+\TeX\ strings
+into the |name_of_file| value that is used to open files. The present code
+allows both lowercase and uppercase letters in the file name.
+@^system dependencies@>
+
+@d append_to_name(#)==begin c:=#; if not (c="""") then begin incr(k);
+  if k<=file_name_size then name_of_file[k]:=xchr[c];
+  end end
+
+@p procedure pack_file_name(@!n,@!a,@!e:str_number);
+var k:integer; {number of positions filled in |name_of_file|}
+@!c: ASCII_code; {character being packed}
+@!j:pool_pointer; {index into |str_pool|}
+begin k:=0;
+if name_of_file then libc_free (name_of_file);
+name_of_file:= xmalloc_array (ASCII_code, length(a)+length(n)+length(e)+1);
+for j:=str_start[a] to str_start[a+1]-1 do append_to_name(so(str_pool[j]));
+for j:=str_start[n] to str_start[n+1]-1 do append_to_name(so(str_pool[j]));
+for j:=str_start[e] to str_start[e+1]-1 do append_to_name(so(str_pool[j]));
+if k<=file_name_size then name_length:=k@+else name_length:=file_name_size;
+name_of_file[name_length+1]:=0;
+end;
+
+@ A messier routine is also needed, since format file names must be scanned
+before \TeX's string mechanism has been initialized. We shall use the
+global variable |TEX_format_default| to supply the text for default system areas
+and extensions related to format files.
+@^system dependencies@>
+
+Under {\mc UNIX} we don't give the area part, instead depending
+on the path searching that will happen during file opening.  Also, the
+length will be set in the main program.
+
+@d format_area_length=0 {length of its area part}
+@d format_ext_length=4 {length of its `\.{.fmt}' part}
+@d format_extension=".fmt" {the extension, as a \.{WEB} constant}
+
+@<Glob...@>=
+@!format_default_length: integer;
+@!TEX_format_default: cstring;
+
+@ We set the name of the default format file and the length of that name
+in C, instead of Pascal, since we want them to depend on the name of the
+program.
+@.TeXformats@>
+@.plain@>
+@^system dependencies@>
+
+@ @<Check the ``constant'' values for consistency@>=
+if format_default_length>file_name_size then bad:=31;
+
+@ Here is the messy routine that was just mentioned. It sets |name_of_file|
+from the first |n| characters of |TEX_format_default|, followed by
+|buffer[a..b]|, followed by the last |format_ext_length| characters of
+|TEX_format_default|.
+
+We dare not give error messages here, since \TeX\ calls this routine before
+the |error| routine is ready to roll. Instead, we simply drop excess characters,
+since the error will be detected in another way when a strange file name
+isn't found.
+@^system dependencies@>
+
+@p procedure pack_buffered_name(@!n:small_number;@!a,@!b:integer);
+var k:integer; {number of positions filled in |name_of_file|}
+@!c: ASCII_code; {character being packed}
+@!j:integer; {index into |buffer| or |TEX_format_default|}
+begin if n+b-a+1+format_ext_length>file_name_size then
+  b:=a+file_name_size-n-1-format_ext_length;
+k:=0;
+if name_of_file then libc_free (name_of_file);
+name_of_file := xmalloc_array (ASCII_code, n+(b-a+1)+format_ext_length+1);
+for j:=1 to n do append_to_name(xord[ucharcast(TEX_format_default[j])]);
+for j:=a to b do append_to_name(buffer[j]);
+for j:=format_default_length-format_ext_length+1 to format_default_length do
+  append_to_name(xord[ucharcast(TEX_format_default[j])]);
+if k<=file_name_size then name_length:=k@+else name_length:=file_name_size;
+name_of_file[name_length+1]:=0;
+end;
+
+@ Here is the only place we use |pack_buffered_name|. This part of the program
+becomes active when a ``virgin'' \TeX\ is trying to get going, just after
+the preliminary initialization, or when the user is substituting another
+format file by typing `\.\&' after the initial `\.{**}' prompt.  The buffer
+contains the first line of input in |buffer[loc..(last-1)]|, where
+|loc<last| and |buffer[loc]<>" "|.
+
+@<Declare the function called |open_fmt_file|@>=
+function open_fmt_file:boolean;
+label found,exit;
+var j:0..buf_size; {the first space after the format file name}
+begin j:=loc;
+if buffer[loc]="&" then
+  begin incr(loc); j:=loc; buffer[last]:=" ";
+  while buffer[j]<>" " do incr(j);
+  pack_buffered_name(0,loc,j-1); {Kpathsea does everything}
+  if w_open_in(fmt_file) then goto found;
+  wake_up_terminal;
+  wterm ('Sorry, I can''t find the format `');
+  fputs (stringcast(name_of_file + 1), stdout);
+  wterm ('''; will try `');
+  fputs (TEX_format_default + 1, stdout);
+  wterm_ln ('''.');
+@.Sorry, I can't find...@>
+  update_terminal;
+  end;
+  {now pull out all the stops: try for the system \.{plain} file}
+pack_buffered_name(format_default_length-format_ext_length,1,0);
+if not w_open_in(fmt_file) then
+  begin wake_up_terminal;
+  wterm ('I can''t find the format file `');
+  fputs (TEX_format_default + 1, stdout);
+  wterm_ln ('''!');
+@.I can't find the format...@>
+@.plain@>
+  open_fmt_file:=false; return;
+  end;
+found:loc:=j; open_fmt_file:=true;
+exit:end;
+
+@ Operating systems often make it possible to determine the exact name (and
+possible version number) of a file that has been opened. The following routine,
+which simply makes a \TeX\ string from the value of |name_of_file|, should
+ideally be changed to deduce the full name of file~|f|, which is the file
+most recently opened, if it is possible to do this in a \PASCAL\ program.
+@^system dependencies@>
+
+This routine might be called after string memory has overflowed, hence
+we dare not use `|str_room|'.
+
+@p function make_name_string:str_number;
+var k:1..file_name_size; {index into |name_of_file|}
+save_area_delimiter, save_ext_delimiter: pool_pointer;
+save_name_in_progress, save_stop_at_space: boolean;
+begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or
+ (cur_length>0) then
+  make_name_string:="?"
+else  begin for k:=1 to name_length do append_char(xord[name_of_file[k]]);
+  make_name_string:=make_string;
+  {At this point we also set |cur_name|, |cur_ext|, and |cur_area| to
+   match the contents of |name_of_file|.}
+  save_area_delimiter:=area_delimiter; save_ext_delimiter:=ext_delimiter;
+  save_name_in_progress:=name_in_progress; save_stop_at_space:=stop_at_space;
+  name_in_progress:=true;
+  begin_name;
+  stop_at_space:=false;
+  k:=1;
+  while (k<=name_length)and(more_name(name_of_file[k])) do
+    incr(k);
+  stop_at_space:=save_stop_at_space;
+  end_name;
+  name_in_progress:=save_name_in_progress;
+  area_delimiter:=save_area_delimiter; ext_delimiter:=save_ext_delimiter;
+  end;
+end;
+function a_make_name_string(var f:alpha_file):str_number;
+begin a_make_name_string:=make_name_string;
+end;
+function b_make_name_string(var f:byte_file):str_number;
+begin b_make_name_string:=make_name_string;
+end;
+function w_make_name_string(var f:word_file):str_number;
+begin w_make_name_string:=make_name_string;
+end;
+
+@ Now let's consider the ``driver''
+routines by which \TeX\ deals with file names
+in a system-independent manner.  First comes a procedure that looks for a
+file name in the input by calling |get_x_token| for the information.
+
+@p procedure scan_file_name;
+label done;
+begin name_in_progress:=true; begin_name;
+@<Get the next non-blank non-call...@>;
+skip_mode:=false;
+loop@+begin
+  if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then {is kanji}
+    begin str_room(2);
+    append_char(Hi(cur_chr)); {kanji upper byte}
+    append_char(Lo(cur_chr)); {kanji lower byte}
+    end
+  else if (cur_cmd>other_char)or(cur_chr>255) then {not a alphabet}
+    begin back_input; goto done;
+    end
+  {If |cur_chr| is a space and we're not scanning a token list, check
+   whether we're at the end of the buffer. Otherwise we end up adding
+   spurious spaces to file names in some cases.}
+   else if ((cur_chr=" ") and (state<>token_list) and (loc>limit)) or not more_name(cur_chr) then goto done;
+  get_x_token;
+  end;
+done: end_name; name_in_progress:=false;
+skip_mode:=true;
+end;
+
+@ The global variable |name_in_progress| is used to prevent recursive
+use of |scan_file_name|, since the |begin_name| and other procedures
+communicate via global variables. Recursion would arise only by
+devious tricks like `\.{\\input\\input f}'; such attempts at sabotage
+must be thwarted. Furthermore, |name_in_progress| prevents \.{\\input}
+@^recursion@>
+from being initiated when a font size specification is being scanned.
+
+Another global variable, |job_name|, contains the file name that was first
+\.{\\input} by the user. This name is extended by `\.{.log}' and `\.{.dvi}'
+and `\.{.fmt}' in the names of \TeX's output files.
+
+@<Glob...@>=
+@!name_in_progress:boolean; {is a file name being scanned?}
+@!job_name:str_number; {principal file name}
+@!log_opened:boolean; {has the transcript file been opened?}
+
+@ Initially |job_name=0|; it becomes nonzero as soon as the true name is known.
+We have |job_name=0| if and only if the `\.{log}' file has not been opened,
+except of course for a short time just after |job_name| has become nonzero.
+
+@<Initialize the output...@>=
+job_name:=0; name_in_progress:=false; log_opened:=false;
+
+@ Here is a routine that manufactures the output file names, assuming that
+|job_name<>0|. It ignores and changes the current settings of |cur_area|
+and |cur_ext|.
+
+@d pack_cur_name==pack_file_name(cur_name,cur_area,cur_ext)
+
+@p procedure pack_job_name(@!s:str_number); {|s = ".log"|, |".dvi"|, or
+  |format_extension|}
+begin cur_area:=""; cur_ext:=s;
+cur_name:=job_name; pack_cur_name;
+end;
+
+@ If some trouble arises when \TeX\ tries to open a file, the following
+routine calls upon the user to supply another file name. Parameter~|s|
+is used in the error message to identify the type of file; parameter~|e|
+is the default extension if none is given. Upon exit from the routine,
+variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are
+ready for another attempt at file opening.
+
+@p procedure prompt_file_name(@!s,@!e:str_number);
+label done;
+var k:0..buf_size; {index into |buffer|}
+@!saved_cur_name:str_number; {to catch empty terminal input}
+@!saved_cur_ext:str_number; {to catch empty terminal input}
+@!saved_cur_area:str_number; {to catch empty terminal input}
+begin if interaction=scroll_mode then wake_up_terminal;
+if s="input file name" then print_err("I can't find file `")
+@.I can't find file x@>
+else print_err("I can't write on file `");
+@.I can't write on file x@>
+print_file_name(cur_name,cur_area,cur_ext); print("'.");
+if (e=".tex") or (e="") then show_context;
+print_ln; print_c_string(prompt_file_name_help_msg);
+if (e<>"") then
+  begin
+    print("; default file extension is `"); print(e); print("'");
+  end;
+print(")"); print_ln;
+print_nl("Please type another "); print(s);
+@.Please type...@>
+if interaction<scroll_mode then
+  fatal_error("*** (job aborted, file error in nonstop mode)");
+@.job aborted, file error...@>
+saved_cur_name:=cur_name;
+saved_cur_ext:=cur_ext;
+saved_cur_area:=cur_area;
+clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
+if (length(cur_name)=0) and (cur_ext="") and (cur_area="") then
+  begin
+    cur_name:=saved_cur_name;
+    cur_ext:=saved_cur_ext;
+    cur_area:=saved_cur_area;
+  end
+else
+  if cur_ext="" then cur_ext:=e;
+pack_cur_name;
+end;
+
+@ @<Scan file name in the buffer@>=
+begin begin_name; k:=first;
+while (buffer[k]=" ")and(k<last) do incr(k);
+loop@+  begin if k=last then goto done;
+  if not more_name(buffer[k]) then goto done;
+  incr(k);
+  end;
+done:end_name;
+end
+
+@ Here's an example of how these conventions are used. Whenever it is time to
+ship out a box of stuff, we shall use the macro |ensure_dvi_open|.
+
+@d log_name == texmf_log_name
+@d ensure_dvi_open==if output_file_name=0 then
+  begin if job_name=0 then open_log_file;
+  pack_job_name(".dvi");
+  while not b_open_out(dvi_file) do
+    prompt_file_name("file name for output",".dvi");
+  output_file_name:=b_make_name_string(dvi_file);
+  end
+
+@<Glob...@>=
+@!dvi_file: byte_file; {the device-independent output goes here}
+@!output_file_name: str_number; {full name of the output file}
+@!log_name:str_number; {full name of the log file}
+
+@ @<Initialize the output...@>=output_file_name:=0;
+
+@ The |open_log_file| routine is used to open the transcript file and to help
+it catch up to what has previously been printed on the terminal.
+
+@p procedure open_log_file;
+var old_setting:0..max_selector; {previous |selector| setting}
+@!k:0..buf_size; {index into |months| and |buffer|}
+@!l:0..buf_size; {end of first input line}
+@!months:const_cstring;
+begin old_setting:=selector;
+if job_name=0 then job_name:=get_job_name("texput");
+@.texput@>
+pack_job_name(".fls");
+recorder_change_filename(stringcast(name_of_file+1));
+pack_job_name(".log");
+while not a_open_out(log_file) do @<Try to get a different log file name@>;
+log_name:=a_make_name_string(log_file);
+selector:=log_only; log_opened:=true;
+@<Print the banner line, including the date and time@>;
+if mltex_enabled_p then
+  begin wlog_cr; wlog('MLTeX v2.2 enabled');
+  end;
+input_stack[input_ptr]:=cur_input; {make sure bottom level is in memory}
+print_nl("**");
+@.**@>
+l:=input_stack[0].limit_field; {last position of first line}
+if buffer[l]=end_line_char then decr(l);
+for k:=1 to l do print(buffer[k]);
+print_ln; {now the transcript file contains the first line of input}
+selector:=old_setting+2; {|log_only| or |term_and_log|}
+end;
+
+@ Sometimes |open_log_file| is called at awkward moments when \TeX\ is
+unable to print error messages or even to |show_context|.
+The |prompt_file_name| routine can result in a |fatal_error|, but the |error|
+routine will not be invoked because |log_opened| will be false.
+
+The normal idea of |batch_mode| is that nothing at all should be written
+on the terminal. However, in the unusual case that
+no log file could be opened, we make an exception and allow
+an explanatory message to be seen.
+
+Incidentally, the program always refers to the log file as a `\.{transcript
+file}', because some systems cannot use the extension `\.{.log}' for
+this file.
+
+@<Try to get a different log file name@>=
+begin selector:=term_only;
+prompt_file_name("transcript file name",".log");
+end
+
+@ @<Print the banner...@>=
+begin
+if src_specials_p or file_line_error_style_p or parse_first_line_p
+then
+  wlog(banner_k)
+else
+  wlog(banner);
+  wlog(' (');
+  wlog(conststringcast(get_enc_string));
+  wlog(')');
+wlog(version_string);
+slow_print(format_ident); print("  ");
+print_int(day); print_char(" ");
+months := ' JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC';
+for k:=3*month-2 to 3*month do wlog(months[k]);
+print_char(" "); print_int(year); print_char(" ");
+print_two(time div 60); print_char(":"); print_two(time mod 60);
+if shellenabledp then begin
+  wlog_cr;
+  wlog(' ');
+  if restrictedshell then begin
+    wlog('restricted ');
+  end;
+  wlog('\write18 enabled.')
+  end;
+if src_specials_p then begin
+  wlog_cr;
+  wlog(' Source specials enabled.')
+  end;
+if file_line_error_style_p then begin
+  wlog_cr;
+  wlog(' file:line:error style messages enabled.')
+  end;
+if parse_first_line_p then begin
+  wlog_cr;
+  wlog(' %&-line parsing enabled.');
+  end;
+if translate_filename then begin
+  wlog_cr;
+  wlog(' (');
+  fputs(translate_filename, log_file);
+  wlog(')');
+  end;
+end
+
+@ Let's turn now to the procedure that is used to initiate file reading
+when an `\.{\\input}' command is being processed.
+
+@p procedure start_input; {\TeX\ will \.{\\input} something}
+label done;
+var temp_str: str_number;
+begin scan_file_name; {set |cur_name| to desired file name}
+pack_cur_name;
+loop@+begin
+  begin_file_reading; {set up |cur_file| and new level of input}
+  tex_input_type := 1; {Tell |open_input| we are \.{\\input}.}
+  {Kpathsea tries all the various ways to get the file.}
+  if kpse_in_name_ok(stringcast(name_of_file+1))
+     and a_open_in(cur_file, kpse_tex_format) then
+    goto done;
+  end_file_reading; {remove the level that didn't work}
+  prompt_file_name("input file name","");
+  end;
+done: name:=a_make_name_string(cur_file);
+source_filename_stack[in_open]:=name;
+full_source_filename_stack[in_open]:=make_full_name_string;
+if name=str_ptr-1 then {we can try to conserve string pool space now}
+  begin temp_str:=search_string(name);
+  if temp_str>0 then
+    begin name:=temp_str; flush_string;
+    end;
+  end;
+if job_name=0 then
+  begin job_name:=get_job_name(cur_name); open_log_file;
+  end; {|open_log_file| doesn't |show_context|, so |limit|
+    and |loc| needn't be set to meaningful values yet}
+if term_offset+length(full_source_filename_stack[in_open])>max_print_line-2
+then print_ln
+else if (term_offset>0)or(file_offset>0) then print_char(" ");
+print_char("("); incr(open_parens);
+slow_print(full_source_filename_stack[in_open]); update_terminal;
+state:=new_line;
+@<Read the first line of the new file@>;
+end;
+
+@ Here we have to remember to tell the |input_ln| routine not to
+start with a |get|. If the file is empty, it is considered to
+contain a single blank line.
+@^system dependencies@>
+@^empty line at end of file@>
+
+@<Read the first line...@>=
+begin line:=1;
+if input_ln(cur_file,false) then do_nothing;
+firm_up_the_line;
+if end_line_char_inactive then decr(limit)
+else  buffer[limit]:=end_line_char;
+first:=limit+1; loc:=start;
+end
+
+@* \[30] Font metric data.
+\TeX\ gets its knowledge about fonts from font metric files, also called
+\.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX,
+but other programs know about them too.
+@:TFM files}{\.{TFM} files@>
+@^font metric files@>
+
+The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
+Since the number of bytes is always a multiple of 4, we could
+also regard the file as a sequence of 32-bit words, but \TeX\ uses the
+byte interpretation. The format of \.{TFM} files was designed by
+Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
+@^Ramshaw, Lyle Harold@>
+of information in a compact but useful form.
+
+@<Glob...@>=
+@!tfm_file:byte_file;
+
+@ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
+integers that give the lengths of the various subsequent portions
+of the file. These twelve integers are, in order:
+$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
+|lf|&length of the entire file, in words;\cr
+|lh|&length of the header data, in words;\cr
+|bc|&smallest character code in the font;\cr
+|ec|&largest character code in the font;\cr
+|nw|&number of words in the width table;\cr
+|nh|&number of words in the height table;\cr
+|nd|&number of words in the depth table;\cr
+|ni|&number of words in the italic correction table;\cr
+|nl|&number of words in the lig/kern table;\cr
+|nk|&number of words in the kern table;\cr
+|ne|&number of words in the extensible character table;\cr
+|np|&number of font parameter words.\cr}}$$
+They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
+and
+$$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
+Note that a font may contain as many as 256 characters (if |bc=0| and |ec=255|),
+and as few as 0 characters (if |bc=ec+1|).
+
+Incidentally, when two or more 8-bit bytes are combined to form an integer of
+16 or more bits, the most significant bytes appear first in the file.
+This is called BigEndian order.
+@!@^BigEndian order@>
+
+We use to get \TeX\ knowledge about KANJI fonts from \.{JFM} files.
+The \.{JFM} format holds more two 16-bit integers ,|id| and |nt|,
+at the top of the file.
+$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
+|id|&identification code of the file;\cr
+|nt|&number of words in the |char_type| table;\cr}}$$
+The identification byte, |id| equals~11 or~9. When \TeX read a font file,
+the |id| equals~11 or~9 then the font is the \.{JFM}, othercases it is
+the \.{TFM} file. The \.{TFM} holds |lf| at the same postion of |id|,
+usually it take a larger number than~9 or~11.
+The |nt| is nonngative and less than $2^{15}$.
+
+We must have |ec=0|,
+$$\hbox{|lf=7+lh+nt+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
+
+@d yoko_jfm_id=11 {for `yoko-kumi' fonts}
+@d tate_jfm_id=9  {for `tate-kumi' fonts}
+
+@ The rest of the \.{TFM} file may be regarded as a sequence of ten data
+arrays having the informal specification
+$$\def\arr$[#1]#2${\&{array} $[#1]$ \&{of} #2}
+\vbox{\halign{\hfil\\{#}&$\,:\,$\arr#\hfil\cr
+header&|[0..lh-1]@t\\{stuff}@>|\cr
+char\_info&|[bc..ec]char_info_word|\cr
+width&|[0..nw-1]fix_word|\cr
+height&|[0..nh-1]fix_word|\cr
+depth&|[0..nd-1]fix_word|\cr
+italic&|[0..ni-1]fix_word|\cr
+lig\_kern&|[0..nl-1]lig_kern_command|\cr
+kern&|[0..nk-1]fix_word|\cr
+exten&|[0..ne-1]extensible_recipe|\cr
+param&|[1..np]fix_word|\cr}}$$
+The most important data type used here is a |@!fix_word|, which is
+a 32-bit representation of a binary fraction. A |fix_word| is a signed
+quantity, with the two's complement of the entire word used to represent
+negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
+binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
+the smallest is $-2048$. We will see below, however, that all but two of
+the |fix_word| values must lie between $-16$ and $+16$.
+
+@ The first data array is a block of header information, which contains
+general facts about the font. The header must contain at least two words,
+|header[0]| and |header[1]|, whose meaning is explained below.
+Additional header information of use to other software routines might
+also be included, but \TeX82 does not need to know about such details.
+For example, 16 more words of header information are in use at the Xerox
+Palo Alto Research Center; the first ten specify the character coding
+scheme used (e.g., `\.{XEROX text}' or `\.{TeX math symbols}'), the next five
+give the font identifier (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
+last gives the ``face byte.'' The program that converts \.{DVI} files
+to Xerox printing format gets this information by looking at the \.{TFM}
+file, which it needs to read anyway because of other information that
+is not explicitly repeated in \.{DVI}~format.
+
+\yskip\hang|header[0]| is a 32-bit check sum that \TeX\ will copy into
+the \.{DVI} output file. Later on when the \.{DVI} file is printed,
+possibly on another computer, the actual font that gets used is supposed
+to have a check sum that agrees with the one in the \.{TFM} file used by
+\TeX. In this way, users will be warned about potential incompatibilities.
+(However, if the check sum is zero in either the font file or the \.{TFM}
+file, no check is made.)  The actual relation between this check sum and
+the rest of the \.{TFM} file is not important; the check sum is simply an
+identification number with the property that incompatible fonts almost
+always have distinct check sums.
+@^check sum@>
+
+\yskip\hang|header[1]| is a |fix_word| containing the design size of
+the font, in units of \TeX\ points. This number must be at least 1.0; it is
+fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
+font, i.e., a font that was designed to look best at a 10-point size,
+whatever that really means. When a \TeX\ user asks for a font
+`\.{at} $\delta$ \.{pt}', the effect is to override the design size
+and replace it by $\delta$, and to multiply the $x$ and~$y$ coordinates
+of the points in the font image by a factor of $\delta$ divided by the
+design size.  {\sl All other dimensions in the\/ \.{TFM} file are
+|fix_word|\kern-1pt\ numbers in design-size units}, with the exception of
+|param[1]| (which denotes the slant ratio). Thus, for example, the value
+of |param[6]|, which defines the \.{em} unit, is often the |fix_word| value
+$2^{20}=1.0$, since many fonts have a design size equal to one em.
+The other dimensions must be less than 16 design-size units in absolute
+value; thus, |header[1]| and |param[1]| are the only |fix_word|
+entries in the whole \.{TFM} file whose first byte might be something
+besides 0 or 255.
+
+@ Next comes the |char_info| array, which contains one |@!char_info_word|
+per character. Each word in this part of the file contains six fields
+packed into four bytes as follows.
+
+\yskip\hang first byte: |@!width_index| (8 bits)\par
+\hang second byte: |@!height_index| (4 bits) times 16, plus |@!depth_index|
+  (4~bits)\par
+\hang third byte: |@!italic_index| (6 bits) times 4, plus |@!tag|
+  (2~bits)\par
+\hang fourth byte: |@!remainder| (8 bits)\par
+\yskip\noindent
+The actual width of a character is \\{width}|[width_index]|, in design-size
+units; this is a device for compressing information, since many characters
+have the same width. Since it is quite common for many characters
+to have the same height, depth, or italic correction, the \.{TFM} format
+imposes a limit of 16 different heights, 16 different depths, and
+64 different italic corrections.
+
+@!@^italic correction@>
+The italic correction of a character has two different uses.
+(a)~In ordinary text, the italic correction is added to the width only if
+the \TeX\ user specifies `\.{\\/}' after the character.
+(b)~In math formulas, the italic correction is always added to the width,
+except with respect to the positioning of subscripts.
+
+Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
+\\{italic}[0]=0$ should always hold, so that an index of zero implies a
+value of zero.  The |width_index| should never be zero unless the
+character does not exist in the font, since a character is valid if and
+only if it lies between |bc| and |ec| and has a nonzero |width_index|.
+
+@ The |tag| field in a |char_info_word| has four values that explain how to
+interpret the |remainder| field.
+
+\yskip\hangg|tag=0| (|no_tag|) means that |remainder| is unused.\par
+\hangg|tag=1| (|lig_tag|) means that this character has a ligature/kerning
+program starting at position |remainder| in the |lig_kern| array.\par
+\hangg|tag=2| (|list_tag|) means that this character is part of a chain of
+characters of ascending sizes, and not the largest in the chain.  The
+|remainder| field gives the character code of the next larger character.\par
+\hangg|tag=3| (|ext_tag|) means that this character code represents an
+extensible character, i.e., a character that is built up of smaller pieces
+so that it can be made arbitrarily large. The pieces are specified in
+|@!exten[remainder]|.\par
+\yskip\noindent
+Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
+unless they are used in special circumstances in math formulas. For example,
+the \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
+operation looks for both |list_tag| and |ext_tag|.
+
+If the \.{JFM}, the |lig_tag| is called |gk_tag|. The |gk_tag| means that
+this character has a glue/kerning program starting at position |remainder|
+in the |glue_kern| array. And a \.{JFM} not used |tag=2| and |tag=3|.
+
+@d no_tag=0 {vanilla character}
+@d lig_tag=1 {character has a ligature/kerning program}
+@d gk_tag=1 {character has a glue/kerning program}
+@d list_tag=2 {character has a successor in a charlist}
+@d ext_tag=3 {character is extensible}
+
+@ The |lig_kern| array contains instructions in a simple programming language
+that explains what to do for special letter pairs. Each word in this array is a
+|@!lig_kern_command| of four bytes.
+
+\yskip\hang first byte: |skip_byte|, indicates that this is the final program
+  step if the byte is 128 or more, otherwise the next step is obtained by
+  skipping this number of intervening steps.\par
+\hang second byte: |next_char|, ``if |next_char| follows the current character,
+  then perform the operation and stop, otherwise continue.''\par
+\hang third byte: |op_byte|, indicates a ligature step if less than~128,
+  a kern step otherwise.\par
+\hang fourth byte: |remainder|.\par
+\yskip\noindent
+In a kern step, an
+additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
+between the current character and |next_char|. This amount is
+often negative, so that the characters are brought closer together
+by kerning; but it might be positive.
+
+There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
+$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
+|remainder| is inserted between the current character and |next_char|;
+then the current character is deleted if $b=0$, and |next_char| is
+deleted if $c=0$; then we pass over $a$~characters to reach the next
+current character (which may have a ligature/kerning program of its own).
+
+If the very first instruction of the |lig_kern| array has |skip_byte=255|,
+the |next_char| byte is the so-called right boundary character of this font;
+the value of |next_char| need not lie between |bc| and~|ec|.
+If the very last instruction of the |lig_kern| array has |skip_byte=255|,
+there is a special ligature/kerning program for a left boundary character,
+beginning at location |256*op_byte+remainder|.
+The interpretation is that \TeX\ puts implicit boundary characters
+before and after each consecutive string of characters from the same font.
+These implicit characters do not appear in the output, but they can affect
+ligatures and kerning.
+
+If the very first instruction of a character's |lig_kern| program has
+|skip_byte>128|, the program actually begins in location
+|256*op_byte+remainder|. This feature allows access to large |lig_kern|
+arrays, because the first instruction must otherwise
+appear in a location |<=255|.
+
+Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy
+the condition
+$$\hbox{|256*op_byte+remainder<nl|.}$$
+If such an instruction is encountered during
+normal program execution, it denotes an unconditional halt; no ligature
+or kerning command is performed.
+
+@d stop_flag==qi(128) {value indicating `\.{STOP}' in a lig/kern program}
+@d kern_flag==qi(128) {op code for a kern step}
+@d skip_byte(#)==#.b0
+@d next_char(#)==#.b1
+@d op_byte(#)==#.b2
+@d rem_byte(#)==#.b3
+
+@ Extensible characters are specified by an |@!extensible_recipe|, which
+consists of four bytes called |@!top|, |@!mid|, |@!bot|, and |@!rep| (in this
+order). These bytes are the character codes of individual pieces used to
+build up a large symbol.  If |top|, |mid|, or |bot| are zero, they are not
+present in the built-up result. For example, an extensible vertical line is
+like an extensible bracket, except that the top and bottom pieces are missing.
+
+Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
+if the piece isn't present. Then the extensible characters have the form
+$TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent;
+in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
+The width of the extensible character is the width of $R$; and the
+height-plus-depth is the sum of the individual height-plus-depths of the
+components used, since the pieces are butted together in a vertical list.
+
+@d ext_top(#)==#.b0 {|top| piece in a recipe}
+@d ext_mid(#)==#.b1 {|mid| piece in a recipe}
+@d ext_bot(#)==#.b2 {|bot| piece in a recipe}
+@d ext_rep(#)==#.b3 {|rep| piece in a recipe}
+
+@ The final portion of a \.{TFM} file is the |param| array, which is another
+sequence of |fix_word| values.
+
+\yskip\hang|param[1]=slant| is the amount of italic slant, which is used
+to help position accents. For example, |slant=.25| means that when you go
+up one unit, you also go .25 units to the right. The |slant| is a pure
+number; it's the only |fix_word| other than the design size itself that is
+not scaled by the design size.
+
+\hang|param[2]=space| is the normal spacing between words in text.
+Note that character |" "| in the font need not have anything to do with
+blank spaces.
+
+\hang|param[3]=space_stretch| is the amount of glue stretching between words.
+
+\hang|param[4]=space_shrink| is the amount of glue shrinking between words.
+
+\hang|param[5]=x_height| is the size of one ex in the font; it is also
+the height of letters for which accents don't have to be raised or lowered.
+
+\hang|param[6]=quad| is the size of one em in the font.
+
+\hang|param[7]=extra_space| is the amount added to |param[2]| at the
+ends of sentences.
+
+\yskip\noindent
+If fewer than seven parameters are present, \TeX\ sets the missing parameters
+to zero. Fonts used for math symbols are required to have
+additional parameter information, which is explained later.
+
+@d slant_code=1
+@d space_code=2
+@d space_stretch_code=3
+@d space_shrink_code=4
+@d x_height_code=5
+@d quad_code=6
+@d extra_space_code=7
+
+@ So that is what \.{TFM} files hold. Since \TeX\ has to absorb such information
+about lots of fonts, it stores most of the data in a large array called
+|font_info|. Each item of |font_info| is a |memory_word|; the |fix_word|
+data gets converted into |scaled| entries, while everything else goes into
+words of type |four_quarters|.
+
+When the user defines \.{\\font\\f}, say, \TeX\ assigns an internal number
+to the user's font~\.{\\f}. Adding this number to |font_id_base| gives the
+|eqtb| location of a ``frozen'' control sequence that will always select
+the font.
+
+@<Types...@>=
+@!internal_font_number=integer; {|font| in a |char_node|}
+@!font_index=integer; {index into |font_info|}
+@!nine_bits=min_quarterword..non_char;
+
+@ Here now is the (rather formidable) array of font arrays.
+
+@d non_char==qi(256) {a |halfword| code that can't match a real character}
+@d non_address=0 {a spurious |bchar_label|}
+
+@<Glob...@>=
+@!font_info: ^memory_word; {pTeX: use halfword for |char_type| table.}
+@!font_dir: ^eight_bits;
+  {pTeX: direction of fonts, 0 is default, 1 is Yoko, 2 is Tate}
+@!font_num_ext: ^integer;
+  {pTeX: number of the |char_type| table.}
+  {the big collection of font data}
+@!fmem_ptr:font_index; {first unused word of |font_info|}
+@!font_ptr:internal_font_number; {largest internal font number in use}
+@!font_check: ^four_quarters; {check sum}
+@!font_size: ^scaled; {``at'' size}
+@!font_dsize: ^scaled; {``design'' size}
+@!font_params: ^font_index; {how many font
+  parameters are present}
+@!font_name: ^str_number; {name of the font}
+@!font_area: ^str_number; {area of the font}
+@!font_bc: ^eight_bits;
+  {beginning (smallest) character code}
+@!font_ec: ^eight_bits;
+  {ending (largest) character code}
+@!font_glue: ^pointer;
+  {glue specification for interword space, |null| if not allocated}
+@!font_used: ^boolean;
+  {has a character from this font actually appeared in the output?}
+@!hyphen_char: ^integer;
+  {current \.{\\hyphenchar} values}
+@!skew_char: ^integer;
+  {current \.{\\skewchar} values}
+@!bchar_label: ^font_index;
+  {start of |lig_kern| program for left boundary character,
+  |non_address| if there is none}
+@!font_bchar: ^nine_bits;
+  {right boundary character, |non_char| if there is none}
+@!font_false_bchar: ^nine_bits;
+  {|font_bchar| if it doesn't exist in the font, otherwise |non_char|}
+
+@ Besides the arrays just enumerated, we have directory arrays that make it
+easy to get at the individual entries in |font_info|. For example, the
+|char_info| data for character |c| in font |f| will be in
+|font_info[char_base[f]+c].qqqq|; and if |w| is the |width_index|
+part of this word (the |b0| field), the width of the character is
+|font_info[width_base[f]+w].sc|. (These formulas assume that
+|min_quarterword| has already been added to |c| and to |w|, since \TeX\
+stores its quarterwords that way.)
+
+@<Glob...@>=
+@!char_base: ^integer;
+  {base addresses for |char_info|}
+@!ctype_base: ^integer;
+  {pTeX: base addresses for KANJI character type parameters}
+@!width_base: ^integer;
+  {base addresses for widths}
+@!height_base: ^integer;
+  {base addresses for heights}
+@!depth_base: ^integer;
+  {base addresses for depths}
+@!italic_base: ^integer;
+  {base addresses for italic corrections}
+@!lig_kern_base: ^integer;
+  {base addresses for ligature/kerning programs}
+@!kern_base: ^integer;
+  {base addresses for kerns}
+@!exten_base: ^integer;
+  {base addresses for extensible recipes}
+@!param_base: ^integer;
+  {base addresses for font parameters}
+
+@ @<Set init...@>=
+
+@ \TeX\ always knows at least one font, namely the null font. It has no
+characters, and its seven parameters are all equal to zero.
+
+@<Initialize table...@>=
+
+@ @<Put each...@>=
+primitive("nullfont",set_font,null_font);
+@!@:null_font_}{\.{\\nullfont} primitive@>
+text(frozen_null_font):="nullfont"; eqtb[frozen_null_font]:=eqtb[cur_val];
+
+@ Of course we want to define macros that suppress the detail of how font
+information is actually packed, so that we don't have to write things like
+$$\hbox{|font_info[width_base[f]+font_info[char_base[f]+c].qqqq.b0].sc|}$$
+too often. The \.{WEB} definitions here make |char_info(f)(c)| the
+|four_quarters| word of font information corresponding to character
+|c| of font |f|. If |q| is such a word, |char_width(f)(q)| will be
+the character's width; hence the long formula above is at least
+abbreviated to
+$$\hbox{|char_width(f)(char_info(f)(c))|.}$$
+Usually, of course, we will fetch |q| first and look at several of its
+fields at the same time.
+
+The italic correction of a character will be denoted by
+|char_italic(f)(q)|, so it is analogous to |char_width|.  But we will get
+at the height and depth in a slightly different way, since we usually want
+to compute both height and depth if we want either one.  The value of
+|height_depth(q)| will be the 8-bit quantity
+$$b=|height_index|\times16+|depth_index|,$$ and if |b| is such a byte we
+will write |char_height(f)(b)| and |char_depth(f)(b)| for the height and
+depth of the character |c| for which |q=char_info(f)(c)|. Got that?
+
+The tag field will be called |char_tag(q)|; the remainder byte will be
+called |rem_byte(q)|, using a macro that we have already defined above.
+
+Access to a character's |width|, |height|, |depth|, and |tag| fields is
+part of \TeX's inner loop, so we want these macros to produce code that is
+as fast as possible under the circumstances.
+@^inner loop@>
+
+ML\TeX{} will assume that a character |c| exists iff either exists in
+the current font or a character substitution definition for this
+character was defined using \.{\\charsubdef}.  To avoid the
+distinction between these two cases, ML\TeX{} introduces the notion
+``effective character'' of an input character |c|.  If |c| exists in
+the current font, the effective character of |c| is the character |c|
+itself.  If it doesn't exist but a character substitution is defined,
+the effective character of |c| is the base character defined in the
+character substitution.  If there is an effective character for a
+non-existing character |c|, the ``virtual character'' |c| will get
+appended to the horizontal lists.
+
+The effective character is used within |char_info| to access
+appropriate character descriptions in the font.  For example, when
+calculating the width of a box, ML\TeX{} will use the metrics of the
+effective characters.  For the case of a substitution, ML\TeX{} uses
+the metrics of the base character, ignoring the metrics of the accent
+character.
+
+If character substitutions are changed, it will be possible that a
+character |c| neither exists in a font nor there is a valid character
+substitution for |c|.  To handle these cases |effective_char| should
+be called with its first argument set to |true| to ensure that it
+will still return an existing character in the font.  If neither |c|
+nor the substituted base character in the current character
+substitution exists, |effective_char| will output a warning and
+return the character |font_bc[f]| (which is incorrect, but can not be
+changed within the current framework).
+
+Sometimes character substitutions are unwanted, therefore the
+original definition of |char_info| can be used using the macro
+|orig_char_info|.  Operations in which character substitutions should
+be avoided are, for example, loading a new font and checking the font
+metric information in this font, and character accesses in math mode.
+
+@d char_list_exists(#)==(char_sub_code(#)>hi(0))
+@d char_list_accent(#)==(ho(char_sub_code(#)) div 256)
+@d char_list_char(#)==(ho(char_sub_code(#)) mod 256)
+@#
+@d char_info_end(#)== #@=)@>].qqqq
+@d char_info(#)==
+  font_info[char_base[#]+effective_char@=(@>true,#,char_info_end
+@#
+@d orig_char_info_end(#)==#].qqqq
+@d orig_char_info(#)==font_info[char_base[#]+orig_char_info_end
+@#
+@d kchar_code_end(#)==#].hh.rh
+@d kchar_code(#)==font_info[ctype_base[#]+kchar_code_end
+@d kchar_type_end(#)==#].hh.lhfield
+@d kchar_type(#)==font_info[ctype_base[#]+kchar_type_end
+@#
+@d char_width_end(#)==#.b0].sc
+@d char_width(#)==font_info[width_base[#]+char_width_end
+@d char_exists(#)==(#.b0>min_quarterword)
+@d char_italic_end(#)==(qo(#.b2)) div 4].sc
+@d char_italic(#)==font_info[italic_base[#]+char_italic_end
+@d height_depth(#)==qo(#.b1)
+@d char_height_end(#)==(#) div 16].sc
+@d char_height(#)==font_info[height_base[#]+char_height_end
+@d char_depth_end(#)==(#) mod 16].sc
+@d char_depth(#)==font_info[depth_base[#]+char_depth_end
+@d char_tag(#)==((qo(#.b2)) mod 4)
+
+@ The global variable |null_character| is set up to be a word of
+|char_info| for a character that doesn't exist. Such a word provides a
+convenient way to deal with erroneous situations.
+
+@<Glob...@>=
+@!null_character:four_quarters; {nonexistent character information}
+
+@ @<Set init...@>=
+null_character.b0:=min_quarterword; null_character.b1:=min_quarterword;
+null_character.b2:=min_quarterword; null_character.b3:=min_quarterword;
+
+@ Here are some macros that help process ligatures and kerns.
+We write |char_kern(f)(j)| to find the amount of kerning specified by
+kerning command~|j| in font~|f|. If |j| is the |char_info| for a character
+with a ligature/kern program, the first instruction of that program is either
+|i=font_info[lig_kern_start(f)(j)]| or |font_info[lig_kern_restart(f)(i)]|,
+depending on whether or not |skip_byte(i)<=stop_flag|.
+
+The constant |kern_base_offset| should be simplified, for \PASCAL\ compilers
+that do not do local optimization.
+@^system dependencies@>
+
+@d char_kern_end(#)==256*op_byte(#)+rem_byte(#)].sc
+@d char_kern(#)==font_info[kern_base[#]+char_kern_end
+@d kern_base_offset==256*(128+min_quarterword)
+@d lig_kern_start(#)==lig_kern_base[#]+rem_byte {beginning of lig/kern program}
+@d glue_kern_start(#)==lig_kern_base[#]+rem_byte
+  {beginning of glue/kern program}
+@d lig_kern_restart_end(#)==256*op_byte(#)+rem_byte(#)+32768-kern_base_offset
+@d lig_kern_restart(#)==lig_kern_base[#]+lig_kern_restart_end
+
+@ Font parameters are referred to as |slant(f)|, |space(f)|, etc.
+
+@d param_end(#)==param_base[#]].sc
+@d param(#)==font_info[#+param_end
+@d slant==param(slant_code) {slant to the right, per unit distance upward}
+@d space==param(space_code) {normal space between words}
+@d space_stretch==param(space_stretch_code) {stretch between words}
+@d space_shrink==param(space_shrink_code) {shrink between words}
+@d x_height==param(x_height_code) {one ex}
+@d quad==param(quad_code) {one em}
+@d extra_space==param(extra_space_code) {additional space at end of sentence}
+
+@<The em width for |cur_font|@>=quad(cur_font)
+
+@ @<The x-height for |cur_font|@>=x_height(cur_font)
+
+@ \TeX\ checks the information of a \.{TFM} file for validity as the
+file is being read in, so that no further checks will be needed when
+typesetting is going on. The somewhat tedious subroutine that does this
+is called |read_font_info|. It has four parameters: the user font
+identifier~|u|, the file name and area strings |nom| and |aire|, and the
+``at'' size~|s|. If |s|~is negative, it's the negative of a scale factor
+to be applied to the design size; |s=-1000| is the normal case.
+Otherwise |s| will be substituted for the design size; in this
+case, |s| must be positive and less than $2048\rm\,pt$
+(i.e., it must be less than $2^{27}$ when considered as an integer).
+
+The subroutine opens and closes a global file variable called |tfm_file|.
+It returns the value of the internal font number that was just loaded.
+If an error is detected, an error message is issued and no font
+information is stored; |null_font| is returned in this case.
+
+@d bad_tfm=11 {label for |read_font_info|}
+@d abort==goto bad_tfm {do this when the \.{TFM} data is wrong}
+
+@p @t\4@>@<Declare additional functions for ML\TeX@>@/
+
+function read_font_info(@!u:pointer;@!nom,@!aire:str_number;
+  @!s:scaled):internal_font_number; {input a \.{TFM} file}
+label done,bad_tfm,not_found;
+var k:font_index; {index into |font_info|}
+@!jfm_flag:dir_default..dir_tate; {direction of the \.{JFM}}
+@!nt:halfword; {number of the |char_type| tables}
+@!cx:KANJI_code; {kanji code}
+@!name_too_long:boolean; {|nom| or |aire| exceeds 255 bytes?}
+@!file_opened:boolean; {was |tfm_file| successfully opened?}
+@!lf,@!lh,@!bc,@!ec,@!nw,@!nh,@!nd,@!ni,@!nl,@!nk,@!ne,@!np:halfword;
+  {sizes of subfiles}
+@!f:internal_font_number; {the new font's number}
+@!g:internal_font_number; {the number to return}
+@!a,@!b,@!c,@!d:eight_bits; {byte variables}
+@!qw:four_quarters;@!sw:scaled; {accumulators}
+@!bch_label:integer; {left boundary start location, or infinity}
+@!bchar:0..256; {right boundary character, or 256}
+@!z:scaled; {the design size or the ``at'' size}
+@!alpha:integer;@!beta:1..16;
+  {auxiliary quantities used in fixed-point multiplication}
+begin g:=null_font;@/
+@<Read and check the font data; |abort| if the \.{TFM} file is
+  malformed; if there's no room for this font, say so and |goto
+  done|; otherwise |incr(font_ptr)| and |goto done|@>;
+bad_tfm: @<Report that the font won't be loaded@>;
+done: if file_opened then b_close(tfm_file);
+read_font_info:=g;
+end;
+
+@ There are programs called \.{TFtoPL} and \.{PLtoTF} that convert
+between the \.{TFM} format and a symbolic property-list format
+that can be easily edited. These programs contain extensive
+diagnostic information, so \TeX\ does not have to bother giving
+precise details about why it rejects a particular \.{TFM} file.
+@.TFtoPL@> @.PLtoTF@>
+
+@d start_font_error_message==print_err("Font "); sprint_cs(u);
+  print_char("="); print_file_name(nom,aire,"");
+  if s>=0 then
+    begin print(" at "); print_scaled(s); print("pt");
+    end
+  else if s<>-1000 then
+    begin print(" scaled "); print_int(-s);
+    end
+
+@<Report that the font won't be loaded@>=
+start_font_error_message;
+@.Font x=xx not loadable...@>
+if file_opened then print(" not loadable: Bad metric (TFM) file")
+else if name_too_long then print(" not loadable: Metric (TFM) file name too long")
+else print(" not loadable: Metric (TFM) file not found");
+help5("I wasn't able to read the size data for this font,")@/
+("so I will ignore the font specification.")@/
+("[Wizards can fix TFM files using TFtoPL/PLtoTF.]")@/
+("You might try inserting a different font spec;")@/
+("e.g., type `I\font<same font id>=<substitute font name>'.");
+error
+
+@ @<Read and check...@>=
+@<Open |tfm_file| for input@>;
+@<Read the {\.{TFM}} size fields@>;
+@<Use size fields to allocate font information@>;
+@<Read the {\.{TFM}} header@>;
+@<Read character data@>;
+@<Read box dimensions@>;
+@<Read ligature/kern program@>;
+@<Read extensible character recipes@>;
+@<Read font parameters@>;
+@<Make final adjustments and |goto done|@>
+
+@ @<Open |tfm_file| for input@>=
+file_opened:=false;
+name_too_long:=(length(nom)>255)or(length(aire)>255);
+if name_too_long then abort;
+{|kpse_find_file| will append the |".tfm"|, and avoid searching the disk
+ before the font alias files as well.}
+pack_file_name(nom,aire,"");
+if not b_open_in(tfm_file) then abort;
+file_opened:=true
+
+@ Note: A malformed \.{TFM} file might be shorter than it claims to be;
+thus |eof(tfm_file)| might be true when |read_font_info| refers to
+|tfm_file^| or when it says |get(tfm_file)|. If such circumstances
+cause system error messages, you will have to defeat them somehow,
+for example by defining |fget| to be `\ignorespaces|begin get(tfm_file);|
+|if eof(tfm_file) then abort; end|\unskip'.
+@^system dependencies@>
+
+@d fget==tfm_temp:=getc(tfm_file)
+@d fbyte==tfm_temp
+@d read_sixteen(#)==begin #:=fbyte;
+  if #>127 then abort;
+  fget; #:=#*@'400+fbyte;
+  end
+@d store_four_quarters(#)==begin fget; a:=fbyte; qw.b0:=qi(a);
+  fget; b:=fbyte; qw.b1:=qi(b);
+  fget; c:=fbyte; qw.b2:=qi(c);
+  fget; d:=fbyte; qw.b3:=qi(d);
+  #:=qw;
+  end
+
+@ @<Read the {\.{TFM}} size fields@>=
+begin read_sixteen(lf);
+fget; read_sixteen(lh);
+if lf=yoko_jfm_id then
+  begin jfm_flag:=dir_yoko; nt:=lh;
+  fget; read_sixteen(lf);
+  fget; read_sixteen(lh);
+  end
+else if lf=tate_jfm_id then
+  begin jfm_flag:=dir_tate; nt:=lh;
+  fget; read_sixteen(lf);
+  fget; read_sixteen(lh);
+  end
+else begin jfm_flag:=dir_default; nt:=0;
+  end;
+fget; read_sixteen(bc);
+fget; read_sixteen(ec);
+if (bc>ec+1)or(ec>255) then abort;
+if bc>255 then {|bc=256| and |ec=255|}
+  begin bc:=1; ec:=0;
+  end;
+fget; read_sixteen(nw);
+fget; read_sixteen(nh);
+fget; read_sixteen(nd);
+fget; read_sixteen(ni);
+fget; read_sixteen(nl);
+fget; read_sixteen(nk);
+fget; read_sixteen(ne);
+fget; read_sixteen(np);
+if jfm_flag<>dir_default then
+  begin if lf<>7+lh+nt+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np then abort;
+  end
+else
+  begin if lf<>6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np then abort;
+  end;
+if (nw=0)or(nh=0)or(nd=0)or(ni=0) then abort;
+end
+
+@ The preliminary settings of the index-offset variables |char_base|,
+|width_base|, |lig_kern_base|, |kern_base|, and |exten_base| will be
+corrected later by subtracting |min_quarterword| from them; and we will
+subtract 1 from |param_base| too. It's best to forget about such anomalies
+until later.
+
+@<Use size fields to allocate font information@>=
+if jfm_flag<>dir_default then
+  lf:=lf-7-lh  {If \.{JFM}, |lf| holds more two-16bit records than \.{TFM}}
+else
+  lf:=lf-6-lh; {|lf| words should be loaded into |font_info|}
+if np<7 then lf:=lf+7-np; {at least seven parameters will appear}
+if (font_ptr=font_max)or(fmem_ptr+lf>font_mem_size) then
+  @<Apologize for not loading the font, |goto done|@>;
+f:=font_ptr+1;
+font_dir[f]:=jfm_flag;
+font_num_ext[f]:=nt;
+ctype_base[f]:=fmem_ptr;
+char_base[f]:=ctype_base[f]+nt-bc;
+width_base[f]:=char_base[f]+ec+1;
+height_base[f]:=width_base[f]+nw;
+depth_base[f]:=height_base[f]+nh;
+italic_base[f]:=depth_base[f]+nd;
+lig_kern_base[f]:=italic_base[f]+ni;
+kern_base[f]:=lig_kern_base[f]+nl-kern_base_offset;
+exten_base[f]:=kern_base[f]+kern_base_offset+nk;
+param_base[f]:=exten_base[f]+ne;
+
+@ @<Apologize for not loading...@>=
+begin start_font_error_message;
+print(" not loaded: Not enough room left");
+@.Font x=xx not loaded...@>
+help4("I'm afraid I won't be able to make use of this font,")@/
+("because my memory for character-size data is too small.")@/
+("If you're really stuck, ask a wizard to enlarge me.")@/
+("Or maybe try `I\font<same font id>=<name of loaded font>'.");
+error; goto done;
+end
+
+@ Only the first two words of the header are needed by \TeX82.
+
+@<Read the {\.{TFM}} header@>=
+begin if lh<2 then abort;
+store_four_quarters(font_check[f]);
+fget; read_sixteen(z); {this rejects a negative design size}
+fget; z:=z*@'400+fbyte; fget; z:=(z*@'20)+(fbyte div@'20);
+if z<unity then abort;
+while lh>2 do
+  begin fget;fget;fget;fget;decr(lh); {ignore the rest of the header}
+  end;
+font_dsize[f]:=z;
+if s<>-1000 then
+  if s>=0 then z:=s
+  else z:=xn_over_d(z,-s,1000);
+font_size[f]:=z;
+end
+
+@ @<Read character data@>=
+if jfm_flag<>dir_default then
+  for k:=ctype_base[f] to ctype_base[f]+nt-1 do
+    begin
+    fget; read_sixteen(cx); font_info[k].hh.rh:=tokanji(cx); {|kchar_code|}
+    fget; read_sixteen(cx); font_info[k].hh.lhfield:=tonum(cx); {|kchar_type|}
+    end;
+for k:=char_base[f]+bc to width_base[f]-1 do
+  begin store_four_quarters(font_info[k].qqqq);
+  if (a>=nw)or(b div @'20>=nh)or(b mod @'20>=nd)or
+    (c div 4>=ni) then abort;
+  case c mod 4 of
+  lig_tag: if d>=nl then abort;
+  ext_tag: if d>=ne then abort;
+  list_tag: @<Check for charlist cycle@>;
+  othercases do_nothing {|no_tag|}
+  endcases;
+  end
+
+@ We want to make sure that there is no cycle of characters linked together
+by |list_tag| entries, since such a cycle would get \TeX\ into an endless
+loop. If such a cycle exists, the routine here detects it when processing
+the largest character code in the cycle.
+
+@d check_byte_range(#)==begin if (#<bc)or(#>ec) then abort@+end
+@d current_character_being_worked_on==k-char_base[f]
+
+@<Check for charlist cycle@>=
+begin check_byte_range(d);
+while d<current_character_being_worked_on do
+  begin qw:=orig_char_info(f)(d);
+  {N.B.: not |qi(d)|, since |char_base[f]| hasn't been adjusted yet}
+  if char_tag(qw)<>list_tag then goto not_found;
+  d:=qo(rem_byte(qw)); {next character on the list}
+  end;
+if d=current_character_being_worked_on then abort; {yes, there's a cycle}
+not_found:end
+
+@ A |fix_word| whose four bytes are $(a,b,c,d)$ from left to right represents
+the number
+$$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
+-16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$
+(No other choices of |a| are allowed, since the magnitude of a number in
+design-size units must be less than 16.)  We want to multiply this
+quantity by the integer~|z|, which is known to be less than $2^{27}$.
+If $|z|<2^{23}$, the individual multiplications $b\cdot z$,
+$c\cdot z$, $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2,
+4, 8, or 16, to obtain a multiplier less than $2^{23}$, and we can
+compensate for this later. If |z| has thereby been replaced by
+$|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we shall compute
+$$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$
+if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$.
+This calculation must be done exactly, in order to guarantee portability
+of \TeX\ between computers.
+
+@d store_scaled(#)==begin fget; a:=fbyte; fget; b:=fbyte;
+  fget; c:=fbyte; fget; d:=fbyte;@/
+  sw:=(((((d*z)div@'400)+(c*z))div@'400)+(b*z))div beta;
+  if a=0 then #:=sw@+else if a=255 then #:=sw-alpha@+else abort;
+  end
+
+@<Read box dimensions@>=
+begin @<Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$@>;
+for k:=width_base[f] to lig_kern_base[f]-1 do
+  store_scaled(font_info[k].sc);
+if font_info[width_base[f]].sc<>0 then abort; {\\{width}[0] must be zero}
+if font_info[height_base[f]].sc<>0 then abort; {\\{height}[0] must be zero}
+if font_info[depth_base[f]].sc<>0 then abort; {\\{depth}[0] must be zero}
+if font_info[italic_base[f]].sc<>0 then abort; {\\{italic}[0] must be zero}
+end
+
+@ @<Replace |z|...@>=
+begin alpha:=16;
+while z>=@'40000000 do
+  begin z:=z div 2; alpha:=alpha+alpha;
+  end;
+beta:=256 div alpha; alpha:=alpha*z;
+end
+
+@ @d check_existence(#)==@t@>@;@/
+  begin check_byte_range(#);
+  qw:=orig_char_info(f)(#); {N.B.: not |qi(#)|}
+  if not char_exists(qw) then abort;
+  end
+
+@<Read ligature/kern program@>=
+bch_label:=@'77777; bchar:=256;
+if nl>0 then
+  begin for k:=lig_kern_base[f] to kern_base[f]+kern_base_offset-1 do
+    begin store_four_quarters(font_info[k].qqqq);
+    if a>128 then
+      begin if 256*c+d>=nl then abort;
+      if a=255 then if k=lig_kern_base[f] then bchar:=b;
+      end
+    else begin if b<>bchar then check_existence(b);
+      if c<128 then begin
+          if jfm_flag<>dir_default then begin if d>=ne then abort; end
+        else check_existence(d); {check ligature}
+      end else if 256*(c-128)+d>=nk then abort; {check kern}
+      if a<128 then if k-lig_kern_base[f]+a+1>=nl then abort;
+      end;
+    end;
+  if a=255 then bch_label:=256*c+d;
+  end;
+for k:=kern_base[f]+kern_base_offset to exten_base[f]-1 do
+  store_scaled(font_info[k].sc);
+
+@ @<Read extensible character recipes@>=
+if jfm_flag<>dir_default then
+  for k:=exten_base[f] to param_base[f]-1 do
+    store_scaled(font_info[k].sc) {NOTE: this area subst for glue program}
+else for k:=exten_base[f] to param_base[f]-1 do
+  begin store_four_quarters(font_info[k].qqqq);
+  if a<>0 then check_existence(a);
+  if b<>0 then check_existence(b);
+  if c<>0 then check_existence(c);
+  check_existence(d);
+  end
+
+@ We check to see that the \.{TFM} file doesn't end prematurely; but
+no error message is given for files having more than |lf| words.
+
+@<Read font parameters@>=
+begin for k:=1 to np do
+  if k=1 then {the |slant| parameter is a pure number}
+    begin fget; sw:=fbyte; if sw>127 then sw:=sw-256;
+    fget; sw:=sw*@'400+fbyte; fget; sw:=sw*@'400+fbyte;
+    fget; font_info[param_base[f]].sc:=
+      (sw*@'20)+(fbyte div@'20);
+    end
+  else store_scaled(font_info[param_base[f]+k-1].sc);
+if feof(tfm_file) then abort;
+for k:=np+1 to 7 do font_info[param_base[f]+k-1].sc:=0;
+end
+
+@ Now to wrap it up, we have checked all the necessary things about the \.{TFM}
+file, and all we need to do is put the finishing touches on the data for
+the new font.
+
+@d adjust(#)==#[f]:=qo(#[f])
+  {correct for the excess |min_quarterword| that was added}
+
+@<Make final adjustments...@>=
+if np>=7 then font_params[f]:=np@+else font_params[f]:=7;
+hyphen_char[f]:=default_hyphen_char; skew_char[f]:=default_skew_char;
+if bch_label<nl then bchar_label[f]:=bch_label+lig_kern_base[f]
+else bchar_label[f]:=non_address;
+font_bchar[f]:=qi(bchar);
+font_false_bchar[f]:=qi(bchar);
+if bchar<=ec then if bchar>=bc then
+  begin qw:=orig_char_info(f)(bchar); {N.B.: not |qi(bchar)|}
+  if char_exists(qw) then font_false_bchar[f]:=non_char;
+  end;
+font_name[f]:=nom;
+font_area[f]:=aire;
+font_bc[f]:=bc; font_ec[f]:=ec; font_glue[f]:=null;
+adjust(ctype_base);
+adjust(char_base); adjust(width_base); adjust(lig_kern_base);
+adjust(kern_base); adjust(exten_base);
+decr(param_base[f]);
+fmem_ptr:=fmem_ptr+lf; font_ptr:=f; g:=f; goto done
+
+@ Before we forget about the format of these tables, let's deal with two
+of \TeX's basic scanning routines related to font information.
+
+@<Declare procedures that scan font-related stuff@>=
+procedure scan_font_ident;
+var f:internal_font_number;
+@!m:halfword;
+begin @<Get the next non-blank non-call...@>;
+if cur_cmd=def_jfont then f:=cur_jfont
+else if cur_cmd=def_tfont then f:=cur_tfont
+else if cur_cmd=def_font then f:=cur_font
+else if cur_cmd=set_font then f:=cur_chr
+else if cur_cmd=def_family then
+  begin m:=cur_chr; scan_four_bit_int; f:=equiv(m+cur_val);
+  end
+else  begin print_err("Missing font identifier");
+@.Missing font identifier@>
+  help2("I was looking for a control sequence whose")@/
+  ("current meaning has been defined by \font.");
+  back_error; f:=null_font;
+  end;
+cur_val:=f;
+end;
+
+@ The following routine is used to implement `\.{\\fontdimen} |n| |f|'.
+The boolean parameter |writing| is set |true| if the calling program
+intends to change the parameter value.
+
+@<Declare procedures that scan font-related stuff@>=
+procedure find_font_dimen(@!writing:boolean);
+  {sets |cur_val| to |font_info| location}
+var f:internal_font_number;
+@!n:integer; {the parameter number}
+begin scan_int; n:=cur_val; scan_font_ident; f:=cur_val;
+if n<=0 then cur_val:=fmem_ptr
+else  begin if writing and(n<=space_shrink_code)and@|
+    (n>=space_code)and(font_glue[f]<>null) then
+    begin delete_glue_ref(font_glue[f]);
+    font_glue[f]:=null;
+    end;
+  if n>font_params[f] then
+    if f<font_ptr then cur_val:=fmem_ptr
+    else @<Increase the number of parameters in the last font@>
+  else cur_val:=n+param_base[f];
+  end;
+@<Issue an error message if |cur_val=fmem_ptr|@>;
+end;
+
+@ @<Issue an error message if |cur_val=fmem_ptr|@>=
+if cur_val=fmem_ptr then
+  begin print_err("Font "); print_esc(font_id_text(f));
+  print(" has only "); print_int(font_params[f]);
+  print(" fontdimen parameters");
+@.Font x has only...@>
+  help2("To increase the number of font parameters, you must")@/
+    ("use \fontdimen immediately after the \font is loaded.");
+  error;
+  end
+
+@ @<Increase the number of parameters...@>=
+begin repeat if fmem_ptr=font_mem_size then
+  overflow("font memory",font_mem_size);
+@:TeX capacity exceeded font memory}{\quad font memory@>
+font_info[fmem_ptr].sc:=0; incr(fmem_ptr); incr(font_params[f]);
+until n=font_params[f];
+cur_val:=fmem_ptr-1; {this equals |param_base[f]+font_params[f]|}
+end
+
+@ When \TeX\ wants to typeset a character that doesn't exist, the
+character node is not created; thus the output routine can assume
+that characters exist when it sees them. The following procedure
+prints a warning message unless the user has suppressed it.
+
+@d print_lc_hex(#)==l:=#;
+  if l<10 then print_char(l+"0")@+else print_char(l-10+"a")
+
+@p procedure char_warning(@!f:internal_font_number;@!c:eight_bits);
+var @!l:0..255; {small indices or counters}
+begin if tracing_lost_chars>0 then
+  begin begin_diagnostic;
+  print_nl("Missing character: There is no ");
+@.Missing character@>
+  if (c<" ")or(c>"~") then
+    begin print_char("^"); print_char("^");
+    if c<64 then print_char(c+64)
+    else if c<128 then print_char(c-64)
+    else begin print_lc_hex(c div 16);  print_lc_hex(c mod 16); end
+    end
+  else print_ASCII(c);
+  print(" in font ");
+  slow_print(font_name[f]); print_char("!"); end_diagnostic(false);
+  end;
+end;
+
+@ Here is a function that returns a pointer to a character node for a
+given character in a given font. If that character doesn't exist,
+|null| is returned instead.
+
+
+This allows a character node to be used if there is an equivalent
+in the |char_sub_code| list.
+
+@p function new_character(@!f:internal_font_number;@!c:eight_bits):pointer;
+label exit;
+var p:pointer; {newly allocated node}
+@!ec:quarterword;  {effective character of |c|}
+begin ec:=effective_char(false,f,qi(c));
+if font_bc[f]<=qo(ec) then if font_ec[f]>=qo(ec) then
+  if char_exists(orig_char_info(f)(ec)) then  {N.B.: not |char_info|}
+    begin p:=get_avail; font(p):=f; character(p):=qi(c);
+    new_character:=p; return;
+    end;
+char_warning(f,c);
+new_character:=null;
+exit:end;
+
+@* \[31] Device-independent file format.
+The most important output produced by a run of \TeX\ is the ``device
+independent'' (\.{DVI}) file that specifies where characters and rules
+are to appear on printed pages. The form of these files was designed by
+David R. Fuchs in 1979. Almost any reasonable typesetting device can be
+@^Fuchs, David Raymond@>
+@:DVI_files}{\.{DVI} files@>
+driven by a program that takes \.{DVI} files as input, and dozens of such
+\.{DVI}-to-whatever programs have been written. Thus, it is possible to
+print the output of \TeX\ on many different kinds of equipment, using \TeX\
+as a device-independent ``front end.''
+
+A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a
+series of commands in a machine-like language. The first byte of each command
+is the operation code, and this code is followed by zero or more bytes
+that provide parameters to the command. The parameters themselves may consist
+of several consecutive bytes; for example, the `|set_rule|' command has two
+parameters, each of which is four bytes long. Parameters are usually
+regarded as nonnegative integers; but four-byte-long parameters,
+and shorter parameters that denote distances, can be
+either positive or negative. Such parameters are given in two's complement
+notation. For example, a two-byte-long distance parameter has a value between
+$-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy
+more than one byte position appear in BigEndian order.
+
+A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one
+or more ``pages,'' followed by a ``postamble.'' The preamble is simply a
+|pre| command, with its parameters that define the dimensions used in the
+file; this must come first.  Each ``page'' consists of a |bop| command,
+followed by any number of other commands that tell where characters are to
+be placed on a physical page, followed by an |eop| command. The pages
+appear in the order that \TeX\ generated them. If we ignore |nop| commands
+and \\{fnt\_def} commands (which are allowed between any two commands in
+the file), each |eop| command is immediately followed by a |bop| command,
+or by a |post| command; in the latter case, there are no more pages in the
+file, and the remaining bytes form the postamble.  Further details about
+the postamble will be explained later.
+
+Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
+quantities that give the location number of some other byte in the file;
+the first byte is number~0, then comes number~1, and so on. For example,
+one of the parameters of a |bop| command points to the previous |bop|;
+this makes it feasible to read the pages in backwards order, in case the
+results are being directed to a device that stacks its output face up.
+Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the
+first page occupies bytes 100 to 999, say, and if the second
+page occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000
+points to 100 and the |bop| that starts in byte 2000 points to 1000. (The
+very first |bop|, i.e., the one starting in byte 100, has a pointer of~$-1$.)
+
+@ The \.{DVI} format is intended to be both compact and easily interpreted
+by a machine. Compactness is achieved by making most of the information
+implicit instead of explicit. When a \.{DVI}-reading program reads the
+commands for a page, it keeps track of several quantities: (a)~The current
+font |f| is an integer; this value is changed only
+by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page
+is given by two numbers called the horizontal and vertical coordinates,
+|h| and |v|. Both coordinates are zero at the upper left corner of the page;
+moving to the right corresponds to increasing the horizontal coordinate, and
+moving down corresponds to increasing the vertical coordinate. Thus, the
+coordinates are essentially Cartesian, except that vertical directions are
+flipped; the Cartesian version of |(h,v)| would be |(h,-v)|.  (c)~The
+current spacing amounts are given by four numbers |w|, |x|, |y|, and |z|,
+where |w| and~|x| are used for horizontal spacing and where |y| and~|z|
+are used for vertical spacing. (d)~There is a stack containing
+|(h,v,w,x,y,z)| values; the \.{DVI} commands |push| and |pop| are used to
+change the current level of operation. Note that the current font~|f| is
+not pushed and popped; the stack contains only information about
+positioning.
+
+The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up
+to 32 bits, including the sign. Since they represent physical distances,
+there is a small unit of measurement such that increasing |h| by~1 means
+moving a certain tiny distance to the right. The actual unit of
+measurement is variable, as explained below; \TeX\ sets things up so that
+its \.{DVI} output is in sp units, i.e., scaled points, in agreement with
+all the |scaled| dimensions in \TeX's data structures.
+
+@ Here is a list of all the commands that may appear in a \.{DVI} file. Each
+command is specified by its symbolic name (e.g., |bop|), its opcode byte
+(e.g., 139), and its parameters (if any). The parameters are followed
+by a bracketed number telling how many bytes they occupy; for example,
+`|p[4]|' means that parameter |p| is four bytes long.
+
+\yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f|
+such that the reference point of the character is at |(h,v)|. Then
+increase |h| by the width of that character. Note that a character may
+have zero or negative width, so one cannot be sure that |h| will advance
+after this command; but |h| usually does increase.
+
+\yskip\hang\\{set\_char\_1} through \\{set\_char\_127} (opcodes 1 to 127).
+Do the operations of |set_char_0|; but use the character whose number
+matches the opcode, instead of character~0.
+
+\yskip\hang|set1| 128 |c[1]|. Same as |set_char_0|, except that character
+number~|c| is typeset. \TeX82 uses this command for characters in the
+range |128<=c<256|.
+
+\yskip\hang|@!set2| 129 |c[2]|. Same as |set1|, except that |c|~is two
+bytes long, so it is in the range |0<=c<65536|. \TeX82 never uses this
+command, but it should come in handy for extensions of \TeX\ that deal
+with oriental languages.
+@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
+
+\yskip\hang|@!set3| 130 |c[3]|. Same as |set1|, except that |c|~is three
+bytes long, so it can be as large as $2^{24}-1$. Not even the Chinese
+language has this many characters, but this command might prove useful
+in some yet unforeseen extension.
+
+\yskip\hang|@!set4| 131 |c[4]|. Same as |set1|, except that |c|~is four
+bytes long. Imagine that.
+
+\yskip\hang|set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle
+of height~|a| and width~|b|, with its bottom left corner at |(h,v)|. Then
+set |h:=h+b|. If either |a<=0| or |b<=0|, nothing should be typeset. Note
+that if |b<0|, the value of |h| will decrease even though nothing else happens.
+See below for details about how to typeset rules so that consistency with
+\MF\ is guaranteed.
+
+\yskip\hang|@!put1| 133 |c[1]|. Typeset character number~|c| from font~|f|
+such that the reference point of the character is at |(h,v)|. (The `put'
+commands are exactly like the `set' commands, except that they simply put out a
+character or a rule without moving the reference point afterwards.)
+
+\yskip\hang|@!put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.
+
+\yskip\hang|@!put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.
+
+\yskip\hang|@!put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.
+
+\yskip\hang|put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that
+|h| is not changed.
+
+\yskip\hang|nop| 138. No operation, do nothing. Any number of |nop|'s
+may occur between \.{DVI} commands, but a |nop| cannot be inserted between
+a command and its parameters or between two parameters.
+
+\yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning
+of a page: Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set
+the current font |f| to an undefined value.  The ten $c_i$ parameters hold
+the values of \.{\\count0} $\ldots$ \.{\\count9} in \TeX\ at the time
+\.{\\shipout} was invoked for this page; they can be used to identify
+pages, if a user wants to print only part of a \.{DVI} file. The parameter
+|p| points to the previous |bop| in the file; the first
+|bop| has $p=-1$.
+
+\yskip\hang|eop| 140.  End of page: Print what you have read since the
+previous |bop|. At this point the stack should be empty. (The \.{DVI}-reading
+programs that drive most output devices will have kept a buffer of the
+material that appears on the page that has just ended. This material is
+largely, but not entirely, in order by |v| coordinate and (for fixed |v|) by
+|h|~coordinate; so it usually needs to be sorted into some order that is
+appropriate for the device in question.)
+
+\yskip\hang|push| 141. Push the current values of |(h,v,w,x,y,z)| onto the
+top of the stack; do not change any of these values. Note that |f| is
+not pushed.
+
+\yskip\hang|pop| 142. Pop the top six values off of the stack and assign
+them respectively to |(h,v,w,x,y,z)|. The number of pops should never
+exceed the number of pushes, since it would be highly embarrassing if the
+stack were empty at the time of a |pop| command.
+
+\yskip\hang|right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units.
+The parameter is a signed number in two's complement notation, |-128<=b<128|;
+if |b<0|, the reference point moves left.
+
+\yskip\hang|right2| 144 |b[2]|. Same as |right1|, except that |b| is a
+two-byte quantity in the range |-32768<=b<32768|.
+
+\yskip\hang|right3| 145 |b[3]|. Same as |right1|, except that |b| is a
+three-byte quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+
+\yskip\hang|right4| 146 |b[4]|. Same as |right1|, except that |b| is a
+four-byte quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+
+\yskip\hang|w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck,
+this parameterless command will usually suffice, because the same kind of motion
+will occur several times in succession; the following commands explain how
+|w| gets particular values.
+
+\yskip\hang|w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a
+signed quantity in two's complement notation, |-128<=b<128|. This command
+changes the current |w|~spacing and moves right by |b|.
+
+\yskip\hang|@!w2| 149 |b[2]|. Same as |w1|, but |b| is two bytes long,
+|-32768<=b<32768|.
+
+\yskip\hang|@!w3| 150 |b[3]|. Same as |w1|, but |b| is three bytes long,
+|@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+
+\yskip\hang|@!w4| 151 |b[4]|. Same as |w1|, but |b| is four bytes long,
+|@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+
+\yskip\hang|x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|'
+commands are like the `|w|' commands except that they involve |x| instead
+of |w|.
+
+\yskip\hang|x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a
+signed quantity in two's complement notation, |-128<=b<128|. This command
+changes the current |x|~spacing and moves right by |b|.
+
+\yskip\hang|@!x2| 154 |b[2]|. Same as |x1|, but |b| is two bytes long,
+|-32768<=b<32768|.
+
+\yskip\hang|@!x3| 155 |b[3]|. Same as |x1|, but |b| is three bytes long,
+|@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+
+\yskip\hang|@!x4| 156 |b[4]|. Same as |x1|, but |b| is four bytes long,
+|@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+
+\yskip\hang|down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units.
+The parameter is a signed number in two's complement notation, |-128<=a<128|;
+if |a<0|, the reference point moves up.
+
+\yskip\hang|@!down2| 158 |a[2]|. Same as |down1|, except that |a| is a
+two-byte quantity in the range |-32768<=a<32768|.
+
+\yskip\hang|@!down3| 159 |a[3]|. Same as |down1|, except that |a| is a
+three-byte quantity in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+
+\yskip\hang|@!down4| 160 |a[4]|. Same as |down1|, except that |a| is a
+four-byte quantity in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+
+\yskip\hang|y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck,
+this parameterless command will usually suffice, because the same kind of motion
+will occur several times in succession; the following commands explain how
+|y| gets particular values.
+
+\yskip\hang|y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a
+signed quantity in two's complement notation, |-128<=a<128|. This command
+changes the current |y|~spacing and moves down by |a|.
+
+\yskip\hang|@!y2| 163 |a[2]|. Same as |y1|, but |a| is two bytes long,
+|-32768<=a<32768|.
+
+\yskip\hang|@!y3| 164 |a[3]|. Same as |y1|, but |a| is three bytes long,
+|@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+
+\yskip\hang|@!y4| 165 |a[4]|. Same as |y1|, but |a| is four bytes long,
+|@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+
+\yskip\hang|z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands
+are like the `|y|' commands except that they involve |z| instead of |y|.
+
+\yskip\hang|z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a
+signed quantity in two's complement notation, |-128<=a<128|. This command
+changes the current |z|~spacing and moves down by |a|.
+
+\yskip\hang|@!z2| 168 |a[2]|. Same as |z1|, but |a| is two bytes long,
+|-32768<=a<32768|.
+
+\yskip\hang|@!z3| 169 |a[3]|. Same as |z1|, but |a| is three bytes long,
+|@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+
+\yskip\hang|@!z4| 170 |a[4]|. Same as |z1|, but |a| is four bytes long,
+|@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+
+\yskip\hang|fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been
+defined by a \\{fnt\_def} instruction, as explained below.
+
+\yskip\hang\\{fnt\_num\_1} through \\{fnt\_num\_63} (opcodes 172 to 234). Set
+|f:=1|, \dots, \hbox{|f:=63|}, respectively.
+
+\yskip\hang|fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font
+numbers in the range |64<=k<256|.
+
+\yskip\hang|@!fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two
+bytes long, so it is in the range |0<=k<65536|. \TeX82 never generates this
+command, but large font numbers may prove useful for specifications of
+color or texture, or they may be used for special fonts that have fixed
+numbers in some external coding scheme.
+
+\yskip\hang|@!fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three
+bytes long, so it can be as large as $2^{24}-1$.
+
+\yskip\hang|@!fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four
+bytes long; this is for the really big font numbers (and for the negative ones).
+
+\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
+general; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading
+programs are being used. \TeX82 generates |xxx1| when a short enough
+\.{\\special} appears, setting |k| to the number of bytes being sent. It
+is recommended that |x| be a string having the form of a keyword followed
+by possible parameters relevant to that keyword.
+
+\yskip\hang|@!xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
+
+\yskip\hang|@!xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
+
+\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously
+large. \TeX82 uses |xxx4| when sending a string of length 256 or more.
+
+\yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0<=k<256|; font definitions will be explained shortly.
+
+\yskip\hang|@!fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0<=k<65536|.
+
+\yskip\hang|@!fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0<=k<@t$2^{24}$@>|.
+
+\yskip\hang|@!fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|.
+
+\yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
+Beginning of the preamble; this must come at the very beginning of the
+file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.
+
+\yskip\hang|post| 248. Beginning of the postamble, see below.
+
+\yskip\hang|post_post| 249. Ending of the postamble, see below.
+
+\yskip\noindent Commands 250--255 are undefined at the present time.
+
+@ @d set_char_0=0 {typeset character 0 and move right}
+@d set1=128 {typeset a character and move right}
+@d set2=129 {typeset a character and move right}
+@d set_rule=132 {typeset a rule and move right}
+@d put_rule=137 {typeset a rule}
+@d nop=138 {no operation}
+@d bop=139 {beginning of page}
+@d eop=140 {ending of page}
+@d push=141 {save the current positions}
+@d pop=142 {restore previous positions}
+@d right1=143 {move right}
+@d w0=147 {move right by |w|}
+@d w1=148 {move right and set |w|}
+@d x0=152 {move right by |x|}
+@d x1=153 {move right and set |x|}
+@d down1=157 {move down}
+@d y0=161 {move down by |y|}
+@d y1=162 {move down and set |y|}
+@d z0=166 {move down by |z|}
+@d z1=167 {move down and set |z|}
+@d fnt_num_0=171 {set current font to 0}
+@d fnt1=235 {set current font}
+@d xxx1=239 {extension to \.{DVI} primitives}
+@d xxx4=242 {potentially long extension to \.{DVI} primitives}
+@d fnt_def1=243 {define the meaning of a font number}
+@d pre=247 {preamble}
+@d post=248 {postamble beginning}
+@d post_post=249 {postamble ending}
+@d dirchg=255 {direction change}
+
+@ The preamble contains basic information about the file as a whole. As
+stated above, there are six parameters:
+$$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
+The |i| byte identifies \.{DVI} format; currently this byte is always set
+to~2. (The value |i=3| is currently used for an extended format that
+allows a mixture of right-to-left and left-to-right typesetting.
+Some day we will set |i=4|, when \.{DVI} format makes another
+incompatible change---perhaps in the year 2048.)
+
+The next two parameters, |num| and |den|, are positive integers that define
+the units of measurement; they are the numerator and denominator of a
+fraction by which all dimensions in the \.{DVI} file could be multiplied
+in order to get lengths in units of $10^{-7}$ meters. Since $\rm 7227{pt} =
+254{cm}$, and since \TeX\ works with scaled points where there are $2^{16}$
+sp in a point, \TeX\ sets
+$|num|/|den|=(254\cdot10^5)/(7227\cdot2^{16})=25400000/473628672$.
+@^sp@>
+
+The |mag| parameter is what \TeX\ calls \.{\\mag}, i.e., 1000 times the
+desired magnification. The actual fraction by which dimensions are
+multiplied is therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\
+source document does not call for any `\.{true}' dimensions, and if you
+change it only by specifying a different \.{\\mag} setting, the \.{DVI}
+file that \TeX\ creates will be completely unchanged except for the value
+of |mag| in the preamble and postamble. (Fancy \.{DVI}-reading programs allow
+users to override the |mag|~setting when a \.{DVI} file is being printed.)
+
+Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
+interpreted further. The length of comment |x| is |k|, where |0<=k<256|.
+
+@d id_byte=2 {identifies the kind of \.{DVI} files described here}
+@d ex_id_byte=3 {identifies the kind of extended \.{DVI} files}
+
+@ Font definitions for a given font number |k| contain further parameters
+$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$
+The four-byte value |c| is the check sum that \TeX\ found in the \.{TFM}
+file for this font; |c| should match the check sum of the font found by
+programs that read this \.{DVI} file.
+@^check sum@>
+
+Parameter |s| contains a fixed-point scale factor that is applied to
+the character widths in font |k|; font dimensions in \.{TFM} files and
+other font files are relative to this quantity, which is called the
+``at size'' elsewhere in this documentation. The value of |s| is
+always positive and less than $2^{27}$. It is given in the same units
+as the other \.{DVI} dimensions, i.e., in sp when \TeX82 has made the
+file.  Parameter |d| is similar to |s|; it is the ``design size,'' and
+(like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be used
+at $|mag|\cdot s/1000d$ times its normal size.
+
+The remaining part of a font definition gives the external name of the font,
+which is an ASCII string of length |a+l|. The number |a| is the length
+of the ``area'' or directory, and |l| is the length of the font name itself;
+the standard local system font area is supposed to be used when |a=0|.
+The |n| field contains the area in its first |a| bytes.
+
+Font definitions must appear before the first use of a particular font number.
+Once font |k| is defined, it must not be defined again; however, we
+shall see below that font definitions appear in the postamble as well as
+in the pages, so in this sense each font number is defined exactly twice,
+if at all. Like |nop| commands, font definitions can
+appear before the first |bop|, or between an |eop| and a |bop|.
+
+@ Sometimes it is desirable to make horizontal or vertical rules line up
+precisely with certain features in characters of a font. It is possible to
+guarantee the correct matching between \.{DVI} output and the characters
+generated by \MF\ by adhering to the following principles: (1)~The \MF\
+characters should be positioned so that a bottom edge or left edge that is
+supposed to line up with the bottom or left edge of a rule appears at the
+reference point, i.e., in row~0 and column~0 of the \MF\ raster. This
+ensures that the position of the rule will not be rounded differently when
+the pixel size is not a perfect multiple of the units of measurement in
+the \.{DVI} file. (2)~A typeset rule of height $a>0$ and width $b>0$
+should be equivalent to a \MF-generated character having black pixels in
+precisely those raster positions whose \MF\ coordinates satisfy
+|0<=x<@t$\alpha$@>b| and |0<=y<@t$\alpha$@>a|, where $\alpha$ is the number
+of pixels per \.{DVI} unit.
+@:METAFONT}{\MF@>
+@^alignment of rules with characters@>
+@^rules aligning with characters@>
+
+@ The last page in a \.{DVI} file is followed by `|post|'; this command
+introduces the postamble, which summarizes important facts that \TeX\ has
+accumulated about the file, making it possible to print subsets of the data
+with reasonable efficiency. The postamble has the form
+$$\vbox{\halign{\hbox{#\hfil}\cr
+  |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
+  $\langle\,$font definitions$\,\rangle$\cr
+  |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
+Here |p| is a pointer to the final |bop| in the file. The next three
+parameters, |num|, |den|, and |mag|, are duplicates of the quantities that
+appeared in the preamble.
+
+Parameters |l| and |u| give respectively the height-plus-depth of the tallest
+page and the width of the widest page, in the same units as other dimensions
+of the file. These numbers might be used by a \.{DVI}-reading program to
+position individual ``pages'' on large sheets of film or paper; however,
+the standard convention for output on normal size paper is to position each
+page so that the upper left-hand corner is exactly one inch from the left
+and the top. Experience has shown that it is unwise to design \.{DVI}-to-printer
+software that attempts cleverly to center the output; a fixed position of
+the upper left corner is easiest for users to understand and to work with.
+Therefore |l| and~|u| are often ignored.
+
+Parameter |s| is the maximum stack depth (i.e., the largest excess of
+|push| commands over |pop| commands) needed to process this file. Then
+comes |t|, the total number of pages (|bop| commands) present.
+
+The postamble continues with font definitions, which are any number of
+\\{fnt\_def} commands as described above, possibly interspersed with |nop|
+commands. Each font number that is used in the \.{DVI} file must be defined
+exactly twice: Once before it is first selected by a \\{fnt} command, and once
+in the postamble.
+
+@ The last part of the postamble, following the |post_post| byte that
+signifies the end of the font definitions, contains |q|, a pointer to the
+|post| command that started the postamble.  An identification byte, |i|,
+comes next; this equals~2 or~3. If not used p\TeX primitives then the
+identification byte equals~2, othercase this is set to~3.
+
+The |i| byte is followed by four or more bytes that are all equal to
+the decimal number 223 (i.e., @'337 in octal). \TeX\ puts out four to seven of
+these trailing bytes, until the total length of the file is a multiple of
+four bytes, since this works out best on machines that pack four bytes per
+word; but any number of 223's is allowed, as long as there are at least four
+of them. In effect, 223 is a sort of signature that is added at the very end.
+@^Fuchs, David Raymond@>
+
+This curious way to finish off a \.{DVI} file makes it feasible for
+\.{DVI}-reading programs to find the postamble first, on most computers,
+even though \TeX\ wants to write the postamble last. Most operating
+systems permit random access to individual words or bytes of a file, so
+the \.{DVI} reader can start at the end and skip backwards over the 223's
+until finding the identification byte. Then it can back up four bytes, read
+|q|, and move to byte |q| of the file. This byte should, of course,
+contain the value 248 (|post|); now the postamble can be read, so the
+\.{DVI} reader can discover all the information needed for typesetting the
+pages. Note that it is also possible to skip through the \.{DVI} file at
+reasonably high speed to locate a particular page, if that proves
+desirable. This saves a lot of time, since \.{DVI} files used in production
+jobs tend to be large.
+
+Unfortunately, however, standard \PASCAL\ does not include the ability to
+@^system dependencies@>
+access a random position in a file, or even to determine the length of a file.
+Almost all systems nowadays provide the necessary capabilities, so \.{DVI}
+format has been designed to work most efficiently with modern operating systems.
+But if \.{DVI} files have to be processed under the restrictions of standard
+\PASCAL, one can simply read them from front to back, since the necessary
+header information is present in the preamble and in the font definitions.
+(The |l| and |u| and |s| and |t| parameters, which appear only in the
+postamble, are ``frills'' that are handy but not absolutely necessary.)
+
+@* \[32] Shipping pages out.
+After considering \TeX's eyes and stomach, we come now to the bowels.
+@^bowels@>
+
+The |ship_out| procedure is given a pointer to a box; its mission is
+to describe that box in \.{DVI} form, outputting a ``page'' to |dvi_file|.
+The \.{DVI} coordinates $(h,v)=(0,0)$ should correspond to the upper left
+corner of the box being shipped.
+
+Since boxes can be inside of boxes inside of boxes, the main work of
+|ship_out| is done by two mutually recursive routines, |hlist_out|
+and |vlist_out|, which traverse the hlists and vlists inside of horizontal
+and vertical boxes.
+
+As individual pages are being processed, we need to accumulate
+information about the entire set of pages, since such statistics must be
+reported in the postamble. The global variables |total_pages|, |max_v|,
+|max_h|, |max_push|, and |last_bop| are used to record this information.
+
+The variable |doing_leaders| is |true| while leaders are being output.
+The variable |dead_cycles| contains the number of times an output routine
+has been initiated since the last |ship_out|.
+
+A few additional global variables are also defined here for use in
+|vlist_out| and |hlist_out|. They could have been local variables, but
+that would waste stack space when boxes are deeply nested, since the
+values of these variables are not needed during recursive calls.
+@^recursion@>
+
+@<Glob...@>=
+@!total_pages:integer; {the number of pages that have been shipped out}
+@!max_v:scaled; {maximum height-plus-depth of pages shipped so far}
+@!max_h:scaled; {maximum width of pages shipped so far}
+@!max_push:integer; {deepest nesting of |push| commands encountered so far}
+@!last_bop:integer; {location of previous |bop| in the \.{DVI} output}
+@!dead_cycles:integer; {recent outputs that didn't ship anything out}
+@!doing_leaders:boolean; {are we inside a leader box?}
+@#
+ {character and font in current |char_node|}
+@!c:quarterword;
+@!f:internal_font_number;
+@!dir_used:boolean; {Is this dvi extended?}
+@!rule_ht,@!rule_dp,@!rule_wd:scaled; {size of current rule being output}
+@!g:pointer; {current glue specification}
+@!lq,@!lr:integer; {quantities used in calculations for leaders}
+
+@ @<Set init...@>=
+total_pages:=0; max_v:=0; max_h:=0; max_push:=0; last_bop:=-1;
+doing_leaders:=false; dead_cycles:=0; cur_s:=-1; dir_used:=false;
+
+@ The \.{DVI} bytes are output to a buffer instead of being written directly
+to the output file. This makes it possible to reduce the overhead of
+subroutine calls, thereby measurably speeding up the computation, since
+output of \.{DVI} bytes is part of \TeX's inner loop. And it has another
+advantage as well, since we can change instructions in the buffer in order to
+make the output more compact. For example, a `|down2|' command can be
+changed to a `|y2|', thereby making a subsequent `|y0|' command possible,
+saving two bytes.
+
+The output buffer is divided into two parts of equal size; the bytes found
+in |dvi_buf[0..half_buf-1]| constitute the first half, and those in
+|dvi_buf[half_buf..dvi_buf_size-1]| constitute the second. The global
+variable |dvi_ptr| points to the position that will receive the next
+output byte. When |dvi_ptr| reaches |dvi_limit|, which is always equal
+to one of the two values |half_buf| or |dvi_buf_size|, the half buffer that
+is about to be invaded next is sent to the output and |dvi_limit| is
+changed to its other value. Thus, there is always at least a half buffer's
+worth of information present, except at the very beginning of the job.
+
+Bytes of the \.{DVI} file are numbered sequentially starting with 0;
+the next byte to be generated will be number |dvi_offset+dvi_ptr|.
+A byte is present in the buffer only if its number is |>=dvi_gone|.
+
+@<Types...@>=
+@!dvi_index=0..dvi_buf_size; {an index into the output buffer}
+
+@ Some systems may find it more efficient to make |dvi_buf| a |packed|
+array, since output of four bytes at once may be facilitated.
+@^system dependencies@>
+
+@<Glob...@>=
+@!dvi_buf:^eight_bits; {buffer for \.{DVI} output}
+@!half_buf:integer; {half of |dvi_buf_size|}
+@!dvi_limit:integer; {end of the current half buffer}
+@!dvi_ptr:integer; {the next available buffer address}
+@!dvi_offset:integer; {|dvi_buf_size| times the number of times the
+  output buffer has been fully emptied}
+@!dvi_gone:integer; {the number of bytes already output to |dvi_file|}
+
+@ Initially the buffer is all in one piece; we will output half of it only
+after it first fills up.
+
+@<Set init...@>=
+half_buf:=dvi_buf_size div 2; dvi_limit:=dvi_buf_size; dvi_ptr:=0;
+dvi_offset:=0; dvi_gone:=0;
+
+@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
+|write_dvi(a,b)|. For best results, this procedure should be optimized to
+run as fast as possible on each particular system, since it is part of
+\TeX's inner loop. It is safe to assume that |a| and |b+1| will both be
+multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on
+many machines to use efficient methods to pack four bytes per word and to
+output an array of words with one system call.
+@^system dependencies@>
+@^inner loop@>
+@^defecation@>
+
+In C, we use a macro to call |fwrite| or |write| directly, writing all
+the bytes in one shot.  Much better even than writing four
+bytes at a time.
+
+@ To put a byte in the buffer without paying the cost of invoking a procedure
+each time, we use the macro |dvi_out|.
+
+The length of |dvi_file| should not exceed |@"7FFFFFFF|; we set |cur_s:=-2|
+to prevent further \.{DVI} output causing infinite recursion.
+
+@d dvi_out(#)==@+begin dvi_buf[dvi_ptr]:=#; incr(dvi_ptr);
+  if dvi_ptr=dvi_limit then dvi_swap;
+  end
+
+@p procedure dvi_swap; {outputs half of the buffer}
+begin if dvi_ptr>(@"7FFFFFFF-dvi_offset) then
+  begin cur_s:=-2;
+  fatal_error("dvi length exceeds ""7FFFFFFF");
+@.dvi length exceeds...@>
+  end;
+if dvi_limit=dvi_buf_size then
+  begin write_dvi(0,half_buf-1); dvi_limit:=half_buf;
+  dvi_offset:=dvi_offset+dvi_buf_size; dvi_ptr:=0;
+  end
+else  begin write_dvi(half_buf,dvi_buf_size-1); dvi_limit:=dvi_buf_size;
+  end;
+dvi_gone:=dvi_gone+half_buf;
+end;
+
+@ Here is how we clean out the buffer when \TeX\ is all through; |dvi_ptr|
+will be a multiple of~4.
+
+@<Empty the last bytes out of |dvi_buf|@>=
+if dvi_limit=half_buf then write_dvi(half_buf,dvi_buf_size-1);
+if dvi_ptr>(@"7FFFFFFF-dvi_offset) then
+  begin cur_s:=-2;
+  fatal_error("dvi length exceeds ""7FFFFFFF");
+@.dvi length exceeds...@>
+  end;
+if dvi_ptr>0 then write_dvi(0,dvi_ptr-1)
+
+@ The |dvi_four| procedure outputs four bytes in two's complement notation,
+without risking arithmetic overflow.
+
+@p procedure dvi_four(@!x:integer);
+begin if x>=0 then dvi_out(x div @'100000000)
+else  begin x:=x+@'10000000000;
+  x:=x+@'10000000000;
+  dvi_out((x div @'100000000) + 128);
+  end;
+x:=x mod @'100000000; dvi_out(x div @'200000);
+x:=x mod @'200000; dvi_out(x div @'400);
+dvi_out(x mod @'400);
+end;
+
+@ A mild optimization of the output is performed by the |dvi_pop|
+routine, which issues a |pop| unless it is possible to cancel a
+`|push| |pop|' pair. The parameter to |dvi_pop| is the byte address
+following the old |push| that matches the new |pop|.
+
+@p procedure dvi_pop(@!l:integer);
+begin if (l=dvi_offset+dvi_ptr)and(dvi_ptr>0) then decr(dvi_ptr)
+else dvi_out(pop);
+end;
+
+@ Here's a procedure that outputs a font definition. Since \TeX82 uses at
+most 256 different fonts per job, |fnt_def1| is always used as the command code.
+
+@p procedure dvi_font_def(@!f:internal_font_number);
+var k:pool_pointer; {index into |str_pool|}
+begin if f<=256+font_base then
+  begin dvi_out(fnt_def1);
+  dvi_out(f-font_base-1);
+  end
+else begin dvi_out(fnt_def1+1);
+  dvi_out((f-font_base-1) div @'400);
+  dvi_out((f-font_base-1) mod @'400);
+  end;
+dvi_out(qo(font_check[f].b0));
+dvi_out(qo(font_check[f].b1));
+dvi_out(qo(font_check[f].b2));
+dvi_out(qo(font_check[f].b3));@/
+dvi_four(font_size[f]);
+dvi_four(font_dsize[f]);@/
+dvi_out(length(font_area[f]));
+dvi_out(length(font_name[f]));
+@<Output the font name whose internal number is |f|@>;
+end;
+
+@ @<Output the font name whose internal number is |f|@>=
+for k:=str_start[font_area[f]] to str_start[font_area[f]+1]-1 do
+  dvi_out(so(str_pool[k]));
+for k:=str_start[font_name[f]] to str_start[font_name[f]+1]-1 do
+  dvi_out(so(str_pool[k]))
+
+@ Versions of \TeX\ intended for small computers might well choose to omit
+the ideas in the next few parts of this program, since it is not really
+necessary to optimize the \.{DVI} code by making use of the |w0|, |x0|,
+|y0|, and |z0| commands. Furthermore, the algorithm that we are about to
+describe does not pretend to give an optimum reduction in the length
+of the \.{DVI} code; after all, speed is more important than compactness.
+But the method is surprisingly effective, and it takes comparatively little
+time.
+
+We can best understand the basic idea by first considering a simpler problem
+that has the same essential characteristics. Given a sequence of digits,
+say $3\,1\,4\,1\,5\,9\,2\,6\,5\,3\,5\,8\,9$, we want to assign subscripts
+$d$, $y$, or $z$ to each digit so as to maximize the number of ``$y$-hits''
+and ``$z$-hits''; a $y$-hit is an instance of two appearances of the same
+digit with the subscript $y$, where no $y$'s intervene between the two
+appearances, and a $z$-hit is defined similarly. For example, the sequence
+above could be decorated with subscripts as follows:
+$$3_z\,1_y\,4_d\,1_y\,5_y\,9_d\,2_d\,6_d\,5_y\,3_z\,5_y\,8_d\,9_d.$$
+There are three $y$-hits ($1_y\ldots1_y$ and $5_y\ldots5_y\ldots5_y$) and
+one $z$-hit ($3_z\ldots3_z$); there are no $d$-hits, since the two appearances
+of $9_d$ have $d$'s between them, but we don't count $d$-hits so it doesn't
+matter how many there are. These subscripts are analogous to the \.{DVI}
+commands called \\{down}, $y$, and $z$, and the digits are analogous to
+different amounts of vertical motion; a $y$-hit or $z$-hit corresponds to
+the opportunity to use the one-byte commands |y0| or |z0| in a \.{DVI} file.
+
+\TeX's method of assigning subscripts works like this: Append a new digit,
+say $\delta$, to the right of the sequence. Now look back through the
+sequence until one of the following things happens: (a)~You see
+$\delta_y$ or $\delta_z$, and this was the first time you encountered a
+$y$ or $z$ subscript, respectively.  Then assign $y$ or $z$ to the new
+$\delta$; you have scored a hit. (b)~You see $\delta_d$, and no $y$
+subscripts have been encountered so far during this search.  Then change
+the previous $\delta_d$ to $\delta_y$ (this corresponds to changing a
+command in the output buffer), and assign $y$ to the new $\delta$; it's
+another hit.  (c)~You see $\delta_d$, and a $y$ subscript has been seen
+but not a $z$.  Change the previous $\delta_d$ to $\delta_z$ and assign
+$z$ to the new $\delta$. (d)~You encounter both $y$ and $z$ subscripts
+before encountering a suitable $\delta$, or you scan all the way to the
+front of the sequence. Assign $d$ to the new $\delta$; this assignment may
+be changed later.
+
+The subscripts $3_z\,1_y\,4_d\ldots\,$ in the example above were, in fact,
+produced by this procedure, as the reader can verify. (Go ahead and try it.)
+
+@ In order to implement such an idea, \TeX\ maintains a stack of pointers
+to the \\{down}, $y$, and $z$ commands that have been generated for the
+current page. And there is a similar stack for \\{right}, |w|, and |x|
+commands. These stacks are called the down stack and right stack, and their
+top elements are maintained in the variables |down_ptr| and |right_ptr|.
+
+Each entry in these stacks contains four fields: The |width| field is
+the amount of motion down or to the right; the |location| field is the
+byte number of the \.{DVI} command in question (including the appropriate
+|dvi_offset|); the |link| field points to the next item below this one
+on the stack; and the |info| field encodes the options for possible change
+in the \.{DVI} command.
+
+@d movement_node_size=3 {number of words per entry in the down and right stacks}
+@d location(#)==mem[#+2].int {\.{DVI} byte number for a movement command}
+
+@<Glob...@>=
+@!down_ptr,@!right_ptr:pointer; {heads of the down and right stacks}
+
+@ @<Set init...@>=
+down_ptr:=null; right_ptr:=null;
+
+@ Here is a subroutine that produces a \.{DVI} command for some specified
+downward or rightward motion. It has two parameters: |w| is the amount
+of motion, and |o| is either |down1| or |right1|. We use the fact that
+the command codes have convenient arithmetic properties: |y1-down1=w1-right1|
+and |z1-down1=x1-right1|.
+
+@p procedure movement(@!w:scaled;@!o:eight_bits);
+label exit,found,not_found,2,1;
+var mstate:small_number; {have we seen a |y| or |z|?}
+@!p,@!q:pointer; {current and top nodes on the stack}
+@!k:integer; {index into |dvi_buf|, modulo |dvi_buf_size|}
+begin q:=get_node(movement_node_size); {new node for the top of the stack}
+width(q):=w; location(q):=dvi_offset+dvi_ptr;
+if o=down1 then
+  begin link(q):=down_ptr; down_ptr:=q;
+  end
+else  begin link(q):=right_ptr; right_ptr:=q;
+  end;
+@<Look at the other stack entries until deciding what sort of \.{DVI} command
+  to generate; |goto found| if node |p| is a ``hit''@>;
+@<Generate a |down| or |right| command for |w| and |return|@>;
+found: @<Generate a |y0| or |z0| command in order to reuse a previous
+  appearance of~|w|@>;
+exit:end;
+
+@ The |info| fields in the entries of the down stack or the right stack
+have six possible settings: |y_here| or |z_here| mean that the \.{DVI}
+command refers to |y| or |z|, respectively (or to |w| or |x|, in the
+case of horizontal motion); |yz_OK| means that the \.{DVI} command is
+\\{down} (or \\{right}) but can be changed to either |y| or |z| (or
+to either |w| or |x|); |y_OK| means that it is \\{down} and can be changed
+to |y| but not |z|; |z_OK| is similar; and |d_fixed| means it must stay
+\\{down}.
+
+The four settings |yz_OK|, |y_OK|, |z_OK|, |d_fixed| would not need to
+be distinguished from each other if we were simply solving the
+digit-subscripting problem mentioned above. But in \TeX's case there is
+a complication because of the nested structure of |push| and |pop|
+commands. Suppose we add parentheses to the digit-subscripting problem,
+redefining hits so that $\delta_y\ldots \delta_y$ is a hit if all $y$'s between
+the $\delta$'s are enclosed in properly nested parentheses, and if the
+parenthesis level of the right-hand $\delta_y$ is deeper than or equal to
+that of the left-hand one. Thus, `(' and `)' correspond to `|push|'
+and `|pop|'. Now if we want to assign a subscript to the final 1 in the
+sequence
+$$2_y\,7_d\,1_d\,(\,8_z\,2_y\,8_z\,)\,1$$
+we cannot change the previous $1_d$ to $1_y$, since that would invalidate
+the $2_y\ldots2_y$ hit. But we can change it to $1_z$, scoring a hit
+since the intervening $8_z$'s are enclosed in parentheses.
+
+The program below removes movement nodes that are introduced after a |push|,
+before it outputs the corresponding |pop|.
+
+@d y_here=1 {|info| when the movement entry points to a |y| command}
+@d z_here=2 {|info| when the movement entry points to a |z| command}
+@d yz_OK=3 {|info| corresponding to an unconstrained \\{down} command}
+@d y_OK=4 {|info| corresponding to a \\{down} that can't become a |z|}
+@d z_OK=5 {|info| corresponding to a \\{down} that can't become a |y|}
+@d d_fixed=6 {|info| corresponding to a \\{down} that can't change}
+
+@ When the |movement| procedure gets to the label |found|, the value of
+|info(p)| will be either |y_here| or |z_here|. If it is, say, |y_here|,
+the procedure generates a |y0| command (or a |w0| command), and marks
+all |info| fields between |q| and |p| so that |y| is not OK in that range.
+
+@<Generate a |y0| or |z0| command...@>=
+info(q):=info(p);
+if info(q)=y_here then
+  begin dvi_out(o+y0-down1); {|y0| or |w0|}
+  while link(q)<>p do
+    begin q:=link(q);
+    case info(q) of
+    yz_OK: info(q):=z_OK;
+    y_OK: info(q):=d_fixed;
+    othercases do_nothing
+    endcases;
+    end;
+  end
+else  begin dvi_out(o+z0-down1); {|z0| or |x0|}
+  while link(q)<>p do
+    begin q:=link(q);
+    case info(q) of
+    yz_OK: info(q):=y_OK;
+    z_OK: info(q):=d_fixed;
+    othercases do_nothing
+    endcases;
+    end;
+  end
+
+@ @<Generate a |down| or |right|...@>=
+info(q):=yz_OK;
+if abs(w)>=@'40000000 then
+  begin dvi_out(o+3); {|down4| or |right4|}
+  dvi_four(w); return;
+  end;
+if abs(w)>=@'100000 then
+  begin dvi_out(o+2); {|down3| or |right3|}
+  if w<0 then w:=w+@'100000000;
+  dvi_out(w div @'200000); w:=w mod @'200000; goto 2;
+  end;
+if abs(w)>=@'200 then
+  begin dvi_out(o+1); {|down2| or |right2|}
+  if w<0 then w:=w+@'200000;
+  goto 2;
+  end;
+dvi_out(o); {|down1| or |right1|}
+if w<0 then w:=w+@'400;
+goto 1;
+2: dvi_out(w div @'400);
+1: dvi_out(w mod @'400); return
+
+@ As we search through the stack, we are in one of three states,
+|y_seen|, |z_seen|, or |none_seen|, depending on whether we have
+encountered |y_here| or |z_here| nodes. These states are encoded as
+multiples of 6, so that they can be added to the |info| fields for quick
+decision-making.
+@^inner loop@>
+
+@d none_seen=0 {no |y_here| or |z_here| nodes have been encountered yet}
+@d y_seen=6 {we have seen |y_here| but not |z_here|}
+@d z_seen=12 {we have seen |z_here| but not |y_here|}
+
+@<Look at the other stack entries until deciding...@>=
+p:=link(q); mstate:=none_seen;
+while p<>null do
+  begin if width(p)=w then @<Consider a node with matching width;
+    |goto found| if it's a hit@>
+  else  case mstate+info(p) of
+    none_seen+y_here: mstate:=y_seen;
+    none_seen+z_here: mstate:=z_seen;
+    y_seen+z_here,z_seen+y_here: goto not_found;
+    othercases do_nothing
+    endcases;
+  p:=link(p);
+  end;
+not_found:
+
+@ We might find a valid hit in a |y| or |z| byte that is already gone
+from the buffer. But we can't change bytes that are gone forever; ``the
+moving finger writes, $\ldots\,\,$.''
+
+@<Consider a node with matching width...@>=
+case mstate+info(p) of
+none_seen+yz_OK,none_seen+y_OK,z_seen+yz_OK,z_seen+y_OK:@t@>@;@/
+  if location(p)<dvi_gone then goto not_found
+  else @<Change buffered instruction to |y| or |w| and |goto found|@>;
+none_seen+z_OK,y_seen+yz_OK,y_seen+z_OK:@t@>@;@/
+  if location(p)<dvi_gone then goto not_found
+  else @<Change buffered instruction to |z| or |x| and |goto found|@>;
+none_seen+y_here,none_seen+z_here,y_seen+z_here,z_seen+y_here: goto found;
+othercases do_nothing
+endcases
+
+@ @<Change buffered instruction to |y| or |w| and |goto found|@>=
+begin k:=location(p)-dvi_offset;
+if k<0 then k:=k+dvi_buf_size;
+dvi_buf[k]:=dvi_buf[k]+y1-down1;
+info(p):=y_here; goto found;
+end
+
+@ @<Change buffered instruction to |z| or |x| and |goto found|@>=
+begin k:=location(p)-dvi_offset;
+if k<0 then k:=k+dvi_buf_size;
+dvi_buf[k]:=dvi_buf[k]+z1-down1;
+info(p):=z_here; goto found;
+end
+
+@ In case you are wondering when all the movement nodes are removed from
+\TeX's memory, the answer is that they are recycled just before
+|hlist_out| and |vlist_out| finish outputting a box. This restores the
+down and right stacks to the state they were in before the box was output,
+except that some |info|'s may have become more restrictive.
+
+@p procedure prune_movements(@!l:integer);
+  {delete movement nodes with |location>=l|}
+label done,exit;
+var p:pointer; {node being deleted}
+begin while down_ptr<>null do
+  begin if location(down_ptr)<l then goto done;
+  p:=down_ptr; down_ptr:=link(p); free_node(p,movement_node_size);
+  end;
+done: while right_ptr<>null do
+  begin if location(right_ptr)<l then return;
+  p:=right_ptr; right_ptr:=link(p); free_node(p,movement_node_size);
+  end;
+exit:end;
+
+@ The actual distances by which we want to move might be computed as the
+sum of several separate movements. For example, there might be several
+glue nodes in succession, or we might want to move right by the width of
+some box plus some amount of glue. More importantly, the baselineskip
+distances are computed in terms of glue together with the depth and
+height of adjacent boxes, and we want the \.{DVI} file to lump these
+three quantities together into a single motion.
+
+Therefore, \TeX\ maintains two pairs of global variables: |dvi_h| and |dvi_v|
+are the |h| and |v| coordinates corresponding to the commands actually
+output to the \.{DVI} file, while |cur_h| and |cur_v| are the coordinates
+corresponding to the current state of the output routines. Coordinate
+changes will accumulate in |cur_h| and |cur_v| without being reflected
+in the output, until such a change becomes necessary or desirable; we
+can call the |movement| procedure whenever we want to make |dvi_h=cur_h|
+or |dvi_v=cur_v|.
+
+The current font reflected in the \.{DVI} output is called |dvi_f|;
+there is no need for a `\\{cur\_f}' variable.
+
+The depth of nesting of |hlist_out| and |vlist_out| is called |cur_s|;
+this is essentially the depth of |push| commands in the \.{DVI} output.
+
+@d synch_h==if cur_h<>dvi_h then
+    begin movement(cur_h-dvi_h,right1); dvi_h:=cur_h;
+    end
+@d synch_v==if cur_v<>dvi_v then
+    begin movement(cur_v-dvi_v,down1); dvi_v:=cur_v;
+    end
+
+@<Glob...@>=
+@!dvi_h,@!dvi_v:scaled; {a \.{DVI} reader program thinks we are here}
+@!cur_h,@!cur_v:scaled; {\TeX\ thinks we are here}
+@!dvi_f:internal_font_number; {the current font}
+@!cur_s:integer; {current depth of output box nesting, initially $-1$}
+
+@ @<Initialize variables as |ship_out| begins@>=
+dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font;
+dvi_dir:=dir_yoko; cur_dir_hv:=dvi_dir;
+ensure_dvi_open;
+if total_pages=0 then
+  begin dvi_out(pre); dvi_out(id_byte); {output the preamble}
+@^preamble of \.{DVI} file@>
+  dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp}
+  prepare_mag; dvi_four(mag); {magnification factor is frozen}
+if output_comment then
+  begin l:=strlen(output_comment); dvi_out(l);
+  for s:=0 to l-1 do dvi_out(output_comment[s]);
+  end
+else begin {the default code is unchanged}
+  old_setting:=selector; selector:=new_string;
+  print(" TeX output "); print_int(year); print_char(".");
+  print_two(month); print_char("."); print_two(day);
+  print_char(":"); print_two(time div 60);
+  print_two(time mod 60);
+  selector:=old_setting; dvi_out(cur_length);
+  for s:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[s]));
+  pool_ptr:=str_start[str_ptr]; {flush the current string}
+end;
+  end
+
+@ When |hlist_out| is called, its duty is to output the box represented
+by the |hlist_node| pointed to by |temp_ptr|. The reference point of that
+box has coordinates |(cur_h,cur_v)|.
+
+Similarly, when |vlist_out| is called, its duty is to output the box represented
+by the |vlist_node| pointed to by |temp_ptr|. The reference point of that
+box has coordinates |(cur_h,cur_v)|.
+@^recursion@>
+
+@p procedure@?vlist_out; forward; {|hlist_out| and |vlist_out| are mutually
+  recursive}
+
+@ The recursive procedures |hlist_out| and |vlist_out| each have local variables
+|save_h| and |save_v| to hold the values of |dvi_h| and |dvi_v| just before
+entering a new level of recursion.  In effect, the values of |save_h| and
+|save_v| on \TeX's run-time stack correspond to the values of |h| and |v|
+that a \.{DVI}-reading program will push onto its coordinate stack.
+
+@d move_past=13 {go to this label when advancing past glue or a rule}
+@d fin_rule=14 {go to this label to finish processing a rule}
+@d next_p=15 {go to this label when finished with node |p|}
+
+@p @t\4@>@<Declare procedures needed in |hlist_out|, |vlist_out|@>@t@>@/
+procedure hlist_out; {output an |hlist_node| box}
+label reswitch, move_past, fin_rule, next_p, continue, found;
+var base_line: scaled; {the baseline coordinate for this box}
+@!disp: scaled; {displacement}
+@!save_dir:eight_bits; {what |dvi_dir| should pop to}
+@!jc:KANJI_code; {temporary register for KANJI codes}
+@!ksp_ptr:pointer; {position of |auto_spacing_glue| in the hlist}
+@!left_edge: scaled; {the left coordinate for this box}
+@!save_h,@!save_v: scaled; {what |dvi_h| and |dvi_v| should pop to}
+@!this_box: pointer; {pointer to containing box}
+@!g_order: glue_ord; {applicable order of infinity for glue}
+@!g_sign: normal..shrinking; {selects type of glue}
+@!p:pointer; {current position in the hlist}
+@!save_loc:integer; {\.{DVI} byte location upon entry}
+@!leader_box:pointer; {the leader box being replicated}
+@!leader_wd:scaled; {width of leader box being replicated}
+@!lx:scaled; {extra space between leader boxes}
+@!outer_doing_leaders:boolean; {were we doing leaders?}
+@!edge:scaled; {left edge of sub-box, or right edge of leader space}
+@!glue_temp:real; {glue value before rounding}
+@!cur_glue:real; {glue seen so far}
+@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio}
+begin cur_g:=0; cur_glue:=float_constant(0);
+this_box:=temp_ptr; g_order:=glue_order(this_box);
+g_sign:=glue_sign(this_box); p:=list_ptr(this_box);
+ksp_ptr:=space_ptr(this_box);
+incr(cur_s);
+if cur_s>0 then dvi_out(push);
+if cur_s>max_push then max_push:=cur_s;
+save_loc:=dvi_offset+dvi_ptr;
+synch_dir;
+base_line:=cur_v; left_edge:=cur_h; disp:=0;
+while p<>null do @<Output node |p| for |hlist_out| and move to the next node,
+  maintaining the condition |cur_v=base_line|@>;
+prune_movements(save_loc);
+if cur_s>0 then dvi_pop(save_loc);
+decr(cur_s);
+end;
+
+@ We ought to give special care to the efficiency of one part of |hlist_out|,
+since it belongs to \TeX's inner loop. When a |char_node| is encountered,
+we save a little time by processing several nodes in succession until
+reaching a non-|char_node|. The program uses the fact that |set_char_0=0|.
+
+In ML\TeX{} this part looks for the existence of a substitution
+definition for a character |c|, if |c| does not exist in the font,
+and create appropriate \.{DVI} commands.  Former versions of ML\TeX{}
+have spliced appropriate character, kern, and box nodes into the
+horizontal list.
+%
+% 91/05/08 \charsubdefmax bug detected by Bernd Raichle
+Because the user can change character substitions or
+\.{\\charsubdefmax} on the fly, we have to test a again
+for valid substitutions.
+%
+% 93/10/29 \leaders bug detected by Eberhard Mattes
+(Additional it is necessary to be careful---if leaders are used
+the current hlist is normally traversed more than once!)
+@^inner loop@>
+
+@<Output node |p| for |hlist_out|...@>=
+reswitch: if is_char_node(p) then
+  begin synch_h; synch_v;
+  chain:=false;
+  repeat f:=font(p); c:=character(p);
+  if f<>dvi_f then @<Change font |dvi_f| to |f|@>;
+  if font_dir[f]=dir_default then
+    begin chain:=false;
+    if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
+      if char_exists(orig_char_info(f)(c)) then  {N.B.: not |char_info|}
+        begin if c>=qi(128) then dvi_out(set1);
+        dvi_out(qo(c));@/
+        cur_h:=cur_h+char_width(f)(orig_char_info(f)(c));
+        goto continue;
+        end;
+    if mltex_enabled_p then
+      @<Output a substitution, |goto continue| if not possible@>;
+continue:
+    end
+  else
+    begin if chain=false then chain:=true
+    else begin cur_h:=cur_h+width(ksp_ptr);
+      if g_sign<>normal then
+        begin  if g_sign=stretching then
+          begin  if stretch_order(ksp_ptr)=g_order then
+            cur_h:=cur_h+round(float(glue_set(this_box))*stretch(ksp_ptr));
+@^real multiplication@>
+          end
+        else
+          begin  if shrink_order(ksp_ptr)=g_order then
+            cur_h:=cur_h-round(float(glue_set(this_box))*shrink(ksp_ptr));
+@^real multiplication@>
+          end;
+        end;
+      synch_h;
+      end;
+    p:=link(p);
+       jc:=toDVI(KANJI(info(p)));
+    dvi_out(set2); dvi_out(Hi(jc)); dvi_out(Lo(jc));
+    cur_h:=cur_h+char_width(f)(orig_char_info(f)(c)); {not |jc|}
+    end;
+  dvi_h:=cur_h; p:=link(p);
+  until not is_char_node(p);
+  chain:=false;
+  end
+else @<Output the non-|char_node| |p| for |hlist_out|
+    and move to the next node@>
+
+@ @<Change font |dvi_f| to |f|@>=
+begin if not font_used[f] then
+  begin dvi_font_def(f); font_used[f]:=true;
+  end;
+if f<=64+font_base then dvi_out(f-font_base-1+fnt_num_0)
+else if f<=256+font_base then
+  begin dvi_out(fnt1); dvi_out(f-font_base-1);
+  end
+else begin dvi_out(fnt1+1);
+  dvi_out((f-font_base-1) div @'400);
+  dvi_out((f-font_base-1) mod @'400);
+  end;
+dvi_f:=f;
+end
+
+@ @<Output the non-|char_node| |p| for |hlist_out|...@>=
+begin case type(p) of
+hlist_node,vlist_node,dir_node:@<Output a box in an hlist@>;
+rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p);
+  goto fin_rule;
+  end;
+whatsit_node: @<Output the whatsit node |p| in an hlist@>;
+disp_node: begin disp:=disp_dimen(p); cur_v:=base_line+disp; end;
+glue_node: @<Move right or output leaders@>;
+kern_node,math_node:cur_h:=cur_h+width(p);
+ligature_node: @<Make node |p| look like a |char_node| and |goto reswitch|@>;
+othercases do_nothing
+endcases;@/
+goto next_p;
+fin_rule: @<Output a rule in an hlist@>;
+move_past: cur_h:=cur_h+rule_wd;
+next_p:p:=link(p);
+end
+
+@ @<Output a box in an hlist@>=
+if list_ptr(p)=null then cur_h:=cur_h+width(p)
+else  begin save_h:=dvi_h; save_v:=dvi_v; save_dir:=dvi_dir;
+  cur_v:=base_line+disp+shift_amount(p); {shift the box down}
+  temp_ptr:=p; edge:=cur_h;
+  case type(p) of
+    hlist_node:hlist_out;
+    vlist_node:vlist_out;
+    dir_node:dir_out;
+  endcases;
+  dvi_h:=save_h; dvi_v:=save_v; dvi_dir:=save_dir;
+  cur_h:=edge+width(p); cur_v:=base_line+disp; cur_dir_hv:=save_dir;
+  end
+
+@ @<Output a rule in an hlist@>=
+if is_running(rule_ht) then rule_ht:=height(this_box)+disp;
+if is_running(rule_dp) then rule_dp:=depth(this_box)-disp;
+rule_ht:=rule_ht+rule_dp; {this is the rule thickness}
+if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules}
+  begin synch_h; cur_v:=base_line+rule_dp; synch_v;
+  dvi_out(set_rule); dvi_four(rule_ht); dvi_four(rule_wd);
+  cur_v:=base_line; dvi_h:=dvi_h+rule_wd;
+  end
+
+@ @d billion==float_constant(1000000000)
+@d vet_glue(#)== glue_temp:=#;
+  if glue_temp>billion then
+           glue_temp:=billion
+  else if glue_temp<-billion then
+           glue_temp:=-billion
+
+@<Move right or output leaders@>=
+begin g:=glue_ptr(p); rule_wd:=width(g)-cur_g;
+if g_sign<>normal then
+  begin if g_sign=stretching then
+    begin if stretch_order(g)=g_order then
+      begin cur_glue:=cur_glue+stretch(g);
+      vet_glue(float(glue_set(this_box))*cur_glue);
+@^real multiplication@>
+      cur_g:=round(glue_temp);
+      end;
+    end
+  else if shrink_order(g)=g_order then
+      begin cur_glue:=cur_glue-shrink(g);
+      vet_glue(float(glue_set(this_box))*cur_glue);
+      cur_g:=round(glue_temp);
+      end;
+  end;
+rule_wd:=rule_wd+cur_g;
+if subtype(p)>=a_leaders then
+  @<Output leaders in an hlist, |goto fin_rule| if a rule
+    or to |next_p| if done@>;
+goto move_past;
+end
+
+@ @<Output leaders in an hlist...@>=
+begin leader_box:=leader_ptr(p);
+if type(leader_box)=rule_node then
+  begin rule_ht:=height(leader_box); rule_dp:=depth(leader_box);
+  goto fin_rule;
+  end;
+leader_wd:=width(leader_box);
+if (leader_wd>0)and(rule_wd>0) then
+  begin rule_wd:=rule_wd+10; {compensate for floating-point rounding}
+  edge:=cur_h+rule_wd; lx:=0;
+  @<Let |cur_h| be the position of the first box, and set |leader_wd+lx|
+    to the spacing between corresponding parts of boxes@>;
+  while cur_h+leader_wd<=edge do
+    @<Output a leader box at |cur_h|,
+      then advance |cur_h| by |leader_wd+lx|@>;
+  cur_h:=edge-10; goto next_p;
+  end;
+end
+
+@ The calculations related to leaders require a bit of care. First, in the
+case of |a_leaders| (aligned leaders), we want to move |cur_h| to
+|left_edge| plus the smallest multiple of |leader_wd| for which the result
+is not less than the current value of |cur_h|; i.e., |cur_h| should become
+$|left_edge|+|leader_wd|\times\lceil
+(|cur_h|-|left_edge|)/|leader_wd|\rceil$.  The program here should work in
+all cases even though some implementations of \PASCAL\ give nonstandard
+results for the |div| operation when |cur_h| is less than |left_edge|.
+
+In the case of |c_leaders| (centered leaders), we want to increase |cur_h|
+by half of the excess space not occupied by the leaders; and in the
+case of |x_leaders| (expanded leaders) we increase |cur_h|
+by $1/(q+1)$ of this excess space, where $q$ is the number of times the
+leader box will be replicated. Slight inaccuracies in the division might
+accumulate; half of this rounding error is placed at each end of the leaders.
+
+@<Let |cur_h| be the position of the first box, ...@>=
+if subtype(p)=a_leaders then
+  begin save_h:=cur_h;
+  cur_h:=left_edge+leader_wd*((cur_h-left_edge)@!div leader_wd);
+  if cur_h<save_h then cur_h:=cur_h+leader_wd;
+  end
+else  begin lq:=rule_wd div leader_wd; {the number of box copies}
+  lr:=rule_wd mod leader_wd; {the remaining space}
+  if subtype(p)=c_leaders then cur_h:=cur_h+(lr div 2)
+  else  begin lx:=lr div (lq+1);
+    cur_h:=cur_h+((lr-(lq-1)*lx) div 2);
+    end;
+  end
+
+@ The `\\{synch}' operations here are intended to decrease the number of
+bytes needed to specify horizontal and vertical motion in the \.{DVI} output.
+
+@<Output a leader box at |cur_h|, ...@>=
+begin cur_v:=base_line+disp+shift_amount(leader_box); synch_v; save_v:=dvi_v;@/
+synch_h; save_h:=dvi_h; save_dir:=dvi_dir; temp_ptr:=leader_box;
+outer_doing_leaders:=doing_leaders; doing_leaders:=true;
+case type(leader_box) of
+  hlist_node:hlist_out;
+  vlist_node:vlist_out;
+  dir_node:dir_out;
+endcases;
+doing_leaders:=outer_doing_leaders;
+dvi_v:=save_v; dvi_h:=save_h; dvi_dir:=save_dir;
+cur_v:=base_line; cur_h:=save_h+leader_wd+lx; cur_dir_hv:=save_dir;
+end
+
+@ The |vlist_out| routine is similar to |hlist_out|, but a bit simpler.
+
+@p procedure vlist_out; {output a |vlist_node| box}
+label move_past, fin_rule, next_p;
+var left_edge: scaled; {the left coordinate for this box}
+@!top_edge: scaled; {the top coordinate for this box}
+@!save_h,@!save_v: scaled; {what |dvi_h| and |dvi_v| should pop to}
+@!this_box: pointer; {pointer to containing box}
+@!g_order: glue_ord; {applicable order of infinity for glue}
+@!g_sign: normal..shrinking; {selects type of glue}
+@!p:pointer; {current position in the vlist}
+@!save_loc:integer; {\.{DVI} byte location upon entry}
+@!leader_box:pointer; {the leader box being replicated}
+@!leader_ht:scaled; {height of leader box being replicated}
+@!lx:scaled; {extra space between leader boxes}
+@!outer_doing_leaders:boolean; {were we doing leaders?}
+@!edge:scaled; {bottom boundary of leader space}
+@!glue_temp:real; {glue value before rounding}
+@!cur_glue:real; {glue seen so far}
+@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio}
+@!save_dir:integer; {what |dvi_dir| should pop to}
+begin cur_g:=0; cur_glue:=float_constant(0);
+this_box:=temp_ptr; g_order:=glue_order(this_box);
+g_sign:=glue_sign(this_box); p:=list_ptr(this_box);
+incr(cur_s);
+if cur_s>0 then dvi_out(push);
+if cur_s>max_push then max_push:=cur_s;
+save_loc:=dvi_offset+dvi_ptr;
+synch_dir;
+left_edge:=cur_h; cur_v:=cur_v-height(this_box);
+top_edge:=cur_v;
+while p<>null do @<Output node |p| for |vlist_out| and move to the next node,
+  maintaining the condition |cur_h=left_edge|@>;
+prune_movements(save_loc);
+if cur_s>0 then dvi_pop(save_loc);
+decr(cur_s);
+end;
+
+@ @<Output node |p| for |vlist_out|...@>=
+begin if is_char_node(p) then confusion("vlistout")
+@:this can't happen vlistout}{\quad vlistout@>
+else @<Output the non-|char_node| |p| for |vlist_out|@>;
+next_p:p:=link(p);
+end
+
+@ @<Output the non-|char_node| |p| for |vlist_out|@>=
+begin case type(p) of
+hlist_node,vlist_node,dir_node: @<Output a box in a vlist@>;
+rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p);
+  goto fin_rule;
+  end;
+whatsit_node: @<Output the whatsit node |p| in a vlist@>;
+glue_node: @<Move down or output leaders@>;
+kern_node:cur_v:=cur_v+width(p);
+othercases do_nothing
+endcases;@/
+goto next_p;
+fin_rule: @<Output a rule in a vlist, |goto next_p|@>;
+move_past: cur_v:=cur_v+rule_ht;
+end
+
+@ The |synch_v| here allows the \.{DVI} output to use one-byte commands
+for adjusting |v| in most cases, since the baselineskip distance will
+usually be constant.
+
+@<Output a box in a vlist@>=
+if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p)
+else begin cur_v:=cur_v+height(p); synch_v;
+  save_h:=dvi_h; save_v:=dvi_v; save_dir:=dvi_dir;
+  cur_h:=left_edge+shift_amount(p); {shift the box right}
+  temp_ptr:=p;
+  case type(p) of
+    hlist_node:hlist_out;
+    vlist_node:vlist_out;
+    dir_node:dir_out;
+  endcases;
+  dvi_h:=save_h; dvi_v:=save_v; dvi_dir:=save_dir;
+  cur_v:=save_v+depth(p); cur_h:=left_edge; cur_dir_hv:=save_dir;
+  end
+
+@ @<Output a rule in a vlist...@>=
+if is_running(rule_wd) then rule_wd:=width(this_box);
+rule_ht:=rule_ht+rule_dp; {this is the rule thickness}
+cur_v:=cur_v+rule_ht;
+if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules}
+  begin synch_h; synch_v;
+  dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd);
+  end;
+goto next_p
+
+@ @<Move down or output leaders@>=
+begin g:=glue_ptr(p); rule_ht:=width(g)-cur_g;
+if g_sign<>normal then
+  begin if g_sign=stretching then
+    begin if stretch_order(g)=g_order then
+      begin cur_glue:=cur_glue+stretch(g);
+      vet_glue(float(glue_set(this_box))*cur_glue);
+@^real multiplication@>
+      cur_g:=round(glue_temp);
+      end;
+    end
+  else if shrink_order(g)=g_order then
+      begin cur_glue:=cur_glue-shrink(g);
+      vet_glue(float(glue_set(this_box))*cur_glue);
+      cur_g:=round(glue_temp);
+      end;
+  end;
+rule_ht:=rule_ht+cur_g;
+if subtype(p)>=a_leaders then
+  @<Output leaders in a vlist, |goto fin_rule| if a rule
+    or to |next_p| if done@>;
+goto move_past;
+end
+
+@ @<Output leaders in a vlist...@>=
+begin leader_box:=leader_ptr(p);
+if type(leader_box)=rule_node then
+  begin rule_wd:=width(leader_box); rule_dp:=0;
+  goto fin_rule;
+  end;
+leader_ht:=height(leader_box)+depth(leader_box);
+if (leader_ht>0)and(rule_ht>0) then
+  begin rule_ht:=rule_ht+10; {compensate for floating-point rounding}
+  edge:=cur_v+rule_ht; lx:=0;
+  @<Let |cur_v| be the position of the first box, and set |leader_ht+lx|
+    to the spacing between corresponding parts of boxes@>;
+  while cur_v+leader_ht<=edge do
+    @<Output a leader box at |cur_v|,
+      then advance |cur_v| by |leader_ht+lx|@>;
+  cur_v:=edge-10; goto next_p;
+  end;
+end
+
+@ @<Let |cur_v| be the position of the first box, ...@>=
+if subtype(p)=a_leaders then
+  begin save_v:=cur_v;
+  cur_v:=top_edge+leader_ht*((cur_v-top_edge)@!div leader_ht);
+  if cur_v<save_v then cur_v:=cur_v+leader_ht;
+  end
+else  begin lq:=rule_ht div leader_ht; {the number of box copies}
+  lr:=rule_ht mod leader_ht; {the remaining space}
+  if subtype(p)=c_leaders then cur_v:=cur_v+(lr div 2)
+  else  begin lx:=lr div (lq+1);
+    cur_v:=cur_v+((lr-(lq-1)*lx) div 2);
+    end;
+  end
+
+@ When we reach this part of the program, |cur_v| indicates the top of a
+leader box, not its baseline.
+
+@<Output a leader box at |cur_v|, ...@>=
+begin cur_h:=left_edge+shift_amount(leader_box); synch_h; save_h:=dvi_h;@/
+cur_v:=cur_v+height(leader_box); synch_v; save_v:=dvi_v; save_dir:=dvi_dir;
+temp_ptr:=leader_box;
+outer_doing_leaders:=doing_leaders; doing_leaders:=true;
+case type(leader_box) of
+  hlist_node:hlist_out;
+  vlist_node:vlist_out;
+  dir_node:dir_out;
+endcases;
+doing_leaders:=outer_doing_leaders;
+dvi_v:=save_v; dvi_h:=save_h; dvi_dir:=save_dir;
+cur_h:=left_edge; cur_v:=save_v-height(leader_box)+leader_ht+lx;
+cur_dir_hv:=save_dir;
+end
+
+@ The |hlist_out| and |vlist_out| procedures are now complete, so we are
+ready for the |ship_out| routine that gets them started in the first place.
+
+@p procedure ship_out(@!p:pointer); {output the box |p|}
+label done;
+var page_loc:integer; {location of the current |bop|}
+@!del_node:pointer; {used when delete the |dir_node| continued box}
+@!j,@!k:0..9; {indices to first ten count registers}
+@!s:pool_pointer; {index into |str_pool|}
+@!old_setting:0..max_selector; {saved |selector| setting}
+begin if tracing_output>0 then
+  begin print_nl(""); print_ln;
+  print("Completed box being shipped out");
+@.Completed box...@>
+  end;
+if term_offset>max_print_line-9 then print_ln
+else if (term_offset>0)or(file_offset>0) then print_char(" ");
+print_char("["); j:=9;
+while (count(j)=0)and(j>0) do decr(j);
+for k:=0 to j do
+  begin print_int(count(k));
+  if k<j then print_char(".");
+  end;
+update_terminal;
+if tracing_output>0 then
+  begin print_char("]");
+  begin_diagnostic; show_box(p); end_diagnostic(true);
+  end;
+if type(p)=dir_node then
+  begin del_node:=p; p:=list_ptr(p);
+  delete_glue_ref(space_ptr(del_node));
+  delete_glue_ref(xspace_ptr(del_node));
+  free_node(del_node,box_node_size);
+  end;
+flush_node_list(link(p)); link(p):=null;
+if box_dir(p)<>dir_yoko then p:=new_dir_node(p,dir_yoko);
+@<Ship box |p| out@>;
+if tracing_output<=0 then print_char("]");
+dead_cycles:=0;
+update_terminal; {progress report}
+@<Flush the box from memory, showing statistics if requested@>;
+end;
+
+@ @<Flush the box from memory, showing statistics if requested@>=
+@!stat if tracing_stats>1 then
+  begin print_nl("Memory usage before: ");
+@.Memory usage...@>
+  print_int(var_used); print_char("&");
+  print_int(dyn_used); print_char(";");
+  end;
+tats@/
+flush_node_list(p);
+@!stat if tracing_stats>1 then
+  begin print(" after: ");
+  print_int(var_used); print_char("&");
+  print_int(dyn_used); print("; still untouched: ");
+  print_int(hi_mem_min-lo_mem_max-1); print_ln;
+  end;
+tats
+
+@ @<Ship box |p| out@>=
+@<Update the values of |max_h| and |max_v|; but if the page is too large,
+  |goto done|@>;
+@<Initialize variables as |ship_out| begins@>;
+page_loc:=dvi_offset+dvi_ptr;
+dvi_out(bop);
+for k:=0 to 9 do dvi_four(count(k));
+dvi_four(last_bop); last_bop:=page_loc;
+cur_v:=height(p)+v_offset; temp_ptr:=p;
+case type(p) of
+  hlist_node:hlist_out;
+  vlist_node:vlist_out;
+  dir_node:dir_out;
+endcases;
+dvi_out(eop); incr(total_pages); cur_s:=-1;
+ifdef ('IPC')
+if ipc_on>0 then
+  begin if dvi_limit=half_buf then
+    begin write_dvi(half_buf, dvi_buf_size-1);
+    flush_dvi;
+    dvi_gone:=dvi_gone+half_buf;
+    end;
+  if dvi_ptr>(@"7FFFFFFF-dvi_offset) then
+    begin cur_s:=-2;
+    fatal_error("dvi length exceeds ""7FFFFFFF");
+@.dvi length exceeds...@>
+    end;
+  if dvi_ptr>0 then
+    begin write_dvi(0, dvi_ptr-1);
+    flush_dvi;
+    dvi_offset:=dvi_offset+dvi_ptr; dvi_gone:=dvi_gone+dvi_ptr;
+    end;
+  dvi_ptr:=0; dvi_limit:=dvi_buf_size;
+  ipc_page(dvi_gone);
+  end;
+endif ('IPC');
+done:
+
+@ Sometimes the user will generate a huge page because other error messages
+are being ignored. Such pages are not output to the \.{dvi} file, since they
+may confuse the printing software.
+
+@<Update the values of |max_h| and |max_v|; but if the page is too large...@>=
+if (height(p)>max_dimen)or@|(depth(p)>max_dimen)or@|
+   (height(p)+depth(p)+v_offset>max_dimen)or@|
+   (width(p)+h_offset>max_dimen) then
+  begin print_err("Huge page cannot be shipped out");
+@.Huge page...@>
+  help2("The page just created is more than 18 feet tall or")@/
+   ("more than 18 feet wide, so I suspect something went wrong.");
+  error;
+  if tracing_output<=0 then
+    begin begin_diagnostic;
+    print_nl("The following box has been deleted:");
+@.The following...deleted@>
+    show_box(p);
+    end_diagnostic(true);
+    end;
+  goto done;
+  end;
+if height(p)+depth(p)+v_offset>max_v then max_v:=height(p)+depth(p)+v_offset;
+if width(p)+h_offset>max_h then max_h:=width(p)+h_offset
+
+@ At the end of the program, we must finish things off by writing the
+post\-amble. If |total_pages=0|, the \.{DVI} file was never opened.
+If |total_pages>=65536|, the \.{DVI} file will lie. And if
+|max_push>=65536|, the user deserves whatever chaos might ensue.
+
+An integer variable |k| will be declared for use by this routine.
+
+@<Finish the \.{DVI} file@>=
+while cur_s>-1 do
+  begin if cur_s>0 then dvi_out(pop)
+  else  begin dvi_out(eop); incr(total_pages);
+    end;
+  decr(cur_s);
+  end;
+if total_pages=0 then print_nl("No pages of output.")
+@.No pages of output@>
+else if cur_s<>-2 then
+  begin dvi_out(post); {beginning of the postamble}
+  dvi_four(last_bop); last_bop:=dvi_offset+dvi_ptr-5; {|post| location}
+  dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp}
+  prepare_mag; dvi_four(mag); {magnification factor}
+  dvi_four(max_v); dvi_four(max_h);@/
+  dvi_out(max_push div 256); dvi_out(max_push mod 256);@/
+  dvi_out((total_pages div 256) mod 256); dvi_out(total_pages mod 256);@/
+  @<Output the font definitions for all fonts that were used@>;
+  dvi_out(post_post); dvi_four(last_bop);
+  if dir_used then dvi_out(ex_id_byte) else dvi_out(id_byte);@/
+ifdef ('IPC')
+  k:=7-((3+dvi_offset+dvi_ptr) mod 4); {the number of 223's}
+endif ('IPC')
+ifndef ('IPC')
+  k:=4+((dvi_buf_size-dvi_ptr) mod 4); {the number of 223's}
+endifn ('IPC')
+  while k>0 do
+    begin dvi_out(223); decr(k);
+    end;
+  @<Empty the last bytes out of |dvi_buf|@>;
+  print_nl("Output written on "); print_file_name(0, output_file_name, 0);
+@.Output written on x@>
+  print(" ("); print_int(total_pages);
+  if total_pages<>1 then print(" pages")
+  else print(" page");
+  print(", "); print_int(dvi_offset+dvi_ptr); print(" bytes).");
+  b_close(dvi_file);
+  end
+
+@ @<Output the font definitions...@>=
+while font_ptr>font_base do
+  begin if font_used[font_ptr] then dvi_font_def(font_ptr);
+  decr(font_ptr);
+  end
+
+@* \[33] Packaging.
+We're essentially done with the parts of \TeX\ that are concerned with
+the input (|get_next|) and the output (|ship_out|). So it's time to
+get heavily into the remaining part, which does the real work of typesetting.
+
+After lists are constructed, \TeX\ wraps them up and puts them into boxes.
+Two major subroutines are given the responsibility for this task: |hpack|
+applies to horizontal lists (hlists) and |vpack| applies to vertical lists
+(vlists). The main duty of |hpack| and |vpack| is to compute the dimensions
+of the resulting boxes, and to adjust the glue if one of those dimensions
+is pre-specified. The computed sizes normally enclose all of the material
+inside the new box; but some items may stick out if negative glue is used,
+if the box is overfull, or if a \.{\\vbox} includes other boxes that have
+been shifted left.
+
+The subroutine call |hpack(p,w,m)| returns a pointer to an |hlist_node|
+for a box containing the hlist that starts at |p|. Parameter |w| specifies
+a width; and parameter |m| is either `|exactly|' or `|additional|'.  Thus,
+|hpack(p,w,exactly)| produces a box whose width is exactly |w|, while
+|hpack(p,w,additional)| yields a box whose width is the natural width plus
+|w|.  It is convenient to define a macro called `|natural|' to cover the
+most common case, so that we can say |hpack(p,natural)| to get a box that
+has the natural width of list |p|.
+
+Similarly, |vpack(p,w,m)| returns a pointer to a |vlist_node| for a
+box containing the vlist that starts at |p|. In this case |w| represents
+a height instead of a width; the parameter |m| is interpreted as in |hpack|.
+
+@d exactly=0 {a box dimension is pre-specified}
+@d additional=1 {a box dimension is increased from the natural one}
+@d natural==0,additional {shorthand for parameters to |hpack| and |vpack|}
+
+@ The parameters to |hpack| and |vpack| correspond to \TeX's primitives
+like `\.{\\hbox} \.{to} \.{300pt}', `\.{\\hbox} \.{spread} \.{10pt}'; note
+that `\.{\\hbox}' with no dimension following it is equivalent to
+`\.{\\hbox} \.{spread} \.{0pt}'.  The |scan_spec| subroutine scans such
+constructions in the user's input, including the mandatory left brace that
+follows them, and it puts the specification onto |save_stack| so that the
+desired box can later be obtained by executing the following code:
+$$\vbox{\halign{#\hfil\cr
+|save_ptr:=save_ptr-2;|\cr
+|hpack(p,saved(1),saved(0)).|\cr}}$$
+Special care is necessary to ensure that the special |save_stack| codes
+are placed just below the new group code, because scanning can change
+|save_stack| when \.{\\csname} appears.
+
+@p procedure scan_spec(@!c:group_code;@!three_codes:boolean);
+  {scans a box specification and left brace}
+label found;
+var @!s:integer; {temporarily saved value}
+@!spec_code:exactly..additional;
+begin if three_codes then s:=saved(0);
+if scan_keyword("to") then spec_code:=exactly
+@.to@>
+else if scan_keyword("spread") then spec_code:=additional
+@.spread@>
+else  begin spec_code:=additional; cur_val:=0;
+  goto found;
+  end;
+scan_normal_dimen;
+found: if three_codes then
+  begin saved(0):=s; incr(save_ptr);
+  end;
+saved(0):=spec_code; saved(1):=cur_val; save_ptr:=save_ptr+2;
+new_save_level(c); scan_left_brace;
+end;
+
+@ To figure out the glue setting, |hpack| and |vpack| determine how much
+stretchability and shrinkability are present, considering all four orders
+of infinity. The highest order of infinity that has a nonzero coefficient
+is then used as if no other orders were present.
+
+For example, suppose that the given list contains six glue nodes with
+the respective stretchabilities 3pt, 8fill, 5fil, 6pt, $-3$fil, $-8$fill.
+Then the total is essentially 2fil; and if a total additional space of 6pt
+is to be achieved by stretching, the actual amounts of stretch will be
+0pt, 0pt, 15pt, 0pt, $-9$pt, and 0pt, since only `fil' glue will be
+considered. (The `fill' glue is therefore not really stretching infinitely
+with respect to `fil'; nobody would actually want that to happen.)
+
+The arrays |total_stretch| and |total_shrink| are used to determine how much
+glue of each kind is present. A global variable |last_badness| is used
+to implement \.{\\badness}.
+
+@<Glob...@>=
+@!total_stretch, @!total_shrink: array[glue_ord] of scaled;
+  {glue found by |hpack| or |vpack|}
+@!last_badness:integer; {badness of the most recently packaged box}
+
+@ If the global variable |adjust_tail| is non-null, the |hpack| routine
+also removes all occurrences of |ins_node|, |mark_node|, and |adjust_node|
+items and appends the resulting material onto the list that ends at
+location |adjust_tail|.
+
+@< Glob...@>=
+@!adjust_tail:pointer; {tail of adjustment list}
+@!last_disp:scaled; {displacement at end of list}
+@!cur_kanji_skip:pointer;
+@!cur_xkanji_skip:pointer;
+
+@ @<Set init...@>=adjust_tail:=null; last_badness:=0;
+  cur_kanji_skip:=zero_glue; cur_xkanji_skip:=zero_glue;
+{ koko
+  |incr(glue_ref_count(cur_kanji_skip));|
+  |incr(glue_ref_count(cur_xkanji_skip));|
+}
+
+@ Here now is |hpack|, which contains few if any surprises.
+
+@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer;
+label reswitch, common_ending, exit;
+var r:pointer; {the box node that will be returned}
+@!k:pointer; {points to a |kanji_space| specification}
+@!disp:scaled; {displacement}
+@!q:pointer; {trails behind |p|}
+@!h,@!d,@!x:scaled; {height, depth, and natural width}
+@!s:scaled; {shift amount}
+@!g:pointer; {points to a glue specification}
+@!o:glue_ord; {order of infinity}
+@!f:internal_font_number; {the font in a |char_node|}
+@!i:four_quarters; {font information about a |char_node|}
+@!hd:eight_bits; {height and depth indices for a character}
+begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node;
+subtype(r):=min_quarterword; shift_amount(r):=0;
+space_ptr(r):=cur_kanji_skip; xspace_ptr(r):=cur_xkanji_skip;
+add_glue_ref(cur_kanji_skip); add_glue_ref(cur_xkanji_skip);
+k:=cur_kanji_skip;
+q:=r+list_offset; link(q):=p;@/
+h:=0; @<Clear dimensions to zero@>;
+disp:=0;
+while p<>null do @<Examine node |p| in the hlist, taking account of its effect
+  on the dimensions of the new box, or moving it to the adjustment list;
+  then advance |p| to the next node@>;
+if adjust_tail<>null then link(adjust_tail):=null;
+height(r):=h; depth(r):=d;@/
+@<Determine the value of |width(r)| and the appropriate glue setting;
+  then |return| or |goto common_ending|@>;
+common_ending:
+  @<Finish issuing a diagnostic message for an overfull or underfull hbox@>;
+exit: last_disp:=disp; hpack:=r;
+end;
+
+@ @<Clear dimensions to zero@>=
+d:=0; x:=0;
+total_stretch[normal]:=0; total_shrink[normal]:=0;
+total_stretch[fil]:=0; total_shrink[fil]:=0;
+total_stretch[fill]:=0; total_shrink[fill]:=0;
+total_stretch[filll]:=0; total_shrink[filll]:=0
+
+@ @<Examine node |p| in the hlist, taking account of its effect...@>=
+@^inner loop@>
+begin reswitch: chain:=false;
+while is_char_node(p) do
+  @<Incorporate character dimensions into the dimensions of
+    the hbox that will contain~it, then move to the next node@>;
+if p<>null then
+  begin case type(p) of
+  hlist_node,vlist_node,dir_node,rule_node,unset_node:
+    @<Incorporate box dimensions into the dimensions of
+      the hbox that will contain~it@>;
+  ins_node,mark_node,adjust_node:
+    if adjust_tail<>null then @<Transfer node |p| to the adjustment list@>;
+  whatsit_node:@<Incorporate a whatsit node into an hbox@>;
+  disp_node:disp:=disp_dimen(p);
+  glue_node:@<Incorporate glue into the horizontal totals@>;
+  kern_node,math_node: x:=x+width(p);
+  ligature_node: @<Make node |p| look like a |char_node|
+    and |goto reswitch|@>;
+  othercases do_nothing
+  endcases;@/
+  p:=link(p);
+  end;
+end
+
+
+@ @<Make node |p| look like a |char_node| and |goto reswitch|@>=
+begin mem[lig_trick]:=mem[lig_char(p)]; link(lig_trick):=link(p);
+p:=lig_trick; goto reswitch;
+end
+
+@ The code here implicitly uses the fact that running dimensions are
+indicated by |null_flag|, which will be ignored in the calculations
+because it is a highly negative number.
+
+@<Incorporate box dimensions into the dimensions of the hbox...@>=
+begin x:=x+width(p);
+if type(p)>=rule_node then s:=disp @+else s:=shift_amount(p)+disp;
+if height(p)-s>h then h:=height(p)-s;
+if depth(p)+s>d then d:=depth(p)+s;
+end
+
+@ The following code is part of \TeX's inner loop; i.e., adding another
+character of text to the user's input will cause each of these instructions
+to be exercised one more time.
+@^inner loop@>
+
+@<Incorporate character dimensions into the dimensions of the hbox...@>=
+begin f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i);
+x:=x+char_width(f)(i);@/
+s:=char_height(f)(hd)-disp; if s>h then h:=s;
+s:=char_depth(f)(hd)+disp; if s>d then d:=s;
+if font_dir[f]<>dir_default then
+  begin p:=link(p);
+  if chain then
+    begin x:=x+width(k);@/
+    o:=stretch_order(k); total_stretch[o]:=total_stretch[o]+stretch(k);
+    o:=shrink_order(k); total_shrink[o]:=total_shrink[o]+shrink(k);
+    end
+  else chain:=true;
+  end
+else chain:=false;
+p:=link(p);
+end
+
+@ Although node |q| is not necessarily the immediate predecessor of node |p|,
+it always points to some node in the list preceding |p|. Thus, we can delete
+nodes by moving |q| when necessary. The algorithm takes linear time, and the
+extra computation does not intrude on the inner loop unless it is necessary
+to make a deletion.
+@^inner loop@>
+
+@<Transfer node |p| to the adjustment list@>=
+begin while link(q)<>p do q:=link(q);
+if type(p)=adjust_node then
+  begin link(adjust_tail):=adjust_ptr(p);
+  while link(adjust_tail)<>null do adjust_tail:=link(adjust_tail);
+  p:=link(p); free_node(link(q),small_node_size);
+  end
+else  begin link(adjust_tail):=p; adjust_tail:=p; p:=link(p);
+  end;
+link(q):=p; p:=q;
+end
+
+@ @<Incorporate glue into the horizontal totals@>=
+begin g:=glue_ptr(p); x:=x+width(g);@/
+o:=stretch_order(g); total_stretch[o]:=total_stretch[o]+stretch(g);
+o:=shrink_order(g); total_shrink[o]:=total_shrink[o]+shrink(g);
+if subtype(p)>=a_leaders then
+  begin g:=leader_ptr(p);
+  if height(g)>h then h:=height(g);
+  if depth(g)>d then d:=depth(g);
+  end;
+end
+
+@ When we get to the present part of the program, |x| is the natural width
+of the box being packaged.
+
+@<Determine the value of |width(r)| and the appropriate glue setting...@>=
+if m=additional then w:=x+w;
+width(r):=w; x:=w-x; {now |x| is the excess to be made up}
+if x=0 then
+  begin glue_sign(r):=normal; glue_order(r):=normal;
+  set_glue_ratio_zero(glue_set(r));
+  return;
+  end
+else if x>0 then @<Determine horizontal glue stretch setting, then |return|
+    or \hbox{|goto common_ending|}@>
+else @<Determine horizontal glue shrink setting, then |return|
+    or \hbox{|goto common_ending|}@>
+
+@ @<Determine horizontal glue stretch setting...@>=
+begin @<Determine the stretch order@>;
+glue_order(r):=o; glue_sign(r):=stretching;
+if total_stretch[o]<>0 then glue_set(r):=unfloat(x/total_stretch[o])
+@^real division@>
+else  begin glue_sign(r):=normal;
+  set_glue_ratio_zero(glue_set(r)); {there's nothing to stretch}
+  end;
+if o=normal then if list_ptr(r)<>null then
+  @<Report an underfull hbox and |goto common_ending|, if this box
+    is sufficiently bad@>;
+return;
+end
+
+@ @<Determine the stretch order@>=
+if total_stretch[filll]<>0 then o:=filll
+else if total_stretch[fill]<>0 then o:=fill
+else if total_stretch[fil]<>0 then o:=fil
+else o:=normal
+
+@ @<Report an underfull hbox and |goto common_ending|, if...@>=
+begin last_badness:=badness(x,total_stretch[normal]);
+if last_badness>hbadness then
+  begin print_ln;
+  if last_badness>100 then print_nl("Underfull")@+else print_nl("Loose");
+  print(" \hbox (badness "); print_int(last_badness);
+@.Underfull \\hbox...@>
+@.Loose \\hbox...@>
+  goto common_ending;
+  end;
+end
+
+@ In order to provide a decent indication of where an overfull or underfull
+box originated, we use a global variable |pack_begin_line| that is
+set nonzero only when |hpack| is being called by the paragraph builder
+or the alignment finishing routine.
+
+@<Glob...@>=
+@!pack_begin_line:integer; {source file line where the current paragraph
+  or alignment began; a negative value denotes alignment}
+
+@ @<Set init...@>=
+pack_begin_line:=0;
+
+@ @<Finish issuing a diagnostic message for an overfull or underfull hbox@>=
+if output_active then print(") has occurred while \output is active")
+else  begin if pack_begin_line<>0 then
+    begin if pack_begin_line>0 then print(") in paragraph at lines ")
+    else print(") in alignment at lines ");
+    print_int(abs(pack_begin_line));
+    print("--");
+    end
+  else print(") detected at line ");
+  print_int(line);
+  end;
+print_ln;@/
+font_in_short_display:=null_font; short_display(list_ptr(r)); print_ln;@/
+begin_diagnostic; show_box(r); end_diagnostic(true)
+
+@ @<Determine horizontal glue shrink setting...@>=
+begin @<Determine the shrink order@>;
+glue_order(r):=o; glue_sign(r):=shrinking;
+if total_shrink[o]<>0 then glue_set(r):=unfloat((-x)/total_shrink[o])
+@^real division@>
+else  begin glue_sign(r):=normal;
+  set_glue_ratio_zero(glue_set(r)); {there's nothing to shrink}
+  end;
+if (total_shrink[o]<-x)and(o=normal)and(list_ptr(r)<>null) then
+  begin last_badness:=1000000;
+  set_glue_ratio_one(glue_set(r)); {use the maximum shrinkage}
+  @<Report an overfull hbox and |goto common_ending|, if this box
+    is sufficiently bad@>;
+  end
+else if o=normal then if list_ptr(r)<>null then
+  @<Report a tight hbox and |goto common_ending|, if this box
+    is sufficiently bad@>;
+return;
+end
+
+@ @<Determine the shrink order@>=
+if total_shrink[filll]<>0 then o:=filll
+else if total_shrink[fill]<>0 then o:=fill
+else if total_shrink[fil]<>0 then o:=fil
+else o:=normal
+
+@ @<Report an overfull hbox and |goto common_ending|, if...@>=
+if (-x-total_shrink[normal]>hfuzz)or(hbadness<100) then
+  begin if (overfull_rule>0)and(-x-total_shrink[normal]>hfuzz) then
+    begin while link(q)<>null do q:=link(q);
+    link(q):=new_rule;
+    width(link(q)):=overfull_rule;
+    end;
+  print_ln; print_nl("Overfull \hbox (");
+@.Overfull \\hbox...@>
+  print_scaled(-x-total_shrink[normal]); print("pt too wide");
+  goto common_ending;
+  end
+
+@ @<Report a tight hbox and |goto common_ending|, if...@>=
+begin last_badness:=badness(-x,total_shrink[normal]);
+if last_badness>hbadness then
+  begin print_ln; print_nl("Tight \hbox (badness "); print_int(last_badness);
+@.Tight \\hbox...@>
+  goto common_ending;
+  end;
+end
+
+@ The |vpack| subroutine is actually a special case of a slightly more
+general routine called |vpackage|, which has four parameters. The fourth
+parameter, which is |max_dimen| in the case of |vpack|, specifies the
+maximum depth of the page box that is constructed. The depth is first
+computed by the normal rules; if it exceeds this limit, the reference
+point is simply moved down until the limiting depth is attained.
+
+@d vpack(#)==vpackage(#,max_dimen) {special case of unconstrained depth}
+
+@p function vpackage(@!p:pointer;@!h:scaled;@!m:small_number;@!l:scaled):
+  pointer;
+label common_ending, exit;
+var r:pointer; {the box node that will be returned}
+@!w,@!d,@!x:scaled; {width, depth, and natural height}
+@!s:scaled; {shift amount}
+@!g:pointer; {points to a glue specification}
+@!o:glue_ord; {order of infinity}
+begin last_badness:=0; r:=get_node(box_node_size); type(r):=vlist_node;
+subtype(r):=min_quarterword; shift_amount(r):=0;
+space_ptr(r):=zero_glue; xspace_ptr(r):=zero_glue;
+add_glue_ref(zero_glue); add_glue_ref(zero_glue);
+list_ptr(r):=p;@/
+w:=0; @<Clear dimensions to zero@>;
+while p<>null do @<Examine node |p| in the vlist, taking account of its effect
+  on the dimensions of the new box; then advance |p| to the next node@>;
+width(r):=w;
+if d>l then
+  begin x:=x+d-l; depth(r):=l;
+  end
+else depth(r):=d;
+@<Determine the value of |height(r)| and the appropriate glue setting;
+  then |return| or |goto common_ending|@>;
+common_ending: @<Finish issuing a diagnostic message
+      for an overfull or underfull vbox@>;
+exit: vpackage:=r;
+end;
+
+@ @<Examine node |p| in the vlist, taking account of its effect...@>=
+begin if is_char_node(p) then confusion("vpack")
+@:this can't happen vpack}{\quad vpack@>
+else  case type(p) of
+  hlist_node,vlist_node,dir_node,rule_node,unset_node:
+    @<Incorporate box dimensions into the dimensions of
+      the vbox that will contain~it@>;
+  whatsit_node:@<Incorporate a whatsit node into a vbox@>;
+  glue_node: @<Incorporate glue into the vertical totals@>;
+  kern_node: begin x:=x+d+width(p); d:=0;
+    end;
+  othercases do_nothing
+  endcases;
+p:=link(p);
+end
+
+@ @<Incorporate box dimensions into the dimensions of the vbox...@>=
+begin x:=x+d+height(p); d:=depth(p);
+if type(p)>=rule_node then s:=0 @+else s:=shift_amount(p);
+if width(p)+s>w then w:=width(p)+s;
+end
+
+@ @<Incorporate glue into the vertical totals@>=
+begin x:=x+d; d:=0;@/
+g:=glue_ptr(p); x:=x+width(g);@/
+o:=stretch_order(g); total_stretch[o]:=total_stretch[o]+stretch(g);
+o:=shrink_order(g); total_shrink[o]:=total_shrink[o]+shrink(g);
+if subtype(p)>=a_leaders then
+  begin g:=leader_ptr(p);
+  if width(g)>w then w:=width(g);
+  end;
+end
+
+@ When we get to the present part of the program, |x| is the natural height
+of the box being packaged.
+
+@<Determine the value of |height(r)| and the appropriate glue setting...@>=
+if m=additional then h:=x+h;
+height(r):=h; x:=h-x; {now |x| is the excess to be made up}
+if x=0 then
+  begin glue_sign(r):=normal; glue_order(r):=normal;
+  set_glue_ratio_zero(glue_set(r));
+  return;
+  end
+else if x>0 then @<Determine vertical glue stretch setting, then |return|
+    or \hbox{|goto common_ending|}@>
+else @<Determine vertical glue shrink setting, then |return|
+    or \hbox{|goto common_ending|}@>
+
+@ @<Determine vertical glue stretch setting...@>=
+begin @<Determine the stretch order@>;
+glue_order(r):=o; glue_sign(r):=stretching;
+if total_stretch[o]<>0 then glue_set(r):=unfloat(x/total_stretch[o])
+@^real division@>
+else  begin glue_sign(r):=normal;
+  set_glue_ratio_zero(glue_set(r)); {there's nothing to stretch}
+  end;
+if o=normal then if list_ptr(r)<>null then
+  @<Report an underfull vbox and |goto common_ending|, if this box
+    is sufficiently bad@>;
+return;
+end
+
+@ @<Report an underfull vbox and |goto common_ending|, if...@>=
+begin last_badness:=badness(x,total_stretch[normal]);
+if last_badness>vbadness then
+  begin print_ln;
+  if last_badness>100 then print_nl("Underfull")@+else print_nl("Loose");
+  print(" \vbox (badness "); print_int(last_badness);
+@.Underfull \\vbox...@>
+@.Loose \\vbox...@>
+  goto common_ending;
+  end;
+end
+
+@ @<Finish issuing a diagnostic message for an overfull or underfull vbox@>=
+if output_active then print(") has occurred while \output is active")
+else  begin if pack_begin_line<>0 then {it's actually negative}
+    begin print(") in alignment at lines ");
+    print_int(abs(pack_begin_line));
+    print("--");
+    end
+  else print(") detected at line ");
+  print_int(line);
+  print_ln;@/
+  end;
+begin_diagnostic; show_box(r); end_diagnostic(true)
+
+@ @<Determine vertical glue shrink setting...@>=
+begin @<Determine the shrink order@>;
+glue_order(r):=o; glue_sign(r):=shrinking;
+if total_shrink[o]<>0 then glue_set(r):=unfloat((-x)/total_shrink[o])
+@^real division@>
+else  begin glue_sign(r):=normal;
+  set_glue_ratio_zero(glue_set(r)); {there's nothing to shrink}
+  end;
+if (total_shrink[o]<-x)and(o=normal)and(list_ptr(r)<>null) then
+  begin last_badness:=1000000;
+  set_glue_ratio_one(glue_set(r)); {use the maximum shrinkage}
+  @<Report an overfull vbox and |goto common_ending|, if this box
+    is sufficiently bad@>;
+  end
+else if o=normal then if list_ptr(r)<>null then
+  @<Report a tight vbox and |goto common_ending|, if this box
+    is sufficiently bad@>;
+return;
+end
+
+@ @<Report an overfull vbox and |goto common_ending|, if...@>=
+if (-x-total_shrink[normal]>vfuzz)or(vbadness<100) then
+  begin print_ln; print_nl("Overfull \vbox (");
+@.Overfull \\vbox...@>
+  print_scaled(-x-total_shrink[normal]); print("pt too high");
+  goto common_ending;
+  end
+
+@ @<Report a tight vbox and |goto common_ending|, if...@>=
+begin last_badness:=badness(-x,total_shrink[normal]);
+if last_badness>vbadness then
+  begin print_ln; print_nl("Tight \vbox (badness "); print_int(last_badness);
+@.Tight \\vbox...@>
+  goto common_ending;
+  end;
+end
+
+@ When a box is being appended to the current vertical list, the
+baselineskip calculation is handled by the |append_to_vlist| routine.
+
+@p procedure append_to_vlist(@!b:pointer);
+var d:scaled; {deficiency of space between baselines}
+@!p:pointer; {a new glue node}
+begin if prev_depth>ignore_depth then
+  begin d:=width(baseline_skip)-prev_depth-height(b);
+  if d<line_skip_limit then p:=new_param_glue(line_skip_code)
+  else  begin p:=new_skip_param(baseline_skip_code);
+    width(temp_ptr):=d; {|temp_ptr=glue_ptr(p)|}
+    end;
+  link(tail):=p; tail:=p;
+  end;
+link(tail):=b; tail:=b; prev_depth:=depth(b);
+end;
+
+@* \[34] Data structures for math mode.
+When \TeX\ reads a formula that is enclosed between \.\$'s, it constructs an
+{\sl mlist}, which is essentially a tree structure representing that
+formula.  An mlist is a linear sequence of items, but we can regard it as
+a tree structure because mlists can appear within mlists. For example, many
+of the entries can be subscripted or superscripted, and such ``scripts''
+are mlists in their own right.
+
+An entire formula is parsed into such a tree before any of the actual
+typesetting is done, because the current style of type is usually not
+known until the formula has been fully scanned. For example, when the
+formula `\.{\$a+b \\over c+d\$}' is being read, there is no way to tell
+that `\.{a+b}' will be in script size until `\.{\\over}' has appeared.
+
+During the scanning process, each element of the mlist being built is
+classified as a relation, a binary operator, an open parenthesis, etc.,
+or as a construct like `\.{\\sqrt}' that must be built up. This classification
+appears in the mlist data structure.
+
+After a formula has been fully scanned, the mlist is converted to an hlist
+so that it can be incorporated into the surrounding text. This conversion is
+controlled by a recursive procedure that decides all of the appropriate
+styles by a ``top-down'' process starting at the outermost level and working
+in towards the subformulas. The formula is ultimately pasted together using
+combinations of horizontal and vertical boxes, with glue and penalty nodes
+inserted as necessary.
+
+An mlist is represented internally as a linked list consisting chiefly
+of ``noads'' (pronounced ``no-adds''), to distinguish them from the somewhat
+similar ``nodes'' in hlists and vlists. Certain kinds of ordinary nodes are
+allowed to appear in mlists together with the noads; \TeX\ tells the difference
+by means of the |type| field, since a noad's |type| is always greater than
+that of a node. An mlist does not contain character nodes, hlist nodes, vlist
+nodes, math nodes, ligature nodes,
+or unset nodes; in particular, each mlist item appears in the
+variable-size part of |mem|, so the |type| field is always present.
+
+@ Each noad is four or more words long. The first word contains the |type|
+and |subtype| and |link| fields that are already so familiar to us; the
+second, third, and fourth words are called the noad's |nucleus|, |subscr|,
+and |supscr| fields.
+
+Consider, for example, the simple formula `\.{\$x\^2\$}', which would be
+parsed into an mlist containing a single element called an |ord_noad|.
+The |nucleus| of this noad is a representation of `\.x', the |subscr| is
+empty, and the |supscr| is a representation of `\.2'.
+
+The |nucleus|, |subscr|, and |supscr| fields are further broken into
+subfields. If |p| points to a noad, and if |q| is one of its principal
+fields (e.g., |q=subscr(p)|), there are several possibilities for the
+subfields, depending on the |math_type| of |q|.
+
+\yskip\hang|math_type(q)=math_char| means that |fam(q)| refers to one of
+the sixteen font families, and |character(q)| is the number of a character
+within a font of that family, as in a character node.
+
+\yskip\hang|math_type(q)=math_text_char| is similar, but the character is
+unsubscripted and unsuperscripted and it is followed immediately by another
+character from the same font. (This |math_type| setting appears only
+briefly during the processing; it is used to suppress unwanted italic
+corrections.)
+
+\yskip\hang|math_type(q)=empty| indicates a field with no value (the
+corresponding attribute of noad |p| is not present).
+
+\yskip\hang|math_type(q)=sub_box| means that |info(q)| points to a box
+node (either an |hlist_node| or a |vlist_node|) that should be used as the
+value of the field.  The |shift_amount| in the subsidiary box node is the
+amount by which that box will be shifted downward.
+
+\yskip\hang|math_type(q)=sub_mlist| means that |info(q)| points to
+an mlist; the mlist must be converted to an hlist in order to obtain
+the value of this field.
+
+\yskip\noindent In the latter case, we might have |info(q)=null|. This
+is not the same as |math_type(q)=empty|; for example, `\.{\$P\_\{\}\$}'
+and `\.{\$P\$}' produce different results (the former will not have the
+``italic correction'' added to the width of |P|, but the ``script skip''
+will be added).
+
+The definitions of subfields given here are evidently wasteful of space,
+since a halfword is being used for the |math_type| although only three
+bits would be needed. However, there are hardly ever many noads present at
+once, since they are soon converted to nodes that take up even more space,
+so we can afford to represent them in whatever way simplifies the
+programming.
+
+\yskip\hang In Japanese, |math_type(q)=math_jchar| means that |fam(q)|
+refers to one of the sixteen kanji font families, and |KANJI(q)| is the
+internal kanji code number.
+@^Japanese extentions@>
+
+@d noad_size=5 {number of words in a normal noad}
+@d nucleus(#)==#+1 {the |nucleus| field of a noad}
+@d supscr(#)==#+2 {the |supscr| field of a noad}
+@d subscr(#)==#+3 {the |subscr| field of a noad}
+@d kcode_noad(#)==#+4
+@d math_kcode(#)==info(#+4) {the |kanji character| field of a noad}
+@d kcode_noad_nucleus(#)==#+3
+@d math_kcode_nucleus(#)==info(#+3)
+       {the |kanji character| field offset from nucleus}
+@#
+@d math_jchar=5
+@d math_text_jchar=6
+@d math_type==link {a |halfword| in |mem|}
+@d fam==font {a |quarterword| in |mem|}
+@d math_char=1 {|math_type| when the attribute is simple}
+@d sub_box=2 {|math_type| when the attribute is a box}
+@d sub_mlist=3 {|math_type| when the attribute is a formula}
+@d math_text_char=4 {|math_type| when italic correction is dubious}
+
+@ Each portion of a formula is classified as Ord, Op, Bin, Rel, Ope,
+Clo, Pun, or Inn, for purposes of spacing and line breaking. An
+|ord_noad|, |op_noad|, |bin_noad|, |rel_noad|, |open_noad|, |close_noad|,
+|punct_noad|, or |inner_noad| is used to represent portions of the various
+types. For example, an `\.=' sign in a formula leads to the creation of a
+|rel_noad| whose |nucleus| field is a representation of an equals sign
+(usually |fam=0|, |character=@'75|).  A formula preceded by \.{\\mathrel}
+also results in a |rel_noad|.  When a |rel_noad| is followed by an
+|op_noad|, say, and possibly separated by one or more ordinary nodes (not
+noads), \TeX\ will insert a penalty node (with the current |rel_penalty|)
+just after the formula that corresponds to the |rel_noad|, unless there
+already was a penalty immediately following; and a ``thick space'' will be
+inserted just before the formula that corresponds to the |op_noad|.
+
+A noad of type |ord_noad|, |op_noad|, \dots, |inner_noad| usually
+has a |subtype=normal|. The only exception is that an |op_noad| might
+have |subtype=limits| or |no_limits|, if the normal positioning of
+limits has been overridden for this operator.
+
+@d ord_noad=unset_node+3 {|type| of a noad classified Ord}
+@d op_noad=ord_noad+1 {|type| of a noad classified Op}
+@d bin_noad=ord_noad+2 {|type| of a noad classified Bin}
+@d rel_noad=ord_noad+3 {|type| of a noad classified Rel}
+@d open_noad=ord_noad+4 {|type| of a noad classified Ope}
+@d close_noad=ord_noad+5 {|type| of a noad classified Clo}
+@d punct_noad=ord_noad+6 {|type| of a noad classified Pun}
+@d inner_noad=ord_noad+7 {|type| of a noad classified Inn}
+@d limits=1 {|subtype| of |op_noad| whose scripts are to be above, below}
+@d no_limits=2 {|subtype| of |op_noad| whose scripts are to be normal}
+
+@ A |radical_noad| is five words long; the fifth word is the |left_delimiter|
+field, which usually represents a square root sign.
+
+A |fraction_noad| is six words long; it has a |right_delimiter| field
+as well as a |left_delimiter|.
+
+Delimiter fields are of type |four_quarters|, and they have four subfields
+called |small_fam|, |small_char|, |large_fam|, |large_char|. These subfields
+represent variable-size delimiters by giving the ``small'' and ``large''
+starting characters, as explained in Chapter~17 of {\sl The \TeX book}.
+@:TeXbook}{\sl The \TeX book@>
+
+A |fraction_noad| is actually quite different from all other noads. Not
+only does it have six words, it has |thickness|, |denominator|, and
+|numerator| fields instead of |nucleus|, |subscr|, and |supscr|. The
+|thickness| is a scaled value that tells how thick to make a fraction
+rule; however, the special value |default_code| is used to stand for the
+|default_rule_thickness| of the current size. The |numerator| and
+|denominator| point to mlists that define a fraction; we always have
+$$\hbox{|math_type(numerator)=math_type(denominator)=sub_mlist|}.$$ The
+|left_delimiter| and |right_delimiter| fields specify delimiters that will
+be placed at the left and right of the fraction. In this way, a
+|fraction_noad| is able to represent all of \TeX's operators \.{\\over},
+\.{\\atop}, \.{\\above}, \.{\\overwithdelims}, \.{\\atopwithdelims}, and
+ \.{\\abovewithdelims}.
+
+@d left_delimiter(#)==#+5 {first delimiter field of a noad}
+@d right_delimiter(#)==#+4 {second delimiter field of a fraction noad}
+@d radical_noad=inner_noad+1 {|type| of a noad for square roots}
+@d radical_noad_size=6 {number of |mem| words in a radical noad}
+@d fraction_noad=radical_noad+1 {|type| of a noad for generalized fractions}
+@d fraction_noad_size=6 {number of |mem| words in a fraction noad}
+@d small_fam(#)==mem[#].qqqq.b0 {|fam| for ``small'' delimiter}
+@d small_char(#)==mem[#].qqqq.b1 {|character| for ``small'' delimiter}
+@d large_fam(#)==mem[#].qqqq.b2 {|fam| for ``large'' delimiter}
+@d large_char(#)==mem[#].qqqq.b3 {|character| for ``large'' delimiter}
+@d thickness==width {|thickness| field in a fraction noad}
+@d default_code==@'10000000000 {denotes |default_rule_thickness|}
+@d numerator==supscr {|numerator| field in a fraction noad}
+@d denominator==subscr {|denominator| field in a fraction noad}
+
+@ The global variable |empty_field| is set up for initialization of empty
+fields in new noads. Similarly, |null_delimiter| is for the initialization
+of delimiter fields.
+
+@<Glob...@>=
+@!empty_field:two_halves;
+@!null_delimiter:four_quarters;
+
+@ @<Set init...@>=
+empty_field.rh:=empty; empty_field.lh:=null;@/
+null_delimiter.b0:=0; null_delimiter.b1:=min_quarterword;@/
+null_delimiter.b2:=0; null_delimiter.b3:=min_quarterword;
+
+@ The |new_noad| function creates an |ord_noad| that is completely null.
+
+@p function new_noad:pointer;
+var p:pointer;
+begin p:=get_node(noad_size);
+type(p):=ord_noad; subtype(p):=normal;
+mem[nucleus(p)].hh:=empty_field;
+mem[subscr(p)].hh:=empty_field;
+mem[supscr(p)].hh:=empty_field;
+mem[kcode_noad(p)].hh:=empty_field;
+new_noad:=p;
+end;
+
+@ A few more kinds of noads will complete the set: An |under_noad| has its
+nucleus underlined; an |over_noad| has it overlined. An |accent_noad| places
+an accent over its nucleus; the accent character appears as
+|fam(accent_chr(p))| and |character(accent_chr(p))|. A |vcenter_noad|
+centers its nucleus vertically with respect to the axis of the formula;
+in such noads we always have |math_type(nucleus(p))=sub_box|.
+
+And finally, we have |left_noad| and |right_noad| types, to implement
+\TeX's \.{\\left} and \.{\\right}. The |nucleus| of such noads is
+replaced by a |delimiter| field; thus, for example, `\.{\\left(}' produces
+a |left_noad| such that |delimiter(p)| holds the family and character
+codes for all left parentheses. A |left_noad| never appears in an mlist
+except as the first element, and a |right_noad| never appears in an mlist
+except as the last element; furthermore, we either have both a |left_noad|
+and a |right_noad|, or neither one is present. The |subscr| and |supscr|
+fields are always |empty| in a |left_noad| and a |right_noad|.
+
+@d under_noad=fraction_noad+1 {|type| of a noad for underlining}
+@d over_noad=under_noad+1 {|type| of a noad for overlining}
+@d accent_noad=over_noad+1 {|type| of a noad for accented subformulas}
+@d accent_noad_size=6 {number of |mem| words in an accent noad}
+@d accent_chr(#)==#+5 {the |accent_chr| field of an accent noad}
+@d vcenter_noad=accent_noad+1 {|type| of a noad for \.{\\vcenter}}
+@d left_noad=vcenter_noad+1 {|type| of a noad for \.{\\left}}
+@d right_noad=left_noad+1 {|type| of a noad for \.{\\right}}
+@d delimiter==nucleus {|delimiter| field in left and right noads}
+@d scripts_allowed(#)==(type(#)>=ord_noad)and(type(#)<left_noad)
+
+@ Math formulas can also contain instructions like \.{\\textstyle} that
+override \TeX's normal style rules. A |style_node| is inserted into the
+data structure to record such instructions; it is three words long, so it
+is considered a node instead of a noad. The |subtype| is either |display_style|
+or |text_style| or |script_style| or |script_script_style|. The
+second and third words of a |style_node| are not used, but they are
+present because a |choice_node| is converted to a |style_node|.
+
+\TeX\ uses even numbers 0, 2, 4, 6 to encode the basic styles
+|display_style|, \dots, |script_script_style|, and adds~1 to get the
+``cramped'' versions of these styles. This gives a numerical order that
+is backwards from the convention of Appendix~G in {\sl The \TeX book\/};
+i.e., a smaller style has a larger numerical value.
+@:TeXbook}{\sl The \TeX book@>
+
+@d style_node=unset_node+1 {|type| of a style node}
+@d style_node_size=3 {number of words in a style node}
+@d display_style=0 {|subtype| for \.{\\displaystyle}}
+@d text_style=2 {|subtype| for \.{\\textstyle}}
+@d script_style=4 {|subtype| for \.{\\scriptstyle}}
+@d script_script_style=6 {|subtype| for \.{\\scriptscriptstyle}}
+@d cramped=1 {add this to an uncramped style if you want to cramp it}
+
+@p function new_style(@!s:small_number):pointer; {create a style node}
+var p:pointer; {the new node}
+begin p:=get_node(style_node_size); type(p):=style_node;
+subtype(p):=s; width(p):=0; depth(p):=0; {the |width| and |depth| are not used}
+new_style:=p;
+end;
+
+@ Finally, the \.{\\mathchoice} primitive creates a |choice_node|, which
+has special subfields |display_mlist|, |text_mlist|, |script_mlist|,
+and |script_script_mlist| pointing to the mlists for each style.
+
+@d choice_node=unset_node+2 {|type| of a choice node}
+@d display_mlist(#)==info(#+1) {mlist to be used in display style}
+@d text_mlist(#)==link(#+1) {mlist to be used in text style}
+@d script_mlist(#)==info(#+2) {mlist to be used in script style}
+@d script_script_mlist(#)==link(#+2) {mlist to be used in scriptscript style}
+
+@p function new_choice:pointer; {create a choice node}
+var p:pointer; {the new node}
+begin p:=get_node(style_node_size); type(p):=choice_node;
+subtype(p):=0; {the |subtype| is not used}
+display_mlist(p):=null; text_mlist(p):=null; script_mlist(p):=null;
+script_script_mlist(p):=null;
+new_choice:=p;
+end;
+
+@ Let's consider now the previously unwritten part of |show_node_list|
+that displays the things that can only be present in mlists; this
+program illustrates how to access the data structures just defined.
+
+In the context of the following program, |p| points to a node or noad that
+should be displayed, and the current string contains the ``recursion history''
+that leads to this point. The recursion history consists of a dot for each
+outer level in which |p| is subsidiary to some node, or in which |p| is
+subsidiary to the |nucleus| field of some noad; the dot is replaced by
+`\.\_' or `\.\^' or `\./' or `\.\\' if |p| is descended from the |subscr|
+or |supscr| or |denominator| or |numerator| fields of noads. For example,
+the current string would be `\.{.\^.\_/}' if |p| points to the |ord_noad| for
+|x| in the (ridiculous) formula
+`\.{\$\\sqrt\{a\^\{\\mathinner\{b\_\{c\\over x+y\}\}\}\}\$}'.
+
+@<Cases of |show_node_list| that arise...@>=
+style_node:print_style(subtype(p));
+choice_node:@<Display choice node |p|@>;
+ord_noad,op_noad,bin_noad,rel_noad,open_noad,close_noad,punct_noad,inner_noad,
+  radical_noad,over_noad,under_noad,vcenter_noad,accent_noad,
+  left_noad,right_noad:@<Display normal noad |p|@>;
+fraction_noad:@<Display fraction noad |p|@>;
+
+@ Here are some simple routines used in the display of noads.
+
+@<Declare procedures needed for displaying the elements of mlists@>=
+procedure print_fam_and_char(@!p:pointer;@!t:small_number);
+                                       {prints family and character}
+var @!cx:KANJI_code; {temporary register for KANJI}
+begin print_esc("fam"); print_int(fam(p)); print_char(" ");
+if t=math_char then print_ASCII(qo(character(p)))
+else  begin KANJI(cx):=math_kcode_nucleus(p); print_kanji(cx);
+  end;
+end;
+@#
+procedure print_delimiter(@!p:pointer); {prints a delimiter as 24-bit hex value}
+var a:integer; {accumulator}
+begin a:=small_fam(p)*256+qo(small_char(p));
+a:=a*@"1000+large_fam(p)*256+qo(large_char(p));
+if a<0 then print_int(a) {this should never happen}
+else print_hex(a);
+end;
+
+@ The next subroutine will descend to another level of recursion when a
+subsidiary mlist needs to be displayed. The parameter |c| indicates what
+character is to become part of the recursion history. An empty mlist is
+distinguished from a field with |math_type(p)=empty|, because these are
+not equivalent (as explained above).
+@^recursion@>
+
+@<Declare procedures needed for displaying...@>=
+procedure@?show_info; forward;@t\2@>@?{|show_node_list(info(temp_ptr))|}
+procedure print_subsidiary_data(@!p:pointer;@!c:ASCII_code);
+  {display a noad field}
+begin if cur_length>=depth_threshold then
+  begin if math_type(p)<>empty then print(" []");
+  end
+else  begin append_char(c); {include |c| in the recursion history}
+  temp_ptr:=p; {prepare for |show_info| if recursion is needed}
+  case math_type(p) of
+  math_char, math_jchar: begin print_ln; print_current_string;
+    print_fam_and_char(p,math_type(p));
+    end;
+  sub_box: show_info; {recursive call}
+  sub_mlist: if info(p)=null then
+      begin print_ln; print_current_string; print("{}");
+      end
+    else show_info; {recursive call}
+  othercases do_nothing {|empty|}
+  endcases;@/
+  flush_char; {remove |c| from the recursion history}
+  end;
+end;
+
+@ The inelegant introduction of |show_info| in the code above seems better
+than the alternative of using \PASCAL's strange |forward| declaration for a
+procedure with parameters. The \PASCAL\ convention about dropping parameters
+from a post-|forward| procedure is, frankly, so intolerable to the author
+of \TeX\ that he would rather stoop to communication via a global temporary
+variable. (A similar stoopidity occurred with respect to |hlist_out| and
+|vlist_out| above, and it will occur with respect to |mlist_to_hlist| below.)
+@^Knuth, Donald Ervin@>
+@:PASCAL}{\PASCAL@>
+
+@p procedure show_info; {the reader will kindly forgive this}
+begin show_node_list(info(temp_ptr));
+end;
+
+@ @<Declare procedures needed for displaying...@>=
+procedure print_style(@!c:integer);
+begin case c div 2 of
+0: print_esc("displaystyle"); {|display_style=0|}
+1: print_esc("textstyle"); {|text_style=2|}
+2: print_esc("scriptstyle"); {|script_style=4|}
+3: print_esc("scriptscriptstyle"); {|script_script_style=6|}
+othercases print("Unknown style!")
+endcases;
+end;
+
+@ @<Display choice node |p|@>=
+begin print_esc("mathchoice");
+append_char("D"); show_node_list(display_mlist(p)); flush_char;
+append_char("T"); show_node_list(text_mlist(p)); flush_char;
+append_char("S"); show_node_list(script_mlist(p)); flush_char;
+append_char("s"); show_node_list(script_script_mlist(p)); flush_char;
+end
+
+@ @<Display normal noad |p|@>=
+begin case type(p) of
+ord_noad: print_esc("mathord");
+op_noad: print_esc("mathop");
+bin_noad: print_esc("mathbin");
+rel_noad: print_esc("mathrel");
+open_noad: print_esc("mathopen");
+close_noad: print_esc("mathclose");
+punct_noad: print_esc("mathpunct");
+inner_noad: print_esc("mathinner");
+over_noad: print_esc("overline");
+under_noad: print_esc("underline");
+vcenter_noad: print_esc("vcenter");
+radical_noad: begin print_esc("radical"); print_delimiter(left_delimiter(p));
+  end;
+accent_noad: begin print_esc("accent");
+  print_fam_and_char(accent_chr(p),math_char);
+  end;
+left_noad: begin print_esc("left"); print_delimiter(delimiter(p));
+  end;
+right_noad: begin print_esc("right"); print_delimiter(delimiter(p));
+  end;
+end;
+if subtype(p)<>normal then
+  if subtype(p)=limits then print_esc("limits")
+  else print_esc("nolimits");
+if type(p)<left_noad then print_subsidiary_data(nucleus(p),".");
+print_subsidiary_data(supscr(p),"^");
+print_subsidiary_data(subscr(p),"_");
+end
+
+@ @<Display fraction noad |p|@>=
+begin print_esc("fraction, thickness ");
+if thickness(p)=default_code then print("= default")
+else print_scaled(thickness(p));
+if (small_fam(left_delimiter(p))<>0)or@+
+  (small_char(left_delimiter(p))<>min_quarterword)or@|
+  (large_fam(left_delimiter(p))<>0)or@|
+  (large_char(left_delimiter(p))<>min_quarterword) then
+  begin print(", left-delimiter "); print_delimiter(left_delimiter(p));
+  end;
+if (small_fam(right_delimiter(p))<>0)or@|
+  (small_char(right_delimiter(p))<>min_quarterword)or@|
+  (large_fam(right_delimiter(p))<>0)or@|
+  (large_char(right_delimiter(p))<>min_quarterword) then
+  begin print(", right-delimiter "); print_delimiter(right_delimiter(p));
+  end;
+print_subsidiary_data(numerator(p),"\");
+print_subsidiary_data(denominator(p),"/");
+end
+
+@ That which can be displayed can also be destroyed.
+
+@<Cases of |flush_node_list| that arise...@>=
+style_node: begin free_node(p,style_node_size); goto done;
+  end;
+choice_node:begin flush_node_list(display_mlist(p));
+  flush_node_list(text_mlist(p));
+  flush_node_list(script_mlist(p));
+  flush_node_list(script_script_mlist(p));
+  free_node(p,style_node_size); goto done;
+  end;
+ord_noad,op_noad,bin_noad,rel_noad,open_noad,close_noad,punct_noad,inner_noad,
+  radical_noad,over_noad,under_noad,vcenter_noad,accent_noad:@t@>@;@/
+  begin if math_type(nucleus(p))>=sub_box then
+    flush_node_list(info(nucleus(p)));
+  if math_type(supscr(p))>=sub_box then
+    flush_node_list(info(supscr(p)));
+  if math_type(subscr(p))>=sub_box then
+    flush_node_list(info(subscr(p)));
+  if type(p)=radical_noad then free_node(p,radical_noad_size)
+  else if type(p)=accent_noad then free_node(p,accent_noad_size)
+  else free_node(p,noad_size);
+  goto done;
+  end;
+left_noad,right_noad: begin free_node(p,noad_size); goto done;
+  end;
+fraction_noad: begin flush_node_list(info(numerator(p)));
+  flush_node_list(info(denominator(p)));
+  free_node(p,fraction_noad_size); goto done;
+  end;
+
+@* \[35] Subroutines for math mode.
+In order to convert mlists to hlists, i.e., noads to nodes, we need several
+subroutines that are conveniently dealt with now.
+
+Let us first introduce the macros that make it easy to get at the parameters and
+other font information. A size code, which is a multiple of 16, is added to a
+family number to get an index into the table of internal font numbers
+for each combination of family and size.  (Be alert: Size codes get
+larger as the type gets smaller.)
+
+@d text_size=0 {size code for the largest size in a family}
+@d script_size=16 {size code for the medium size in a family}
+@d script_script_size=32 {size code for the smallest size in a family}
+
+@<Basic printing procedures@>=
+procedure print_size(@!s:integer);
+begin if s=text_size then print_esc("textfont")
+else if s=script_size then print_esc("scriptfont")
+else print_esc("scriptscriptfont");
+end;
+
+@ Before an mlist is converted to an hlist, \TeX\ makes sure that
+the fonts in family~2 have enough parameters to be math-symbol
+fonts, and that the fonts in family~3 have enough parameters to be
+math-extension fonts. The math-symbol parameters are referred to by using the
+following macros, which take a size code as their parameter; for example,
+|num1(cur_size)| gives the value of the |num1| parameter for the current size.
+@^parameters for symbols@>
+@^font parameters@>
+
+@d mathsy_end(#)==fam_fnt(2+#)]].sc
+@d mathsy(#)==font_info[#+param_base[mathsy_end
+@d math_x_height==mathsy(5) {height of `\.x'}
+@d math_quad==mathsy(6) {\.{18mu}}
+@d num1==mathsy(8) {numerator shift-up in display styles}
+@d num2==mathsy(9) {numerator shift-up in non-display, non-\.{\\atop}}
+@d num3==mathsy(10) {numerator shift-up in non-display \.{\\atop}}
+@d denom1==mathsy(11) {denominator shift-down in display styles}
+@d denom2==mathsy(12) {denominator shift-down in non-display styles}
+@d sup1==mathsy(13) {superscript shift-up in uncramped display style}
+@d sup2==mathsy(14) {superscript shift-up in uncramped non-display}
+@d sup3==mathsy(15) {superscript shift-up in cramped styles}
+@d sub1==mathsy(16) {subscript shift-down if superscript is absent}
+@d sub2==mathsy(17) {subscript shift-down if superscript is present}
+@d sup_drop==mathsy(18) {superscript baseline below top of large box}
+@d sub_drop==mathsy(19) {subscript baseline below bottom of large box}
+@d delim1==mathsy(20) {size of \.{\\atopwithdelims} delimiters
+  in display styles}
+@d delim2==mathsy(21) {size of \.{\\atopwithdelims} delimiters in non-displays}
+@d axis_height==mathsy(22) {height of fraction lines above the baseline}
+@d total_mathsy_params=22
+
+@ The math-extension parameters have similar macros, but the size code is
+omitted (since it is always |cur_size| when we refer to such parameters).
+@^parameters for symbols@>
+@^font parameters@>
+
+@d mathex(#)==font_info[#+param_base[fam_fnt(3+cur_size)]].sc
+@d default_rule_thickness==mathex(8) {thickness of \.{\\over} bars}
+@d big_op_spacing1==mathex(9) {minimum clearance above a displayed op}
+@d big_op_spacing2==mathex(10) {minimum clearance below a displayed op}
+@d big_op_spacing3==mathex(11) {minimum baselineskip above displayed op}
+@d big_op_spacing4==mathex(12) {minimum baselineskip below displayed op}
+@d big_op_spacing5==mathex(13) {padding above and below displayed limits}
+@d total_mathex_params=13
+
+@ We also need to compute the change in style between mlists and their
+subsidiaries. The following macros define the subsidiary style for
+an overlined nucleus (|cramped_style|), for a subscript or a superscript
+(|sub_style| or |sup_style|), or for a numerator or denominator (|num_style|
+or |denom_style|).
+
+@d cramped_style(#)==2*(# div 2)+cramped {cramp the style}
+@d sub_style(#)==2*(# div 4)+script_style+cramped {smaller and cramped}
+@d sup_style(#)==2*(# div 4)+script_style+(# mod 2) {smaller}
+@d num_style(#)==#+2-2*(# div 6) {smaller unless already script-script}
+@d denom_style(#)==2*(# div 2)+cramped+2-2*(# div 6) {smaller, cramped}
+
+@ When the style changes, the following piece of program computes associated
+information:
+
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>=
+begin if cur_style<script_style then cur_size:=text_size
+else cur_size:=16*((cur_style-text_style) div 2);
+cur_mu:=x_over_n(math_quad(cur_size),18);
+end
+
+@ Here is a function that returns a pointer to a rule node having a given
+thickness |t|. The rule will extend horizontally to the boundary of the vlist
+that eventually contains it.
+
+@p function fraction_rule(@!t:scaled):pointer;
+  {construct the bar for a fraction}
+var p:pointer; {the new node}
+begin p:=new_rule; height(p):=t; depth(p):=0; fraction_rule:=p;
+end;
+
+@ The |overbar| function returns a pointer to a vlist box that consists of
+a given box |b|, above which has been placed a kern of height |k| under a
+fraction rule of thickness |t| under additional space of height |t|.
+
+@p function overbar(@!b:pointer;@!k,@!t:scaled):pointer;
+var p,@!q:pointer; {nodes being constructed}
+begin p:=new_kern(k); link(p):=b; q:=fraction_rule(t); link(q):=p;
+p:=new_kern(t); link(p):=q; overbar:=vpack(p,natural);
+end;
+
+@ The |var_delimiter| function, which finds or constructs a sufficiently
+large delimiter, is the most interesting of the auxiliary functions that
+currently concern us. Given a pointer |d| to a delimiter field in some noad,
+together with a size code |s| and a vertical distance |v|, this function
+returns a pointer to a box that contains the smallest variant of |d| whose
+height plus depth is |v| or more. (And if no variant is large enough, it
+returns the largest available variant.) In particular, this routine will
+construct arbitrarily large delimiters from extensible components, if
+|d| leads to such characters.
+
+The value returned is a box whose |shift_amount| has been set so that
+the box is vertically centered with respect to the axis in the given size.
+If a built-up symbol is returned, the height of the box before shifting
+will be the height of its topmost component.
+
+@p@t\4@>@<Declare subprocedures for |var_delimiter|@>
+function var_delimiter(@!d:pointer;@!s:small_number;@!v:scaled):pointer;
+label found,continue;
+var b:pointer; {the box that will be constructed}
+@!f,@!g: internal_font_number; {best-so-far and tentative font codes}
+@!c,@!x,@!y: quarterword; {best-so-far and tentative character codes}
+@!m,@!n: integer; {the number of extensible pieces}
+@!u: scaled; {height-plus-depth of a tentative character}
+@!w: scaled; {largest height-plus-depth so far}
+@!q: four_quarters; {character info}
+@!hd: eight_bits; {height-depth byte}
+@!r: four_quarters; {extensible pieces}
+@!z: small_number; {runs through font family members}
+@!large_attempt: boolean; {are we trying the ``large'' variant?}
+begin f:=null_font; w:=0; large_attempt:=false;
+z:=small_fam(d); x:=small_char(d);
+loop@+  begin @<Look at the variants of |(z,x)|; set |f| and |c| whenever
+    a better character is found; |goto found| as soon as a
+    large enough variant is encountered@>;
+  if large_attempt then goto found; {there were none large enough}
+  large_attempt:=true; z:=large_fam(d); x:=large_char(d);
+  end;
+found: if f<>null_font then
+  @<Make variable |b| point to a box for |(f,c)|@>
+else  begin b:=new_null_box;
+  width(b):=null_delimiter_space; {use this width if no delimiter was found}
+  end;
+shift_amount(b):=half(height(b)-depth(b)) - axis_height(s);
+var_delimiter:=b;
+end;
+
+@ The search process is complicated slightly by the facts that some of the
+characters might not be present in some of the fonts, and they might not
+be probed in increasing order of height.
+
+@<Look at the variants of |(z,x)|; set |f| and |c|...@>=
+if (z<>0)or(x<>min_quarterword) then
+  begin z:=z+s+16;
+  repeat z:=z-16; g:=fam_fnt(z);
+  if g<>null_font then
+    @<Look at the list of characters starting with |x| in
+      font |g|; set |f| and |c| whenever
+      a better character is found; |goto found| as soon as a
+      large enough variant is encountered@>;
+  until z<16;
+  end
+
+@ @<Look at the list of characters starting with |x|...@>=
+begin y:=x;
+if (qo(y)>=font_bc[g])and(qo(y)<=font_ec[g]) then
+  begin continue: q:=orig_char_info(g)(y);
+  if char_exists(q) then
+    begin if char_tag(q)=ext_tag then
+      begin f:=g; c:=y; goto found;
+      end;
+    hd:=height_depth(q);
+    u:=char_height(g)(hd)+char_depth(g)(hd);
+    if u>w then
+      begin f:=g; c:=y; w:=u;
+      if u>=v then goto found;
+      end;
+    if char_tag(q)=list_tag then
+      begin y:=rem_byte(q); goto continue;
+      end;
+    end;
+  end;
+end
+
+@ Here is a subroutine that creates a new box, whose list contains a
+single character, and whose width includes the italic correction for
+that character. The height or depth of the box will be negative, if
+the height or depth of the character is negative; thus, this routine
+may deliver a slightly different result than |hpack| would produce.
+
+@<Declare subprocedures for |var_delimiter|@>=
+function char_box(@!f:internal_font_number;@!c:quarterword):pointer;
+var q:four_quarters;
+@!hd:eight_bits; {|height_depth| byte}
+@!b,@!p:pointer; {the new box and its character node}
+begin q:=char_info(f)(c); hd:=height_depth(q);
+b:=new_null_box; width(b):=char_width(f)(q)+char_italic(f)(q);
+height(b):=char_height(f)(hd); depth(b):=char_depth(f)(hd);
+p:=get_avail; character(p):=c; font(p):=f; list_ptr(b):=p; char_box:=b;
+end;
+
+@ When the following code is executed, |char_tag(q)| will be equal to
+|ext_tag| if and only if a built-up symbol is supposed to be returned.
+
+@<Make variable |b| point to a box for |(f,c)|@>=
+if char_tag(q)=ext_tag then
+  @<Construct an extensible character in a new box |b|,
+    using recipe |rem_byte(q)| and font |f|@>
+else b:=char_box(f,c)
+
+@ When we build an extensible character, it's handy to have the
+following subroutine, which puts a given character on top
+of the characters already in box |b|:
+
+@<Declare subprocedures for |var_delimiter|@>=
+procedure stack_into_box(@!b:pointer;@!f:internal_font_number;
+  @!c:quarterword);
+var p:pointer; {new node placed into |b|}
+begin p:=char_box(f,c); link(p):=list_ptr(b); list_ptr(b):=p;
+height(b):=height(p);
+end;
+
+@ Another handy subroutine computes the height plus depth of
+a given character:
+
+@<Declare subprocedures for |var_delimiter|@>=
+function height_plus_depth(@!f:internal_font_number;@!c:quarterword):scaled;
+var q:four_quarters;
+@!hd:eight_bits; {|height_depth| byte}
+begin q:=char_info(f)(c); hd:=height_depth(q);
+height_plus_depth:=char_height(f)(hd)+char_depth(f)(hd);
+end;
+
+@ @<Construct an extensible...@>=
+begin b:=new_null_box;
+type(b):=vlist_node;
+r:=font_info[exten_base[f]+rem_byte(q)].qqqq;@/
+@<Compute the minimum suitable height, |w|, and the corresponding
+  number of extension steps, |n|; also set |width(b)|@>;
+c:=ext_bot(r);
+if c<>min_quarterword then stack_into_box(b,f,c);
+c:=ext_rep(r);
+for m:=1 to n do stack_into_box(b,f,c);
+c:=ext_mid(r);
+if c<>min_quarterword then
+  begin stack_into_box(b,f,c); c:=ext_rep(r);
+  for m:=1 to n do stack_into_box(b,f,c);
+  end;
+c:=ext_top(r);
+if c<>min_quarterword then stack_into_box(b,f,c);
+depth(b):=w-height(b);
+end
+
+@ The width of an extensible character is the width of the repeatable
+module. If this module does not have positive height plus depth,
+we don't use any copies of it, otherwise we use as few as possible
+(in groups of two if there is a middle part).
+
+@<Compute the minimum suitable height, |w|, and...@>=
+c:=ext_rep(r); u:=height_plus_depth(f,c);
+w:=0; q:=char_info(f)(c); width(b):=char_width(f)(q)+char_italic(f)(q);@/
+c:=ext_bot(r);@+if c<>min_quarterword then w:=w+height_plus_depth(f,c);
+c:=ext_mid(r);@+if c<>min_quarterword then w:=w+height_plus_depth(f,c);
+c:=ext_top(r);@+if c<>min_quarterword then w:=w+height_plus_depth(f,c);
+n:=0;
+if u>0 then while w<v do
+  begin w:=w+u; incr(n);
+  if ext_mid(r)<>min_quarterword then w:=w+u;
+  end
+
+@ The next subroutine is much simpler; it is used for numerators and
+denominators of fractions as well as for displayed operators and
+their limits above and below. It takes a given box~|b| and
+changes it so that the new box is centered in a box of width~|w|.
+The centering is done by putting \.{\\hss} glue at the left and right
+of the list inside |b|, then packaging the new box; thus, the
+actual box might not really be centered, if it already contains
+infinite glue.
+
+The given box might contain a single character whose italic correction
+has been added to the width of the box; in this case a compensating
+kern is inserted.
+
+@p function rebox(@!b:pointer;@!w:scaled):pointer;
+var p:pointer; {temporary register for list manipulation}
+@!f:internal_font_number; {font in a one-character box}
+@!v:scaled; {width of a character without italic correction}
+begin if (width(b)<>w)and(list_ptr(b)<>null) then
+  begin if type(b)<>hlist_node then b:=hpack(b,natural);
+  p:=list_ptr(b);
+  if is_char_node(p) then
+    if font_dir[font(p)]<>dir_default then
+      begin if link(link(p))=null then
+        begin f:=font(p); v:=char_width(f)(orig_char_info(f)(character(p)));
+        if v<>width(b) then link(link(p)):=new_kern(width(b)-v);
+        end
+      end
+    else if link(p)=null then
+      begin f:=font(p); v:=char_width(f)(orig_char_info(f)(character(p)));
+      if v<>width(b) then link(p):=new_kern(width(b)-v);
+      end;
+  delete_glue_ref(space_ptr(b)); delete_glue_ref(xspace_ptr(b));
+  free_node(b,box_node_size);
+  b:=new_glue(ss_glue); link(b):=p;
+  while link(p)<>null do p:=link(p);
+  link(p):=new_glue(ss_glue);
+  rebox:=hpack(b,w,exactly);
+  end
+else  begin width(b):=w; rebox:=b;
+  end;
+end;
+
+@ Here is a subroutine that creates a new glue specification from another
+one that is expressed in `\.{mu}', given the value of the math unit.
+
+@d mu_mult(#)==nx_plus_y(n,#,xn_over_d(#,f,@'200000))
+
+@p function math_glue(@!g:pointer;@!m:scaled):pointer;
+var p:pointer; {the new glue specification}
+@!n:integer; {integer part of |m|}
+@!f:scaled; {fraction part of |m|}
+begin n:=x_over_n(m,@'200000); f:=remainder;@/
+if f<0 then
+  begin decr(n); f:=f+@'200000;
+  end;
+p:=get_node(glue_spec_size);
+width(p):=mu_mult(width(g)); {convert \.{mu} to \.{pt}}
+stretch_order(p):=stretch_order(g);
+if stretch_order(p)=normal then stretch(p):=mu_mult(stretch(g))
+else stretch(p):=stretch(g);
+shrink_order(p):=shrink_order(g);
+if shrink_order(p)=normal then shrink(p):=mu_mult(shrink(g))
+else shrink(p):=shrink(g);
+math_glue:=p;
+end;
+
+@ The |math_kern| subroutine removes |mu_glue| from a kern node, given
+the value of the math unit.
+
+@p procedure math_kern(@!p:pointer;@!m:scaled);
+var @!n:integer; {integer part of |m|}
+@!f:scaled; {fraction part of |m|}
+begin if subtype(p)=mu_glue then
+  begin n:=x_over_n(m,@'200000); f:=remainder;@/
+  if f<0 then
+    begin decr(n); f:=f+@'200000;
+    end;
+  width(p):=mu_mult(width(p)); subtype(p):=explicit;
+  end;
+end;
+
+@ Sometimes it is necessary to destroy an mlist. The following
+subroutine empties the current list, assuming that |abs(mode)=mmode|.
+
+@p procedure flush_math;
+begin flush_node_list(link(head)); flush_node_list(incompleat_noad);
+link(head):=null; tail:=head; incompleat_noad:=null;
+end;
+
+@* \[36] Typesetting math formulas.
+\TeX's most important routine for dealing with formulas is called
+|mlist_to_hlist|.  After a formula has been scanned and represented as an
+mlist, this routine converts it to an hlist that can be placed into a box
+or incorporated into the text of a paragraph. There are three implicit
+parameters, passed in global variables: |cur_mlist| points to the first
+node or noad in the given mlist (and it might be |null|); |cur_style| is a
+style code; and |mlist_penalties| is |true| if penalty nodes for potential
+line breaks are to be inserted into the resulting hlist. After
+|mlist_to_hlist| has acted, |link(temp_head)| points to the translated hlist.
+
+Since mlists can be inside mlists, the procedure is recursive. And since this
+is not part of \TeX's inner loop, the program has been written in a manner
+that stresses compactness over efficiency.
+@^recursion@>
+
+@<Glob...@>=
+@!cur_mlist:pointer; {beginning of mlist to be translated}
+@!cur_style:small_number; {style code at current place in the list}
+@!cur_size:small_number; {size code corresponding to |cur_style|}
+@!cur_mu:scaled; {the math unit width corresponding to |cur_size|}
+@!mlist_penalties:boolean; {should |mlist_to_hlist| insert penalties?}
+
+@ The recursion in |mlist_to_hlist| is due primarily to a subroutine
+called |clean_box| that puts a given noad field into a box using a given
+math style; |mlist_to_hlist| can call |clean_box|, which can call
+|mlist_to_hlist|.
+@^recursion@>
+
+The box returned by |clean_box| is ``clean'' in the
+sense that its |shift_amount| is zero.
+
+@p procedure@?mlist_to_hlist; forward;@t\2@>@/
+function clean_box(@!p:pointer;@!s:small_number;@!jc:halfword):pointer;
+label found;
+var q:pointer; {beginning of a list to be boxed}
+@!save_style:small_number; {|cur_style| to be restored}
+@!x:pointer; {box to be returned}
+@!r:pointer; {temporary pointer}
+begin case math_type(p) of
+math_char: begin cur_mlist:=new_noad; mem[nucleus(cur_mlist)]:=mem[p];
+  end;
+math_jchar: begin cur_mlist:=new_noad; mem[nucleus(cur_mlist)]:=mem[p];
+  math_kcode(cur_mlist):=jc;
+  end;
+sub_box: begin q:=info(p); goto found;
+  end;
+sub_mlist: cur_mlist:=info(p);
+othercases begin q:=new_null_box; goto found;
+  end
+endcases;@/
+save_style:=cur_style; cur_style:=s; mlist_penalties:=false;@/
+mlist_to_hlist; q:=link(temp_head); {recursive call}
+cur_style:=save_style; {restore the style}
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+found: if is_char_node(q)or(q=null) then x:=hpack(q,natural)
+  else if (link(q)=null)and(type(q)<=dir_node)and(shift_amount(q)=0) then
+    x:=q {it's already clean}
+  else x:=hpack(q,natural);
+@<Simplify a trivial box@>;
+clean_box:=x;
+end;
+
+@ Here we save memory space in a common case.
+
+@<Simplify a trivial box@>=
+q:=list_ptr(x);
+if is_char_node(q) then
+  begin if font_dir[font(q)]<>dir_default then q:=link(q);
+  r:=link(q);
+  if r<>null then if link(r)=null then if not is_char_node(r) then
+   if type(r)=kern_node then {unneeded italic correction}
+    begin free_node(r,small_node_size); link(q):=null;
+    end;
+  end
+
+@ It is convenient to have a procedure that converts a |math_char|
+field to an ``unpacked'' form. The |fetch| routine sets |cur_f|, |cur_c|,
+and |cur_i| to the font code, character code, and character information bytes of
+a given noad field. It also takes care of issuing error messages for
+nonexistent characters; in such cases, |char_exists(cur_i)| will be |false|
+after |fetch| has acted, and the field will also have been reset to |empty|.
+
+@p procedure fetch(@!a:pointer); {unpack the |math_char| field |a|}
+begin cur_c:=character(a); cur_f:=fam_fnt(fam(a)+cur_size);
+if cur_f=null_font then
+  @<Complain about an undefined family and set |cur_i| null@>
+else  begin if font_dir[cur_f]<>dir_default then
+    cur_c:=qi(get_jfm_pos(KANJI(math_kcode_nucleus(a)),cur_f));
+  if (qo(cur_c)>=font_bc[cur_f])and(qo(cur_c)<=font_ec[cur_f]) then
+    cur_i:=orig_char_info(cur_f)(cur_c)
+  else cur_i:=null_character;
+  if not(char_exists(cur_i)) then
+    begin char_warning(cur_f,qo(cur_c));
+    math_type(a):=empty;
+    end;
+  end;
+end;
+
+@ @<Complain about an undefined family...@>=
+begin print_err(""); print_size(cur_size); print_char(" ");
+print_int(fam(a)); print(" is undefined (character ");
+print_ASCII(qo(cur_c)); print_char(")");
+help4("Somewhere in the math formula just ended, you used the")@/
+("stated character from an undefined font family. For example,")@/
+("plain TeX doesn't allow \it or \sl in subscripts. Proceed,")@/
+("and I'll try to forget that I needed that character.");
+error; cur_i:=null_character; math_type(a):=empty;
+end
+
+@ The outputs of |fetch| are placed in global variables.
+
+@<Glob...@>=
+@!cur_f:internal_font_number; {the |font| field of a |math_char|}
+@!cur_c:quarterword; {the |character| field of a |math_char|}
+@!cur_i:four_quarters; {the |char_info| of a |math_char|,
+  or a lig/kern instruction}
+
+@ We need to do a lot of different things, so |mlist_to_hlist| makes two
+passes over the given mlist.
+
+The first pass does most of the processing: It removes ``mu'' spacing from
+glue, it recursively evaluates all subsidiary mlists so that only the
+top-level mlist remains to be handled, it puts fractions and square roots
+and such things into boxes, it attaches subscripts and superscripts, and
+it computes the overall height and depth of the top-level mlist so that
+the size of delimiters for a |left_noad| and a |right_noad| will be known.
+The hlist resulting from each noad is recorded in that noad's |new_hlist|
+field, an integer field that replaces the |nucleus| or |thickness|.
+@^recursion@>
+
+The second pass eliminates all noads and inserts the correct glue and
+penalties between nodes.
+
+@d new_hlist(#)==mem[nucleus(#)].int {the translation of an mlist}
+
+@ Here is the overall plan of |mlist_to_hlist|, and the list of its
+local variables.
+
+@d done_with_noad=80 {go here when a noad has been fully translated}
+@d done_with_node=81 {go here when a node has been fully converted}
+@d check_dimensions=82 {go here to update |max_h| and |max_d|}
+@d delete_q=83 {go here to delete |q| and move to the next node}
+
+@p@t\4@>@<Declare math construction procedures@>
+procedure mlist_to_hlist;
+label reswitch, check_dimensions, done_with_noad, done_with_node, delete_q,
+  done;
+var mlist:pointer; {beginning of the given list}
+@!penalties:boolean; {should penalty nodes be inserted?}
+@!style:small_number; {the given style}
+@!u:pointer; {temporary register}
+@!save_style:small_number; {holds |cur_style| during recursion}
+@!q:pointer; {runs through the mlist}
+@!r:pointer; {the most recent noad preceding |q|}
+@!r_type:small_number; {the |type| of noad |r|, or |op_noad| if |r=null|}
+@!t:small_number; {the effective |type| of noad |q| during the second pass}
+@!p,@!x,@!y,@!z: pointer; {temporary registers for list construction}
+@!pen:integer; {a penalty to be inserted}
+@!s:small_number; {the size of a noad to be deleted}
+@!max_h,@!max_d:scaled; {maximum height and depth of the list translated so far}
+@!delta:scaled; {offset between subscript and superscript}
+begin mlist:=cur_mlist; penalties:=mlist_penalties;
+style:=cur_style; {tuck global parameters away as local variables}
+q:=mlist; r:=null; r_type:=op_noad; max_h:=0; max_d:=0;
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+while q<>null do @<Process node-or-noad |q| as much as possible in preparation
+    for the second pass of |mlist_to_hlist|, then move to the next
+    item in the mlist@>;
+@<Convert \(a)a final |bin_noad| to an |ord_noad|@>;
+@<Make a second pass over the mlist, removing all noads and inserting the
+  proper spacing and penalties@>;
+p:=new_null_box; link(p):=link(temp_head);
+adjust_hlist(p,false); link(temp_head):=link(p);
+delete_glue_ref(space_ptr(p)); delete_glue_ref(xspace_ptr(p));
+free_node(p,box_node_size);
+end;
+
+@ We use the fact that no character nodes appear in an mlist, hence
+the field |type(q)| is always present.
+
+@<Process node-or-noad...@>=
+begin @<Do first-pass processing based on |type(q)|; |goto done_with_noad|
+  if a noad has been fully processed, |goto check_dimensions| if it
+  has been translated into |new_hlist(q)|, or |goto done_with_node|
+  if a node has been fully processed@>;
+check_dimensions: z:=hpack(new_hlist(q),natural);
+if height(z)>max_h then max_h:=height(z);
+if depth(z)>max_d then max_d:=depth(z);
+delete_glue_ref(space_ptr(z)); delete_glue_ref(xspace_ptr(z));
+free_node(z,box_node_size);
+done_with_noad: r:=q; r_type:=type(r);
+done_with_node: q:=link(q);
+end
+
+@ One of the things we must do on the first pass is change a |bin_noad| to
+an |ord_noad| if the |bin_noad| is not in the context of a binary operator.
+The values of |r| and |r_type| make this fairly easy.
+
+@<Do first-pass processing...@>=
+reswitch: delta:=0;
+case type(q) of
+bin_noad: case r_type of
+  bin_noad,op_noad,rel_noad,open_noad,punct_noad,left_noad:
+    begin type(q):=ord_noad; goto reswitch;
+    end;
+  othercases do_nothing
+  endcases;
+rel_noad,close_noad,punct_noad,right_noad: begin@t@>@;@/
+  @<Convert \(a)a final |bin_noad| to an |ord_noad|@>;
+  if type(q)=right_noad then goto done_with_noad;
+  end;
+@t\4@>@<Cases for noads that can follow a |bin_noad|@>@;
+@t\4@>@<Cases for nodes that can appear in an mlist, after which we
+  |goto done_with_node|@>@;
+othercases confusion("mlist1")
+@:this can't happen mlist1}{\quad mlist1@>
+endcases;@/
+@<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@>
+
+@ @<Convert \(a)a final |bin_noad| to an |ord_noad|@>=
+if r_type=bin_noad then type(r):=ord_noad
+
+@ @<Cases for nodes that can appear in an mlist...@>=
+style_node: begin cur_style:=subtype(q);
+  @<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+  goto done_with_node;
+  end;
+choice_node: @<Change this node to a style node followed by the correct choice,
+   then |goto done_with_node|@>;
+ins_node,mark_node,adjust_node,
+  whatsit_node,penalty_node,disc_node: goto done_with_node;
+rule_node: begin if height(q)>max_h then max_h:=height(q);
+  if depth(q)>max_d then max_d:=depth(q); goto done_with_node;
+  end;
+glue_node: begin @<Convert \(m)math glue to ordinary glue@>;
+  goto done_with_node;
+  end;
+kern_node: begin math_kern(q,cur_mu); goto done_with_node;
+  end;
+disp_node: goto done_with_node;
+
+@ @d choose_mlist(#)==begin p:=#(q); #(q):=null;@+end
+
+@<Change this node to a style node...@>=
+begin case cur_style div 2 of
+0: choose_mlist(display_mlist); {|display_style=0|}
+1: choose_mlist(text_mlist); {|text_style=2|}
+2: choose_mlist(script_mlist); {|script_style=4|}
+3: choose_mlist(script_script_mlist); {|script_script_style=6|}
+end; {there are no other cases}
+flush_node_list(display_mlist(q));
+flush_node_list(text_mlist(q));
+flush_node_list(script_mlist(q));
+flush_node_list(script_script_mlist(q));@/
+type(q):=style_node; subtype(q):=cur_style; width(q):=0; depth(q):=0;
+if p<>null then
+  begin z:=link(q); link(q):=p;
+  while link(p)<>null do p:=link(p);
+  link(p):=z;
+  end;
+goto done_with_node;
+end
+
+@ Conditional math glue (`\.{\\nonscript}') results in a |glue_node|
+pointing to |zero_glue|, with |subtype(q)=cond_math_glue|; in such a case
+the node following will be eliminated if it is a glue or kern node and if the
+current size is different from |text_size|. Unconditional math glue
+(`\.{\\muskip}') is converted to normal glue by multiplying the dimensions
+by |cur_mu|.
+@!@:non_script_}{\.{\\nonscript} primitive@>
+
+@<Convert \(m)math glue to ordinary glue@>=
+if subtype(q)=mu_glue then
+  begin x:=glue_ptr(q);
+  y:=math_glue(x,cur_mu); delete_glue_ref(x); glue_ptr(q):=y;
+  subtype(q):=normal;
+  end
+else if (cur_size<>text_size)and(subtype(q)=cond_math_glue) then
+  begin p:=link(q);
+  if p<>null then if (type(p)=glue_node)or(type(p)=kern_node) then
+    begin link(q):=link(p); link(p):=null; flush_node_list(p);
+    end;
+  end
+
+@ @<Cases for noads that can follow a |bin_noad|@>=
+left_noad: goto done_with_noad;
+fraction_noad: begin make_fraction(q); goto check_dimensions;
+  end;
+op_noad: begin delta:=make_op(q);
+  if subtype(q)=limits then goto check_dimensions;
+  end;
+ord_noad: make_ord(q);
+open_noad,inner_noad: do_nothing;
+radical_noad: make_radical(q);
+over_noad: make_over(q);
+under_noad: make_under(q);
+accent_noad: make_math_accent(q);
+vcenter_noad: make_vcenter(q);
+
+@ Most of the actual construction work of |mlist_to_hlist| is done
+by procedures with names
+like |make_fraction|, |make_radical|, etc. To illustrate
+the general setup of such procedures, let's begin with a couple of
+simple ones.
+
+@<Declare math...@>=
+procedure make_over(@!q:pointer);
+begin info(nucleus(q)):=@|
+  overbar(clean_box(nucleus(q),cramped_style(cur_style),math_kcode(q)),@|
+  3*default_rule_thickness,default_rule_thickness);
+math_type(nucleus(q)):=sub_box;
+end;
+
+@ @<Declare math...@>=
+procedure make_under(@!q:pointer);
+var p,@!x,@!y: pointer; {temporary registers for box construction}
+@!delta:scaled; {overall height plus depth}
+begin x:=clean_box(nucleus(q),cur_style,math_kcode(q));
+p:=new_kern(3*default_rule_thickness); link(x):=p;
+link(p):=fraction_rule(default_rule_thickness);
+y:=vpack(x,natural);
+delta:=height(y)+depth(y)+default_rule_thickness;
+height(y):=height(x); depth(y):=delta-height(y);
+info(nucleus(q)):=y; math_type(nucleus(q)):=sub_box;
+end;
+
+@ @<Declare math...@>=
+procedure make_vcenter(@!q:pointer);
+var v:pointer; {the box that should be centered vertically}
+@!delta:scaled; {its height plus depth}
+begin v:=info(nucleus(q));
+if type(v)=dir_node then
+  begin if type(list_ptr(v))<>vlist_node then confusion("dircenter")
+  end
+else  begin if type(v)<>vlist_node then confusion("vcenter")
+  end;
+@:this can't happen vcenter}{\quad vcenter@>
+delta:=height(v)+depth(v);
+height(v):=axis_height(cur_size)+half(delta);
+depth(v):=delta-height(v);
+end;
+
+@ According to the rules in the \.{DVI} file specifications, we ensure alignment
+@^square roots@>
+between a square root sign and the rule above its nucleus by assuming that the
+baseline of the square-root symbol is the same as the bottom of the rule. The
+height of the square-root symbol will be the thickness of the rule, and the
+depth of the square-root symbol should exceed or equal the height-plus-depth
+of the nucleus plus a certain minimum clearance~|clr|. The symbol will be
+placed so that the actual clearance is |clr| plus half the excess.
+
+@<Declare math...@>=
+procedure make_radical(@!q:pointer);
+var x,@!y:pointer; {temporary registers for box construction}
+@!delta,@!clr:scaled; {dimensions involved in the calculation}
+begin x:=clean_box(nucleus(q),cramped_style(cur_style),math_kcode(q));
+if cur_style<text_style then {display style}
+  clr:=default_rule_thickness+(abs(math_x_height(cur_size)) div 4)
+else  begin clr:=default_rule_thickness; clr:=clr + (abs(clr) div 4);
+  end;
+y:=var_delimiter(left_delimiter(q),cur_size,height(x)+depth(x)+clr+
+  default_rule_thickness);
+delta:=depth(y)-(height(x)+depth(x)+clr);
+if delta>0 then clr:=clr+half(delta); {increase the actual clearance}
+shift_amount(y):=-(height(x)+clr);
+link(y):=overbar(x,clr,height(y));
+info(nucleus(q)):=hpack(y,natural); math_type(nucleus(q)):=sub_box;
+end;
+
+@ Slants are not considered when placing accents in math mode. The accenter is
+centered over the accentee, and the accent width is treated as zero with
+respect to the size of the final box.
+
+@<Declare math...@>=
+procedure make_math_accent(@!q:pointer);
+label done,done1;
+var p,@!x,@!y:pointer; {temporary registers for box construction}
+@!a:integer; {address of lig/kern instruction}
+@!c:quarterword; {accent character}
+@!f:internal_font_number; {its font}
+@!i:four_quarters; {its |char_info|}
+@!s:scaled; {amount to skew the accent to the right}
+@!h:scaled; {height of character being accented}
+@!delta:scaled; {space to remove between accent and accentee}
+@!w:scaled; {width of the accentee, not including sub/superscripts}
+begin fetch(accent_chr(q));
+if char_exists(cur_i) then
+  begin i:=cur_i; c:=cur_c; f:=cur_f;@/
+  @<Compute the amount of skew@>;
+  x:=clean_box(nucleus(q),cramped_style(cur_style),math_kcode(q));
+  w:=width(x); h:=height(x);
+  @<Switch to a larger accent if available and appropriate@>;
+  if h<x_height(f) then delta:=h@+else delta:=x_height(f);
+  if (math_type(supscr(q))<>empty)or(math_type(subscr(q))<>empty) then
+    if math_type(nucleus(q))=math_char then
+      @<Swap the subscript and superscript into box |x|@>;
+  y:=char_box(f,c);
+  shift_amount(y):=s+half(w-width(y));
+  width(y):=0; p:=new_kern(-delta); link(p):=x; link(y):=p;
+  y:=vpack(y,natural); width(y):=width(x);
+  if height(y)<h then @<Make the height of box |y| equal to |h|@>;
+  info(nucleus(q)):=y;
+  math_type(nucleus(q)):=sub_box;
+  end;
+end;
+
+@ @<Make the height of box |y|...@>=
+begin p:=new_kern(h-height(y)); link(p):=list_ptr(y); list_ptr(y):=p;
+height(y):=h;
+end
+
+@ @<Switch to a larger accent if available and appropriate@>=
+loop@+  begin if char_tag(i)<>list_tag then goto done;
+  y:=rem_byte(i);
+  i:=orig_char_info(f)(y);
+  if not char_exists(i) then goto done;
+  if char_width(f)(i)>w then goto done;
+  c:=y;
+  end;
+done:
+
+@ @<Compute the amount of skew@>=
+s:=0;
+if math_type(nucleus(q))=math_char then
+  begin fetch(nucleus(q));
+  if char_tag(cur_i)=lig_tag then
+    begin a:=lig_kern_start(cur_f)(cur_i);
+    cur_i:=font_info[a].qqqq;
+    if skip_byte(cur_i)>stop_flag then
+      begin a:=lig_kern_restart(cur_f)(cur_i);
+      cur_i:=font_info[a].qqqq;
+      end;
+    loop@+ begin if qo(next_char(cur_i))=skew_char[cur_f] then
+        begin if op_byte(cur_i)>=kern_flag then
+          if skip_byte(cur_i)<=stop_flag then s:=char_kern(cur_f)(cur_i);
+        goto done1;
+        end;
+      if skip_byte(cur_i)>=stop_flag then goto done1;
+      a:=a+qo(skip_byte(cur_i))+1;
+      cur_i:=font_info[a].qqqq;
+      end;
+    end;
+  end;
+done1:
+
+@ @<Swap the subscript and superscript into box |x|@>=
+begin flush_node_list(x); x:=new_noad;
+mem[nucleus(x)]:=mem[nucleus(q)];
+mem[supscr(x)]:=mem[supscr(q)];
+mem[subscr(x)]:=mem[subscr(q)];@/
+mem[supscr(q)].hh:=empty_field;
+mem[subscr(q)].hh:=empty_field;@/
+math_type(nucleus(q)):=sub_mlist; info(nucleus(q)):=x;
+x:=clean_box(nucleus(q),cur_style,math_kcode(q));
+delta:=delta+height(x)-h; h:=height(x);
+end
+
+@ The |make_fraction| procedure is a bit different because it sets
+|new_hlist(q)| directly rather than making a sub-box.
+
+@<Declare math...@>=
+procedure make_fraction(@!q:pointer);
+var p,@!v,@!x,@!y,@!z:pointer; {temporary registers for box construction}
+@!delta,@!delta1,@!delta2,@!shift_up,@!shift_down,@!clr:scaled;
+  {dimensions for box calculations}
+begin if thickness(q)=default_code then thickness(q):=default_rule_thickness;
+@<Create equal-width boxes |x| and |z| for the numerator and denominator,
+  and compute the default amounts |shift_up| and |shift_down| by which they
+  are displaced from the baseline@>;
+if thickness(q)=0 then @<Adjust \(s)|shift_up| and |shift_down| for the case
+  of no fraction line@>
+else @<Adjust \(s)|shift_up| and |shift_down| for the case of a fraction line@>;
+@<Construct a vlist box for the fraction, according to |shift_up| and
+  |shift_down|@>;
+@<Put the \(f)fraction into a box with its delimiters, and make |new_hlist(q)|
+  point to it@>;
+end;
+
+@ @<Create equal-width boxes |x| and |z| for the numerator and denom...@>=
+x:=clean_box(numerator(q),num_style(cur_style),math_kcode(q));
+z:=clean_box(denominator(q),denom_style(cur_style),math_kcode(q));
+if width(x)<width(z) then x:=rebox(x,width(z))
+else z:=rebox(z,width(x));
+if cur_style<text_style then {display style}
+  begin shift_up:=num1(cur_size); shift_down:=denom1(cur_size);
+  end
+else  begin shift_down:=denom2(cur_size);
+  if thickness(q)<>0 then shift_up:=num2(cur_size)
+  else shift_up:=num3(cur_size);
+  end
+
+@ The numerator and denominator must be separated by a certain minimum
+clearance, called |clr| in the following program. The difference between
+|clr| and the actual clearance is |2delta|.
+
+@<Adjust \(s)|shift_up| and |shift_down| for the case of no fraction line@>=
+begin if cur_style<text_style then clr:=7*default_rule_thickness
+else clr:=3*default_rule_thickness;
+delta:=half(clr-((shift_up-depth(x))-(height(z)-shift_down)));
+if delta>0 then
+  begin shift_up:=shift_up+delta;
+  shift_down:=shift_down+delta;
+  end;
+end
+
+@ In the case of a fraction line, the minimum clearance depends on the actual
+thickness of the line.
+
+@<Adjust \(s)|shift_up| and |shift_down| for the case of a fraction line@>=
+begin if cur_style<text_style then clr:=3*thickness(q)
+else clr:=thickness(q);
+delta:=half(thickness(q));
+delta1:=clr-((shift_up-depth(x))-(axis_height(cur_size)+delta));
+delta2:=clr-((axis_height(cur_size)-delta)-(height(z)-shift_down));
+if delta1>0 then shift_up:=shift_up+delta1;
+if delta2>0 then shift_down:=shift_down+delta2;
+end
+
+@ @<Construct a vlist box for the fraction...@>=
+v:=new_null_box; type(v):=vlist_node;
+height(v):=shift_up+height(x); depth(v):=depth(z)+shift_down;
+width(v):=width(x); {this also equals |width(z)|}
+if thickness(q)=0 then
+  begin p:=new_kern((shift_up-depth(x))-(height(z)-shift_down));
+  link(p):=z;
+  end
+else  begin y:=fraction_rule(thickness(q));@/
+  p:=new_kern((axis_height(cur_size)-delta)-@|(height(z)-shift_down));@/
+  link(y):=p; link(p):=z;@/
+  p:=new_kern((shift_up-depth(x))-(axis_height(cur_size)+delta));
+  link(p):=y;
+  end;
+link(x):=p; list_ptr(v):=x
+
+@ @<Put the \(f)fraction into a box with its delimiters...@>=
+if cur_style<text_style then delta:=delim1(cur_size)
+else delta:=delim2(cur_size);
+x:=var_delimiter(left_delimiter(q), cur_size, delta); link(x):=v;@/
+z:=var_delimiter(right_delimiter(q), cur_size, delta); link(v):=z;@/
+new_hlist(q):=hpack(x,natural)
+
+@ If the nucleus of an |op_noad| is a single character, it is to be
+centered vertically with respect to the axis, after first being enlarged
+(via a character list in the font) if we are in display style.  The normal
+convention for placing displayed limits is to put them above and below the
+operator in display style.
+
+The italic correction is removed from the character if there is a subscript
+and the limits are not being displayed. The |make_op|
+routine returns the value that should be used as an offset between
+subscript and superscript.
+
+After |make_op| has acted, |subtype(q)| will be |limits| if and only if
+the limits have been set above and below the operator. In that case,
+|new_hlist(q)| will already contain the desired final box.
+
+@<Declare math...@>=
+function make_op(@!q:pointer):scaled;
+var delta:scaled; {offset between subscript and superscript}
+@!p,@!v,@!x,@!y,@!z:pointer; {temporary registers for box construction}
+@!c:quarterword;@+@!i:four_quarters; {registers for character examination}
+@!shift_up,@!shift_down:scaled; {dimensions for box calculation}
+begin if (subtype(q)=normal)and(cur_style<text_style) then
+  subtype(q):=limits;
+if math_type(nucleus(q))=math_char then
+  begin fetch(nucleus(q));
+  if (cur_style<text_style)and(char_tag(cur_i)=list_tag) then {make it larger}
+    begin c:=rem_byte(cur_i); i:=orig_char_info(cur_f)(c);
+    if char_exists(i) then
+      begin cur_c:=c; cur_i:=i; character(nucleus(q)):=c;
+      end;
+    end;
+  delta:=char_italic(cur_f)(cur_i);
+  x:=clean_box(nucleus(q),cur_style,math_kcode(q));
+  if (math_type(subscr(q))<>empty)and(subtype(q)<>limits) then
+    width(x):=width(x)-delta; {remove italic correction}
+  shift_amount(x):=half(height(x)-depth(x)) - axis_height(cur_size);
+    {center vertically}
+  math_type(nucleus(q)):=sub_box; info(nucleus(q)):=x;
+  end
+else delta:=0;
+if subtype(q)=limits then
+  @<Construct a box with limits above and below it, skewed by |delta|@>;
+make_op:=delta;
+end;
+
+@ The following program builds a vlist box |v| for displayed limits. The
+width of the box is not affected by the fact that the limits may be skewed.
+
+@<Construct a box with limits above and below it...@>=
+begin x:=clean_box(supscr(q),sup_style(cur_style),math_kcode(q));
+y:=clean_box(nucleus(q),cur_style,math_kcode(q));
+z:=clean_box(subscr(q),sub_style(cur_style),math_kcode(q));
+v:=new_null_box; type(v):=vlist_node; width(v):=width(y);
+if width(x)>width(v) then width(v):=width(x);
+if width(z)>width(v) then width(v):=width(z);
+x:=rebox(x,width(v)); y:=rebox(y,width(v)); z:=rebox(z,width(v));@/
+shift_amount(x):=half(delta); shift_amount(z):=-shift_amount(x);
+height(v):=height(y); depth(v):=depth(y);
+@<Attach the limits to |y| and adjust |height(v)|, |depth(v)| to
+  account for their presence@>;
+new_hlist(q):=v;
+end
+
+@ We use |shift_up| and |shift_down| in the following program for the
+amount of glue between the displayed operator |y| and its limits |x| and
+|z|. The vlist inside box |v| will consist of |x| followed by |y| followed
+by |z|, with kern nodes for the spaces between and around them.
+
+@<Attach the limits to |y| and adjust |height(v)|, |depth(v)|...@>=
+if math_type(supscr(q))=empty then
+  begin
+    delete_glue_ref(space_ptr(x)); delete_glue_ref(xspace_ptr(x));
+    free_node(x,box_node_size); list_ptr(v):=y;
+  end
+else  begin shift_up:=big_op_spacing3-depth(x);
+  if shift_up<big_op_spacing1 then shift_up:=big_op_spacing1;
+  p:=new_kern(shift_up); link(p):=y; link(x):=p;@/
+  p:=new_kern(big_op_spacing5); link(p):=x; list_ptr(v):=p;
+  height(v):=height(v)+big_op_spacing5+height(x)+depth(x)+shift_up;
+  end;
+if math_type(subscr(q))=empty then begin
+  delete_glue_ref(space_ptr(z)); delete_glue_ref(xspace_ptr(z));
+  free_node(z,box_node_size)
+end
+else  begin shift_down:=big_op_spacing4-height(z);
+  if shift_down<big_op_spacing2 then shift_down:=big_op_spacing2;
+  p:=new_kern(shift_down); link(y):=p; link(p):=z;@/
+  p:=new_kern(big_op_spacing5); link(z):=p;
+  depth(v):=depth(v)+big_op_spacing5+height(z)+depth(z)+shift_down;
+  end
+
+@ A ligature found in a math formula does not create a |ligature_node|, because
+there is no question of hyphenation afterwards; the ligature will simply be
+stored in an ordinary |char_node|, after residing in an |ord_noad|.
+
+The |math_type| is converted to |math_text_char| here if we would not want to
+apply an italic correction to the current character unless it belongs
+to a math font (i.e., a font with |space=0|).
+
+No boundary characters enter into these ligatures.
+
+@<Declare math...@>=
+procedure make_ord(@!q:pointer);
+label restart,exit;
+var a:integer; {address of lig/kern instruction}
+@!gp,@!gq,@!p,@!r:pointer; {temporary registers for list manipulation}
+@!rr:halfword;
+begin restart:@t@>@;@/
+if (math_type(subscr(q))=empty)and(math_type(supscr(q))=empty)and@|
+((math_type(nucleus(q))=math_char)or(math_type(nucleus(q))=math_jchar)) then
+  begin p:=link(q);
+  if p<>null then if (type(p)>=ord_noad)and(type(p)<=punct_noad) then
+   if fam(nucleus(p))=fam(nucleus(q)) then
+    if math_type(nucleus(p))=math_char then
+      begin math_type(nucleus(q)):=math_text_char;
+      fetch(nucleus(q));
+      if char_tag(cur_i)=lig_tag then
+        begin a:=lig_kern_start(cur_f)(cur_i);
+        cur_c:=character(nucleus(p));
+        cur_i:=font_info[a].qqqq;
+        if skip_byte(cur_i)>stop_flag then
+          begin a:=lig_kern_restart(cur_f)(cur_i);
+          cur_i:=font_info[a].qqqq;
+          end;
+        loop@+ begin @<If instruction |cur_i| is a kern with |cur_c|, attach
+            the kern after~|q|; or if it is a ligature with |cur_c|, combine
+            noads |q| and~|p| appropriately; then |return| if the cursor has
+            moved past a noad, or |goto restart|@>;
+          if skip_byte(cur_i)>=stop_flag then return;
+          a:=a+qo(skip_byte(cur_i))+1;
+          cur_i:=font_info[a].qqqq;
+          end;
+        end;
+      end
+    else  if math_type(nucleus(p))=math_jchar then
+      begin math_type(nucleus(q)):=math_text_jchar;
+      fetch(nucleus(p)); a:=cur_c; fetch(nucleus(q));
+      if char_tag(cur_i)=gk_tag then
+        begin cur_c:=a; a:=glue_kern_start(cur_f)(cur_i);
+        {|cur_c|:=qi(|get_jfm_pos|(|math_kcode|(p),
+                   |fam_fnt|(fam(nucleus(p))+|cur_size|)));}
+        repeat
+         cur_i:=font_info[a].qqqq;
+         if next_char(cur_i)=cur_c then
+         if op_byte(cur_i)<kern_flag then
+           begin gp:=font_glue[cur_f]; rr:=rem_byte(cur_i);
+           if gp<>null then begin
+             while((type(gp)<>rr)and(link(gp)<>null)) do begin gp:=link(gp);
+               end;
+             gq:=glue_ptr(gp);
+             end
+           else begin gp:=get_node(small_node_size);
+             font_glue[cur_f]:=gp; gq:=null;
+             end;
+           if gq=null then
+             begin type(gp):=rr; gq:=new_spec(zero_glue); glue_ptr(gp):=gq;
+             a:=exten_base[cur_f]+qi((qo(rr))*3); width(gq):=font_info[a].sc;
+             stretch(gq):=font_info[a+1].sc; shrink(gq):=font_info[a+2].sc;
+             add_glue_ref(gq); link(gp):=get_node(small_node_size);
+             gp:=link(gp); glue_ptr(gp):=null; link(gp):=null;
+             end;
+           p:=new_glue(gq); link(p):=link(q); link(q):=p; return;
+           end
+         else begin p:=new_kern(char_kern(cur_f)(cur_i));
+           link(p):=link(q); link(q):=p; return;
+           end;
+         incr(a);
+        until skip_byte(cur_i)>=stop_flag;
+        end;
+      end;
+  end;
+exit:end;
+
+@ Note that a ligature between an |ord_noad| and another kind of noad
+is replaced by an |ord_noad|, when the two noads collapse into one.
+But we could make a parenthesis (say) change shape when it follows
+certain letters. Presumably a font designer will define such
+ligatures only when this convention makes sense.
+
+\chardef\?='174 % vertical line to indicate character retention
+
+@<If instruction |cur_i| is a kern with |cur_c|, ...@>=
+if next_char(cur_i)=cur_c then if skip_byte(cur_i)<=stop_flag then
+  if op_byte(cur_i)>=kern_flag then
+    begin p:=new_kern(char_kern(cur_f)(cur_i));
+    link(p):=link(q); link(q):=p; return;
+    end
+  else  begin check_interrupt; {allow a way out of infinite ligature loop}
+    case op_byte(cur_i) of
+  qi(1),qi(5): character(nucleus(q)):=rem_byte(cur_i); {\.{=:\?}, \.{=:\?>}}
+  qi(2),qi(6): character(nucleus(p)):=rem_byte(cur_i); {\.{\?=:}, \.{\?=:>}}
+  qi(3),qi(7),qi(11):begin r:=new_noad; {\.{\?=:\?}, \.{\?=:\?>}, \.{\?=:\?>>}}
+      character(nucleus(r)):=rem_byte(cur_i);
+      fam(nucleus(r)):=fam(nucleus(q));@/
+      link(q):=r; link(r):=p;
+      if op_byte(cur_i)<qi(11) then math_type(nucleus(r)):=math_char
+      else math_type(nucleus(r)):=math_text_char; {prevent combination}
+      end;
+    othercases begin link(q):=link(p);
+      character(nucleus(q)):=rem_byte(cur_i); {\.{=:}}
+      mem[subscr(q)]:=mem[subscr(p)]; mem[supscr(q)]:=mem[supscr(p)];@/
+      free_node(p,noad_size);
+      end
+    endcases;
+    if op_byte(cur_i)>qi(3) then return;
+    math_type(nucleus(q)):=math_char; goto restart;
+    end
+
+@ When we get to the following part of the program, we have ``fallen through''
+from cases that did not lead to |check_dimensions| or |done_with_noad| or
+|done_with_node|. Thus, |q|~points to a noad whose nucleus may need to be
+converted to an hlist, and whose subscripts and superscripts need to be
+appended if they are present.
+
+If |nucleus(q)| is not a |math_char|, the variable |delta| is the amount
+by which a superscript should be moved right with respect to a subscript
+when both are present.
+@^subscripts@>
+@^superscripts@>
+
+@<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@>=
+case math_type(nucleus(q)) of
+math_char, math_text_char, math_jchar, math_text_jchar:
+  @<Create a character node |p| for |nucleus(q)|, possibly followed
+  by a kern node for the italic correction, and set |delta| to the
+  italic correction if a subscript is present@>;
+empty: p:=null;
+sub_box: p:=info(nucleus(q));
+sub_mlist: begin cur_mlist:=info(nucleus(q)); save_style:=cur_style;
+  mlist_penalties:=false; mlist_to_hlist; {recursive call}
+@^recursion@>
+  cur_style:=save_style; @<Set up the values...@>;
+  p:=hpack(link(temp_head),natural);
+  end;
+othercases confusion("mlist2")
+@:this can't happen mlist2}{\quad mlist2@>
+endcases;@/
+new_hlist(q):=p;
+if (math_type(subscr(q))=empty)and(math_type(supscr(q))=empty) then
+  goto check_dimensions;
+make_scripts(q,delta)
+
+@ @<Create a character node |p| for |nucleus(q)|...@>=
+begin fetch(nucleus(q));
+if char_exists(cur_i) then
+  begin delta:=char_italic(cur_f)(cur_i); p:=new_character(cur_f,qo(cur_c));
+  u:=p;
+  if font_dir[cur_f]<>dir_default then begin
+    link(u):=get_avail; u:=link(u); info(u):=math_kcode(q);
+  end;
+  if ((math_type(nucleus(q))=math_text_char)or
+      (math_type(nucleus(q))=math_text_jchar))and(space(cur_f)<>0) then
+    delta:=0; {no italic correction in mid-word of text font}
+  if (math_type(subscr(q))=empty)and(delta<>0) then begin
+    link(u):=new_kern(delta); delta:=0;
+    end;
+  end
+else p:=null;
+end
+
+@ The purpose of |make_scripts(q,delta)| is to attach the subscript and/or
+superscript of noad |q| to the list that starts at |new_hlist(q)|,
+given that subscript and superscript aren't both empty. The superscript
+will appear to the right of the subscript by a given distance |delta|.
+
+We set |shift_down| and |shift_up| to the minimum amounts to shift the
+baseline of subscripts and superscripts based on the given nucleus.
+
+@<Declare math...@>=
+procedure make_scripts(@!q:pointer;@!delta:scaled);
+var p,@!x,@!y,@!z:pointer; {temporary registers for box construction}
+@!shift_up,@!shift_down,@!clr:scaled; {dimensions in the calculation}
+@!t:small_number; {subsidiary size code}
+begin p:=new_hlist(q);
+if is_char_node(p) then
+  begin shift_up:=0; shift_down:=0;
+  end
+else  begin z:=hpack(p,natural);
+  if cur_style<script_style then t:=script_size@+else t:=script_script_size;
+  shift_up:=height(z)-sup_drop(t);
+  shift_down:=depth(z)+sub_drop(t);
+  delete_glue_ref(space_ptr(z)); delete_glue_ref(xspace_ptr(z));
+  free_node(z,box_node_size);
+  end;
+if math_type(supscr(q))=empty then
+  @<Construct a subscript box |x| when there is no superscript@>
+else  begin @<Construct a superscript box |x|@>;
+  if math_type(subscr(q))=empty then shift_amount(x):=-shift_up
+  else @<Construct a sub/superscript combination box |x|, with the
+    superscript offset by |delta|@>;
+  end;
+if new_hlist(q)=null then new_hlist(q):=x
+else  begin p:=new_hlist(q);
+  while link(p)<>null do p:=link(p);
+  link(p):=x;
+  end;
+end;
+
+@ When there is a subscript without a superscript, the top of the subscript
+should not exceed the baseline plus four-fifths of the x-height.
+
+@<Construct a subscript box |x| when there is no superscript@>=
+begin x:=clean_box(subscr(q),sub_style(cur_style),math_kcode(q));
+width(x):=width(x)+script_space;
+if shift_down<sub1(cur_size) then shift_down:=sub1(cur_size);
+clr:=height(x)-(abs(math_x_height(cur_size)*4) div 5);
+if shift_down<clr then shift_down:=clr;
+shift_amount(x):=shift_down;
+end
+
+@ The bottom of a superscript should never descend below the baseline plus
+one-fourth of the x-height.
+
+@<Construct a superscript box |x|@>=
+begin x:=clean_box(supscr(q),sup_style(cur_style),math_kcode(q));
+width(x):=width(x)+script_space;
+if odd(cur_style) then clr:=sup3(cur_size)
+else if cur_style<text_style then clr:=sup1(cur_size)
+else clr:=sup2(cur_size);
+if shift_up<clr then shift_up:=clr;
+clr:=depth(x)+(abs(math_x_height(cur_size)) div 4);
+if shift_up<clr then shift_up:=clr;
+end
+
+@ When both subscript and superscript are present, the subscript must be
+separated from the superscript by at least four times |default_rule_thickness|.
+If this condition would be violated, the subscript moves down, after which
+both subscript and superscript move up so that the bottom of the superscript
+is at least as high as the baseline plus four-fifths of the x-height.
+
+@<Construct a sub/superscript combination box |x|...@>=
+begin y:=clean_box(subscr(q),sub_style(cur_style),math_kcode(q));
+width(y):=width(y)+script_space;
+if shift_down<sub2(cur_size) then shift_down:=sub2(cur_size);
+clr:=4*default_rule_thickness-
+  ((shift_up-depth(x))-(height(y)-shift_down));
+if clr>0 then
+  begin shift_down:=shift_down+clr;
+  clr:=(abs(math_x_height(cur_size)*4) div 5)-(shift_up-depth(x));
+  if clr>0 then
+    begin shift_up:=shift_up+clr;
+    shift_down:=shift_down-clr;
+    end;
+  end;
+shift_amount(x):=delta; {superscript is |delta| to the right of the subscript}
+p:=new_kern((shift_up-depth(x))-(height(y)-shift_down)); link(x):=p; link(p):=y;
+x:=vpack(x,natural); shift_amount(x):=shift_down;
+end
+
+@ We have now tied up all the loose ends of the first pass of |mlist_to_hlist|.
+The second pass simply goes through and hooks everything together with the
+proper glue and penalties. It also handles the |left_noad| and |right_noad| that
+might be present, since |max_h| and |max_d| are now known. Variable |p| points
+to a node at the current end of the final hlist.
+
+@<Make a second pass over the mlist, ...@>=
+p:=temp_head; link(p):=null; q:=mlist; r_type:=0; cur_style:=style;
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+while q<>null do
+  begin @<If node |q| is a style node, change the style and |goto delete_q|;
+    otherwise if it is not a noad, put it into the hlist,
+    advance |q|, and |goto done|; otherwise set |s| to the size
+    of noad |q|, set |t| to the associated type (|ord_noad..
+    inner_noad|), and set |pen| to the associated penalty@>;
+  @<Append inter-element spacing based on |r_type| and |t|@>;
+  @<Append any |new_hlist| entries for |q|, and any appropriate penalties@>;
+  r_type:=t;
+  delete_q: r:=q; q:=link(q); free_node(r,s);
+  done: end
+
+@ Just before doing the big |case| switch in the second pass, the program
+sets up default values so that most of the branches are short.
+
+@<If node |q| is a style node, change the style...@>=
+t:=ord_noad; s:=noad_size; pen:=inf_penalty;
+case type(q) of
+op_noad,open_noad,close_noad,punct_noad,inner_noad: t:=type(q);
+bin_noad: begin t:=bin_noad; pen:=bin_op_penalty;
+  end;
+rel_noad: begin t:=rel_noad; pen:=rel_penalty;
+  end;
+ord_noad,vcenter_noad,over_noad,under_noad: do_nothing;
+radical_noad: s:=radical_noad_size;
+accent_noad: s:=accent_noad_size;
+fraction_noad: begin t:=inner_noad; s:=fraction_noad_size;
+  end;
+left_noad,right_noad: t:=make_left_right(q,style,max_d,max_h);
+style_node: @<Change the current style and |goto delete_q|@>;
+whatsit_node,penalty_node,rule_node,disc_node,adjust_node,ins_node,mark_node,
+ glue_node,kern_node:@t@>@;@/
+  begin link(p):=q; p:=q; q:=link(q); link(p):=null; goto done;
+  end;
+disp_node: begin link(p):=q; p:=q; q:=link(q); link(p):=null; goto done;
+  end;
+othercases confusion("mlist3")
+@:this can't happen mlist3}{\quad mlist3@>
+endcases
+
+@ The |make_left_right| function constructs a left or right delimiter of
+the required size and returns the value |open_noad| or |close_noad|. The
+|right_noad| and |left_noad| will both be based on the original |style|,
+so they will have consistent sizes.
+
+We use the fact that |right_noad-left_noad=close_noad-open_noad|.
+
+@<Declare math...@>=
+function make_left_right(@!q:pointer;@!style:small_number;
+  @!max_d,@!max_h:scaled):small_number;
+var delta,@!delta1,@!delta2:scaled; {dimensions used in the calculation}
+begin if style<script_style then cur_size:=text_size
+else cur_size:=16*((style-text_style) div 2);
+delta2:=max_d+axis_height(cur_size);
+delta1:=max_h+max_d-delta2;
+if delta2>delta1 then delta1:=delta2; {|delta1| is max distance from axis}
+delta:=(delta1 div 500)*delimiter_factor;
+delta2:=delta1+delta1-delimiter_shortfall;
+if delta<delta2 then delta:=delta2;
+new_hlist(q):=var_delimiter(delimiter(q),cur_size,delta);
+make_left_right:=type(q)-(left_noad-open_noad); {|open_noad| or |close_noad|}
+end;
+
+@ @<Change the current style and |goto delete_q|@>=
+begin cur_style:=subtype(q); s:=style_node_size;
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+goto delete_q;
+end
+
+@ The inter-element spacing in math formulas depends on a $8\times8$ table that
+\TeX\ preloads as a 64-digit string. The elements of this string have the
+following significance:
+$$\vbox{\halign{#\hfil\cr
+\.0 means no space;\cr
+\.1 means a conditional thin space (\.{\\nonscript\\mskip\\thinmuskip});\cr
+\.2 means a thin space (\.{\\mskip\\thinmuskip});\cr
+\.3 means a conditional medium space
+  (\.{\\nonscript\\mskip\\medmuskip});\cr
+\.4 means a conditional thick space
+  (\.{\\nonscript\\mskip\\thickmuskip});\cr
+\.* means an impossible case.\cr}}$$
+This is all pretty cryptic, but {\sl The \TeX book\/} explains what is
+supposed to happen, and the string makes it happen.
+@:TeXbook}{\sl The \TeX book@>
+
+A global variable |magic_offset| is computed so that if |a| and |b| are
+in the range |ord_noad..inner_noad|, then |str_pool[a*8+b+magic_offset]|
+is the digit for spacing between noad types |a| and |b|.
+
+If \PASCAL\ had provided a good way to preload constant arrays, this part of
+the program would not have been so strange.
+@:PASCAL}{\PASCAL@>
+
+@d math_spacing=@;@/
+@t\hskip-35pt@>
+"0234000122*4000133**3**344*0400400*000000234000111*1111112341011"
+@t$ \hskip-35pt$@>
+
+@<Glob...@>=
+@!magic_offset:integer; {used to find inter-element spacing}
+
+@ @<Compute the magic offset@>=
+magic_offset:=str_start[math_spacing]-9*ord_noad
+
+@ @<Append inter-element spacing based on |r_type| and |t|@>=
+if r_type>0 then {not the first noad}
+  begin case so(str_pool[r_type*8+t+magic_offset]) of
+  "0": x:=0;
+  "1": if cur_style<script_style then x:=thin_mu_skip_code@+else x:=0;
+  "2": x:=thin_mu_skip_code;
+  "3": if cur_style<script_style then x:=med_mu_skip_code@+else x:=0;
+  "4": if cur_style<script_style then x:=thick_mu_skip_code@+else x:=0;
+  othercases confusion("mlist4")
+@:this can't happen mlist4}{\quad mlist4@>
+  endcases;
+  if x<>0 then
+    begin y:=math_glue(glue_par(x),cur_mu);
+    z:=new_glue(y); glue_ref_count(y):=null; link(p):=z; p:=z;@/
+    subtype(z):=x+1; {store a symbolic subtype}
+    end;
+  end
+
+@ We insert a penalty node after the hlist entries of noad |q| if |pen|
+is not an ``infinite'' penalty, and if the node immediately following |q|
+is not a penalty node or a |rel_noad| or absent entirely.
+
+@<Append any |new_hlist| entries for |q|, and any appropriate penalties@>=
+if new_hlist(q)<>null then
+  begin link(p):=new_hlist(q);
+  repeat p:=link(p);
+  until link(p)=null;
+  end;
+if penalties then if link(q)<>null then if pen<inf_penalty then
+  begin r_type:=type(link(q));
+  if r_type<>penalty_node then if r_type<>rel_noad then
+    begin z:=new_penalty(pen); link(p):=z; p:=z;
+    end;
+  end
+
+@* \[37] Alignment.
+It's sort of a miracle whenever \.{\\halign} and \.{\\valign} work, because
+they cut across so many of the control structures of \TeX.
+
+Therefore the
+present page is probably not the best place for a beginner to start reading
+this program; it is better to master everything else first.
+
+Let us focus our thoughts on an example of what the input might be, in order
+to get some idea about how the alignment miracle happens. The example doesn't
+do anything useful, but it is sufficiently general to indicate all of the
+special cases that must be dealt with; please do not be disturbed by its
+apparent complexity and meaninglessness.
+$$\vbox{\halign{\.{#}\hfil\cr
+{}\\tabskip 2pt plus 3pt\cr
+{}\\halign to 300pt\{u1\#v1\&\cr
+\hskip 50pt\\tabskip 1pt plus 1fil u2\#v2\&\cr
+\hskip 50pt u3\#v3\\cr\cr
+\hskip 25pt a1\&\\omit a2\&\\vrule\\cr\cr
+\hskip 25pt \\noalign\{\\vskip 3pt\}\cr
+\hskip 25pt b1\\span b2\\cr\cr
+\hskip 25pt \\omit\&c2\\span\\omit\\cr\}\cr}}$$
+Here's what happens:
+
+\yskip
+(0) When `\.{\\halign to 300pt\{}' is scanned, the |scan_spec| routine
+places the 300pt dimension onto the |save_stack|, and an |align_group|
+code is placed above it. This will make it possible to complete the alignment
+when the matching `\.\}' is found.
+
+(1) The preamble is scanned next. Macros in the preamble are not expanded,
+@^preamble@>
+except as part of a tabskip specification. For example, if \.{u2} had been
+a macro in the preamble above, it would have been expanded, since \TeX\
+must look for `\.{minus...}' as part of the tabskip glue. A ``preamble list''
+is constructed based on the user's preamble; in our case it contains the
+following seven items:
+$$\vbox{\halign{\.{#}\hfil\qquad&(#)\hfil\cr
+{}\\glue 2pt plus 3pt&the tabskip preceding column 1\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 1\cr
+{}\\glue 2pt plus 3pt&the tabskip between columns 1 and 2\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 2\cr
+{}\\glue 1pt plus 1fil&the tabskip between columns 2 and 3\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 3\cr
+{}\\glue 1pt plus 1fil&the tabskip following column 3\cr}}$$
+These ``alignrecord'' entries have the same size as an |unset_node|,
+since they will later be converted into such nodes. However, at the
+moment they have no |type| or |subtype| fields; they have |info| fields
+instead, and these |info| fields are initially set to the value |end_span|,
+for reasons explained below. Furthermore, the alignrecord nodes have no
+|height| or |depth| fields; these are renamed |u_part| and |v_part|,
+and they point to token lists for the templates of the alignment.
+For example, the |u_part| field in the first alignrecord points to the
+token list `\.{u1}', i.e., the template preceding the `\.\#' for column~1.
+
+(2) \TeX\ now looks at what follows the \.{\\cr} that ended the preamble.
+It is not `\.{\\noalign}' or `\.{\\omit}', so this input is put back to
+be read again, and the template `\.{u1}' is fed to the scanner. Just
+before reading `\.{u1}', \TeX\ goes into restricted horizontal mode.
+Just after reading `\.{u1}', \TeX\ will see `\.{a1}', and then (when the
+{\.\&} is sensed) \TeX\ will see `\.{v1}'. Then \TeX\ scans an |endv|
+token, indicating the end of a column. At this point an |unset_node| is
+created, containing the contents of the current hlist (i.e., `\.{u1a1v1}').
+The natural width of this unset node replaces the |width| field of the
+alignrecord for column~1; in general, the alignrecords will record the
+maximum natural width that has occurred so far in a given column.
+
+(3) Since `\.{\\omit}' follows the `\.\&', the templates for column~2
+are now bypassed. Again \TeX\ goes into restricted horizontal mode and
+makes an |unset_node| from the resulting hlist; but this time the
+hlist contains simply `\.{a2}'. The natural width of the new unset box
+is remembered in the |width| field of the alignrecord for column~2.
+
+(4) A third |unset_node| is created for column 3, using essentially the
+mechanism that worked for column~1; this unset box contains `\.{u3\\vrule
+v3}'. The vertical rule in this case has running dimensions that will later
+extend to the height and depth of the whole first row, since each |unset_node|
+in a row will eventually inherit the height and depth of its enclosing box.
+
+(5) The first row has now ended; it is made into a single unset box
+comprising the following seven items:
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: u1a1v1\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: a2\cr
+{}\\glue 1pt plus 1fil\cr
+{}\\unsetbox for 1 column: u3\\vrule v3\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+The width of this unset row is unimportant, but it has the correct height
+and depth, so the correct baselineskip glue will be computed as the row
+is inserted into a vertical list.
+
+(6) Since `\.{\\noalign}' follows the current \.{\\cr}, \TeX\ appends
+additional material (in this case \.{\\vskip 3pt}) to the vertical list.
+While processing this material, \TeX\ will be in internal vertical
+mode, and |no_align_group| will be on |save_stack|.
+
+(7) The next row produces an unset box that looks like this:
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 2 columns: u1b1v1u2b2v2\cr
+{}\\glue 1pt plus 1fil\cr
+{}\\unsetbox for 1 column: {\rm(empty)}\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+The natural width of the unset box that spans columns 1~and~2 is stored
+in a ``span node,'' which we will explain later; the |info| field of the
+alignrecord for column~1 now points to the new span node, and the |info|
+of the span node points to |end_span|.
+
+(8) The final row produces the unset box
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: {\rm(empty)}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 2 columns: u2c2v2\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+A new span node is attached to the alignrecord for column 2.
+
+(9) The last step is to compute the true column widths and to change all the
+unset boxes to hboxes, appending the whole works to the vertical list that
+encloses the \.{\\halign}. The rules for deciding on the final widths of
+each unset column box will be explained below.
+
+\yskip\noindent
+Note that as \.{\\halign} is being processed, we fearlessly give up control
+to the rest of \TeX. At critical junctures, an alignment routine is
+called upon to step in and do some little action, but most of the time
+these routines just lurk in the background. It's something like
+post-hypnotic suggestion.
+
+@ We have mentioned that alignrecords contain no |height| or |depth| fields.
+Their |glue_sign| and |glue_order| are pre-empted as well, since it
+is necessary to store information about what to do when a template ends.
+This information is called the |extra_info| field.
+
+@d u_part(#)==mem[#+height_offset].int {pointer to \<u_j> token list}
+@d v_part(#)==mem[#+depth_offset].int {pointer to \<v_j> token list}
+@d extra_info(#)==info(#+list_offset) {info to remember during template}
+
+@ Alignments can occur within alignments, so a small stack is used to access
+the alignrecord information. At each level we have a |preamble| pointer,
+indicating the beginning of the preamble list; a |cur_align| pointer,
+indicating the current position in the preamble list; a |cur_span| pointer,
+indicating the value of |cur_align| at the beginning of a sequence of
+spanned columns; a |cur_loop| pointer, indicating the tabskip glue before
+an alignrecord that should be copied next if the current list is extended;
+and the |align_state| variable, which indicates the nesting of braces so
+that \.{\\cr} and \.{\\span} and tab marks are properly intercepted.
+There also are pointers |cur_head| and |cur_tail| to the head and tail
+of a list of adjustments being moved out from horizontal mode to
+vertical~mode.
+
+The current values of these seven quantities appear in global variables;
+when they have to be pushed down, they are stored in 5-word nodes, and
+|align_ptr| points to the topmost such node.
+
+@d preamble==link(align_head) {the current preamble list}
+@d align_stack_node_size=5 {number of |mem| words to save alignment states}
+
+@<Glob...@>=
+@!cur_align:pointer; {current position in preamble list}
+@!cur_span:pointer; {start of currently spanned columns in preamble list}
+@!cur_loop:pointer; {place to copy when extending a periodic preamble}
+@!align_ptr:pointer; {most recently pushed-down alignment stack node}
+@!cur_head,@!cur_tail:pointer; {adjustment list pointers}
+
+@ The |align_state| and |preamble| variables are initialized elsewhere.
+
+@<Set init...@>=
+align_ptr:=null; cur_align:=null; cur_span:=null; cur_loop:=null;
+cur_head:=null; cur_tail:=null;
+
+@ Alignment stack maintenance is handled by a pair of trivial routines
+called |push_alignment| and |pop_alignment|.
+
+@p procedure push_alignment;
+var p:pointer; {the new alignment stack node}
+begin p:=get_node(align_stack_node_size);
+link(p):=align_ptr; info(p):=cur_align;
+llink(p):=preamble; rlink(p):=cur_span;
+mem[p+2].int:=cur_loop; mem[p+3].int:=align_state;
+info(p+4):=cur_head; link(p+4):=cur_tail;
+align_ptr:=p;
+cur_head:=get_avail;
+end;
+@#
+procedure pop_alignment;
+var p:pointer; {the top alignment stack node}
+begin free_avail(cur_head);
+p:=align_ptr;
+cur_tail:=link(p+4); cur_head:=info(p+4);
+align_state:=mem[p+3].int; cur_loop:=mem[p+2].int;
+cur_span:=rlink(p); preamble:=llink(p);
+cur_align:=info(p); align_ptr:=link(p);
+free_node(p,align_stack_node_size);
+end;
+
+@ \TeX\ has eight procedures that govern alignments: |init_align| and
+|fin_align| are used at the very beginning and the very end; |init_row| and
+|fin_row| are used at the beginning and end of individual rows; |init_span|
+is used at the beginning of a sequence of spanned columns (possibly involving
+only one column); |init_col| and |fin_col| are used at the beginning and
+end of individual columns; and |align_peek| is used after \.{\\cr} to see
+whether the next item is \.{\\noalign}.
+
+We shall consider these routines in the order they are first used during
+the course of a complete \.{\\halign}, namely |init_align|, |align_peek|,
+|init_row|, |init_span|, |init_col|, |fin_col|, |fin_row|, |fin_align|.
+
+@ When \.{\\halign} or \.{\\valign} has been scanned in an appropriate
+mode, \TeX\ calls |init_align|, whose task is to get everything off to a
+good start. This mostly involves scanning the preamble and putting its
+information into the preamble list.
+@^preamble@>
+
+@p @t\4@>@<Declare the procedure called |get_preamble_token|@>@t@>@/
+procedure@?align_peek; forward;@t\2@>@/
+procedure@?normal_paragraph; forward;@t\2@>@/
+procedure init_align;
+label done, done1, done2, continue;
+var save_cs_ptr:pointer; {|warning_index| value for error messages}
+@!p:pointer; {for short-term temporary use}
+begin save_cs_ptr:=cur_cs; {\.{\\halign} or \.{\\valign}, usually}
+push_alignment; align_state:=-1000000; {enter a new alignment level}
+@<Check for improper alignment in displayed math@>;
+push_nest; {enter a new semantic level}
+@<Change current mode to |-vmode| for \.{\\halign}, |-hmode| for \.{\\valign}@>;
+scan_spec(align_group,false);@/
+@<Scan the preamble and record it in the |preamble| list@>;
+new_save_level(align_group);
+if every_cr<>null then begin_token_list(every_cr,every_cr_text);
+align_peek; {look for \.{\\noalign} or \.{\\omit}}
+end;
+
+@ In vertical modes, |prev_depth| already has the correct value. But
+if we are in |mmode| (displayed formula mode), we reach out to the
+enclosing vertical mode for the |prev_depth| value that produces the
+correct baseline calculations.
+
+@<Change current mode...@>=
+if mode=mmode then
+  begin mode:=-vmode; prev_depth:=nest[nest_ptr-2].aux_field.sc;
+  end
+else if mode>0 then negate(mode)
+
+@ When \.{\\halign} is used as a displayed formula, there should be
+no other pieces of mlists present.
+
+@<Check for improper alignment in displayed math@>=
+if (mode=mmode)and((tail<>head)or(incompleat_noad<>null)) then
+  begin print_err("Improper "); print_esc("halign"); print(" inside $$'s");
+@.Improper \\halign...@>
+  help3("Displays can use special alignments (like \eqalignno)")@/
+  ("only if nothing but the alignment itself is between $$'s.")@/
+  ("So I've deleted the formulas that preceded this alignment.");
+  error; flush_math;
+  end
+
+@ @<Scan the preamble and record it in the |preamble| list@>=
+preamble:=null; cur_align:=align_head; cur_loop:=null; scanner_status:=aligning;
+warning_index:=save_cs_ptr; align_state:=-1000000;
+  {at this point, |cur_cmd=left_brace|}
+loop@+  begin @<Append the current tabskip glue to the preamble list@>;
+  if cur_cmd=car_ret then goto done; {\.{\\cr} ends the preamble}
+  @<Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret|,
+    looking for changes in the tabskip glue; append an
+    alignrecord to the preamble list@>;
+  end;
+done: scanner_status:=normal
+
+@ @<Append the current tabskip glue to the preamble list@>=
+link(cur_align):=new_param_glue(tab_skip_code);
+cur_align:=link(cur_align)
+
+@ @<Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret|...@>=
+@<Scan the template \<u_j>, putting the resulting token list in |hold_head|@>;
+link(cur_align):=new_null_box; cur_align:=link(cur_align); {a new alignrecord}
+info(cur_align):=end_span; width(cur_align):=null_flag;
+u_part(cur_align):=link(hold_head);
+@<Scan the template \<v_j>, putting the resulting token list in |hold_head|@>;
+v_part(cur_align):=link(hold_head)
+
+@ We enter `\.{\\span}' into |eqtb| with |tab_mark| as its command code,
+and with |span_code| as the command modifier. This makes \TeX\ interpret it
+essentially the same as an alignment delimiter like `\.\&', yet it is
+recognizably different when we need to distinguish it from a normal delimiter.
+It also turns out to be useful to give a special |cr_code| to `\.{\\cr}',
+and an even larger |cr_cr_code| to `\.{\\crcr}'.
+
+The end of a template is represented by two ``frozen'' control sequences
+called \.{\\endtemplate}. The first has the command code |end_template|, which
+is |>outer_call|, so it will not easily disappear in the presence of errors.
+The |get_x_token| routine converts the first into the second, which has |endv|
+as its command code.
+
+@d span_code=256 {distinct from any character}
+@d cr_code=257 {distinct from |span_code| and from any character}
+@d cr_cr_code=cr_code+1 {this distinguishes \.{\\crcr} from \.{\\cr}}
+@d end_template_token==cs_token_flag+frozen_end_template
+
+@<Put each of \TeX's primitives into the hash table@>=
+primitive("span",tab_mark,span_code);@/
+@!@:span_}{\.{\\span} primitive@>
+primitive("cr",car_ret,cr_code);
+@!@:cr_}{\.{\\cr} primitive@>
+text(frozen_cr):="cr"; eqtb[frozen_cr]:=eqtb[cur_val];@/
+primitive("crcr",car_ret,cr_cr_code);
+@!@:cr_cr_}{\.{\\crcr} primitive@>
+text(frozen_end_template):="endtemplate"; text(frozen_endv):="endtemplate";
+eq_type(frozen_endv):=endv; equiv(frozen_endv):=null_list;
+eq_level(frozen_endv):=level_one;@/
+eqtb[frozen_end_template]:=eqtb[frozen_endv];
+eq_type(frozen_end_template):=end_template;
+
+@ @<Cases of |print_cmd_chr|...@>=
+tab_mark: if chr_code=span_code then print_esc("span")
+  else chr_cmd("alignment tab character ");
+car_ret: if chr_code=cr_code then print_esc("cr")
+  else print_esc("crcr");
+
+@ The preamble is copied directly, except that \.{\\tabskip} causes a change
+to the tabskip glue, thereby possibly expanding macros that immediately
+follow it. An appearance of \.{\\span} also causes such an expansion.
+
+Note that if the preamble contains `\.{\\global\\tabskip}', the `\.{\\global}'
+token survives in the preamble and the `\.{\\tabskip}' defines new
+tabskip glue (locally).
+
+@<Declare the procedure called |get_preamble_token|@>=
+procedure get_preamble_token;
+label restart;
+begin restart: get_token;
+while (cur_chr=span_code)and(cur_cmd=tab_mark) do
+  begin get_token; {this token will be expanded once}
+  if cur_cmd>max_command then
+    begin expand; get_token;
+    end;
+  end;
+if cur_cmd=endv then
+  fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+if (cur_cmd=assign_glue)and(cur_chr=glue_base+tab_skip_code) then
+  begin scan_optional_equals; scan_glue(glue_val);
+  if global_defs>0 then geq_define(glue_base+tab_skip_code,glue_ref,cur_val)
+  else eq_define(glue_base+tab_skip_code,glue_ref,cur_val);
+  goto restart;
+  end;
+end;
+
+@ Spaces are eliminated from the beginning of a template.
+
+@<Scan the template \<u_j>...@>=
+p:=hold_head; link(p):=null;
+loop@+  begin get_preamble_token;
+  if cur_cmd=mac_param then goto done1;
+  if (cur_cmd<=car_ret)and(cur_cmd>=tab_mark)and(align_state=-1000000) then
+   if (p=hold_head)and(cur_loop=null)and(cur_cmd=tab_mark)
+    then cur_loop:=cur_align
+   else  begin print_err("Missing # inserted in alignment preamble");
+@.Missing \# inserted...@>
+    help3("There should be exactly one # between &'s, when an")@/
+    ("\halign or \valign is being set up. In this case you had")@/
+    ("none, so I've put one in; maybe that will work.");
+    back_error; goto done1;
+    end
+  else if (cur_cmd<>spacer)or(p<>hold_head) then
+    begin link(p):=get_avail; p:=link(p); info(p):=cur_tok;
+    end;
+  end;
+done1:
+
+@ @<Scan the template \<v_j>...@>=
+p:=hold_head; link(p):=null;
+loop@+  begin continue: get_preamble_token;
+  if (cur_cmd<=car_ret)and(cur_cmd>=tab_mark)and(align_state=-1000000) then
+    goto done2;
+  if cur_cmd=mac_param then
+    begin print_err("Only one # is allowed per tab");
+@.Only one \# is allowed...@>
+    help3("There should be exactly one # between &'s, when an")@/
+    ("\halign or \valign is being set up. In this case you had")@/
+    ("more than one, so I'm ignoring all but the first.");
+    error; goto continue;
+    end;
+  link(p):=get_avail; p:=link(p); info(p):=cur_tok;
+  end;
+done2: link(p):=get_avail; p:=link(p);
+info(p):=end_template_token {put \.{\\endtemplate} at the end}
+
+@ The tricky part about alignments is getting the templates into the
+scanner at the right time, and recovering control when a row or column
+is finished.
+
+We usually begin a row after each \.{\\cr} has been sensed, unless that
+\.{\\cr} is followed by \.{\\noalign} or by the right brace that terminates
+the alignment. The |align_peek| routine is used to look ahead and do
+the right thing; it either gets a new row started, or gets a \.{\\noalign}
+started, or finishes off the alignment.
+
+@<Declare the procedure called |align_peek|@>=
+procedure align_peek;
+label restart;
+begin restart: align_state:=1000000; @<Get the next non-blank non-call token@>;
+if cur_cmd=no_align then
+  begin scan_left_brace; new_save_level(no_align_group);
+  if mode=-vmode then normal_paragraph;
+  end
+else if cur_cmd=right_brace then fin_align
+else if (cur_cmd=car_ret)and(cur_chr=cr_cr_code) then
+  goto restart {ignore \.{\\crcr}}
+else  begin init_row; {start a new row}
+  init_col; {start a new column and replace what we peeked at}
+  end;
+end;
+
+@ To start a row (i.e., a `row' that rhymes with `dough' but not with `bough'),
+we enter a new semantic level, copy the first tabskip glue, and change
+from internal vertical mode to restricted horizontal mode or vice versa.
+The |space_factor| and |prev_depth| are not used on this semantic level,
+but we clear them to zero just to be tidy.
+
+@p @t\4@>@<Declare the procedure called |init_span|@>@t@>@/
+procedure init_row;
+begin push_nest; mode:=(-hmode-vmode)-mode;
+if mode=-hmode then space_factor:=0 @+else prev_depth:=0;
+tail_append(new_glue(glue_ptr(preamble)));
+subtype(tail):=tab_skip_code+1;@/
+cur_align:=link(preamble); cur_tail:=cur_head; init_span(cur_align);
+end;
+
+@ The parameter to |init_span| is a pointer to the alignrecord where the
+next column or group of columns will begin. A new semantic level is
+entered, so that the columns will generate a list for subsequent packaging.
+
+@<Declare the procedure called |init_span|@>=
+procedure init_span(@!p:pointer);
+begin push_nest;
+if mode=-hmode then space_factor:=1000
+else  begin prev_depth:=ignore_depth; normal_paragraph;
+  end;
+cur_span:=p;
+end;
+
+@ When a column begins, we assume that |cur_cmd| is either |omit| or else
+the current token should be put back into the input until the \<u_j>
+template has been scanned.  (Note that |cur_cmd| might be |tab_mark| or
+|car_ret|.)  We also assume that |align_state| is approximately 1000000 at
+this time.  We remain in the same mode, and start the template if it is
+called for.
+
+@p procedure init_col;
+begin extra_info(cur_align):=cur_cmd;
+if cur_cmd=omit then align_state:=0
+else  begin back_input; begin_token_list(u_part(cur_align),u_template);
+  end; {now |align_state=1000000|}
+end;
+
+@ The scanner sets |align_state| to zero when the \<u_j> template ends. When
+a subsequent \.{\\cr} or \.{\\span} or tab mark occurs with |align_state=0|,
+the scanner activates the following code, which fires up the \<v_j> template.
+We need to remember the |cur_chr|, which is either |cr_cr_code|, |cr_code|,
+|span_code|, or a character code, depending on how the column text has ended.
+
+This part of the program had better not be activated when the preamble
+to another alignment is being scanned, or when no alignment preamble is active.
+
+@<Insert the \(v)\<v_j>...@>=
+begin if (scanner_status=aligning) or (cur_align=null) then
+  fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+cur_cmd:=extra_info(cur_align); extra_info(cur_align):=cur_chr;
+if cur_cmd=omit then begin_token_list(omit_template,v_template)
+else begin_token_list(v_part(cur_align),v_template);
+align_state:=1000000; goto restart;
+end
+
+@ The token list |omit_template| just referred to is a constant token
+list that contains the special control sequence \.{\\endtemplate} only.
+
+@<Initialize the special...@>=
+info(omit_template):=end_template_token; {|link(omit_template)=null|}
+
+@ When the |endv| command at the end of a \<v_j> template comes through the
+scanner, things really start to happen; and it is the |fin_col| routine
+that makes them happen. This routine returns |true| if a row as well as a
+column has been finished.
+
+@p function fin_col:boolean;
+label exit;
+var p:pointer; {the alignrecord after the current one}
+@!q,@!r:pointer; {temporary pointers for list manipulation}
+@!s:pointer; {a new span node}
+@!u:pointer; {a new unset box}
+@!w:scaled; {natural width}
+@!o:glue_ord; {order of infinity}
+@!n:halfword; {span counter}
+begin if cur_align=null then confusion("endv");
+q:=link(cur_align);@+if q=null then confusion("endv");
+@:this can't happen endv}{\quad endv@>
+if align_state<500000 then
+  fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+p:=link(q);
+@<If the preamble list has been traversed, check that the row has ended@>;
+if extra_info(cur_align)<>span_code then
+  begin unsave; new_save_level(align_group);@/
+  @<Package an unset box for the current column and record its width@>;
+  @<Copy the tabskip glue between columns@>;
+  if extra_info(cur_align)>=cr_code then
+    begin fin_col:=true; return;
+    end;
+  init_span(p);
+  end;
+align_state:=1000000; @<Get the next non-blank non-call token@>;
+cur_align:=p;
+init_col; fin_col:=false;
+exit: end;
+
+@ @<If the preamble list has been traversed, check that the row has ended@>=
+if (p=null)and(extra_info(cur_align)<cr_code) then
+ if cur_loop<>null then @<Lengthen the preamble periodically@>
+ else  begin print_err("Extra alignment tab has been changed to ");
+@.Extra alignment tab...@>
+  print_esc("cr");
+  help3("You have given more \span or & marks than there were")@/
+  ("in the preamble to the \halign or \valign now in progress.")@/
+  ("So I'll assume that you meant to type \cr instead.");
+  extra_info(cur_align):=cr_code; error;
+  end
+
+@ @<Lengthen the preamble...@>=
+begin link(q):=new_null_box; p:=link(q); {a new alignrecord}
+info(p):=end_span; width(p):=null_flag; cur_loop:=link(cur_loop);
+@<Copy the templates from node |cur_loop| into node |p|@>;
+cur_loop:=link(cur_loop);
+link(p):=new_glue(glue_ptr(cur_loop));
+end
+
+@ @<Copy the templates from node |cur_loop| into node |p|@>=
+q:=hold_head; r:=u_part(cur_loop);
+while r<>null do
+  begin link(q):=get_avail; q:=link(q); info(q):=info(r); r:=link(r);
+  end;
+link(q):=null; u_part(p):=link(hold_head);
+q:=hold_head; r:=v_part(cur_loop);
+while r<>null do
+  begin link(q):=get_avail; q:=link(q); info(q):=info(r); r:=link(r);
+  end;
+link(q):=null; v_part(p):=link(hold_head)
+
+@ @<Copy the tabskip glue...@>=
+tail_append(new_glue(glue_ptr(link(cur_align))));
+subtype(tail):=tab_skip_code+1
+
+@ @<Package an unset...@>=
+begin if mode=-hmode then
+  begin adjust_tail:=cur_tail; adjust_hlist(head,false);
+  delete_glue_ref(cur_kanji_skip); delete_glue_ref(cur_xkanji_skip);
+  cur_kanji_skip:=space_ptr(head); cur_xkanji_skip:=xspace_ptr(head);
+  add_glue_ref(cur_kanji_skip); add_glue_ref(cur_xkanji_skip);
+  u:=hpack(link(head),natural); w:=width(u);
+  cur_tail:=adjust_tail; adjust_tail:=null;
+  end
+else  begin u:=vpackage(link(head),natural,0); w:=height(u);
+  end;
+n:=min_quarterword; {this represents a span count of 1}
+if cur_span<>cur_align then @<Update width entry for spanned columns@>
+else if w>width(cur_align) then width(cur_align):=w;
+type(u):=unset_node; span_count(u):=n;@/
+@<Determine the stretch order@>;
+glue_order(u):=o; glue_stretch(u):=total_stretch[o];@/
+@<Determine the shrink order@>;
+glue_sign(u):=o; glue_shrink(u):=total_shrink[o];@/
+pop_nest; link(tail):=u; tail:=u;
+end
+
+@ A span node is a 2-word record containing |width|, |info|, and |link|
+fields. The |link| field is not really a link, it indicates the number of
+spanned columns; the |info| field points to a span node for the same
+starting column, having a greater extent of spanning, or to |end_span|,
+which has the largest possible |link| field; the |width| field holds the
+largest natural width corresponding to a particular set of spanned columns.
+
+A list of the maximum widths so far, for spanned columns starting at a
+given column, begins with the |info| field of the alignrecord for that
+column.
+
+@d span_node_size=2 {number of |mem| words for a span node}
+
+@<Initialize the special list heads...@>=
+link(end_span):=max_quarterword+1; info(end_span):=null;
+
+@ @<Update width entry for spanned columns@>=
+begin q:=cur_span;
+repeat incr(n); q:=link(link(q));
+until q=cur_align;
+if n>max_quarterword then confusion("256 spans"); {this can happen, but won't}
+@^system dependencies@>
+@:this can't happen 256 spans}{\quad 256 spans@>
+q:=cur_span; while link(info(q))<n do q:=info(q);
+if link(info(q))>n then
+  begin s:=get_node(span_node_size); info(s):=info(q); link(s):=n;
+  info(q):=s; width(s):=w;
+  end
+else if width(info(q))<w then width(info(q)):=w;
+end
+
+@ At the end of a row, we append an unset box to the current vlist (for
+\.{\\halign}) or the current hlist (for \.{\\valign}). This unset box
+contains the unset boxes for the columns, separated by the tabskip glue.
+Everything will be set later.
+
+@p procedure fin_row;
+var p:pointer; {the new unset box}
+begin if mode=-hmode then
+  begin adjust_hlist(head,false);
+  delete_glue_ref(cur_kanji_skip); delete_glue_ref(cur_xkanji_skip);
+  cur_kanji_skip:=space_ptr(head); cur_xkanji_skip:=xspace_ptr(head);
+  add_glue_ref(cur_kanji_skip); add_glue_ref(cur_xkanji_skip);
+  p:=hpack(link(head),natural);
+  pop_nest; append_to_vlist(p);
+  if cur_head<>cur_tail then
+    begin link(tail):=link(cur_head); tail:=cur_tail;
+    end;
+  end
+else  begin p:=vpack(link(head),natural); pop_nest;
+  link(tail):=p; tail:=p; space_factor:=1000;
+  end;
+type(p):=unset_node; glue_stretch(p):=0;
+if every_cr<>null then begin_token_list(every_cr,every_cr_text);
+align_peek;
+end; {note that |glue_shrink(p)=0| since |glue_shrink==shift_amount|}
+
+@ Finally, we will reach the end of the alignment, and we can breathe a
+sigh of relief that memory hasn't overflowed. All the unset boxes will now be
+set so that the columns line up, taking due account of spanned columns.
+
+@p procedure@?do_assignments; forward;@t\2@>@/
+procedure@?resume_after_display; forward;@t\2@>@/
+procedure@?build_page; forward;@t\2@>@/
+procedure fin_align;
+var @!p,@!q,@!r,@!s,@!u,@!v,@!z: pointer; {registers for the list operations}
+@!t,@!w:scaled; {width of column}
+@!o:scaled; {shift offset for unset boxes}
+@!n:halfword; {matching span amount}
+@!rule_save:scaled; {temporary storage for |overfull_rule|}
+@!aux_save:memory_word; {temporary storage for |aux|}
+begin if cur_group<>align_group then confusion("align1");
+@:this can't happen align}{\quad align@>
+unsave; {that |align_group| was for individual entries}
+if cur_group<>align_group then confusion("align0");
+unsave; {that |align_group| was for the whole alignment}
+if nest[nest_ptr-1].mode_field=mmode then o:=display_indent
+  else o:=0;
+@<Go through the preamble list, determining the column widths and
+  changing the alignrecords to dummy unset boxes@>;
+@<Package the preamble list, to determine the actual tabskip glue amounts,
+  and let |p| point to this prototype box@>;
+@<Set the glue in all the unset boxes of the current list@>;
+flush_node_list(p); pop_alignment;
+@<Insert the \(c)current list into its environment@>;
+end;@/
+@t\4@>@<Declare the procedure called |align_peek|@>
+
+@ It's time now to dismantle the preamble list and to compute the column
+widths. Let $w_{ij}$ be the maximum of the natural widths of all entries
+that span columns $i$ through $j$, inclusive. The alignrecord for column~$i$
+contains $w_{ii}$ in its |width| field, and there is also a linked list of
+the nonzero $w_{ij}$ for increasing $j$, accessible via the |info| field;
+these span nodes contain the value $j-i+|min_quarterword|$ in their
+|link| fields. The values of $w_{ii}$ were initialized to |null_flag|, which
+we regard as $-\infty$.
+
+The final column widths are defined by the formula
+$$w_j=\max_{1\L i\L j}\biggl( w_{ij}-\sum_{i\L k<j}(t_k+w_k)\biggr),$$
+where $t_k$ is the natural width of the tabskip glue between columns
+$k$ and~$k+1$. However, if $w_{ij}=-\infty$ for all |i| in the range
+|1<=i<=j| (i.e., if every entry that involved column~|j| also involved
+column~|j+1|), we let $w_j=0$, and we zero out the tabskip glue after
+column~|j|.
+
+\TeX\ computes these values by using the following scheme: First $w_1=w_{11}$.
+Then replace $w_{2j}$ by $\max(w_{2j},w_{1j}-t_1-w_1)$, for all $j>1$.
+Then $w_2=w_{22}$. Then replace $w_{3j}$ by $\max(w_{3j},w_{2j}-t_2-w_2)$
+for all $j>2$; and so on. If any $w_j$ turns out to be $-\infty$, its
+value is changed to zero and so is the next tabskip.
+
+@<Go through the preamble list,...@>=
+q:=link(preamble);
+repeat flush_list(u_part(q)); flush_list(v_part(q));
+p:=link(link(q));
+if width(q)=null_flag then
+  @<Nullify |width(q)| and the tabskip glue following this column@>;
+if info(q)<>end_span then
+  @<Merge the widths in the span nodes of |q| with those of |p|,
+    destroying the span nodes of |q|@>;
+type(q):=unset_node; span_count(q):=min_quarterword; height(q):=0;
+depth(q):=0; glue_order(q):=normal; glue_sign(q):=normal;
+glue_stretch(q):=0; glue_shrink(q):=0; q:=p;
+until q=null
+
+@ @<Nullify |width(q)| and the tabskip glue following this column@>=
+begin width(q):=0; r:=link(q); s:=glue_ptr(r);
+if s<>zero_glue then
+  begin add_glue_ref(zero_glue); delete_glue_ref(s);
+  glue_ptr(r):=zero_glue;
+  end;
+end
+
+@ Merging of two span-node lists is a typical exercise in the manipulation of
+linearly linked data structures. The essential invariant in the following
+|repeat| loop is that we want to dispense with node |r|, in |q|'s list,
+and |u| is its successor; all nodes of |p|'s list up to and including |s|
+have been processed, and the successor of |s| matches |r| or precedes |r|
+or follows |r|, according as |link(r)=n| or |link(r)>n| or |link(r)<n|.
+
+@<Merge the widths...@>=
+begin t:=width(q)+width(glue_ptr(link(q)));
+r:=info(q); s:=end_span; info(s):=p; n:=min_quarterword+1;
+repeat width(r):=width(r)-t; u:=info(r);
+while link(r)>n do
+  begin s:=info(s); n:=link(info(s))+1;
+  end;
+if link(r)<n then
+  begin info(r):=info(s); info(s):=r; decr(link(r)); s:=r;
+  end
+else  begin if width(r)>width(info(s)) then width(info(s)):=width(r);
+  free_node(r,span_node_size);
+  end;
+r:=u;
+until r=end_span;
+end
+
+@ Now the preamble list has been converted to a list of alternating unset
+boxes and tabskip glue, where the box widths are equal to the final
+column sizes. In case of \.{\\valign}, we change the widths to heights,
+so that a correct error message will be produced if the alignment is
+overfull or underfull.
+
+@<Package the preamble list...@>=
+save_ptr:=save_ptr-2; pack_begin_line:=-mode_line;
+if mode=-vmode then
+  begin rule_save:=overfull_rule;
+  overfull_rule:=0; {prevent rule from being packaged}
+  z:=new_null_box; link(z):=preamble;
+  adjust_hlist(z,false);
+  delete_glue_ref(cur_kanji_skip); delete_glue_ref(cur_xkanji_skip);
+  cur_kanji_skip:=space_ptr(z); cur_xkanji_skip:=xspace_ptr(z);
+  add_glue_ref(cur_kanji_skip); add_glue_ref(cur_xkanji_skip);
+  p:=hpack(preamble,saved(1),saved(0)); overfull_rule:=rule_save;
+  delete_glue_ref(space_ptr(z)); delete_glue_ref(xspace_ptr(z));
+  free_node(z,box_node_size);
+  end
+else  begin q:=link(preamble);
+  repeat height(q):=width(q); width(q):=0; q:=link(link(q));
+  until q=null;
+  p:=vpack(preamble,saved(1),saved(0));
+  q:=link(preamble);
+  repeat width(q):=height(q); height(q):=0; q:=link(link(q));
+  until q=null;
+  end;
+pack_begin_line:=0
+
+@ @<Set the glue in all the unset...@>=
+q:=link(head); s:=head;
+while q<>null do
+  begin if not is_char_node(q) then
+    if type(q)=unset_node then
+      @<Set the unset box |q| and the unset boxes in it@>
+    else if type(q)=rule_node then
+      @<Make the running dimensions in rule |q| extend to the
+        boundaries of the alignment@>;
+  s:=q; q:=link(q);
+  end
+
+@ @<Make the running dimensions in rule |q| extend...@>=
+begin if is_running(width(q)) then width(q):=width(p);
+if is_running(height(q)) then height(q):=height(p);
+if is_running(depth(q)) then depth(q):=depth(p);
+if o<>0 then
+  begin r:=link(q); link(q):=null; q:=hpack(q,natural);
+  shift_amount(q):=o; link(q):=r; link(s):=q;
+  end;
+end
+
+@ The unset box |q| represents a row that contains one or more unset boxes,
+depending on how soon \.{\\cr} occurred in that row.
+
+@<Set the unset box |q| and the unset boxes in it@>=
+begin if mode=-vmode then
+  begin type(q):=hlist_node; width(q):=width(p);
+  end
+else  begin type(q):=vlist_node; height(q):=height(p);
+  end;
+set_box_dir(q)(abs(direction));
+glue_order(q):=glue_order(p); glue_sign(q):=glue_sign(p);
+glue_set(q):=glue_set(p); shift_amount(q):=o;
+r:=link(list_ptr(q)); s:=link(list_ptr(p));
+repeat @<Set the glue in node |r| and change it from an unset node@>;
+r:=link(link(r)); s:=link(link(s));
+until r=null;
+end
+
+@ A box made from spanned columns will be followed by tabskip glue nodes and
+by empty boxes as if there were no spanning. This permits perfect alignment
+of subsequent entries, and it prevents values that depend on floating point
+arithmetic from entering into the dimensions of any boxes.
+
+@<Set the glue in node |r|...@>=
+n:=span_count(r); t:=width(s); w:=t; u:=hold_head;
+while n>min_quarterword do
+  begin decr(n);
+  @<Append tabskip glue and an empty box to list |u|,
+    and update |s| and |t| as the prototype nodes are passed@>;
+  end;
+if mode=-vmode then
+  @<Make the unset node |r| into an |hlist_node| of width |w|,
+    setting the glue as if the width were |t|@>
+else @<Make the unset node |r| into a |vlist_node| of height |w|,
+    setting the glue as if the height were |t|@>;
+shift_amount(r):=0;
+if u<>hold_head then {append blank boxes to account for spanned nodes}
+  begin link(u):=link(r); link(r):=link(hold_head); r:=u;
+  end
+
+@ @<Append tabskip glue and an empty box to list |u|...@>=
+s:=link(s); v:=glue_ptr(s); link(u):=new_glue(v); u:=link(u);
+subtype(u):=tab_skip_code+1; t:=t+width(v);
+if glue_sign(p)=stretching then
+  begin if stretch_order(v)=glue_order(p) then
+    t:=t+round(float(glue_set(p))*stretch(v));
+@^real multiplication@>
+  end
+else if glue_sign(p)=shrinking then
+  begin if shrink_order(v)=glue_order(p) then
+    t:=t-round(float(glue_set(p))*shrink(v));
+  end;
+s:=link(s); link(u):=new_null_box; u:=link(u); t:=t+width(s);
+if mode=-vmode then width(u):=width(s)@+else
+  begin type(u):=vlist_node; height(u):=width(s);
+  end;
+set_box_dir(u)(abs(direction))
+
+@ @<Make the unset node |r| into an |hlist_node| of width |w|...@>=
+begin height(r):=height(q); depth(r):=depth(q);
+if t=width(r) then
+  begin glue_sign(r):=normal; glue_order(r):=normal;
+  set_glue_ratio_zero(glue_set(r));
+  end
+else if t>width(r) then
+  begin glue_sign(r):=stretching;
+  if glue_stretch(r)=0 then set_glue_ratio_zero(glue_set(r))
+  else glue_set(r):=unfloat((t-width(r))/glue_stretch(r));
+@^real division@>
+  end
+else  begin glue_order(r):=glue_sign(r); glue_sign(r):=shrinking;
+  if glue_shrink(r)=0 then set_glue_ratio_zero(glue_set(r))
+  else if (glue_order(r)=normal)and(width(r)-t>glue_shrink(r)) then
+    set_glue_ratio_one(glue_set(r))
+  else glue_set(r):=unfloat((width(r)-t)/glue_shrink(r));
+  end;
+width(r):=w; type(r):=hlist_node;
+set_box_dir(r)(abs(direction));
+end
+
+@ @<Make the unset node |r| into a |vlist_node| of height |w|...@>=
+begin width(r):=width(q);
+if t=height(r) then
+  begin glue_sign(r):=normal; glue_order(r):=normal;
+  set_glue_ratio_zero(glue_set(r));
+  end
+else if t>height(r) then
+  begin glue_sign(r):=stretching;
+  if glue_stretch(r)=0 then set_glue_ratio_zero(glue_set(r))
+  else glue_set(r):=unfloat((t-height(r))/glue_stretch(r));
+@^real division@>
+  end
+else  begin glue_order(r):=glue_sign(r); glue_sign(r):=shrinking;
+  if glue_shrink(r)=0 then set_glue_ratio_zero(glue_set(r))
+  else if (glue_order(r)=normal)and(height(r)-t>glue_shrink(r)) then
+    set_glue_ratio_one(glue_set(r))
+  else glue_set(r):=unfloat((height(r)-t)/glue_shrink(r));
+  end;
+height(r):=w; type(r):=vlist_node;
+set_box_dir(r)(abs(direction));
+end
+
+@ We now have a completed alignment, in the list that starts at |head|
+and ends at |tail|. This list will be merged with the one that encloses
+it. (In case the enclosing mode is |mmode|, for displayed formulas,
+we will need to insert glue before and after the display; that part of the
+program will be deferred until we're more familiar with such operations.)
+
+In restricted horizontal mode, the |clang| part of |aux| is undefined;
+an over-cautious \PASCAL\ runtime system may complain about this.
+@^dirty \PASCAL@>
+
+@<Insert the \(c)current list into its environment@>=
+aux_save:=aux; p:=link(head); q:=tail; pop_nest;
+if mode=mmode then @<Finish an alignment in a display@>
+else  begin aux:=aux_save; link(tail):=p;
+  if p<>null then tail:=q;
+  if mode=vmode then build_page;
+  end
+
+@* \[38] Breaking paragraphs into lines.
+We come now to what is probably the most interesting algorithm of \TeX:
+the mechanism for choosing the ``best possible'' breakpoints that yield
+the individual lines of a paragraph. \TeX's line-breaking algorithm takes
+a given horizontal list and converts it to a sequence of boxes that are
+appended to the current vertical list. In the course of doing this, it
+creates a special data structure containing three kinds of records that are
+not used elsewhere in \TeX. Such nodes are created while a paragraph is
+being processed, and they are destroyed afterwards; thus, the other parts
+of \TeX\ do not need to know anything about how line-breaking is done.
+
+The method used here is based on an approach devised by Michael F. Plass and
+@^Plass, Michael Frederick@>
+@^Knuth, Donald Ervin@>
+the author in 1977, subsequently generalized and improved by the same two
+people in 1980. A detailed discussion appears in {\sl SOFTWARE---Practice
+\AM\ Experience \bf11} (1981), 1119--1184, where it is shown that the
+line-breaking problem can be regarded as a special case of the problem of
+computing the shortest path in an acyclic network. The cited paper includes
+numerous examples and describes the history of line breaking as it has been
+practiced by printers through the ages. The present implementation adds two
+new ideas to the algorithm of 1980: Memory space requirements are considerably
+reduced by using smaller records for inactive nodes than for active ones,
+and arithmetic overflow is avoided by using ``delta distances'' instead of
+keeping track of the total distance from the beginning of the paragraph to the
+current point.
+
+@ The |line_break| procedure should be invoked only in horizontal mode; it
+leaves that mode and places its output into the current vlist of the
+enclosing vertical mode (or internal vertical mode).
+There is one explicit parameter:  |final_widow_penalty| is the amount of
+additional penalty to be inserted before the final line of the paragraph.
+
+There are also a number of implicit parameters: The hlist to be broken
+starts at |link(head)|, and it is nonempty. The value of |prev_graf| in the
+enclosing semantic level tells where the paragraph should begin in the
+sequence of line numbers, in case hanging indentation or \.{\\parshape}
+are in use; |prev_graf| is zero unless this paragraph is being continued
+after a displayed formula.  Other implicit parameters, such as the
+|par_shape_ptr| and various penalties to use for hyphenation, etc., appear
+in |eqtb|.
+
+After |line_break| has acted, it will have updated the current vlist and the
+value of |prev_graf|. Furthermore, the global variable |just_box| will
+point to the final box created by |line_break|, so that the width of this
+line can be ascertained when it is necessary to decide whether to use
+|above_display_skip| or |above_display_short_skip| before a displayed formula.
+
+@<Glob...@>=
+@!just_box:pointer; {the |hlist_node| for the last line of the new paragraph}
+
+@ Since |line_break| is a rather lengthy procedure---sort of a small world unto
+itself---we must build it up little by little, somewhat more cautiously
+than we have done with the simpler procedures of \TeX. Here is the
+general outline.
+
+@p@t\4@>@<Declare subprocedures for |line_break|@>
+procedure line_break(@!final_widow_penalty:integer);
+label done,done1,done2,done3,done4,done5,continue;
+var @<Local variables for line breaking@>@;
+begin pack_begin_line:=mode_line; {this is for over/underfull box messages}
+@<Get ready to start line breaking@>;
+@<Find optimal breakpoints@>;
+@<Break the paragraph at the chosen breakpoints, justify the resulting lines
+to the correct widths, and append them to the current vertical list@>;
+@<Clean up the memory by removing the break nodes@>;
+pack_begin_line:=0;
+end;
+
+@ The first task is to move the list from |head| to |temp_head| and go
+into the enclosing semantic level. We also append the \.{\\parfillskip}
+glue to the end of the paragraph, removing a space (or other glue node) if
+it was there, since spaces usually precede blank lines and instances of
+`\.{\$\$}'. The |par_fill_skip| is preceded by an infinite penalty, so
+it will never be considered as a potential breakpoint.
+
+This code assumes that a |glue_node| and a |penalty_node| occupy the
+same number of |mem|~words.
+@^data structure assumptions@>
+
+@<Get ready to start...@>=
+first_use:=true; chain:=false;
+delete_glue_ref(cur_kanji_skip); delete_glue_ref(cur_xkanji_skip);
+cur_kanji_skip:=space_ptr(head); cur_xkanji_skip:=xspace_ptr(head);
+add_glue_ref(cur_kanji_skip); add_glue_ref(cur_xkanji_skip);
+link(temp_head):=link(head);
+if not is_char_node(tail)and(type(tail)=disp_node) then
+  begin free_node(tail,small_node_size); tail:=prev_node; link(tail):=null
+  end;
+if is_char_node(tail) then tail_append(new_penalty(inf_penalty))
+else if type(tail)<>glue_node then tail_append(new_penalty(inf_penalty))
+else  begin type(tail):=penalty_node; delete_glue_ref(glue_ptr(tail));
+  flush_node_list(leader_ptr(tail)); penalty(tail):=inf_penalty;
+  end;
+link(tail):=new_param_glue(par_fill_skip_code);
+init_cur_lang:=prev_graf mod @'200000;
+init_l_hyf:=prev_graf div @'20000000;
+init_r_hyf:=(prev_graf div @'200000) mod @'100;
+pop_nest;
+
+@ When looking for optimal line breaks, \TeX\ creates a ``break node'' for
+each break that is {\sl feasible}, in the sense that there is a way to end
+a line at the given place without requiring any line to stretch more than
+a given tolerance. A break node is characterized by three things: the position
+of the break (which is a pointer to a |glue_node|, |math_node|, |penalty_node|,
+or |disc_node|); the ordinal number of the line that will follow this
+breakpoint; and the fitness classification of the line that has just
+ended, i.e., |tight_fit|, |decent_fit|, |loose_fit|, or |very_loose_fit|.
+
+@d tight_fit=3 {fitness classification for lines shrinking 0.5 to 1.0 of their
+  shrinkability}
+@d loose_fit=1 {fitness classification for lines stretching 0.5 to 1.0 of their
+  stretchability}
+@d very_loose_fit=0 {fitness classification for lines stretching more than
+  their stretchability}
+@d decent_fit=2 {fitness classification for all other lines}
+
+@ The algorithm essentially determines the best possible way to achieve
+each feasible combination of position, line, and fitness. Thus, it answers
+questions like, ``What is the best way to break the opening part of the
+paragraph so that the fourth line is a tight line ending at such-and-such
+a place?'' However, the fact that all lines are to be the same length
+after a certain point makes it possible to regard all sufficiently large
+line numbers as equivalent, when the looseness parameter is zero, and this
+makes it possible for the algorithm to save space and time.
+
+An ``active node'' and a ``passive node'' are created in |mem| for each
+feasible breakpoint that needs to be considered. Active nodes are three
+words long and passive nodes are two words long. We need active nodes only
+for breakpoints near the place in the paragraph that is currently being
+examined, so they are recycled within a comparatively short time after
+they are created.
+
+@ An active node for a given breakpoint contains six fields:
+
+\yskip\hang|link| points to the next node in the list of active nodes; the
+last active node has |link=last_active|.
+
+\yskip\hang|break_node| points to the passive node associated with this
+breakpoint.
+
+\yskip\hang|line_number| is the number of the line that follows this
+breakpoint.
+
+\yskip\hang|fitness| is the fitness classification of the line ending at this
+breakpoint.
+
+\yskip\hang|type| is either |hyphenated| or |unhyphenated|, depending on
+whether this breakpoint is a |disc_node|.
+
+\yskip\hang|total_demerits| is the minimum possible sum of demerits over all
+lines leading from the beginning of the paragraph to this breakpoint.
+
+\yskip\noindent
+The value of |link(active)| points to the first active node on a linked list
+of all currently active nodes. This list is in order by |line_number|,
+except that nodes with |line_number>easy_line| may be in any order relative
+to each other.
+
+@d active_node_size=3 {number of words in active nodes}
+@d fitness==subtype {|very_loose_fit..tight_fit| on final line for this break}
+@d break_node==rlink {pointer to the corresponding passive node}
+@d line_number==llink {line that begins at this breakpoint}
+@d total_demerits(#)==mem[#+2].int {the quantity that \TeX\ minimizes}
+@d unhyphenated=0 {the |type| of a normal active break node}
+@d hyphenated=1 {the |type| of an active node that breaks at a |disc_node|}
+@d last_active==active {the active list ends where it begins}
+
+@ @<Initialize the special list heads...@>=
+type(last_active):=hyphenated; line_number(last_active):=max_halfword;
+subtype(last_active):=0; {the |subtype| is never examined by the algorithm}
+
+@ The passive node for a given breakpoint contains only four fields:
+
+\yskip\hang|link| points to the passive node created just before this one,
+if any, otherwise it is |null|.
+
+\yskip\hang|cur_break| points to the position of this breakpoint in the
+horizontal list for the paragraph being broken.
+
+\yskip\hang|prev_break| points to the passive node that should precede this
+one in an optimal path to this breakpoint.
+
+\yskip\hang|serial| is equal to |n| if this passive node is the |n|th
+one created during the current pass. (This field is used only when
+printing out detailed statistics about the line-breaking calculations.)
+
+\yskip\noindent
+There is a global variable called |passive| that points to the most
+recently created passive node. Another global variable, |printed_node|,
+is used to help print out the paragraph when detailed information about
+the line-breaking computation is being displayed.
+
+@d passive_node_size=2 {number of words in passive nodes}
+@d cur_break==rlink {in passive node, points to position of this breakpoint}
+@d prev_break==llink {points to passive node that should precede this one}
+@d serial==info {serial number for symbolic identification}
+
+@<Glob...@>=
+@!passive:pointer; {most recent node on passive list}
+@!printed_node:pointer; {most recent node that has been printed}
+@!pass_number:halfword; {the number of passive nodes allocated on this pass}
+
+@ The active list also contains ``delta'' nodes that help the algorithm
+compute the badness of individual lines. Such nodes appear only between two
+active nodes, and they have |type=delta_node|. If |p| and |r| are active nodes
+and if |q| is a delta node between them, so that |link(p)=q| and |link(q)=r|,
+then |q| tells the space difference between lines in the horizontal list that
+start after breakpoint |p| and lines that start after breakpoint |r|. In
+other words, if we know the length of the line that starts after |p| and
+ends at our current position, then the corresponding length of the line that
+starts after |r| is obtained by adding the amounts in node~|q|. A delta node
+contains six scaled numbers, since it must record the net change in glue
+stretchability with respect to all orders of infinity. The natural width
+difference appears in |mem[q+1].sc|; the stretch differences in units of
+pt, fil, fill, and filll appear in |mem[q+2..q+5].sc|; and the shrink difference
+appears in |mem[q+6].sc|. The |subtype| field of a delta node is not used.
+
+@d delta_node_size=7 {number of words in a delta node}
+@d delta_node=2 {|type| field in a delta node}
+
+@ As the algorithm runs, it maintains a set of six delta-like registers
+for the length of the line following the first active breakpoint to the
+current position in the given hlist. When it makes a pass through the
+active list, it also maintains a similar set of six registers for the
+length following the active breakpoint of current interest. A third set
+holds the length of an empty line (namely, the sum of \.{\\leftskip} and
+\.{\\rightskip}); and a fourth set is used to create new delta nodes.
+
+When we pass a delta node we want to do operations like
+$$\hbox{\ignorespaces|for
+k:=1 to 6 do cur_active_width[k]:=cur_active_width[k]+mem[q+k].sc|};$$ and we
+want to do this without the overhead of |for| loops. The |do_all_six|
+macro makes such six-tuples convenient.
+
+@d do_all_six(#)==#(1);#(2);#(3);#(4);#(5);#(6)
+
+@<Glob...@>=
+@!active_width:array[1..6] of scaled;
+  {distance from first active node to~|cur_p|}
+@!cur_active_width:array[1..6] of scaled; {distance from current active node}
+@!background:array[1..6] of scaled; {length of an ``empty'' line}
+@!break_width:array[1..6] of scaled; {length being computed after current break}
+
+@ Let's state the principles of the delta nodes more precisely and concisely,
+so that the following programs will be less obscure. For each legal
+breakpoint~|p| in the paragraph, we define two quantities $\alpha(p)$ and
+$\beta(p)$ such that the length of material in a line from breakpoint~|p|
+to breakpoint~|q| is $\gamma+\beta(q)-\alpha(p)$, for some fixed $\gamma$.
+Intuitively, $\alpha(p)$ and $\beta(q)$ are the total length of material from
+the beginning of the paragraph to a point ``after'' a break at |p| and to a
+point ``before'' a break at |q|; and $\gamma$ is the width of an empty line,
+namely the length contributed by \.{\\leftskip} and \.{\\rightskip}.
+
+Suppose, for example, that the paragraph consists entirely of alternating
+boxes and glue skips; let the boxes have widths $x_1\ldots x_n$ and
+let the skips have widths $y_1\ldots y_n$, so that the paragraph can be
+represented by $x_1y_1\ldots x_ny_n$. Let $p_i$ be the legal breakpoint
+at $y_i$; then $\alpha(p_i)=x_1+y_1+\cdots+x_i+y_i$, and $\beta(p_i)=
+x_1+y_1+\cdots+x_i$. To check this, note that the length of material from
+$p_2$ to $p_5$, say, is $\gamma+x_3+y_3+x_4+y_4+x_5=\gamma+\beta(p_5)
+-\alpha(p_2)$.
+
+The quantities $\alpha$, $\beta$, $\gamma$ involve glue stretchability and
+shrinkability as well as a natural width. If we were to compute $\alpha(p)$
+and $\beta(p)$ for each |p|, we would need multiple precision arithmetic, and
+the multiprecise numbers would have to be kept in the active nodes.
+\TeX\ avoids this problem by working entirely with relative differences
+or ``deltas.'' Suppose, for example, that the active list contains
+$a_1\,\delta_1\,a_2\,\delta_2\,a_3$, where the |a|'s are active breakpoints
+and the $\delta$'s are delta nodes. Then $\delta_1=\alpha(a_1)-\alpha(a_2)$
+and $\delta_2=\alpha(a_2)-\alpha(a_3)$. If the line breaking algorithm is
+currently positioned at some other breakpoint |p|, the |active_width| array
+contains the value $\gamma+\beta(p)-\alpha(a_1)$. If we are scanning through
+the list of active nodes and considering a tentative line that runs from
+$a_2$ to~|p|, say, the |cur_active_width| array will contain the value
+$\gamma+\beta(p)-\alpha(a_2)$. Thus, when we move from $a_2$ to $a_3$,
+we want to add $\alpha(a_2)-\alpha(a_3)$ to |cur_active_width|; and this
+is just $\delta_2$, which appears in the active list between $a_2$ and
+$a_3$. The |background| array contains $\gamma$. The |break_width| array
+will be used to calculate values of new delta nodes when the active
+list is being updated.
+
+@ Glue nodes in a horizontal list that is being paragraphed are not supposed to
+include ``infinite'' shrinkability; that is why the algorithm maintains
+four registers for stretching but only one for shrinking. If the user tries to
+introduce infinite shrinkability, the shrinkability will be reset to finite
+and an error message will be issued. A boolean variable |no_shrink_error_yet|
+prevents this error message from appearing more than once per paragraph.
+
+@d check_shrinkage(#)==if (shrink_order(#)<>normal)and(shrink(#)<>0) then
+  begin #:=finite_shrink(#);
+  end
+
+@<Glob...@>=
+@!no_shrink_error_yet:boolean; {have we complained about infinite shrinkage?}
+
+@ @<Declare subprocedures for |line_break|@>=
+function finite_shrink(@!p:pointer):pointer; {recovers from infinite shrinkage}
+var q:pointer; {new glue specification}
+begin if no_shrink_error_yet then
+  begin no_shrink_error_yet:=false;
+  print_err("Infinite glue shrinkage found in a paragraph");
+@.Infinite glue shrinkage...@>
+  help5("The paragraph just ended includes some glue that has")@/
+  ("infinite shrinkability, e.g., `\hskip 0pt minus 1fil'.")@/
+  ("Such glue doesn't belong there---it allows a paragraph")@/
+  ("of any length to fit on one line. But it's safe to proceed,")@/
+  ("since the offensive shrinkability has been made finite.");
+  error;
+  end;
+q:=new_spec(p); shrink_order(q):=normal;
+delete_glue_ref(p); finite_shrink:=q;
+end;
+
+@ @<Get ready to start...@>=
+no_shrink_error_yet:=true;@/
+check_shrinkage(left_skip); check_shrinkage(right_skip);@/
+q:=left_skip; r:=right_skip; background[1]:=width(q)+width(r);@/
+background[2]:=0; background[3]:=0; background[4]:=0; background[5]:=0;@/
+background[2+stretch_order(q)]:=stretch(q);@/
+background[2+stretch_order(r)]:=@|background[2+stretch_order(r)]+stretch(r);@/
+background[6]:=shrink(q)+shrink(r);
+
+@ A pointer variable |cur_p| runs through the given horizontal list as we look
+for breakpoints. This variable is global, since it is used both by |line_break|
+and by its subprocedure |try_break|.
+
+Another global variable called |threshold| is used to determine the feasibility
+of individual lines: Breakpoints are feasible if there is a way to reach
+them without creating lines whose badness exceeds |threshold|.  (The
+badness is compared to |threshold| before penalties are added, so that
+penalty values do not affect the feasibility of breakpoints, except that
+no break is allowed when the penalty is 10000 or more.) If |threshold|
+is 10000 or more, all legal breaks are considered feasible, since the
+|badness| function specified above never returns a value greater than~10000.
+
+Up to three passes might be made through the paragraph in an attempt to find at
+least one set of feasible breakpoints. On the first pass, we have
+|threshold=pretolerance| and |second_pass=final_pass=false|.
+If this pass fails to find a
+feasible solution, |threshold| is set to |tolerance|, |second_pass| is set
+|true|, and an attempt is made to hyphenate as many words as possible.
+If that fails too, we add |emergency_stretch| to the background
+stretchability and set |final_pass=true|.
+
+@<Glob...@>=
+@!cur_p:pointer; {the current breakpoint under consideration}
+@!chain:boolean; {chain current line and next line?}
+@!second_pass:boolean; {is this our second attempt to break this paragraph?}
+@!final_pass:boolean; {is this our final attempt to break this paragraph?}
+@!threshold:integer; {maximum badness on feasible lines}
+
+@ The heart of the line-breaking procedure is `|try_break|', a subroutine
+that tests if the current breakpoint |cur_p| is feasible, by running
+through the active list to see what lines of text can be made from active
+nodes to~|cur_p|.  If feasible breaks are possible, new break nodes are
+created.  If |cur_p| is too far from an active node, that node is
+deactivated.
+
+The parameter |pi| to |try_break| is the penalty associated
+with a break at |cur_p|; we have |pi=eject_penalty| if the break is forced,
+and |pi=inf_penalty| if the break is illegal.
+
+The other parameter, |break_type|, is set to |hyphenated| or |unhyphenated|,
+depending on whether or not the current break is at a |disc_node|. The
+end of a paragraph is also regarded as `|hyphenated|'; this case is
+distinguishable by the condition |cur_p=null|.
+
+@d copy_to_cur_active(#)==cur_active_width[#]:=active_width[#]
+@d deactivate=60 {go here when node |r| should be deactivated}
+
+@<Declare subprocedures for |line_break|@>=
+procedure try_break(@!pi:integer;@!break_type:small_number);
+label exit,done,done1,continue,deactivate;
+var r:pointer; {runs through the active list}
+@!prev_r:pointer; {stays a step behind |r|}
+@!old_l:halfword; {maximum line number in current equivalence class of lines}
+@!no_break_yet:boolean; {have we found a feasible break at |cur_p|?}
+@<Other local variables for |try_break|@>@;
+begin @<Make sure that |pi| is in the proper range@>;
+no_break_yet:=true; prev_r:=active; old_l:=0;
+do_all_six(copy_to_cur_active);
+loop@+  begin continue: r:=link(prev_r);
+  @<If node |r| is of type |delta_node|, update |cur_active_width|,
+    set |prev_r| and |prev_prev_r|, then |goto continue|@>;
+  @<If a line number class has ended, create new active nodes for
+    the best feasible breaks in that class; then |return|
+    if |r=last_active|, otherwise compute the new |line_width|@>;
+  @<Consider the demerits for a line from |r| to |cur_p|;
+    deactivate node |r| if it should no longer be active;
+    then |goto continue| if a line from |r| to |cur_p| is infeasible,
+    otherwise record a new feasible break@>;
+  end;
+exit: @!stat @<Update the value of |printed_node| for
+  symbolic displays@>@+tats@;
+end;
+
+@ @<Other local variables for |try_break|@>=
+@!prev_prev_r:pointer; {a step behind |prev_r|, if |type(prev_r)=delta_node|}
+@!s:pointer; {runs through nodes ahead of |cur_p|}
+@!q:pointer; {points to a new node being created}
+@!v:pointer; {points to a glue specification or a node ahead of |cur_p|}
+@!t:integer; {node count, if |cur_p| is a discretionary node}
+@!f:internal_font_number; {used in character width calculation}
+@!l:halfword; {line number of current active node}
+@!node_r_stays_active:boolean; {should node |r| remain in the active list?}
+@!line_width:scaled; {the current line will be justified to this width}
+@!fit_class:very_loose_fit..tight_fit; {possible fitness class of test line}
+@!b:halfword; {badness of test line}
+@!d:integer; {demerits of test line}
+@!artificial_demerits:boolean; {has |d| been forced to zero?}
+@!save_link:pointer; {temporarily holds value of |link(cur_p)|}
+@!shortfall:scaled; {used in badness calculations}
+
+@ @<Make sure that |pi| is in the proper range@>=
+if abs(pi)>=inf_penalty then
+  if pi>0 then return {this breakpoint is inhibited by infinite penalty}
+  else pi:=eject_penalty {this breakpoint will be forced}
+
+@ The following code uses the fact that |type(last_active)<>delta_node|.
+
+@d update_width(#)==@|
+  cur_active_width[#]:=cur_active_width[#]+mem[r+#].sc
+
+@<If node |r|...@>=
+@^inner loop@>
+if type(r)=delta_node then
+  begin do_all_six(update_width);
+  prev_prev_r:=prev_r; prev_r:=r; goto continue;
+  end
+
+@ As we consider various ways to end a line at |cur_p|, in a given line number
+class, we keep track of the best total demerits known, in an array with
+one entry for each of the fitness classifications. For example,
+|minimal_demerits[tight_fit]| contains the fewest total demerits of feasible
+line breaks ending at |cur_p| with a |tight_fit| line; |best_place[tight_fit]|
+points to the passive node for the break before~|cur_p| that achieves such
+an optimum; and |best_pl_line[tight_fit]| is the |line_number| field in the
+active node corresponding to |best_place[tight_fit]|. When no feasible break
+sequence is known, the |minimal_demerits| entries will be equal to
+|awful_bad|, which is $2^{30}-1$. Another variable, |minimum_demerits|,
+keeps track of the smallest value in the |minimal_demerits| array.
+
+@d awful_bad==@'7777777777 {more than a billion demerits}
+
+@<Global...@>=
+@!minimal_demerits:array[very_loose_fit..tight_fit] of integer; {best total
+  demerits known for current line class and position, given the fitness}
+@!minimum_demerits:integer; {best total demerits known for current line class
+  and position}
+@!best_place:array[very_loose_fit..tight_fit] of pointer; {how to achieve
+  |minimal_demerits|}
+@!best_pl_line:array[very_loose_fit..tight_fit] of halfword; {corresponding
+  line number}
+
+@ @<Get ready to start...@>=
+minimum_demerits:=awful_bad;
+minimal_demerits[tight_fit]:=awful_bad;
+minimal_demerits[decent_fit]:=awful_bad;
+minimal_demerits[loose_fit]:=awful_bad;
+minimal_demerits[very_loose_fit]:=awful_bad;
+
+@ The first part of the following code is part of \TeX's inner loop, so
+we don't want to waste any time. The current active node, namely node |r|,
+contains the line number that will be considered next. At the end of the
+list we have arranged the data structure so that |r=last_active| and
+|line_number(last_active)>old_l|.
+@^inner loop@>
+
+@<If a line number class...@>=
+begin l:=line_number(r);
+if l>old_l then
+  begin {now we are no longer in the inner loop}
+  if (minimum_demerits<awful_bad)and@|
+      ((old_l<>easy_line)or(r=last_active)) then
+    @<Create new active nodes for the best feasible breaks
+      just found@>;
+  if r=last_active then return;
+  @<Compute the new line width@>;
+  end;
+end
+
+@ It is not necessary to create new active nodes having |minimal_demerits|
+greater than
+|minimum_demerits+abs(adj_demerits)|, since such active nodes will never
+be chosen in the final paragraph breaks. This observation allows us to
+omit a substantial number of feasible breakpoints from further consideration.
+
+@<Create new active nodes...@>=
+begin if no_break_yet then @<Compute the values of |break_width|@>;
+@<Insert a delta node to prepare for breaks at |cur_p|@>;
+if abs(adj_demerits)>=awful_bad-minimum_demerits then
+  minimum_demerits:=awful_bad-1
+else minimum_demerits:=minimum_demerits+abs(adj_demerits);
+for fit_class:=very_loose_fit to tight_fit do
+  begin if minimal_demerits[fit_class]<=minimum_demerits then
+    @<Insert a new active node
+      from |best_place[fit_class]| to |cur_p|@>;
+  minimal_demerits[fit_class]:=awful_bad;
+  end;
+minimum_demerits:=awful_bad;
+@<Insert a delta node to prepare for the next active node@>;
+end
+
+@ When we insert a new active node for a break at |cur_p|, suppose this
+new node is to be placed just before active node |a|; then we essentially
+want to insert `$\delta\,|cur_p|\,\delta^\prime$' before |a|, where
+$\delta=\alpha(a)-\alpha(|cur_p|)$ and $\delta^\prime=\alpha(|cur_p|)-\alpha(a)$
+in the notation explained above.  The |cur_active_width| array now holds
+$\gamma+\beta(|cur_p|)-\alpha(a)$; so $\delta$ can be obtained by
+subtracting |cur_active_width| from the quantity $\gamma+\beta(|cur_p|)-
+\alpha(|cur_p|)$. The latter quantity can be regarded as the length of a
+line ``from |cur_p| to |cur_p|''; we call it the |break_width| at |cur_p|.
+
+The |break_width| is usually negative, since it consists of the background
+(which is normally zero) minus the width of nodes following~|cur_p| that are
+eliminated after a break. If, for example, node |cur_p| is a glue node, the
+width of this glue is subtracted from the background; and we also look
+ahead to eliminate all subsequent glue and penalty and kern and math
+nodes, subtracting their widths as well.
+
+Kern nodes do not disappear at a line break unless they are |explicit|.
+
+@d set_break_width_to_background(#)==break_width[#]:=background[#]
+
+@<Compute the values of |break...@>=
+begin no_break_yet:=false; do_all_six(set_break_width_to_background);
+s:=cur_p;
+if break_type>unhyphenated then if cur_p<>null then
+  @<Compute the discretionary |break_width| values@>;
+while s<>null do
+  begin if is_char_node(s) then
+    begin if chain then
+      begin break_width[1]:=break_width[1]-width(cur_kanji_skip);
+      break_width[2+stretch_order(cur_kanji_skip)]:=
+         break_width[2+stretch_order(cur_kanji_skip)]-stretch(cur_kanji_skip);
+      break_width[6]:=break_width[6]-shrink(cur_kanji_skip);
+      end;
+    goto done end;
+  case type(s) of
+  glue_node:@<Subtract glue from |break_width|@>;
+  penalty_node: do_nothing;
+  math_node: break_width[1]:=break_width[1]-width(s);
+  kern_node: if (subtype(s)<>explicit)and(subtype(s)<>ita_kern) then
+    goto done
+    else break_width[1]:=break_width[1]-width(s);
+  othercases goto done
+  endcases;@/
+  s:=link(s);
+  end;
+done: end
+
+@ @<Subtract glue from |break...@>=
+begin v:=glue_ptr(s); break_width[1]:=break_width[1]-width(v);
+break_width[2+stretch_order(v)]:=break_width[2+stretch_order(v)]-stretch(v);
+break_width[6]:=break_width[6]-shrink(v);
+end
+
+@ When |cur_p| is a discretionary break, the length of a line ``from |cur_p| to
+|cur_p|'' has to be defined properly so that the other calculations work out.
+Suppose that the pre-break text at |cur_p| has length $l_0$, the post-break
+text has length $l_1$, and the replacement text has length |l|. Suppose
+also that |q| is the node following the replacement text. Then length of a
+line from |cur_p| to |q| will be computed as $\gamma+\beta(q)-\alpha(|cur_p|)$,
+where $\beta(q)=\beta(|cur_p|)-l_0+l$. The actual length will be the background
+plus $l_1$, so the length from |cur_p| to |cur_p| should be $\gamma+l_0+l_1-l$.
+If the post-break text of the discretionary is empty, a break may also
+discard~|q|; in that unusual case we subtract the length of~|q| and any
+other nodes that will be discarded after the discretionary break.
+
+The value of $l_0$ need not be computed, since |line_break| will put
+it into the global variable |disc_width| before calling |try_break|.
+
+@<Glob...@>=
+@!disc_width:scaled; {the length of discretionary material preceding a break}
+
+@ @<Compute the discretionary |break...@>=
+begin t:=replace_count(cur_p); v:=cur_p; s:=post_break(cur_p);
+while t>0 do
+  begin decr(t); v:=link(v);
+  @<Subtract the width of node |v| from |break_width|@>;
+  end;
+while s<>null do
+  begin @<Add the width of node |s| to |break_width|@>;
+  s:=link(s);
+  end;
+break_width[1]:=break_width[1]+disc_width;
+if post_break(cur_p)=null then s:=link(v);
+          {nodes may be discardable after the break}
+end
+
+@ Replacement texts and discretionary texts are supposed to contain
+only character nodes, kern nodes, ligature nodes, and box or rule nodes.
+
+@<Subtract the width of node |v|...@>=
+if is_char_node(v) then
+  begin f:=font(v);
+  break_width[1]:=break_width[1]-char_width(f)(orig_char_info(f)(character(v)));
+  if font_dir[f]<>dir_default then v:=link(v);
+  end
+else case type(v) of
+  ligature_node: begin f:=font(lig_char(v));@/
+    break_width[1]:=@|break_width[1]-
+      char_width(f)(orig_char_info(f)(character(lig_char(v))));
+    end;
+  hlist_node,vlist_node,dir_node,rule_node,kern_node:
+    break_width[1]:=break_width[1]-width(v);
+  disp_node: do_nothing;
+  othercases confusion("disc1")
+@:this can't happen disc1}{\quad disc1@>
+  endcases
+
+@ @<Add the width of node |s| to |b...@>=
+if is_char_node(s) then
+  begin f:=font(s);
+  break_width[1]:=@|break_width[1]+char_width(f)(orig_char_info(f)(character(s)));
+  if font_dir[f]<>dir_default then s:=link(s);
+  end
+else  case type(s) of
+  ligature_node: begin f:=font(lig_char(s));
+    break_width[1]:=break_width[1]+
+      char_width(f)(orig_char_info(f)(character(lig_char(s))));
+    end;
+  hlist_node,vlist_node,dir_node,rule_node,kern_node:
+    break_width[1]:=break_width[1]+width(s);
+  disp_node: do_nothing;
+  othercases confusion("disc2")
+@:this can't happen disc2}{\quad disc2@>
+  endcases
+
+@ We use the fact that |type(active)<>delta_node|.
+
+@d convert_to_break_width(#)==@|
+  mem[prev_r+#].sc:=@|@t\hskip10pt@>mem[prev_r+#].sc
+  -cur_active_width[#]+break_width[#]
+@d store_break_width(#)==active_width[#]:=break_width[#]
+@d new_delta_to_break_width(#)==@|
+  mem[q+#].sc:=break_width[#]-cur_active_width[#]
+
+@<Insert a delta node to prepare for breaks at |cur_p|@>=
+if type(prev_r)=delta_node then {modify an existing delta node}
+  begin do_all_six(convert_to_break_width);
+  end
+else if prev_r=active then {no delta node needed at the beginning}
+  begin do_all_six(store_break_width);
+  end
+else  begin q:=get_node(delta_node_size); link(q):=r; type(q):=delta_node;@/
+  subtype(q):=0; {the |subtype| is not used}
+  do_all_six(new_delta_to_break_width);
+  link(prev_r):=q; prev_prev_r:=prev_r; prev_r:=q;
+  end
+
+@ When the following code is performed, we will have just inserted at
+least one active node before |r|, so |type(prev_r)<>delta_node|.
+
+@d new_delta_from_break_width(#)==@|mem[q+#].sc:=
+    cur_active_width[#]-break_width[#]
+
+@<Insert a delta node to prepare for the next active node@>=
+if r<>last_active then
+  begin q:=get_node(delta_node_size); link(q):=r; type(q):=delta_node;@/
+  subtype(q):=0; {the |subtype| is not used}
+  do_all_six(new_delta_from_break_width);
+  link(prev_r):=q; prev_prev_r:=prev_r; prev_r:=q;
+  end
+
+@ When we create an active node, we also create the corresponding
+passive node.
+
+@<Insert a new active node from |best_place[fit_class]| to |cur_p|@>=
+begin q:=get_node(passive_node_size);
+link(q):=passive; passive:=q; cur_break(q):=cur_p;
+@!stat incr(pass_number); serial(q):=pass_number;@+tats@;@/
+prev_break(q):=best_place[fit_class];@/
+q:=get_node(active_node_size); break_node(q):=passive;
+line_number(q):=best_pl_line[fit_class]+1;
+fitness(q):=fit_class; type(q):=break_type;
+total_demerits(q):=minimal_demerits[fit_class];
+link(q):=r; link(prev_r):=q; prev_r:=q;
+@!stat if tracing_paragraphs>0 then
+  @<Print a symbolic description of the new break node@>;
+tats@;@/
+end
+
+@ @<Print a symbolic description of the new break node@>=
+begin print_nl("@@@@"); print_int(serial(passive));
+@.\AT!\AT!@>
+print(": line "); print_int(line_number(q)-1);
+print_char("."); print_int(fit_class);
+if break_type=hyphenated then print_char("-");
+print(" t="); print_int(total_demerits(q));
+print(" -> @@@@");
+if prev_break(passive)=null then print_char("0")
+else print_int(serial(prev_break(passive)));
+end
+
+@ The length of lines depends on whether the user has specified
+\.{\\parshape} or \.{\\hangindent}. If |par_shape_ptr| is not null, it
+points to a $(2n+1)$-word record in |mem|, where the |info| in the first
+word contains the value of |n|, and the other $2n$ words contain the left
+margins and line lengths for the first |n| lines of the paragraph; the
+specifications for line |n| apply to all subsequent lines. If
+|par_shape_ptr=null|, the shape of the paragraph depends on the value of
+|n=hang_after|; if |n>=0|, hanging indentation takes place on lines |n+1|,
+|n+2|, \dots, otherwise it takes place on lines 1, \dots, $\vert
+n\vert$. When hanging indentation is active, the left margin is
+|hang_indent|, if |hang_indent>=0|, else it is 0; the line length is
+$|hsize|-\vert|hang_indent|\vert$. The normal setting is
+|par_shape_ptr=null|, |hang_after=1|, and |hang_indent=0|.
+Note that if |hang_indent=0|, the value of |hang_after| is irrelevant.
+@^length of lines@> @^hanging indentation@>
+
+@<Glob...@>=
+@!easy_line:halfword; {line numbers |>easy_line| are equivalent in break nodes}
+@!last_special_line:halfword; {line numbers |>last_special_line| all have
+  the same width}
+@!first_width:scaled; {the width of all lines |<=last_special_line|, if
+  no \.{\\parshape} has been specified}
+@!second_width:scaled; {the width of all lines |>last_special_line|}
+@!first_indent:scaled; {left margin to go with |first_width|}
+@!second_indent:scaled; {left margin to go with |second_width|}
+
+@ We compute the values of |easy_line| and the other local variables relating
+to line length when the |line_break| procedure is initializing itself.
+
+@<Get ready to start...@>=
+if par_shape_ptr=null then
+  if hang_indent=0 then
+    begin last_special_line:=0; second_width:=hsize;
+    second_indent:=0;
+    end
+  else @<Set line length parameters in preparation for hanging indentation@>
+else  begin last_special_line:=info(par_shape_ptr)-1;
+  second_width:=mem[par_shape_ptr+2*(last_special_line+1)].sc;
+  second_indent:=mem[par_shape_ptr+2*last_special_line+1].sc;
+  end;
+if looseness=0 then easy_line:=last_special_line
+else easy_line:=max_halfword
+
+@ @<Set line length parameters in preparation for hanging indentation@>=
+begin last_special_line:=abs(hang_after);
+if hang_after<0 then
+  begin first_width:=hsize-abs(hang_indent);
+  if hang_indent>=0 then first_indent:=hang_indent
+  else first_indent:=0;
+  second_width:=hsize; second_indent:=0;
+  end
+else  begin first_width:=hsize; first_indent:=0;
+  second_width:=hsize-abs(hang_indent);
+  if hang_indent>=0 then second_indent:=hang_indent
+  else second_indent:=0;
+  end;
+end
+
+@ When we come to the following code, we have just encountered the first
+active node~|r| whose |line_number| field contains |l|. Thus we want to
+compute the length of the $l\mskip1mu$th line of the current paragraph. Furthermore,
+we want to set |old_l| to the last number in the class of line numbers
+equivalent to~|l|.
+
+@<Compute the new line width@>=
+if l>easy_line then
+  begin line_width:=second_width; old_l:=max_halfword-1;
+  end
+else  begin old_l:=l;
+  if l>last_special_line then line_width:=second_width
+  else if par_shape_ptr=null then line_width:=first_width
+  else line_width:=mem[par_shape_ptr+2*l@,].sc;
+  end
+
+@ The remaining part of |try_break| deals with the calculation of
+demerits for a break from |r| to |cur_p|.
+
+The first thing to do is calculate the badness, |b|. This value will always
+be between zero and |inf_bad+1|; the latter value occurs only in the
+case of lines from |r| to |cur_p| that cannot shrink enough to fit the necessary
+width. In such cases, node |r| will be deactivated.
+We also deactivate node~|r| when a break at~|cur_p| is forced, since future
+breaks must go through a forced break.
+
+@<Consider the demerits for a line from |r| to |cur_p|...@>=
+begin artificial_demerits:=false;@/
+@^inner loop@>
+shortfall:=line_width-cur_active_width[1]; {we're this much too short}
+if shortfall>0 then
+  @<Set the value of |b| to the badness for stretching the line,
+    and compute the corresponding |fit_class|@>
+else @<Set the value of |b| to the badness for shrinking the line,
+    and compute the corresponding |fit_class|@>;
+if (b>inf_bad)or(pi=eject_penalty) then
+  @<Prepare to deactivate node~|r|, and |goto deactivate| unless
+    there is a reason to consider lines of text from |r| to |cur_p|@>
+else  begin prev_r:=r;
+  if b>threshold then goto continue;
+  node_r_stays_active:=true;
+  end;
+@<Record a new feasible break@>;
+if node_r_stays_active then goto continue; {|prev_r| has been set to |r|}
+deactivate: @<Deactivate node |r|@>;
+end
+
+@ When a line must stretch, the available stretchability can be found in the
+subarray |cur_active_width[2..5]|, in units of points, fil, fill, and filll.
+
+The present section is part of \TeX's inner loop, and it is most often performed
+when the badness is infinite; therefore it is worth while to make a quick
+test for large width excess and small stretchability, before calling the
+|badness| subroutine.
+@^inner loop@>
+
+@<Set the value of |b| to the badness for stretching...@>=
+if (cur_active_width[3]<>0)or(cur_active_width[4]<>0)or@|
+  (cur_active_width[5]<>0) then
+  begin b:=0; fit_class:=decent_fit; {infinite stretch}
+  end
+else  begin if shortfall>7230584 then if cur_active_width[2]<1663497 then
+    begin b:=inf_bad; fit_class:=very_loose_fit; goto done1;
+    end;
+  b:=badness(shortfall,cur_active_width[2]);
+  if b>12 then
+    if b>99 then fit_class:=very_loose_fit
+    else fit_class:=loose_fit
+  else fit_class:=decent_fit;
+  done1:
+  end
+
+@ Shrinkability is never infinite in a paragraph;
+we can shrink the line from |r| to |cur_p| by at most |cur_active_width[6]|.
+
+@<Set the value of |b| to the badness for shrinking...@>=
+begin if -shortfall>cur_active_width[6] then b:=inf_bad+1
+else b:=badness(-shortfall,cur_active_width[6]);
+if b>12 then fit_class:=tight_fit@+else fit_class:=decent_fit;
+end
+
+@ During the final pass, we dare not lose all active nodes, lest we lose
+touch with the line breaks already found. The code shown here makes sure
+that such a catastrophe does not happen, by permitting overfull boxes as
+a last resort. This particular part of \TeX\ was a source of several subtle
+bugs before the correct program logic was finally discovered; readers
+who seek to ``improve'' \TeX\ should therefore think thrice before daring
+to make any changes here.
+@^overfull boxes@>
+
+@<Prepare to deactivate node~|r|, and |goto deactivate| unless...@>=
+begin if final_pass and (minimum_demerits=awful_bad) and@|
+   (link(r)=last_active) and
+   (prev_r=active) then
+  artificial_demerits:=true {set demerits zero, this break is forced}
+else if b>threshold then goto deactivate;
+node_r_stays_active:=false;
+end
+
+@ When we get to this part of the code, the line from |r| to |cur_p| is
+feasible, its badness is~|b|, and its fitness classification is |fit_class|.
+We don't want to make an active node for this break yet, but we will
+compute the total demerits and record them in the |minimal_demerits| array,
+if such a break is the current champion among all ways to get to |cur_p|
+in a given line-number class and fitness class.
+
+@<Record a new feasible break@>=
+if artificial_demerits then d:=0
+else @<Compute the demerits, |d|, from |r| to |cur_p|@>;
+@!stat if tracing_paragraphs>0 then
+  @<Print a symbolic description of this feasible break@>;
+tats@;@/
+d:=d+total_demerits(r); {this is the minimum total demerits
+  from the beginning to |cur_p| via |r|}
+if d<=minimal_demerits[fit_class] then
+  begin minimal_demerits[fit_class]:=d;
+  best_place[fit_class]:=break_node(r); best_pl_line[fit_class]:=l;
+  if d<minimum_demerits then minimum_demerits:=d;
+  end
+
+@ @<Print a symbolic description of this feasible break@>=
+begin if printed_node<>cur_p then
+  @<Print the list between |printed_node| and |cur_p|,
+    then set |printed_node:=cur_p|@>;
+print_nl("@@");
+@.\AT!@>
+if cur_p=null then print_esc("par")
+else if (type(cur_p)<>glue_node)and(not is_char_node(cur_p)) then
+  begin if type(cur_p)=penalty_node then print_esc("penalty")
+  else if type(cur_p)=disc_node then print_esc("discretionary")
+  else if type(cur_p)=kern_node then print_esc("kern")
+  else print_esc("math");
+  end;
+print(" via @@@@");
+if break_node(r)=null then print_char("0")
+else print_int(serial(break_node(r)));
+print(" b=");
+if b>inf_bad then print_char("*")@+else print_int(b);
+@.*\relax@>
+print(" p="); print_int(pi); print(" d=");
+if artificial_demerits then print_char("*")@+else print_int(d);
+end
+
+@ @<Print the list between |printed_node| and |cur_p|...@>=
+begin print_nl("");
+if cur_p=null then short_display(link(printed_node))
+else  begin save_link:=link(cur_p);
+  link(cur_p):=null; print_nl(""); short_display(link(printed_node));
+  link(cur_p):=save_link;
+  end;
+printed_node:=cur_p;
+end
+
+@ When the data for a discretionary break is being displayed, we will have
+printed the |pre_break| and |post_break| lists; we want to skip over the
+third list, so that the discretionary data will not appear twice.  The
+following code is performed at the very end of |try_break|.
+
+@<Update the value of |printed_node|...@>=
+if cur_p=printed_node then if cur_p<>null then if type(cur_p)=disc_node then
+  begin t:=replace_count(cur_p);
+  while t>0 do
+    begin decr(t); printed_node:=link(printed_node);
+    end;
+  end
+
+@ @<Compute the demerits, |d|, from |r| to |cur_p|@>=
+begin d:=line_penalty+b;
+if abs(d)>=10000 then d:=100000000@+else d:=d*d;
+if pi<>0 then
+  if pi>0 then d:=d+pi*pi
+  else if pi>eject_penalty then d:=d-pi*pi;
+if (break_type=hyphenated)and(type(r)=hyphenated) then
+  if cur_p<>null then d:=d+double_hyphen_demerits
+  else d:=d+final_hyphen_demerits;
+if abs(intcast(fit_class)-intcast(fitness(r)))>1 then d:=d+adj_demerits;
+end
+
+@ When an active node disappears, we must delete an adjacent delta node if the
+active node was at the beginning or the end of the active list, or if it
+was surrounded by delta nodes. We also must preserve the property that
+|cur_active_width| represents the length of material from |link(prev_r)|
+to~|cur_p|.
+
+@d combine_two_deltas(#)==@|mem[prev_r+#].sc:=mem[prev_r+#].sc+mem[r+#].sc
+@d downdate_width(#)==@|cur_active_width[#]:=cur_active_width[#]-
+  mem[prev_r+#].sc
+
+@<Deactivate node |r|@>=
+link(prev_r):=link(r); free_node(r,active_node_size);
+if prev_r=active then @<Update the active widths, since the first active
+  node has been deleted@>
+else if type(prev_r)=delta_node then
+  begin r:=link(prev_r);
+  if r=last_active then
+    begin do_all_six(downdate_width);
+    link(prev_prev_r):=last_active;
+    free_node(prev_r,delta_node_size); prev_r:=prev_prev_r;
+    end
+  else if type(r)=delta_node then
+    begin do_all_six(update_width);
+    do_all_six(combine_two_deltas);
+    link(prev_r):=link(r); free_node(r,delta_node_size);
+    end;
+  end
+
+@ The following code uses the fact that |type(last_active)<>delta_node|. If the
+active list has just become empty, we do not need to update the
+|active_width| array, since it will be initialized when an active
+node is next inserted.
+
+@d update_active(#)==active_width[#]:=active_width[#]+mem[r+#].sc
+
+@<Update the active widths,...@>=
+begin r:=link(active);
+if type(r)=delta_node then
+  begin do_all_six(update_active);
+  do_all_six(copy_to_cur_active);
+  link(active):=link(r); free_node(r,delta_node_size);
+  end;
+end
+
+@* \[39] Breaking paragraphs into lines, continued.
+So far we have gotten a little way into the |line_break| routine, having
+covered its important |try_break| subroutine. Now let's consider the
+rest of the process.
+
+The main loop of |line_break| traverses the given hlist,
+starting at |link(temp_head)|, and calls |try_break| at each legal
+breakpoint. A variable called |auto_breaking| is set to true except
+within math formulas, since glue nodes are not legal breakpoints when
+they appear in formulas.
+
+The current node of interest in the hlist is pointed to by |cur_p|. Another
+variable, |prev_p|, is usually one step behind |cur_p|, but the real
+meaning of |prev_p| is this: If |type(cur_p)=glue_node| then |cur_p| is a legal
+breakpoint if and only if |auto_breaking| is true and |prev_p| does not
+point to a glue node, penalty node, explicit kern node, or math node.
+
+The following declarations provide for a few other local variables that are
+used in special calculations.
+
+@<Local variables for line breaking@>=
+@!auto_breaking:boolean; {is node |cur_p| outside a formula?}
+@!prev_p:pointer; {helps to determine when glue nodes are breakpoints}
+@!q,@!r,@!s,@!prev_s:pointer; {miscellaneous nodes of temporary interest}
+@!f,@!post_f:internal_font_number; {used when calculating character widths}
+@!post_p:pointer;
+@!cc:ASCII_code;
+@!first_use:boolean;
+
+@ The `\ignorespaces|loop|\unskip' in the following code is performed at most
+thrice per call of |line_break|, since it is actually a pass over the
+entire paragraph.
+
+@<Find optimal breakpoints@>=
+threshold:=pretolerance;
+if threshold>=0 then
+  begin @!stat if tracing_paragraphs>0 then
+    begin begin_diagnostic; print_nl("@@firstpass");@+end;@;@+tats@;@/
+  second_pass:=false; final_pass:=false;
+  end
+else  begin threshold:=tolerance; second_pass:=true;
+  final_pass:=(emergency_stretch<=0);
+  @!stat if tracing_paragraphs>0 then begin_diagnostic;@+tats@;
+  end;
+loop@+  begin if threshold>inf_bad then threshold:=inf_bad;
+  if second_pass then @<Initialize for hyphenating a paragraph@>;
+  @<Create an active breakpoint representing the beginning of the paragraph@>;
+  cur_p:=link(temp_head); auto_breaking:=true;@/
+  prev_p:=cur_p; {glue at beginning is not a legal breakpoint}
+  while (cur_p<>null)and(link(active)<>last_active) do
+    @<Call |try_break| if |cur_p| is a legal breakpoint;
+    on the second pass, also try to hyphenate the next
+    word, if |cur_p| is a glue node;
+    then advance |cur_p| to the next node of the paragraph
+    that could possibly be a legal breakpoint@>;
+  if cur_p=null then
+    @<Try the final line break at the end of the paragraph,
+    and |goto done| if the desired breakpoints have been found@>;
+  @<Clean up the memory by removing the break nodes@>;
+  if not second_pass then
+    begin@!stat if tracing_paragraphs>0 then print_nl("@@secondpass");@;@+tats@/
+    threshold:=tolerance; second_pass:=true; final_pass:=(emergency_stretch<=0);
+    end {if at first you don't succeed, \dots}
+  else begin @!stat if tracing_paragraphs>0 then
+      print_nl("@@emergencypass");@;@+tats@/
+    background[2]:=background[2]+emergency_stretch; final_pass:=true;
+    end;
+  end;
+done: @!stat if tracing_paragraphs>0 then
+  begin end_diagnostic(true); normalize_selector;
+  end;@+tats@/
+
+@ The active node that represents the starting point does not need a
+corresponding passive node.
+
+@d store_background(#)==active_width[#]:=background[#]
+
+@<Create an active breakpoint representing the beginning of the paragraph@>=
+q:=get_node(active_node_size);
+type(q):=unhyphenated; fitness(q):=decent_fit;
+link(q):=last_active; break_node(q):=null;
+line_number(q):=prev_graf+1; total_demerits(q):=0; link(active):=q;
+do_all_six(store_background);@/
+passive:=null; printed_node:=temp_head; pass_number:=0;
+font_in_short_display:=null_font
+
+@ @<Clean...@>=
+q:=link(active);
+while q<>last_active do
+  begin cur_p:=link(q);
+  if type(q)=delta_node then free_node(q,delta_node_size)
+  else free_node(q,active_node_size);
+  q:=cur_p;
+  end;
+q:=passive;
+while q<>null do
+  begin cur_p:=link(q);
+  free_node(q,passive_node_size);
+  q:=cur_p;
+  end
+
+@ Here is the main switch in the |line_break| routine, where legal breaks
+are determined. As we move through the hlist, we need to keep the |active_width|
+array up to date, so that the badness of individual lines is readily calculated
+by |try_break|. It is convenient to use the short name |act_width| for
+the component of active width that represents real width as opposed to glue.
+
+@d act_width==active_width[1] {length from first active node to current node}
+@d kern_break==begin if not is_char_node(link(cur_p)) and auto_breaking then
+    if type(link(cur_p))=glue_node then try_break(0,unhyphenated);
+  act_width:=act_width+width(cur_p);
+  end
+
+@<Call |try_break| if |cur_p| is a legal breakpoint...@>=
+begin if is_char_node(cur_p) then
+  @<Advance \(c)|cur_p| to the node following the present
+    string of characters@>;
+case type(cur_p) of
+hlist_node,vlist_node,dir_node,rule_node: act_width:=act_width+width(cur_p);
+whatsit_node: @<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>;
+glue_node: begin @<If node |cur_p| is a legal breakpoint, call |try_break|;
+  then update the active widths by including the glue in |glue_ptr(cur_p)|@>;
+  if second_pass and auto_breaking then
+    @<Try to hyphenate the following word@>;
+  end;
+kern_node: if (subtype(cur_p)=explicit)or(subtype(cur_p)=ita_kern) then
+  kern_break
+  else act_width:=act_width+width(cur_p);
+ligature_node: begin f:=font(lig_char(cur_p));
+  act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
+  end;
+disc_node: @<Try to break after a discretionary fragment, then |goto done5|@>;
+math_node: begin auto_breaking:=(subtype(cur_p)=after); kern_break;
+  end;
+penalty_node: try_break(penalty(cur_p),unhyphenated);
+disp_node,mark_node,ins_node,adjust_node: do_nothing;
+othercases confusion("paragraph")
+@:this can't happen paragraph}{\quad paragraph@>
+endcases;@/
+prev_p:=cur_p; cur_p:=link(cur_p);
+done5:end
+
+@ The code that passes over the characters of words in a paragraph is
+part of \TeX's inner loop, so it has been streamlined for speed. We use
+the fact that `\.{\\parfillskip}' glue appears at the end of each paragraph;
+it is therefore unnecessary to check if |link(cur_p)=null| when |cur_p| is a
+character node.
+@^inner loop@>
+
+@<Advance \(c)|cur_p| to the node following the present string...@>=
+begin chain:=false;
+if is_char_node(cur_p) then
+  if font_dir[font(cur_p)]<>dir_default then
+    begin case type(prev_p) of
+    hlist_node,vlist_node,dir_node,rule_node,
+    ligature_node,disc_node,math_node: begin
+      cur_p:=prev_p; try_break(0,unhyphenated); cur_p:=link(cur_p);
+      end;
+    othercases do_nothing;
+    endcases;
+    end;
+  prev_p:=cur_p; post_p:=cur_p; post_f:=font(post_p);
+  repeat f:=post_f; cc:=character(cur_p);
+  act_width:=act_width+char_width(f)(orig_char_info(f)(cc));
+  post_p:=link(cur_p);
+  if font_dir[f]<>dir_default then
+    begin prev_p:=cur_p; cur_p:=post_p; post_p:=link(post_p);
+    if is_char_node(post_p) then
+      begin post_f:=font(post_p);
+      if font_dir[post_f]<>dir_default then chain:=true else chain:=false;
+      try_break(0,unhyphenated);
+      end
+    else
+      begin chain:=false;
+      case type(post_p) of
+      hlist_node,vlist_node,dir_node,rule_node,ligature_node,
+        disc_node,math_node: try_break(0,unhyphenated);
+      othercases do_nothing;
+      endcases;
+      end;
+    if chain then
+      begin if first_use then
+        begin check_shrinkage(cur_kanji_skip);
+        first_use:=false;
+        end;
+      act_width:=act_width+width(cur_kanji_skip);@|
+      active_width[2+stretch_order(cur_kanji_skip)]:=@|
+          active_width[2+stretch_order(cur_kanji_skip)]
+          +stretch(cur_kanji_skip);@/
+      active_width[6]:=active_width[6]+shrink(cur_kanji_skip);
+      end;
+    prev_p:=cur_p;
+    end
+  else  if is_char_node(post_p) then
+    begin post_f:=font(post_p); chain:=false;
+    if font_dir[post_f]<>dir_default then try_break(0,unhyphenated);
+    end;
+  cur_p:=post_p;
+  until not is_char_node(cur_p);
+chain:=false;
+end
+
+@ When node |cur_p| is a glue node, we look at |prev_p| to see whether or not
+a breakpoint is legal at |cur_p|, as explained above.
+
+@<If node |cur_p| is a legal breakpoint, call...@>=
+if auto_breaking then
+  begin if is_char_node(prev_p) then try_break(0,unhyphenated)
+  else if precedes_break(prev_p) then try_break(0,unhyphenated)
+  else if type(prev_p)=kern_node then
+    if (subtype(prev_p)<>explicit)and(subtype(prev_p)<>ita_kern) then
+    try_break(0,unhyphenated);
+  end;
+check_shrinkage(glue_ptr(cur_p)); q:=glue_ptr(cur_p);
+act_width:=act_width+width(q);@|
+active_width[2+stretch_order(q)]:=@|
+  active_width[2+stretch_order(q)]+stretch(q);@/
+active_width[6]:=active_width[6]+shrink(q)
+
+@ The following code knows that discretionary texts contain
+only character nodes, kern nodes, box nodes, rule nodes, and ligature nodes.
+
+@<Try to break after a discretionary fragment...@>=
+begin s:=pre_break(cur_p); disc_width:=0;
+if s=null then try_break(ex_hyphen_penalty,hyphenated)
+else  begin repeat @<Add the width of node |s| to |disc_width|@>;
+    s:=link(s);
+  until s=null;
+  act_width:=act_width+disc_width;
+  try_break(hyphen_penalty,hyphenated);
+  act_width:=act_width-disc_width;
+  end;
+r:=replace_count(cur_p); s:=link(cur_p);
+while r>0 do
+  begin @<Add the width of node |s| to |act_width|@>;
+  decr(r); s:=link(s);
+  end;
+prev_p:=cur_p; cur_p:=s; goto done5;
+end
+
+@ @<Add the width of node |s| to |disc_width|@>=
+if is_char_node(s) then
+  begin f:=font(s);
+  disc_width:=disc_width+char_width(f)(orig_char_info(f)(character(s)));
+  if font_dir[f]<>dir_default then s:=link(s)
+  end
+else  case type(s) of
+  ligature_node: begin f:=font(lig_char(s));
+    disc_width:=disc_width+
+      char_width(f)(orig_char_info(f)(character(lig_char(s))));
+    end;
+  hlist_node,vlist_node,dir_node,rule_node,kern_node:
+    disc_width:=disc_width+width(s);
+  disp_node: do_nothing;
+  othercases confusion("disc3")
+@:this can't happen disc3}{\quad disc3@>
+  endcases
+
+@ @<Add the width of node |s| to |act_width|@>=
+if is_char_node(s) then
+  begin f:=font(s);
+  act_width:=act_width+char_width(f)(orig_char_info(f)(character(s)));
+  if font_dir[f]<>dir_default then s:=link(s)
+  end
+else  case type(s) of
+  ligature_node: begin f:=font(lig_char(s));
+    act_width:=act_width+
+      char_width(f)(orig_char_info(f)(character(lig_char(s))));
+    end;
+  hlist_node,vlist_node,dir_node,rule_node,kern_node:
+    act_width:=act_width+width(s);
+  disp_node: do_nothing;
+  othercases confusion("disc4")
+@:this can't happen disc4}{\quad disc4@>
+  endcases
+
+@ The forced line break at the paragraph's end will reduce the list of
+breakpoints so that all active nodes represent breaks at |cur_p=null|.
+On the first pass, we insist on finding an active node that has the
+correct ``looseness.'' On the final pass, there will be at least one active
+node, and we will match the desired looseness as well as we can.
+
+The global variable |best_bet| will be set to the active node for the best
+way to break the paragraph, and a few other variables are used to
+help determine what is best.
+
+@<Glob...@>=
+@!best_bet:pointer; {use this passive node and its predecessors}
+@!fewest_demerits:integer; {the demerits associated with |best_bet|}
+@!best_line:halfword; {line number following the last line of the new paragraph}
+@!actual_looseness:integer; {the difference between |line_number(best_bet)|
+  and the optimum |best_line|}
+@!line_diff:integer; {the difference between the current line number and
+  the optimum |best_line|}
+
+@ @<Try the final line break at the end of the paragraph...@>=
+begin try_break(eject_penalty,hyphenated);
+if link(active)<>last_active then
+  begin @<Find an active node with fewest demerits@>;
+  if looseness=0 then goto done;
+  @<Find the best active node for the desired looseness@>;
+  if (actual_looseness=looseness)or final_pass then goto done;
+  end;
+end
+
+@ @<Find an active node...@>=
+r:=link(active); fewest_demerits:=awful_bad;
+repeat if type(r)<>delta_node then if total_demerits(r)<fewest_demerits then
+  begin fewest_demerits:=total_demerits(r); best_bet:=r;
+  end;
+r:=link(r);
+until r=last_active;
+best_line:=line_number(best_bet)
+
+@ The adjustment for a desired looseness is a slightly more complicated
+version of the loop just considered. Note that if a paragraph is broken
+into segments by displayed equations, each segment will be subject to the
+looseness calculation, independently of the other segments.
+
+@<Find the best active node...@>=
+begin r:=link(active); actual_looseness:=0;
+repeat if type(r)<>delta_node then
+  begin line_diff:=intcast(line_number(r))-intcast(best_line);
+  if ((line_diff<actual_looseness)and(looseness<=line_diff))or@|
+  ((line_diff>actual_looseness)and(looseness>=line_diff)) then
+    begin best_bet:=r; actual_looseness:=line_diff;
+    fewest_demerits:=total_demerits(r);
+    end
+  else if (line_diff=actual_looseness)and@|
+    (total_demerits(r)<fewest_demerits) then
+    begin best_bet:=r; fewest_demerits:=total_demerits(r);
+    end;
+  end;
+r:=link(r);
+until r=last_active;
+best_line:=line_number(best_bet);
+end
+
+@ Once the best sequence of breakpoints has been found (hurray), we call on the
+procedure |post_line_break| to finish the remainder of the work.
+(By introducing this subprocedure, we are able to keep |line_break|
+from getting extremely long.)
+
+@<Break the paragraph at the chosen...@>=
+post_line_break(final_widow_penalty)
+
+@ The total number of lines that will be set by |post_line_break|
+is |best_line-prev_graf-1|. The last breakpoint is specified by
+|break_node(best_bet)|, and this passive node points to the other breakpoints
+via the |prev_break| links. The finishing-up phase starts by linking the
+relevant passive nodes in forward order, changing |prev_break| to
+|next_break|. (The |next_break| fields actually reside in the same memory
+space as the |prev_break| fields did, but we give them a new name because
+of their new significance.) Then the lines are justified, one by one.
+
+@d next_break==prev_break {new name for |prev_break| after links are reversed}
+
+@<Declare subprocedures for |line_break|@>=
+procedure post_line_break(@!final_widow_penalty:integer);
+label done,done1;
+var q,@!r,@!s:pointer; {temporary registers for list manipulation}
+@!disc_break:boolean; {was the current break at a discretionary node?}
+@!post_disc_break:boolean; {and did it have a nonempty post-break part?}
+@!cur_width:scaled; {width of line number |cur_line|}
+@!cur_indent:scaled; {left margin of line number |cur_line|}
+@!t:quarterword; {used for replacement counts in discretionary nodes}
+@!pen:integer; {use when calculating penalties between lines}
+@!cur_line: halfword; {the current line number being justified}
+begin @<Reverse the links of the relevant passive nodes, setting |cur_p| to the
+  first breakpoint@>;
+cur_line:=prev_graf+1; last_disp:=0;
+repeat @<Justify the line ending at breakpoint |cur_p|, and append it to the
+  current vertical list, together with associated penalties and other
+  insertions@>;
+incr(cur_line); cur_p:=next_break(cur_p);
+if cur_p<>null then if not post_disc_break then
+  @<Prune unwanted nodes at the beginning of the next line@>;
+until cur_p=null;
+if (cur_line<>best_line)or(link(temp_head)<>null) then
+  confusion("line breaking");
+@:this can't happen line breaking}{\quad line breaking@>
+prev_graf:=best_line-1;
+end;
+
+@ The job of reversing links in a list is conveniently regarded as the job
+of taking items off one stack and putting them on another. In this case we
+take them off a stack pointed to by |q| and having |prev_break| fields;
+we put them on a stack pointed to by |cur_p| and having |next_break| fields.
+Node |r| is the passive node being moved from stack to stack.
+
+@<Reverse the links of the relevant passive nodes...@>=
+q:=break_node(best_bet); cur_p:=null;
+repeat r:=q; q:=prev_break(q); next_break(r):=cur_p; cur_p:=r;
+until q=null
+
+@ Glue and penalty and kern and math nodes are deleted at the beginning of
+a line, except in the anomalous case that the node to be deleted is actually
+one of the chosen breakpoints. Otherwise
+the pruning done here is designed to match
+the lookahead computation in |try_break|, where the |break_width| values
+are computed for non-discretionary breakpoints.
+
+@<Prune unwanted nodes at the beginning of the next line@>=
+begin r:=temp_head;
+loop@+  begin q:=link(r);
+  if q=cur_break(cur_p) then goto done1;
+    {|cur_break(cur_p)| is the next breakpoint}
+  {now |q| cannot be |null|}
+  if is_char_node(q) then goto done1;
+  if non_discardable(q) then goto done1;
+  if type(q)=kern_node then
+    if (subtype(q)<>explicit)and(subtype(q)<>ita_kern) then goto done1;
+  r:=q; {now |type(q)=glue_node|, |kern_node|, |math_node| or |penalty_node|}
+  end;
+done1: if r<>temp_head then
+  begin link(r):=null; flush_node_list(link(temp_head));
+  link(temp_head):=q;
+  end;
+end
+
+@ The current line to be justified appears in a horizontal list starting
+at |link(temp_head)| and ending at |cur_break(cur_p)|. If |cur_break(cur_p)| is
+a glue node, we reset the glue to equal the |right_skip| glue; otherwise
+we append the |right_skip| glue at the right. If |cur_break(cur_p)| is a
+discretionary node, we modify the list so that the discretionary break
+is compulsory, and we set |disc_break| to |true|. We also append
+the |left_skip| glue at the left of the line, unless it is zero.
+
+@<Justify the line ending at breakpoint |cur_p|, and append it...@>=
+@<Modify the end of the line to reflect the nature of the break and to include
+  \.{\\rightskip}; also set the proper value of |disc_break|@>;
+@<Put the \(l)\.{\\leftskip} glue at the left and detach this line@>;
+@<Call the packaging subroutine, setting |just_box| to the justified box@>;
+@<Append the new box to the current vertical list, followed by the list of
+  special nodes taken out of the box by the packager@>;
+@<Append a penalty node, if a nonzero penalty is appropriate@>
+
+@ At the end of the following code, |q| will point to the final node on the
+list about to be justified.
+
+@<Modify the end of the line...@>=
+q:=cur_break(cur_p); disc_break:=false; post_disc_break:=false;
+if q<>null then {|q| may be a |char_node|}
+  begin if not is_char_node(q) then
+    if type(q)=glue_node then
+      begin delete_glue_ref(glue_ptr(q));
+      glue_ptr(q):=right_skip;
+      subtype(q):=right_skip_code+1; add_glue_ref(right_skip);
+      goto done;
+      end
+    else  begin if type(q)=disc_node then
+        @<Change discretionary to compulsory and set
+          |disc_break:=true|@>
+    else if (type(q)=math_node)or(type(q)=kern_node) then width(q):=0;
+      end
+  end
+else  begin q:=temp_head;
+  while link(q)<>null do q:=link(q);
+  end;
+@<Put the \(r)\.{\\rightskip} glue after node |q|@>;
+done:
+
+@ @<Change discretionary to compulsory...@>=
+begin t:=replace_count(q);
+@<Destroy the |t| nodes following |q|, and
+   make |r| point to the following node@>;
+if post_break(q)<>null then @<Transplant the post-break list@>;
+if pre_break(q)<>null then @<Transplant the pre-break list@>;
+link(q):=r; disc_break:=true;
+end
+
+@ @<Destroy the |t| nodes following |q|...@>=
+if t=0 then r:=link(q)
+else  begin r:=q;
+  while t>1 do
+    begin r:=link(r); decr(t);
+    end;
+  s:=link(r);
+  r:=link(s); link(s):=null;
+  flush_node_list(link(q)); replace_count(q):=0;
+  end
+
+@ We move the post-break list from inside node |q| to the main list by
+re\-attaching it just before the present node |r|, then resetting |r|.
+
+@<Transplant the post-break list@>=
+begin s:=post_break(q);
+while link(s)<>null do s:=link(s);
+link(s):=r; r:=post_break(q); post_break(q):=null; post_disc_break:=true;
+end
+
+@ We move the pre-break list from inside node |q| to the main list by
+re\-attaching it just after the present node |q|, then resetting |q|.
+
+@<Transplant the pre-break list@>=
+begin s:=pre_break(q); link(q):=s;
+while link(s)<>null do s:=link(s);
+pre_break(q):=null; q:=s;
+end
+
+@ @<Put the \(r)\.{\\rightskip} glue after node |q|@>=
+r:=new_param_glue(right_skip_code); link(r):=link(q); link(q):=r; q:=r
+
+@ The following code begins with |q| at the end of the list to be
+justified. It ends with |q| at the beginning of that list, and with
+|link(temp_head)| pointing to the remainder of the paragraph, if any.
+
+@<Put the \(l)\.{\\leftskip} glue at the left...@>=
+r:=link(q); link(q):=null; q:=link(temp_head); link(temp_head):=r;
+if last_disp<>0 then begin
+  r:=get_node(small_node_size);
+  type(r):=disp_node; disp_dimen(r):=last_disp;
+  link(r):=q; q:=r;
+  end;
+if left_skip<>zero_glue then
+  begin r:=new_param_glue(left_skip_code);
+  link(r):=q; q:=r;
+  end
+
+@ @<Append the new box to the current vertical list...@>=
+append_to_vlist(just_box);
+if adjust_head<>adjust_tail then
+  begin link(tail):=link(adjust_head); tail:=adjust_tail;
+   end;
+adjust_tail:=null
+
+@ Now |q| points to the hlist that represents the current line of the
+paragraph. We need to compute the appropriate line width, pack the
+line into a box of this size, and shift the box by the appropriate
+amount of indentation.
+
+@<Call the packaging subroutine...@>=
+if cur_line>last_special_line then
+  begin cur_width:=second_width; cur_indent:=second_indent;
+  end
+else if par_shape_ptr=null then
+  begin cur_width:=first_width; cur_indent:=first_indent;
+  end
+else  begin cur_width:=mem[par_shape_ptr+2*cur_line].sc;
+  cur_indent:=mem[par_shape_ptr+2*cur_line-1].sc;
+  end;
+adjust_tail:=adjust_head; just_box:=hpack(q,cur_width,exactly);
+shift_amount(just_box):=cur_indent
+
+@ Penalties between the lines of a paragraph come from club and widow lines,
+from the |inter_line_penalty| parameter, and from lines that end at
+discretionary breaks.  Breaking between lines of a two-line paragraph gets
+both club-line and widow-line penalties. The local variable |pen| will
+be set to the sum of all relevant penalties for the current line, except
+that the final line is never penalized.
+
+@<Append a penalty node, if a nonzero penalty is appropriate@>=
+if cur_line+1<>best_line then
+  begin pen:=inter_line_penalty;
+  if cur_line=prev_graf+1 then pen:=pen+club_penalty;
+  if cur_line+2=best_line then pen:=pen+final_widow_penalty;
+  if disc_break then pen:=pen+broken_penalty;
+  if pen<>0 then
+    begin r:=new_penalty(pen);
+    link(tail):=r; tail:=r;
+    end;
+  end
+
+@* \[40] Pre-hyphenation.
+When the line-breaking routine is unable to find a feasible sequence of
+breakpoints, it makes a second pass over the paragraph, attempting to
+hyphenate the hyphenatable words. The goal of hyphenation is to insert
+discretionary material into the paragraph so that there are more
+potential places to break.
+
+The general rules for hyphenation are somewhat complex and technical,
+because we want to be able to hyphenate words that are preceded or
+followed by punctuation marks, and because we want the rules to work
+for languages other than English. We also must contend with the fact
+that hyphens might radically alter the ligature and kerning structure
+of a word.
+
+A sequence of characters will be considered for hyphenation only if it
+belongs to a ``potentially hyphenatable part'' of the current paragraph.
+This is a sequence of nodes $p_0p_1\ldots p_m$ where $p_0$ is a glue node,
+$p_1\ldots p_{m-1}$ are either character or ligature or whatsit or
+implicit kern nodes, and $p_m$ is a glue or penalty or insertion or adjust
+or mark or whatsit or explicit kern node.  (Therefore hyphenation is
+disabled by boxes, math formulas, and discretionary nodes already inserted
+by the user.) The ligature nodes among $p_1\ldots p_{m-1}$ are effectively
+expanded into the original non-ligature characters; the kern nodes and
+whatsits are ignored. Each character |c| is now classified as either a
+nonletter (if |lc_code(c)=0|), a lowercase letter (if
+|lc_code(c)=c|), or an uppercase letter (otherwise); an uppercase letter
+is treated as if it were |lc_code(c)| for purposes of hyphenation. The
+characters generated by $p_1\ldots p_{m-1}$ may begin with nonletters; let
+$c_1$ be the first letter that is not in the middle of a ligature. Whatsit
+nodes preceding $c_1$ are ignored; a whatsit found after $c_1$ will be the
+terminating node $p_m$. All characters that do not have the same font as
+$c_1$ will be treated as nonletters. The |hyphen_char| for that font
+must be between 0 and 255, otherwise hyphenation will not be attempted.
+\TeX\ looks ahead for as many consecutive letters $c_1\ldots c_n$ as
+possible; however, |n| must be less than 64, so a character that would
+otherwise be $c_{64}$ is effectively not a letter. Furthermore $c_n$ must
+not be in the middle of a ligature.  In this way we obtain a string of
+letters $c_1\ldots c_n$ that are generated by nodes $p_a\ldots p_b$, where
+|1<=a<=b+1<=m|. If |n>=l_hyf+r_hyf|, this string qualifies for hyphenation;
+however, |uc_hyph| must be positive, if $c_1$ is uppercase.
+
+The hyphenation process takes place in three stages. First, the candidate
+sequence $c_1\ldots c_n$ is found; then potential positions for hyphens
+are determined by referring to hyphenation tables; and finally, the nodes
+$p_a\ldots p_b$ are replaced by a new sequence of nodes that includes the
+discretionary breaks found.
+
+Fortunately, we do not have to do all this calculation very often, because
+of the way it has been taken out of \TeX's inner loop. For example, when
+the second edition of the author's 700-page book {\sl Seminumerical
+Algorithms} was typeset by \TeX, only about 1.2 hyphenations needed to be
+@^Knuth, Donald Ervin@>
+tried per paragraph, since the line breaking algorithm needed to use two
+passes on only about 5 per cent of the paragraphs.
+
+@<Initialize for hyphenating...@>=
+begin @!init if trie_not_ready then init_trie;@+tini@;@/
+cur_lang:=init_cur_lang; l_hyf:=init_l_hyf; r_hyf:=init_r_hyf;
+end
+
+@ The letters $c_1\ldots c_n$ that are candidates for hyphenation are placed
+into an array called |hc|; the number |n| is placed into |hn|; pointers to
+nodes $p_{a-1}$ and~$p_b$ in the description above are placed into variables
+|ha| and |hb|; and the font number is placed into |hf|.
+
+@<Glob...@>=
+@!hc:array[0..65] of 0..256; {word to be hyphenated}
+@!hn:small_number; {the number of positions occupied in |hc|}
+@!ha,@!hb:pointer; {nodes |ha..hb| should be replaced by the hyphenated result}
+@!hf:internal_font_number; {font number of the letters in |hc|}
+@!hu:array[0..63] of 0..256; {like |hc|, before conversion to lowercase}
+@!hyf_char:integer; {hyphen character of the relevant font}
+@!cur_lang,@!init_cur_lang:ASCII_code; {current hyphenation table of interest}
+@!l_hyf,@!r_hyf,@!init_l_hyf,@!init_r_hyf:integer; {limits on fragment sizes}
+@!hyf_bchar:halfword; {boundary character after $c_n$}
+
+@ Hyphenation routines need a few more local variables.
+
+@<Local variables for line...@>=
+@!j:small_number; {an index into |hc| or |hu|}
+@!c:0..255; {character being considered for hyphenation}
+
+@ When the following code is activated, the |line_break| procedure is in its
+second pass, and |cur_p| points to a glue node.
+
+@<Try to hyphenate...@>=
+begin prev_s:=cur_p; s:=link(prev_s);
+if s<>null then
+  begin @<Skip to node |ha|, or |goto done1| if no hyphenation
+    should be attempted@>;
+  if l_hyf+r_hyf>63 then goto done1;
+  @<Skip to node |hb|, putting letters into |hu| and |hc|@>;
+  @<Check that the nodes following |hb| permit hyphenation and that at least
+    |l_hyf+r_hyf| letters have been found, otherwise |goto done1|@>;
+  hyphenate;
+  end;
+done1: end
+
+@ @<Declare subprocedures for |line_break|@>=
+@t\4@>@<Declare the function called |reconstitute|@>
+procedure hyphenate;
+label common_ending,done,found,found1,found2,not_found,exit;
+var @<Local variables for hyphenation@>@;
+begin @<Find hyphen locations for the word in |hc|, or |return|@>;
+@<If no hyphens were found, |return|@>;
+@<Replace nodes |ha..hb| by a sequence of nodes that includes
+  the discretionary hyphens@>;
+exit:end;
+
+@ The first thing we need to do is find the node |ha| just before the
+first letter.
+
+@<Skip to node |ha|, or |goto done1|...@>=
+loop@+  begin if is_char_node(s) then
+    begin hf:=font(s);
+    if font_dir[hf]<>dir_default then
+      begin prev_s:=s; s:=link(prev_s); c:=info(s); goto continue;
+      end else c:=qo(character(s));
+    end
+  else if type(s)=disp_node then goto continue
+  else if (type(s)=penalty_node)and(not subtype(s)=normal) then goto continue
+  else if type(s)=ligature_node then
+    if lig_ptr(s)=null then goto continue
+    else begin q:=lig_ptr(s); c:=qo(character(q)); hf:=font(q);
+      end
+  else if (type(s)=kern_node)and(subtype(s)=normal) then goto continue
+  else if type(s)=whatsit_node then
+    begin @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>;
+    goto continue;
+    end
+  else goto done1;
+  if lc_code(c)<>0 then
+    if (lc_code(c)=c)or(uc_hyph>0) then goto done2
+    else goto done1;
+continue: prev_s:=s; s:=link(prev_s);
+  end;
+done2: hyf_char:=hyphen_char[hf];
+if hyf_char<0 then goto done1;
+if hyf_char>255 then goto done1;
+ha:=prev_s
+
+@ The word to be hyphenated is now moved to the |hu| and |hc| arrays.
+
+@<Skip to node |hb|, putting letters...@>=
+hn:=0;
+loop@+  begin if is_char_node(s) then
+    begin if font(s)<>hf then goto done3;
+    hyf_bchar:=character(s); c:=qo(hyf_bchar);
+    if lc_code(c)=0 then goto done3;
+    if hn=63 then goto done3;
+    hb:=s; incr(hn); hu[hn]:=c; hc[hn]:=lc_code(c); hyf_bchar:=non_char;
+    end
+  else if type(s)=ligature_node then
+    @<Move the characters of a ligature node to |hu| and |hc|;
+      but |goto done3| if they are not all letters@>
+  else if (type(s)=kern_node)and(subtype(s)=normal) then
+    begin hb:=s;
+    hyf_bchar:=font_bchar[hf];
+    end
+  else goto done3;
+  s:=link(s);
+  end;
+done3:
+
+@ We let |j| be the index of the character being stored when a ligature node
+is being expanded, since we do not want to advance |hn| until we are sure
+that the entire ligature consists of letters. Note that it is possible
+to get to |done3| with |hn=0| and |hb| not set to any value.
+
+@<Move the characters of a ligature node to |hu| and |hc|...@>=
+begin if font(lig_char(s))<>hf then goto done3;
+j:=hn; q:=lig_ptr(s);@+if q>null then hyf_bchar:=character(q);
+while q>null do
+  begin c:=qo(character(q));
+  if lc_code(c)=0 then goto done3;
+  if j=63 then goto done3;
+  incr(j); hu[j]:=c; hc[j]:=lc_code(c);@/
+  q:=link(q);
+  end;
+hb:=s; hn:=j;
+if odd(subtype(s)) then hyf_bchar:=font_bchar[hf]@+else hyf_bchar:=non_char;
+end
+
+@ @<Check that the nodes following |hb| permit hyphenation...@>=
+if hn<l_hyf+r_hyf then goto done1; {|l_hyf| and |r_hyf| are |>=1|}
+loop@+  begin if not(is_char_node(s)) then
+    case type(s) of
+    ligature_node: do_nothing;
+    kern_node: if subtype(s)<>normal then goto done4;
+    disp_node: do_nothing;
+    whatsit_node,glue_node,penalty_node,ins_node,adjust_node,mark_node:
+      goto done4;
+    othercases goto done1
+    endcases;
+  s:=link(s);
+  end;
+done4:
+
+@* \[41] Post-hyphenation.
+If a hyphen may be inserted between |hc[j]| and |hc[j+1]|, the hyphenation
+procedure will set |hyf[j]| to some small odd number. But before we look
+at \TeX's hyphenation procedure, which is independent of the rest of the
+line-breaking algorithm, let us consider what we will do with the hyphens
+it finds, since it is better to work on this part of the program before
+forgetting what |ha| and |hb|, etc., are all about.
+
+@<Glob...@>=
+@!hyf:array [0..64] of 0..9; {odd values indicate discretionary hyphens}
+@!init_list:pointer; {list of punctuation characters preceding the word}
+@!init_lig:boolean; {does |init_list| represent a ligature?}
+@!init_lft:boolean; {if so, did the ligature involve a left boundary?}
+
+@ @<Local variables for hyphenation@>=
+@!i,@!j,@!l:0..65; {indices into |hc| or |hu|}
+@!q,@!r,@!s:pointer; {temporary registers for list manipulation}
+@!bchar:halfword; {right boundary character of hyphenated word, or |non_char|}
+
+@ \TeX\ will never insert a hyphen that has fewer than
+\.{\\lefthyphenmin} letters before it or fewer than
+\.{\\righthyphenmin} after it; hence, a short word has
+comparatively little chance of being hyphenated. If no hyphens have
+been found, we can save time by not having to make any changes to the
+paragraph.
+
+@<If no hyphens were found, |return|@>=
+for j:=l_hyf to hn-r_hyf do if odd(hyf[j]) then goto found1;
+return;
+found1:
+
+@ If hyphens are in fact going to be inserted, \TeX\ first deletes the
+subsequence of nodes between |ha| and~|hb|. An attempt is made to
+preserve the effect that implicit boundary characters and punctuation marks
+had on ligatures inside the hyphenated word, by storing a left boundary or
+preceding character in |hu[0]| and by storing a possible right boundary
+in |bchar|. We set |j:=0| if |hu[0]| is to be part of the reconstruction;
+otherwise |j:=1|.
+The variable |s| will point to the tail of the current hlist, and
+|q| will point to the node following |hb|, so that
+things can be hooked up after we reconstitute the hyphenated word.
+
+@<Replace nodes |ha..hb| by a sequence of nodes...@>=
+q:=link(hb); link(hb):=null; r:=link(ha); link(ha):=null; bchar:=hyf_bchar;
+if is_char_node(ha) then
+  if font(ha)<>hf then goto found2
+  else begin init_list:=ha; init_lig:=false; hu[0]:=qo(character(ha));
+    end
+else if type(ha)=ligature_node then
+  if font(lig_char(ha))<>hf then goto found2
+  else begin init_list:=lig_ptr(ha); init_lig:=true; init_lft:=(subtype(ha)>1);
+    hu[0]:=qo(character(lig_char(ha)));
+    if init_list=null then if init_lft then
+      begin hu[0]:=256; init_lig:=false;
+      end; {in this case a ligature will be reconstructed from scratch}
+    free_node(ha,small_node_size);
+    end
+else begin {no punctuation found; look for left boundary}
+  if not is_char_node(r) then if type(r)=ligature_node then
+   if subtype(r)>1 then goto found2;
+  j:=1; s:=ha; init_list:=null; goto common_ending;
+  end;
+s:=cur_p; {we have |cur_p<>ha| because |type(cur_p)=glue_node|}
+while link(s)<>ha do s:=link(s);
+j:=0; goto common_ending;
+found2: s:=ha; j:=0; hu[0]:=256; init_lig:=false; init_list:=null;
+common_ending: flush_node_list(r);
+@<Reconstitute nodes for the hyphenated word, inserting discretionary hyphens@>;
+flush_list(init_list)
+
+@ We must now face the fact that the battle is not over, even though the
+{\def\!{\kern-1pt}%
+hyphens have been found: The process of reconstituting a word can be nontrivial
+because ligatures might change when a hyphen is present. {\sl The \TeX book\/}
+discusses the difficulties of the word ``difficult'', and
+the discretionary material surrounding a
+hyphen can be considerably more complex than that. Suppose
+\.{abcdef} is a word in a font for which the only ligatures are \.{b\!c},
+\.{c\!d}, \.{d\!e}, and \.{e\!f}. If this word permits hyphenation
+between \.b and \.c, the two patterns with and without hyphenation are
+$\.a\,\.b\,\.-\,\.{c\!d}\,\.{e\!f}$ and $\.a\,\.{b\!c}\,\.{d\!e}\,\.f$.
+Thus the insertion of a hyphen might cause effects to ripple arbitrarily
+far into the rest of the word. A further complication arises if additional
+hyphens appear together with such rippling, e.g., if the word in the
+example just given could also be hyphenated between \.c and \.d; \TeX\
+avoids this by simply ignoring the additional hyphens in such weird cases.}
+
+Still further complications arise in the presence of ligatures that do not
+delete the original characters. When punctuation precedes the word being
+hyphenated, \TeX's method is not perfect under all possible scenarios,
+because punctuation marks and letters can propagate information back and forth.
+For example, suppose the original pre-hyphenation pair
+\.{*a} changes to \.{*y} via a \.{\?=:} ligature, which changes to \.{xy}
+via a \.{=:\?} ligature; if $p_{a-1}=\.x$ and $p_a=\.y$, the reconstitution
+procedure isn't smart enough to obtain \.{xy} again. In such cases the
+font designer should include a ligature that goes from \.{xa} to \.{xy}.
+
+@ The processing is facilitated by a subroutine called |reconstitute|. Given
+a string of characters $x_j\ldots x_n$, there is a smallest index $m\ge j$
+such that the ``translation'' of $x_j\ldots x_n$ by ligatures and kerning
+has the form $y_1\ldots y_t$ followed by the translation of $x_{m+1}\ldots x_n$,
+where $y_1\ldots y_t$ is some nonempty sequence of character, ligature, and
+kern nodes. We call $x_j\ldots x_m$ a ``cut prefix'' of $x_j\ldots x_n$.
+For example, if $x_1x_2x_3=\.{fly}$, and if the font contains `fl' as a
+ligature and a kern between `fl' and `y', then $m=2$, $t=2$, and $y_1$ will
+be a ligature node for `fl' followed by an appropriate kern node~$y_2$.
+In the most common case, $x_j$~forms no ligature with $x_{j+1}$ and we
+simply have $m=j$, $y_1=x_j$. If $m<n$ we can repeat the procedure on
+$x_{m+1}\ldots x_n$ until the entire translation has been found.
+
+The |reconstitute| function returns the integer $m$ and puts the nodes
+$y_1\ldots y_t$ into a linked list starting at |link(hold_head)|,
+getting the input $x_j\ldots x_n$ from the |hu| array. If $x_j=256$,
+we consider $x_j$ to be an implicit left boundary character; in this
+case |j| must be strictly less than~|n|. There is a
+parameter |bchar|, which is either 256 or an implicit right boundary character
+assumed to be present just following~$x_n$. (The value |hu[n+1]| is never
+explicitly examined, but the algorithm imagines that |bchar| is there.)
+
+If there exists an index |k| in the range $j\le k\le m$ such that |hyf[k]|
+is odd and such that the result of |reconstitute| would have been different
+if $x_{k+1}$ had been |hchar|, then |reconstitute| sets |hyphen_passed|
+to the smallest such~|k|. Otherwise it sets |hyphen_passed| to zero.
+
+A special convention is used in the case |j=0|: Then we assume that the
+translation of |hu[0]| appears in a special list of charnodes starting at
+|init_list|; moreover, if |init_lig| is |true|, then |hu[0]| will be
+a ligature character, involving a left boundary if |init_lft| is |true|.
+This facility is provided for cases when a hyphenated
+word is preceded by punctuation (like single or double quotes) that might
+affect the translation of the beginning of the word.
+
+@<Glob...@>=
+@!hyphen_passed:small_number; {first hyphen in a ligature, if any}
+
+@ @<Declare the function called |reconstitute|@>=
+function reconstitute(@!j,@!n:small_number;@!bchar,@!hchar:halfword):
+  small_number;
+label continue,done;
+var @!p:pointer; {temporary register for list manipulation}
+@!t:pointer; {a node being appended to}
+@!q:four_quarters; {character information or a lig/kern instruction}
+@!cur_rh:halfword; {hyphen character for ligature testing}
+@!test_char:halfword; {hyphen or other character for ligature testing}
+@!w:scaled; {amount of kerning}
+@!k:font_index; {position of current lig/kern instruction}
+begin hyphen_passed:=0; t:=hold_head; w:=0; link(hold_head):=null;
+ {at this point |ligature_present=lft_hit=rt_hit=false|}
+@<Set up data structures with the cursor following position |j|@>;
+continue:@<If there's a ligature or kern at the cursor position, update the data
+  structures, possibly advancing~|j|; continue until the cursor moves@>;
+@<Append a ligature and/or kern to the translation;
+  |goto continue| if the stack of inserted ligatures is nonempty@>;
+reconstitute:=j;
+end;
+
+@ The reconstitution procedure shares many of the global data structures
+by which \TeX\ has processed the words before they were hyphenated.
+There is an implied ``cursor'' between characters |cur_l| and |cur_r|;
+these characters will be tested for possible ligature activity. If
+|ligature_present| then |cur_l| is a ligature character formed from the
+original characters following |cur_q| in the current translation list.
+There is a ``ligature stack'' between the cursor and character |j+1|,
+consisting of pseudo-ligature nodes linked together by their |link| fields.
+This stack is normally empty unless a ligature command has created a new
+character that will need to be processed later. A pseudo-ligature is
+a special node having a |character| field that represents a potential
+ligature and a |lig_ptr| field that points to a |char_node| or is |null|.
+We have
+$$|cur_r|=\cases{|character(lig_stack)|,&if |lig_stack>null|;\cr
+  |qi(hu[j+1])|,&if |lig_stack=null| and |j<n|;\cr
+  bchar,&if |lig_stack=null| and |j=n|.\cr}$$
+
+@<Glob...@>=
+@!cur_l,@!cur_r:halfword; {characters before and after the cursor}
+@!cur_q:pointer; {where a ligature should be detached}
+@!lig_stack:pointer; {unfinished business to the right of the cursor}
+@!ligature_present:boolean; {should a ligature node be made for |cur_l|?}
+@!lft_hit,@!rt_hit:boolean; {did we hit a ligature with a boundary character?}
+
+@ @d append_charnode_to_t(#)== begin link(t):=get_avail; t:=link(t);
+    font(t):=hf; character(t):=#;
+    end
+@d set_cur_r==begin if j<n then cur_r:=qi(hu[j+1])@+else cur_r:=bchar;
+    if odd(hyf[j]) then cur_rh:=hchar@+else cur_rh:=non_char;
+    end
+
+@<Set up data structures with the cursor following position |j|@>=
+cur_l:=qi(hu[j]); cur_q:=t;
+if j=0 then
+  begin ligature_present:=init_lig; p:=init_list;
+  if ligature_present then lft_hit:=init_lft;
+  while p>null do
+    begin append_charnode_to_t(character(p)); p:=link(p);
+    end;
+  end
+else if cur_l<non_char then append_charnode_to_t(cur_l);
+lig_stack:=null; set_cur_r
+
+@ We may want to look at the lig/kern program twice, once for a hyphen
+and once for a normal letter. (The hyphen might appear after the letter
+in the program, so we'd better not try to look for both at once.)
+
+@<If there's a ligature or kern at the cursor position, update...@>=
+if cur_l=non_char then
+  begin k:=bchar_label[hf];
+  if k=non_address then goto done@+else q:=font_info[k].qqqq;
+  end
+else begin q:=char_info(hf)(cur_l);
+  if char_tag(q)<>lig_tag then goto done;
+  k:=lig_kern_start(hf)(q); q:=font_info[k].qqqq;
+  if skip_byte(q)>stop_flag then
+    begin k:=lig_kern_restart(hf)(q); q:=font_info[k].qqqq;
+    end;
+  end; {now |k| is the starting address of the lig/kern program}
+if cur_rh<non_char then test_char:=cur_rh@+else test_char:=cur_r;
+loop@+begin if next_char(q)=test_char then if skip_byte(q)<=stop_flag then
+    if cur_rh<non_char then
+      begin hyphen_passed:=j; hchar:=non_char; cur_rh:=non_char;
+      goto continue;
+      end
+    else begin if hchar<non_char then if odd(hyf[j]) then
+        begin hyphen_passed:=j; hchar:=non_char;
+        end;
+      if op_byte(q)<kern_flag then
+      @<Carry out a ligature replacement, updating the cursor structure
+        and possibly advancing~|j|; |goto continue| if the cursor doesn't
+        advance, otherwise |goto done|@>;
+      w:=char_kern(hf)(q); goto done; {this kern will be inserted below}
+     end;
+  if skip_byte(q)>=stop_flag then
+    if cur_rh=non_char then goto done
+    else begin cur_rh:=non_char; goto continue;
+      end;
+  k:=k+qo(skip_byte(q))+1; q:=font_info[k].qqqq;
+  end;
+done:
+
+@ @d wrap_lig(#)==if ligature_present then
+    begin p:=new_ligature(hf,cur_l,link(cur_q));
+    if lft_hit then
+      begin subtype(p):=2; lft_hit:=false;
+      end;
+    if # then if lig_stack=null then
+      begin incr(subtype(p)); rt_hit:=false;
+      end;
+    link(cur_q):=p; t:=p; ligature_present:=false;
+    end
+@d pop_lig_stack==begin if lig_ptr(lig_stack)>null then
+    begin link(t):=lig_ptr(lig_stack); {this is a charnode for |hu[j+1]|}
+    t:=link(t); incr(j);
+    end;
+  p:=lig_stack; lig_stack:=link(p); free_node(p,small_node_size);
+  if lig_stack=null then set_cur_r@+else cur_r:=character(lig_stack);
+  end {if |lig_stack| isn't |null| we have |cur_rh=non_char|}
+
+@<Append a ligature and/or kern to the translation...@>=
+wrap_lig(rt_hit);
+if w<>0 then
+  begin link(t):=new_kern(w); t:=link(t); w:=0;
+  end;
+if lig_stack>null then
+  begin cur_q:=t; cur_l:=character(lig_stack); ligature_present:=true;
+  pop_lig_stack; goto continue;
+  end
+
+@ @<Carry out a ligature replacement, updating the cursor structure...@>=
+begin if cur_l=non_char then lft_hit:=true;
+if j=n then if lig_stack=null then rt_hit:=true;
+check_interrupt; {allow a way out in case there's an infinite ligature loop}
+case op_byte(q) of
+qi(1),qi(5):begin cur_l:=rem_byte(q); {\.{=:\?}, \.{=:\?>}}
+  ligature_present:=true;
+  end;
+qi(2),qi(6):begin cur_r:=rem_byte(q); {\.{\?=:}, \.{\?=:>}}
+  if lig_stack>null then character(lig_stack):=cur_r
+  else begin lig_stack:=new_lig_item(cur_r);
+    if j=n then bchar:=non_char
+    else begin p:=get_avail; lig_ptr(lig_stack):=p;
+      character(p):=qi(hu[j+1]); font(p):=hf;
+      end;
+    end;
+  end;
+qi(3):begin cur_r:=rem_byte(q); {\.{\?=:\?}}
+  p:=lig_stack; lig_stack:=new_lig_item(cur_r); link(lig_stack):=p;
+  end;
+qi(7),qi(11):begin wrap_lig(false); {\.{\?=:\?>}, \.{\?=:\?>>}}
+  cur_q:=t; cur_l:=rem_byte(q); ligature_present:=true;
+  end;
+othercases begin cur_l:=rem_byte(q); ligature_present:=true; {\.{=:}}
+  if lig_stack>null then pop_lig_stack
+  else if j=n then goto done
+  else begin append_charnode_to_t(cur_r); incr(j); set_cur_r;
+    end;
+  end
+endcases;
+if op_byte(q)>qi(4) then if op_byte(q)<>qi(7) then goto done;
+goto continue;
+end
+
+@ Okay, we're ready to insert the potential hyphenations that were found.
+When the following program is executed, we want to append the word
+|hu[1..hn]| after node |ha|, and node |q| should be appended to the result.
+During this process, the variable |i| will be a temporary
+index into |hu|; the variable |j| will be an index to our current position
+in |hu|; the variable |l| will be the counterpart of |j|, in a discretionary
+branch; the variable |r| will point to new nodes being created; and
+we need a few new local variables:
+
+@<Local variables for hyph...@>=
+@!major_tail,@!minor_tail:pointer; {the end of lists in the main and
+  discretionary branches being reconstructed}
+@!c:ASCII_code; {character temporarily replaced by a hyphen}
+@!c_loc:0..63; {where that character came from}
+@!r_count:integer; {replacement count for discretionary}
+@!hyf_node:pointer; {the hyphen, if it exists}
+
+@ When the following code is performed, |hyf[0]| and |hyf[hn]| will be zero.
+
+@<Reconstitute nodes for the hyphenated word...@>=
+repeat l:=j; j:=reconstitute(j,hn,bchar,qi(hyf_char))+1;
+if hyphen_passed=0 then
+  begin link(s):=link(hold_head);
+  while link(s)>null do s:=link(s);
+  if odd(hyf[j-1]) then
+    begin l:=j; hyphen_passed:=j-1; link(hold_head):=null;
+    end;
+  end;
+if hyphen_passed>0 then
+  @<Create and append a discretionary node as an alternative to the
+    unhyphenated word, and continue to develop both branches until they
+    become equivalent@>;
+until j>hn;
+link(s):=q
+
+@ In this repeat loop we will insert another discretionary if |hyf[j-1]| is
+odd, when both branches of the previous discretionary end at position |j-1|.
+Strictly speaking, we aren't justified in doing this, because we don't know
+that a hyphen after |j-1| is truly independent of those branches. But in almost
+all applications we would rather not lose a potentially valuable hyphenation
+point. (Consider the word `difficult', where the letter `c' is in position |j|.)
+
+@d advance_major_tail==begin major_tail:=link(major_tail); incr(r_count);
+    end
+
+@<Create and append a discretionary node as an alternative...@>=
+repeat r:=get_node(small_node_size);
+link(r):=link(hold_head); type(r):=disc_node;
+major_tail:=r; r_count:=0;
+while link(major_tail)>null do advance_major_tail;
+i:=hyphen_passed; hyf[i]:=0;
+@<Put the \(c)characters |hu[l..i]| and a hyphen into |pre_break(r)|@>;
+@<Put the \(c)characters |hu[i+1..@,]| into |post_break(r)|, appending to this
+  list and to |major_tail| until synchronization has been achieved@>;
+@<Move pointer |s| to the end of the current list, and set |replace_count(r)|
+  appropriately@>;
+hyphen_passed:=j-1; link(hold_head):=null;
+until not odd(hyf[j-1])
+
+@ The new hyphen might combine with the previous character via ligature
+or kern. At this point we have |l-1<=i<j| and |i<hn|.
+
+@<Put the \(c)characters |hu[l..i]| and a hyphen into |pre_break(r)|@>=
+minor_tail:=null; pre_break(r):=null; hyf_node:=new_character(hf,hyf_char);
+if hyf_node<>null then
+  begin incr(i); c:=hu[i]; hu[i]:=hyf_char; free_avail(hyf_node);
+  end;
+while l<=i do
+  begin l:=reconstitute(l,i,font_bchar[hf],non_char)+1;
+  if link(hold_head)>null then
+    begin if minor_tail=null then pre_break(r):=link(hold_head)
+    else link(minor_tail):=link(hold_head);
+    minor_tail:=link(hold_head);
+    while link(minor_tail)>null do minor_tail:=link(minor_tail);
+    end;
+  end;
+if hyf_node<>null then
+  begin hu[i]:=c; {restore the character in the hyphen position}
+  l:=i; decr(i);
+  end
+
+@ The synchronization algorithm begins with |l=i+1<=j|.
+
+@<Put the \(c)characters |hu[i+1..@,]| into |post_break(r)|...@>=
+minor_tail:=null; post_break(r):=null; c_loc:=0;
+if bchar_label[hf]<>non_address then {put left boundary at beginning of new line}
+  begin decr(l); c:=hu[l]; c_loc:=l; hu[l]:=256;
+  end;
+while l<j do
+  begin repeat l:=reconstitute(l,hn,bchar,non_char)+1;
+  if c_loc>0 then
+    begin hu[c_loc]:=c; c_loc:=0;
+    end;
+  if link(hold_head)>null then
+    begin if minor_tail=null then post_break(r):=link(hold_head)
+    else link(minor_tail):=link(hold_head);
+    minor_tail:=link(hold_head);
+    while link(minor_tail)>null do minor_tail:=link(minor_tail);
+    end;
+  until l>=j;
+  while l>j do
+    @<Append characters of |hu[j..@,]| to |major_tail|, advancing~|j|@>;
+  end
+
+@ @<Append characters of |hu[j..@,]|...@>=
+begin j:=reconstitute(j,hn,bchar,non_char)+1;
+link(major_tail):=link(hold_head);
+while link(major_tail)>null do advance_major_tail;
+end
+
+@ Ligature insertion can cause a word to grow exponentially in size. Therefore
+we must test the size of |r_count| here, even though the hyphenated text
+was at most 63 characters long.
+
+@<Move pointer |s| to the end of the current list...@>=
+if r_count>127 then {we have to forget the discretionary hyphen}
+  begin link(s):=link(r); link(r):=null; flush_node_list(r);
+  end
+else begin link(s):=r; replace_count(r):=r_count;
+  end;
+s:=major_tail
+
+@* \[42] Hyphenation.
+When a word |hc[1..hn]| has been set up to contain a candidate for hyphenation,
+\TeX\ first looks to see if it is in the user's exception dictionary. If not,
+hyphens are inserted based on patterns that appear within the given word,
+using an algorithm due to Frank~M. Liang.
+@^Liang, Franklin Mark@>
+
+Let's consider Liang's method first, since it is much more interesting than the
+exception-lookup routine.  The algorithm begins by setting |hyf[j]| to zero
+for all |j|, and invalid characters are inserted into |hc[0]|
+and |hc[hn+1]| to serve as delimiters. Then a reasonably fast method is
+used to see which of a given set of patterns occurs in the word
+|hc[0..(hn+1)]|. Each pattern $p_1\ldots p_k$ of length |k| has an associated
+sequence of |k+1| numbers $n_0\ldots n_k$; and if the pattern occurs in
+|hc[(j+1)..(j+k)]|, \TeX\ will set |hyf[j+i]:=@tmax@>(hyf[j+i],@t$n_i$@>)| for
+|0<=i<=k|. After this has been done for each pattern that occurs, a
+discretionary hyphen will be inserted between |hc[j]| and |hc[j+1]| when
+|hyf[j]| is odd, as we have already seen.
+
+The set of patterns $p_1\ldots p_k$ and associated numbers $n_0\ldots n_k$
+depends, of course, on the language whose words are being hyphenated, and
+on the degree of hyphenation that is desired. A method for finding
+appropriate |p|'s and |n|'s, from a given dictionary of words and acceptable
+hyphenations, is discussed in Liang's Ph.D. thesis (Stanford University,
+1983); \TeX\ simply starts with the patterns and works from there.
+
+@ The patterns are stored in a compact table that is also efficient for
+retrieval, using a variant of ``trie memory'' [cf.\ {\sl The Art of
+Computer Programming \bf3} (1973), 481--505]. We can find each pattern
+$p_1\ldots p_k$ by letting $z_0$ be one greater than the relevant language
+index and then, for |1<=i<=k|,
+setting |@t$z_i$@>:=trie_link@t$(z_{i-1})+p_i$@>|; the pattern will be
+identified by the number $z_k$. Since all the pattern information is
+packed together into a single |trie_link| array, it is necessary to
+prevent confusion between the data from inequivalent patterns, so another
+table is provided such that |trie_char@t$(z_i)=p_i$@>| for all |i|. There
+is also a table |trie_op|$(z_k)$ to identify the numbers $n_0\ldots n_k$
+associated with $p_1\ldots p_k$.
+
+The theory that comparatively few different number sequences $n_0\ldots n_k$
+actually occur, since most of the |n|'s are generally zero, seems to fail
+at least for the large German hyphenation patterns.
+Therefore the number sequences cannot any longer be encoded in such a way
+that |trie_op|$(z_k)$ is only one byte long.
+We have introduced a new constant |max_trie_op| for the maximum allowable
+hyphenation operation code value; |max_trie_op| might be different for
+\TeX\ and \.{INITEX} and must not exceed |max_halfword|.
+An opcode will occupy a halfword if |max_trie_op| exceeds |max_quarterword|
+or a quarterword otherwise.
+@^system dependencies@>
+If |trie_op(@t$z_k$@>)<>min_trie_op|, when $p_1\ldots p_k$ has matched
+the letters in |hc[(l-k+1)..l@,]| of language |t|,
+we perform all of the required operations
+for this pattern by carrying out the following little program: Set
+|v:=trie_op(@t$z_k$@>)|. Then set |v:=v+op_start[t]|,
+|hyf[l-hyf_distance[v]]:=@tmax@>(hyf[l-hyf_distance[v]], hyf_num[v])|,
+and |v:=hyf_next[v]|; repeat, if necessary, until |v=min_trie_op|.
+
+@<Types...@>=
+@!trie_pointer=0..ssup_trie_size; {an index into |trie|}
+@!trie_opcode=0..ssup_trie_opcode;  {a trie opcode}
+
+@ For more than 255 trie op codes, the three fields |trie_link|, |trie_char|,
+and |trie_op| will no longer fit into one memory word; thus using web2c
+we define |trie| as three array instead of an array of records.
+The variant will be implented by reusing the opcode field later on with
+another macro.
+
+@d trie_link(#)==trie_trl[#] {``downward'' link in a trie}
+@d trie_char(#)==trie_trc[#] {character matched at this trie location}
+@d trie_op(#)==trie_tro[#] {program for hyphenation at this trie location}
+
+@<Glob...@>=
+{We will dynamically allocate these arrays.}
+@!trie_trl:^trie_pointer; {|trie_link|}
+@!trie_tro:^trie_pointer; {|trie_op|}
+@!trie_trc:^quarterword; {|trie_char|}
+@!hyf_distance:array[1..trie_op_size] of small_number; {position |k-j| of $n_j$}
+@!hyf_num:array[1..trie_op_size] of small_number; {value of $n_j$}
+@!hyf_next:array[1..trie_op_size] of trie_opcode; {continuation code}
+@!op_start:array[ASCII_code] of 0..trie_op_size; {offset for current language}
+
+@ @<Local variables for hyph...@>=
+@!z:trie_pointer; {an index into |trie|}
+@!v:integer; {an index into |hyf_distance|, etc.}
+
+@ Assuming that these auxiliary tables have been set up properly, the
+hyphenation algorithm is quite short. In the following code we set |hc[hn+2]|
+to the impossible value 256, in order to guarantee that |hc[hn+3]| will
+never be fetched.
+
+@<Find hyphen locations for the word in |hc|...@>=
+for j:=0 to hn do hyf[j]:=0;
+@<Look for the word |hc[1..hn]| in the exception table, and |goto found| (with
+  |hyf| containing the hyphens) if an entry is found@>;
+if trie_char(cur_lang+1)<>qi(cur_lang) then return; {no patterns for |cur_lang|}
+hc[0]:=0; hc[hn+1]:=0; hc[hn+2]:=256; {insert delimiters}
+for j:=0 to hn-r_hyf+1 do
+  begin z:=trie_link(cur_lang+1)+hc[j]; l:=j;
+  while hc[l]=qo(trie_char(z)) do
+    begin if trie_op(z)<>min_trie_op then
+      @<Store \(m)maximum values in the |hyf| table@>;
+    incr(l); z:=trie_link(z)+hc[l];
+    end;
+  end;
+found: for j:=0 to l_hyf-1 do hyf[j]:=0;
+for j:=0 to r_hyf-1 do hyf[hn-j]:=0
+
+@ @<Store \(m)maximum values in the |hyf| table@>=
+begin v:=trie_op(z);
+repeat v:=v+op_start[cur_lang]; i:=l-hyf_distance[v];
+if hyf_num[v]>hyf[i] then hyf[i]:=hyf_num[v];
+v:=hyf_next[v];
+until v=min_trie_op;
+end
+
+@ The exception table that is built by \TeX's \.{\\hyphenation} primitive is
+organized as an ordered hash table [cf.\ Amble and Knuth, {\sl The Computer
+@^Amble, Ole@> @^Knuth, Donald Ervin@>
+Journal\/ \bf17} (1974), 135--142] using linear probing. If $\alpha$ and
+$\beta$ are words, we will say that $\alpha<\beta$ if $\vert\alpha\vert<
+\vert\beta\vert$ or if $\vert\alpha\vert=\vert\beta\vert$ and
+$\alpha$ is lexicographically smaller than $\beta$. (The notation $\vert
+\alpha\vert$ stands for the length of $\alpha$.) The idea of ordered hashing
+is to arrange the table so that a given word $\alpha$ can be sought by computing
+a hash address $h=h(\alpha)$ and then looking in table positions |h|, |h-1|,
+\dots, until encountering the first word $\L\alpha$. If this word is
+different from $\alpha$, we can conclude that $\alpha$ is not in the table.
+This is a clever scheme which saves the need for a hash link array.
+However, it is difficult to increase the size of the hyphen exception
+arrays. To make this easier, the ordered hash has been replaced by
+a simple hash, using an additional array |hyph_link|. The value
+|0| in |hyph_link[k]| means that there are no more entries corresponding
+to the specific hash chain. When |hyph_link[k]>0|, the next entry in
+the hash chain is |hyph_link[k]-1|. This value is used because the
+arrays start at |0|.
+
+The words in the table point to lists in |mem| that specify hyphen positions
+in their |info| fields. The list for $c_1\ldots c_n$ contains the number |k| if
+the word $c_1\ldots c_n$ has a discretionary hyphen between $c_k$ and
+$c_{k+1}$.
+
+@<Types...@>=
+@!hyph_pointer=0..ssup_hyph_size; {index into hyphen exceptions hash table;
+                     enlarging this requires changing (un)dump code}
+
+@ @<Glob...@>=
+@!hyph_word: ^str_number; {exception words}
+@!hyph_list: ^pointer; {lists of hyphen positions}
+@!hyph_link: ^hyph_pointer; {link array for hyphen exceptions hash table}
+@!hyph_count:integer; {the number of words in the exception dictionary}
+@!hyph_next:integer; {next free slot in hyphen exceptions hash table}
+
+@ @<Local variables for init...@>=
+@!z:hyph_pointer; {runs through the exception dictionary}
+
+@ @<Set init...@>=
+for z:=0 to hyph_size do
+  begin hyph_word[z]:=0; hyph_list[z]:=null; hyph_link[z]:=0;
+  end;
+hyph_count:=0;
+hyph_next:=hyph_prime+1; if hyph_next>hyph_size then hyph_next:=hyph_prime;
+
+@ The algorithm for exception lookup is quite simple, as soon as we have
+a few more local variables to work with.
+
+@<Local variables for hyph...@>=
+@!h:hyph_pointer; {an index into |hyph_word| and |hyph_list|}
+@!k:str_number; {an index into |str_start|}
+@!u:pool_pointer; {an index into |str_pool|}
+
+@ First we compute the hash code |h|, then we search until we either
+find the word or we don't. Words from different languages are kept
+separate by appending the language code to the string.
+
+@<Look for the word |hc[1...@>=
+h:=hc[1]; incr(hn); hc[hn]:=cur_lang;
+for j:=2 to hn do h:=(h+h+hc[j]) mod hyph_prime;
+loop@+  begin @<If the string |hyph_word[h]| is less than \(hc)|hc[1..hn]|,
+    |goto not_found|; but if the two strings are equal,
+    set |hyf| to the hyphen positions and |goto found|@>;
+  h:=hyph_link[h]; if h=0 then goto not_found;
+  decr(h);
+  end;
+not_found: decr(hn)
+
+@ @<If the string |hyph_word[h]| is less than \(hc)...@>=
+{This is now a simple hash list, not an ordered one, so
+the module title is no longer descriptive.}
+k:=hyph_word[h]; if k=0 then goto not_found;
+if length(k)=hn then
+  begin j:=1; u:=str_start[k];
+  repeat
+  if so(str_pool[u])<>hc[j] then goto done;
+  incr(j); incr(u);
+  until j>hn;
+  @<Insert hyphens as specified in |hyph_list[h]|@>;
+  decr(hn); goto found;
+  end;
+done:
+
+@ @<Insert hyphens as specified...@>=
+s:=hyph_list[h];
+while s<>null do
+  begin hyf[info(s)]:=1; s:=link(s);
+  end
+
+@ @<Search |hyph_list| for pointers to |p|@>=
+for q:=0 to hyph_size do
+  begin if hyph_list[q]=p then
+    begin print_nl("HYPH("); print_int(q); print_char(")");
+    end;
+  end
+
+@ We have now completed the hyphenation routine, so the |line_break| procedure
+is finished at last. Since the hyphenation exception table is fresh in our
+minds, it's a good time to deal with the routine that adds new entries to it.
+
+When \TeX\ has scanned `\.{\\hyphenation}', it calls on a procedure named
+|new_hyph_exceptions| to do the right thing.
+
+@d set_cur_lang==if language<=0 then cur_lang:=0
+  else if language>255 then cur_lang:=0
+  else cur_lang:=language
+
+@p procedure new_hyph_exceptions; {enters new exceptions}
+label reswitch, exit, found, not_found;
+var n:0..64; {length of current word; not always a |small_number|}
+@!j:0..64; {an index into |hc|}
+@!h:hyph_pointer; {an index into |hyph_word| and |hyph_list|}
+@!k:str_number; {an index into |str_start|}
+@!p:pointer; {head of a list of hyphen positions}
+@!q:pointer; {used when creating a new node for list |p|}
+@!s:str_number; {strings being compared or stored}
+@!u,@!v:pool_pointer; {indices into |str_pool|}
+begin scan_left_brace; {a left brace must follow \.{\\hyphenation}}
+set_cur_lang;
+@<Enter as many hyphenation exceptions as are listed,
+until coming to a right brace; then |return|@>;
+exit:end;
+
+@ @<Enter as many...@>=
+n:=0; p:=null;
+loop@+  begin get_x_token;
+  reswitch: case cur_cmd of
+  letter,other_char,char_given:@<Append a new letter or hyphen@>;
+  char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
+    goto reswitch;
+    end;
+  spacer,right_brace: begin if n>1 then @<Enter a hyphenation exception@>;
+    if cur_cmd=right_brace then return;
+    n:=0; p:=null;
+    end;
+  othercases @<Give improper \.{\\hyphenation} error@>
+  endcases;
+  end
+
+@ @<Give improper \.{\\hyph...@>=
+begin print_err("Improper "); print_esc("hyphenation");
+@.Improper \\hyphenation...@>
+  print(" will be flushed");
+help2("Hyphenation exceptions must contain only letters")@/
+  ("and hyphens. But continue; I'll forgive and forget.");
+error;
+end
+
+@ @<Append a new letter or hyphen@>=
+if cur_chr="-" then @<Append the value |n| to list |p|@>
+else  begin if lc_code(cur_chr)=0 then
+    begin print_err("Not a letter");
+@.Not a letter@>
+    help2("Letters in \hyphenation words must have \lccode>0.")@/
+      ("Proceed; I'll ignore the character I just read.");
+    error;
+    end
+  else if n<63 then
+    begin incr(n); hc[n]:=lc_code(cur_chr);
+    end;
+  end
+
+@ @<Append the value |n| to list |p|@>=
+begin if n<63 then
+  begin q:=get_avail; link(q):=p; info(q):=n; p:=q;
+  end;
+end
+
+@ @<Enter a hyphenation exception@>=
+begin incr(n); hc[n]:=cur_lang; str_room(n); h:=0;
+for j:=1 to n do
+  begin h:=(h+h+hc[j]) mod hyph_prime;
+  append_char(hc[j]);
+  end;
+s:=make_string;
+@<Insert the \(p)pair |(s,p)| into the exception table@>;
+end
+
+@ @<Insert the \(p)pair |(s,p)|...@>=
+  if hyph_next <= hyph_prime then
+     while (hyph_next>0) and (hyph_word[hyph_next-1]>0) do decr(hyph_next);
+if (hyph_count=hyph_size)or(hyph_next=0) then
+   overflow("exception dictionary",hyph_size);
+@:TeX capacity exceeded exception dictionary}{\quad exception dictionary@>
+incr(hyph_count);
+while hyph_word[h]<>0 do
+  begin @<If the string |hyph_word[h]| is less than \(or)or equal to
+  |s|, interchange |(hyph_word[h],hyph_list[h])| with |(s,p)|@>;
+  if hyph_link[h]=0 then
+  begin
+    hyph_link[h]:=hyph_next;
+    if hyph_next >= hyph_size then hyph_next:=hyph_prime;
+    if hyph_next > hyph_prime then incr(hyph_next);
+  end;
+  h:=hyph_link[h]-1;
+  end;
+
+found: hyph_word[h]:=s; hyph_list[h]:=p
+
+@ @<If the string |hyph_word[h]| is less than \(or)...@>=
+{This is now a simple hash list, not an ordered one, so
+the module title is no longer descriptive.}
+k:=hyph_word[h];
+if length(k)<>length(s) then goto not_found;
+u:=str_start[k]; v:=str_start[s];
+repeat if str_pool[u]<>str_pool[v] then goto not_found;
+incr(u); incr(v);
+until u=str_start[k+1];
+{repeat hyphenation exception; flushing old data}
+flush_string; s:=hyph_word[h]; {avoid |slow_make_string|!}
+decr(hyph_count);
+{ We could also |flush_list(hyph_list[h]);|, but it interferes
+  with \.{trip.log}. }
+goto found;
+not_found:
+
+@* \[43] Initializing the hyphenation tables.
+The trie for \TeX's hyphenation algorithm is built from a sequence of
+patterns following a \.{\\patterns} specification. Such a specification
+is allowed only in \.{INITEX}, since the extra memory for auxiliary tables
+and for the initialization program itself would only clutter up the
+production version of \TeX\ with a lot of deadwood.
+
+The first step is to build a trie that is linked, instead of packed
+into sequential storage, so that insertions are readily made.
+After all patterns have been processed, \.{INITEX}
+compresses the linked trie by identifying common subtries. Finally the
+trie is packed into the efficient sequential form that the hyphenation
+algorithm actually uses.
+
+@<Declare subprocedures for |line_break|@>=
+@!init @<Declare procedures for preprocessing hyphenation patterns@>@;
+tini
+
+@ Before we discuss trie building in detail, let's consider the simpler
+problem of creating the |hyf_distance|, |hyf_num|, and |hyf_next| arrays.
+
+Suppose, for example, that \TeX\ reads the pattern `\.{ab2cde1}'. This is
+a pattern of length 5, with $n_0\ldots n_5=0\,0\,2\,0\,0\,1$ in the
+notation above. We want the corresponding |trie_op| code |v| to have
+|hyf_distance[v]=3|, |hyf_num[v]=2|, and |hyf_next[v]=@t$v^\prime$@>|,
+where the auxiliary |trie_op| code $v^\prime$ has
+|hyf_distance[@t$v^\prime$@>]=0|, |hyf_num[@t$v^\prime$@>]=1|, and
+|hyf_next[@t$v^\prime$@>]=min_trie_op|.
+
+\TeX\ computes an appropriate value |v| with the |new_trie_op| subroutine
+below, by setting
+$$\hbox{|@t$v^\prime$@>:=new_trie_op(0,1,min_trie_op)|,\qquad
+|v:=new_trie_op(3,2,@t$v^\prime$@>)|.}$$
+This subroutine looks up its three
+parameters in a special hash table, assigning a new value only if these
+three have not appeared before for the current language.
+
+The hash table is called |trie_op_hash|, and the number of entries it contains
+is |trie_op_ptr|.
+
+@<Glob...@>=
+@!init@! trie_op_hash:array[neg_trie_op_size..trie_op_size] of 0..trie_op_size;
+  {trie op codes for quadruples}
+@!trie_used:array[ASCII_code] of trie_opcode;
+  {largest opcode used so far for this language}
+@!trie_op_lang:array[1..trie_op_size] of ASCII_code;
+  {language part of a hashed quadruple}
+@!trie_op_val:array[1..trie_op_size] of trie_opcode;
+  {opcode corresponding to a hashed quadruple}
+@!trie_op_ptr:0..trie_op_size; {number of stored ops so far}
+tini@;
+@!max_op_used:trie_opcode; {largest opcode used for any language}
+@!small_op:boolean; {flag used while dumping or undumping}
+
+@ It's tempting to remove the |overflow| stops in the following procedure;
+|new_trie_op| could return |min_trie_op| (thereby simply ignoring
+part of a hyphenation pattern) instead of aborting the job. However, that would
+lead to different hyphenation results on different installations of \TeX\
+using the same patterns. The |overflow| stops are necessary for portability
+of patterns.
+
+@<Declare procedures for preprocessing hyph...@>=
+function new_trie_op(@!d,@!n:small_number;@!v:trie_opcode):trie_opcode;
+label exit;
+var h:neg_trie_op_size..trie_op_size; {trial hash location}
+@!u:trie_opcode; {trial op code}
+@!l:0..trie_op_size; {pointer to stored data}
+begin h:=abs(intcast(n)+313*intcast(d)+361*intcast(v)+1009*intcast(cur_lang))
+  mod (trie_op_size - neg_trie_op_size)
+  + neg_trie_op_size;
+loop@+  begin l:=trie_op_hash[h];
+  if l=0 then {empty position found for a new op}
+    begin if trie_op_ptr=trie_op_size then
+      overflow("pattern memory ops",trie_op_size);
+    u:=trie_used[cur_lang];
+    if u=max_trie_op then
+      overflow("pattern memory ops per language",
+      max_trie_op-min_trie_op);
+    incr(trie_op_ptr); incr(u); trie_used[cur_lang]:=u;
+    if u>max_op_used then max_op_used:=u;
+    hyf_distance[trie_op_ptr]:=d;
+    hyf_num[trie_op_ptr]:=n; hyf_next[trie_op_ptr]:=v;
+    trie_op_lang[trie_op_ptr]:=cur_lang; trie_op_hash[h]:=trie_op_ptr;
+    trie_op_val[trie_op_ptr]:=u; new_trie_op:=u; return;
+    end;
+  if (hyf_distance[l]=d)and(hyf_num[l]=n)and(hyf_next[l]=v)
+   and(trie_op_lang[l]=cur_lang) then
+    begin new_trie_op:=trie_op_val[l]; return;
+    end;
+  if h>-trie_op_size then decr(h)@+else h:=trie_op_size;
+  end;
+exit:end;
+
+@ After |new_trie_op| has compressed the necessary opcode information,
+plenty of information is available to unscramble the data into the
+final form needed by our hyphenation algorithm.
+
+@<Sort \(t)the hyphenation op tables into proper order@>=
+op_start[0]:=-min_trie_op;
+for j:=1 to 255 do op_start[j]:=op_start[j-1]+qo(trie_used[j-1]);
+for j:=1 to trie_op_ptr do
+  trie_op_hash[j]:=op_start[trie_op_lang[j]]+trie_op_val[j]; {destination}
+for j:=1 to trie_op_ptr do while trie_op_hash[j]>j do
+  begin k:=trie_op_hash[j];@/
+  t:=hyf_distance[k]; hyf_distance[k]:=hyf_distance[j]; hyf_distance[j]:=t;@/
+  t:=hyf_num[k]; hyf_num[k]:=hyf_num[j]; hyf_num[j]:=t;@/
+  t:=hyf_next[k]; hyf_next[k]:=hyf_next[j]; hyf_next[j]:=t;@/
+  trie_op_hash[j]:=trie_op_hash[k]; trie_op_hash[k]:=k;
+  end
+
+@ Before we forget how to initialize the data structures that have been
+mentioned so far, let's write down the code that gets them started.
+
+@<Initialize table entries...@>=
+for k:=-trie_op_size to trie_op_size do trie_op_hash[k]:=0;
+for k:=0 to 255 do trie_used[k]:=min_trie_op;
+max_op_used:=min_trie_op;
+trie_op_ptr:=0;
+
+@ The linked trie that is used to preprocess hyphenation patterns appears
+in several global arrays. Each node represents an instruction of the form
+``if you see character |c|, then perform operation |o|, move to the
+next character, and go to node |l|; otherwise go to node |r|.''
+The four quantities |c|, |o|, |l|, and |r| are stored in four arrays
+|trie_c|, |trie_o|, |trie_l|, and |trie_r|. The root of the trie
+is |trie_l[0]|, and the number of nodes is |trie_ptr|. Null trie
+pointers are represented by zero. To initialize the trie, we simply
+set |trie_l[0]| and |trie_ptr| to zero. We also set |trie_c[0]| to some
+arbitrary value, since the algorithm may access it.
+
+The algorithms maintain the condition
+$$\hbox{|trie_c[trie_r[z]]>trie_c[z]|\qquad
+whenever |z<>0| and |trie_r[z]<>0|};$$ in other words, sibling nodes are
+ordered by their |c| fields.
+
+@d trie_root==trie_l[0] {root of the linked trie}
+
+@<Glob...@>=
+@!init @!trie_c:^packed_ASCII_code;
+  {characters to match}
+@t\hskip10pt@>@!trie_o:^trie_opcode;
+  {operations to perform}
+@t\hskip10pt@>@!trie_l:^trie_pointer;
+  {left subtrie links}
+@t\hskip10pt@>@!trie_r:^trie_pointer;
+  {right subtrie links}
+@t\hskip10pt@>@!trie_ptr:trie_pointer; {the number of nodes in the trie}
+@t\hskip10pt@>@!trie_hash:^trie_pointer;
+  {used to identify equivalent subtries}
+tini
+
+@ Let us suppose that a linked trie has already been constructed.
+Experience shows that we can often reduce its size by recognizing common
+subtries; therefore another hash table is introduced for this purpose,
+somewhat similar to |trie_op_hash|. The new hash table will be
+initialized to zero.
+
+The function |trie_node(p)| returns |p| if |p| is distinct from other nodes
+that it has seen, otherwise it returns the number of the first equivalent
+node that it has seen.
+
+Notice that we might make subtries equivalent even if they correspond to
+patterns for different languages, in which the trie ops might mean quite
+different things. That's perfectly all right.
+
+@<Declare procedures for preprocessing hyph...@>=
+function trie_node(@!p:trie_pointer):trie_pointer; {converts
+  to a canonical form}
+label exit;
+var h:trie_pointer; {trial hash location}
+@!q:trie_pointer; {trial trie node}
+begin h:=abs(intcast(trie_c[p])+1009*intcast(trie_o[p])+@|
+    2718*intcast(trie_l[p])+3142*intcast(trie_r[p])) mod trie_size;
+loop@+  begin q:=trie_hash[h];
+  if q=0 then
+    begin trie_hash[h]:=p; trie_node:=p; return;
+    end;
+  if (trie_c[q]=trie_c[p])and(trie_o[q]=trie_o[p])and@|
+    (trie_l[q]=trie_l[p])and(trie_r[q]=trie_r[p]) then
+    begin trie_node:=q; return;
+    end;
+  if h>0 then decr(h)@+else h:=trie_size;
+  end;
+exit:end;
+
+@ A neat recursive procedure is now able to compress a trie by
+traversing it and applying |trie_node| to its nodes in ``bottom up''
+fashion. We will compress the entire trie by clearing |trie_hash| to
+zero and then saying `|trie_root:=compress_trie(trie_root)|'.
+@^recursion@>
+
+@<Declare procedures for preprocessing hyph...@>=
+function compress_trie(@!p:trie_pointer):trie_pointer;
+begin if p=0 then compress_trie:=0
+else  begin trie_l[p]:=compress_trie(trie_l[p]);
+  trie_r[p]:=compress_trie(trie_r[p]);
+  compress_trie:=trie_node(p);
+  end;
+end;
+
+@ The compressed trie will be packed into the |trie| array using a
+``top-down first-fit'' procedure. This is a little tricky, so the reader
+should pay close attention: The |trie_hash| array is cleared to zero
+again and renamed |trie_ref| for this phase of the operation; later on,
+|trie_ref[p]| will be nonzero only if the linked trie node |p| is the
+smallest character
+in a family and if the characters |c| of that family have been allocated to
+locations |trie_ref[p]+c| in the |trie| array. Locations of |trie| that
+are in use will have |trie_link=0|, while the unused holes in |trie|
+will be doubly linked with |trie_link| pointing to the next larger vacant
+location and |trie_back| pointing to the next smaller one. This double
+linking will have been carried out only as far as |trie_max|, where
+|trie_max| is the largest index of |trie| that will be needed.
+To save time at the low end of the trie, we maintain array entries
+|trie_min[c]| pointing to the smallest hole that is greater than~|c|.
+Another array |trie_taken| tells whether or not a given location is
+equal to |trie_ref[p]| for some |p|; this array is used to ensure that
+distinct nodes in the compressed trie will have distinct |trie_ref|
+entries.
+
+@d trie_ref==trie_hash {where linked trie families go into |trie|}
+@d trie_back(#)==trie_tro[#] {use the opcode field now for backward links}
+
+@<Glob...@>=
+@!init@!trie_taken: ^boolean;
+  {does a family start here?}
+@t\hskip10pt@>@!trie_min:array[ASCII_code] of trie_pointer;
+  {the first possible slot for each character}
+@t\hskip10pt@>@!trie_max:trie_pointer; {largest location used in |trie|}
+@t\hskip10pt@>@!trie_not_ready:boolean; {is the trie still in linked form?}
+tini
+
+@ Each time \.{\\patterns} appears, it contributes further patterns to
+the future trie, which will be built only when hyphenation is attempted or
+when a format file is dumped. The boolean variable |trie_not_ready|
+will change to |false| when the trie is compressed; this will disable
+further patterns.
+
+@<Initialize table entries...@>=
+trie_not_ready:=true;
+
+@ Here is how the trie-compression data structures are initialized.
+If storage is tight, it would be possible to overlap |trie_op_hash|,
+|trie_op_lang|, and |trie_op_val| with |trie|, |trie_hash|, and |trie_taken|,
+because we finish with the former just before we need the latter.
+
+@<Get ready to compress the trie@>=
+@<Sort \(t)the hyphenation...@>;
+for p:=0 to trie_size do trie_hash[p]:=0;
+trie_root:=compress_trie(trie_root); {identify equivalent subtries}
+for p:=0 to trie_ptr do trie_ref[p]:=0;
+for p:=0 to 255 do trie_min[p]:=p+1;
+trie_link(0):=1; trie_max:=0
+
+@ The |first_fit| procedure finds the smallest hole |z| in |trie| such that
+a trie family starting at a given node |p| will fit into vacant positions
+starting at |z|. If |c=trie_c[p]|, this means that location |z-c| must
+not already be taken by some other family, and that |z-c+@t$c^\prime$@>|
+must be vacant for all characters $c^\prime$ in the family. The procedure
+sets |trie_ref[p]| to |z-c| when the first fit has been found.
+
+@<Declare procedures for preprocessing hyph...@>=
+procedure first_fit(@!p:trie_pointer); {packs a family into |trie|}
+label not_found,found;
+var h:trie_pointer; {candidate for |trie_ref[p]|}
+@!z:trie_pointer; {runs through holes}
+@!q:trie_pointer; {runs through the family starting at |p|}
+@!c:ASCII_code; {smallest character in the family}
+@!l,@!r:trie_pointer; {left and right neighbors}
+@!ll:1..256; {upper limit of |trie_min| updating}
+begin c:=so(trie_c[p]);
+z:=trie_min[c]; {get the first conceivably good hole}
+loop@+  begin h:=z-c;@/
+  @<Ensure that |trie_max>=h+256|@>;
+  if trie_taken[h] then goto not_found;
+  @<If all characters of the family fit relative to |h|, then
+    |goto found|,\30\ otherwise |goto not_found|@>;
+  not_found: z:=trie_link(z); {move to the next hole}
+  end;
+found: @<Pack the family into |trie| relative to |h|@>;
+end;
+
+@ By making sure that |trie_max| is at least |h+256|, we can be sure that
+|trie_max>z|, since |h=z-c|. It follows that location |trie_max| will
+never be occupied in |trie|, and we will have |trie_max>=trie_link(z)|.
+
+@<Ensure that |trie_max>=h+256|@>=
+if trie_max<h+256 then
+  begin if trie_size<=h+256 then overflow("pattern memory",trie_size);
+@:TeX capacity exceeded pattern memory}{\quad pattern memory@>
+  repeat incr(trie_max); trie_taken[trie_max]:=false;
+  trie_link(trie_max):=trie_max+1; trie_back(trie_max):=trie_max-1;
+  until trie_max=h+256;
+  end
+
+@ @<If all characters of the family fit relative to |h|...@>=
+q:=trie_r[p];
+while q>0 do
+  begin if trie_link(h+so(trie_c[q]))=0 then goto not_found;
+  q:=trie_r[q];
+  end;
+goto found
+
+@ @<Pack the family into |trie| relative to |h|@>=
+trie_taken[h]:=true; trie_ref[p]:=h; q:=p;
+repeat z:=h+so(trie_c[q]); l:=trie_back(z); r:=trie_link(z);
+trie_back(r):=l; trie_link(l):=r; trie_link(z):=0;
+if l<256 then
+  begin if z<256 then ll:=z @+else ll:=256;
+  repeat trie_min[l]:=r; incr(l);
+  until l=ll;
+  end;
+q:=trie_r[q];
+until q=0
+
+@ To pack the entire linked trie, we use the following recursive procedure.
+@^recursion@>
+
+@<Declare procedures for preprocessing hyph...@>=
+procedure trie_pack(@!p:trie_pointer); {pack subtries of a family}
+var q:trie_pointer; {a local variable that need not be saved on recursive calls}
+begin repeat q:=trie_l[p];
+if (q>0)and(trie_ref[q]=0) then
+  begin first_fit(q); trie_pack(q);
+  end;
+p:=trie_r[p];
+until p=0;
+end;
+
+@ When the whole trie has been allocated into the sequential table, we
+must go through it once again so that |trie| contains the correct
+information. Null pointers in the linked trie will be represented by the
+value~0, which properly implements an ``empty'' family.
+
+@d clear_trie == {clear |trie[r]|}
+  begin trie_link(r):=0;
+  trie_op(r):=min_trie_op;
+  trie_char(r):=min_quarterword; {|trie_char:=qi(0)|}
+  end
+
+@<Move the data into |trie|@>=
+if trie_root=0 then {no patterns were given}
+  begin for r:=0 to 256 do clear_trie;
+  trie_max:=256;
+  end
+else begin trie_fix(trie_root); {this fixes the non-holes in |trie|}
+  r:=0; {now we will zero out all the holes}
+  repeat s:=trie_link(r); clear_trie; r:=s;
+  until r>trie_max;
+  end;
+trie_char(0):=qi("?"); {make |trie_char(c)<>c| for all |c|}
+
+@ The fixing-up procedure is, of course, recursive. Since the linked trie
+usually has overlapping subtries, the same data may be moved several
+times; but that causes no harm, and at most as much work is done as it
+took to build the uncompressed trie.
+@^recursion@>
+
+@<Declare procedures for preprocessing hyph...@>=
+procedure trie_fix(@!p:trie_pointer); {moves |p| and its siblings into |trie|}
+var q:trie_pointer; {a local variable that need not be saved on recursive calls}
+@!c:ASCII_code; {another one that need not be saved}
+@!z:trie_pointer; {|trie| reference; this local variable must be saved}
+begin z:=trie_ref[p];
+repeat q:=trie_l[p]; c:=so(trie_c[p]);
+trie_link(z+c):=trie_ref[q]; trie_char(z+c):=qi(c); trie_op(z+c):=trie_o[p];
+if q>0 then trie_fix(q);
+p:=trie_r[p];
+until p=0;
+end;
+
+@ Now let's go back to the easier problem, of building the linked
+trie.  When \.{INITEX} has scanned the `\.{\\patterns}' control
+sequence, it calls on |new_patterns| to do the right thing.
+
+@<Declare procedures for preprocessing hyph...@>=
+procedure new_patterns; {initializes the hyphenation pattern data}
+label done, done1;
+var k,@!l:0..64; {indices into |hc| and |hyf|;
+                  not always in |small_number| range}
+@!digit_sensed:boolean; {should the next digit be treated as a letter?}
+@!v:trie_opcode; {trie op code}
+@!p,@!q:trie_pointer; {nodes of trie traversed during insertion}
+@!first_child:boolean; {is |p=trie_l[q]|?}
+@!c:ASCII_code; {character being inserted}
+begin if trie_not_ready then
+  begin set_cur_lang; scan_left_brace; {a left brace must follow \.{\\patterns}}
+  @<Enter all of the patterns into a linked trie, until coming to a right
+  brace@>;
+  end
+else begin print_err("Too late for "); print_esc("patterns");
+  help1("All patterns must be given before typesetting begins.");
+  error; link(garbage):=scan_toks(false,false); flush_list(def_ref);
+  end;
+end;
+
+@ Novices are not supposed to be using \.{\\patterns}, so the error
+messages are terse. (Note that all error messages appear in \TeX's string
+pool, even if they are used only by \.{INITEX}.)
+
+@<Enter all of the patterns into a linked trie...@>=
+k:=0; hyf[0]:=0; digit_sensed:=false;
+loop@+  begin get_x_token;
+  case cur_cmd of
+  letter,other_char:@<Append a new letter or a hyphen level@>;
+  spacer,right_brace: begin if k>0 then
+      @<Insert a new pattern into the linked trie@>;
+    if cur_cmd=right_brace then goto done;
+    k:=0; hyf[0]:=0; digit_sensed:=false;
+    end;
+  othercases begin print_err("Bad "); print_esc("patterns");
+@.Bad \\patterns@>
+    help1("(See Appendix H.)"); error;
+    end
+  endcases;
+  end;
+done:
+
+@ @<Append a new letter or a hyphen level@>=
+if digit_sensed or(cur_chr<"0")or(cur_chr>"9") then
+  begin if cur_chr="." then cur_chr:=0 {edge-of-word delimiter}
+  else  begin cur_chr:=lc_code(cur_chr);
+    if cur_chr=0 then
+      begin print_err("Nonletter");
+@.Nonletter@>
+      help1("(See Appendix H.)"); error;
+      end;
+    end;
+  if k<63 then
+    begin incr(k); hc[k]:=cur_chr; hyf[k]:=0; digit_sensed:=false;
+    end;
+  end
+else if k<63 then
+  begin hyf[k]:=cur_chr-"0"; digit_sensed:=true;
+  end
+
+@ When the following code comes into play, the pattern $p_1\ldots p_k$
+appears in |hc[1..k]|, and the corresponding sequence of numbers $n_0\ldots
+n_k$ appears in |hyf[0..k]|.
+
+@<Insert a new pattern into the linked trie@>=
+begin @<Compute the trie op code, |v|, and set |l:=0|@>;
+q:=0; hc[0]:=cur_lang;
+while l<=k do
+  begin c:=hc[l]; incr(l); p:=trie_l[q]; first_child:=true;
+  while (p>0)and(c>so(trie_c[p])) do
+    begin q:=p; p:=trie_r[q]; first_child:=false;
+    end;
+  if (p=0)or(c<so(trie_c[p])) then
+    @<Insert a new trie node between |q| and |p|, and
+      make |p| point to it@>;
+  q:=p; {now node |q| represents $p_1\ldots p_{l-1}$}
+  end;
+if trie_o[q]<>min_trie_op then
+  begin print_err("Duplicate pattern");
+@.Duplicate pattern@>
+  help1("(See Appendix H.)"); error;
+  end;
+trie_o[q]:=v;
+end
+
+@ @<Insert a new trie node between |q| and |p|...@>=
+begin if trie_ptr=trie_size then overflow("pattern memory",trie_size);
+@:TeX capacity exceeded pattern memory}{\quad pattern memory@>
+incr(trie_ptr); trie_r[trie_ptr]:=p; p:=trie_ptr; trie_l[p]:=0;
+if first_child then trie_l[q]:=p@+else trie_r[q]:=p;
+trie_c[p]:=si(c); trie_o[p]:=min_trie_op;
+end
+
+@ @<Compute the trie op code, |v|...@>=
+if hc[1]=0 then hyf[0]:=0;
+if hc[k]=0 then hyf[k]:=0;
+l:=k; v:=min_trie_op;
+loop@+  begin if hyf[l]<>0 then v:=new_trie_op(k-l,hyf[l],v);
+  if l>0 then decr(l)@+else goto done1;
+  end;
+done1:
+
+@ Finally we put everything together: Here is how the trie gets to its
+final, efficient form.
+The following packing routine is rigged so that the root of the linked
+tree gets mapped into location 1 of |trie|, as required by the hyphenation
+algorithm. This happens because the first call of |first_fit| will
+``take'' location~1.
+
+@<Declare procedures for preprocessing hyphenation patterns@>=
+procedure init_trie;
+var @!p:trie_pointer; {pointer for initialization}
+@!j,@!k,@!t:integer; {all-purpose registers for initialization}
+@!r,@!s:trie_pointer; {used to clean up the packed |trie|}
+begin @<Get ready to compress the trie@>;
+if trie_root<>0 then
+  begin first_fit(trie_root); trie_pack(trie_root);
+  end;
+@<Move the data into |trie|@>;
+trie_not_ready:=false;
+end;
+
+@* \[44] Breaking vertical lists into pages.
+The |vsplit| procedure, which implements \TeX's \.{\\vsplit} operation,
+is considerably simpler than |line_break| because it doesn't have to
+worry about hyphenation, and because its mission is to discover a single
+break instead of an optimum sequence of breakpoints.  But before we get
+into the details of |vsplit|, we need to consider a few more basic things.
+
+@ A subroutine called |prune_page_top| takes a pointer to a vlist and
+returns a pointer to a modified vlist in which all glue, kern, and penalty nodes
+have been deleted before the first box or rule node. However, the first
+box or rule is actually preceded by a newly created glue node designed so that
+the topmost baseline will be at distance |split_top_skip| from the top,
+whenever this is possible without backspacing.
+
+In this routine and those that follow, we make use of the fact that a
+vertical list contains no character nodes, hence the |type| field exists
+for each node in the list.
+@^data structure assumptions@>
+
+@p function prune_page_top(@!p:pointer):pointer; {adjust top after page break}
+var prev_p:pointer; {lags one step behind |p|}
+@!q:pointer; {temporary variable for list manipulation}
+begin prev_p:=temp_head; link(temp_head):=p;
+while p<>null do
+  case type(p) of
+  dir_node,
+  hlist_node,vlist_node,rule_node:@<Insert glue for |split_top_skip|
+    and set~|p:=null|@>;
+  whatsit_node,mark_node,ins_node: begin prev_p:=p; p:=link(prev_p);
+    end;
+  glue_node,kern_node,penalty_node: begin q:=p; p:=link(q); link(q):=null;
+    link(prev_p):=p; flush_node_list(q);
+    end;
+  othercases confusion("pruning")
+@:this can't happen pruning}{\quad pruning@>
+  endcases;
+prune_page_top:=link(temp_head);
+end;
+
+@ @<Insert glue for |split_top_skip|...@>=
+begin q:=new_skip_param(split_top_skip_code); link(prev_p):=q; link(q):=p;
+  {now |temp_ptr=glue_ptr(q)|}
+if width(temp_ptr)>height(p) then width(temp_ptr):=width(temp_ptr)-height(p)
+else width(temp_ptr):=0;
+p:=null;
+end
+
+@ The next subroutine finds the best place to break a given vertical list
+so as to obtain a box of height~|h|, with maximum depth~|d|.
+A pointer to the beginning of the vertical list is given,
+and a pointer to the optimum breakpoint is returned. The list is effectively
+followed by a forced break, i.e., a penalty node with the |eject_penalty|;
+if the best break occurs at this artificial node, the value |null| is returned.
+
+An array of six |scaled| distances is used to keep track of the height
+from the beginning of the list to the current place, just as in |line_break|.
+In fact, we use one of the same arrays, only changing its name to reflect
+its new significance.
+
+@d active_height==active_width {new name for the six distance variables}
+@d cur_height==active_height[1] {the natural height}
+@d set_height_zero(#)==active_height[#]:=0 {initialize the height to zero}
+@#
+@d update_heights=90 {go here to record glue in the |active_height| table}
+
+@p function vert_break(@!p:pointer; @!h,@!d:scaled):pointer;
+  {finds optimum page break}
+label done,not_found,update_heights;
+var prev_p:pointer; {if |p| is a glue node, |type(prev_p)| determines
+  whether |p| is a legal breakpoint}
+@!q,@!r:pointer; {glue specifications}
+@!pi:integer; {penalty value}
+@!b:integer; {badness at a trial breakpoint}
+@!least_cost:integer; {the smallest badness plus penalties found so far}
+@!best_place:pointer; {the most recent break that leads to |least_cost|}
+@!prev_dp:scaled; {depth of previous box in the list}
+@!t:small_number; {|type| of the node following a kern}
+begin prev_p:=p; {an initial glue node is not a legal breakpoint}
+least_cost:=awful_bad; do_all_six(set_height_zero); prev_dp:=0;
+loop@+  begin @<If node |p| is a legal breakpoint, check if this break is
+    the best known, and |goto done| if |p| is null or
+    if the page-so-far is already too full to accept more stuff@>;
+  prev_p:=p; p:=link(prev_p);
+  end;
+done: vert_break:=best_place;
+end;
+
+@ A global variable |best_height_plus_depth| will be set to the natural size
+of the box that corresponds to the optimum breakpoint found by |vert_break|.
+(This value is used by the insertion-splitting algorithm of the page builder.)
+
+@<Glob...@>=
+@!best_height_plus_depth:scaled; {height of the best box, without stretching or
+  shrinking}
+
+@ A subtle point to be noted here is that the maximum depth~|d| might be
+negative, so |cur_height| and |prev_dp| might need to be corrected even
+after a glue or kern node.
+
+@<If node |p| is a legal breakpoint, check...@>=
+if p=null then pi:=eject_penalty
+else  @<Use node |p| to update the current height and depth measurements;
+    if this node is not a legal breakpoint, |goto not_found|
+    or |update_heights|,
+    otherwise set |pi| to the associated penalty at the break@>;
+@<Check if node |p| is a new champion breakpoint; then \(go)|goto done|
+  if |p| is a forced break or if the page-so-far is already too full@>;
+if (type(p)<glue_node)or(type(p)>kern_node) then goto not_found;
+update_heights: @<Update the current height and depth measurements with
+  respect to a glue or kern node~|p|@>;
+not_found: if prev_dp>d then
+    begin cur_height:=cur_height+prev_dp-d;
+    prev_dp:=d;
+    end;
+
+@ @<Use node |p| to update the current height and depth measurements...@>=
+case type(p) of
+dir_node,
+hlist_node,vlist_node,rule_node: begin@t@>@;@/
+  cur_height:=cur_height+prev_dp+height(p); prev_dp:=depth(p);
+  goto not_found;
+  end;
+whatsit_node:@<Process whatsit |p| in |vert_break| loop, |goto not_found|@>;
+glue_node: if precedes_break(prev_p) then pi:=0
+  else goto update_heights;
+kern_node: begin if link(p)=null then t:=penalty_node
+  else t:=type(link(p));
+  if t=glue_node then pi:=0@+else goto update_heights;
+  end;
+penalty_node: pi:=penalty(p);
+mark_node,ins_node: goto not_found;
+othercases confusion("vertbreak")
+@:this can't happen vertbreak}{\quad vertbreak@>
+endcases
+
+@ @d deplorable==100000 {more than |inf_bad|, but less than |awful_bad|}
+
+@<Check if node |p| is a new champion breakpoint; then \(go)...@>=
+if pi<inf_penalty then
+  begin @<Compute the badness, |b|, using |awful_bad|
+    if the box is too full@>;
+  if b<awful_bad then
+    if pi<=eject_penalty then b:=pi
+    else if b<inf_bad then b:=b+pi
+      else b:=deplorable;
+  if b<=least_cost then
+    begin best_place:=p; least_cost:=b;
+    best_height_plus_depth:=cur_height+prev_dp;
+    end;
+  if (b=awful_bad)or(pi<=eject_penalty) then goto done;
+  end
+
+@ @<Compute the badness, |b|, using |awful_bad| if the box is too full@>=
+if cur_height<h then
+  if (active_height[3]<>0) or (active_height[4]<>0) or
+    (active_height[5]<>0) then b:=0
+  else b:=badness(h-cur_height,active_height[2])
+else if cur_height-h>active_height[6] then b:=awful_bad
+else b:=badness(cur_height-h,active_height[6])
+
+@ Vertical lists that are subject to the |vert_break| procedure should not
+contain infinite shrinkability, since that would permit any amount of
+information to ``fit'' on one page.
+
+@<Update the current height and depth measurements with...@>=
+if type(p)=kern_node then q:=p
+else  begin q:=glue_ptr(p);
+  active_height[2+stretch_order(q)]:=@|
+    active_height[2+stretch_order(q)]+stretch(q);@/
+  active_height[6]:=active_height[6]+shrink(q);
+  if (shrink_order(q)<>normal)and(shrink(q)<>0) then
+    begin@t@>@;@/
+    print_err("Infinite glue shrinkage found in box being split");@/
+@.Infinite glue shrinkage...@>
+    help4("The box you are \vsplitting contains some infinitely")@/
+      ("shrinkable glue, e.g., `\vss' or `\vskip 0pt minus 1fil'.")@/
+      ("Such glue doesn't belong there; but you can safely proceed,")@/
+      ("since the offensive shrinkability has been made finite.");
+    error; r:=new_spec(q); shrink_order(r):=normal; delete_glue_ref(q);
+    glue_ptr(p):=r; q:=r;
+    end;
+  end;
+cur_height:=cur_height+prev_dp+width(q); prev_dp:=0
+
+@ Now we are ready to consider |vsplit| itself. Most of
+its work is accomplished by the two subroutines that we have just considered.
+
+Given the number of a vlist box |n|, and given a desired page height |h|,
+the |vsplit| function finds the best initial segment of the vlist and
+returns a box for a page of height~|h|. The remainder of the vlist, if
+any, replaces the original box, after removing glue and penalties and
+adjusting for |split_top_skip|. Mark nodes in the split-off box are used to
+set the values of |split_first_mark| and |split_bot_mark|; we use the
+fact that |split_first_mark=null| if and only if |split_bot_mark=null|.
+
+The original box becomes ``void'' if and only if it has been entirely
+extracted.  The extracted box is ``void'' if and only if the original
+box was void (or if it was, erroneously, an hlist box).
+
+@p function vsplit(@!n:eight_bits; @!h:scaled):pointer;
+  {extracts a page of height |h| from box |n|}
+label exit,done;
+var v:pointer; {the box to be split}
+w:pointer; {|dir_node|}
+p:pointer; {runs through the vlist}
+q:pointer; {points to where the break occurs}
+begin v:=box(n);
+if split_first_mark<>null then
+  begin delete_token_ref(split_first_mark); split_first_mark:=null;
+  delete_token_ref(split_bot_mark); split_bot_mark:=null;
+  end;
+@<Dispense with trivial cases of void or bad boxes@>;
+q:=vert_break(list_ptr(v),h,split_max_depth);
+@<Look at all the marks in nodes before the break, and set the final
+  link to |null| at the break@>;
+q:=prune_page_top(q); p:=list_ptr(v);
+if q=null then box(n):=null {the |eq_level| of the box stays the same}
+else begin
+  box(n):=vpack(q,natural); set_box_dir(box(n))(box_dir(v));
+  end;
+q:=vpackage(p,h,exactly,split_max_depth);
+set_box_dir(q)(box_dir(v));
+delete_glue_ref(space_ptr(v)); delete_glue_ref(xspace_ptr(v));
+free_node(v,box_node_size);
+vsplit:=q;
+exit: end;
+
+@ @<Dispense with trivial cases of void or bad boxes@>=
+if v=null then
+  begin vsplit:=null; return;
+  end;
+if type(v)=dir_node then begin
+  w:=v; v:=list_ptr(v);
+  delete_glue_ref(space_ptr(w));
+  delete_glue_ref(xspace_ptr(w));
+  free_node(w,box_node_size);
+end;
+if type(v)<>vlist_node then begin
+  print_err(""); print_esc("vsplit"); print(" needs a ");
+  print_esc("vbox");
+@:vsplit_}{\.{\\vsplit needs a \\vbox}@>
+  help2("The box you are trying to split is an \hbox.")@/
+  ("I can't split such a box, so I'll leave it alone.");
+  error; vsplit:=null; return;
+end;
+flush_node_list(link(v)); link(v):=null
+
+@ It's possible that the box begins with a penalty node that is the
+``best'' break, so we must be careful to handle this special case correctly.
+
+@<Look at all the marks...@>=
+p:=list_ptr(v);
+if p=q then list_ptr(v):=null
+else loop@+begin if type(p)=mark_node then
+    if split_first_mark=null then
+      begin split_first_mark:=mark_ptr(p);
+      split_bot_mark:=split_first_mark;
+      token_ref_count(split_first_mark):=@|
+        token_ref_count(split_first_mark)+2;
+      end
+    else  begin delete_token_ref(split_bot_mark);
+      split_bot_mark:=mark_ptr(p);
+      add_token_ref(split_bot_mark);
+      end;
+  if link(p)=q then
+    begin link(p):=null; goto done;
+    end;
+  p:=link(p);
+  end;
+done:
+
+@* \[45] The page builder.
+When \TeX\ appends new material to its main vlist in vertical mode, it uses
+a method something like |vsplit| to decide where a page ends, except that
+the calculations are done ``on line'' as new items come in.
+The main complication in this process is that insertions must be put
+into their boxes and removed from the vlist, in a more-or-less optimum manner.
+
+We shall use the term ``current page'' for that part of the main vlist that
+is being considered as a candidate for being broken off and sent to the
+user's output routine. The current page starts at |link(page_head)|, and
+it ends at |page_tail|.  We have |page_head=page_tail| if this list is empty.
+@^current page@>
+
+Utter chaos would reign if the user kept changing page specifications
+while a page is being constructed, so the page builder keeps the pertinent
+specifications frozen as soon as the page receives its first box or
+insertion.  The global variable |page_contents| is |empty| when the
+current page contains only mark nodes and content-less whatsit nodes; it
+is |inserts_only| if the page contains only insertion nodes in addition to
+marks and whatsits.  Glue nodes, kern nodes, and penalty nodes are
+discarded until a box or rule node appears, at which time |page_contents|
+changes to |box_there|.  As soon as |page_contents| becomes non-|empty|,
+the current |vsize| and |max_depth| are squirreled away into |page_goal|
+and |page_max_depth|; the latter values will be used until the page has
+been forwarded to the user's output routine. The \.{\\topskip} adjustment
+is made when |page_contents| changes to |box_there|.
+
+Although |page_goal| starts out equal to |vsize|, it is decreased by the
+scaled natural height-plus-depth of the insertions considered so far, and by
+the \.{\\skip} corrections for those insertions. Therefore it represents
+the size into which the non-inserted material should fit, assuming that
+all insertions in the current page have been made.
+
+The global variables |best_page_break| and |least_page_cost| correspond
+respectively to the local variables |best_place| and |least_cost| in the
+|vert_break| routine that we have already studied; i.e., they record the
+location and value of the best place currently known for breaking the
+current page. The value of |page_goal| at the time of the best break is
+stored in |best_size|.
+
+@d inserts_only=1
+  {|page_contents| when an insert node has been contributed, but no boxes}
+@d box_there=2 {|page_contents| when a box or rule has been contributed}
+
+@<Glob...@>=
+@!page_tail:pointer; {the final node on the current page}
+@!page_contents:empty..box_there; {what is on the current page so far?}
+@!page_max_depth:scaled; {maximum box depth on page being built}
+@!best_page_break:pointer; {break here to get the best page known so far}
+@!least_page_cost:integer; {the score for this currently best page}
+@!best_size:scaled; {its |page_goal|}
+
+@ The page builder has another data structure to keep track of insertions.
+This is a list of four-word nodes, starting and ending at |page_ins_head|.
+That is, the first element of the list is node |r@t$_1$@>=link(page_ins_head)|;
+node $r_j$ is followed by |r@t$_{j+1}$@>=link(r@t$_j$@>)|; and if there are
+|n| items we have |r@t$_{n+1}$@>=page_ins_head|. The |subtype| field of
+each node in this list refers to an insertion number; for example, `\.{\\insert
+250}' would correspond to a node whose |subtype| is |qi(250)|
+(the same as the |subtype| field of the relevant |ins_node|). These |subtype|
+fields are in increasing order, and |subtype(page_ins_head)=
+qi(255)|, so |page_ins_head| serves as a convenient sentinel
+at the end of the list. A record is present for each insertion number that
+appears in the current page.
+
+The |type| field in these nodes distinguishes two possibilities that
+might occur as we look ahead before deciding on the optimum page break.
+If |type(r)=inserting|, then |height(r)| contains the total of the
+height-plus-depth dimensions of the box and all its inserts seen so far.
+If |type(r)=split_up|, then no more insertions will be made into this box,
+because at least one previous insertion was too big to fit on the current
+page; |broken_ptr(r)| points to the node where that insertion will be
+split, if \TeX\ decides to split it, |broken_ins(r)| points to the
+insertion node that was tentatively split, and |height(r)| includes also the
+natural height plus depth of the part that would be split off.
+
+In both cases, |last_ins_ptr(r)| points to the last |ins_node|
+encountered for box |qo(subtype(r))| that would be at least partially
+inserted on the next page; and |best_ins_ptr(r)| points to the last
+such |ins_node| that should actually be inserted, to get the page with
+minimum badness among all page breaks considered so far. We have
+|best_ins_ptr(r)=null| if and only if no insertion for this box should
+be made to produce this optimum page.
+
+The data structure definitions here use the fact that the |@!height| field
+appears in the fourth word of a box node.
+@^data structure assumptions@>
+
+@d page_ins_node_size=4 {number of words for a page insertion node}
+@d inserting=0 {an insertion class that has not yet overflowed}
+@d split_up=1 {an overflowed insertion class}
+@d broken_ptr(#)==link(#+1)
+  {an insertion for this class will break here if anywhere}
+@d broken_ins(#)==info(#+1) {this insertion might break at |broken_ptr|}
+@d last_ins_ptr(#)==link(#+2) {the most recent insertion for this |subtype|}
+@d best_ins_ptr(#)==info(#+2) {the optimum most recent insertion}
+
+@<Initialize the special list heads...@>=
+subtype(page_ins_head):=qi(255);
+type(page_ins_head):=split_up; link(page_ins_head):=page_ins_head;
+
+@ An array |page_so_far| records the heights and depths of everything
+on the current page. This array contains six |scaled| numbers, like the
+similar arrays already considered in |line_break| and |vert_break|; and it
+also contains |page_goal| and |page_depth|, since these values are
+all accessible to the user via |set_page_dimen| commands. The
+value of |page_so_far[1]| is also called |page_total|.  The stretch
+and shrink components of the \.{\\skip} corrections for each insertion are
+included in |page_so_far|, but the natural space components of these
+corrections are not, since they have been subtracted from |page_goal|.
+
+The variable |page_depth| records the depth of the current page; it has been
+adjusted so that it is at most |page_max_depth|. The variable
+|last_glue| points to the glue specification of the most recent node
+contributed from the contribution list, if this was a glue node; otherwise
+|last_glue=max_halfword|. (If the contribution list is nonempty,
+however, the value of |last_glue| is not necessarily accurate.)
+The variables |last_penalty| and |last_kern| are similar.  And
+finally, |insert_penalties| holds the sum of the penalties associated with
+all split and floating insertions.
+
+@d page_goal==page_so_far[0] {desired height of information on page being built}
+@d page_total==page_so_far[1] {height of the current page}
+@d page_shrink==page_so_far[6] {shrinkability of the current page}
+@d page_depth==page_so_far[7] {depth of the current page}
+
+@<Glob...@>=
+@!page_so_far:array [0..7] of scaled; {height and glue of the current page}
+@!last_glue:pointer; {used to implement \.{\\lastskip}}
+@!last_penalty:integer; {used to implement \.{\\lastpenalty}}
+@!last_kern:scaled; {used to implement \.{\\lastkern}}
+@!insert_penalties:integer; {sum of the penalties for held-over insertions}
+
+@ @<Put each...@>=
+primitive("pagegoal",set_page_dimen,0);
+@!@:page_goal_}{\.{\\pagegoal} primitive@>
+primitive("pagetotal",set_page_dimen,1);
+@!@:page_total_}{\.{\\pagetotal} primitive@>
+primitive("pagestretch",set_page_dimen,2);
+@!@:page_stretch_}{\.{\\pagestretch} primitive@>
+primitive("pagefilstretch",set_page_dimen,3);
+@!@:page_fil_stretch_}{\.{\\pagefilstretch} primitive@>
+primitive("pagefillstretch",set_page_dimen,4);
+@!@:page_fill_stretch_}{\.{\\pagefillstretch} primitive@>
+primitive("pagefilllstretch",set_page_dimen,5);
+@!@:page_filll_stretch_}{\.{\\pagefilllstretch} primitive@>
+primitive("pageshrink",set_page_dimen,6);
+@!@:page_shrink_}{\.{\\pageshrink} primitive@>
+primitive("pagedepth",set_page_dimen,7);
+@!@:page_depth_}{\.{\\pagedepth} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+set_page_dimen: case chr_code of
+0: print_esc("pagegoal");
+1: print_esc("pagetotal");
+2: print_esc("pagestretch");
+3: print_esc("pagefilstretch");
+4: print_esc("pagefillstretch");
+5: print_esc("pagefilllstretch");
+6: print_esc("pageshrink");
+othercases print_esc("pagedepth")
+endcases;
+
+@ @d print_plus_end(#)==print(#);@+end
+@d print_plus(#)==if page_so_far[#]<>0 then
+  begin print(" plus "); print_scaled(page_so_far[#]); print_plus_end
+
+@p procedure print_totals;
+begin print_scaled(page_total);
+print_plus(2)("");
+print_plus(3)("fil");
+print_plus(4)("fill");
+print_plus(5)("filll");
+if page_shrink<>0 then
+  begin print(" minus "); print_scaled(page_shrink);
+  end;
+end;
+
+@ @<Show the status of the current page@>=
+if page_head<>page_tail then
+  begin print_nl("### current page:");
+  if output_active then print(" (held over for next output)");
+@.held over for next output@>
+  show_box(link(page_head));
+  if page_contents>empty then
+    begin print_nl("total height "); print_totals;
+@:total_height}{\.{total height}@>
+    print_nl(" goal height "); print_scaled(page_goal);
+@.goal height@>
+    r:=link(page_ins_head);
+    while r<>page_ins_head do
+      begin print_ln; print_esc("insert"); t:=qo(subtype(r));
+      print_int(t); print(" adds ");
+      if count(t)=1000 then t:=height(r)
+      else t:=x_over_n(height(r),1000)*count(t);
+      print_scaled(t);
+      if type(r)=split_up then
+        begin q:=page_head; t:=0;
+        repeat q:=link(q);
+        if (type(q)=ins_node)and(subtype(q)=subtype(r)) then incr(t);
+        until q=broken_ins(r);
+        print(", #"); print_int(t); print(" might split");
+        end;
+      r:=link(r);
+      end;
+    end;
+  end
+
+@ Here is a procedure that is called when the |page_contents| is changing
+from |empty| to |inserts_only| or |box_there|.
+
+@d set_page_so_far_zero(#)==page_so_far[#]:=0
+
+@p procedure freeze_page_specs(@!s:small_number);
+begin page_contents:=s;
+page_goal:=vsize; page_max_depth:=max_depth;
+page_depth:=0; do_all_six(set_page_so_far_zero);
+least_page_cost:=awful_bad;
+@!stat if tracing_pages>0 then
+  begin begin_diagnostic;
+  print_nl("%% goal height="); print_scaled(page_goal);
+@.goal height@>
+  print(", max depth="); print_scaled(page_max_depth);
+  end_diagnostic(false);
+  end;@;@+tats@;@/
+end;
+
+@ Pages are built by appending nodes to the current list in \TeX's
+vertical mode, which is at the outermost level of the semantic nest. This
+vlist is split into two parts; the ``current page'' that we have been
+talking so much about already, and the ``contribution list'' that receives
+new nodes as they are created.  The current page contains everything that
+the page builder has accounted for in its data structures, as described
+above, while the contribution list contains other things that have been
+generated by other parts of \TeX\ but have not yet been
+seen by the page builder.
+The contribution list starts at |link(contrib_head)|, and it ends at the
+current node in \TeX's vertical mode.
+
+When \TeX\ has appended new material in vertical mode, it calls the procedure
+|build_page|, which tries to catch up by moving nodes from the contribution
+list to the current page. This procedure will succeed in its goal of
+emptying the contribution list, unless a page break is discovered, i.e.,
+unless the current page has grown to the point where the optimum next
+page break has been determined. In the latter case, the nodes after the
+optimum break will go back onto the contribution list, and control will
+effectively pass to the user's output routine.
+
+We make |type(page_head)=glue_node|, so that an initial glue node on
+the current page will not be considered a valid breakpoint.
+
+@<Initialize the special list...@>=
+type(page_head):=glue_node; subtype(page_head):=normal;
+
+@ The global variable |output_active| is true during the time the
+user's output routine is driving \TeX.
+
+@<Glob...@>=
+@!output_active:boolean; {are we in the midst of an output routine?}
+
+@ @<Set init...@>=
+output_active:=false; insert_penalties:=0;
+
+@ The page builder is ready to start a fresh page if we initialize
+the following state variables. (However, the page insertion list is initialized
+elsewhere.)
+
+@<Start a new current page@>=
+page_contents:=empty; page_tail:=page_head; link(page_head):=null;@/
+last_glue:=max_halfword; last_penalty:=0; last_kern:=0;
+page_depth:=0; page_max_depth:=0
+
+@ At certain times box 255 is supposed to be void (i.e., |null|),
+or an insertion box is supposed to be ready to accept a vertical list.
+If not, an error message is printed, and the following subroutine
+flushes the unwanted contents, reporting them to the user.
+
+@p procedure box_error(@!n:eight_bits);
+begin error; begin_diagnostic;
+print_nl("The following box has been deleted:");
+@.The following...deleted@>
+show_box(box(n)); end_diagnostic(true);
+flush_node_list(box(n)); box(n):=null;
+end;
+
+@ The following procedure guarantees that a given box register
+does not contain an \.{\\hbox}.
+
+@p procedure ensure_vbox(@!n:eight_bits);
+var p:pointer; {the box register contents}
+begin p:=box(n);
+if p<>null then if type(p)=dir_node then
+  begin p:=list_ptr(p);
+  delete_glue_ref(space_ptr(box(n)));
+  delete_glue_ref(xspace_ptr(box(n)));
+  free_node(box(n),box_node_size);
+  box(n):=p
+end;
+if p<>null then if type(p)<>vlist_node then begin
+  print_err("Insertions can only be added to a vbox");
+@.Insertions can only...@>
+  help3("Tut tut: You're trying to \insert into a")@/
+    ("\box register that now contains an \hbox.")@/
+    ("Proceed, and I'll discard its present contents.");
+  box_error(n);
+  end;
+end;
+
+@ \TeX\ is not always in vertical mode at the time |build_page|
+is called; the current mode reflects what \TeX\ should return to, after
+the contribution list has been emptied. A call on |build_page| should
+be immediately followed by `|goto big_switch|', which is \TeX's central
+control point.
+
+@d contribute=80 {go here to link a node into the current page}
+
+@p @t\4@>@<Declare the procedure called |fire_up|@>@;@/
+procedure build_page; {append contributions to the current page}
+label exit,done,done1,continue,contribute,update_heights;
+var p:pointer; {the node being appended}
+@!q,@!r:pointer; {nodes being examined}
+@!b,@!c:integer; {badness and cost of current page}
+@!pi:integer; {penalty to be added to the badness}
+@!n:min_quarterword..255; {insertion box number}
+@!delta,@!h,@!w:scaled; {sizes used for insertion calculations}
+begin if (link(contrib_head)=null)or output_active then return;
+repeat continue: p:=link(contrib_head);@/
+@<Update the values of |last_glue|, |last_penalty|, and |last_kern|@>;
+@<Move node |p| to the current page; if it is time for a page break,
+  put the nodes following the break back onto the contribution list,
+  and |return| to the user's output routine if there is one@>;
+until link(contrib_head)=null;
+@<Make the contribution list empty by setting its tail to |contrib_head|@>;
+exit:end;
+
+@ @d contrib_tail==nest[0].tail_field {tail of the contribution list}
+
+@<Make the contribution list empty...@>=
+if nest_ptr=0 then tail:=contrib_head {vertical mode}
+else contrib_tail:=contrib_head {other modes}
+
+@ @<Update the values of |last_glue|...@>=
+if last_glue<>max_halfword then delete_glue_ref(last_glue);
+last_penalty:=0; last_kern:=0;
+if type(p)=glue_node then
+  begin last_glue:=glue_ptr(p); add_glue_ref(last_glue);
+  end
+else  begin last_glue:=max_halfword;
+  if type(p)=penalty_node then last_penalty:=penalty(p)
+  else if type(p)=kern_node then last_kern:=width(p);
+  end
+
+@ The code here is an example of a many-way switch into routines that
+merge together in different places. Some people call this unstructured
+programming, but the author doesn't see much wrong with it, as long as
+@^Knuth, Donald Ervin@>
+the various labels have a well-understood meaning.
+
+@<Move node |p| to the current page; ...@>=
+@<If the current page is empty and node |p| is to be deleted, |goto done1|;
+  otherwise use node |p| to update the state of the current page;
+  if this node is an insertion, |goto contribute|; otherwise if this node
+  is not a legal breakpoint, |goto contribute| or |update_heights|;
+  otherwise set |pi| to the penalty associated with this breakpoint@>;
+@<Check if node |p| is a new champion breakpoint; then \(if)if it is time for
+  a page break, prepare for output, and either fire up the user's
+  output routine and |return| or ship out the page and |goto done|@>;
+if (type(p)<glue_node)or(type(p)>kern_node) then goto contribute;
+update_heights:@<Update the current page measurements with respect to the
+  glue or kern specified by node~|p|@>;
+contribute: @<Make sure that |page_max_depth| is not exceeded@>;
+@<Link node |p| into the current page and |goto done|@>;
+done1:@<Recycle node |p|@>;
+done:
+
+@ @<Link node |p| into the current page and |goto done|@>=
+link(page_tail):=p; page_tail:=p;
+link(contrib_head):=link(p); link(p):=null; goto done
+
+@ @<Recycle node |p|@>=
+link(contrib_head):=link(p); link(p):=null; flush_node_list(p)
+
+@ The title of this section is already so long, it seems best to avoid
+making it more accurate but still longer, by mentioning the fact that a
+kern node at the end of the contribution list will not be contributed until
+we know its successor.
+
+@<If the current page is empty...@>=
+case type(p) of
+hlist_node,vlist_node,dir_node,rule_node: if page_contents<box_there then
+    @<Initialize the current page, insert the \.{\\topskip} glue
+      ahead of |p|, and |goto continue|@>
+  else @<Prepare to move a box or rule node to the current page,
+    then |goto contribute|@>;
+whatsit_node: @<Prepare to move whatsit |p| to the current page,
+  then |goto contribute|@>;
+glue_node: if page_contents<box_there then goto done1
+  else if precedes_break(page_tail) then pi:=0
+  else goto update_heights;
+kern_node: if page_contents<box_there then goto done1
+  else if link(p)=null then return
+  else if type(link(p))=glue_node then pi:=0
+  else goto update_heights;
+penalty_node: if page_contents<box_there then goto done1@+else pi:=penalty(p);
+mark_node: goto contribute;
+ins_node: @<Append an insertion to the current page and |goto contribute|@>;
+othercases confusion("page")
+@:this can't happen page}{\quad page@>
+endcases
+
+@ @<Initialize the current page, insert the \.{\\topskip} glue...@>=
+begin if page_contents=empty then freeze_page_specs(box_there)
+else page_contents:=box_there;
+q:=new_skip_param(top_skip_code); {now |temp_ptr=glue_ptr(q)|}
+if width(temp_ptr)>height(p) then width(temp_ptr):=width(temp_ptr)-height(p)
+else width(temp_ptr):=0;
+link(q):=p; link(contrib_head):=q; goto continue;
+end
+
+@ @<Prepare to move a box or rule node to the current page...@>=
+begin page_total:=page_total+page_depth+height(p);
+page_depth:=depth(p);
+goto contribute;
+end
+
+@ @<Make sure that |page_max_depth| is not exceeded@>=
+if page_depth>page_max_depth then
+  begin page_total:=@|
+    page_total+page_depth-page_max_depth;@/
+  page_depth:=page_max_depth;
+  end;
+
+@ @<Update the current page measurements with respect to the glue...@>=
+if type(p)=kern_node then q:=p
+else begin q:=glue_ptr(p);
+  page_so_far[2+stretch_order(q)]:=@|
+    page_so_far[2+stretch_order(q)]+stretch(q);@/
+  page_shrink:=page_shrink+shrink(q);
+  if (shrink_order(q)<>normal)and(shrink(q)<>0) then
+    begin@t@>@;@/
+    print_err("Infinite glue shrinkage found on current page");@/
+@.Infinite glue shrinkage...@>
+    help4("The page about to be output contains some infinitely")@/
+      ("shrinkable glue, e.g., `\vss' or `\vskip 0pt minus 1fil'.")@/
+      ("Such glue doesn't belong there; but you can safely proceed,")@/
+      ("since the offensive shrinkability has been made finite.");
+    error;
+    r:=new_spec(q); shrink_order(r):=normal; delete_glue_ref(q);
+    glue_ptr(p):=r; q:=r;
+    end;
+  end;
+page_total:=page_total+page_depth+width(q); page_depth:=0
+
+@ @<Check if node |p| is a new champion breakpoint; then \(if)...@>=
+if pi<inf_penalty then
+  begin @<Compute the badness, |b|, of the current page,
+    using |awful_bad| if the box is too full@>;
+  if b<awful_bad then
+    if pi<=eject_penalty then c:=pi
+    else  if b<inf_bad then c:=b+pi+insert_penalties
+      else c:=deplorable
+  else c:=b;
+  if insert_penalties>=10000 then c:=awful_bad;
+  @!stat if tracing_pages>0 then @<Display the page break cost@>;@+tats@;@/
+  if c<=least_page_cost then
+    begin best_page_break:=p; best_size:=page_goal;
+    least_page_cost:=c;
+    r:=link(page_ins_head);
+    while r<>page_ins_head do
+      begin best_ins_ptr(r):=last_ins_ptr(r);
+      r:=link(r);
+      end;
+    end;
+  if (c=awful_bad)or(pi<=eject_penalty) then
+    begin fire_up(p); {output the current page at the best place}
+    if output_active then return; {user's output routine will act}
+    goto done; {the page has been shipped out by default output routine}
+    end;
+  end
+
+@ @<Display the page break cost@>=
+begin begin_diagnostic; print_nl("%");
+print(" t="); print_totals;@/
+print(" g="); print_scaled(page_goal);@/
+print(" b=");
+if b=awful_bad then print_char("*")@+else print_int(b);
+@.*\relax@>
+print(" p="); print_int(pi);
+print(" c=");
+if c=awful_bad then print_char("*")@+else print_int(c);
+if c<=least_page_cost then print_char("#");
+end_diagnostic(false);
+end
+
+@ @<Compute the badness, |b|, of the current page...@>=
+if page_total<page_goal then
+  if (page_so_far[3]<>0) or (page_so_far[4]<>0) or@|
+    (page_so_far[5]<>0) then b:=0
+  else b:=badness(page_goal-page_total,page_so_far[2])
+else if page_total-page_goal>page_shrink then b:=awful_bad
+else b:=badness(page_total-page_goal,page_shrink)
+
+@ @<Append an insertion to the current page and |goto contribute|@>=
+begin if page_contents=empty then freeze_page_specs(inserts_only);
+n:=subtype(p); r:=page_ins_head;
+while n>=subtype(link(r)) do r:=link(r);
+n:=qo(n);
+if subtype(r)<>qi(n) then
+  @<Create a page insertion node with |subtype(r)=qi(n)|, and
+    include the glue correction for box |n| in the
+    current page state@>;
+if type(r)=split_up then insert_penalties:=insert_penalties+float_cost(p)
+else  begin last_ins_ptr(r):=p;
+  delta:=page_goal-page_total-page_depth+page_shrink;
+    {this much room is left if we shrink the maximum}
+  if count(n)=1000 then h:=height(p)
+  else h:=x_over_n(height(p),1000)*count(n); {this much room is needed}
+  if ((h<=0)or(h<=delta))and(height(p)+height(r)<=dimen(n)) then
+    begin page_goal:=page_goal-h; height(r):=height(r)+height(p);
+    end
+  else @<Find the best way to split the insertion, and change
+    |type(r)| to |split_up|@>;
+  end;
+goto contribute;
+end
+
+@ We take note of the value of \.{\\skip} |n| and the height plus depth
+of \.{\\box}~|n| only when the first \.{\\insert}~|n| node is
+encountered for a new page. A user who changes the contents of \.{\\box}~|n|
+after that first \.{\\insert}~|n| had better be either extremely careful
+or extremely lucky, or both.
+
+@<Create a page insertion node...@>=
+begin q:=get_node(page_ins_node_size); link(q):=link(r); link(r):=q; r:=q;
+subtype(r):=qi(n); type(r):=inserting; ensure_vbox(n);
+if box(n)=null then height(r):=0
+else
+  begin if ins_dir(p)<>box_dir(box(n)) then
+    begin print_err("Insertions can only be added to a same direction vbox");
+@.Insertions can only...@>
+    help3("Tut tut: You're trying to \insert into a")@/
+      ("\box register that now have a different direction.")@/
+      ("Proceed, and I'll discard its present contents.");
+    box_error(n)
+    end
+  else
+    height(r):=height(box(n))+depth(box(n));
+  end;
+best_ins_ptr(r):=null;@/
+q:=skip(n);
+if count(n)=1000 then h:=height(r)
+else h:=x_over_n(height(r),1000)*count(n);
+page_goal:=page_goal-h-width(q);@/
+page_so_far[2+stretch_order(q)]:=@|page_so_far[2+stretch_order(q)]+stretch(q);@/
+page_shrink:=page_shrink+shrink(q);
+if (shrink_order(q)<>normal)and(shrink(q)<>0) then
+  begin print_err("Infinite glue shrinkage inserted from "); print_esc("skip");
+@.Infinite glue shrinkage...@>
+  print_int(n);
+  help3("The correction glue for page breaking with insertions")@/
+    ("must have finite shrinkability. But you may proceed,")@/
+    ("since the offensive shrinkability has been made finite.");
+  error;
+  end;
+end
+
+@ Here is the code that will split a long footnote between pages, in an
+emergency. The current situation deserves to be recapitulated: Node |p|
+is an insertion into box |n|; the insertion will not fit, in its entirety,
+either because it would make the total contents of box |n| greater than
+\.{\\dimen} |n|, or because it would make the incremental amount of growth
+|h| greater than the available space |delta|, or both. (This amount |h| has
+been weighted by the insertion scaling factor, i.e., by \.{\\count} |n|
+over 1000.) Now we will choose the best way to break the vlist of the
+insertion, using the same criteria as in the \.{\\vsplit} operation.
+
+@<Find the best way to split the insertion...@>=
+begin if count(n)<=0 then w:=max_dimen
+else  begin w:=page_goal-page_total-page_depth;
+  if count(n)<>1000 then w:=x_over_n(w,count(n))*1000;
+  end;
+if w>dimen(n)-height(r) then w:=dimen(n)-height(r);
+q:=vert_break(ins_ptr(p),w,depth(p));
+height(r):=height(r)+best_height_plus_depth;
+@!stat if tracing_pages>0 then @<Display the insertion split cost@>;@+tats@;@/
+if count(n)<>1000 then
+  best_height_plus_depth:=x_over_n(best_height_plus_depth,1000)*count(n);
+page_goal:=page_goal-best_height_plus_depth;
+type(r):=split_up; broken_ptr(r):=q; broken_ins(r):=p;
+if q=null then insert_penalties:=insert_penalties+eject_penalty
+else if type(q)=penalty_node then insert_penalties:=insert_penalties+penalty(q);
+end
+
+@ @<Display the insertion split cost@>=
+begin begin_diagnostic; print_nl("% split"); print_int(n);
+@.split@>
+print(" to "); print_scaled(w);
+print_char(","); print_scaled(best_height_plus_depth);@/
+print(" p=");
+if q=null then print_int(eject_penalty)
+else if type(q)=penalty_node then print_int(penalty(q))
+else print_char("0");
+end_diagnostic(false);
+end
+
+@ When the page builder has looked at as much material as could appear before
+the next page break, it makes its decision. The break that gave minimum
+badness will be used to put a completed ``page'' into box 255, with insertions
+appended to their other boxes.
+
+We also set the values of |top_mark|, |first_mark|, and |bot_mark|. The
+program uses the fact that |bot_mark<>null| implies |first_mark<>null|;
+it also knows that |bot_mark=null| implies |top_mark=first_mark=null|.
+
+The |fire_up| subroutine prepares to output the current page at the best
+place; then it fires up the user's output routine, if there is one,
+or it simply ships out the page. There is one parameter, |c|, which represents
+the node that was being contributed to the page when the decision to
+force an output was made.
+
+@<Declare the procedure called |fire_up|@>=
+procedure fire_up(@!c:pointer);
+label exit;
+var p,@!q,@!r,@!s:pointer; {nodes being examined and/or changed}
+@!prev_p:pointer; {predecessor of |p|}
+@!n:min_quarterword..255; {insertion box number}
+@!wait:boolean; {should the present insertion be held over?}
+@!save_vbadness:integer; {saved value of |vbadness|}
+@!save_vfuzz: scaled; {saved value of |vfuzz|}
+@!save_split_top_skip: pointer; {saved value of |split_top_skip|}
+begin @<Set the value of |output_penalty|@>;
+if bot_mark<>null then
+  begin if top_mark<>null then delete_token_ref(top_mark);
+  top_mark:=bot_mark; add_token_ref(top_mark);
+  delete_token_ref(first_mark); first_mark:=null;
+  end;
+@<Put the \(o)optimal current page into box 255, update |first_mark| and
+  |bot_mark|, append insertions to their boxes, and put the
+  remaining nodes back on the contribution list@>;
+if (top_mark<>null)and(first_mark=null) then
+  begin first_mark:=top_mark; add_token_ref(top_mark);
+  end;
+if output_routine<>null then
+  if dead_cycles>=max_dead_cycles then
+    @<Explain that too many dead cycles have occurred in a row@>
+  else @<Fire up the user's output routine and |return|@>;
+@<Perform the default output routine@>;
+exit:end;
+
+@ @<Set the value of |output_penalty|@>=
+if type(best_page_break)=penalty_node then
+  begin geq_word_define(int_base+output_penalty_code,penalty(best_page_break));
+  penalty(best_page_break):=inf_penalty;
+  end
+else geq_word_define(int_base+output_penalty_code,inf_penalty)
+
+@ As the page is finally being prepared for output,
+pointer |p| runs through the vlist, with |prev_p| trailing behind;
+pointer |q| is the tail of a list of insertions that
+are being held over for a subsequent page.
+
+@<Put the \(o)optimal current page into box 255...@>=
+if c=best_page_break then best_page_break:=null; {|c| not yet linked in}
+@<Ensure that box 255 is empty before output@>;
+insert_penalties:=0; {this will count the number of insertions held over}
+save_split_top_skip:=split_top_skip;
+if holding_inserts<=0 then
+  @<Prepare all the boxes involved in insertions to act as queues@>;
+q:=hold_head; link(q):=null; prev_p:=page_head; p:=link(prev_p);
+while p<>best_page_break do
+  begin if type(p)=ins_node then
+    begin if holding_inserts<=0 then
+       @<Either insert the material specified by node |p| into the
+         appropriate box, or hold it for the next page;
+         also delete node |p| from the current page@>;
+    end
+  else if type(p)=mark_node then @<Update the values of
+    |first_mark| and |bot_mark|@>;
+  prev_p:=p; p:=link(prev_p);
+  end;
+split_top_skip:=save_split_top_skip;
+@<Break the current page at node |p|, put it in box~255,
+  and put the remaining nodes on the contribution list@>;
+@<Delete \(t)the page-insertion nodes@>
+
+@ @<Ensure that box 255 is empty before output@>=
+if box(255)<>null then
+  begin print_err(""); print_esc("box"); print("255 is not void");
+@:box255}{\.{\\box255 is not void}@>
+  help2("You shouldn't use \box255 except in \output routines.")@/
+    ("Proceed, and I'll discard its present contents.");
+  box_error(255);
+  end
+
+@ @<Update the values of |first_mark| and |bot_mark|@>=
+begin if first_mark=null then
+  begin first_mark:=mark_ptr(p);
+  add_token_ref(first_mark);
+  end;
+if bot_mark<>null then delete_token_ref(bot_mark);
+bot_mark:=mark_ptr(p); add_token_ref(bot_mark);
+end
+
+@ When the following code is executed, the current page runs from node
+|link(page_head)| to node |prev_p|, and the nodes from |p| to |page_tail|
+are to be placed back at the front of the contribution list. Furthermore
+the heldover insertions appear in a list from |link(hold_head)| to |q|; we
+will put them into the current page list for safekeeping while the user's
+output routine is active.  We might have |q=hold_head|; and |p=null| if
+and only if |prev_p=page_tail|. Error messages are suppressed within
+|vpackage|, since the box might appear to be overfull or underfull simply
+because the stretch and shrink from the \.{\\skip} registers for inserts
+are not actually present in the box.
+
+@<Break the current page at node |p|, put it...@>=
+if p<>null then
+  begin if link(contrib_head)=null then
+    if nest_ptr=0 then tail:=page_tail
+    else contrib_tail:=page_tail;
+  link(page_tail):=link(contrib_head);
+  link(contrib_head):=p;
+  link(prev_p):=null;
+  end;
+save_vbadness:=vbadness; vbadness:=inf_bad;
+save_vfuzz:=vfuzz; vfuzz:=max_dimen; {inhibit error messages}
+box(255):=vpackage(link(page_head),best_size,exactly,page_max_depth);
+set_box_dir(box(255))(page_dir);
+vbadness:=save_vbadness; vfuzz:=save_vfuzz;
+if last_glue<>max_halfword then delete_glue_ref(last_glue);
+@<Start a new current page@>; {this sets |last_glue:=max_halfword|}
+if q<>hold_head then
+  begin link(page_head):=link(hold_head); page_tail:=q;
+  end
+
+@ If many insertions are supposed to go into the same box, we want to know
+the position of the last node in that box, so that we don't need to waste time
+when linking further information into it. The |last_ins_ptr| fields of the
+page insertion nodes are therefore used for this purpose during the
+packaging phase.
+
+@<Prepare all the boxes involved in insertions to act as queues@>=
+begin r:=link(page_ins_head);
+while r<>page_ins_head do
+  begin if best_ins_ptr(r)<>null then
+    begin n:=qo(subtype(r)); ensure_vbox(n);
+    if box(n)=null then box(n):=new_null_box;
+    p:=box(n)+list_offset;
+    while link(p)<>null do p:=link(p);
+    last_ins_ptr(r):=p;
+    end;
+  r:=link(r);
+  end;
+end
+
+@ @<Delete \(t)the page-insertion nodes@>=
+r:=link(page_ins_head);
+while r<>page_ins_head do
+  begin q:=link(r); free_node(r,page_ins_node_size); r:=q;
+  end;
+link(page_ins_head):=page_ins_head
+
+@ We will set |best_ins_ptr:=null| and package the box corresponding to
+insertion node~|r|, just after making the final insertion into that box.
+If this final insertion is `|split_up|', the remainder after splitting
+and pruning (if any) will be carried over to the next page.
+
+@<Either insert the material specified by node |p| into...@>=
+begin r:=link(page_ins_head);
+while subtype(r)<>subtype(p) do r:=link(r);
+if best_ins_ptr(r)=null then wait:=true
+else  begin wait:=false;
+  n:=qo(subtype(p));
+  case box_dir(box(n)) of
+    any_dir:
+      if ins_dir(p)<>box_dir(box(n)) then begin
+        print_err("Insertions can only be added to a same direction vbox");
+@.Insertions can only...@>
+        help3("Tut tut: You're trying to \insert into a")@/
+          ("\box register that now have a different direction.")@/
+          ("Proceed, and I'll discard its present contents.");
+        box_error(n);
+        box(n):=new_null_box; last_ins_ptr(r):=box(n)+list_offset;
+      end;
+    othercases
+      set_box_dir(box(n))(ins_dir(p));
+  endcases;
+  s:=last_ins_ptr(r); link(s):=ins_ptr(p);
+  if best_ins_ptr(r)=p then
+    @<Wrap up the box specified by node |r|, splitting node |p| if
+    called for; set |wait:=true| if node |p| holds a remainder after
+    splitting@>
+  else  begin while link(s)<>null do s:=link(s);
+    last_ins_ptr(r):=s;
+    end;
+  end;
+@<Either append the insertion node |p| after node |q|, and remove it
+  from the current page, or delete |node(p)|@>;
+end
+
+@ @<Wrap up the box specified by node |r|, splitting node |p| if...@>=
+begin if type(r)=split_up then
+  if (broken_ins(r)=p)and(broken_ptr(r)<>null) then
+    begin while link(s)<>broken_ptr(r) do s:=link(s);
+    link(s):=null;
+    split_top_skip:=split_top_ptr(p);
+    ins_ptr(p):=prune_page_top(broken_ptr(r));
+    if ins_ptr(p)<>null then
+      begin temp_ptr:=vpack(ins_ptr(p),natural);
+      height(p):=height(temp_ptr)+depth(temp_ptr);
+      delete_glue_ref(space_ptr(temp_ptr));
+      delete_glue_ref(xspace_ptr(temp_ptr));
+      free_node(temp_ptr,box_node_size); wait:=true;
+      end;
+    end;
+best_ins_ptr(r):=null;
+n:=qo(subtype(r));
+temp_ptr:=list_ptr(box(n));
+delete_glue_ref(space_ptr(box(n)));
+delete_glue_ref(xspace_ptr(box(n)));
+flush_node_list(link(box(n)));
+free_node(box(n),box_node_size);
+box(n):=vpack(temp_ptr,natural); set_box_dir(box(n))(ins_dir(p));
+end
+
+@ @<Either append the insertion node |p|...@>=
+link(prev_p):=link(p); link(p):=null;
+if wait then
+  begin link(q):=p; q:=p; incr(insert_penalties);
+  end
+else  begin delete_glue_ref(split_top_ptr(p));
+  free_node(p,ins_node_size);
+  end;
+p:=prev_p
+
+@ The list of heldover insertions, running from |link(page_head)| to
+|page_tail|, must be moved to the contribution list when the user has
+specified no output routine.
+
+@<Perform the default output routine@>=
+begin if link(page_head)<>null then
+  begin if link(contrib_head)=null then
+    if nest_ptr=0 then tail:=page_tail@+else contrib_tail:=page_tail
+  else link(page_tail):=link(contrib_head);
+  link(contrib_head):=link(page_head);
+  link(page_head):=null; page_tail:=page_head;
+  end;
+ship_out(box(255)); box(255):=null;
+end
+
+@ @<Explain that too many dead cycles have occurred in a row@>=
+begin print_err("Output loop---"); print_int(dead_cycles);
+@.Output loop...@>
+print(" consecutive dead cycles");
+help3("I've concluded that your \output is awry; it never does a")@/
+("\shipout, so I'm shipping \box255 out myself. Next time")@/
+("increase \maxdeadcycles if you want me to be more patient!"); error;
+end
+
+@ @<Fire up the user's output routine and |return|@>=
+begin output_active:=true;
+incr(dead_cycles);
+push_nest; mode:=-vmode; prev_depth:=ignore_depth; mode_line:=-line;
+begin_token_list(output_routine,output_text);
+new_save_level(output_group); normal_paragraph;
+scan_left_brace;
+return;
+end
+
+@ When the user's output routine finishes, it has constructed a vlist
+in internal vertical mode, and \TeX\ will do the following:
+
+@<Resume the page builder after an output routine has come to an end@>=
+begin if (loc<>null) or
+ ((token_type<>output_text)and(token_type<>backed_up)) then
+  @<Recover from an unbalanced output routine@>;
+end_token_list; {conserve stack space in case more outputs are triggered}
+end_graf; unsave; output_active:=false; insert_penalties:=0;@/
+@<Ensure that box 255 is empty after output@>;
+if tail<>head then {current list goes after heldover insertions}
+  begin link(page_tail):=link(head);
+  page_tail:=tail;
+  end;
+if link(page_head)<>null then {and both go before heldover contributions}
+  begin if link(contrib_head)=null then contrib_tail:=page_tail;
+  link(page_tail):=link(contrib_head);
+  link(contrib_head):=link(page_head);
+  link(page_head):=null; page_tail:=page_head;
+  end;
+pop_nest; build_page;
+end
+
+@ @<Recover from an unbalanced output routine@>=
+begin print_err("Unbalanced output routine");
+@.Unbalanced output routine@>
+help2("Your sneaky output routine has problematic {'s and/or }'s.")@/
+("I can't handle that very well; good luck."); error;
+repeat get_token;
+until loc=null;
+end {loops forever if reading from a file, since |null=min_halfword<=0|}
+
+@ @<Ensure that box 255 is empty after output@>=
+if box(255)<>null then
+  begin print_err("Output routine didn't use all of ");
+  print_esc("box"); print_int(255);
+@.Output routine didn't use...@>
+  help3("Your \output commands should empty \box255,")@/
+    ("e.g., by saying `\shipout\box255'.")@/
+    ("Proceed; I'll discard its present contents.");
+  box_error(255);
+  end
+
+@* \[46] The chief executive.
+We come now to the |main_control| routine, which contains the master
+switch that causes all the various pieces of \TeX\ to do their things,
+in the right order.
+
+In a sense, this is the grand climax of the program: It applies all the
+tools that we have worked so hard to construct. In another sense, this is
+the messiest part of the program: It necessarily refers to other pieces
+of code all over the place, so that a person can't fully understand what is
+going on without paging back and forth to be reminded of conventions that
+are defined elsewhere. We are now at the hub of the web, the central nervous
+system that touches most of the other parts and ties them together.
+@^brain@>
+
+The structure of |main_control| itself is quite simple. There's a label
+called |big_switch|, at which point the next token of input is fetched
+using |get_x_token|. Then the program branches at high speed into one of
+about 100 possible directions, based on the value of the current
+mode and the newly fetched command code; the sum |abs(mode)+cur_cmd|
+indicates what to do next. For example, the case `|vmode+letter|' arises
+when a letter occurs in vertical mode (or internal vertical mode); this
+case leads to instructions that initialize a new paragraph and enter
+horizontal mode.
+
+The big |case| statement that contains this multiway switch has been labeled
+|reswitch|, so that the program can |goto reswitch| when the next token
+has already been fetched. Most of the cases are quite short; they call
+an ``action procedure'' that does the work for that case, and then they
+either |goto reswitch| or they ``fall through'' to the end of the |case|
+statement, which returns control back to |big_switch|. Thus, |main_control|
+is not an extremely large procedure, in spite of the multiplicity of things
+it must do; it is small enough to be handled by \PASCAL\ compilers that put
+severe restrictions on procedure size.
+@!@^action procedure@>
+
+One case is singled out for special treatment, because it accounts for most
+of \TeX's activities in typical applications. The process of reading simple
+text and converting it into |char_node| records, while looking for ligatures
+and kerns, is part of \TeX's ``inner loop''; the whole program runs
+efficiently when its inner loop is fast, so this part has been written
+with particular care.
+
+@ We shall concentrate first on the inner loop of |main_control|, deferring
+consideration of the other cases until later.
+@^inner loop@>
+
+@d big_switch=60 {go here to branch on the next token of input}
+@d main_loop=70 {go here to typeset a string of consecutive characters}
+@d main_loop_wrapup=80 {go here to finish a character or ligature}
+@d main_loop_move=90 {go here to advance the ligature cursor}
+@d main_loop_move_lig=95 {same, when advancing past a generated ligature}
+@d main_loop_lookahead=100 {go here to bring in another character, if any}
+@d main_lig_loop=110 {go here to check for ligatures or kerning}
+@d append_normal_space=120 {go here to append a normal space between words}
+@d main_loop_j=130 {like |main_loop|, but |cur_chr| holds a KANJI code}
+@d skip_loop=141
+@d again_2=150
+
+@p @t\4@>@<Declare action procedures for use by |main_control|@>@;
+@t\4@>@<Declare the procedure called |handle_right_brace|@>@;
+procedure main_control; {governs \TeX's activities}
+label big_switch,reswitch,main_loop,main_loop_wrapup,
+  main_loop_j,main_loop_j+1,main_loop_j+3,skip_loop,again_2,
+  main_loop_move,main_loop_move+1,main_loop_move+2,main_loop_move_lig,
+  main_loop_lookahead,main_loop_lookahead+1,
+  main_lig_loop,main_lig_loop+1,main_lig_loop+2,
+  append_normal_space,exit;
+var@!t:integer; {general-purpose temporary variable}
+@!cx:KANJI_code; {kanji character}
+@!kp:pointer; {kinsoku penalty register}
+@!gp,gq:pointer; {temporary registers for list manipulation}
+@!disp:scaled; {displacement register}
+@!ins_kp:boolean; {whether insert kinsoku penalty}
+begin if every_job<>null then begin_token_list(every_job,every_job_text);
+big_switch: get_x_token;@/
+reswitch: @<Give diagnostic information, if requested@>;
+ins_kp:=false;
+case abs(mode)+cur_cmd of
+hmode+letter,hmode+other_char: goto main_loop;
+hmode+kanji,hmode+kana,hmode+other_kchar: goto main_loop_j;
+hmode+char_given:
+  if is_char_ascii(cur_chr) then goto main_loop else goto main_loop_j;
+hmode+char_num: begin scan_char_num; cur_chr:=cur_val;
+  if is_char_ascii(cur_chr) then goto main_loop else goto main_loop_j;
+  end;
+hmode+no_boundary: begin get_x_token;
+  if (cur_cmd=letter)or(cur_cmd=other_char)or
+   (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar)or
+   (cur_cmd=char_given)or(cur_cmd=char_num) then cancel_boundary:=true;
+  goto reswitch;
+  end;
+hmode+spacer: if space_factor=1000 then goto append_normal_space
+  else app_space;
+hmode+ex_space,mmode+ex_space: goto append_normal_space;
+@t\4@>@<Cases of |main_control| that are not part of the inner loop@>@;
+end; {of the big |case| statement}
+goto big_switch;
+main_loop_j:@<Append KANJI-character |cur_chr|
+  to the current hlist in the current font; |goto reswitch| when
+  a non-character has been fetched@>;
+main_loop: inhibit_glue_flag:=false;
+@<Append character |cur_chr| and the following characters (if~any)
+  to the current hlist in the current font; |goto reswitch| when
+  a non-character has been fetched@>;
+append_normal_space:@<Append a normal inter-word space to the current list,
+  then |goto big_switch|@>;
+exit:end;
+
+@ When a new token has just been fetched at |big_switch|, we have an
+ideal place to monitor \TeX's activity.
+@^debugging@>
+
+@<Give diagnostic information, if requested@>=
+if interrupt<>0 then if OK_to_interrupt then
+  begin back_input; check_interrupt; goto big_switch;
+  end;
+@!debug if panicking then check_mem(false);@+@;@+gubed
+if tracing_commands>0 then show_cur_cmd_chr
+
+@ The following part of the program was first written in a structured
+manner, according to the philosophy that ``premature optimization is
+the root of all evil.'' Then it was rearranged into pieces of
+spaghetti so that the most common actions could proceed with little or
+no redundancy.
+
+The original unoptimized form of this algorithm resembles the
+|reconstitute| procedure, which was described earlier in connection with
+hyphenation. Again we have an implied ``cursor'' between characters
+|cur_l| and |cur_r|. The main difference is that the |lig_stack| can now
+contain a charnode as well as pseudo-ligatures; that stack is now
+usually nonempty, because the next character of input (if any) has been
+appended to it. In |main_control| we have
+$$|cur_r|=\cases{|character(lig_stack)|,&if |lig_stack>null|;\cr
+  |font_bchar[cur_font]|,&otherwise;\cr}$$
+except when |character(lig_stack)=font_false_bchar[cur_font]|.
+Several additional global variables are needed.
+
+@<Glob...@>=
+@!main_f:internal_font_number; {the current font}
+@!main_i:four_quarters; {character information bytes for |cur_l|}
+@!main_j:four_quarters; {ligature/kern command}
+@!main_k:font_index; {index into |font_info|}
+@!main_p:pointer; {temporary register for list manipulation}
+@!main_s:integer; {space factor value}
+@!bchar:halfword; {right boundary character of current font, or |non_char|}
+@!false_bchar:halfword; {nonexistent character matching |bchar|, or |non_char|}
+@!cancel_boundary:boolean; {should the left boundary be ignored?}
+@!ins_disc:boolean; {should we insert a discretionary node?}
+
+@ The boolean variables of the main loop are normally false, and always reset
+to false before the loop is left. That saves us the extra work of initializing
+each time.
+
+@<Set init...@>=
+ligature_present:=false; cancel_boundary:=false; lft_hit:=false; rt_hit:=false;
+ins_disc:=false;
+
+@ We leave the |space_factor| unchanged if |sf_code(cur_chr)=0|; otherwise we
+set it equal to |sf_code(cur_chr)|, except that it should never change
+from a value less than 1000 to a value exceeding 1000. The most common
+case is |sf_code(cur_chr)=1000|, so we want that case to be fast.
+
+The overall structure of the main loop is presented here. Some program labels
+are inside the individual sections.
+
+@d adjust_space_factor==@t@>@;@/
+  main_s:=sf_code(cur_chr);
+  if main_s=1000 then space_factor:=1000
+  else if main_s<1000 then
+    begin if main_s>0 then space_factor:=main_s;
+    end
+  else if space_factor<1000 then space_factor:=1000
+  else space_factor:=main_s
+
+@<Append character |cur_chr|...@>=
+if ((head=tail) and (mode>0)) then begin
+  if (insert_src_special_auto) then append_src_special;
+end;
+adjust_space_factor;@/
+if direction=dir_tate then disp:=t_baseline_shift else disp:=y_baseline_shift;
+@<Append |disp_node| at begin of displace area@>;
+main_f:=cur_font;
+bchar:=font_bchar[main_f]; false_bchar:=font_false_bchar[main_f];
+if mode>0 then if language<>clang then fix_language;
+fast_get_avail(lig_stack); font(lig_stack):=main_f; cur_l:=qi(cur_chr);
+character(lig_stack):=cur_l;@/
+cur_q:=tail;
+if cancel_boundary then
+  begin cancel_boundary:=false; main_k:=non_address;
+  end
+else main_k:=bchar_label[main_f];
+if main_k=non_address then goto main_loop_move+2; {no left boundary processing}
+cur_r:=cur_l; cur_l:=non_char;
+goto main_lig_loop+1; {begin with cursor after left boundary}
+@#
+main_loop_wrapup:@<Make a ligature node, if |ligature_present|;
+  insert a null discretionary, if appropriate@>;
+main_loop_move:@<If the cursor is immediately followed by the right boundary,
+  |goto reswitch|; if it's followed by an invalid character, |goto big_switch|;
+  otherwise move the cursor one step to the right and |goto main_lig_loop|@>;
+main_loop_lookahead:@<Look ahead for another character, or leave |lig_stack|
+  empty if there's none there@>;
+main_lig_loop:@<If there's a ligature/kern command relevant to |cur_l| and
+  |cur_r|, adjust the text appropriately; exit to |main_loop_wrapup|@>;
+main_loop_move_lig:@<Move the cursor past a pseudo-ligature, then
+  |goto main_loop_lookahead| or |main_lig_loop|@>
+
+@ If |link(cur_q)| is nonnull when |wrapup| is invoked, |cur_q| points to
+the list of characters that were consumed while building the ligature
+character~|cur_l|.
+
+A discretionary break is not inserted for an explicit hyphen when we are in
+restricted horizontal mode. In particular, this avoids putting discretionary
+nodes inside of other discretionaries.
+
+@d pack_lig(#)== {the parameter is either |rt_hit| or |false|}
+  begin main_p:=new_ligature(main_f,cur_l,link(cur_q));
+  if lft_hit then
+    begin subtype(main_p):=2; lft_hit:=false;
+    end;
+  if # then if lig_stack=null then
+    begin incr(subtype(main_p)); rt_hit:=false;
+    end;
+  link(cur_q):=main_p; tail:=main_p; ligature_present:=false;
+  end
+
+@d wrapup(#)==if cur_l<non_char then
+  begin if link(cur_q)>null then
+    if character(tail)=qi(hyphen_char[main_f]) then ins_disc:=true;
+  if ligature_present then pack_lig(#);
+  if ins_disc then
+    begin ins_disc:=false;
+    if mode>0 then tail_append(new_disc);
+    end;
+  end
+
+@<Make a ligature node, if |ligature_present|;...@>=
+wrapup(rt_hit)
+
+@ @<If the cursor is immediately followed by the right boundary...@>=
+if lig_stack=null then
+  begin @<Append |disp_node| at end of displace area@>;
+  goto reswitch;
+  end;
+cur_q:=tail; cur_l:=character(lig_stack);
+main_loop_move+1:if not is_char_node(lig_stack) then goto main_loop_move_lig;
+main_loop_move+2:
+if(qo(effective_char(false,main_f,qi(cur_chr)))>font_ec[main_f])or
+  (qo(effective_char(false,main_f,qi(cur_chr)))<font_bc[main_f]) then
+  begin char_warning(main_f,cur_chr); free_avail(lig_stack); goto big_switch;
+  end;
+main_i:=effective_char_info(main_f,cur_l);
+if not char_exists(main_i) then
+  begin char_warning(main_f,cur_chr); free_avail(lig_stack); goto big_switch;
+  end;
+link(tail):=lig_stack; tail:=lig_stack {|main_loop_lookahead| is next}
+
+@ Here we are at |main_loop_move_lig|.
+When we begin this code we have |cur_q=tail| and |cur_l=character(lig_stack)|.
+
+@<Move the cursor past a pseudo-ligature...@>=
+main_p:=lig_ptr(lig_stack);
+if main_p>null then tail_append(main_p); {append a single character}
+temp_ptr:=lig_stack; lig_stack:=link(temp_ptr);
+free_node(temp_ptr,small_node_size);
+main_i:=char_info(main_f)(cur_l); ligature_present:=true;
+if lig_stack=null then
+  if main_p>null then goto main_loop_lookahead
+  else cur_r:=bchar
+else cur_r:=character(lig_stack);
+goto main_lig_loop
+
+@ The result of \.{\\char} can participate in a ligature or kern, so we must
+look ahead for it.
+
+@<Look ahead for another character...@>=
+get_next; {set only |cur_cmd| and |cur_chr|, for speed}
+if cur_cmd=letter then goto main_loop_lookahead+1;
+if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then
+  @<goto |main_lig_loop|@>;
+if cur_cmd=other_char then goto main_loop_lookahead+1;
+if cur_cmd=char_given then
+  begin if is_char_ascii(cur_chr) then goto main_loop_lookahead+1
+  else @<goto |main_lig_loop|@>;
+  end;
+x_token; {now expand and set |cur_cmd|, |cur_chr|, |cur_tok|}
+if cur_cmd=letter then goto main_loop_lookahead+1;
+if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then
+  @<goto |main_lig_loop|@>;
+if cur_cmd=other_char then goto main_loop_lookahead+1;
+if cur_cmd=char_given then
+  begin if is_char_ascii(cur_chr) then goto main_loop_lookahead+1
+  else @<goto |main_lig_loop|@>;
+  end;
+if cur_cmd=char_num then
+  begin scan_char_num; cur_chr:=cur_val;
+  if is_char_ascii(cur_chr) then goto main_loop_lookahead+1
+  else @<goto |main_lig_loop|@>;
+  end;
+if cur_cmd=inhibit_glue then
+  begin inhibit_glue_flag:=true; goto main_loop_lookahead;
+  end;
+if cur_cmd=no_boundary then bchar:=non_char;
+cur_r:=bchar; lig_stack:=null; goto main_lig_loop;
+main_loop_lookahead+1: adjust_space_factor;
+inhibit_glue_flag:=false;
+fast_get_avail(lig_stack); font(lig_stack):=main_f;
+cur_r:=qi(cur_chr); character(lig_stack):=cur_r;
+if cur_r=false_bchar then cur_r:=non_char {this prevents spurious ligatures}
+
+@ @<goto |main_lig_loop|@>=
+begin bchar:=non_char; cur_r:=bchar; lig_stack:=null;
+if ligature_present then pack_lig(rt_hit);
+if ins_kp=true then
+  begin cx:=cur_l; @<Insert kinsoku penalty@>;
+  end;
+ins_kp:=false;
+goto main_loop_j;
+end
+
+@ Even though comparatively few characters have a lig/kern program, several
+of the instructions here count as part of \TeX's inner loop, since a
+@^inner loop@>
+potentially long sequential search must be performed. For example, tests with
+Computer Modern Roman showed that about 40 per cent of all characters
+actually encountered in practice had a lig/kern program, and that about four
+lig/kern commands were investigated for every such character.
+
+At the beginning of this code we have |main_i=char_info(main_f)(cur_l)|.
+
+@<If there's a ligature/kern command...@>=
+if char_tag(main_i)<>lig_tag then goto main_loop_wrapup;
+if cur_r=non_char then goto main_loop_wrapup;
+main_k:=lig_kern_start(main_f)(main_i); main_j:=font_info[main_k].qqqq;
+if skip_byte(main_j)<=stop_flag then goto main_lig_loop+2;
+main_k:=lig_kern_restart(main_f)(main_j);
+main_lig_loop+1:main_j:=font_info[main_k].qqqq;
+main_lig_loop+2:if next_char(main_j)=cur_r then
+ if skip_byte(main_j)<=stop_flag then
+  @<Do ligature or kern command, returning to |main_lig_loop|
+  or |main_loop_wrapup| or |main_loop_move|@>;
+if skip_byte(main_j)=qi(0) then incr(main_k)
+else begin if skip_byte(main_j)>=stop_flag then goto main_loop_wrapup;
+  main_k:=main_k+qo(skip_byte(main_j))+1;
+  end;
+goto main_lig_loop+1
+
+@ When a ligature or kern instruction matches a character, we know from
+|read_font_info| that the character exists in the font, even though we
+haven't verified its existence in the normal way.
+
+This section could be made into a subroutine, if the code inside
+|main_control| needs to be shortened.
+
+\chardef\?='174 % vertical line to indicate character retention
+
+@<Do ligature or kern command...@>=
+begin if op_byte(main_j)>=kern_flag then
+  begin wrapup(rt_hit);
+  tail_append(new_kern(char_kern(main_f)(main_j))); goto main_loop_move;
+  end;
+if cur_l=non_char then lft_hit:=true
+else if lig_stack=null then rt_hit:=true;
+check_interrupt; {allow a way out in case there's an infinite ligature loop}
+case op_byte(main_j) of
+qi(1),qi(5):begin cur_l:=rem_byte(main_j); {\.{=:\?}, \.{=:\?>}}
+  main_i:=char_info(main_f)(cur_l); ligature_present:=true;
+  end;
+qi(2),qi(6):begin cur_r:=rem_byte(main_j); {\.{\?=:}, \.{\?=:>}}
+  if lig_stack=null then {right boundary character is being consumed}
+    begin lig_stack:=new_lig_item(cur_r); bchar:=non_char;
+    end
+  else if is_char_node(lig_stack) then {|link(lig_stack)=null|}
+    begin main_p:=lig_stack; lig_stack:=new_lig_item(cur_r);
+    lig_ptr(lig_stack):=main_p;
+    end
+  else character(lig_stack):=cur_r;
+  end;
+qi(3):begin cur_r:=rem_byte(main_j); {\.{\?=:\?}}
+  main_p:=lig_stack; lig_stack:=new_lig_item(cur_r);
+  link(lig_stack):=main_p;
+  end;
+qi(7),qi(11):begin wrapup(false); {\.{\?=:\?>}, \.{\?=:\?>>}}
+  cur_q:=tail; cur_l:=rem_byte(main_j);
+  main_i:=char_info(main_f)(cur_l); ligature_present:=true;
+  end;
+othercases begin cur_l:=rem_byte(main_j); ligature_present:=true; {\.{=:}}
+  if lig_stack=null then goto main_loop_wrapup
+  else goto main_loop_move+1;
+  end
+endcases;
+if op_byte(main_j)>qi(4) then
+  if op_byte(main_j)<>qi(7) then goto main_loop_wrapup;
+if cur_l<non_char then goto main_lig_loop;
+main_k:=bchar_label[main_f]; goto main_lig_loop+1;
+end
+
+@ The occurrence of blank spaces is almost part of \TeX's inner loop,
+@^inner loop@>
+since we usually encounter about one space for every five non-blank characters.
+Therefore |main_control| gives second-highest priority to ordinary spaces.
+
+When a glue parameter like \.{\\spaceskip} is set to `\.{0pt}', we will
+see to it later that the corresponding glue specification is precisely
+|zero_glue|, not merely a pointer to some specification that happens
+to be full of zeroes. Therefore it is simple to test whether a glue parameter
+is zero or~not.
+
+@<Append a normal inter-word space...@>=
+if space_skip=zero_glue then
+  begin @<Find the glue specification, |main_p|, for
+    text spaces in the current font@>;
+  temp_ptr:=new_glue(main_p);
+  end
+else temp_ptr:=new_param_glue(space_skip_code);
+if not is_char_node(tail)and(type(tail)=disp_node) then
+  begin link(prev_node):=temp_ptr; link(temp_ptr):=tail; prev_node:=temp_ptr;
+  end
+else begin link(tail):=temp_ptr; tail:=temp_ptr;
+  end;
+goto big_switch
+
+@ Having |font_glue| allocated for each text font saves both time and memory.
+If any of the three spacing parameters are subsequently changed by the
+use of \.{\\fontdimen}, the |find_font_dimen| procedure deallocates the
+|font_glue| specification allocated here.
+
+@<Find the glue specification...@>=
+begin main_p:=font_glue[cur_font];
+if main_p=null then
+  begin main_p:=new_spec(zero_glue); main_k:=param_base[cur_font]+space_code;
+  width(main_p):=font_info[main_k].sc; {that's |space(cur_font)|}
+  stretch(main_p):=font_info[main_k+1].sc; {and |space_stretch(cur_font)|}
+  shrink(main_p):=font_info[main_k+2].sc; {and |space_shrink(cur_font)|}
+  font_glue[cur_font]:=main_p;
+  end;
+end
+
+@ @<Declare act...@>=
+procedure app_space; {handle spaces when |space_factor<>1000|}
+var@!q:pointer; {glue node}
+begin if (space_factor>=2000)and(xspace_skip<>zero_glue) then
+  q:=new_param_glue(xspace_skip_code)
+else  begin if space_skip<>zero_glue then main_p:=space_skip
+  else @<Find the glue specification...@>;
+  main_p:=new_spec(main_p);
+  @<Modify the glue specification in |main_p| according to the space factor@>;
+  q:=new_glue(main_p); glue_ref_count(main_p):=null;
+  end;
+if not is_char_node(tail)and(type(tail)=disp_node) then
+  begin link(prev_node):=q; link(q):=tail; prev_node:=q;
+  end
+else begin link(tail):=q; tail:=q;
+  end
+end;
+
+@ @<Modify the glue specification in |main_p| according to the space factor@>=
+if space_factor>=2000 then width(main_p):=width(main_p)+extra_space(cur_font);
+stretch(main_p):=xn_over_d(stretch(main_p),space_factor,1000);
+shrink(main_p):=xn_over_d(shrink(main_p),1000,space_factor)
+
+@ Whew---that covers the main loop. We can now proceed at a leisurely
+pace through the other combinations of possibilities.
+
+@d any_mode(#)==vmode+#,hmode+#,mmode+# {for mode-independent commands}
+
+@<Cases of |main_control| that are not part of the inner loop@>=
+any_mode(relax),vmode+spacer,mmode+spacer,mmode+no_boundary:do_nothing;
+any_mode(ignore_spaces): begin @<Get the next non-blank non-call...@>;
+  goto reswitch;
+  end;
+vmode+stop: if its_all_over then return; {this is the only way out}
+@t\4@>@<Forbidden cases detected in |main_control|@>@+@,any_mode(mac_param):
+  report_illegal_case;
+@<Math-only cases in non-math modes, or vice versa@>: insert_dollar_sign;
+@t\4@>@<Cases of |main_control| that build boxes and lists@>@;
+@t\4@>@<Cases of |main_control| that don't depend on |mode|@>@;
+@t\4@>@<Cases of |main_control| that are for extensions to \TeX@>@;
+
+@ Here is a list of cases where the user has probably gotten into or out of math
+mode by mistake. \TeX\ will insert a dollar sign and rescan the current token.
+
+@d non_math(#)==vmode+#,hmode+#
+
+@<Math-only cases in non-math modes...@>=
+non_math(sup_mark), non_math(sub_mark), non_math(math_char_num),
+non_math(math_given), non_math(math_comp), non_math(delim_num),
+non_math(left_right), non_math(above), non_math(radical),
+non_math(math_style), non_math(math_choice), non_math(vcenter),
+non_math(non_script), non_math(mkern), non_math(limit_switch),
+non_math(mskip), non_math(math_accent),
+mmode+endv, mmode+par_end, mmode+stop, mmode+vskip, mmode+un_vbox,
+mmode+valign, mmode+hrule
+
+@ @<Declare action...@>=
+procedure insert_dollar_sign;
+begin back_input; cur_tok:=math_shift_token+"$";
+print_err("Missing $ inserted");
+@.Missing \$ inserted@>
+help2("I've inserted a begin-math/end-math symbol since I think")@/
+("you left one out. Proceed, with fingers crossed."); ins_error;
+end;
+
+@ When erroneous situations arise, \TeX\ usually issues an error message
+specific to the particular error. For example, `\.{\\noalign}' should
+not appear in any mode, since it is recognized by the |align_peek| routine
+in all of its legitimate appearances; a special error message is given
+when `\.{\\noalign}' occurs elsewhere. But sometimes the most appropriate
+error message is simply that the user is not allowed to do what he or she
+has attempted. For example, `\.{\\moveleft}' is allowed only in vertical mode,
+and `\.{\\lower}' only in non-vertical modes.  Such cases are enumerated
+here and in the other sections referred to under `See also \dots.'
+
+@<Forbidden cases...@>=
+vmode+vmove,hmode+hmove,mmode+hmove,any_mode(last_item),
+
+@ The `|you_cant|' procedure prints a line saying that the current command
+is illegal in the current mode; it identifies these things symbolically.
+
+@<Declare action...@>=
+procedure you_cant;
+begin print_err("You can't use `");
+@.You can't use x in y mode@>
+print_cmd_chr(cur_cmd,cur_chr);
+print_in_mode(mode);
+end;
+
+@ @<Declare act...@>=
+procedure report_illegal_case;
+begin you_cant;
+help4("Sorry, but I'm not programmed to handle this case;")@/
+("I'll just pretend that you didn't ask for it.")@/
+("If you're in the wrong mode, you might be able to")@/
+("return to the right one by typing `I}' or `I$' or `I\par'.");@/
+error;
+end;
+
+@ Some operations are allowed only in privileged modes, i.e., in cases
+that |mode>0|. The |privileged| function is used to detect violations
+of this rule; it issues an error message and returns |false| if the
+current |mode| is negative.
+
+@<Declare act...@>=
+function privileged:boolean;
+begin if mode>0 then privileged:=true
+else  begin report_illegal_case; privileged:=false;
+  end;
+end;
+
+@ Either \.{\\dump} or \.{\\end} will cause |main_control| to enter the
+endgame, since both of them have `|stop|' as their command code.
+
+@<Put each...@>=
+primitive("end",stop,0);@/
+@!@:end_}{\.{\\end} primitive@>
+primitive("dump",stop,1);@/
+@!@:dump_}{\.{\\dump} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+stop:if chr_code=1 then print_esc("dump")@+else print_esc("end");
+
+@ We don't want to leave |main_control| immediately when a |stop| command
+is sensed, because it may be necessary to invoke an \.{\\output} routine
+several times before things really grind to a halt. (The output routine
+might even say `\.{\\gdef\\end\{...\}}', to prolong the life of the job.)
+Therefore |its_all_over| is |true| only when the current page
+and contribution list are empty, and when the last output was not a
+``dead cycle.''
+
+@<Declare act...@>=
+function its_all_over:boolean; {do this when \.{\\end} or \.{\\dump} occurs}
+label exit;
+begin if privileged then
+  begin if (page_head=page_tail)and(head=tail)and(dead_cycles=0) then
+    begin its_all_over:=true; return;
+    end;
+  back_input; {we will try to end again after ejecting residual material}
+  tail_append(new_null_box);
+  width(tail):=hsize;
+  tail_append(new_glue(fill_glue));
+  tail_append(new_penalty(-@'10000000000));@/
+  build_page; {append \.{\\hbox to \\hsize\{\}\\vfill\\penalty-'10000000000}}
+  end;
+its_all_over:=false;
+exit:end;
+
+@* \[47] Building boxes and lists.
+The most important parts of |main_control| are concerned with \TeX's
+chief mission of box-making. We need to control the activities that put
+entries on vlists and hlists, as well as the activities that convert
+those lists into boxes. All of the necessary machinery has already been
+developed; it remains for us to ``push the buttons'' at the right times.
+
+@ As an introduction to these routines, let's consider one of the simplest
+cases: What happens when `\.{\\hrule}' occurs in vertical mode, or
+`\.{\\vrule}' in horizontal mode or math mode? The code in |main_control|
+is short, since the |scan_rule_spec| routine already does most of what is
+required; thus, there is no need for a special action procedure.
+
+Note that baselineskip calculations are disabled after a rule in vertical
+mode, by setting |prev_depth:=ignore_depth|.
+
+@<Cases of |main_control| that build...@>=
+vmode+hrule,hmode+vrule,mmode+vrule: begin tail_append(scan_rule_spec);
+  if abs(mode)=vmode then prev_depth:=ignore_depth
+  else if abs(mode)=hmode then space_factor:=1000;
+  end;
+
+@ The processing of things like \.{\\hskip} and \.{\\vskip} is slightly
+more complicated. But the code in |main_control| is very short, since
+it simply calls on the action routine |append_glue|. Similarly, \.{\\kern}
+activates |append_kern|.
+
+@<Cases of |main_control| that build...@>=
+vmode+vskip,hmode+hskip,mmode+hskip,mmode+mskip: append_glue;
+any_mode(kern),mmode+mkern: append_kern;
+
+@ The |hskip| and |vskip| command codes are used for control sequences
+like \.{\\hss} and \.{\\vfil} as well as for \.{\\hskip} and \.{\\vskip}.
+The difference is in the value of |cur_chr|.
+
+@d fil_code=0 {identifies \.{\\hfil} and \.{\\vfil}}
+@d fill_code=1 {identifies \.{\\hfill} and \.{\\vfill}}
+@d ss_code=2 {identifies \.{\\hss} and \.{\\vss}}
+@d fil_neg_code=3 {identifies \.{\\hfilneg} and \.{\\vfilneg}}
+@d skip_code=4 {identifies \.{\\hskip} and \.{\\vskip}}
+@d mskip_code=5 {identifies \.{\\mskip}}
+
+@<Put each...@>=
+primitive("hskip",hskip,skip_code);@/
+@!@:hskip_}{\.{\\hskip} primitive@>
+primitive("hfil",hskip,fil_code);
+@!@:hfil_}{\.{\\hfil} primitive@>
+primitive("hfill",hskip,fill_code);@/
+@!@:hfill_}{\.{\\hfill} primitive@>
+primitive("hss",hskip,ss_code);
+@!@:hss_}{\.{\\hss} primitive@>
+primitive("hfilneg",hskip,fil_neg_code);@/
+@!@:hfil_neg_}{\.{\\hfilneg} primitive@>
+primitive("vskip",vskip,skip_code);@/
+@!@:vskip_}{\.{\\vskip} primitive@>
+primitive("vfil",vskip,fil_code);
+@!@:vfil_}{\.{\\vfil} primitive@>
+primitive("vfill",vskip,fill_code);@/
+@!@:vfill_}{\.{\\vfill} primitive@>
+primitive("vss",vskip,ss_code);
+@!@:vss_}{\.{\\vss} primitive@>
+primitive("vfilneg",vskip,fil_neg_code);@/
+@!@:vfil_neg_}{\.{\\vfilneg} primitive@>
+primitive("mskip",mskip,mskip_code);@/
+@!@:mskip_}{\.{\\mskip} primitive@>
+primitive("kern",kern,explicit);
+@!@:kern_}{\.{\\kern} primitive@>
+primitive("mkern",mkern,mu_glue);@/
+@!@:mkern_}{\.{\\mkern} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+hskip: case chr_code of
+  skip_code:print_esc("hskip");
+  fil_code:print_esc("hfil");
+  fill_code:print_esc("hfill");
+  ss_code:print_esc("hss");
+  othercases print_esc("hfilneg")
+  endcases;
+vskip: case chr_code of
+  skip_code:print_esc("vskip");
+  fil_code:print_esc("vfil");
+  fill_code:print_esc("vfill");
+  ss_code:print_esc("vss");
+  othercases print_esc("vfilneg")
+  endcases;
+mskip: print_esc("mskip");
+kern: print_esc("kern");
+mkern: print_esc("mkern");
+
+@ All the work relating to glue creation has been relegated to the
+following subroutine. It does not call |build_page|, because it is
+used in at least one place where that would be a mistake.
+
+@<Declare action...@>=
+procedure append_glue;
+var s:small_number; {modifier of skip command}
+begin s:=cur_chr;
+case s of
+fil_code: cur_val:=fil_glue;
+fill_code: cur_val:=fill_glue;
+ss_code: cur_val:=ss_glue;
+fil_neg_code: cur_val:=fil_neg_glue;
+skip_code: scan_glue(glue_val);
+mskip_code: scan_glue(mu_val);
+end; {now |cur_val| points to the glue specification}
+tail_append(new_glue(cur_val));
+inhibit_glue_flag := false;
+if s>=skip_code then
+  begin decr(glue_ref_count(cur_val));
+  if s>skip_code then subtype(tail):=mu_glue;
+  end;
+end;
+
+@ @<Declare act...@>=
+procedure append_kern;
+var s:quarterword; {|subtype| of the kern node}
+begin s:=cur_chr; scan_dimen(s=mu_glue,false,false);
+inhibit_glue_flag := false;
+if not is_char_node(tail)and(type(tail)=disp_node) then
+  begin prev_append(new_kern(cur_val)); subtype(prev_node):=s;
+  end
+else
+  begin tail_append(new_kern(cur_val)); subtype(tail):=s;
+  end;
+end;
+
+@ Many of the actions related to box-making are triggered by the appearance
+of braces in the input. For example, when the user says `\.{\\hbox}
+\.{to} \.{100pt\{$\langle\,\hbox{hlist}\,\rangle$\}}' in vertical mode,
+the information about the box size (100pt, |exactly|) is put onto |save_stack|
+with a level boundary word just above it, and |cur_group:=adjusted_hbox_group|;
+\TeX\ enters restricted horizontal mode to process the hlist. The right
+brace eventually causes |save_stack| to be restored to its former state,
+at which time the information about the box size (100pt, |exactly|) is
+available once again; a box is packaged and we leave restricted horizontal
+mode, appending the new box to the current list of the enclosing mode
+(in this case to the current list of vertical mode), followed by any
+vertical adjustments that were removed from the box by |hpack|.
+
+The next few sections of the program are therefore concerned with the
+treatment of left and right curly braces.
+
+@ If a left brace occurs in the middle of a page or paragraph, it simply
+introduces a new level of grouping, and the matching right brace will not have
+such a drastic effect. Such grouping affects neither the mode nor the
+current list.
+
+@<Cases of |main_control| that build...@>=
+non_math(left_brace): new_save_level(simple_group);
+any_mode(begin_group): new_save_level(semi_simple_group);
+any_mode(end_group): if cur_group=semi_simple_group then unsave
+  else off_save;
+
+@ We have to deal with errors in which braces and such things are not
+properly nested. Sometimes the user makes an error of commission by
+inserting an extra symbol, but sometimes the user makes an error of omission.
+\TeX\ can't always tell one from the other, so it makes a guess and tries
+to avoid getting into a loop.
+
+The |off_save| routine is called when the current group code is wrong. It tries
+to insert something into the user's input that will help clean off
+the top level.
+
+@<Declare act...@>=
+procedure off_save;
+var p:pointer; {inserted token}
+begin if cur_group=bottom_level then
+  @<Drop current token and complain that it was unmatched@>
+else  begin back_input; p:=get_avail; link(temp_head):=p;
+  print_err("Missing ");
+  @<Prepare to insert a token that matches |cur_group|,
+    and print what it is@>;
+  print(" inserted"); ins_list(link(temp_head));
+  help5("I've inserted something that you may have forgotten.")@/
+  ("(See the <inserted text> above.)")@/
+  ("With luck, this will get me unwedged. But if you")@/
+  ("really didn't forget anything, try typing `2' now; then")@/
+  ("my insertion and my current dilemma will both disappear.");
+  error;
+  end;
+end;
+
+@ At this point, |link(temp_head)=p|, a pointer to an empty one-word node.
+
+@<Prepare to insert a token that matches |cur_group|...@>=
+case cur_group of
+semi_simple_group: begin info(p):=cs_token_flag+frozen_end_group;
+  print_esc("endgroup");
+@.Missing \\endgroup inserted@>
+  end;
+math_shift_group: begin info(p):=math_shift_token+"$"; print_char("$");
+@.Missing \$ inserted@>
+  end;
+math_left_group: begin info(p):=cs_token_flag+frozen_right; link(p):=get_avail;
+  p:=link(p); info(p):=other_token+"."; print_esc("right.");
+@.Missing \\right\hbox{.} inserted@>
+@^null delimiter@>
+  end;
+othercases begin info(p):=right_brace_token+"}"; print_char("}");
+@.Missing \} inserted@>
+  end
+endcases
+
+@ @<Drop current token and complain that it was unmatched@>=
+begin print_err("Extra "); print_cmd_chr(cur_cmd,cur_chr);
+@.Extra x@>
+help1("Things are pretty mixed up, but I think the worst is over.");@/
+error;
+end
+
+@ The routine for a |right_brace| character branches into many subcases,
+since a variety of things may happen, depending on |cur_group|. Some
+types of groups are not supposed to be ended by a right brace; error
+messages are given in hopes of pinpointing the problem. Most branches
+of this routine will be filled in later, when we are ready to understand
+them; meanwhile, we must prepare ourselves to deal with such errors.
+
+@<Cases of |main_control| that build...@>=
+any_mode(right_brace): handle_right_brace;
+
+@ @<Declare the procedure called |handle_right_brace|@>=
+procedure handle_right_brace;
+var p,@!q:pointer; {for short-term use}
+@!r:pointer; {temporaly}
+@!d:scaled; {holds |split_max_depth| in |insert_group|}
+@!f:integer; {holds |floating_penalty| in |insert_group|}
+begin case cur_group of
+simple_group: unsave;
+bottom_level: begin print_err("Too many }'s");
+@.Too many \}'s@>
+  help2("You've closed more groups than you opened.")@/
+  ("Such booboos are generally harmless, so keep going."); error;
+  end;
+semi_simple_group,math_shift_group,math_left_group: extra_right_brace;
+@t\4@>@<Cases of |handle_right_brace| where a |right_brace| triggers
+  a delayed action@>@;
+othercases confusion("rightbrace")
+@:this can't happen rightbrace}{\quad rightbrace@>
+endcases;
+end;
+
+@ @<Declare act...@>=
+procedure extra_right_brace;
+begin print_err("Extra }, or forgotten ");
+@.Extra \}, or forgotten x@>
+case cur_group of
+semi_simple_group: print_esc("endgroup");
+math_shift_group: print_char("$");
+math_left_group: print_esc("right");
+end;@/
+help5("I've deleted a group-closing symbol because it seems to be")@/
+("spurious, as in `$x}$'. But perhaps the } is legitimate and")@/
+("you forgot something else, as in `\hbox{$x}'. In such cases")@/
+("the way to recover is to insert both the forgotten and the")@/
+("deleted material, e.g., by typing `I$}'."); error;
+incr(align_state);
+end;
+
+@ Here is where we clear the parameters that are supposed to revert to their
+default values after every paragraph and when internal vertical mode is entered.
+
+@<Declare act...@>=
+procedure normal_paragraph;
+begin if looseness<>0 then eq_word_define(int_base+looseness_code,0);
+if hang_indent<>0 then eq_word_define(dimen_base+hang_indent_code,0);
+if hang_after<>1 then eq_word_define(int_base+hang_after_code,1);
+if par_shape_ptr<>null then eq_define(par_shape_loc,shape_ref,null);
+end;
+
+@ Now let's turn to the question of how \.{\\hbox} is treated. We actually
+need to consider also a slightly larger context, since constructions like
+`\.{\\setbox3=}\penalty0\.{\\hbox...}' and
+`\.{\\leaders}\penalty0\.{\\hbox...}' and
+`\.{\\lower3.8pt\\hbox...}'
+are supposed to invoke quite
+different actions after the box has been packaged. Conversely,
+constructions like `\.{\\setbox3=}' can be followed by a variety of
+different kinds of boxes, and we would like to encode such things in an
+efficient way.
+
+In other words, there are two problems: to represent the context of a box,
+and to represent its type.
+
+The first problem is solved by putting a ``context code'' on the |save_stack|,
+just below the two entries that give the dimensions produced by |scan_spec|.
+The context code is either a (signed) shift amount, or it is a large
+integer |>=box_flag|, where |box_flag=@t$2^{30}$@>|. Codes |box_flag| through
+|box_flag+255| represent `\.{\\setbox0}' through `\.{\\setbox255}';
+codes |box_flag+256| through |box_flag+511| represent `\.{\\global\\setbox0}'
+through `\.{\\global\\setbox255}';
+code |box_flag+512| represents `\.{\\shipout}'; and codes |box_flag+513|
+through |box_flag+515| represent `\.{\\leaders}', `\.{\\cleaders}',
+and `\.{\\xleaders}'.
+
+The second problem is solved by giving the command code |make_box| to all
+control sequences that produce a box, and by using the following |chr_code|
+values to distinguish between them: |box_code|, |copy_code|, |last_box_code|,
+|vsplit_code|, |vtop_code|, |vtop_code+vmode|, and |vtop_code+hmode|,
+where the latter two are used denote \.{\\vbox} and \.{\\hbox}, respectively.
+
+@d box_flag==@'10000000000 {context code for `\.{\\setbox0}'}
+@d ship_out_flag==box_flag+512 {context code for `\.{\\shipout}'}
+@d leader_flag==box_flag+513 {context code for `\.{\\leaders}'}
+@d box_code=0 {|chr_code| for `\.{\\box}'}
+@d copy_code=1 {|chr_code| for `\.{\\copy}'}
+@d last_box_code=2 {|chr_code| for `\.{\\lastbox}'}
+@d vsplit_code=3 {|chr_code| for `\.{\\vsplit}'}
+@d vtop_code=4 {|chr_code| for `\.{\\vtop}'}
+
+@<Put each...@>=
+primitive("moveleft",hmove,1);
+@!@:move_left_}{\.{\\moveleft} primitive@>
+primitive("moveright",hmove,0);@/
+@!@:move_right_}{\.{\\moveright} primitive@>
+primitive("raise",vmove,1);
+@!@:raise_}{\.{\\raise} primitive@>
+primitive("lower",vmove,0);
+@!@:lower_}{\.{\\lower} primitive@>
+@#
+primitive("box",make_box,box_code);
+@!@:box_}{\.{\\box} primitive@>
+primitive("copy",make_box,copy_code);
+@!@:copy_}{\.{\\copy} primitive@>
+primitive("lastbox",make_box,last_box_code);
+@!@:last_box_}{\.{\\lastbox} primitive@>
+primitive("vsplit",make_box,vsplit_code);
+@!@:vsplit_}{\.{\\vsplit} primitive@>
+primitive("vtop",make_box,vtop_code);@/
+@!@:vtop_}{\.{\\vtop} primitive@>
+primitive("vbox",make_box,vtop_code+vmode);
+@!@:vbox_}{\.{\\vbox} primitive@>
+primitive("hbox",make_box,vtop_code+hmode);@/
+@!@:hbox_}{\.{\\hbox} primitive@>
+primitive("tate",chg_dir,dir_tate);@/
+@!@:tate_}{\.{\\tate} primitive@>
+primitive("yoko",chg_dir,dir_yoko);@/
+@!@:yoko_}{\.{\\yoko} primitive@>
+primitive("dtou",chg_dir,dir_dtou);@/
+@!@:dtou_}{\.{\\dtou} primitive@>
+primitive("shipout",leader_ship,a_leaders-1); {|ship_out_flag=leader_flag-1|}
+@!@:ship_out_}{\.{\\shipout} primitive@>
+primitive("leaders",leader_ship,a_leaders);
+@!@:leaders_}{\.{\\leaders} primitive@>
+primitive("cleaders",leader_ship,c_leaders);
+@!@:c_leaders_}{\.{\\cleaders} primitive@>
+primitive("xleaders",leader_ship,x_leaders);
+@!@:x_leaders_}{\.{\\xleaders} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+hmove: if chr_code=1 then print_esc("moveleft")@+else print_esc("moveright");
+vmove: if chr_code=1 then print_esc("raise")@+else print_esc("lower");
+make_box: case chr_code of
+  box_code: print_esc("box");
+  copy_code: print_esc("copy");
+  last_box_code: print_esc("lastbox");
+  vsplit_code: print_esc("vsplit");
+  vtop_code: print_esc("vtop");
+  vtop_code+vmode: print_esc("vbox");
+  othercases print_esc("hbox")
+  endcases;
+chg_dir:
+  case chr_code of
+    dir_yoko: print_esc("yoko");
+    dir_tate: print_esc("tate");
+    dir_dtou: print_esc("dtou");
+  endcases;
+leader_ship: if chr_code=a_leaders then print_esc("leaders")
+  else if chr_code=c_leaders then print_esc("cleaders")
+  else if chr_code=x_leaders then print_esc("xleaders")
+  else print_esc("shipout");
+
+@ Constructions that require a box are started by calling |scan_box| with
+a specified context code. The |scan_box| routine verifies
+that a |make_box| command comes next and then it calls |begin_box|.
+
+@<Cases of |main_control| that build...@>=
+vmode+hmove,hmode+vmove,mmode+vmove: begin t:=cur_chr;
+  scan_normal_dimen;
+  if t=0 then scan_box(cur_val)@+else scan_box(-cur_val);
+  end;
+any_mode(leader_ship): scan_box(leader_flag-a_leaders+cur_chr);
+any_mode(make_box): begin_box(0);
+any_mode(chg_dir):
+  begin  if cur_group<>align_group then
+    if head=tail then
+      begin direction:=cur_chr;
+      if mode=vmode then page_dir:=cur_chr;
+      end
+    else begin print_err("Use `"); print_cmd_chr(cur_cmd,cur_chr);
+      print("' at top of list");
+      help2("Direction change command is available only while")
+      ("current list is null."); error;
+      end
+  else begin print_err("You can't use `"); print_cmd_chr(cur_cmd,cur_chr);
+    print("' in an align");
+    help2("To change direction in an align,")
+    ("you shold use \hbox or \vbox with \tate or \yoko."); error;
+    end
+  end;
+
+@ The global variable |cur_box| will point to a newly made box. If the box
+is void, we will have |cur_box=null|. Otherwise we will have
+|type(cur_box)=hlist_node| or |vlist_node| or |rule_node|; the |rule_node|
+case can occur only with leaders.
+
+@<Glob...@>=
+@!cur_box:pointer; {box to be placed into its context}
+
+@ The |box_end| procedure does the right thing with |cur_box|, if
+|box_context| represents the context as explained above.
+
+@<Declare act...@>=
+procedure box_end(@!box_context:integer);
+var p:pointer; {|ord_noad| for new box in math mode}
+q:pointer;
+begin if box_context<box_flag then @<Append box |cur_box| to the current list,
+    shifted by |box_context|@>
+else if box_context<ship_out_flag then @<Store \(c)|cur_box| in a box register@>
+else if cur_box<>null then
+  if box_context>ship_out_flag then @<Append a new leader node that
+      uses |cur_box|@>
+  else ship_out(cur_box);
+end;
+
+@ The global variable |adjust_tail| will be non-null if and only if the
+current box might include adjustments that should be appended to the
+current vertical list.
+
+@<Append box |cur_box| to the current...@>=
+begin if cur_box<>null then
+  begin p:=link(cur_box); link(cur_box):=null;
+  while p<>null do begin
+    q:=p; p:=link(p);
+    if box_dir(q)=abs(direction) then
+      begin list_ptr(q):=cur_box; cur_box:=q; link(cur_box):=null;
+      end
+    else begin
+      delete_glue_ref(space_ptr(q));
+      delete_glue_ref(xspace_ptr(q));
+      free_node(q,box_node_size);
+      end;
+  end;
+  if box_dir(cur_box)<>abs(direction) then
+    cur_box:=new_dir_node(cur_box,abs(direction));
+  shift_amount(cur_box):=box_context;
+  if abs(mode)=vmode then
+    begin append_to_vlist(cur_box);
+    if adjust_tail<>null then
+      begin if adjust_head<>adjust_tail then
+        begin link(tail):=link(adjust_head); tail:=adjust_tail;
+        end;
+      adjust_tail:=null;
+      end;
+    if mode>0 then build_page;
+    end
+  else  begin if abs(mode)=hmode then space_factor:=1000
+    else  begin p:=new_noad;
+      math_type(nucleus(p)):=sub_box;
+      info(nucleus(p)):=cur_box; cur_box:=p;
+      end;
+    link(tail):=cur_box; tail:=cur_box;
+    end;
+  end;
+end
+
+@ @<Store \(c)|cur_box| in a box register@>=
+if box_context<box_flag+256 then
+  eq_define(box_base-box_flag+box_context,box_ref,cur_box)
+else geq_define(box_base-box_flag-256+box_context,box_ref,cur_box)
+
+@ @<Append a new leader node ...@>=
+begin @<Get the next non-blank non-relax...@>;
+if ((cur_cmd=hskip)and(abs(mode)<>vmode))or@|
+   ((cur_cmd=vskip)and(abs(mode)=vmode)) then
+  begin append_glue; subtype(tail):=box_context-(leader_flag-a_leaders);
+  if type(cur_box)<=dir_node then
+    begin p:=link(cur_box); link(cur_box):=null;
+    while p<>null do
+      begin q:=p; p:=link(p);
+      if box_dir(q)=abs(direction) then
+        begin list_ptr(q):=cur_box; cur_box:=q; link(cur_box):=null;
+        end
+      else begin
+        delete_glue_ref(space_ptr(q));
+        delete_glue_ref(xspace_ptr(q));
+        free_node(q,box_node_size);
+        end;
+      end;
+    if box_dir(cur_box)<>abs(direction) then
+      cur_box:=new_dir_node(cur_box,abs(direction));
+    end;
+  leader_ptr(tail):=cur_box;
+  end
+else  begin print_err("Leaders not followed by proper glue");
+@.Leaders not followed by...@>
+  help3("You should say `\leaders <box or rule><hskip or vskip>'.")@/
+  ("I found the <box or rule>, but there's no suitable")@/
+  ("<hskip or vskip>, so I'm ignoring these leaders."); back_error;
+  flush_node_list(cur_box);
+  end;
+end
+
+@ Now that we can see what eventually happens to boxes, we can consider
+the first steps in their creation. The |begin_box| routine is called when
+|box_context| is a context specification, |cur_chr| specifies the type of
+box desired, and |cur_cmd=make_box|.
+
+@<Declare act...@>=
+procedure begin_box(@!box_context:integer);
+label exit, done;
+var @!p,@!q:pointer; {run through the current list}
+@!r:pointer; {running behind |p|}
+@!fd:boolean; {a final |disp_node| pair?}
+@!disp,@!pdisp:scaled; {displacement}
+@!a_dir:eight_bits; {adjust direction}
+@!tx:pointer; {effective tail node}
+@!m:quarterword; {the length of a replacement list}
+@!k:halfword; {0 or |vmode| or |hmode|}
+@!n:eight_bits; {a box number}
+begin case cur_chr of
+box_code: begin scan_eight_bit_int; cur_box:=box(cur_val);
+  box(cur_val):=null; {the box becomes void, at the same level}
+  end;
+copy_code: begin scan_eight_bit_int; cur_box:=copy_node_list(box(cur_val));
+  end;
+last_box_code: @<If the current list ends with a box node, delete it from
+  the list and make |cur_box| point to it; otherwise set |cur_box:=null|@>;
+vsplit_code: @<Split off part of a vertical box, make |cur_box| point to it@>;
+othercases @<Initiate the construction of an hbox or vbox, then |return|@>
+endcases;@/
+box_end(box_context); {in simple cases, we use the box immediately}
+exit:end;
+
+@ Note that in \TeX\ the condition |not is_char_node(tail)| implies that
+|head<>tail|, since |head| is a one-word node; this is not so for p\TeX.
+
+@d check_effective_tail_pTeX(#)==
+tx:=tail;
+if not is_char_node(tx) then
+  if type(tx)=disp_node then
+    begin tx:=prev_node;
+    if not is_char_node(tx) then
+      if type(tx)=disp_node then #; {|disp_node| from a discretionary}
+    end
+@#
+@d fetch_effective_tail_pTeX(#)== {extract |tx|, merge |disp_node| pair}
+q:=head; p:=null; disp:=0; pdisp:=0;
+repeat r:=p; p:=q; fd:=false;
+if not is_char_node(q) then
+  if type(q)=disc_node then
+    begin for m:=1 to replace_count(q) do p:=link(p);
+    if p=tx then #;
+    end
+  else if type(q)=disp_node then
+    begin pdisp:=disp; disp:=disp_dimen(q); fd:=true;@+end;
+q:=link(p);
+until q=tx; {found |r|$\to$|p|$\to$|q=tx|}
+q:=link(tx); link(p):=q; link(tx):=null;
+if q=null then tail:=p
+else if fd then {|r|$\to$|p=disp_node|$\to$|q=disp_node|}
+  begin prev_node:=r; prev_disp:=pdisp; link(p):=null; tail:=p;
+  disp_dimen(p):=disp_dimen(q); free_node(q,small_node_size);
+  end
+else prev_node:=p
+@#
+@d check_effective_tail==check_effective_tail_pTeX
+@d fetch_effective_tail==fetch_effective_tail_pTeX
+
+@<If the current list ends with a box node, delete it...@>=
+begin cur_box:=null;
+if abs(mode)=mmode then
+  begin you_cant; help1("Sorry; this \lastbox will be void."); error;
+  end
+else if (mode=vmode)and(head=tail) then
+  begin you_cant;
+  help2("Sorry...I usually can't take things from the current page.")@/
+    ("This \lastbox will therefore be void."); error;
+  end
+else  begin check_effective_tail(goto done);
+  if not is_char_node(tx)and(head<>tx) then
+    if (type(tx)=hlist_node)or(type(tx)=vlist_node)
+       or(type(tx)=dir_node) then
+      @<Remove the last box, unless it's part of a discretionary@>;
+  done:end;
+end
+
+@ @<Remove the last box...@>=
+begin fetch_effective_tail(goto done);
+cur_box:=tx; shift_amount(cur_box):=0;
+if type(cur_box)=dir_node then
+  begin link(list_ptr(cur_box)):=cur_box;
+  cur_box:=list_ptr(cur_box);
+  list_ptr(link(cur_box)):=null;
+  end
+else
+  if box_dir(cur_box)=dir_default then set_box_dir(cur_box)(abs(direction));
+end
+
+@ Here we deal with things like `\.{\\vsplit 13 to 100pt}'.
+
+@<Split off part of a vertical box, make |cur_box| point to it@>=
+begin scan_eight_bit_int; n:=cur_val;
+if not scan_keyword("to") then
+@.to@>
+  begin print_err("Missing `to' inserted");
+@.Missing `to' inserted@>
+  help2("I'm working on `\vsplit<box number> to <dimen>';")@/
+  ("will look for the <dimen> next."); error;
+  end;
+scan_normal_dimen;
+cur_box:=vsplit(n,cur_val);
+end
+
+@ Here is where we enter restricted horizontal mode or internal vertical
+mode, in order to make a box.
+
+@<Initiate the construction of an hbox or vbox, then |return|@>=
+begin k:=cur_chr-vtop_code; saved(0):=box_context;
+a_dir:=adjust_dir;
+if k=hmode then
+  if (box_context<box_flag)and(abs(mode)=vmode) then
+    begin a_dir:=abs(direction); scan_spec(adjusted_hbox_group,true);
+    end
+  else scan_spec(hbox_group,true)
+else  begin if k=vmode then scan_spec(vbox_group,true)
+  else  begin scan_spec(vtop_group,true); k:=vmode;
+    end;
+  normal_paragraph;
+  end;
+push_nest; mode:=-k; adjust_dir:=a_dir;
+if k=vmode then
+  begin prev_depth:=ignore_depth;
+  if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text);
+  end
+else  begin space_factor:=1000;
+  if every_hbox<>null then begin_token_list(every_hbox,every_hbox_text);
+  end;
+return;
+end
+
+@ @<Declare act...@>=
+procedure scan_box(@!box_context:integer);
+  {the next input should specify a box or perhaps a rule}
+begin @<Get the next non-blank non-relax...@>;
+if cur_cmd=make_box then begin_box(box_context)
+else if (box_context>=leader_flag)and((cur_cmd=hrule)or(cur_cmd=vrule)) then
+  begin cur_box:=scan_rule_spec; box_end(box_context);
+  end
+else  begin@t@>@;@/
+  print_err("A <box> was supposed to be here");@/
+@.A <box> was supposed to...@>
+  help3("I was expecting to see \hbox or \vbox or \copy or \box or")@/
+  ("something like that. So you might find something missing in")@/
+  ("your output. But keep trying; you can fix this later."); back_error;
+  end;
+end;
+
+@ When the right brace occurs at the end of an \.{\\hbox} or \.{\\vbox} or
+\.{\\vtop} construction, the |package| routine comes into action. We might
+also have to finish a paragraph that hasn't ended.
+
+@<Cases of |handle...@>=
+hbox_group: begin adjust_hlist(head,false); package(0);
+  end;
+adjusted_hbox_group: begin adjust_hlist(head,false);
+  adjust_tail:=adjust_head; package(0);
+  end;
+vbox_group: begin end_graf; package(0);
+  end;
+vtop_group: begin end_graf; package(vtop_code);
+  end;
+
+@ @<Declare action...@>=
+procedure package(@!c:small_number);
+var h:scaled; {height of box}
+@!p:pointer; {first node in a box}
+@!d:scaled; {max depth}
+begin d:=box_max_depth;
+  delete_glue_ref(cur_kanji_skip); delete_glue_ref(cur_xkanji_skip);
+  if auto_spacing>0 then cur_kanji_skip:=kanji_skip
+  else cur_kanji_skip:=zero_glue;
+  if auto_xspacing>0 then cur_xkanji_skip:=xkanji_skip
+  else cur_xkanji_skip:=zero_glue;
+  add_glue_ref(cur_kanji_skip); add_glue_ref(cur_xkanji_skip);
+  unsave; save_ptr:=save_ptr-3;
+  if mode=-hmode then begin
+    cur_box:=hpack(link(head),saved(2),saved(1));
+    set_box_dir(cur_box)(abs(direction)); pop_nest;
+  end else begin
+    cur_box:=vpackage(link(head),saved(2),saved(1),d);
+    set_box_dir(cur_box)(abs(direction)); pop_nest;
+    if c=vtop_code then
+      @<Readjust the height and depth of |cur_box|, for \.{\\vtop}@>;
+  end;
+  box_end(saved(0));
+end;
+
+@ The height of a `\.{\\vtop}' box is inherited from the first item on its list,
+if that item is an |hlist_node|, |vlist_node|, or |rule_node|; otherwise
+the \.{\\vtop} height is zero.
+
+
+@<Readjust the height...@>=
+begin h:=0; p:=list_ptr(cur_box);
+if p<>null then if type(p)<=rule_node then h:=height(p);
+depth(cur_box):=depth(cur_box)-h+height(cur_box); height(cur_box):=h;
+end
+
+@ A paragraph begins when horizontal-mode material occurs in vertical mode,
+or when the paragraph is explicitly started by `\.{\\indent}' or
+`\.{\\noindent}'.
+
+@<Put each...@>=
+primitive("indent",start_par,1);
+@!@:indent_}{\.{\\indent} primitive@>
+primitive("noindent",start_par,0);
+@!@:no_indent_}{\.{\\noindent} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+start_par: if chr_code=0 then print_esc("noindent")@+ else print_esc("indent");
+
+@ @<Cases of |main_control| that build...@>=
+vmode+start_par: new_graf(cur_chr>0);
+vmode+letter,vmode+other_char,vmode+char_num,vmode+char_given,
+   vmode+math_shift,vmode+un_hbox,vmode+vrule,
+   vmode+accent,vmode+discretionary,vmode+hskip,vmode+valign,
+   vmode+kanji,vmode+kana,vmode+other_kchar,
+   vmode+ex_space,vmode+no_boundary:@t@>@;@/
+  begin back_input; new_graf(true);
+  end;
+
+@ @<Declare act...@>=
+function norm_min(@!h:integer):small_number;
+begin if h<=0 then norm_min:=1@+else if h>=63 then norm_min:=63@+
+else norm_min:=h;
+end;
+@#
+procedure new_graf(@!indented:boolean);
+begin prev_graf:=0;
+if (mode=vmode)or(head<>tail) then
+  tail_append(new_param_glue(par_skip_code));
+inhibit_glue_flag := false;
+push_nest; adjust_dir:=abs(direction);
+mode:=hmode; space_factor:=1000; set_cur_lang; clang:=cur_lang;
+prev_graf:=(norm_min(left_hyphen_min)*@'100+norm_min(right_hyphen_min))
+             *@'200000+cur_lang;
+if indented then
+  begin tail:=new_null_box; link(head):=tail; width(tail):=par_indent;
+  if (insert_src_special_every_par) then insert_src_special;@+
+  end;
+if every_par<>null then begin_token_list(every_par,every_par_text);
+if nest_ptr=1 then build_page; {put |par_skip| glue on current page}
+end;
+
+@ @<Cases of |main_control| that build...@>=
+hmode+start_par,mmode+start_par: indent_in_hmode;
+
+@ @<Declare act...@>=
+procedure indent_in_hmode;
+var p,@!q:pointer;
+begin if cur_chr>0 then {\.{\\indent}}
+  begin p:=new_null_box; width(p):=par_indent;
+  if abs(mode)=hmode then space_factor:=1000
+  else  begin q:=new_noad; math_type(nucleus(q)):=sub_box;
+    info(nucleus(q)):=p; p:=q;
+    end;
+  tail_append(p);
+  end;
+end;
+
+@ A paragraph ends when a |par_end| command is sensed, or when we are in
+horizontal mode when reaching the right brace of vertical-mode routines
+like \.{\\vbox}, \.{\\insert}, or \.{\\output}.
+
+@<Cases of |main_control| that build...@>=
+vmode+par_end: begin normal_paragraph;
+  if mode>0 then build_page;
+  end;
+hmode+par_end: begin if align_state<0 then off_save; {this tries to
+    recover from an alignment that didn't end properly}
+  end_graf; {this takes us to the enclosing mode, if |mode>0|}
+  if mode=vmode then build_page;
+  end;
+hmode+stop,hmode+vskip,hmode+hrule,hmode+un_vbox,hmode+halign: head_for_vmode;
+
+@ @<Declare act...@>=
+procedure head_for_vmode;
+begin if mode<0 then
+  if cur_cmd<>hrule then off_save
+  else  begin print_err("You can't use `");
+    print_esc("hrule"); print("' here except with leaders");
+@.You can't use \\hrule...@>
+    help2("To put a horizontal rule in an hbox or an alignment,")@/
+      ("you should use \leaders or \hrulefill (see The TeXbook).");
+    error;
+    end
+else  begin back_input; cur_tok:=par_token; back_input; token_type:=inserted;
+  end;
+end;
+
+@ @<Declare act...@>=
+procedure end_graf;
+begin if mode=hmode then
+  begin if head=tail then pop_nest {null paragraphs are ignored}
+  else begin adjust_hlist(head,true); line_break(widow_penalty)
+       end;
+  normal_paragraph;
+  error_count:=0;
+  end;
+end;
+
+@ Insertion and adjustment and mark nodes are constructed by the following
+pieces of the program.
+
+@<Cases of |main_control| that build...@>=
+any_mode(insert),hmode+vadjust,mmode+vadjust: begin_insert_or_adjust;
+any_mode(mark): make_mark;
+
+@ @<Forbidden...@>=
+vmode+vadjust,
+
+@ @<Declare act...@>=
+procedure begin_insert_or_adjust;
+begin if cur_cmd=vadjust then cur_val:=255
+else  begin scan_eight_bit_int;
+  if cur_val=255 then
+    begin print_err("You can't "); print_esc("insert"); print_int(255);
+@.You can't \\insert255@>
+    help1("I'm changing to \insert0; box 255 is special.");
+    error; cur_val:=0;
+    end;
+  end;
+saved(0):=cur_val; incr(save_ptr);
+new_save_level(insert_group); scan_left_brace; normal_paragraph;
+push_nest; mode:=-vmode; direction:=adjust_dir; prev_depth:=ignore_depth;
+end;
+
+@ @<Cases of |handle...@>=
+insert_group: begin end_graf; q:=split_top_skip; add_glue_ref(q);
+  d:=split_max_depth; f:=floating_penalty; unsave; decr(save_ptr);
+  {now |saved(0)| is the insertion number, or 255 for |vadjust|}
+  p:=vpack(link(head),natural); set_box_dir(p)(abs(direction)); pop_nest;
+  if saved(0)<255 then
+    begin r:=get_node(ins_node_size);
+    type(r):=ins_node; subtype(r):=qi(saved(0));
+    height(r):=height(p)+depth(p); ins_ptr(r):=list_ptr(p);
+    split_top_ptr(r):=q; depth(r):=d; float_cost(r):=f;
+    ins_dir(r):=box_dir(p);
+    if not is_char_node(tail)and(type(tail)=disp_node) then
+      prev_append(r)
+    else tail_append(r);
+    end
+  else  begin
+    if box_dir(p)<>adjust_dir then
+      begin print_err("Direction Incompatible.");
+      help1("\vadjust's argument and outer vlist must have same direction.");
+      error; flush_node_list(list_ptr(p));
+      end
+    else  begin
+      r:=get_node(small_node_size); type(r):=adjust_node;@/
+      adjust_ptr(r):=list_ptr(p); delete_glue_ref(q);
+      if not is_char_node(tail)and(type(tail)=disp_node) then
+        prev_append(r)
+      else tail_append(r);
+      end;
+    end;
+  delete_glue_ref(space_ptr(p));
+  delete_glue_ref(xspace_ptr(p));
+  free_node(p,box_node_size);
+  if nest_ptr=0 then build_page;
+  end;
+output_group: @<Resume the page builder...@>;
+
+@ @<Declare act...@>=
+procedure make_mark;
+var p:pointer; {new node}
+begin p:=scan_toks(false,true); p:=get_node(small_node_size);
+type(p):=mark_node; subtype(p):=0; {the |subtype| is not used}
+mark_ptr(p):=def_ref;
+if not is_char_node(tail)and(type(tail)=disp_node) then
+  prev_append(p)
+else tail_append(p);
+end;
+
+@ Penalty nodes get into a list via the |break_penalty| command.
+@^penalties@>
+
+@<Cases of |main_control| that build...@>=
+any_mode(break_penalty): append_penalty;
+
+@ @<Declare action...@>=
+procedure append_penalty;
+begin scan_int;
+  if not is_char_node(tail)and(type(tail)=disp_node) then
+    prev_append(new_penalty(cur_val))
+  else tail_append(new_penalty(cur_val));
+  if mode=vmode then build_page;
+end;
+
+@ The |remove_item| command removes a penalty, kern, or glue node if it
+appears at the tail of the current list, using a brute-force linear scan.
+Like \.{\\lastbox}, this command is not allowed in vertical mode (except
+internal vertical mode), since the current list in vertical mode is sent
+to the page builder.  But if we happen to be able to implement it in
+vertical mode, we do.
+
+@<Cases of |main_control| that build...@>=
+any_mode(remove_item): delete_last;
+
+@ When |delete_last| is called, |cur_chr| is the |type| of node that
+will be deleted, if present.
+
+@<Declare action...@>=
+procedure delete_last;
+label exit;
+var @!p,@!q:pointer; {run through the current list}
+@!r:pointer; {running behind |p|}
+@!fd:boolean; {a final |disp_node| pair?}
+@!disp,@!pdisp:scaled; {displacement}
+@!tx:pointer; {effective tail node}
+@!m:quarterword; {the length of a replacement list}
+begin if (mode=vmode)and(tail=head) then
+  @<Apologize for inability to do the operation now,
+    unless \.{\\unskip} follows non-glue@>
+else  begin check_effective_tail(return);
+  if not is_char_node(tx) then if type(tx)=cur_chr then
+    begin fetch_effective_tail(return);
+    flush_node_list(tx);
+    end;
+  end;
+exit:end;
+
+@ @<Apologize for inability to do the operation...@>=
+begin if (cur_chr<>glue_node)or(last_glue<>max_halfword) then
+  begin you_cant;
+  help2("Sorry...I usually can't take things from the current page.")@/
+    ("Try `I\vskip-\lastskip' instead.");
+  if cur_chr=kern_node then help_line[0]:=
+    ("Try `I\kern-\lastkern' instead.")
+  else if cur_chr<>glue_node then help_line[0]:=@|
+    ("Perhaps you can make the output routine do it.");
+  error;
+  end;
+end
+
+@ @<Put each...@>=
+primitive("unpenalty",remove_item,penalty_node);@/
+@!@:un_penalty_}{\.{\\unpenalty} primitive@>
+primitive("unkern",remove_item,kern_node);@/
+@!@:un_kern_}{\.{\\unkern} primitive@>
+primitive("unskip",remove_item,glue_node);@/
+@!@:un_skip_}{\.{\\unskip} primitive@>
+primitive("unhbox",un_hbox,box_code);@/
+@!@:un_hbox_}{\.{\\unhbox} primitive@>
+primitive("unhcopy",un_hbox,copy_code);@/
+@!@:un_hcopy_}{\.{\\unhcopy} primitive@>
+primitive("unvbox",un_vbox,box_code);@/
+@!@:un_vbox_}{\.{\\unvbox} primitive@>
+primitive("unvcopy",un_vbox,copy_code);@/
+@!@:un_vcopy_}{\.{\\unvcopy} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+remove_item: if chr_code=glue_node then print_esc("unskip")
+  else if chr_code=kern_node then print_esc("unkern")
+  else print_esc("unpenalty");
+un_hbox: if chr_code=copy_code then print_esc("unhcopy")
+  else print_esc("unhbox");
+un_vbox: if chr_code=copy_code then print_esc("unvcopy")
+  else print_esc("unvbox");
+
+@ The |un_hbox| and |un_vbox| commands unwrap one of the 256 current boxes.
+
+@<Cases of |main_control| that build...@>=
+vmode+un_vbox,hmode+un_hbox,mmode+un_hbox: unpackage;
+
+@ @<Declare act...@>=
+procedure unpackage;
+label exit;
+var p:pointer; {the box}
+@!c:box_code..copy_code; {should we copy?}
+@!disp:scaled; {displacement}
+begin c:=cur_chr; scan_eight_bit_int; p:=box(cur_val);
+if p=null then return;
+if type(p)=dir_node then p:=list_ptr(p);
+if (abs(mode)=mmode)or((abs(mode)=vmode)and(type(p)<>vlist_node))or@|
+    ((abs(mode)=hmode)and(type(p)<>hlist_node)) then
+  begin print_err("Incompatible list can't be unboxed");
+@.Incompatible list...@>
+  help3("Sorry, Pandora. (You sneaky devil.)")@/
+  ("I refuse to unbox an \hbox in vertical mode or vice versa.")@/
+  ("And I can't open any boxes in math mode.");@/
+  error; return;
+end;
+case box_dir(p) of
+  any_dir:
+    if abs(direction)<>box_dir(p) then begin
+      print_err("Incompatible direction list can't be unboxed");
+      help2("Sorry, Pandora. (You sneaky devil.)")@/
+      ("I refuse to unbox a box in differrent direction.");@/
+      error; return;
+    end;
+endcases;
+disp:=0;
+if c=copy_code then link(tail):=copy_node_list(list_ptr(p))
+else
+  begin if type(box(cur_val))=dir_node then
+    begin delete_glue_ref(space_ptr(box(cur_val)));
+    delete_glue_ref(xspace_ptr(box(cur_val)));
+    free_node(box(cur_val),box_node_size);
+    end;
+  flush_node_list(link(p));
+  link(tail):=list_ptr(p); box(cur_val):=null;
+  delete_glue_ref(space_ptr(p));
+  delete_glue_ref(xspace_ptr(p));
+  free_node(p,box_node_size);
+  end;
+while link(tail)<>null do
+  begin p:=tail; tail:=link(tail);
+  if not is_char_node(tail) then
+    case type(tail) of
+    glue_node :
+      if (subtype(tail)=kanji_skip_code+1)
+             or(subtype(tail)=xkanji_skip_code+1) then
+        begin link(p):=link(tail);
+        delete_glue_ref(glue_ptr(tail));
+        free_node(tail,small_node_size); tail:=p;
+        end;
+    penalty_node :
+      if subtype(tail)=widow_pena then
+        begin link(p):=link(tail); free_node(tail,small_node_size);
+        tail:=p;
+        end;
+    disp_node :
+      begin prev_disp:=disp; disp:=disp_dimen(tail); prev_node:=p;
+      end;
+    endcases;
+  end;
+exit:end;
+
+@ @<Forbidden...@>=vmode+ital_corr,
+
+@ Italic corrections are converted to kern nodes when the |ital_corr| command
+follows a character. In math mode the same effect is achieved by appending
+a kern of zero here, since italic corrections are supplied later.
+
+@<Cases of |main_control| that build...@>=
+hmode+ital_corr: append_italic_correction;
+mmode+ital_corr: tail_append(new_kern(0));
+
+@ @<Declare act...@>=
+procedure append_italic_correction;
+label exit;
+var p:pointer; {|char_node| at the tail of the current list}
+@!f:internal_font_number; {the font in the |char_node|}
+@!d:pointer; {|disp_node|}
+begin if tail<>head then
+  begin
+  if not is_char_node(tail)and(type(tail)=disp_node) then
+    begin d:=tail; tail:=prev_node;
+    end
+  else d:=null;
+  if (last_jchr<>null)and(link(last_jchr)=tail)and(is_char_node(tail)) then
+    p:=last_jchr
+  else if is_char_node(tail) then p:=tail
+  else if type(tail)=ligature_node then p:=lig_char(tail)
+  else return;
+  f:=font(p);
+  tail_append(new_kern(char_italic(f)(char_info(f)(character(p)))));
+  subtype(tail):=ita_kern;
+  if d<>null then
+    begin prev_node:=tail; tail_append(d);
+    end;
+  end;
+exit:end;
+
+@ Discretionary nodes are easy in the common case `\.{\\-}', but in the
+general case we must process three braces full of items.
+
+@<Put each...@>=
+primitive("-",discretionary,1);
+@!@:Single-character primitives -}{\quad\.{\\-}@>
+primitive("discretionary",discretionary,0);
+@!@:discretionary_}{\.{\\discretionary} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+discretionary: if chr_code=1 then
+  print_esc("-")@+else print_esc("discretionary");
+
+@ @<Cases of |main_control| that build...@>=
+hmode+discretionary,mmode+discretionary: append_discretionary;
+
+@ The space factor does not change when we append a discretionary node,
+but it starts out as 1000 in the subsidiary lists.
+
+@<Declare act...@>=
+procedure append_discretionary;
+var c:integer; {hyphen character}
+begin tail_append(new_disc);
+if cur_chr=1 then
+  begin c:=hyphen_char[cur_font];
+  if c>=0 then if c<256 then pre_break(tail):=new_character(cur_font,c);
+  end
+else  begin incr(save_ptr); saved(-1):=0; new_save_level(disc_group);
+  scan_left_brace; push_nest; mode:=-hmode; space_factor:=1000;
+  end;
+end;
+
+@ The three discretionary lists are constructed somewhat as if they were
+hboxes. A~subroutine called |build_discretionary| handles the transitions.
+(This is sort of fun.)
+
+@<Cases of |handle...@>=
+disc_group: build_discretionary;
+
+@ @<Declare act...@>=
+procedure build_discretionary;
+label done,exit;
+var p,@!q:pointer; {for link manipulation}
+@!n:integer; {length of discretionary list}
+begin unsave;
+@<Prune the current list, if necessary, until it contains only
+  |char_node|, |kern_node|, |hlist_node|, |vlist_node|, |rule_node|,
+  and |ligature_node| items; set |n| to the length of the list,
+  and set |q| to the list's tail@>;
+p:=link(head); pop_nest;
+case saved(-1) of
+0:pre_break(tail):=p;
+1:post_break(tail):=p;
+2:@<Attach list |p| to the current list, and record its length;
+  then finish up and |return|@>;
+end; {there are no other cases}
+incr(saved(-1)); new_save_level(disc_group); scan_left_brace;
+push_nest; mode:=-hmode; space_factor:=1000;
+exit:end;
+
+@ @<Attach list |p| to the current...@>=
+begin if (n>0)and(abs(mode)=mmode) then
+  begin print_err("Illegal math "); print_esc("discretionary");
+@.Illegal math \\disc...@>
+  help2("Sorry: The third part of a discretionary break must be")@/
+  ("empty, in math formulas. I had to delete your third part.");
+  flush_node_list(p); n:=0; error;
+  end
+else link(tail):=p;
+if n<=max_quarterword then replace_count(tail):=n
+else  begin print_err("Discretionary list is too long");
+@.Discretionary list is too long@>
+  help2("Wow---I never thought anybody would tweak me here.")@/
+  ("You can't seriously need such a huge discretionary list?");
+  error;
+  end;
+if n>0 then tail:=q;
+decr(save_ptr);
+prev_node:=tail; tail_append(get_node(small_node_size));
+type(tail):=disp_node; disp_dimen(tail):=0; prev_disp:=0;
+return;
+end
+
+@ During this loop, |p=link(q)| and there are |n| items preceding |p|.
+
+@<Prune the current list, if necessary...@>=
+q:=head; p:=link(q); n:=0;
+while p<>null do
+  begin if not is_char_node(p) then
+    if (type(p)>rule_node)and(type(p)<>kern_node)and
+         (type(p)<>ligature_node)and(type(p)<>disp_node) then
+      if (type(p)=penalty_node)and(subtype(p)<>normal) then
+        begin link(q):=link(p); free_node(p,small_node_size); p:=q;
+        end
+      else
+        begin print_err("Improper discretionary list");
+@.Improper discretionary list@>
+      help1("Discretionary lists must contain only boxes and kerns.");@/
+      error;
+      begin_diagnostic;
+      print_nl("The following discretionary sublist has been deleted:");
+@.The following...deleted@>
+      show_box(p);
+      end_diagnostic(true);
+      flush_node_list(p); link(q):=null; goto done;
+      end;
+  q:=p; p:=link(q); incr(n);
+  end;
+done:
+
+@ We need only one more thing to complete the horizontal mode routines, namely
+the \.{\\accent} primitive.
+
+@<Cases of |main_control| that build...@>=
+hmode+accent: make_accent;
+
+@ The positioning of accents is straightforward but tedious. Given an accent
+of width |a|, designed for characters of height |x| and slant |s|;
+and given a character of width |w|, height |h|, and slant |t|: We will shift
+the accent down by |x-h|, and we will insert kern nodes that have the effect of
+centering the accent over the character and shifting the accent to the
+right by $\delta={1\over2}(w-a)+h\cdot t-x\cdot s$.  If either character is
+absent from the font, we will simply use the other, without shifting.
+
+@<Declare act...@>=
+procedure make_accent;
+var s,@!t: real; {amount of slant}
+@!disp:scaled; {displacement}
+@!cx:KANJI_code; {temporary register for KANJI}
+@!p,@!q,@!r:pointer; {character, box, and kern nodes}
+@!f:internal_font_number; {relevant font}
+@!a,@!h,@!x,@!w,@!delta:scaled; {heights and widths, as explained above}
+@!i:four_quarters; {character information}
+begin scan_char_num;
+if not is_char_ascii(cur_val) then
+  begin KANJI(cx):=cur_val;
+  if direction=dir_tate then f:=cur_tfont else f:=cur_jfont;
+  p:=new_character(f,get_jfm_pos(KANJI(cx),f));
+  if p<>null then
+    begin
+      link(p):=get_avail; info(link(p)):=KANJI(cx);
+    end;
+  end
+else begin f:=cur_font; p:=new_character(f,cur_val);
+  end;
+if p<>null then
+  begin x:=x_height(f); s:=slant(f)/float_constant(65536);
+@^real division@>
+  a:=char_width(f)(char_info(f)(character(p)));@/
+  do_assignments;@/
+  @<Create a character node |q| for the next character,
+    but set |q:=null| if problems arise@>;
+  if q<>null then @<Append the accent with appropriate kerns,
+      then set |p:=q|@>;
+  link(tail):=p;
+  if link(p)<>null then tail:=link(p) else tail:=p;
+  @<Append |disp_node| at end of displace area@>;
+  space_factor:=1000;
+  end;
+end;
+
+@ @<Create a character node |q| for the next...@>=
+q:=null; f:=cur_font; KANJI(cx):=empty;
+if (cur_cmd=letter)or(cur_cmd=other_char) then
+  q:=new_character(f,cur_chr)
+else if (cur_cmd=kanji)or(cur_cmd=kana)or(cur_cmd=other_kchar) then
+  begin  if direction=dir_tate then f:=cur_tfont else f:=cur_jfont;
+  cx:=cur_chr;
+  end
+else if cur_cmd=char_given then
+  if is_char_ascii(cur_chr) then q:=new_character(f,cur_chr)
+  else begin
+    if direction=dir_tate then f:=cur_tfont else f:=cur_jfont;
+    KANJI(cx):=cur_chr
+    end
+  else if cur_cmd=char_num then
+    begin scan_char_num;
+    if is_char_ascii(cur_val) then q:=new_character(f,cur_val)
+    else  begin
+      if direction=dir_tate then f:=cur_tfont else f:=cur_jfont;
+      KANJI(cx):=cur_val
+    end
+  end
+else back_input;
+if direction=dir_tate then
+  begin if font_dir[f]=dir_tate then disp:=0
+  else if font_dir[f]=dir_yoko then disp:=t_baseline_shift-y_baseline_shift
+  else disp:=t_baseline_shift
+  end
+else  begin if font_dir[f]=dir_yoko then disp:=0
+  else if font_dir[f]=dir_tate then disp:=y_baseline_shift-t_baseline_shift
+  else disp:=y_baseline_shift
+  end;
+@<Append |disp_node| at begin of displace area@>;
+if KANJI(cx)<>empty then
+  begin q:=new_character(f,get_jfm_pos(KANJI(cx),f));
+  link(q):=get_avail; info(link(q)):=KANJI(cx); last_jchr:=q;
+  end;
+
+@ The kern nodes appended here must be distinguished from other kerns, lest
+they be wiped away by the hyphenation algorithm or by a previous line break.
+
+The two kerns are computed with (machine-dependent) |real| arithmetic, but
+their sum is machine-independent; the net effect is machine-independent,
+because the user cannot remove these nodes nor access them via \.{\\lastkern}.
+
+@<Append the accent with appropriate kerns...@>=
+begin t:=slant(f)/float_constant(65536);
+@^real division@>
+i:=char_info(f)(character(q));
+w:=char_width(f)(i); h:=char_height(f)(height_depth(i));
+if h<>x then {the accent must be shifted up or down}
+  begin delete_glue_ref(cur_kanji_skip); delete_glue_ref(cur_xkanji_skip);
+  cur_kanji_skip:=zero_glue; cur_xkanji_skip:=zero_glue;
+  add_glue_ref(cur_kanji_skip); add_glue_ref(cur_xkanji_skip);
+  p:=hpack(p,natural); shift_amount(p):=x-h;
+  end;
+delta:=round((w-a)/float_constant(2)+h*t-x*s);
+@^real multiplication@>
+@^real addition@>
+r:=new_kern(delta); subtype(r):=acc_kern; link(tail):=r; link(r):=p;
+tail:=new_kern(-a-delta); subtype(tail):=acc_kern;
+if h=x then begin
+  if font_dir[font(p)]<>dir_default then link(link(p)):=tail
+  else link(p):=tail; end
+else link(p):=tail;
+{ bugfix: if |p| is KANJI char, |link(p)|:=|tail| collapses |p| and kern after accent. }
+p:=q;
+end
+
+@ When `\.{\\cr}' or `\.{\\span}' or a tab mark comes through the scanner
+into |main_control|, it might be that the user has foolishly inserted
+one of them into something that has nothing to do with alignment. But it is
+far more likely that a left brace or right brace has been omitted, since
+|get_next| takes actions appropriate to alignment only when `\.{\\cr}'
+or `\.{\\span}' or tab marks occur with |align_state=0|. The following
+program attempts to make an appropriate recovery.
+
+@<Cases of |main_control| that build...@>=
+any_mode(car_ret), any_mode(tab_mark): align_error;
+any_mode(no_align): no_align_error;
+any_mode(omit): omit_error;
+
+@ @<Declare act...@>=
+procedure align_error;
+begin if abs(align_state)>2 then
+  @<Express consternation over the fact that no alignment is in progress@>
+else  begin back_input;
+  if align_state<0 then
+    begin print_err("Missing { inserted");
+@.Missing \{ inserted@>
+    incr(align_state); cur_tok:=left_brace_token+"{";
+    end
+  else  begin print_err("Missing } inserted");
+@.Missing \} inserted@>
+    decr(align_state); cur_tok:=right_brace_token+"}";
+    end;
+  help3("I've put in what seems to be necessary to fix")@/
+    ("the current column of the current alignment.")@/
+    ("Try to go on, since this might almost work."); ins_error;
+  end;
+end;
+
+@ @<Express consternation...@>=
+begin print_err("Misplaced "); print_cmd_chr(cur_cmd,cur_chr);
+@.Misplaced \&@>
+@.Misplaced \\span@>
+@.Misplaced \\cr@>
+if cur_tok=tab_token+"&" then
+  begin help6("I can't figure out why you would want to use a tab mark")@/
+  ("here. If you just want an ampersand, the remedy is")@/
+  ("simple: Just type `I\&' now. But if some right brace")@/
+  ("up above has ended a previous alignment prematurely,")@/
+  ("you're probably due for more error messages, and you")@/
+  ("might try typing `S' now just to see what is salvageable.");
+  end
+else  begin help5("I can't figure out why you would want to use a tab mark")@/
+  ("or \cr or \span just now. If something like a right brace")@/
+  ("up above has ended a previous alignment prematurely,")@/
+  ("you're probably due for more error messages, and you")@/
+  ("might try typing `S' now just to see what is salvageable.");
+  end;
+error;
+end
+
+@ The help messages here contain a little white lie, since \.{\\noalign}
+and \.{\\omit} are allowed also after `\.{\\noalign\{...\}}'.
+
+@<Declare act...@>=
+procedure no_align_error;
+begin print_err("Misplaced "); print_esc("noalign");
+@.Misplaced \\noalign@>
+help2("I expect to see \noalign only after the \cr of")@/
+  ("an alignment. Proceed, and I'll ignore this case."); error;
+end;
+procedure omit_error;
+begin print_err("Misplaced "); print_esc("omit");
+@.Misplaced \\omit@>
+help2("I expect to see \omit only after tab marks or the \cr of")@/
+  ("an alignment. Proceed, and I'll ignore this case."); error;
+end;
+
+@ We've now covered most of the abuses of \.{\\halign} and \.{\\valign}.
+Let's take a look at what happens when they are used correctly.
+
+@<Cases of |main_control| that build...@>=
+vmode+halign,hmode+valign:init_align;
+mmode+halign: if privileged then
+  if cur_group=math_shift_group then init_align
+  else off_save;
+vmode+endv,hmode+endv: do_endv;
+
+@ An |align_group| code is supposed to remain on the |save_stack|
+during an entire alignment, until |fin_align| removes it.
+
+A devious user might force an |endv| command to occur just about anywhere;
+we must defeat such hacks.
+
+@<Declare act...@>=
+procedure do_endv;
+begin base_ptr:=input_ptr; input_stack[base_ptr]:=cur_input;
+while (input_stack[base_ptr].index_field<>v_template) and
+      (input_stack[base_ptr].loc_field=null) and
+      (input_stack[base_ptr].state_field=token_list) do decr(base_ptr);
+if (input_stack[base_ptr].index_field<>v_template) or
+      (input_stack[base_ptr].loc_field<>null) or
+      (input_stack[base_ptr].state_field<>token_list) then
+  fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+ if cur_group=align_group then
+  begin end_graf;
+  if fin_col then fin_row;
+  end
+else off_save;
+end;
+
+@ @<Cases of |handle_right_brace|...@>=
+align_group: begin back_input; cur_tok:=cs_token_flag+frozen_cr;
+  print_err("Missing "); print_esc("cr"); print(" inserted");
+@.Missing \\cr inserted@>
+  help1("I'm guessing that you meant to end an alignment here.");
+  ins_error;
+  end;
+
+@ @<Cases of |handle_right_brace|...@>=
+no_align_group: begin end_graf; unsave; align_peek;
+  end;
+
+@ Finally, \.{\\endcsname} is not supposed to get through to |main_control|.
+
+@<Cases of |main_control| that build...@>=
+any_mode(end_cs_name): cs_error;
+
+@ @<Declare act...@>=
+procedure cs_error;
+begin print_err("Extra "); print_esc("endcsname");
+@.Extra \\endcsname@>
+help1("I'm ignoring this, since I wasn't doing a \csname.");
+error;
+end;
+
+@* \[48] Building math lists.
+The routines that \TeX\ uses to create mlists are similar to those we have
+just seen for the generation of hlists and vlists. But it is necessary to
+make ``noads'' as well as nodes, so the reader should review the
+discussion of math mode data structures before trying to make sense out of
+the following program.
+
+Here is a little routine that needs to be done whenever a subformula
+is about to be processed. The parameter is a code like |math_group|.
+
+@<Declare act...@>=
+procedure push_math(@!c:group_code);
+begin push_nest; mode:=-mmode; incompleat_noad:=null; new_save_level(c);
+end;
+
+@ We get into math mode from horizontal mode when a `\.\$' (i.e., a
+|math_shift| character) is scanned. We must check to see whether this
+`\.\$' is immediately followed by another, in case display math mode is
+called for.
+
+@<Cases of |main_control| that build...@>=
+hmode+math_shift:init_math;
+
+@ @<Declare act...@>=
+procedure init_math;
+label reswitch,found,not_found,done;
+var w:scaled; {new or partial |pre_display_size|}
+@!l:scaled; {new |display_width|}
+@!s:scaled; {new |display_indent|}
+@!p:pointer; {current node when calculating |pre_display_size|}
+@!q:pointer; {glue specification when calculating |pre_display_size|}
+@!f:internal_font_number; {font in current |char_node|}
+@!n:integer; {scope of paragraph shape specification}
+@!v:scaled; {|w| plus possible glue amount}
+@!d:scaled; {increment to |v|}
+begin get_token; {|get_x_token| would fail on \.{\\ifmmode}\thinspace!}
+if (cur_cmd=math_shift)and(mode>0) then @<Go into display math mode@>
+else  begin back_input; @<Go into ordinary math mode@>;
+  end;
+direction:=-abs(direction);
+end;
+
+@ @<Go into ordinary math mode@>=
+begin push_math(math_shift_group); eq_word_define(int_base+cur_fam_code,-1);
+if (insert_src_special_every_math) then insert_src_special;
+if every_math<>null then begin_token_list(every_math,every_math_text);
+end
+
+@ We get into ordinary math mode from display math mode when `\.{\\eqno}' or
+`\.{\\leqno}' appears. In such cases |cur_chr| will be 0 or~1, respectively;
+the value of |cur_chr| is placed onto |save_stack| for safe keeping.
+
+@<Cases of |main_control| that build...@>=
+mmode+eq_no: if privileged then
+  if cur_group=math_shift_group then start_eq_no
+  else off_save;
+
+@ @<Put each...@>=
+primitive("eqno",eq_no,0);
+@!@:eq_no_}{\.{\\eqno} primitive@>
+primitive("leqno",eq_no,1);
+@!@:leq_no_}{\.{\\leqno} primitive@>
+
+@ When \TeX\ is in display math mode, |cur_group=math_shift_group|,
+so it is not necessary for the |start_eq_no| procedure to test for
+this condition.
+
+@<Declare act...@>=
+procedure start_eq_no;
+begin saved(0):=cur_chr; incr(save_ptr);
+@<Go into ordinary math mode@>;
+end;
+
+@ @<Cases of |print_cmd_chr|...@>=
+eq_no:if chr_code=1 then print_esc("leqno")@+else print_esc("eqno");
+
+@ @<Forbidden...@>=non_math(eq_no),
+
+@ When we enter display math mode, we need to call |line_break| to
+process the partial paragraph that has just been interrupted by the
+display. Then we can set the proper values of |display_width| and
+|display_indent| and |pre_display_size|.
+
+@<Go into display math mode@>=
+begin if head=tail then {`\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}'}
+  begin pop_nest; w:=-max_dimen;
+  end
+else  begin adjust_hlist(head,true); line_break(display_widow_penalty);@/
+  @<Calculate the natural width, |w|, by which the characters of the
+    final line extend to the right of the reference point,
+    plus two ems; or set |w:=max_dimen| if the non-blank information
+    on that line is affected by stretching or shrinking@>;
+  end;
+{now we are in vertical mode, working on the list that will contain the display}
+@<Calculate the length, |l|, and the shift amount, |s|, of the display lines@>;
+push_math(math_shift_group); mode:=mmode;
+eq_word_define(int_base+cur_fam_code,-1);@/
+eq_word_define(dimen_base+pre_display_size_code,w);
+eq_word_define(dimen_base+display_width_code,l);
+eq_word_define(dimen_base+display_indent_code,s);
+if every_display<>null then begin_token_list(every_display,every_display_text);
+if nest_ptr=1 then build_page;
+end
+
+@ @<Calculate the natural width, |w|, by which...@>=
+v:=shift_amount(just_box)+2*quad(cur_font); w:=-max_dimen;
+p:=list_ptr(just_box);
+while p<>null do
+  begin @<Let |d| be the natural width of node |p|;
+    if the node is ``visible,'' |goto found|;
+    if the node is glue that stretches or shrinks, set |v:=max_dimen|@>;
+  if v<max_dimen then v:=v+d;
+  goto not_found;
+  found: if v<max_dimen then
+    begin v:=v+d; w:=v;
+    end
+  else  begin w:=max_dimen; goto done;
+    end;
+  not_found: p:=link(p);
+  end;
+done:
+
+@ @<Let |d| be the natural width of node |p|...@>=
+reswitch: if is_char_node(p) then
+  begin f:=font(p); d:=char_width(f)(orig_char_info(f)(character(p)));
+  if font_dir[f]<>dir_default then p:=link(p);
+  goto found;
+  end;
+case type(p) of
+hlist_node,vlist_node,dir_node,rule_node: begin d:=width(p); goto found;
+  end;
+ligature_node:@<Make node |p| look like a |char_node|...@>;
+kern_node,math_node: d:=width(p);
+glue_node:@<Let |d| be the natural width of this glue; if stretching
+  or shrinking, set |v:=max_dimen|; |goto found| in the case of leaders@>;
+whatsit_node: @<Let |d| be the width of the whatsit |p|@>;
+othercases d:=0
+endcases
+
+@ We need to be careful that |w|, |v|, and |d| do not depend on any |glue_set|
+values, since such values are subject to system-dependent rounding.
+System-dependent numbers are not allowed to infiltrate parameters like
+|pre_display_size|, since \TeX82 is supposed to make the same decisions on all
+machines.
+
+@<Let |d| be the natural width of this glue...@>=
+begin q:=glue_ptr(p); d:=width(q);
+if glue_sign(just_box)=stretching then
+  begin if (glue_order(just_box)=stretch_order(q))and@|
+     (stretch(q)<>0) then
+    v:=max_dimen;
+  end
+else if glue_sign(just_box)=shrinking then
+  begin if (glue_order(just_box)=shrink_order(q))and@|
+     (shrink(q)<>0) then
+    v:=max_dimen;
+  end;
+if subtype(p)>=a_leaders then goto found;
+end
+
+@ A displayed equation is considered to be three lines long, so we
+calculate the length and offset of line number |prev_graf+2|.
+
+@<Calculate the length, |l|, ...@>=
+if par_shape_ptr=null then
+  if (hang_indent<>0)and@|
+   (((hang_after>=0)and(prev_graf+2>hang_after))or@|
+    (prev_graf+1<-hang_after)) then
+    begin l:=hsize-abs(hang_indent);
+    if hang_indent>0 then s:=hang_indent@+else s:=0;
+    end
+  else  begin l:=hsize; s:=0;
+    end
+else  begin n:=info(par_shape_ptr);
+  if prev_graf+2>=n then p:=par_shape_ptr+2*n
+  else p:=par_shape_ptr+2*(prev_graf+2);
+  s:=mem[p-1].sc; l:=mem[p].sc;
+  end
+
+@ Subformulas of math formulas cause a new level of math mode to be entered,
+on the semantic nest as well as the save stack. These subformulas arise in
+several ways: (1)~A left brace by itself indicates the beginning of a
+subformula that will be put into a box, thereby freezing its glue and
+preventing line breaks. (2)~A subscript or superscript is treated as a
+subformula if it is not a single character; the same applies to
+the nucleus of things like \.{\\underline}. (3)~The \.{\\left} primitive
+initiates a subformula that will be terminated by a matching \.{\\right}.
+The group codes placed on |save_stack| in these three cases are
+|math_group|, |math_group|, and |math_left_group|, respectively.
+
+Here is the code that handles case (1); the other cases are not quite as
+trivial, so we shall consider them later.
+
+@<Cases of |main_control| that build...@>=
+mmode+left_brace: begin tail_append(new_noad);
+  back_input; scan_math(nucleus(tail),kcode_noad(tail));
+  end;
+
+@ Recall that the |nucleus|, |subscr|, and |supscr| fields in a noad are
+broken down into subfields called |math_type| and either |info| or
+|(fam,character)|. The job of |scan_math| is to figure out what to place
+in one of these principal fields; it looks at the subformula that
+comes next in the input, and places an encoding of that subformula
+into a given word of |mem|.
+
+@d fam_in_range==((cur_fam>=0)and(cur_fam<16))
+
+@<Declare act...@>=
+procedure scan_math(@!p,@!q:pointer);
+label restart,reswitch,exit;
+var c:integer; {math character code}
+cx:KANJI_code; {temporary register for KANJI}
+begin KANJI(cx):=0;
+restart: @<Get the next non-blank non-relax...@>;
+reswitch:case cur_cmd of
+letter,other_char,char_given:
+  if (is_char_ascii(cur_chr) or (cur_chr=256)) then begin
+    c:=ho(math_code(cur_chr));
+    if c=@'100000 then
+      begin @<Treat |cur_chr| as an active character@>;
+      goto restart;
+      end;
+    end
+  else
+    KANJI(cx):=cur_chr;
+kanji,kana,other_kchar: cx:=cur_chr;
+char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
+  goto reswitch;
+  end;
+math_char_num: begin scan_fifteen_bit_int; c:=cur_val;
+  end;
+math_given: c:=cur_chr;
+delim_num: begin scan_twenty_seven_bit_int; c:=cur_val div @'10000;
+  end;
+othercases @<Scan a subformula enclosed in braces and |return|@>
+endcases;@/
+if KANJI(cx)=0 then
+  begin math_type(p):=math_char; character(p):=qi(c mod 256);
+  if (c>=var_code)and(fam_in_range) then fam(p):=cur_fam
+  else fam(p):=(c div 256) mod 16;
+  if font_dir[fam_fnt(fam(p)+cur_size)]<>dir_default then
+    begin print_err("Not one-byte family");
+    help1("IGNORE.");@/
+    error;
+    end
+  end
+else  begin
+  if q=null then
+    begin math_type(p):=sub_mlist; info(p):=new_noad;
+    p:=nucleus(info(p)); q:=kcode_noad_nucleus(p);
+    end;
+  math_type(p):=math_jchar; fam(p):=cur_jfam; character(p):=qi(0);
+  math_kcode(p-1):=KANJI(cx);
+  if font_dir[fam_fnt(fam(p)+cur_size)]=dir_default then
+    begin print_err("Not two-byte family");
+    help1("IGNORE.");@/
+    error;
+    end
+  end;
+exit:end;
+
+@ An active character that is an |outer_call| is allowed here.
+
+@<Treat |cur_chr|...@>=
+begin cur_cs:=cur_chr+active_base;
+cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs);
+x_token; back_input;
+end
+
+@ The pointer |p| is placed on |save_stack| while a complex subformula
+is being scanned.
+
+@<Scan a subformula...@>=
+begin back_input; scan_left_brace;@/
+saved(0):=p; incr(save_ptr); push_math(math_group); return;
+end
+
+@ The simplest math formula is, of course, `\.{\${ }\$}', when no noads are
+generated. The next simplest cases involve a single character, e.g.,
+`\.{\$x\$}'. Even though such cases may not seem to be very interesting,
+the reader can perhaps understand how happy the author was when `\.{\$x\$}'
+was first properly typeset by \TeX. The code in this section was used.
+@^Knuth, Donald Ervin@>
+
+@<Cases of |main_control| that build...@>=
+mmode+letter,mmode+other_char,mmode+char_given:
+  if is_char_ascii(cur_chr) then
+    if cur_chr<128 then set_math_char(ho(math_code(cur_chr)))
+    else set_math_char(cur_chr)
+  else set_math_kchar(cur_chr);
+mmode+kanji,mmode+kana,mmode+other_kchar: begin
+    cx:=cur_chr; set_math_kchar(KANJI(cx));
+  end;
+mmode+char_num: begin scan_char_num; cur_chr:=cur_val;
+  if is_char_ascii(cur_chr) then
+    if cur_chr<128 then set_math_char(ho(math_code(cur_chr)))
+    else set_math_char(cur_chr)
+  else set_math_kchar(cur_chr);
+  end;
+mmode+math_char_num: begin scan_fifteen_bit_int; set_math_char(cur_val);
+  end;
+mmode+math_given: set_math_char(cur_chr);
+mmode+delim_num: begin scan_twenty_seven_bit_int;
+  set_math_char(cur_val div @'10000);
+  end;
+
+@ The |set_math_char| procedure creates a new noad appropriate to a given
+math code, and appends it to the current mlist. However, if the math code
+is sufficiently large, the |cur_chr| is treated as an active character and
+nothing is appended.
+
+@<Declare act...@>=
+procedure set_math_char(@!c:integer);
+var p:pointer; {the new noad}
+begin if c>=@'100000 then
+  @<Treat |cur_chr|...@>
+else  begin p:=new_noad; math_type(nucleus(p)):=math_char;
+  character(nucleus(p)):=qi(c mod 256);
+  fam(nucleus(p)):=(c div 256) mod 16;
+  if c>=var_code then
+    begin if fam_in_range then fam(nucleus(p)):=cur_fam;
+    type(p):=ord_noad;
+    end
+  else  type(p):=ord_noad+(c div @'10000);
+  link(tail):=p; tail:=p;
+  if font_dir[fam_fnt(fam(nucleus(p))+cur_size)]<>dir_default then begin
+    print_err("Not one-byte family");
+    help1("IGNORE.");@/
+    error;
+  end;
+  inhibit_glue_flag:=false;
+  end;
+end;
+
+@ Primitive math operators like \.{\\mathop} and \.{\\underline} are given
+the command code |math_comp|, supplemented by the noad type that they
+generate.
+
+@<Put each...@>=
+primitive("mathord",math_comp,ord_noad);
+@!@:math_ord_}{\.{\\mathord} primitive@>
+primitive("mathop",math_comp,op_noad);
+@!@:math_op_}{\.{\\mathop} primitive@>
+primitive("mathbin",math_comp,bin_noad);
+@!@:math_bin_}{\.{\\mathbin} primitive@>
+primitive("mathrel",math_comp,rel_noad);
+@!@:math_rel_}{\.{\\mathrel} primitive@>
+primitive("mathopen",math_comp,open_noad);
+@!@:math_open_}{\.{\\mathopen} primitive@>
+primitive("mathclose",math_comp,close_noad);
+@!@:math_close_}{\.{\\mathclose} primitive@>
+primitive("mathpunct",math_comp,punct_noad);
+@!@:math_punct_}{\.{\\mathpunct} primitive@>
+primitive("mathinner",math_comp,inner_noad);
+@!@:math_inner_}{\.{\\mathinner} primitive@>
+primitive("underline",math_comp,under_noad);
+@!@:underline_}{\.{\\underline} primitive@>
+primitive("overline",math_comp,over_noad);@/
+@!@:overline_}{\.{\\overline} primitive@>
+primitive("displaylimits",limit_switch,normal);
+@!@:display_limits_}{\.{\\displaylimits} primitive@>
+primitive("limits",limit_switch,limits);
+@!@:limits_}{\.{\\limits} primitive@>
+primitive("nolimits",limit_switch,no_limits);
+@!@:no_limits_}{\.{\\nolimits} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+math_comp: case chr_code of
+  ord_noad: print_esc("mathord");
+  op_noad: print_esc("mathop");
+  bin_noad: print_esc("mathbin");
+  rel_noad: print_esc("mathrel");
+  open_noad: print_esc("mathopen");
+  close_noad: print_esc("mathclose");
+  punct_noad: print_esc("mathpunct");
+  inner_noad: print_esc("mathinner");
+  under_noad: print_esc("underline");
+  othercases print_esc("overline")
+  endcases;
+limit_switch: if chr_code=limits then print_esc("limits")
+  else if chr_code=no_limits then print_esc("nolimits")
+  else print_esc("displaylimits");
+
+@ @<Cases of |main_control| that build...@>=
+mmode+math_comp: begin tail_append(new_noad);
+  type(tail):=cur_chr; scan_math(nucleus(tail),kcode_noad(tail));
+  end;
+mmode+limit_switch: math_limit_switch;
+
+@ @<Declare act...@>=
+procedure math_limit_switch;
+label exit;
+begin if head<>tail then if type(tail)=op_noad then
+  begin subtype(tail):=cur_chr; return;
+  end;
+print_err("Limit controls must follow a math operator");
+@.Limit controls must follow...@>
+help1("I'm ignoring this misplaced \limits or \nolimits command."); error;
+exit:end;
+
+@ Delimiter fields of noads are filled in by the |scan_delimiter| routine.
+The first parameter of this procedure is the |mem| address where the
+delimiter is to be placed; the second tells if this delimiter follows
+\.{\\radical} or not.
+
+@<Declare act...@>=
+procedure scan_delimiter(@!p:pointer;@!r:boolean);
+begin if r then scan_twenty_seven_bit_int
+else  begin @<Get the next non-blank non-relax...@>;
+  case cur_cmd of
+  letter,other_char: cur_val:=del_code(cur_chr);
+  delim_num: scan_twenty_seven_bit_int;
+  othercases cur_val:=-1
+  endcases;
+  end;
+if cur_val<0 then @<Report that an invalid delimiter code is being changed
+   to null; set~|cur_val:=0|@>;
+small_fam(p):=(cur_val div @'4000000) mod 16;
+small_char(p):=qi((cur_val div @'10000) mod 256);
+large_fam(p):=(cur_val div 256) mod 16;
+large_char(p):=qi(cur_val mod 256);
+end;
+
+@ @<Report that an invalid delimiter...@>=
+begin print_err("Missing delimiter (. inserted)");
+@.Missing delimiter...@>
+help6("I was expecting to see something like `(' or `\{' or")@/
+  ("`\}' here. If you typed, e.g., `{' instead of `\{', you")@/
+  ("should probably delete the `{' by typing `1' now, so that")@/
+  ("braces don't get unbalanced. Otherwise just proceed.")@/
+  ("Acceptable delimiters are characters whose \delcode is")@/
+  ("nonnegative, or you can use `\delimiter <delimiter code>'.");
+back_error; cur_val:=0;
+end
+
+@ @<Cases of |main_control| that build...@>=
+mmode+radical:math_radical;
+
+@ @<Declare act...@>=
+procedure math_radical;
+begin tail_append(get_node(radical_noad_size));
+type(tail):=radical_noad; subtype(tail):=normal;
+mem[nucleus(tail)].hh:=empty_field;
+mem[subscr(tail)].hh:=empty_field;
+mem[supscr(tail)].hh:=empty_field;
+scan_delimiter(left_delimiter(tail),true);
+scan_math(nucleus(tail),kcode_noad(tail));
+end;
+
+@ @<Cases of |main_control| that build...@>=
+mmode+accent,mmode+math_accent:math_ac;
+
+@ @<Declare act...@>=
+procedure math_ac;
+begin if cur_cmd=accent then
+  @<Complain that the user should have said \.{\\mathaccent}@>;
+tail_append(get_node(accent_noad_size));
+type(tail):=accent_noad; subtype(tail):=normal;
+mem[nucleus(tail)].hh:=empty_field;
+mem[subscr(tail)].hh:=empty_field;
+mem[supscr(tail)].hh:=empty_field;
+math_type(accent_chr(tail)):=math_char;
+scan_fifteen_bit_int;
+character(accent_chr(tail)):=qi(cur_val mod 256);
+if (cur_val>=var_code)and fam_in_range then fam(accent_chr(tail)):=cur_fam
+else fam(accent_chr(tail)):=(cur_val div 256) mod 16;
+scan_math(nucleus(tail),kcode_noad(tail));
+end;
+
+@ @<Complain that the user should have said \.{\\mathaccent}@>=
+begin print_err("Please use "); print_esc("mathaccent");
+print(" for accents in math mode");
+@.Please use \\mathaccent...@>
+help2("I'm changing \accent to \mathaccent here; wish me luck.")@/
+  ("(Accents are not the same in formulas as they are in text.)");
+error;
+end
+
+@ @<Cases of |main_control| that build...@>=
+mmode+vcenter: begin
+  scan_spec(vcenter_group,false); normal_paragraph;
+  inhibit_glue_flag:=false;
+  push_nest; mode:=-vmode; prev_depth:=ignore_depth;
+  if (insert_src_special_every_vbox) then insert_src_special;
+  if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text);
+  end;
+
+@ @<Cases of |handle...@>=
+vcenter_group: begin end_graf; unsave; save_ptr:=save_ptr-2;
+  p:=vpack(link(head),saved(1),saved(0));
+  set_box_dir(p)(abs(direction)); pop_nest;
+  if box_dir(p)<>abs(direction) then p:=new_dir_node(p,abs(direction));
+  tail_append(new_noad); type(tail):=vcenter_noad;
+  math_type(nucleus(tail)):=sub_box; info(nucleus(tail)):=p;
+  end;
+
+@ The routine that inserts a |style_node| holds no surprises.
+
+@<Put each...@>=
+primitive("displaystyle",math_style,display_style);
+@!@:display_style_}{\.{\\displaystyle} primitive@>
+primitive("textstyle",math_style,text_style);
+@!@:text_style_}{\.{\\textstyle} primitive@>
+primitive("scriptstyle",math_style,script_style);
+@!@:script_style_}{\.{\\scriptstyle} primitive@>
+primitive("scriptscriptstyle",math_style,script_script_style);
+@!@:script_script_style_}{\.{\\scriptscriptstyle} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+math_style: print_style(chr_code);
+
+@ @<Cases of |main_control| that build...@>=
+mmode+math_style: tail_append(new_style(cur_chr));
+mmode+non_script: begin tail_append(new_glue(zero_glue));
+  subtype(tail):=cond_math_glue;
+  end;
+mmode+math_choice: append_choices;
+
+@ The routine that scans the four mlists of a \.{\\mathchoice} is very
+much like the routine that builds discretionary nodes.
+
+@<Declare act...@>=
+procedure append_choices;
+begin tail_append(new_choice); incr(save_ptr); saved(-1):=0;
+push_math(math_choice_group); scan_left_brace;
+end;
+
+@ @<Cases of |handle_right_brace|...@>=
+math_choice_group: build_choices;
+
+@ @<Declare act...@>=
+@t\4@>@<Declare the function called |fin_mlist|@>@t@>@;@/
+procedure build_choices;
+label exit;
+var p:pointer; {the current mlist}
+begin unsave; p:=fin_mlist(null);
+case saved(-1) of
+0:display_mlist(tail):=p;
+1:text_mlist(tail):=p;
+2:script_mlist(tail):=p;
+3:begin script_script_mlist(tail):=p; decr(save_ptr); return;
+  end;
+end; {there are no other cases}
+incr(saved(-1)); push_math(math_choice_group); scan_left_brace;
+exit:end;
+
+@ Subscripts and superscripts are attached to the previous nucleus by the
+@^superscripts@>@^subscripts@>
+action procedure called |sub_sup|. We use the facts that |sub_mark=sup_mark+1|
+and |subscr(p)=supscr(p)+1|.
+
+@<Cases of |main_control| that build...@>=
+mmode+sub_mark,mmode+sup_mark: sub_sup;
+
+@ @<Declare act...@>=
+procedure sub_sup;
+var t:small_number; {type of previous sub/superscript}
+@!p:pointer; {field to be filled by |scan_math|}
+begin t:=empty; p:=null;
+inhibit_glue_flag:=false;
+if tail<>head then if scripts_allowed(tail) then
+  begin p:=supscr(tail)+cur_cmd-sup_mark; {|supscr| or |subscr|}
+  t:=math_type(p);
+  end;
+if (p=null)or(t<>empty) then @<Insert a dummy noad to be sub/superscripted@>;
+scan_math(p,null);
+end;
+
+@ @<Insert a dummy...@>=
+begin tail_append(new_noad);
+p:=supscr(tail)+cur_cmd-sup_mark; {|supscr| or |subscr|}
+if t<>empty then
+  begin if cur_cmd=sup_mark then
+    begin print_err("Double superscript");
+@.Double superscript@>
+    help1("I treat `x^1^2' essentially like `x^1{}^2'.");
+    end
+  else  begin print_err("Double subscript");
+@.Double subscript@>
+    help1("I treat `x_1_2' essentially like `x_1{}_2'.");
+    end;
+  error;
+  end;
+end
+
+@ An operation like `\.{\\over}' causes the current mlist to go into a
+state of suspended animation: |incompleat_noad| points to a |fraction_noad|
+that contains the mlist-so-far as its numerator, while the denominator
+is yet to come. Finally when the mlist is finished, the denominator will
+go into the incompleat fraction noad, and that noad will become the
+whole formula, unless it is surrounded by `\.{\\left}' and `\.{\\right}'
+delimiters.
+
+@d above_code=0 { `\.{\\above}' }
+@d over_code=1 { `\.{\\over}' }
+@d atop_code=2 { `\.{\\atop}' }
+@d delimited_code=3 { `\.{\\abovewithdelims}', etc.}
+
+@<Put each...@>=
+primitive("above",above,above_code);@/
+@!@:above_}{\.{\\above} primitive@>
+primitive("over",above,over_code);@/
+@!@:over_}{\.{\\over} primitive@>
+primitive("atop",above,atop_code);@/
+@!@:atop_}{\.{\\atop} primitive@>
+primitive("abovewithdelims",above,delimited_code+above_code);@/
+@!@:above_with_delims_}{\.{\\abovewithdelims} primitive@>
+primitive("overwithdelims",above,delimited_code+over_code);@/
+@!@:over_with_delims_}{\.{\\overwithdelims} primitive@>
+primitive("atopwithdelims",above,delimited_code+atop_code);
+@!@:atop_with_delims_}{\.{\\atopwithdelims} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+above: case chr_code of
+  over_code:print_esc("over");
+  atop_code:print_esc("atop");
+  delimited_code+above_code:print_esc("abovewithdelims");
+  delimited_code+over_code:print_esc("overwithdelims");
+  delimited_code+atop_code:print_esc("atopwithdelims");
+  othercases print_esc("above")
+  endcases;
+
+@ @<Cases of |main_control| that build...@>=
+mmode+above: math_fraction;
+
+@ @<Declare act...@>=
+procedure math_fraction;
+var c:small_number; {the type of generalized fraction we are scanning}
+begin c:=cur_chr; inhibit_glue_flag:=false;
+if incompleat_noad<>null then
+  @<Ignore the fraction operation and complain about this ambiguous case@>
+else  begin incompleat_noad:=get_node(fraction_noad_size);
+  type(incompleat_noad):=fraction_noad;
+  subtype(incompleat_noad):=normal;
+  math_type(numerator(incompleat_noad)):=sub_mlist;
+  info(numerator(incompleat_noad)):=link(head);
+  mem[denominator(incompleat_noad)].hh:=empty_field;
+  mem[left_delimiter(incompleat_noad)].qqqq:=null_delimiter;
+  mem[right_delimiter(incompleat_noad)].qqqq:=null_delimiter;@/
+  link(head):=null; tail:=head;
+  @<Use code |c| to distinguish between generalized fractions@>;
+  end;
+end;
+
+@ @<Use code |c|...@>=
+if c>=delimited_code then
+  begin scan_delimiter(left_delimiter(incompleat_noad),false);
+  scan_delimiter(right_delimiter(incompleat_noad),false);
+  end;
+case c mod delimited_code of
+above_code: begin scan_normal_dimen;
+  thickness(incompleat_noad):=cur_val;
+  end;
+over_code: thickness(incompleat_noad):=default_code;
+atop_code: thickness(incompleat_noad):=0;
+end {there are no other cases}
+
+@ @<Ignore the fraction...@>=
+begin if c>=delimited_code then
+  begin scan_delimiter(garbage,false); scan_delimiter(garbage,false);
+  end;
+if c mod delimited_code=above_code then scan_normal_dimen;
+print_err("Ambiguous; you need another { and }");
+@.Ambiguous...@>
+help3("I'm ignoring this fraction specification, since I don't")@/
+  ("know whether a construction like `x \over y \over z'")@/
+  ("means `{x \over y} \over z' or `x \over {y \over z}'.");
+error;
+end
+
+@ At the end of a math formula or subformula, the |fin_mlist| routine is
+called upon to return a pointer to the newly completed mlist, and to
+pop the nest back to the enclosing semantic level. The parameter to
+|fin_mlist|, if not null, points to a |right_noad| that ends the
+current mlist; this |right_noad| has not yet been appended.
+
+@<Declare the function called |fin_mlist|@>=
+function fin_mlist(@!p:pointer):pointer;
+var q:pointer; {the mlist to return}
+begin if incompleat_noad<>null then @<Compleat the incompleat noad@>
+else  begin link(tail):=p; q:=link(head);
+  end;
+pop_nest; fin_mlist:=q;
+end;
+
+@ @<Compleat...@>=
+begin math_type(denominator(incompleat_noad)):=sub_mlist;
+info(denominator(incompleat_noad)):=link(head);
+if p=null then q:=incompleat_noad
+else  begin q:=info(numerator(incompleat_noad));
+  if type(q)<>left_noad then confusion("right");
+@:this can't happen right}{\quad right@>
+  info(numerator(incompleat_noad)):=link(q);
+  link(q):=incompleat_noad; link(incompleat_noad):=p;
+  end;
+end
+
+@ Now at last we're ready to see what happens when a right brace occurs
+in a math formula. Two special cases are simplified here: Braces are effectively
+removed when they surround a single Ord without sub/superscripts, or when they
+surround an accent that is the nucleus of an Ord atom.
+
+@<Cases of |handle...@>=
+math_group: begin unsave; decr(save_ptr);@/
+  math_type(saved(0)):=sub_mlist; p:=fin_mlist(null); info(saved(0)):=p;
+  if p<>null then if link(p)=null then
+   if type(p)=ord_noad then
+    begin if math_type(subscr(p))=empty then
+     if ((math_type(supscr(p))=empty)and(math_kcode(p)=null)) then
+      begin mem[saved(0)].hh:=mem[nucleus(p)].hh;
+      free_node(p,noad_size);
+      end;
+    end
+  else if type(p)=accent_noad then if saved(0)=nucleus(tail) then
+   if type(tail)=ord_noad then @<Replace the tail of the list by |p|@>;
+  end;
+
+@ @<Replace the tail...@>=
+begin q:=head; while link(q)<>tail do q:=link(q);
+link(q):=p; free_node(tail,noad_size); tail:=p;
+end
+
+@ We have dealt with all constructions of math mode except `\.{\\left}' and
+`\.{\\right}', so the picture is completed by the following sections of
+the program.
+
+@<Put each...@>=
+primitive("left",left_right,left_noad);
+@!@:left_}{\.{\\left} primitive@>
+primitive("right",left_right,right_noad);
+@!@:right_}{\.{\\right} primitive@>
+text(frozen_right):="right"; eqtb[frozen_right]:=eqtb[cur_val];
+
+@ @<Cases of |print_cmd_chr|...@>=
+left_right: if chr_code=left_noad then print_esc("left")
+else print_esc("right");
+
+@ @<Cases of |main_control| that build...@>=
+mmode+left_right: math_left_right;
+
+@ @<Declare act...@>=
+procedure math_left_right;
+var t:small_number; {|left_noad| or |right_noad|}
+@!p:pointer; {new noad}
+begin t:=cur_chr; inhibit_glue_flag:=false;
+if (t=right_noad)and(cur_group<>math_left_group) then
+  @<Try to recover from mismatched \.{\\right}@>
+else  begin p:=new_noad; type(p):=t;
+  scan_delimiter(delimiter(p),false);
+  if t=left_noad then
+    begin push_math(math_left_group); link(head):=p; tail:=p;
+    end
+  else  begin p:=fin_mlist(p); unsave; {end of |math_left_group|}
+    tail_append(new_noad); type(tail):=inner_noad;
+    math_type(nucleus(tail)):=sub_mlist;
+    info(nucleus(tail)):=p;
+    end;
+  end;
+end;
+
+@ @<Try to recover from mismatch...@>=
+begin if cur_group=math_shift_group then
+  begin scan_delimiter(garbage,false);
+  print_err("Extra "); print_esc("right");
+@.Extra \\right.@>
+  help1("I'm ignoring a \right that had no matching \left.");
+  error;
+  end
+else off_save;
+end
+
+@ Here is the only way out of math mode.
+
+@<Cases of |main_control| that build...@>=
+mmode+math_shift: if cur_group=math_shift_group then after_math
+  else off_save;
+
+@ @<Declare act...@>=
+procedure after_math;
+var l:boolean; {`\.{\\leqno}' instead of `\.{\\eqno}'}
+@!disp:scaled; {displacement}
+@!danger:boolean; {not enough symbol fonts are present}
+@!m:integer; {|mmode| or |-mmode|}
+@!p:pointer; {the formula}
+@!a:pointer; {box containing equation number}
+@<Local variables for finishing a displayed formula@>@;
+begin danger:=false;
+@<Check that the necessary fonts for math symbols are present;
+  if not, flush the current math lists and set |danger:=true|@>;
+delete_glue_ref(cur_kanji_skip); delete_glue_ref(cur_xkanji_skip);
+if auto_spacing>0 then cur_kanji_skip:=kanji_skip
+else cur_kanji_skip:=zero_glue;
+if auto_xspacing>0 then cur_xkanji_skip:=xkanji_skip
+else cur_xkanji_skip:=zero_glue;
+add_glue_ref(cur_kanji_skip); add_glue_ref(cur_xkanji_skip);
+m:=mode; l:=false; p:=fin_mlist(null); {this pops the nest}
+if mode=-m then {end of equation number}
+  begin @<Check that another \.\$ follows@>;
+  cur_mlist:=p; cur_style:=text_style; mlist_penalties:=false;
+  mlist_to_hlist; a:=hpack(link(temp_head),natural);
+  unsave; decr(save_ptr); {now |cur_group=math_shift_group|}
+  if saved(0)=1 then l:=true;
+  danger:=false;
+  @<Check that the necessary fonts for math symbols are present;
+    if not, flush the current math lists and set |danger:=true|@>;
+  m:=mode; p:=fin_mlist(null);
+  end
+else a:=null;
+if m<0 then @<Finish math in text@>
+else  begin if a=null then @<Check that another \.\$ follows@>;
+  @<Finish displayed math@>;
+  end;
+end;
+
+@ @<Check that the necessary fonts...@>=
+if (font_params[fam_fnt(2+text_size)]<total_mathsy_params)or@|
+   (font_params[fam_fnt(2+script_size)]<total_mathsy_params)or@|
+   (font_params[fam_fnt(2+script_script_size)]<total_mathsy_params) then
+  begin print_err("Math formula deleted: Insufficient symbol fonts");@/
+@.Math formula deleted...@>
+  help3("Sorry, but I can't typeset math unless \textfont 2")@/
+    ("and \scriptfont 2 and \scriptscriptfont 2 have all")@/
+    ("the \fontdimen values needed in math symbol fonts.");
+  error; flush_math; danger:=true;
+  end
+else if (font_params[fam_fnt(3+text_size)]<total_mathex_params)or@|
+   (font_params[fam_fnt(3+script_size)]<total_mathex_params)or@|
+   (font_params[fam_fnt(3+script_script_size)]<total_mathex_params) then
+  begin print_err("Math formula deleted: Insufficient extension fonts");@/
+  help3("Sorry, but I can't typeset math unless \textfont 3")@/
+    ("and \scriptfont 3 and \scriptscriptfont 3 have all")@/
+    ("the \fontdimen values needed in math extension fonts.");
+  error; flush_math; danger:=true;
+  end
+
+@ The |unsave| is done after everything else here; hence an appearance of
+`\.{\\mathsurround}' inside of `\.{\$...\$}' affects the spacing at these
+particular \.\$'s. This is consistent with the conventions of
+`\.{\$\$...\$\$}', since `\.{\\abovedisplayskip}' inside a display affects the
+space above that display.
+
+@<Finish math in text@>=
+begin if direction=dir_tate then disp:=t_baseline_shift
+      else disp:=y_baseline_shift;
+@<Append |disp_node| at begin of displace area@>;
+tail_append(new_math(math_surround,before));
+cur_mlist:=p; cur_style:=text_style; mlist_penalties:=(mode>0); mlist_to_hlist;
+link(tail):=link(temp_head);
+while link(tail)<>null do tail:=link(tail);
+tail_append(new_math(math_surround,after));
+@<Append |disp_node| at end of displace area@>;
+space_factor:=1000; unsave;
+end
+
+@ \TeX\ gets to the following part of the program when the first `\.\$' ending
+a display has been scanned.
+
+@<Check that another \.\$ follows@>=
+begin get_x_token;
+if cur_cmd<>math_shift then
+  begin print_err("Display math should end with $$");
+@.Display math...with \$\$@>
+  help2("The `$' that I just saw supposedly matches a previous `$$'.")@/
+    ("So I shall assume that you typed `$$' both times.");
+  back_error;
+  end;
+end
+
+@ We have saved the worst for last: The fussiest part of math mode processing
+occurs when a displayed formula is being centered and placed with an optional
+equation number.
+
+@<Local variables for finishing...@>=
+@!b:pointer; {box containing the equation}
+@!w:scaled; {width of the equation}
+@!z:scaled; {width of the line}
+@!e:scaled; {width of equation number}
+@!q:scaled; {width of equation number plus space to separate from equation}
+@!d:scaled; {displacement of equation in the line}
+@!s:scaled; {move the line right this much}
+@!g1,@!g2:small_number; {glue parameter codes for before and after}
+@!r:pointer; {kern node used to position the display}
+@!t:pointer; {tail of adjustment list}
+
+@ At this time |p| points to the mlist for the formula; |a| is either
+|null| or it points to a box containing the equation number; and we are in
+vertical mode (or internal vertical mode).
+
+@<Finish displayed math@>=
+cur_mlist:=p; cur_style:=display_style; mlist_penalties:=false;
+mlist_to_hlist; p:=link(temp_head);@/
+adjust_tail:=adjust_head; b:=hpack(p,natural); p:=list_ptr(b);
+t:=adjust_tail; adjust_tail:=null;@/
+w:=width(b); z:=display_width; s:=display_indent;
+if (a=null)or danger then
+  begin e:=0; q:=0;
+  end
+else  begin e:=width(a); q:=e+math_quad(text_size);
+  end;
+if w+q>z then
+  @<Squeeze the equation as much as possible; if there is an equation
+    number that should go on a separate line by itself,
+    set~|e:=0|@>;
+@<Determine the displacement, |d|, of the left edge of the equation, with
+  respect to the line size |z|, assuming that |l=false|@>;
+@<Append the glue or equation number preceding the display@>;
+@<Append the display and perhaps also the equation number@>;
+@<Append the glue or equation number following the display@>;
+resume_after_display
+
+@ @<Declare act...@>=
+procedure resume_after_display;
+begin if cur_group<>math_shift_group then confusion("display");
+@:this can't happen display}{\quad display@>
+unsave; prev_graf:=prev_graf+3;
+push_nest; adjust_dir:=abs(direction);
+mode:=hmode; space_factor:=1000; set_cur_lang; clang:=cur_lang;
+prev_graf:=(norm_min(left_hyphen_min)*@'100+norm_min(right_hyphen_min))
+             *@'200000+cur_lang;
+@<Scan an optional space@>;
+if nest_ptr=1 then build_page;
+end;
+
+@ The user can force the equation number to go on a separate line
+by causing its width to be zero.
+
+@<Squeeze the equation as much as possible...@>=
+begin if (e<>0)and((w-total_shrink[normal]+q<=z)or@|
+   (total_shrink[fil]<>0)or(total_shrink[fill]<>0)or
+   (total_shrink[filll]<>0)) then
+  begin delete_glue_ref(space_ptr(b)); delete_glue_ref(xspace_ptr(b));
+  free_node(b,box_node_size);
+  b:=hpack(p,z-q,exactly);
+  end
+else  begin e:=0;
+  if w>z then
+    begin delete_glue_ref(space_ptr(b)); delete_glue_ref(xspace_ptr(b));
+    free_node(b,box_node_size);
+    b:=hpack(p,z,exactly);
+    end;
+  end;
+w:=width(b);
+end
+
+@ We try first to center the display without regard to the existence of
+the equation number. If that would make it too close (where ``too close''
+means that the space between display and equation number is less than the
+width of the equation number), we either center it in the remaining space
+or move it as far from the equation number as possible. The latter alternative
+is taken only if the display begins with glue, since we assume that the
+user put glue there to control the spacing precisely.
+
+@<Determine the displacement, |d|, of the left edge of the equation...@>=
+d:=half(z-w);
+if (e>0)and(d<2*e) then {too close}
+  begin d:=half(z-w-e);
+  if p<>null then if not is_char_node(p) then if type(p)=glue_node then d:=0;
+  end
+
+@ If the equation number is set on a line by itself, either before or
+after the formula, we append an infinite penalty so that no page break will
+separate the display from its number; and we use the same size and
+displacement for all three potential lines of the display, even though
+`\.{\\parshape}' may specify them differently.
+
+@<Append the glue or equation number preceding the display@>=
+tail_append(new_penalty(pre_display_penalty));@/
+if (d+s<=pre_display_size)or l then {not enough clearance}
+  begin g1:=above_display_skip_code; g2:=below_display_skip_code;
+  end
+else  begin g1:=above_display_short_skip_code;
+  g2:=below_display_short_skip_code;
+  end;
+if l and(e=0) then {it follows that |type(a)=hlist_node|}
+  begin shift_amount(a):=s; append_to_vlist(a);
+  tail_append(new_penalty(inf_penalty));
+  end
+else tail_append(new_param_glue(g1))
+
+@ @<Append the display and perhaps also the equation number@>=
+if e<>0 then
+  begin r:=new_kern(z-w-e-d);
+  if l then
+    begin link(a):=r; link(r):=b; b:=a; d:=0;
+    end
+  else  begin link(b):=r; link(r):=a;
+    end;
+  b:=hpack(b,natural);
+  end;
+shift_amount(b):=s+d; append_to_vlist(b)
+
+@ @<Append the glue or equation number following the display@>=
+if (a<>null)and(e=0)and not l then
+  begin tail_append(new_penalty(inf_penalty));
+  shift_amount(a):=s+z-width(a);
+  append_to_vlist(a);
+  g2:=0;
+  end;
+if t<>adjust_head then {migrating material comes after equation number}
+  begin link(tail):=link(adjust_head); tail:=t;
+  end;
+tail_append(new_penalty(post_display_penalty));
+if g2>0 then tail_append(new_param_glue(g2))
+
+@ When \.{\\halign} appears in a display, the alignment routines operate
+essentially as they do in vertical mode. Then the following program is
+activated, with |p| and |q| pointing to the beginning and end of the
+resulting list, and with |aux_save| holding the |prev_depth| value.
+
+@<Finish an alignment in a display@>=
+begin do_assignments;
+if cur_cmd<>math_shift then @<Pontificate about improper alignment in display@>
+else @<Check that another \.\$ follows@>;
+pop_nest;
+tail_append(new_penalty(pre_display_penalty));
+tail_append(new_param_glue(above_display_skip_code));
+link(tail):=p;
+if p<>null then tail:=q;
+tail_append(new_penalty(post_display_penalty));
+tail_append(new_param_glue(below_display_skip_code));
+prev_depth:=aux_save.sc; resume_after_display;
+end
+
+@ @<Pontificate...@>=
+begin print_err("Missing $$ inserted");
+@.Missing {\$\$} inserted@>
+help2("Displays can use special alignments (like \eqalignno)")@/
+  ("only if nothing but the alignment itself is between $$'s.");
+back_error;
+end
+
+@* \[49] Mode-independent processing.
+The long |main_control| procedure has now been fully specified, except for
+certain activities that are independent of the current mode. These activities
+do not change the current vlist or hlist or mlist; if they change anything,
+it is the value of a parameter or the meaning of a control sequence.
+
+Assignments to values in |eqtb| can be global or local. Furthermore, a
+control sequence can be defined to be `\.{\\long}' or `\.{\\outer}', and
+it might or might not be expanded. The prefixes `\.{\\global}', `\.{\\long}',
+and `\.{\\outer}' can occur in any order. Therefore we assign binary numeric
+codes, making it possible to accumulate the union of all specified prefixes
+by adding the corresponding codes.  (\PASCAL's |set| operations could also
+have been used.)
+
+@<Put each...@>=
+primitive("long",prefix,1);
+@!@:long_}{\.{\\long} primitive@>
+primitive("outer",prefix,2);
+@!@:outer_}{\.{\\outer} primitive@>
+primitive("global",prefix,4);
+@!@:global_}{\.{\\global} primitive@>
+primitive("def",def,0);
+@!@:def_}{\.{\\def} primitive@>
+primitive("gdef",def,1);
+@!@:gdef_}{\.{\\gdef} primitive@>
+primitive("edef",def,2);
+@!@:edef_}{\.{\\edef} primitive@>
+primitive("xdef",def,3);
+@!@:xdef_}{\.{\\xdef} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+prefix: if chr_code=1 then print_esc("long")
+  else if chr_code=2 then print_esc("outer")
+  else print_esc("global");
+def: if chr_code=0 then print_esc("def")
+  else if chr_code=1 then print_esc("gdef")
+  else if chr_code=2 then print_esc("edef")
+  else print_esc("xdef");
+
+@ Every prefix, and every command code that might or might not be prefixed,
+calls the action procedure |prefixed_command|. This routine accumulates
+a sequence of prefixes until coming to a non-prefix, then it carries out
+the command.
+
+@<Cases of |main_control| that don't...@>=
+any_mode(assign_kinsoku),
+any_mode(assign_inhibit_xsp_code),
+any_mode(set_auto_spacing),
+any_mode(set_kansuji_char),
+any_mode(toks_register),
+any_mode(assign_toks),
+any_mode(assign_int),
+any_mode(def_jfont),
+any_mode(def_tfont),
+any_mode(assign_dimen),
+any_mode(assign_glue),
+any_mode(assign_mu_glue),
+any_mode(assign_font_dimen),
+any_mode(assign_font_int),
+any_mode(set_aux),
+any_mode(set_prev_graf),
+any_mode(set_page_dimen),
+any_mode(set_page_int),
+any_mode(set_box_dimen),
+any_mode(set_shape),
+any_mode(def_code),
+any_mode(def_family),
+any_mode(set_font),
+any_mode(def_font),
+any_mode(register),
+any_mode(advance),
+any_mode(multiply),
+any_mode(divide),
+any_mode(prefix),
+any_mode(let),
+any_mode(shorthand_def),
+any_mode(read_to_cs),
+any_mode(def),
+any_mode(set_box),
+any_mode(hyph_data),
+any_mode(set_interaction):prefixed_command;
+
+@ If the user says, e.g., `\.{\\global\\global}', the redundancy is
+silently accepted.
+
+@<Declare act...@>=
+@t\4@>@<Declare subprocedures for |prefixed_command|@>@t@>@;@/
+procedure prefixed_command;
+label done,exit;
+var a:small_number; {accumulated prefix codes so far}
+@!m:integer; {ditto}
+@!f:internal_font_number; {identifies a font}
+@!j:halfword; {index into a \.{\\parshape} specification}
+@!k:font_index; {index into |font_info|}
+@!p,@!q:pointer; {for temporary short-term use}
+@!n:integer; {ditto}
+@!e:boolean; {should a definition be expanded? or was \.{\\let} not done?}
+begin a:=0;
+while cur_cmd=prefix do
+  begin if not odd(a div cur_chr) then a:=a+cur_chr;
+  @<Get the next non-blank non-relax...@>;
+  if cur_cmd<=max_non_prefixed_command then
+    @<Discard erroneous prefixes and |return|@>;
+  end;
+@<Discard the prefixes \.{\\long} and \.{\\outer} if they are irrelevant@>;
+@<Adjust \(f)for the setting of \.{\\globaldefs}@>;
+case cur_cmd of
+@t\4@>@<Assignments@>@;
+othercases confusion("prefix")
+@:this can't happen prefix}{\quad prefix@>
+endcases;
+done: @<Insert a token saved by \.{\\afterassignment}, if any@>;
+exit:end;
+
+@ @<Discard erroneous...@>=
+begin print_err("You can't use a prefix with `");
+@.You can't use a prefix with x@>
+print_cmd_chr(cur_cmd,cur_chr); print_char("'");
+help1("I'll pretend you didn't say \long or \outer or \global.");
+back_error; return;
+end
+
+@ @<Discard the prefixes...@>=
+if (cur_cmd<>def)and(a mod 4<>0) then
+  begin print_err("You can't use `"); print_esc("long"); print("' or `");
+  print_esc("outer"); print("' with `");
+@.You can't use \\long...@>
+  print_cmd_chr(cur_cmd,cur_chr); print_char("'");
+  help1("I'll pretend you didn't say \long or \outer here.");
+  error;
+  end
+
+@ The previous routine does not have to adjust |a| so that |a mod 4=0|,
+since the following routines test for the \.{\\global} prefix as follows.
+
+@d global==(a>=4)
+@d define(#)==if global then geq_define(#)@+else eq_define(#)
+@d word_define(#)==if global then geq_word_define(#)@+else eq_word_define(#)
+
+@<Adjust \(f)for the setting of \.{\\globaldefs}@>=
+if global_defs<>0 then
+  if global_defs<0 then
+    begin if global then a:=a-4;
+    end
+  else  begin if not global then a:=a+4;
+    end
+
+@ When a control sequence is to be defined, by \.{\\def} or \.{\\let} or
+something similar, the |get_r_token| routine will substitute a special
+control sequence for a token that is not redefinable.
+
+@<Declare subprocedures for |prefixed_command|@>=
+procedure get_r_token;
+label restart;
+begin restart: repeat get_token;
+until cur_tok<>space_token;
+if (cur_cs=0)or(cur_cs>eqtb_top)or
+  ((cur_cs>frozen_control_sequence)and(cur_cs<=eqtb_size)) then
+  begin print_err("Missing control sequence inserted");
+@.Missing control...@>
+  help5("Please don't say `\def cs{...}', say `\def\cs{...}'.")@/
+  ("I've inserted an inaccessible control sequence so that your")@/
+  ("definition will be completed without mixing me up too badly.")@/
+  ("You can recover graciously from this error, if you're")@/
+  ("careful; see exercise 27.2 in The TeXbook.");
+@:TeXbook}{\sl The \TeX book@>
+  if cur_cs=0 then back_input;
+  cur_tok:=cs_token_flag+frozen_protection; ins_error; goto restart;
+  end;
+end;
+
+@ @<Initialize table entries...@>=
+text(frozen_protection):="inaccessible";
+
+@ Here's an example of the way many of the following routines operate.
+(Unfortunately, they aren't all as simple as this.)
+
+@<Assignments@>=
+set_font: begin
+  if font_dir[cur_chr]=dir_yoko then
+    define(cur_jfont_loc,data,cur_chr)
+  else if font_dir[cur_chr]=dir_tate then
+    define(cur_tfont_loc,data,cur_chr)
+  else
+    define(cur_font_loc,data,cur_chr)
+end;
+
+@ When a |def| command has been scanned,
+|cur_chr| is odd if the definition is supposed to be global, and
+|cur_chr>=2| if the definition is supposed to be expanded.
+
+@<Assignments@>=
+def: begin if odd(cur_chr)and not global and(global_defs>=0) then a:=a+4;
+  e:=(cur_chr>=2); get_r_token; p:=cur_cs;
+  q:=scan_toks(true,e); define(p,call+(a mod 4),def_ref);
+  end;
+
+@ Both \.{\\let} and \.{\\futurelet} share the command code |let|.
+
+@<Put each...@>=
+primitive("let",let,normal);@/
+@!@:let_}{\.{\\let} primitive@>
+primitive("futurelet",let,normal+1);@/
+@!@:future_let_}{\.{\\futurelet} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+let: if chr_code<>normal then print_esc("futurelet")@+else print_esc("let");
+
+@ @<Assignments@>=
+let:  begin n:=cur_chr;
+  get_r_token; p:=cur_cs;
+  if n=normal then
+    begin repeat get_token;
+    until cur_cmd<>spacer;
+    if cur_tok=other_token+"=" then
+      begin get_token;
+      if cur_cmd=spacer then get_token;
+      end;
+    end
+  else  begin get_token; q:=cur_tok; get_token; back_input;
+    cur_tok:=q; back_input; {look ahead, then back up}
+    end; {note that |back_input| doesn't affect |cur_cmd|, |cur_chr|}
+  if cur_cmd>=call then add_token_ref(cur_chr);
+  define(p,cur_cmd,cur_chr);
+  end;
+
+@ A \.{\\chardef} creates a control sequence whose |cmd| is |char_given|;
+a \.{\\mathchardef} creates a control sequence whose |cmd| is |math_given|;
+and the corresponding |chr| is the character code or math code. A \.{\\countdef}
+or \.{\\dimendef} or \.{\\skipdef} or \.{\\muskipdef} creates a control
+sequence whose |cmd| is |assign_int| or \dots\ or |assign_mu_glue|, and the
+corresponding |chr| is the |eqtb| location of the internal register in question.
+
+@d char_def_code=0 {|shorthand_def| for \.{\\chardef}}
+@d math_char_def_code=1 {|shorthand_def| for \.{\\mathchardef}}
+@d count_def_code=2 {|shorthand_def| for \.{\\countdef}}
+@d dimen_def_code=3 {|shorthand_def| for \.{\\dimendef}}
+@d skip_def_code=4 {|shorthand_def| for \.{\\skipdef}}
+@d mu_skip_def_code=5 {|shorthand_def| for \.{\\muskipdef}}
+@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}}
+@d char_sub_def_code=7 {|shorthand_def| for \.{\\charsubdef}}
+
+@<Put each...@>=
+primitive("chardef",shorthand_def,char_def_code);@/
+@!@:char_def_}{\.{\\chardef} primitive@>
+primitive("mathchardef",shorthand_def,math_char_def_code);@/
+@!@:math_char_def_}{\.{\\mathchardef} primitive@>
+primitive("countdef",shorthand_def,count_def_code);@/
+@!@:count_def_}{\.{\\countdef} primitive@>
+primitive("dimendef",shorthand_def,dimen_def_code);@/
+@!@:dimen_def_}{\.{\\dimendef} primitive@>
+primitive("skipdef",shorthand_def,skip_def_code);@/
+@!@:skip_def_}{\.{\\skipdef} primitive@>
+primitive("muskipdef",shorthand_def,mu_skip_def_code);@/
+@!@:mu_skip_def_}{\.{\\muskipdef} primitive@>
+primitive("toksdef",shorthand_def,toks_def_code);@/
+@!@:toks_def_}{\.{\\toksdef} primitive@>
+if mltex_p then
+  begin
+  primitive("charsubdef",shorthand_def,char_sub_def_code);@/
+@!@:char_sub_def_}{\.{\\charsubdef} primitive@>
+  end;
+
+@ @<Cases of |print_cmd_chr|...@>=
+shorthand_def: case chr_code of
+  char_def_code: print_esc("chardef");
+  math_char_def_code: print_esc("mathchardef");
+  count_def_code: print_esc("countdef");
+  dimen_def_code: print_esc("dimendef");
+  skip_def_code: print_esc("skipdef");
+  mu_skip_def_code: print_esc("muskipdef");
+  char_sub_def_code: print_esc("charsubdef");
+  othercases print_esc("toksdef")
+  endcases;
+char_given: begin print_esc("char"); print_hex(chr_code);
+  end;
+math_given: begin print_esc("mathchar"); print_hex(chr_code);
+  end;
+
+@ We temporarily define |p| to be |relax|, so that an occurrence of |p|
+while scanning the definition will simply stop the scanning instead of
+producing an ``undefined control sequence'' error or expanding the
+previous meaning.  This allows, for instance, `\.{\\chardef\\foo=123\\foo}'.
+
+@<Assignments@>=
+shorthand_def: if cur_chr=char_sub_def_code then
+ begin scan_char_num; p:=char_sub_code_base+cur_val; scan_optional_equals;
+  scan_char_num; n:=cur_val; {accent character in substitution}
+  scan_char_num;
+  if (tracing_char_sub_def>0) then
+    begin begin_diagnostic; print_nl("New character substitution: ");
+    print_ASCII(p-char_sub_code_base); print(" = ");
+    print_ASCII(n); print_char(" ");
+    print_ASCII(cur_val); end_diagnostic(false);
+    end;
+  n:=n*256+cur_val;
+  define(p,data,hi(n));
+  if (p-char_sub_code_base)<char_sub_def_min then
+    word_define(int_base+char_sub_def_min_code,p-char_sub_code_base);
+  if (p-char_sub_code_base)>char_sub_def_max then
+    word_define(int_base+char_sub_def_max_code,p-char_sub_code_base);
+ end
+else begin n:=cur_chr; get_r_token; p:=cur_cs; define(p,relax,256);
+  scan_optional_equals;
+  case n of
+  char_def_code: begin scan_char_num; define(p,char_given,cur_val);
+    end;
+  math_char_def_code: begin scan_fifteen_bit_int; define(p,math_given,cur_val);
+    end;
+  othercases begin scan_eight_bit_int;
+    case n of
+    count_def_code: define(p,assign_int,count_base+cur_val);
+    dimen_def_code: define(p,assign_dimen,scaled_base+cur_val);
+    skip_def_code: define(p,assign_glue,skip_base+cur_val);
+    mu_skip_def_code: define(p,assign_mu_glue,mu_skip_base+cur_val);
+    toks_def_code: define(p,assign_toks,toks_base+cur_val);
+    end; {there are no other cases}
+    end
+  endcases;
+  end;
+
+@ @<Assignments@>=
+read_to_cs: begin scan_int; n:=cur_val;
+  if not scan_keyword("to") then
+@.to@>
+    begin print_err("Missing `to' inserted");
+@.Missing `to'...@>
+    help2("You should have said `\read<number> to \cs'.")@/
+    ("I'm going to look for the \cs now."); error;
+    end;
+  get_r_token;
+  p:=cur_cs; read_toks(n,p); define(p,call,cur_val);
+  end;
+
+@ The token-list parameters, \.{\\output} and \.{\\everypar}, etc., receive
+their values in the following way. (For safety's sake, we place an
+enclosing pair of braces around an \.{\\output} list.)
+
+@<Assignments@>=
+toks_register,assign_toks: begin q:=cur_cs;
+  if cur_cmd=toks_register then
+    begin scan_eight_bit_int; p:=toks_base+cur_val;
+    end
+  else p:=cur_chr; {|p=every_par_loc| or |output_routine_loc| or \dots}
+  scan_optional_equals;
+  @<Get the next non-blank non-relax non-call token@>;
+  if cur_cmd<>left_brace then @<If the right-hand side is a token parameter
+      or token register, finish the assignment and |goto done|@>;
+  back_input; cur_cs:=q; q:=scan_toks(false,false);
+  if link(def_ref)=null then {empty list: revert to the default}
+    begin define(p,undefined_cs,null); free_avail(def_ref);
+    end
+  else  begin if p=output_routine_loc then {enclose in curlies}
+      begin link(q):=get_avail; q:=link(q);
+      info(q):=right_brace_token+"}";
+      q:=get_avail; info(q):=left_brace_token+"{";
+      link(q):=link(def_ref); link(def_ref):=q;
+      end;
+    define(p,call,def_ref);
+    end;
+  end;
+
+@ @<If the right-hand side is a token parameter...@>=
+begin if cur_cmd=toks_register then
+  begin scan_eight_bit_int; cur_cmd:=assign_toks; cur_chr:=toks_base+cur_val;
+  end;
+if cur_cmd=assign_toks then
+  begin q:=equiv(cur_chr);
+  if q=null then define(p,undefined_cs,null)
+  else  begin add_token_ref(q); define(p,call,q);
+    end;
+  goto done;
+  end;
+end
+
+@ Similar routines are used to assign values to the numeric parameters.
+
+@<Assignments@>=
+assign_int: begin p:=cur_chr; scan_optional_equals; scan_int;
+  if p=int_base+cur_fam_code then
+    begin if font_dir[fam_fnt(cur_val)]<>dir_default then
+      word_define(int_base+cur_jfam_code,cur_val)
+    else word_define(p,cur_val);
+    end
+  else word_define(p,cur_val);
+  end;
+assign_dimen: begin p:=cur_chr; scan_optional_equals;
+  scan_normal_dimen; word_define(p,cur_val);
+  end;
+assign_glue,assign_mu_glue: begin p:=cur_chr; n:=cur_cmd; scan_optional_equals;
+  if n=assign_mu_glue then scan_glue(mu_val)@+else scan_glue(glue_val);
+  trap_zero_glue;
+  define(p,glue_ref,cur_val);
+  end;
+
+@ When a glue register or parameter becomes zero, it will always point to
+|zero_glue| because of the following procedure. (Exception: The tabskip
+glue isn't trapped while preambles are being scanned.)
+
+@<Declare subprocedures for |prefixed_command|@>=
+procedure trap_zero_glue;
+begin if (width(cur_val)=0)and(stretch(cur_val)=0)and(shrink(cur_val)=0) then
+  begin add_glue_ref(zero_glue);
+  delete_glue_ref(cur_val); cur_val:=zero_glue;
+  end;
+end;
+
+@ The various character code tables are changed by the |def_code| commands,
+and the font families are declared by |def_family|.
+
+@<Put each...@>=
+primitive("catcode",def_code,cat_code_base);
+@!@:cat_code_}{\.{\\catcode} primitive@>
+primitive("kcatcode",def_code,kcat_code_base);
+@!@:cat_code_}{\.{\\kcatcode} primitive@>
+primitive("xspcode",def_code,auto_xsp_code_base);
+@!@:auto_xsp_code_}{\.{\\xspcode} primitive@>
+primitive("mathcode",def_code,math_code_base);
+@!@:math_code_}{\.{\\mathcode} primitive@>
+primitive("lccode",def_code,lc_code_base);
+@!@:lc_code_}{\.{\\lccode} primitive@>
+primitive("uccode",def_code,uc_code_base);
+@!@:uc_code_}{\.{\\uccode} primitive@>
+primitive("sfcode",def_code,sf_code_base);
+@!@:sf_code_}{\.{\\sfcode} primitive@>
+primitive("delcode",def_code,del_code_base);
+@!@:del_code_}{\.{\\delcode} primitive@>
+primitive("textfont",def_family,math_font_base);
+@!@:text_font_}{\.{\\textfont} primitive@>
+primitive("scriptfont",def_family,math_font_base+script_size);
+@!@:script_font_}{\.{\\scriptfont} primitive@>
+primitive("scriptscriptfont",def_family,math_font_base+script_script_size);
+@!@:script_script_font_}{\.{\\scriptscriptfont} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+def_code: if chr_code=cat_code_base then print_esc("catcode")
+  else if chr_code=kcat_code_base then print_esc("kcatcode")
+  else if chr_code=auto_xsp_code_base then print_esc("xspcode")
+  else if chr_code=math_code_base then print_esc("mathcode")
+  else if chr_code=lc_code_base then print_esc("lccode")
+  else if chr_code=uc_code_base then print_esc("uccode")
+  else if chr_code=sf_code_base then print_esc("sfcode")
+  else print_esc("delcode");
+def_family: print_size(chr_code-math_font_base);
+
+@ The different types of code values have different legal ranges; the
+following program is careful to check each case properly.
+
+@<Assignments@>=
+def_code: begin
+  @<Let |m| be the minimal legal code value, based on |cur_chr|@>;
+  @<Let |n| be the largest legal code value, based on |cur_chr|@>;
+  p:=cur_chr; scan_char_num;
+  if p=kcat_code_base then p:=p+kcatcodekey(cur_val)
+  else if not is_char_ascii(cur_val) then p:=p+Hi(cur_val)
+    { If |cur_val| is a KANJI code, we use its upper half, as the case of retrieving. }
+  else p:=p+cur_val;
+  scan_optional_equals; scan_int;
+  if ((cur_val<m)and(p<del_code_base))or(cur_val>n) then
+  begin print_err("Invalid code ("); print_int(cur_val);
+@.Invalid code@>
+    if p<del_code_base then
+      begin print("), should be in the range "); print_int(m); print("..");
+      end
+    else print("), should be at most ");
+    print_int(n);
+    if m=0 then
+      begin help1("I'm going to use 0 instead of that illegal code value.");@/
+      error;
+      end
+    else
+      begin help1("I'm going to use 16 instead of that illegal code value.");@/
+      error;
+      end;
+    cur_val:=m;
+  end;
+  if p<math_code_base then define(p,data,cur_val)
+  else if p<del_code_base then define(p,data,hi(cur_val))
+  else word_define(p,cur_val);
+  end;
+
+@ @<Let |m| be the minimal...@>=
+if cur_chr=kcat_code_base then m:=kanji else m:=0
+
+@ @<Let |n| be the largest...@>=
+if cur_chr=cat_code_base then n:=invalid_char {1byte |max_char_code|}
+else if cur_chr=kcat_code_base then n:=max_char_code
+else if cur_chr=math_code_base then n:=@'100000
+else if cur_chr=sf_code_base then n:=@'77777
+else if cur_chr=del_code_base then n:=@'77777777
+else n:=255
+
+@ @<Assignments@>=
+def_family: begin p:=cur_chr; scan_four_bit_int; p:=p+cur_val;
+  scan_optional_equals; scan_font_ident; define(p,data,cur_val);
+  end;
+
+@ Next we consider changes to \TeX's numeric registers.
+
+@<Assignments@>=
+register,advance,multiply,divide: do_register_command(a);
+
+@ We use the fact that |register<advance<multiply<divide|.
+
+@<Declare subprocedures for |prefixed_command|@>=
+procedure do_register_command(@!a:small_number);
+label found,exit;
+var l,@!q,@!r,@!s:pointer; {for list manipulation}
+@!p:int_val..mu_val; {type of register involved}
+begin q:=cur_cmd;
+@<Compute the register location |l| and its type |p|; but |return| if invalid@>;
+if q=register then scan_optional_equals
+else if scan_keyword("by") then do_nothing; {optional `\.{by}'}
+@.by@>
+arith_error:=false;
+if q<multiply then @<Compute result of |register| or
+    |advance|, put it in |cur_val|@>
+else @<Compute result of |multiply| or |divide|, put it in |cur_val|@>;
+if arith_error then
+  begin print_err("Arithmetic overflow");
+@.Arithmetic overflow@>
+  help2("I can't carry out that multiplication or division,")@/
+    ("since the result is out of range.");
+  if p>=glue_val then delete_glue_ref(cur_val);
+  error; return;
+  end;
+if p<glue_val then word_define(l,cur_val)
+else  begin trap_zero_glue; define(l,glue_ref,cur_val);
+  end;
+exit: end;
+
+@ Here we use the fact that the consecutive codes |int_val..mu_val| and
+|assign_int..assign_mu_glue| correspond to each other nicely.
+
+@<Compute the register location |l| and its type |p|...@>=
+begin if q<>register then
+  begin get_x_token;
+  if (cur_cmd>=assign_int)and(cur_cmd<=assign_mu_glue) then
+    begin l:=cur_chr; p:=cur_cmd-assign_int; goto found;
+    end;
+  if cur_cmd<>register then
+    begin print_err("You can't use `"); print_cmd_chr(cur_cmd,cur_chr);
+@.You can't use x after ...@>
+    print("' after "); print_cmd_chr(q,0);
+    help1("I'm forgetting what you said and not changing anything.");
+    error; return;
+    end;
+  end;
+p:=cur_chr; scan_eight_bit_int;
+case p of
+int_val: l:=cur_val+count_base;
+dimen_val: l:=cur_val+scaled_base;
+glue_val: l:=cur_val+skip_base;
+mu_val: l:=cur_val+mu_skip_base;
+end; {there are no other cases}
+end;
+found:
+
+@ @<Compute result of |register| or |advance|...@>=
+if p<glue_val then
+  begin if p=int_val then scan_int@+else scan_normal_dimen;
+  if q=advance then cur_val:=cur_val+eqtb[l].int;
+  end
+else  begin scan_glue(p);
+  if q=advance then @<Compute the sum of two glue specs@>;
+  end
+
+@ @<Compute the sum of two glue specs@>=
+begin q:=new_spec(cur_val); r:=equiv(l);
+delete_glue_ref(cur_val);
+width(q):=width(q)+width(r);
+if stretch(q)=0 then stretch_order(q):=normal;
+if stretch_order(q)=stretch_order(r) then stretch(q):=stretch(q)+stretch(r)
+else if (stretch_order(q)<stretch_order(r))and(stretch(r)<>0) then
+  begin stretch(q):=stretch(r); stretch_order(q):=stretch_order(r);
+  end;
+if shrink(q)=0 then shrink_order(q):=normal;
+if shrink_order(q)=shrink_order(r) then shrink(q):=shrink(q)+shrink(r)
+else if (shrink_order(q)<shrink_order(r))and(shrink(r)<>0) then
+  begin shrink(q):=shrink(r); shrink_order(q):=shrink_order(r);
+  end;
+cur_val:=q;
+end
+
+@ @<Compute result of |multiply| or |divide|...@>=
+begin scan_int;
+if p<glue_val then
+  if q=multiply then
+    if p=int_val then cur_val:=mult_integers(eqtb[l].int,cur_val)
+    else cur_val:=nx_plus_y(eqtb[l].int,cur_val,0)
+  else cur_val:=x_over_n(eqtb[l].int,cur_val)
+else  begin s:=equiv(l); r:=new_spec(s);
+  if q=multiply then
+    begin width(r):=nx_plus_y(width(s),cur_val,0);
+    stretch(r):=nx_plus_y(stretch(s),cur_val,0);
+    shrink(r):=nx_plus_y(shrink(s),cur_val,0);
+    end
+  else  begin width(r):=x_over_n(width(s),cur_val);
+    stretch(r):=x_over_n(stretch(s),cur_val);
+    shrink(r):=x_over_n(shrink(s),cur_val);
+    end;
+  cur_val:=r;
+  end;
+end
+
+@ The processing of boxes is somewhat different, because we may need
+to scan and create an entire box before we actually change the value of the old
+one.
+
+@<Assignments@>=
+set_box: begin scan_eight_bit_int;
+  if global then n:=256+cur_val@+else n:=cur_val;
+  scan_optional_equals;
+  if set_box_allowed then scan_box(box_flag+n)
+  else begin print_err("Improper "); print_esc("setbox");
+@.Improper \\setbox@>
+    help2("Sorry, \setbox is not allowed after \halign in a display,")@/
+    ("or between \accent and an accented character."); error;
+    end;
+  end;
+
+@ The |space_factor| or |prev_depth| settings are changed when a |set_aux|
+command is sensed. Similarly, |prev_graf| is changed in the presence of
+|set_prev_graf|, and |dead_cycles| or |insert_penalties| in the presence of
+|set_page_int|. These definitions are always global.
+
+When some dimension of a box register is changed, the change isn't exactly
+global; but \TeX\ does not look at the \.{\\global} switch.
+
+@<Assignments@>=
+set_aux:alter_aux;
+set_prev_graf:alter_prev_graf;
+set_page_dimen:alter_page_so_far;
+set_page_int:alter_integer;
+set_box_dimen:alter_box_dimen;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+procedure alter_aux;
+var c:halfword; {|hmode| or |vmode|}
+begin if cur_chr<>abs(mode) then report_illegal_case
+else  begin c:=cur_chr; scan_optional_equals;
+  if c=vmode then
+    begin scan_normal_dimen; prev_depth:=cur_val;
+    end
+  else  begin scan_int;
+    if (cur_val<=0)or(cur_val>32767) then
+      begin print_err("Bad space factor");
+@.Bad space factor@>
+      help1("I allow only values in the range 1..32767 here.");
+      int_error(cur_val);
+      end
+    else space_factor:=cur_val;
+    end;
+  end;
+end;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+procedure alter_prev_graf;
+var p:0..nest_size; {index into |nest|}
+begin nest[nest_ptr]:=cur_list; p:=nest_ptr;
+while abs(nest[p].mode_field)<>vmode do decr(p);
+scan_optional_equals; scan_int;
+if cur_val<0 then
+  begin print_err("Bad "); print_esc("prevgraf");
+@.Bad \\prevgraf@>
+  help1("I allow only nonnegative values here.");
+  int_error(cur_val);
+  end
+else  begin nest[p].pg_field:=cur_val; cur_list:=nest[nest_ptr];
+  end;
+end;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+procedure alter_page_so_far;
+var c:0..7; {index into |page_so_far|}
+begin c:=cur_chr; scan_optional_equals; scan_normal_dimen;
+page_so_far[c]:=cur_val;
+end;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+procedure alter_integer;
+var c:0..1; {0 for \.{\\deadcycles}, 1 for \.{\\insertpenalties}}
+begin c:=cur_chr; scan_optional_equals; scan_int;
+if c=0 then dead_cycles:=cur_val
+else insert_penalties:=cur_val;
+end;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+procedure alter_box_dimen;
+var c:small_number; {|width_offset| or |height_offset| or |depth_offset|}
+@!p,q:pointer; {temporary registers}
+@!b:eight_bits; {box number}
+begin c:=cur_chr; scan_eight_bit_int; b:=cur_val; scan_optional_equals;
+scan_normal_dimen;
+if box(b)<>null then
+  begin q:=box(b); p:=link(q);
+  while p<>null do
+    begin if abs(direction)=box_dir(p) then q:=p;
+    p:=link(p);
+    end;
+  if box_dir(q)<>abs(direction) then
+    begin p:=link(box(b)); link(box(b)):=null;
+    q:=new_dir_node(q,abs(direction)); list_ptr(q):=null;
+    link(q):=p; link(box(b)):=q;
+    end;
+    mem[q+c].sc:=cur_val;
+  end;
+end;
+
+@ Paragraph shapes are set up in the obvious way.
+
+@<Assignments@>=
+set_shape: begin scan_optional_equals; scan_int; n:=cur_val;
+  if n<=0 then p:=null
+  else  begin p:=get_node(2*n+1); info(p):=n;
+    for j:=1 to n do
+      begin scan_normal_dimen;
+      mem[p+2*j-1].sc:=cur_val; {indentation}
+      scan_normal_dimen;
+      mem[p+2*j].sc:=cur_val; {width}
+      end;
+    end;
+  define(par_shape_loc,shape_ref,p);
+  end;
+
+@ Here's something that isn't quite so obvious. It guarantees that
+|info(par_shape_ptr)| can hold any positive~|n| for which |get_node(2*n+1)|
+doesn't overflow the memory capacity.
+
+@<Check the ``constant''...@>=
+if 2*max_halfword<mem_top-mem_min then bad:=41;
+
+@ New hyphenation data is loaded by the |hyph_data| command.
+
+@<Put each...@>=
+primitive("hyphenation",hyph_data,0);
+@!@:hyphenation_}{\.{\\hyphenation} primitive@>
+primitive("patterns",hyph_data,1);
+@!@:patterns_}{\.{\\patterns} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+hyph_data: if chr_code=1 then print_esc("patterns")
+  else print_esc("hyphenation");
+
+@ @<Assignments@>=
+hyph_data: if cur_chr=1 then
+    begin @!Init new_patterns; goto done;@;@+Tini@/
+    print_err("Patterns can be loaded only by INITEX");
+@.Patterns can be...@>
+    help0; error;
+    repeat get_token; until cur_cmd=right_brace; {flush the patterns}
+    return;
+    end
+  else  begin new_hyph_exceptions; goto done;
+    end;
+
+@ All of \TeX's parameters are kept in |eqtb| except the font information,
+the interaction mode, and the hyphenation tables; these are strictly global.
+
+@<Assignments@>=
+assign_font_dimen: begin find_font_dimen(true); k:=cur_val;
+  scan_optional_equals; scan_normal_dimen; font_info[k].sc:=cur_val;
+  end;
+assign_font_int: begin n:=cur_chr; scan_font_ident; f:=cur_val;
+  scan_optional_equals; scan_int;
+  if n=0 then hyphen_char[f]:=cur_val@+else skew_char[f]:=cur_val;
+  end;
+
+@ @<Put each...@>=
+primitive("hyphenchar",assign_font_int,0);
+@!@:hyphen_char_}{\.{\\hyphenchar} primitive@>
+primitive("skewchar",assign_font_int,1);
+@!@:skew_char_}{\.{\\skewchar} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+assign_font_int: if chr_code=0 then print_esc("hyphenchar")
+  else print_esc("skewchar");
+
+@ Here is where the information for a new font gets loaded.
+
+@<Assignments@>=
+def_tfont,def_jfont,def_font: new_font(a);
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+procedure new_font(@!a:small_number);
+label common_ending;
+var u:pointer; {user's font identifier}
+@!s:scaled; {stated ``at'' size, or negative of scaled magnification}
+@!f:internal_font_number; {runs through existing fonts}
+@!t:str_number; {name for the frozen font identifier}
+@!old_setting:0..max_selector; {holds |selector| setting}
+begin if job_name=0 then open_log_file;
+  {avoid confusing \.{texput} with the font name}
+@.texput@>
+get_r_token; u:=cur_cs;
+if u>=hash_base then t:=text(u)
+else if u>=single_base then
+  if u=null_cs then t:="FONT"@+else t:=u-single_base
+else  begin old_setting:=selector; selector:=new_string;
+  print("FONT"); print(u-active_base); selector:=old_setting;
+@.FONTx@>
+  str_room(1); t:=make_string;
+  end;
+define(u,set_font,null_font); scan_optional_equals; scan_file_name;
+@<Scan the font size specification@>;
+@<If this font has already been loaded, set |f| to the internal
+  font number and |goto common_ending|@>;
+f:=read_font_info(u,cur_name,cur_area,s);
+common_ending: equiv(u):=f; eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t;
+end;
+
+@ @<Scan the font size specification@>=
+name_in_progress:=true; {this keeps |cur_name| from being changed}
+if scan_keyword("at") then @<Put the \(p)(positive) `at' size into |s|@>
+@.at@>
+else if scan_keyword("scaled") then
+@.scaled@>
+  begin scan_int; s:=-cur_val;
+  if (cur_val<=0)or(cur_val>32768) then
+    begin print_err("Illegal magnification has been changed to 1000");@/
+@.Illegal magnification...@>
+    help1("The magnification ratio must be between 1 and 32768.");
+    int_error(cur_val); s:=-1000;
+    end;
+  end
+else s:=-1000;
+name_in_progress:=false
+
+@ @<Put the \(p)(positive) `at' size into |s|@>=
+begin scan_normal_dimen; s:=cur_val;
+if (s<=0)or(s>=@'1000000000) then
+  begin print_err("Improper `at' size (");
+  print_scaled(s); print("pt), replaced by 10pt");
+@.Improper `at' size...@>
+  help2("I can only handle fonts at positive sizes that are")@/
+  ("less than 2048pt, so I've changed what you said to 10pt.");
+  error; s:=10*unity;
+  end;
+end
+
+@ When the user gives a new identifier to a font that was previously loaded,
+the new name becomes the font identifier of record. Font names `\.{xyz}' and
+`\.{XYZ}' are considered to be different.
+
+@<If this font has already been loaded...@>=
+for f:=font_base+1 to font_ptr do
+  if str_eq_str(font_name[f],cur_name)and str_eq_str(font_area[f],cur_area) then
+    begin if s>0 then
+      begin if s=font_size[f] then goto common_ending;
+      end
+    else if font_size[f]=xn_over_d(font_dsize[f],-s,1000) then
+      goto common_ending;
+    end
+
+@ @<Cases of |print_cmd_chr|...@>=
+set_font:begin print("select font "); slow_print(font_name[chr_code]);
+  if font_size[chr_code]<>font_dsize[chr_code] then
+    begin print(" at "); print_scaled(font_size[chr_code]);
+    print("pt");
+    end;
+  end;
+
+@ @<Put each...@>=
+primitive("batchmode",set_interaction,batch_mode);
+@!@:batch_mode_}{\.{\\batchmode} primitive@>
+primitive("nonstopmode",set_interaction,nonstop_mode);
+@!@:nonstop_mode_}{\.{\\nonstopmode} primitive@>
+primitive("scrollmode",set_interaction,scroll_mode);
+@!@:scroll_mode_}{\.{\\scrollmode} primitive@>
+primitive("errorstopmode",set_interaction,error_stop_mode);
+@!@:error_stop_mode_}{\.{\\errorstopmode} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+set_interaction: case chr_code of
+  batch_mode: print_esc("batchmode");
+  nonstop_mode: print_esc("nonstopmode");
+  scroll_mode: print_esc("scrollmode");
+  othercases print_esc("errorstopmode")
+  endcases;
+
+@ @<Assignments@>=
+set_interaction: new_interaction;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+procedure new_interaction;
+begin print_ln;
+interaction:=cur_chr;
+if interaction = batch_mode
+then kpse_make_tex_discard_errors := 1
+else kpse_make_tex_discard_errors := 0;
+@<Initialize the print |selector| based on |interaction|@>;
+if log_opened then selector:=selector+2;
+end;
+
+@ The \.{\\afterassignment} command puts a token into the global
+variable |after_token|. This global variable is examined just after
+every assignment has been performed.
+
+@<Glob...@>=
+@!after_token:halfword; {zero, or a saved token}
+
+@ @<Set init...@>=
+after_token:=0;
+
+@ @<Cases of |main_control| that don't...@>=
+any_mode(after_assignment):begin get_token; after_token:=cur_tok;
+  end;
+
+@ @<Insert a token saved by \.{\\afterassignment}, if any@>=
+if after_token<>0 then
+  begin cur_tok:=after_token; back_input; after_token:=0;
+  end
+
+@ Here is a procedure that might be called `Get the next non-blank non-relax
+non-call non-assignment token'.
+
+@<Declare act...@>=
+procedure do_assignments;
+label exit;
+begin loop begin @<Get the next non-blank non-relax...@>;
+  if cur_cmd<=max_non_prefixed_command then return;
+  set_box_allowed:=false; prefixed_command; set_box_allowed:=true;
+  end;
+exit:end;
+
+@ @<Cases of |main_control| that don't...@>=
+any_mode(after_group):begin get_token; save_for_after(cur_tok);
+  end;
+
+@ Files for \.{\\read} are opened and closed by the |in_stream| command.
+
+@<Put each...@>=
+primitive("openin",in_stream,1);
+@!@:open_in_}{\.{\\openin} primitive@>
+primitive("closein",in_stream,0);
+@!@:close_in_}{\.{\\closein} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+in_stream: if chr_code=0 then print_esc("closein")
+  else print_esc("openin");
+
+@ @<Cases of |main_control| that don't...@>=
+any_mode(in_stream): open_or_close_in;
+
+@ @<Declare act...@>=
+procedure open_or_close_in;
+var c:0..1; {1 for \.{\\openin}, 0 for \.{\\closein}}
+@!n:0..15; {stream number}
+begin c:=cur_chr; scan_four_bit_int; n:=cur_val;
+if read_open[n]<>closed then
+  begin a_close(read_file[n]); read_open[n]:=closed;
+  end;
+if c<>0 then
+  begin scan_optional_equals; scan_file_name;
+  pack_cur_name;
+  tex_input_type:=0; {Tell |open_input| we are \.{\\openin}.}
+  if kpse_in_name_ok(stringcast(name_of_file+1))
+     and a_open_in(read_file[n], kpse_tex_format) then
+    read_open[n]:=just_open;
+  end;
+end;
+
+@ The user can issue messages to the terminal, regardless of the
+current mode.
+
+@<Cases of |main_control| that don't...@>=
+any_mode(message):issue_message;
+
+@ @<Put each...@>=
+primitive("message",message,0);
+@!@:message_}{\.{\\message} primitive@>
+primitive("errmessage",message,1);
+@!@:err_message_}{\.{\\errmessage} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+message: if chr_code=0 then print_esc("message")
+  else print_esc("errmessage");
+
+@ @<Declare act...@>=
+procedure issue_message;
+var old_setting:0..max_selector; {holds |selector| setting}
+@!c:0..1; {identifies \.{\\message} and \.{\\errmessage}}
+@!s:str_number; {the message}
+begin c:=cur_chr; link(garbage):=scan_toks(false,true);
+old_setting:=selector; selector:=new_string;
+token_show(def_ref); selector:=old_setting;
+flush_list(def_ref);
+str_room(1); s:=make_string;
+if c=0 then @<Print string |s| on the terminal@>
+else @<Print string |s| as an error message@>;
+flush_string;
+end;
+
+@ @<Print string |s| on the terminal@>=
+begin if term_offset+length(s)>max_print_line-2 then print_ln
+else if (term_offset>0)or(file_offset>0) then print_char(" ");
+slow_print(s); update_terminal;
+end
+
+@ If \.{\\errmessage} occurs often in |scroll_mode|, without user-defined
+\.{\\errhelp}, we don't want to give a long help message each time. So we
+give a verbose explanation only once.
+
+@<Glob...@>=
+@!long_help_seen:boolean; {has the long \.{\\errmessage} help been used?}
+
+@ @<Set init...@>=long_help_seen:=false;
+
+@ @<Print string |s| as an error message@>=
+begin print_err(""); slow_print(s);
+if err_help<>null then use_err_help:=true
+else if long_help_seen then help1("(That was another \errmessage.)")
+else  begin if interaction<error_stop_mode then long_help_seen:=true;
+  help4("This error message was generated by an \errmessage")@/
+  ("command, so I can't give any explicit help.")@/
+  ("Pretend that you're Hercule Poirot: Examine all clues,")@/
+@^Poirot, Hercule@>
+  ("and deduce the truth by order and method.");
+  end;
+error; use_err_help:=false;
+end
+
+@ The |error| routine calls on |give_err_help| if help is requested from
+the |err_help| parameter.
+
+@p procedure give_err_help;
+begin token_show(err_help);
+end;
+
+@ The \.{\\uppercase} and \.{\\lowercase} commands are implemented by
+building a token list and then changing the cases of the letters in it.
+
+@<Cases of |main_control| that don't...@>=
+any_mode(case_shift):shift_case;
+
+@ @<Put each...@>=
+primitive("lowercase",case_shift,lc_code_base);
+@!@:lowercase_}{\.{\\lowercase} primitive@>
+primitive("uppercase",case_shift,uc_code_base);
+@!@:uppercase_}{\.{\\uppercase} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case_shift:if chr_code=lc_code_base then print_esc("lowercase")
+  else print_esc("uppercase");
+
+@ @<Declare act...@>=
+procedure shift_case;
+var b:pointer; {|lc_code_base| or |uc_code_base|}
+@!p:pointer; {runs through the token list}
+@!t:halfword; {token}
+@!c:eight_bits; {character code}
+begin b:=cur_chr; p:=scan_toks(false,false); p:=link(def_ref);
+while p<>null do
+  begin @<Change the case of the token in |p|, if a change is appropriate@>;
+  p:=link(p);
+  end;
+back_list(link(def_ref)); free_avail(def_ref); {omit reference count}
+end;
+
+@ When the case of a |chr_code| changes, we don't change the |cmd|.
+We also change active characters, using the fact that
+|cs_token_flag+active_base| is a multiple of~256.
+@^data structure assumptions@>
+
+@<Change the case of the token in |p|, if a change is appropriate@>=
+t:=info(p);
+if (t<cs_token_flag+single_base)and(not check_kanji(t)) then
+  begin c:=t mod 256;
+  if equiv(b+c)<>0 then info(p):=t-c+equiv(b+c);
+  end
+
+@ We come finally to the last pieces missing from |main_control|, namely the
+`\.{\\show}' commands that are useful when debugging.
+
+@<Cases of |main_control| that don't...@>=
+any_mode(xray): show_whatever;
+
+@ @d show_code=0 { \.{\\show} }
+@d show_box_code=1 { \.{\\showbox} }
+@d show_the_code=2 { \.{\\showthe} }
+@d show_lists=3 { \.{\\showlists} }
+@d show_mode=4 { \.{\\showmode} }
+
+@<Put each...@>=
+primitive("show",xray,show_code);
+@!@:show_}{\.{\\show} primitive@>
+primitive("showbox",xray,show_box_code);
+@!@:show_box_}{\.{\\showbox} primitive@>
+primitive("showthe",xray,show_the_code);
+@!@:show_the_}{\.{\\showthe} primitive@>
+primitive("showlists",xray,show_lists);
+@!@:show_lists_}{\.{\\showlists} primitive@>
+primitive("showmode",xray,show_mode);
+@!@:show_mode_}{\.{\\showmode} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+xray: case chr_code of
+  show_box_code:print_esc("showbox");
+  show_the_code:print_esc("showthe");
+  show_lists:print_esc("showlists");
+  show_mode:print_esc("showmode");
+  othercases print_esc("show")
+  endcases;
+
+@ @<Declare act...@>=
+procedure show_whatever;
+label common_ending;
+var p:pointer; {tail of a token list to show}
+begin case cur_chr of
+show_lists: begin begin_diagnostic; show_activities;
+  end;
+show_box_code: @<Show the current contents of a box@>;
+show_code: @<Show the current meaning of a token, then |goto common_ending|@>;
+show_mode: @<Show the current japanese processing mode@>;
+othercases @<Show the current value of some parameter or register,
+  then |goto common_ending|@>
+endcases;@/
+@<Complete a potentially long \.{\\show} command@>;
+common_ending: if interaction<error_stop_mode then
+  begin help0; decr(error_count);
+  end
+else if tracing_online>0 then
+  begin@t@>@;@/
+  help3("This isn't an error message; I'm just \showing something.")@/
+  ("Type `I\show...' to show more (e.g., \show\cs,")@/
+  ("\showthe\count10, \showbox255, \showlists).");
+  end
+else  begin@t@>@;@/
+  help5("This isn't an error message; I'm just \showing something.")@/
+  ("Type `I\show...' to show more (e.g., \show\cs,")@/
+  ("\showthe\count10, \showbox255, \showlists).")@/
+  ("And type `I\tracingonline=1\show...' to show boxes and")@/
+  ("lists on your terminal as well as in the transcript file.");
+  end;
+error;
+end;
+
+@ @<Show the current meaning of a token...@>=
+begin get_token;
+if interaction=error_stop_mode then wake_up_terminal;
+print_nl("> ");
+if cur_cs<>0 then
+  begin sprint_cs(cur_cs); print_char("=");
+  end;
+print_meaning; goto common_ending;
+end
+
+@ @<Cases of |print_cmd_chr|...@>=
+undefined_cs: print("undefined");
+call: print("macro");
+long_call: print_esc("long macro");
+outer_call: print_esc("outer macro");
+long_outer_call: begin print_esc("long"); print_esc("outer macro");
+  end;
+end_template: print_esc("outer endtemplate");
+
+@ @<Show the current contents of a box@>=
+begin scan_eight_bit_int; begin_diagnostic;
+print_nl("> \box"); print_int(cur_val); print_char("=");
+if box(cur_val)=null then print("void")
+else show_box(box(cur_val));
+end
+
+@ @<Show the current value of some parameter...@>=
+begin p:=the_toks;
+if interaction=error_stop_mode then wake_up_terminal;
+print_nl("> "); token_show(temp_head);
+flush_list(link(temp_head)); goto common_ending;
+end
+
+@ @<Complete a potentially long \.{\\show} command@>=
+end_diagnostic(true); print_err("OK");
+@.OK@>
+if selector=term_and_log then if tracing_online<=0 then
+  begin selector:=term_only; print(" (see the transcript file)");
+  selector:=term_and_log;
+  end
+
+@* \[50] Dumping and undumping the tables.
+After \.{INITEX} has seen a collection of fonts and macros, it
+can write all the necessary information on an auxiliary file so
+that production versions of \TeX\ are able to initialize their
+memory at high speed. The present section of the program takes
+care of such output and input. We shall consider simultaneously
+the processes of storing and restoring,
+so that the inverse relation between them is clear.
+@.INITEX@>
+
+The global variable |format_ident| is a string that is printed right
+after the |banner| line when \TeX\ is ready to start. For \.{INITEX} this
+string says simply `\.{(INITEX)}'; for other versions of \TeX\ it says,
+for example, `\.{(preloaded format=plain 1982.11.19)}', showing the year,
+month, and day that the format file was created. We have |format_ident=0|
+before \TeX's tables are loaded.
+
+@<Glob...@>=
+@!format_ident:str_number;
+
+@ @<Set init...@>=
+format_ident:=0;
+
+@ @<Initialize table entries...@>=
+if ini_version then format_ident:=" (INITEX)";
+
+@ @<Declare act...@>=
+@!init procedure store_fmt_file;
+label found1,found2,done1,done2;
+var j,@!k,@!l:integer; {all-purpose indices}
+@!p,@!q: pointer; {all-purpose pointers}
+@!x: integer; {something to dump}
+@!format_engine: ^text_char;
+begin @<If dumping is not allowed, abort@>;
+@<Create the |format_ident|, open the format file,
+  and inform the user that dumping has begun@>;
+@<Dump constants for consistency check@>;
+@<Dump ML\TeX-specific data@>;
+@<Dump the string pool@>;
+@<Dump the dynamic memory@>;
+@<Dump the table of equivalents@>;
+@<Dump the font information@>;
+@<Dump the hyphenation tables@>;
+@<Dump a couple more things and the closing check word@>;
+@<Close the format file@>;
+end;
+tini
+
+@ Corresponding to the procedure that dumps a format file, we have a function
+that reads one in. The function returns |false| if the dumped format is
+incompatible with the present \TeX\ table sizes, etc.
+
+@d bad_fmt=6666 {go here if the format file is unacceptable}
+@d too_small(#)==begin wake_up_terminal;
+  wterm_ln('---! Must increase the ',#);
+@.Must increase the x@>
+  goto bad_fmt;
+  end
+
+@p @t\4@>@<Declare the function called |open_fmt_file|@>@;
+function load_fmt_file:boolean;
+label bad_fmt,exit;
+var j,@!k:integer; {all-purpose indices}
+@!p,@!q: pointer; {all-purpose pointers}
+@!x: integer; {something undumped}
+@!format_engine: ^text_char;
+@!dummy_xord: ASCII_code;
+@!dummy_xchr: text_char;
+@!dummy_xprn: ASCII_code;
+begin @<Undump constants for consistency check@>;
+@<Undump ML\TeX-specific data@>;
+@<Undump the string pool@>;
+@<Undump the dynamic memory@>;
+@<Undump the table of equivalents@>;
+@<Undump the font information@>;
+@<Undump the hyphenation tables@>;
+@<Undump a couple more things and the closing check word@>;
+load_fmt_file:=true; return; {it worked!}
+bad_fmt: wake_up_terminal;
+  wterm_ln('(Fatal format file error; I''m stymied)');
+@.Fatal format file error@>
+load_fmt_file:=false;
+exit:end;
+
+@ The user is not allowed to dump a format file unless |save_ptr=0|.
+This condition implies that |cur_level=level_one|, hence
+the |xeq_level| array is constant and it need not be dumped.
+
+@<If dumping is not allowed, abort@>=
+if save_ptr<>0 then
+  begin print_err("You can't dump inside a group");
+@.You can't dump...@>
+  help1("`{...\dump}' is a no-no."); succumb;
+  end
+
+@ Format files consist of |memory_word| items, and we use the following
+macros to dump words of different types:
+
+
+@<Glob...@>=
+@!fmt_file:word_file; {for input or output of format information}
+
+@ The inverse macros are slightly more complicated, since we need to check
+the range of the values we are reading in. We say `|undump(a)(b)(x)|' to
+read an integer value |x| that is supposed to be in the range |a<=x<=b|.
+
+@d undump_end_end(#)==#:=x;@+end
+@d undump_end(#)==(x>#) then goto bad_fmt@+else undump_end_end
+@d undump(#)==begin undump_int(x); if (x<#) or undump_end
+@d format_debug_end(#)==
+    write_ln (stderr, ' = ', #);
+  end;
+@d format_debug(#)==
+  if debug_format_file then begin
+    write (stderr, 'fmtdebug:', #);
+    format_debug_end
+@d undump_size_end_end(#)==
+  too_small(#)@+else format_debug (#)(x); undump_end_end
+@d undump_size_end(#)==if x># then undump_size_end_end
+@d undump_size(#)==begin undump_int(x);
+  if x<# then goto bad_fmt; undump_size_end
+
+@ The next few sections of the program should make it clear how we use the
+dump/undump macros.
+
+@<Dump constants for consistency check@>=
+dump_int(@"57325458);  {Web2C \TeX's magic constant: "W2TX"}
+{Align engine to 4 bytes with one or more trailing NUL}
+x:=strlen(engine_name);
+format_engine:=xmalloc_array(text_char,x+4);
+strcpy(stringcast(format_engine), engine_name);
+for k:=x to x+3 do format_engine[k]:=0;
+x:=x+4-(x mod 4);
+dump_int(x);dump_things(format_engine[0], x);
+libc_free(format_engine);@/
+dump_int(@$);@/
+@<Dump |xord|, |xchr|, and |xprn|@>;
+dump_int(max_halfword);@/
+dump_int(hash_high);
+dump_int(mem_bot);@/
+dump_int(mem_top);@/
+dump_int(eqtb_size);@/
+dump_int(hash_prime);@/
+dump_int(hyph_prime)
+
+@ Sections of a \.{WEB} program that are ``commented out'' still contribute
+strings to the string pool; therefore \.{INITEX} and \TeX\ will have
+the same strings. (And it is, of course, a good thing that they do.)
+@.WEB@>
+@^string pool@>
+
+@<Undump constants for consistency check@>=
+@+Init
+libc_free(font_info); libc_free(str_pool); libc_free(str_start);
+libc_free(yhash); libc_free(zeqtb); libc_free(yzmem);
+@+Tini
+undump_int(x);
+format_debug('format magic number')(x);
+if x<>@"57325458 then goto bad_fmt; {not a format file}
+undump_int(x);
+format_debug('engine name size')(x);
+if (x<0) or (x>256) then goto bad_fmt; {corrupted format file}
+format_engine:=xmalloc_array(text_char, x);
+undump_things(format_engine[0], x);
+format_engine[x-1]:=0; {force string termination, just in case}
+if strcmp(engine_name, stringcast(format_engine)) then
+  begin wake_up_terminal;
+  wterm_ln('---! ', stringcast(name_of_file+1), ' was written by ', format_engine);
+  libc_free(format_engine);
+  goto bad_fmt;
+end;
+libc_free(format_engine);
+undump_int(x);
+format_debug('string pool checksum')(x);
+if x<>@$ then begin {check that strings are the same}
+  wake_up_terminal;
+  wterm_ln('---! ', stringcast(name_of_file+1), ' doesn''t match ', pool_name);
+  goto bad_fmt;
+end;
+@<Undump |xord|, |xchr|, and |xprn|@>;
+undump_int(x);
+if x<>max_halfword then goto bad_fmt; {check |max_halfword|}
+undump_int(hash_high);
+  if (hash_high<0)or(hash_high>sup_hash_extra) then goto bad_fmt;
+  if hash_extra<hash_high then hash_extra:=hash_high;
+  eqtb_top:=eqtb_size+hash_extra;
+  if hash_extra=0 then hash_top:=undefined_control_sequence else
+        hash_top:=eqtb_top;
+  yhash:=xmalloc_array(two_halves,1+hash_top-hash_offset);
+  hash:=yhash - hash_offset;
+  next(hash_base):=0; text(hash_base):=0;
+  for x:=hash_base+1 to hash_top do hash[x]:=hash[hash_base];
+  zeqtb:=xmalloc_array (memory_word,eqtb_top+1);
+  eqtb:=zeqtb;
+
+  eq_type(undefined_control_sequence):=undefined_cs;
+  equiv(undefined_control_sequence):=null;
+  eq_level(undefined_control_sequence):=level_zero;
+  for x:=eqtb_size+1 to eqtb_top do
+    eqtb[x]:=eqtb[undefined_control_sequence];
+undump_int(x); format_debug ('mem_bot')(x);
+if x<>mem_bot then goto bad_fmt;
+undump_int(mem_top); format_debug ('mem_top')(mem_top);
+if mem_bot+1100>mem_top then goto bad_fmt;
+
+
+head:=contrib_head; tail:=contrib_head;
+     page_tail:=page_head;  {page initialization}
+
+mem_min := mem_bot - extra_mem_bot;
+mem_max := mem_top + extra_mem_top;
+
+yzmem:=xmalloc_array (memory_word, mem_max - mem_min + 1);
+zmem := yzmem - mem_min;   {this pointer arithmetic fails with some compilers}
+mem := zmem;
+undump_int(x);
+if x<>eqtb_size then goto bad_fmt;
+undump_int(x);
+if x<>hash_prime then goto bad_fmt;
+undump_int(x);
+if x<>hyph_prime then goto bad_fmt
+
+@ @d dump_four_ASCII==
+  w.b0:=qi(so(str_pool[k])); w.b1:=qi(so(str_pool[k+1]));
+  w.b2:=qi(so(str_pool[k+2])); w.b3:=qi(so(str_pool[k+3]));
+  dump_qqqq(w)
+
+@<Dump the string pool@>=
+dump_int(pool_ptr);
+dump_int(str_ptr);
+dump_things(str_start[0], str_ptr+1);
+dump_things(str_pool[0], pool_ptr);
+print_ln; print_int(str_ptr); print(" strings of total length ");
+print_int(pool_ptr)
+
+@ @d undump_four_ASCII==
+  undump_qqqq(w);
+  str_pool[k]:=si(qo(w.b0)); str_pool[k+1]:=si(qo(w.b1));
+  str_pool[k+2]:=si(qo(w.b2)); str_pool[k+3]:=si(qo(w.b3))
+
+@<Undump the string pool@>=
+undump_size(0)(sup_pool_size-pool_free)('string pool size')(pool_ptr);
+if pool_size<pool_ptr+pool_free then
+  pool_size:=pool_ptr+pool_free;
+undump_size(0)(sup_max_strings-strings_free)('sup strings')(str_ptr);@/
+if max_strings<str_ptr+strings_free then
+  max_strings:=str_ptr+strings_free;
+str_start:=xmalloc_array(pool_pointer, max_strings);
+undump_checked_things(0, pool_ptr, str_start[0], str_ptr+1);@/
+str_pool:=xmalloc_array(packed_ASCII_code, pool_size);
+undump_things(str_pool[0], pool_ptr);
+init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr
+
+@ By sorting the list of available spaces in the variable-size portion of
+|mem|, we are usually able to get by without having to dump very much
+of the dynamic memory.
+
+We recompute |var_used| and |dyn_used|, so that \.{INITEX} dumps valid
+information even when it has not been gathering statistics.
+
+@<Dump the dynamic memory@>=
+sort_avail; var_used:=0;
+dump_int(lo_mem_max); dump_int(rover);
+p:=mem_bot; q:=rover; x:=0;
+repeat dump_things(mem[p], q+2-p);
+x:=x+q+2-p; var_used:=var_used+q-p;
+p:=q+node_size(q); q:=rlink(q);
+until q=rover;
+var_used:=var_used+lo_mem_max-p; dyn_used:=mem_end+1-hi_mem_min;@/
+dump_things(mem[p], lo_mem_max+1-p);
+x:=x+lo_mem_max+1-p;
+dump_int(hi_mem_min); dump_int(avail);
+dump_things(mem[hi_mem_min], mem_end+1-hi_mem_min);
+x:=x+mem_end+1-hi_mem_min;
+p:=avail;
+while p<>null do
+  begin decr(dyn_used); p:=link(p);
+  end;
+dump_int(var_used); dump_int(dyn_used);
+print_ln; print_int(x);
+print(" memory locations dumped; current usage is ");
+print_int(var_used); print_char("&"); print_int(dyn_used)
+
+@ @<Undump the dynamic memory@>=
+undump(lo_mem_stat_max+1000)(hi_mem_stat_min-1)(lo_mem_max);
+undump(lo_mem_stat_max+1)(lo_mem_max)(rover);
+p:=mem_bot; q:=rover;
+repeat undump_things(mem[p], q+2-p);
+p:=q+node_size(q);
+if (p>lo_mem_max)or((q>=rlink(q))and(rlink(q)<>rover)) then goto bad_fmt;
+q:=rlink(q);
+until q=rover;
+undump_things(mem[p], lo_mem_max+1-p);
+if mem_min<mem_bot-2 then {make more low memory available}
+  begin p:=llink(rover); q:=mem_min+1;
+  link(mem_min):=null; info(mem_min):=null; {we don't use the bottom word}
+  rlink(p):=q; llink(rover):=q;@/
+  rlink(q):=rover; llink(q):=p; link(q):=empty_flag;
+  node_size(q):=mem_bot-q;
+  end;
+undump(lo_mem_max+1)(hi_mem_stat_min)(hi_mem_min);
+undump(null)(mem_top)(avail); mem_end:=mem_top;
+undump_things (mem[hi_mem_min], mem_end+1-hi_mem_min);
+undump_int(var_used); undump_int(dyn_used)
+
+@ @<Dump the table of equivalents@>=
+@<Dump regions 1 to 4 of |eqtb|@>;
+@<Dump regions 5 and 6 of |eqtb|@>;
+dump_int(par_loc); dump_int(write_loc);@/
+@<Dump the hash table@>
+
+@ @<Undump the table of equivalents@>=
+@<Undump regions 1 to 6 of |eqtb|@>;
+undump(hash_base)(hash_top)(par_loc);
+par_token:=cs_token_flag+par_loc;@/
+undump(hash_base)(hash_top)(write_loc);@/
+@<Undump the hash table@>
+
+@ The table of equivalents usually contains repeated information, so we dump it
+in compressed form: The sequence of $n+2$ values $(n,x_1,\ldots,x_n,m)$ in the
+format file represents $n+m$ consecutive entries of |eqtb|, with |m| extra
+copies of $x_n$, namely $(x_1,\ldots,x_n,x_n,\ldots,x_n)$.
+
+@<Dump regions 1 to 4 of |eqtb|@>=
+k:=active_base;
+repeat j:=k;
+while j<int_base-1 do
+  begin if (equiv(j)=equiv(j+1))and(eq_type(j)=eq_type(j+1))and@|
+    (eq_level(j)=eq_level(j+1)) then goto found1;
+  incr(j);
+  end;
+l:=int_base; goto done1; {|j=int_base-1|}
+found1: incr(j); l:=j;
+while j<int_base-1 do
+  begin if (equiv(j)<>equiv(j+1))or(eq_type(j)<>eq_type(j+1))or@|
+    (eq_level(j)<>eq_level(j+1)) then goto done1;
+  incr(j);
+  end;
+done1:dump_int(l-k);
+dump_things(eqtb[k], l-k);
+k:=j+1; dump_int(k-l);
+until k=int_base
+
+@ @<Dump regions 5 and 6 of |eqtb|@>=
+repeat j:=k;
+while j<eqtb_size do
+  begin if eqtb[j].int=eqtb[j+1].int then goto found2;
+  incr(j);
+  end;
+l:=eqtb_size+1; goto done2; {|j=eqtb_size|}
+found2: incr(j); l:=j;
+while j<eqtb_size do
+  begin if eqtb[j].int<>eqtb[j+1].int then goto done2;
+  incr(j);
+  end;
+done2:dump_int(l-k);
+dump_things(eqtb[k], l-k);
+k:=j+1; dump_int(k-l);
+until k>eqtb_size;
+if hash_high>0 then dump_things(eqtb[eqtb_size+1],hash_high);
+  {dump |hash_extra| part}
+
+@ @<Undump regions 1 to 6 of |eqtb|@>=
+k:=active_base;
+repeat undump_int(x);
+if (x<1)or(k+x>eqtb_size+1) then goto bad_fmt;
+undump_things(eqtb[k], x);
+k:=k+x;
+undump_int(x);
+if (x<0)or(k+x>eqtb_size+1) then goto bad_fmt;
+for j:=k to k+x-1 do eqtb[j]:=eqtb[k-1];
+k:=k+x;
+until k>eqtb_size;
+if hash_high>0 then undump_things(eqtb[eqtb_size+1],hash_high);
+  {undump |hash_extra| part}
+
+@ A different scheme is used to compress the hash table, since its lower
+region is usually sparse. When |text(p)<>0| for |p<=hash_used|, we output
+two words, |p| and |hash[p]|. The hash table is, of course, densely packed
+for |p>=hash_used|, so the remaining entries are output in a~block.
+
+@<Dump the hash table@>=
+dump_int(hash_used); cs_count:=frozen_control_sequence-1-hash_used+hash_high;
+for p:=hash_base to hash_used do if text(p)<>0 then
+  begin dump_int(p); dump_hh(hash[p]); incr(cs_count);
+  end;
+dump_things(hash[hash_used+1], undefined_control_sequence-1-hash_used);
+if hash_high>0 then dump_things(hash[eqtb_size+1], hash_high);
+dump_int(cs_count);@/
+print_ln; print_int(cs_count); print(" multiletter control sequences")
+
+@ @<Undump the hash table@>=
+undump(hash_base)(frozen_control_sequence)(hash_used); p:=hash_base-1;
+repeat undump(p+1)(hash_used)(p); undump_hh(hash[p]);
+until p=hash_used;
+undump_things (hash[hash_used+1], undefined_control_sequence-1-hash_used);
+if debug_format_file then begin
+  print_csnames (hash_base, undefined_control_sequence - 1);
+end;
+if hash_high > 0 then begin
+  undump_things (hash[eqtb_size+1], hash_high);
+  if debug_format_file then begin
+    print_csnames (eqtb_size + 1, hash_high - (eqtb_size + 1));
+  end;
+end;
+undump_int(cs_count)
+
+@ @<Dump the font information@>=
+dump_int(fmem_ptr);
+dump_things(font_info[0], fmem_ptr);
+dump_int(font_ptr);
+@<Dump the array info for internal font number |k|@>;
+print_ln; print_int(fmem_ptr-7); print(" words of font info for ");
+print_int(font_ptr-font_base);
+if font_ptr<>font_base+1 then print(" preloaded fonts")
+else print(" preloaded font")
+
+@ @<Undump the font information@>=
+undump_size(7)(sup_font_mem_size)('font mem size')(fmem_ptr);
+if fmem_ptr>font_mem_size then font_mem_size:=fmem_ptr;
+font_info:=xmalloc_array(memory_word, font_mem_size);
+undump_things(font_info[0], fmem_ptr);@/
+undump_size(font_base)(font_base+max_font_max)('font max')(font_ptr);
+{This undumps all of the font info, despite the name.}
+@<Undump the array info for internal font number |k|@>;
+
+@ @<Dump the array info for internal font number |k|@>=
+begin
+dump_things(font_dir[null_font], font_ptr+1-null_font);
+dump_things(font_num_ext[null_font], font_ptr+1-null_font);
+dump_things(font_check[null_font], font_ptr+1-null_font);
+dump_things(font_size[null_font], font_ptr+1-null_font);
+dump_things(font_dsize[null_font], font_ptr+1-null_font);
+dump_things(font_params[null_font], font_ptr+1-null_font);
+dump_things(hyphen_char[null_font], font_ptr+1-null_font);
+dump_things(skew_char[null_font], font_ptr+1-null_font);
+dump_things(font_name[null_font], font_ptr+1-null_font);
+dump_things(font_area[null_font], font_ptr+1-null_font);
+dump_things(font_bc[null_font], font_ptr+1-null_font);
+dump_things(font_ec[null_font], font_ptr+1-null_font);
+dump_things(ctype_base[null_font], font_ptr+1-null_font);
+dump_things(char_base[null_font], font_ptr+1-null_font);
+dump_things(width_base[null_font], font_ptr+1-null_font);
+dump_things(height_base[null_font], font_ptr+1-null_font);
+dump_things(depth_base[null_font], font_ptr+1-null_font);
+dump_things(italic_base[null_font], font_ptr+1-null_font);
+dump_things(lig_kern_base[null_font], font_ptr+1-null_font);
+dump_things(kern_base[null_font], font_ptr+1-null_font);
+dump_things(exten_base[null_font], font_ptr+1-null_font);
+dump_things(param_base[null_font], font_ptr+1-null_font);
+dump_things(font_glue[null_font], font_ptr+1-null_font);
+dump_things(bchar_label[null_font], font_ptr+1-null_font);
+dump_things(font_bchar[null_font], font_ptr+1-null_font);
+dump_things(font_false_bchar[null_font], font_ptr+1-null_font);
+for k:=null_font to font_ptr do
+  begin print_nl("\font"); print_esc(font_id_text(k)); print_char("=");
+  print_file_name(font_name[k],font_area[k],"");
+  if font_size[k]<>font_dsize[k] then
+    begin print(" at "); print_scaled(font_size[k]); print("pt");
+    end;
+  end;
+end
+
+@ This module should now be named `Undump all the font arrays'.
+
+@<Undump the array info for internal font number |k|@>=
+begin {Allocate the font arrays}
+font_dir:=xmalloc_array(eight_bits, font_max);
+font_num_ext:=xmalloc_array(integer, font_max);
+font_check:=xmalloc_array(four_quarters, font_max);
+font_size:=xmalloc_array(scaled, font_max);
+font_dsize:=xmalloc_array(scaled, font_max);
+font_params:=xmalloc_array(font_index, font_max);
+font_name:=xmalloc_array(str_number, font_max);
+font_area:=xmalloc_array(str_number, font_max);
+font_bc:=xmalloc_array(eight_bits, font_max);
+font_ec:=xmalloc_array(eight_bits, font_max);
+font_glue:=xmalloc_array(halfword, font_max);
+hyphen_char:=xmalloc_array(integer, font_max);
+skew_char:=xmalloc_array(integer, font_max);
+bchar_label:=xmalloc_array(font_index, font_max);
+font_bchar:=xmalloc_array(nine_bits, font_max);
+font_false_bchar:=xmalloc_array(nine_bits, font_max);
+ctype_base:=xmalloc_array(integer, font_max);
+char_base:=xmalloc_array(integer, font_max);
+width_base:=xmalloc_array(integer, font_max);
+height_base:=xmalloc_array(integer, font_max);
+depth_base:=xmalloc_array(integer, font_max);
+italic_base:=xmalloc_array(integer, font_max);
+lig_kern_base:=xmalloc_array(integer, font_max);
+kern_base:=xmalloc_array(integer, font_max);
+exten_base:=xmalloc_array(integer, font_max);
+param_base:=xmalloc_array(integer, font_max);
+
+undump_things(font_dir[null_font], font_ptr+1-null_font);
+undump_things(font_num_ext[null_font], font_ptr+1-null_font);
+undump_things(font_check[null_font], font_ptr+1-null_font);
+undump_things(font_size[null_font], font_ptr+1-null_font);
+undump_things(font_dsize[null_font], font_ptr+1-null_font);
+undump_checked_things(min_halfword, max_halfword,
+                      font_params[null_font], font_ptr+1-null_font);
+undump_things(hyphen_char[null_font], font_ptr+1-null_font);
+undump_things(skew_char[null_font], font_ptr+1-null_font);
+undump_upper_check_things(str_ptr, font_name[null_font], font_ptr+1-null_font);
+undump_upper_check_things(str_ptr, font_area[null_font], font_ptr+1-null_font);
+{There's no point in checking these values against the range $[0,255]$,
+ since the data type is |unsigned char|, and all values of that type are
+ in that range by definition.}
+undump_things(font_bc[null_font], font_ptr+1-null_font);
+undump_things(font_ec[null_font], font_ptr+1-null_font);
+undump_things(ctype_base[null_font], font_ptr+1-null_font);
+undump_things(char_base[null_font], font_ptr+1-null_font);
+undump_things(width_base[null_font], font_ptr+1-null_font);
+undump_things(height_base[null_font], font_ptr+1-null_font);
+undump_things(depth_base[null_font], font_ptr+1-null_font);
+undump_things(italic_base[null_font], font_ptr+1-null_font);
+undump_things(lig_kern_base[null_font], font_ptr+1-null_font);
+undump_things(kern_base[null_font], font_ptr+1-null_font);
+undump_things(exten_base[null_font], font_ptr+1-null_font);
+undump_things(param_base[null_font], font_ptr+1-null_font);
+undump_checked_things(min_halfword, lo_mem_max,
+                     font_glue[null_font], font_ptr+1-null_font);
+undump_checked_things(0, fmem_ptr-1,
+                     bchar_label[null_font], font_ptr+1-null_font);
+undump_checked_things(min_quarterword, non_char,
+                     font_bchar[null_font], font_ptr+1-null_font);
+undump_checked_things(min_quarterword, non_char,
+                     font_false_bchar[null_font], font_ptr+1-null_font);
+end
+
+@ @<Dump the hyphenation tables@>=
+dump_int(hyph_count);
+if hyph_next <= hyph_prime then hyph_next:=hyph_size;
+dump_int(hyph_next);{minumum value of |hyphen_size| needed}
+for k:=0 to hyph_size do if hyph_word[k]<>0 then
+  begin dump_int(k+65536*hyph_link[k]);
+        {assumes number of hyphen exceptions does not exceed 65535}
+   dump_int(hyph_word[k]); dump_int(hyph_list[k]);
+  end;
+print_ln; print_int(hyph_count);
+if hyph_count<>1 then print(" hyphenation exceptions")
+else print(" hyphenation exception");
+if trie_not_ready then init_trie;
+dump_int(trie_max);
+dump_things(trie_trl[0], trie_max+1);
+dump_things(trie_tro[0], trie_max+1);
+dump_things(trie_trc[0], trie_max+1);
+dump_int(trie_op_ptr);
+dump_things(hyf_distance[1], trie_op_ptr);
+dump_things(hyf_num[1], trie_op_ptr);
+dump_things(hyf_next[1], trie_op_ptr);
+print_nl("Hyphenation trie of length "); print_int(trie_max);
+@.Hyphenation trie...@>
+print(" has "); print_int(trie_op_ptr);
+if trie_op_ptr<>1 then print(" ops")
+else print(" op");
+print(" out of "); print_int(trie_op_size);
+for k:=255 downto 0 do if trie_used[k]>min_quarterword then
+  begin print_nl("  "); print_int(qo(trie_used[k]));
+  print(" for language "); print_int(k);
+  dump_int(k); dump_int(qo(trie_used[k]));
+  end
+
+@ Only ``nonempty'' parts of |op_start| need to be restored.
+
+@<Undump the hyphenation tables@>=
+undump_size(0)(hyph_size)('hyph_size')(hyph_count);
+undump_size(hyph_prime)(hyph_size)('hyph_size')(hyph_next);
+j:=0;
+for k:=1 to hyph_count do
+  begin undump_int(j); if j<0 then goto bad_fmt;
+   if j>65535 then
+   begin hyph_next:= j div 65536; j:=j - hyph_next * 65536; end
+       else hyph_next:=0;
+   if (j>=hyph_size)or(hyph_next>hyph_size) then goto bad_fmt;
+   hyph_link[j]:=hyph_next;
+  undump(0)(str_ptr)(hyph_word[j]);
+  undump(min_halfword)(max_halfword)(hyph_list[j]);
+  end;
+  {|j| is now the largest occupied location in |hyph_word|}
+  incr(j);
+  if j<hyph_prime then j:=hyph_prime;
+  hyph_next:=j;
+  if hyph_next >= hyph_size then hyph_next:=hyph_prime else
+  if hyph_next >= hyph_prime then incr(hyph_next);
+undump_size(0)(trie_size)('trie size')(j); @+init trie_max:=j;@+tini
+{These first three haven't been allocated yet unless we're \.{INITEX};
+ we do that precisely so we don't allocate more space than necessary.}
+if not trie_trl then trie_trl:=xmalloc_array(trie_pointer,j+1);
+undump_things(trie_trl[0], j+1);
+if not trie_tro then trie_tro:=xmalloc_array(trie_pointer,j+1);
+undump_things(trie_tro[0], j+1);
+if not trie_trc then trie_trc:=xmalloc_array(quarterword, j+1);
+undump_things(trie_trc[0], j+1);
+undump_size(0)(trie_op_size)('trie op size')(j); @+init trie_op_ptr:=j;@+tini
+{I'm not sure we have such a strict limitation (64) on these values, so
+ let's leave them unchecked.}
+undump_things(hyf_distance[1], j);
+undump_things(hyf_num[1], j);
+undump_upper_check_things(max_trie_op, hyf_next[1], j);
+init for k:=0 to 255 do trie_used[k]:=min_quarterword;@+tini@;@/
+k:=256;
+while j>0 do
+  begin undump(0)(k-1)(k); undump(1)(j)(x);@+init trie_used[k]:=qi(x);@+tini@;@/
+  j:=j-x; op_start[k]:=qo(j);
+  end;
+@!init trie_not_ready:=false @+tini
+
+@ We have already printed a lot of statistics, so we set |tracing_stats:=0|
+to prevent them from appearing again.
+
+@<Dump a couple more things and the closing check word@>=
+dump_int(interaction); dump_int(format_ident); dump_int(69069);
+tracing_stats:=0
+
+@ @<Undump a couple more things and the closing check word@>=
+undump(batch_mode)(error_stop_mode)(interaction);
+if interaction_option<>unspecified_mode then interaction:=interaction_option;
+undump(0)(str_ptr)(format_ident);
+undump_int(x);
+if x<>69069 then goto bad_fmt
+
+@ @<Create the |format_ident|...@>=
+selector:=new_string;
+print(" (format="); print(job_name); print_char(" ");
+print_int(year); print_char(".");
+print_int(month); print_char("."); print_int(day); print_char(")");
+if interaction=batch_mode then selector:=log_only
+else selector:=term_and_log;
+str_room(1);
+format_ident:=make_string;
+pack_job_name(format_extension);
+while not w_open_out(fmt_file) do
+  prompt_file_name("format file name",format_extension);
+print_nl("Beginning to dump on file ");
+@.Beginning to dump...@>
+slow_print(w_make_name_string(fmt_file)); flush_string;
+print_nl(""); slow_print(format_ident)
+
+@ @<Close the format file@>=
+w_close(fmt_file)
+
+@* \[51] The main program.
+This is it: the part of \TeX\ that executes all those procedures we have
+written.
+
+Well---almost. Let's leave space for a few more routines that we may
+have forgotten.
+
+@p @<Last-minute procedures@>
+
+@ We have noted that there are two versions of \TeX82. One, called \.{INITEX},
+@.INITEX@>
+has to be run first; it initializes everything from scratch, without
+reading a format file, and it has the capability of dumping a format file.
+The other one is called `\.{VIRTEX}'; it is a ``virgin'' program that needs
+@.VIRTEX@>
+to input a format file in order to get started. \.{VIRTEX} typically has
+more memory capacity than \.{INITEX}, because it does not need the space
+consumed by the auxiliary hyphenation tables and the numerous calls on
+|primitive|, etc.
+
+The \.{VIRTEX} program cannot read a format file instantaneously, of course;
+the best implementations therefore allow for production versions of \TeX\ that
+not only avoid the loading routine for \PASCAL\ object code, they also have
+a format file pre-loaded. This is impossible to do if we stick to standard
+\PASCAL; but there is a simple way to fool many systems into avoiding the
+initialization, as follows:\quad(1)~We declare a global integer variable
+called |ready_already|. The probability is negligible that this
+variable holds any particular value like 314159 when \.{VIRTEX} is first
+loaded.\quad(2)~After we have read in a format file and initialized
+everything, we set |ready_already:=314159|.\quad(3)~Soon \.{VIRTEX}
+will print `\.*', waiting for more input; and at this point we
+interrupt the program and save its core image in some form that the
+operating system can reload speedily.\quad(4)~When that core image is
+activated, the program starts again at the beginning; but now
+|ready_already=314159| and all the other global variables have
+their initial values too. The former chastity has vanished!
+
+In other words, if we allow ourselves to test the condition
+|ready_already=314159|, before |ready_already| has been
+assigned a value, we can avoid the lengthy initialization. Dirty tricks
+rarely pay off so handsomely.
+@^dirty \PASCAL@>
+@^system dependencies@>
+
+On systems that allow such preloading, the standard program called \.{TeX}
+should be the one that has \.{plain} format preloaded, since that agrees
+with {\sl The \TeX book}. Other versions, e.g., \.{AmSTeX}, should also
+@:TeXbook}{\sl The \TeX book@>
+@.AmSTeX@>
+@.plain@>
+be provided for commonly used formats.
+
+@<Glob...@>=
+@!ready_already:integer; {a sacrifice of purity for economy}
+
+@ Now this is really it: \TeX\ starts and ends here.
+
+The initial test involving |ready_already| should be deleted if the
+\PASCAL\ runtime system is smart enough to detect such a ``mistake.''
+@^system dependencies@>
+
+@d const_chk(#)==begin if # < inf@&# then # := inf@&# else
+                         if # > sup@&# then # := sup@&# end
+
+{|setup_bound_var| stuff duplicated in \.{mf.ch}.}
+@d setup_bound_var(#)==bound_default:=#; setup_bound_var_end
+@d setup_bound_var_end(#)==bound_name:=#; setup_bound_var_end_end
+@d setup_bound_var_end_end(#)==
+  setup_bound_variable(addressof(#), bound_name, bound_default)
+
+@p procedure main_body;
+begin @!{|start_here|}
+
+{Bounds that may be set from the configuration file. We want the user to
+ be able to specify the names with underscores, but \.{TANGLE} removes
+ underscores, so we're stuck giving the names twice, once as a string,
+ once as the identifier. How ugly.}
+  setup_bound_var (0)('mem_bot')(mem_bot);
+  setup_bound_var (250000)('main_memory')(main_memory);
+    {|memory_word|s for |mem| in \.{INITEX}}
+  setup_bound_var (0)('extra_mem_top')(extra_mem_top);
+    {increase high mem in \.{VIRTEX}}
+  setup_bound_var (0)('extra_mem_bot')(extra_mem_bot);
+    {increase low mem in \.{VIRTEX}}
+  setup_bound_var (200000)('pool_size')(pool_size);
+  setup_bound_var (75000)('string_vacancies')(string_vacancies);
+  setup_bound_var (5000)('pool_free')(pool_free); {min pool avail after fmt}
+  setup_bound_var (15000)('max_strings')(max_strings);
+  setup_bound_var (100)('strings_free')(strings_free);
+  setup_bound_var (100000)('font_mem_size')(font_mem_size);
+  setup_bound_var (500)('font_max')(font_max);
+  setup_bound_var (20000)('trie_size')(trie_size);
+    {if |ssup_trie_size| increases, recompile}
+  setup_bound_var (659)('hyph_size')(hyph_size);
+  setup_bound_var (3000)('buf_size')(buf_size);
+  setup_bound_var (50)('nest_size')(nest_size);
+  setup_bound_var (15)('max_in_open')(max_in_open);
+  setup_bound_var (60)('param_size')(param_size);
+  setup_bound_var (4000)('save_size')(save_size);
+  setup_bound_var (300)('stack_size')(stack_size);
+  setup_bound_var (16384)('dvi_buf_size')(dvi_buf_size);
+  setup_bound_var (79)('error_line')(error_line);
+  setup_bound_var (50)('half_error_line')(half_error_line);
+  setup_bound_var (79)('max_print_line')(max_print_line);
+  setup_bound_var (0)('hash_extra')(hash_extra);
+  setup_bound_var (10000)('expand_depth')(expand_depth);
+
+  const_chk (mem_bot);
+  const_chk (main_memory);
+@+Init
+  extra_mem_top := 0;
+  extra_mem_bot := 0;
+@+Tini
+  if extra_mem_bot>sup_main_memory then extra_mem_bot:=sup_main_memory;
+  if extra_mem_top>sup_main_memory then extra_mem_top:=sup_main_memory;
+  {|mem_top| is an index, |main_memory| a size}
+  mem_top := mem_bot + main_memory -1;
+  mem_min := mem_bot;
+  mem_max := mem_top;
+
+  {Check other constants against their sup and inf.}
+  const_chk (trie_size);
+  const_chk (hyph_size);
+  const_chk (buf_size);
+  const_chk (nest_size);
+  const_chk (max_in_open);
+  const_chk (param_size);
+  const_chk (save_size);
+  const_chk (stack_size);
+  const_chk (dvi_buf_size);
+  const_chk (pool_size);
+  const_chk (string_vacancies);
+  const_chk (pool_free);
+  const_chk (max_strings);
+  const_chk (strings_free);
+  const_chk (font_mem_size);
+  const_chk (font_max);
+  const_chk (hash_extra);
+  if error_line > ssup_error_line then error_line := ssup_error_line;
+
+  {array memory allocation}
+  buffer:=xmalloc_array (ASCII_code, buf_size);
+  nest:=xmalloc_array (list_state_record, nest_size);
+  save_stack:=xmalloc_array (memory_word, save_size);
+  input_stack:=xmalloc_array (in_state_record, stack_size);
+  input_file:=xmalloc_array (alpha_file, max_in_open);
+  line_stack:=xmalloc_array (integer, max_in_open);
+  source_filename_stack:=xmalloc_array (str_number, max_in_open);
+  full_source_filename_stack:=xmalloc_array (str_number, max_in_open);
+  param_stack:=xmalloc_array (halfword, param_size);
+  dvi_buf:=xmalloc_array (eight_bits, dvi_buf_size);
+  hyph_word :=xmalloc_array (str_number, hyph_size);
+  hyph_list :=xmalloc_array (halfword, hyph_size);
+  hyph_link :=xmalloc_array (hyph_pointer, hyph_size);
+@+Init
+  yzmem:=xmalloc_array (memory_word, mem_top - mem_bot + 1);
+  zmem := yzmem - mem_bot;   {Some compilers require |mem_bot=0|}
+  eqtb_top := eqtb_size+hash_extra;
+  if hash_extra=0 then hash_top:=undefined_control_sequence else
+        hash_top:=eqtb_top;
+  yhash:=xmalloc_array (two_halves,1+hash_top-hash_offset);
+  hash:=yhash - hash_offset;   {Some compilers require |hash_offset=0|}
+  next(hash_base):=0; text(hash_base):=0;
+  for hash_used:=hash_base+1 to hash_top do hash[hash_used]:=hash[hash_base];
+  zeqtb:=xmalloc_array (memory_word, eqtb_top);
+  eqtb:=zeqtb;
+
+  str_start:=xmalloc_array (pool_pointer, max_strings);
+  str_pool:=xmalloc_array (packed_ASCII_code, pool_size);
+  font_info:=xmalloc_array (memory_word, font_mem_size);
+@+Tini
+history:=fatal_error_stop; {in case we quit during initialization}
+t_open_out; {open the terminal for output}
+if ready_already=314159 then goto start_of_TEX;
+@<Check the ``constant'' values...@>@;
+if bad>0 then
+  begin wterm_ln('Ouch---my internal constants have been clobbered!',
+    '---case ',bad:1);
+@.Ouch...clobbered@>
+  goto final_end;
+  end;
+initialize; {set global variables to their starting values}
+@!Init if not get_strings_started then goto final_end;
+init_prim; {call |primitive| for each primitive}
+init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr; fix_date_and_time;
+Tini@/
+ready_already:=314159;
+start_of_TEX: @<Initialize the output routines@>;
+@<Get the first line of input and prepare to start@>;
+history:=spotless; {ready to go!}
+main_control; {come to life}
+final_cleanup; {prepare for death}
+close_files_and_terminate;
+final_end: do_final_end;
+end {|main_body|};
+
+@ Here we do whatever is needed to complete \TeX's job gracefully on the
+local operating system. The code here might come into play after a fatal
+error; it must therefore consist entirely of ``safe'' operations that
+cannot produce error messages. For example, it would be a mistake to call
+|str_room| or |make_string| at this time, because a call on |overflow|
+might lead to an infinite loop.
+@^system dependencies@>
+
+Actually there's one way to get error messages, via |prepare_mag|;
+but that can't cause infinite recursion.
+@^recursion@>
+
+This program doesn't bother to close the input files that may still be open.
+
+@<Last-minute...@>=
+procedure close_files_and_terminate;
+var k:integer; {all-purpose index}
+begin @<Finish the extensions@>;
+@!stat if tracing_stats>0 then @<Output statistics about this job@>;@;@+tats@/
+wake_up_terminal; @<Finish the \.{DVI} file@>;
+if log_opened then
+  begin wlog_cr; a_close(log_file); selector:=selector-2;
+  if selector=term_only then
+    begin print_nl("Transcript written on ");
+@.Transcript written...@>
+    print_file_name(0, log_name, 0); print_char(".");
+    end;
+  end;
+print_ln;
+if (edit_name_start<>0) and (interaction>batch_mode) then
+  call_edit(str_pool,edit_name_start,edit_name_length,edit_line);
+end;
+
+@ The present section goes directly to the log file instead of using
+|print| commands, because there's no need for these strings to take
+up |str_pool| memory when a non-{\bf stat} version of \TeX\ is being used.
+
+@<Output statistics...@>=
+if log_opened then
+  begin wlog_ln(' ');
+  wlog_ln('Here is how much of TeX''s memory',' you used:');
+@.Here is how much...@>
+  wlog(' ',str_ptr-init_str_ptr:1,' string');
+  if str_ptr<>init_str_ptr+1 then wlog('s');
+  wlog_ln(' out of ', max_strings-init_str_ptr:1);@/
+  wlog_ln(' ',pool_ptr-init_pool_ptr:1,' string characters out of ',
+    pool_size-init_pool_ptr:1);@/
+  wlog_ln(' ',lo_mem_max-mem_min+mem_end-hi_mem_min+2:1,@|
+    ' words of memory out of ',mem_end+1-mem_min:1);@/
+  wlog_ln(' ',cs_count:1,' multiletter control sequences out of ',
+    hash_size:1, '+', hash_extra:1);@/
+  wlog(' ',fmem_ptr:1,' words of font info for ',
+    font_ptr-font_base:1,' font');
+  if font_ptr<>font_base+1 then wlog('s');
+  wlog_ln(', out of ',font_mem_size:1,' for ',font_max-font_base:1);@/
+  wlog(' ',hyph_count:1,' hyphenation exception');
+  if hyph_count<>1 then wlog('s');
+  wlog_ln(' out of ',hyph_size:1);@/
+  wlog_ln(' ',max_in_stack:1,'i,',max_nest_stack:1,'n,',@|
+    max_param_stack:1,'p,',@|
+    max_buf_stack+1:1,'b,',@|
+    max_save_stack+6:1,'s stack positions out of ',@|
+    stack_size:1,'i,',
+    nest_size:1,'n,',
+    param_size:1,'p,',
+    buf_size:1,'b,',
+    save_size:1,'s');
+  end
+
+@ We get to the |final_cleanup| routine when \.{\\end} or \.{\\dump} has
+been scanned and |its_all_over|\kern-2pt.
+
+@<Last-minute...@>=
+procedure final_cleanup;
+label exit;
+var c:small_number; {0 for \.{\\end}, 1 for \.{\\dump}}
+begin c:=cur_chr;
+if job_name=0 then open_log_file;
+while input_ptr>0 do
+  if state=token_list then end_token_list@+else end_file_reading;
+while open_parens>0 do
+  begin print(" )"); decr(open_parens);
+  end;
+if cur_level>level_one then
+  begin print_nl("("); print_esc("end occurred ");
+  print("inside a group at level ");
+@:end_}{\.{(\\end occurred...)}@>
+  print_int(cur_level-level_one); print_char(")");
+  end;
+while cond_ptr<>null do
+  begin print_nl("("); print_esc("end occurred ");
+  print("when "); print_cmd_chr(if_test,cur_if);
+  if if_line<>0 then
+    begin print(" on line "); print_int(if_line);
+    end;
+  print(" was incomplete)");
+  if_line:=if_line_field(cond_ptr);
+  cur_if:=subtype(cond_ptr); temp_ptr:=cond_ptr;
+  cond_ptr:=link(cond_ptr); free_node(temp_ptr,if_node_size);
+  end;
+if history<>spotless then
+ if ((history=warning_issued)or(interaction<error_stop_mode)) then
+  if selector=term_and_log then
+  begin selector:=term_only;
+  print_nl("(see the transcript file for additional information)");
+@.see the transcript file...@>
+  selector:=term_and_log;
+  end;
+if c=1 then
+  begin @!Init for c:=top_mark_code to split_bot_mark_code do
+    if cur_mark[c]<>null then delete_token_ref(cur_mark[c]);
+  if last_glue<>max_halfword then delete_glue_ref(last_glue);
+  store_fmt_file; return;@+Tini@/
+  print_nl("(\dump is performed only by INITEX)"); return;
+@:dump_}{\.{\\dump...only by INITEX}@>
+  end;
+exit:end;
+
+@ @<Last-minute...@>=
+@!init procedure init_prim; {initialize all the primitives}
+begin no_new_control_sequence:=false;
+@<Put each...@>;
+no_new_control_sequence:=true;
+end;
+tini
+
+@ When we begin the following code, \TeX's tables may still contain garbage;
+the strings might not even be present. Thus we must proceed cautiously to get
+bootstrapped in.
+
+But when we finish this part of the program, \TeX\ is ready to call on the
+|main_control| routine to do its work.
+
+@<Get the first line...@>=
+begin @<Initialize the input routines@>;
+if (format_ident=0)or(buffer[loc]="&")or dump_line then
+  begin if format_ident<>0 then initialize; {erase preloaded format}
+  if not open_fmt_file then goto final_end;
+  if not load_fmt_file then
+    begin w_close(fmt_file); goto final_end;
+    end;
+  w_close(fmt_file);
+  eqtb:=zeqtb;
+  while (loc<limit)and(buffer[loc]=" ") do incr(loc);
+  end;
+if end_line_char_inactive then decr(limit)
+else  buffer[limit]:=end_line_char;
+if mltex_enabled_p then
+  begin wterm_ln('MLTeX v2.2 enabled');
+  end;
+fix_date_and_time;@/
+
+@!init
+if trie_not_ready then begin {initex without format loaded}
+  trie_trl:=xmalloc_array (trie_pointer, trie_size);
+  trie_tro:=xmalloc_array (trie_pointer, trie_size);
+  trie_trc:=xmalloc_array (quarterword, trie_size);
+
+  trie_c:=xmalloc_array (packed_ASCII_code, trie_size);
+  trie_o:=xmalloc_array (trie_opcode, trie_size);
+  trie_l:=xmalloc_array (trie_pointer, trie_size);
+  trie_r:=xmalloc_array (trie_pointer, trie_size);
+  trie_hash:=xmalloc_array (trie_pointer, trie_size);
+  trie_taken:=xmalloc_array (boolean, trie_size);
+
+  trie_root:=0; trie_c[0]:=si(0); trie_ptr:=0;
+
+  {Allocate and initialize font arrays}
+  font_dir:=xmalloc_array(eight_bits, font_max);
+  font_num_ext:=xmalloc_array(integer, font_max);
+  font_check:=xmalloc_array(four_quarters, font_max);
+  font_size:=xmalloc_array(scaled, font_max);
+  font_dsize:=xmalloc_array(scaled, font_max);
+  font_params:=xmalloc_array(font_index, font_max);
+  font_name:=xmalloc_array(str_number, font_max);
+  font_area:=xmalloc_array(str_number, font_max);
+  font_bc:=xmalloc_array(eight_bits, font_max);
+  font_ec:=xmalloc_array(eight_bits, font_max);
+  font_glue:=xmalloc_array(halfword, font_max);
+  hyphen_char:=xmalloc_array(integer, font_max);
+  skew_char:=xmalloc_array(integer, font_max);
+  bchar_label:=xmalloc_array(font_index, font_max);
+  font_bchar:=xmalloc_array(nine_bits, font_max);
+  font_false_bchar:=xmalloc_array(nine_bits, font_max);
+  ctype_base:=xmalloc_array(integer, font_max);
+  char_base:=xmalloc_array(integer, font_max);
+  width_base:=xmalloc_array(integer, font_max);
+  height_base:=xmalloc_array(integer, font_max);
+  depth_base:=xmalloc_array(integer, font_max);
+  italic_base:=xmalloc_array(integer, font_max);
+  lig_kern_base:=xmalloc_array(integer, font_max);
+  kern_base:=xmalloc_array(integer, font_max);
+  exten_base:=xmalloc_array(integer, font_max);
+  param_base:=xmalloc_array(integer, font_max);
+
+  font_ptr:=null_font; fmem_ptr:=7;
+  font_dir[null_font]:=dir_default;
+  font_num_ext[null_font]:=0;
+  font_name[null_font]:="nullfont"; font_area[null_font]:="";
+  hyphen_char[null_font]:="-"; skew_char[null_font]:=-1;
+  bchar_label[null_font]:=non_address;
+  font_bchar[null_font]:=non_char; font_false_bchar[null_font]:=non_char;
+  font_bc[null_font]:=1; font_ec[null_font]:=0;
+  font_size[null_font]:=0; font_dsize[null_font]:=0;
+  ctype_base[null_font]:=0; char_base[null_font]:=0; width_base[null_font]:=0;
+  height_base[null_font]:=0; depth_base[null_font]:=0;
+  italic_base[null_font]:=0; lig_kern_base[null_font]:=0;
+  kern_base[null_font]:=0; exten_base[null_font]:=0;
+  font_glue[null_font]:=null; font_params[null_font]:=7;
+  param_base[null_font]:=-1;
+  for font_k:=0 to 6 do font_info[font_k].sc:=0;
+  end;
+  tini@/
+
+  font_used:=xmalloc_array (boolean, font_max);
+  for font_k:=font_base to font_max do font_used[font_k]:=false;
+@<Compute the magic offset@>;
+@<Initialize the print |selector|...@>;
+if (loc<limit)and(cat_code(buffer[loc])<>escape) then start_input;
+  {\.{\\input} assumed}
+end
+
+@* \[52] Debugging.
+Once \TeX\ is working, you should be able to diagnose most errors with
+the \.{\\show} commands and other diagnostic features. But for the initial
+stages of debugging, and for the revelation of really deep mysteries, you
+can compile \TeX\ with a few more aids, including the \PASCAL\ runtime
+checks and its debugger. An additional routine called |debug_help|
+will also come into play when you type `\.D' after an error message;
+|debug_help| also occurs just before a fatal error causes \TeX\ to succumb.
+@^debugging@>
+@^system dependencies@>
+
+The interface to |debug_help| is primitive, but it is good enough when used
+with a \PASCAL\ debugger that allows you to set breakpoints and to read
+variables and change their values. After getting the prompt `\.{debug \#}', you
+type either a negative number (this exits |debug_help|), or zero (this
+goes to a location where you can set a breakpoint, thereby entering into
+dialog with the \PASCAL\ debugger), or a positive number |m| followed by
+an argument |n|. The meaning of |m| and |n| will be clear from the
+program below. (If |m=13|, there is an additional argument, |l|.)
+@.debug \#@>
+
+@d breakpoint=888 {place where a breakpoint is desirable}
+
+@<Last-minute...@>=
+@!debug procedure debug_help; {routine to display various things}
+label breakpoint,exit;
+var k,@!l,@!m,@!n:integer;
+begin loop begin wake_up_terminal;
+  print_nl("debug # (-1 to exit):"); update_terminal;
+@.debug \#@>
+  read(term_in,m);
+  if m<0 then return
+  else if m=0 then
+    dump_core {do something to cause a core dump}
+  else  begin read(term_in,n);
+    case m of
+    @t\4@>@<Numbered cases for |debug_help|@>@;
+    othercases print("?")
+    endcases;
+    end;
+  end;
+exit:end;
+gubed
+
+@ @<Numbered cases...@>=
+1: print_word(mem[n]); {display |mem[n]| in all forms}
+2: print_int(info(n));
+3: print_int(link(n));
+4: print_word(eqtb[n]);
+5: begin print_scaled(font_info[n].sc); print_char(" ");@/
+  print_int(font_info[n].qqqq.b0); print_char(":");@/
+  print_int(font_info[n].qqqq.b1); print_char(":");@/
+  print_int(font_info[n].qqqq.b2); print_char(":");@/
+  print_int(font_info[n].qqqq.b3);
+  end;
+6: print_word(save_stack[n]);
+7: show_box(n);
+  {show a box, abbreviated by |show_box_depth| and |show_box_breadth|}
+8: begin breadth_max:=10000; depth_threshold:=pool_size-pool_ptr-10;
+  show_node_list(n); {show a box in its entirety}
+  end;
+9: show_token_list(n,null,1000);
+10: slow_print(n);
+11: check_mem(n>0); {check wellformedness; print new busy locations if |n>0|}
+12: search_mem(n); {look for pointers to |n|}
+13: begin read(term_in,l); print_cmd_chr(n,l);
+  end;
+14: for k:=0 to n do print(buffer[k]);
+15: begin font_in_short_display:=null_font; short_display(n);
+  end;
+16: panicking:=not panicking;
+
+@* \[53] Extensions.
+The program above includes a bunch of ``hooks'' that allow further
+capabilities to be added without upsetting \TeX's basic structure.
+Most of these hooks are concerned with ``whatsit'' nodes, which are
+intended to be used for special purposes; whenever a new extension to
+\TeX\ involves a new kind of whatsit node, a corresponding change needs
+to be made to the routines below that deal with such nodes,
+but it will usually be unnecessary to make many changes to the
+other parts of this program.
+
+In order to demonstrate how extensions can be made, we shall treat
+`\.{\\write}', `\.{\\openout}', `\.{\\closeout}', `\.{\\immediate}',
+`\.{\\special}', and `\.{\\setlanguage}' as if they were extensions.
+These commands are actually primitives of \TeX, and they should
+appear in all implementations of the system; but let's try to imagine
+that they aren't. Then the program below illustrates how a person
+could add them.
+
+Sometimes, of course, an extension will require changes to \TeX\ itself;
+no system of hooks could be complete enough for all conceivable extensions.
+The features associated with `\.{\\write}' are almost all confined to the
+following paragraphs, but there are small parts of the |print_ln| and
+|print_char| procedures that were introduced specifically to \.{\\write}
+characters. Furthermore one of the token lists recognized by the scanner
+is a |write_text|; and there are a few other miscellaneous places where we
+have already provided for some aspect of \.{\\write}.  The goal of a \TeX\
+extender should be to minimize alterations to the standard parts of the
+program, and to avoid them completely if possible. He or she should also
+be quite sure that there's no easy way to accomplish the desired goals
+with the standard features that \TeX\ already has. ``Think thrice before
+extending,'' because that may save a lot of work, and it will also keep
+incompatible extensions of \TeX\ from proliferating.
+@^system dependencies@>
+@^extensions to \TeX@>
+
+@ First let's consider the format of whatsit nodes that are used to represent
+the data associated with \.{\\write} and its relatives. Recall that a whatsit
+has |type=whatsit_node|, and the |subtype| is supposed to distinguish
+different kinds of whatsits. Each node occupies two or more words; the
+exact number is immaterial, as long as it is readily determined from the
+|subtype| or other data.
+
+We shall introduce five |subtype| values here, corresponding to the
+control sequences \.{\\openout}, \.{\\write}, \.{\\closeout}, \.{\\special}, and
+\.{\\setlanguage}. The second word of I/O whatsits has a |write_stream| field
+that identifies the write-stream number (0 to 15, or 16 for out-of-range and
+positive, or 17 for out-of-range and negative).
+In the case of \.{\\write} and \.{\\special}, there is also a field that
+points to the reference count of a token list that should be sent. In the
+case of \.{\\openout}, we need three words and three auxiliary subfields
+to hold the string numbers for name, area, and extension.
+
+@d write_node_size=2 {number of words in a write/whatsit node}
+@d open_node_size=3 {number of words in an open/whatsit node}
+@d open_node=0 {|subtype| in whatsits that represent files to \.{\\openout}}
+@d write_node=1 {|subtype| in whatsits that represent things to \.{\\write}}
+@d close_node=2 {|subtype| in whatsits that represent streams to \.{\\closeout}}
+@d special_node=3 {|subtype| in whatsits that represent \.{\\special} things}
+@d language_node=4 {|subtype| in whatsits that change the current language}
+@d what_lang(#)==link(#+1) {language number, in the range |0..255|}
+@d what_lhm(#)==type(#+1) {minimum left fragment, in the range |1..63|}
+@d what_rhm(#)==subtype(#+1) {minimum right fragment, in the range |1..63|}
+@d write_tokens(#) == link(#+1) {reference count of token list to write}
+@d write_stream(#) == info(#+1) {stream number (0 to 17)}
+@d open_name(#) == link(#+1) {string number of file name to open}
+@d open_area(#) == info(#+2) {string number of file area for |open_name|}
+@d open_ext(#) == link(#+2) {string number of file extension for |open_name|}
+
+@ The sixteen possible \.{\\write} streams are represented by the |write_file|
+array. The |j|th file is open if and only if |write_open[j]=true|. The last
+two streams are special; |write_open[16]| represents a stream number
+greater than 15, while |write_open[17]| represents a negative stream number,
+and both of these variables are always |false|.
+
+@<Glob...@>=
+@!write_file:array[0..15] of alpha_file;
+@!write_open:array[0..17] of boolean;
+
+@ @<Set init...@>=
+for k:=0 to 17 do write_open[k]:=false;
+
+@ Extensions might introduce new command codes; but it's best to use
+|extension| with a modifier, whenever possible, so that |main_control|
+stays the same.
+
+@d immediate_code=4 {command modifier for \.{\\immediate}}
+@d set_language_code=5 {command modifier for \.{\\setlanguage}}
+
+@<Put each...@>=
+primitive("openout",extension,open_node);@/
+@!@:open_out_}{\.{\\openout} primitive@>
+primitive("write",extension,write_node); write_loc:=cur_val;@/
+@!@:write_}{\.{\\write} primitive@>
+primitive("closeout",extension,close_node);@/
+@!@:close_out_}{\.{\\closeout} primitive@>
+primitive("special",extension,special_node);@/
+text(frozen_special):="special"; eqtb[frozen_special]:=eqtb[cur_val];@/
+@!@:special_}{\.{\\special} primitive@>
+primitive("immediate",extension,immediate_code);@/
+@!@:immediate_}{\.{\\immediate} primitive@>
+primitive("setlanguage",extension,set_language_code);@/
+@!@:set_language_}{\.{\\setlanguage} primitive@>
+
+@ The variable |write_loc| just introduced is used to provide an
+appropriate error message in case of ``runaway'' write texts.
+
+@<Glob...@>=
+@!write_loc:pointer; {|eqtb| address of \.{\\write}}
+
+@ @<Cases of |print_cmd_chr|...@>=
+extension: case chr_code of
+  open_node:print_esc("openout");
+  write_node:print_esc("write");
+  close_node:print_esc("closeout");
+  special_node:print_esc("special");
+  immediate_code:print_esc("immediate");
+  set_language_code:print_esc("setlanguage");
+  othercases print("[unknown extension!]")
+  endcases;
+
+@ When an |extension| command occurs in |main_control|, in any mode,
+the |do_extension| routine is called.
+
+@<Cases of |main_control| that are for extensions...@>=
+any_mode(extension):do_extension;
+
+@ @<Declare act...@>=
+@t\4@>@<Declare procedures needed in |do_extension|@>@;
+procedure do_extension;
+var k:integer; {all-purpose integers}
+@!p:pointer; {all-purpose pointers}
+begin case cur_chr of
+open_node:@<Implement \.{\\openout}@>;
+write_node:@<Implement \.{\\write}@>;
+close_node:@<Implement \.{\\closeout}@>;
+special_node:@<Implement \.{\\special}@>;
+immediate_code:@<Implement \.{\\immediate}@>;
+set_language_code:@<Implement \.{\\setlanguage}@>;
+othercases confusion("ext1")
+@:this can't happen ext1}{\quad ext1@>
+endcases;
+end;
+
+@ Here is a subroutine that creates a whatsit node having a given |subtype|
+and a given number of words. It initializes only the first word of the whatsit,
+and appends it to the current list.
+
+@<Declare procedures needed in |do_extension|@>=
+procedure new_whatsit(@!s:small_number;@!w:small_number);
+var p:pointer; {the new node}
+begin p:=get_node(w); type(p):=whatsit_node; subtype(p):=s;
+link(tail):=p; tail:=p;
+end;
+
+@ The next subroutine uses |cur_chr| to decide what sort of whatsit is
+involved, and also inserts a |write_stream| number.
+
+@<Declare procedures needed in |do_ext...@>=
+procedure new_write_whatsit(@!w:small_number);
+begin new_whatsit(cur_chr,w);
+if w<>write_node_size then scan_four_bit_int
+else  begin scan_int;
+  if cur_val<0 then cur_val:=17
+  else if (cur_val>15) and (cur_val <> 18) then cur_val:=16;
+  end;
+write_stream(tail):=cur_val;
+end;
+
+@ @<Implement \.{\\openout}@>=
+begin new_write_whatsit(open_node_size);
+scan_optional_equals; scan_file_name;@/
+open_name(tail):=cur_name; open_area(tail):=cur_area; open_ext(tail):=cur_ext;
+end
+
+@ When `\.{\\write 12\{...\}}' appears, we scan the token list `\.{\{...\}}'
+without expanding its macros; the macros will be expanded later when this
+token list is rescanned.
+
+@<Implement \.{\\write}@>=
+begin k:=cur_cs; new_write_whatsit(write_node_size);@/
+cur_cs:=k; p:=scan_toks(false,false); write_tokens(tail):=def_ref;
+end
+
+@ @<Implement \.{\\closeout}@>=
+begin new_write_whatsit(write_node_size); write_tokens(tail):=null;
+end
+
+@ When `\.{\\special\{...\}}' appears, we expand the macros in the token
+list as in \.{\\xdef} and \.{\\mark}.
+
+@<Implement \.{\\special}@>=
+begin new_whatsit(special_node,write_node_size); write_stream(tail):=null;
+p:=scan_toks(false,true); write_tokens(tail):=def_ref;
+end
+
+@ Each new type of node that appears in our data structure must be capable
+of being displayed, copied, destroyed, and so on. The routines that we
+need for write-oriented whatsits are somewhat like those for mark nodes;
+other extensions might, of course, involve more subtlety here.
+
+@<Basic printing...@>=
+procedure print_write_whatsit(@!s:str_number;@!p:pointer);
+begin print_esc(s);
+if write_stream(p)<16 then print_int(write_stream(p))
+else if write_stream(p)=16 then print_char("*")
+@.*\relax@>
+else print_char("-");
+end;
+
+@ @<Display the whatsit...@>=
+case subtype(p) of
+open_node:begin print_write_whatsit("openout",p);
+  print_char("="); print_file_name(open_name(p),open_area(p),open_ext(p));
+  end;
+write_node:begin print_write_whatsit("write",p);
+  print_mark(write_tokens(p));
+  end;
+close_node:print_write_whatsit("closeout",p);
+special_node:begin print_esc("special");
+  print_mark(write_tokens(p));
+  end;
+language_node:begin print_esc("setlanguage");
+  print_int(what_lang(p)); print(" (hyphenmin ");
+  print_int(what_lhm(p)); print_char(",");
+  print_int(what_rhm(p)); print_char(")");
+  end;
+othercases print("whatsit?")
+endcases
+
+@ @<Make a partial copy of the whatsit...@>=
+case subtype(p) of
+open_node: begin r:=get_node(open_node_size); words:=open_node_size;
+  end;
+write_node,special_node: begin r:=get_node(write_node_size);
+  add_token_ref(write_tokens(p)); words:=write_node_size;
+  end;
+close_node,language_node: begin r:=get_node(small_node_size);
+  words:=small_node_size;
+  end;
+othercases confusion("ext2")
+@:this can't happen ext2}{\quad ext2@>
+endcases
+
+@ @<Wipe out the whatsit...@>=
+begin case subtype(p) of
+open_node: free_node(p,open_node_size);
+write_node,special_node: begin delete_token_ref(write_tokens(p));
+  free_node(p,write_node_size); goto done;
+  end;
+close_node,language_node: free_node(p,small_node_size);
+othercases confusion("ext3")
+@:this can't happen ext3}{\quad ext3@>
+endcases;@/
+goto done;
+end
+
+@ @<Incorporate a whatsit node into a vbox@>=do_nothing
+
+@ @<Incorporate a whatsit node into an hbox@>=do_nothing
+
+@ @<Let |d| be the width of the whatsit |p|@>=d:=0
+
+@ @d adv_past(#)==@+if subtype(#)=language_node then
+    begin cur_lang:=what_lang(#); l_hyf:=what_lhm(#); r_hyf:=what_rhm(#);@+end
+
+@<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>=@+
+adv_past(cur_p)
+
+@ @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>=@+
+adv_past(s)
+
+@ @<Prepare to move whatsit |p| to the current page, then |goto contribute|@>=
+goto contribute
+
+@ @<Process whatsit |p| in |vert_break| loop, |goto not_found|@>=
+goto not_found
+
+@ @<Output the whatsit node |p| in a vlist@>=
+out_what(p)
+
+@ @<Output the whatsit node |p| in an hlist@>=
+out_what(p)
+
+@ After all this preliminary shuffling, we come finally to the routines
+that actually send out the requested data. Let's do \.{\\special} first
+(it's easier).
+
+@<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+procedure special_out(@!p:pointer);
+var old_setting:0..max_selector; {holds print |selector|}
+@!k:pool_pointer; {index into |str_pool|}
+begin synch_h; synch_v;@/
+old_setting:=selector; selector:=new_string;
+show_token_list(link(write_tokens(p)),null,pool_size-pool_ptr);
+selector:=old_setting;
+str_room(1);
+if cur_length<256 then
+  begin dvi_out(xxx1); dvi_out(cur_length);
+  end
+else  begin dvi_out(xxx4); dvi_four(cur_length);
+  end;
+for k:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[k]));
+pool_ptr:=str_start[str_ptr]; {erase the string}
+end;
+
+@ To write a token list, we must run it through \TeX's scanner, expanding
+macros and \.{\\the} and \.{\\number}, etc. This might cause runaways,
+if a delimited macro parameter isn't matched, and runaways would be
+extremely confusing since we are calling on \TeX's scanner in the middle
+of a \.{\\shipout} command. Therefore we will put a dummy control sequence as
+a ``stopper,'' right after the token list. This control sequence is
+artificially defined to be \.{\\outer}.
+@:end_write_}{\.{\\endwrite}@>
+
+@<Initialize table...@>=
+text(end_write):="endwrite"; eq_level(end_write):=level_one;
+eq_type(end_write):=outer_call; equiv(end_write):=null;
+
+@ @<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+procedure write_out(@!p:pointer);
+var old_setting:0..max_selector; {holds print |selector|}
+@!old_mode:integer; {saved |mode|}
+@!j:small_number; {write stream number}
+@!q,@!r:pointer; {temporary variables for list manipulation}
+@!d:integer; {number of characters in incomplete current string}
+@!clobbered:boolean; {system string is ok?}
+@!runsystem_ret:integer; {return value from |runsystem|}
+begin @<Expand macros in the token list
+  and make |link(def_ref)| point to the result@>;
+old_setting:=selector; j:=write_stream(p);
+if j=18 then selector := new_string
+else if write_open[j] then selector:=j
+else  begin {write to the terminal if file isn't open}
+  if (j=17)and(selector=term_and_log) then selector:=log_only;
+  print_nl("");
+  end;
+token_show(def_ref); print_ln;
+flush_list(def_ref);
+if j=18 then
+  begin if (tracing_online<=0) then
+    selector:=log_only  {Show what we're doing in the log file.}
+  else selector:=term_and_log;  {Show what we're doing.}
+  {If the log file isn't open yet, we can only send output to the terminal.
+   Calling |open_log_file| from here seems to result in bad data in the log.}
+  if not log_opened then selector:=term_only;
+  print_nl("runsystem(");
+  for d:=0 to cur_length-1 do
+    begin {|print| gives up if passed |str_ptr|, so do it by hand.}
+    print(so(str_pool[str_start[str_ptr]+d])); {N.B.: not |print_char|}
+    end;
+  print(")...");
+  if shellenabledp then begin
+    str_room(1); append_char(0); {Append a null byte to the expansion.}
+    clobbered:=false;
+    for d:=0 to cur_length-1 do {Convert to external character set.}
+      begin
+        str_pool[str_start[str_ptr]+d]:=xchr[str_pool[str_start[str_ptr]+d]];
+        if (str_pool[str_start[str_ptr]+d]=null_code)
+           and (d<cur_length-1) then clobbered:=true;
+        {minimal checking: NUL not allowed in argument string of |system|()}
+      end;
+    if clobbered then print("clobbered")
+    else begin {We have the command.  See if we're allowed to execute it,
+         and report in the log.  We don't check the actual exit status of
+         the command, or do anything with the output.}
+      runsystem_ret := runsystem(conststringcast(addressof(
+                                              str_pool[str_start[str_ptr]])));
+      if runsystem_ret = -1 then print("quotation error in system command")
+      else if runsystem_ret = 0 then print("disabled (restricted)")
+      else if runsystem_ret = 1 then print("executed")
+      else if runsystem_ret = 2 then print("executed safely (allowed)")
+    end;
+  end else begin
+    print("disabled"); {|shellenabledp| false}
+  end;
+  print_char("."); print_nl(""); print_ln;
+  pool_ptr:=str_start[str_ptr];  {erase the string}
+end;
+selector:=old_setting;
+end;
+
+@ The final line of this routine is slightly subtle; at least, the author
+didn't think about it until getting burnt! There is a used-up token list
+@^Knuth, Donald Ervin@>
+on the stack, namely the one that contained |end_write_token|. (We
+insert this artificial `\.{\\endwrite}' to prevent runaways, as explained
+above.) If it were not removed, and if there were numerous writes on a
+single page, the stack would overflow.
+
+@d end_write_token==cs_token_flag+end_write
+
+@<Expand macros in the token list and...@>=
+q:=get_avail; info(q):=right_brace_token+"}";@/
+r:=get_avail; link(q):=r; info(r):=end_write_token; ins_list(q);@/
+begin_token_list(write_tokens(p),write_text);@/
+q:=get_avail; info(q):=left_brace_token+"{"; ins_list(q);
+{now we're ready to scan
+  `\.\{$\langle\,$token list$\,\rangle$\.{\} \\endwrite}'}
+old_mode:=mode; mode:=0;
+  {disable \.{\\prevdepth}, \.{\\spacefactor}, \.{\\lastskip}, \.{\\prevgraf}}
+cur_cs:=write_loc; q:=scan_toks(false,true); {expand macros, etc.}
+get_token;@+if cur_tok<>end_write_token then
+  @<Recover from an unbalanced write command@>;
+mode:=old_mode;
+end_token_list {conserve stack space}
+
+@ @<Recover from an unbalanced write command@>=
+begin print_err("Unbalanced write command");
+@.Unbalanced write...@>
+help2("On this page there's a \write with fewer real {'s than }'s.")@/
+("I can't handle that very well; good luck."); error;
+repeat get_token;
+until cur_tok=end_write_token;
+end
+
+@ The |out_what| procedure takes care of outputting whatsit nodes for
+|vlist_out| and |hlist_out|\kern-.3pt.
+
+@<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+procedure out_what(@!p:pointer);
+var j:small_number; {write stream number}
+    @!old_setting:0..max_selector;
+begin case subtype(p) of
+open_node,write_node,close_node:@<Do some work that has been queued up
+  for \.{\\write}@>;
+special_node:special_out(p);
+language_node:do_nothing;
+othercases confusion("ext4")
+@:this can't happen ext4}{\quad ext4@>
+endcases;
+end;
+
+@ We don't implement \.{\\write} inside of leaders. (The reason is that
+the number of times a leader box appears might be different in different
+implementations, due to machine-dependent rounding in the glue calculations.)
+@^leaders@>
+
+@<Do some work that has been queued up...@>=
+if not doing_leaders then
+  begin j:=write_stream(p);
+  if subtype(p)=write_node then write_out(p)
+  else  begin if write_open[j] then a_close(write_file[j]);
+    if subtype(p)=close_node then write_open[j]:=false
+    else if j<16 then
+      begin cur_name:=open_name(p); cur_area:=open_area(p);
+      cur_ext:=open_ext(p);
+      if cur_ext="" then cur_ext:=".tex";
+      pack_cur_name;
+      while not kpse_out_name_ok(stringcast(name_of_file+1))
+            or not a_open_out(write_file[j]) do
+        prompt_file_name("output file name",".tex");
+      write_open[j]:=true;
+      {If on first line of input, log file is not ready yet, so don't log.}
+      if log_opened then begin
+        old_setting:=selector;
+        if (tracing_online<=0) then
+          selector:=log_only  {Show what we're doing in the log file.}
+        else selector:=term_and_log;  {Show what we're doing.}
+        print_nl("\openout");
+        print_int(j);
+        print(" = `");
+        print_file_name(cur_name,cur_area,cur_ext);
+        print("'."); print_nl(""); print_ln;
+        selector:=old_setting;
+      end;
+      end;
+    end;
+  end
+
+@ The presence of `\.{\\immediate}' causes the |do_extension| procedure
+to descend to one level of recursion. Nothing happens unless \.{\\immediate}
+is followed by `\.{\\openout}', `\.{\\write}', or `\.{\\closeout}'.
+@^recursion@>
+
+@<Implement \.{\\immediate}@>=
+begin get_x_token;
+if (cur_cmd=extension)and(cur_chr<=close_node) then
+  begin p:=tail; do_extension; {append a whatsit node}
+  out_what(tail); {do the action immediately}
+  flush_node_list(tail); tail:=p; link(p):=null;
+  end
+else back_input;
+end
+
+@ The \.{\\language} extension is somewhat different.
+We need a subroutine that comes into play when a character of
+a non-|clang| language is being appended to the current paragraph.
+
+@<Declare action...@>=
+procedure fix_language;
+var @!l:ASCII_code; {the new current language}
+begin if language<=0 then l:=0
+else if language>255 then l:=0
+else l:=language;
+if l<>clang then
+  begin new_whatsit(language_node,small_node_size);
+  what_lang(tail):=l; clang:=l;@/
+  what_lhm(tail):=norm_min(left_hyphen_min);
+  what_rhm(tail):=norm_min(right_hyphen_min);
+  end;
+end;
+
+@ @<Implement \.{\\setlanguage}@>=
+if abs(mode)<>hmode then report_illegal_case
+else begin new_whatsit(language_node,small_node_size);
+  scan_int;
+  if cur_val<=0 then clang:=0
+  else if cur_val>255 then clang:=0
+  else clang:=cur_val;
+  what_lang(tail):=clang;
+  what_lhm(tail):=norm_min(left_hyphen_min);
+  what_rhm(tail):=norm_min(right_hyphen_min);
+  end
+
+@ @<Finish the extensions@>=
+for k:=0 to 15 do if write_open[k] then a_close(write_file[k])
+
+@* \[54/web2c] System-dependent changes for Web2c.
+Here are extra variables for Web2c.  (This numbering of the
+system-dependent section allows easy integration of Web2c and e-\TeX, etc.)
+@^<system dependencies@>
+
+@<Glob...@>=
+@!edit_name_start: pool_pointer; {where the filename to switch to starts}
+@!edit_name_length,@!edit_line: integer; {what line to start editing at}
+@!ipc_on: cinttype; {level of IPC action, 0 for none [default]}
+@!stop_at_space: boolean; {whether |more_name| returns false for space}
+
+@ The |edit_name_start| will be set to point into |str_pool| somewhere after
+its beginning if \TeX\ is supposed to switch to an editor on exit.
+
+@<Set init...@>=
+edit_name_start:=0;
+stop_at_space:=true;
+
+@ These are used when we regenerate the representation of the first 256
+strings.
+
+@<Global...@> =
+@!save_str_ptr: str_number;
+@!save_pool_ptr: pool_pointer;
+@!shellenabledp: cinttype;
+@!restrictedshell: cinttype;
+@!output_comment: ^char;
+@!k,l: 0..255; {used by `Make the first 256 strings', etc.}
+
+@ When debugging a macro package, it can be useful to see the exact
+control sequence names in the format file.  For example, if ten new
+csnames appear, it's nice to know what they are, to help pinpoint where
+they came from.  (This isn't a truly ``basic'' printing procedure, but
+that's a convenient module in which to put it.)
+
+@<Basic printing procedures@> =
+procedure print_csnames (hstart:integer; hfinish:integer);
+var c,h:integer;
+begin
+  write_ln(stderr, 'fmtdebug:csnames from ', hstart, ' to ', hfinish, ':');
+  for h := hstart to hfinish do begin
+    if text(h) > 0 then begin {if have anything at this position}
+      for c := str_start[text(h)] to str_start[text(h) + 1] - 1
+      do begin
+        put_byte(str_pool[c], stderr); {print the characters}
+      end;
+      write_ln(stderr, '|');
+    end;
+  end;
+end;
+
+@ Are we printing extra info as we read the format file?
+
+@<Glob...@> =
+@!debug_format_file: boolean;
+
+@ @<Set init...@>=
+@!debug debug_format_file:=true; @+gubed;
+
+
+@ A helper for printing file:line:error style messages.  Look for a
+filename in |full_source_filename_stack|, and if we fail to find
+one fall back on the non-file:line:error style.
+
+@<Basic print...@>=
+procedure print_file_line;
+var level: 0..max_in_open;
+begin
+  level:=in_open;
+  while (level>0) and (full_source_filename_stack[level]=0) do
+    decr(level);
+  if level=0 then
+    print_nl("! ")
+  else begin
+    print_nl (""); print (full_source_filename_stack[level]); print (":");
+    if level=in_open then print_int (line)
+    else print_int (line_stack[level+1]);
+    print (": ");
+  end;
+end;
+
+@ To be able to determine whether \.{\\write18} is enabled from within
+\TeX\ we also implement \.{\\eof18}.  We sort of cheat by having an
+additional route |scan_four_bit_int_or_18| which is the same as
+|scan_four_bit_int| except it also accepts the value 18.
+
+@<Declare procedures that scan restricted classes of integers@>=
+procedure scan_four_bit_int_or_18;
+begin scan_int;
+if (cur_val<0)or((cur_val>15)and(cur_val<>18)) then
+  begin print_err("Bad number");
+@.Bad number@>
+  help2("Since I expected to read a number between 0 and 15,")@/
+    ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+  end;
+end;
+
+@ Dumping the |xord|, |xchr|, and |xprn| arrays.  We dump these always
+in the format, so a TCX file loaded during format creation can set a
+default for users of the format.
+
+@<Dump |xord|, |xchr|, and |xprn|@>=
+dump_things(xord[0], 256);
+dump_things(xchr[0], 256);
+dump_things(xprn[0], 256);
+
+@ Undumping the |xord|, |xchr|, and |xprn| arrays.  This code is more
+complicated, because we want to ensure that a TCX file specified on
+the command line will override whatever is in the format.  Since the
+tcx file has already been loaded, that implies throwing away the data
+in the format.  Also, if no |translate_filename| is given, but
+|eight_bit_p| is set we have to make all characters printable.
+
+@<Undump |xord|, |xchr|, and |xprn|@>=
+if translate_filename then begin
+  for k:=0 to 255 do undump_things(dummy_xord, 1);
+  for k:=0 to 255 do undump_things(dummy_xchr, 1);
+  for k:=0 to 255 do undump_things(dummy_xprn, 1);
+  end
+else begin
+  undump_things(xord[0], 256);
+  undump_things(xchr[0], 256);
+  undump_things(xprn[0], 256);
+  if eight_bit_p then
+    for k:=0 to 255 do
+      xprn[k]:=1;
+end;
+
+
+@* \[54/web2c-string] The string recycling routines.
+\TeX{} uses 2 upto 4 {\it new\/} strings when scanning a filename in an
+\.{\\input}, \.{\\openin}, or \.{\\openout} operation.  These strings are
+normally lost because the reference to them are not saved after finishing
+the operation.  |search_string| searches through the string pool for the
+given string and returns either 0 or the found string number.
+
+@<Declare additional routines for string recycling@>=
+function search_string(@!search:str_number):str_number;
+label found;
+var result: str_number;
+@!s: str_number; {running index}
+@!len: integer; {length of searched string}
+begin result:=0; len:=length(search);
+if len=0 then  {trivial case}
+  begin result:=""; goto found;
+  end
+else  begin s:=search-1;  {start search with newest string below |s|; |search>1|!}
+  while s>255 do  {first 256 strings depend on implementation!!}
+    begin if length(s)=len then
+      if str_eq_str(s,search) then
+        begin result:=s; goto found;
+        end;
+    decr(s);
+    end;
+  end;
+found:search_string:=result;
+end;
+
+@ The following routine is a variant of |make_string|.  It searches
+the whole string pool for a string equal to the string currently built
+and returns a found string.  Otherwise a new string is created and
+returned.  Be cautious, you can not apply |flush_string| to a replaced
+string!
+
+@<Declare additional routines for string recycling@>=
+function slow_make_string : str_number;
+label exit;
+var s: str_number; {result of |search_string|}
+@!t: str_number; {new string}
+begin t:=make_string; s:=search_string(t);
+if s>0 then
+  begin flush_string; slow_make_string:=s; return;
+  end;
+slow_make_string:=t;
+exit:end;
+
+
+@* \[54/ML\TeX] System-dependent changes for ML\TeX.
+
+The boolean variable |mltex_p| is set by web2c according to the given
+command line option (or an entry in the configuration file) before any
+\TeX{} function is called.
+
+@<Global...@> =
+@!mltex_p: boolean;
+
+@ The boolean variable |mltex_enabled_p| is used to enable ML\TeX's
+character substitution.  It is initialised to |false|.  When loading
+a \.{FMT} it is set to the value of the boolean |mltex_p| saved in
+the \.{FMT} file.  Additionally it is set to the value of |mltex_p|
+in Ini\TeX.
+
+@<Glob...@>=
+@!mltex_enabled_p:boolean;  {enable character substitution}
+
+
+@ @<Set init...@>=
+mltex_enabled_p:=false;
+
+
+@ The function |effective_char| computes the effective character with
+respect to font information.  The effective character is either the
+base character part of a character substitution definition, if the
+character does not exist in the font or the character itself.
+
+Inside |effective_char| we can not use |char_info| because the macro
+|char_info| uses |effective_char| calling this function a second time
+with the same arguments.
+
+If neither the character |c| exists in font |f| nor a character
+substitution for |c| was defined, you can not use the function value
+as a character offset in |char_info| because it will access an
+undefined or invalid |font_info| entry!  Therefore inside |char_info|
+and in other places, |effective_char|'s boolean parameter |err_p| is
+set to |true| to issue a warning and return the incorrect
+replacement, but always existing character |font_bc[f]|.
+@^inner loop@>
+
+@<Declare additional functions for ML\TeX@>=
+function effective_char(@!err_p:boolean;
+                        @!f:internal_font_number;@!c:quarterword):integer;
+label found;
+var base_c: integer; {or |eightbits|: replacement base character}
+@!result: integer; {or |quarterword|}
+begin result:=c;  {return |c| unless it does not exist in the font}
+if not mltex_enabled_p then goto found;
+if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
+  if char_exists(orig_char_info(f)(c)) then  {N.B.: not |char_info|(f)(c)}
+    goto found;
+if qo(c)>=char_sub_def_min then if qo(c)<=char_sub_def_max then
+  if char_list_exists(qo(c)) then
+    begin base_c:=char_list_char(qo(c));
+    result:=qi(base_c);  {return |base_c|}
+    if not err_p then goto found;
+    if font_ec[f]>=base_c then if font_bc[f]<=base_c then
+      if char_exists(orig_char_info(f)(qi(base_c))) then goto found;
+    end;
+if err_p then  {print error and return existing character?}
+  begin begin_diagnostic;
+  print_nl("Missing character: There is no "); print("substitution for ");
+@.Missing character@>
+  print_ASCII(qo(c)); print(" in font ");
+  slow_print(font_name[f]); print_char("!"); end_diagnostic(false);
+  result:=qi(font_bc[f]); {N.B.: not non-existing character |c|!}
+  end;
+found: effective_char:=result;
+end;
+
+
+@ The function |effective_char_info| is equivalent to |char_info|,
+except it will return |null_character| if neither the character |c|
+exists in font |f| nor is there a substitution definition for |c|.
+(For these cases |char_info| using |effective_char| will access an
+undefined or invalid |font_info| entry.  See the documentation of
+|effective_char| for more information.)
+@^inner loop@>
+
+@<Declare additional functions for ML\TeX@>=
+function effective_char_info(@!f:internal_font_number;
+                             @!c:quarterword):four_quarters;
+label exit;
+var ci:four_quarters; {character information bytes for |c|}
+@!base_c:integer; {or |eightbits|: replacement base character}
+begin if not mltex_enabled_p then
+  begin effective_char_info:=orig_char_info(f)(c); return;
+  end;
+if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
+  begin ci:=orig_char_info(f)(c);  {N.B.: not |char_info|(f)(c)}
+  if char_exists(ci) then
+    begin effective_char_info:=ci; return;
+    end;
+  end;
+if qo(c)>=char_sub_def_min then if qo(c)<=char_sub_def_max then
+  if char_list_exists(qo(c)) then
+    begin {|effective_char_info:=char_info(f)(qi(char_list_char(qo(c))));|}
+    base_c:=char_list_char(qo(c));
+    if font_ec[f]>=base_c then if font_bc[f]<=base_c then
+      begin ci:=orig_char_info(f)(qi(base_c));  {N.B.: not |char_info|(f)(c)}
+      if char_exists(ci) then
+        begin effective_char_info:=ci; return;
+        end;
+      end;
+    end;
+effective_char_info:=null_character;
+exit:end;
+
+
+@ This code is called for a virtual character |c| in |hlist_out|
+during |ship_out|.  It tries to built a character substitution
+construct for |c| generating appropriate \.{DVI} code using the
+character substitution definition for this character.  If a valid
+character substitution exists \.{DVI} code is created as if
+|make_accent| was used.  In all other cases the status of the
+substituion for this character has been changed between the creation
+of the character node in the hlist and the output of the page---the
+created \.{DVI} code will be correct but the visual result will be
+undefined.
+
+Former ML\TeX\ versions have replaced the character node by a
+sequence of character, box, and accent kern nodes splicing them into
+the original horizontal list.  This version does not do this to avoid
+a)~a memory overflow at this processing stage, b)~additional code to
+add a pointer to the previous node needed for the replacement, and
+c)~to avoid wrong code resulting in anomalies because of the use
+within a \.{\\leaders} box.
+
+@<Output a substitution, |goto continue| if not possible@>=
+  begin
+  @<Get substitution information, check it, goto |found|
+  if all is ok, otherwise goto |continue|@>;
+found: @<Print character substition tracing log@>;
+  @<Rebuild character using substitution information@>;
+  end
+
+
+@ The global variables for the code to substitute a virtual character
+can be declared as local.  Nonetheless we declare them as global to
+avoid stack overflows because |hlist_out| can be called recursivly.
+
+@<Glob...@>=
+@!accent_c,@!base_c,@!replace_c:integer;
+@!ia_c,@!ib_c:four_quarters; {accent and base character information}
+@!base_slant,@!accent_slant:real; {amount of slant}
+@!base_x_height:scaled; {accent is designed for characters of this height}
+@!base_width,@!base_height:scaled; {height and width for base character}
+@!accent_width,@!accent_height:scaled; {height and width for accent}
+@!delta:scaled; {amount of right shift}
+
+
+@ Get the character substitution information in |char_sub_code| for
+the character |c|.  The current code checks that the substition
+exists and is valid and all substitution characters exist in the
+font, so we can {\it not\/} substitute a character used in a
+substitution.  This simplifies the code because we have not to check
+for cycles in all character substitution definitions.
+
+@<Get substitution information, check it...@>=
+  if qo(c)>=char_sub_def_min then if qo(c)<=char_sub_def_max then
+    if char_list_exists(qo(c)) then
+      begin  base_c:=char_list_char(qo(c));
+      accent_c:=char_list_accent(qo(c));
+      if (font_ec[f]>=base_c) then if (font_bc[f]<=base_c) then
+        if (font_ec[f]>=accent_c) then if (font_bc[f]<=accent_c) then
+          begin ia_c:=char_info(f)(qi(accent_c));
+          ib_c:=char_info(f)(qi(base_c));
+          if char_exists(ib_c) then
+            if char_exists(ia_c) then goto found;
+          end;
+      begin_diagnostic;
+      print_nl("Missing character: Incomplete substitution ");
+@.Missing character@>
+      print_ASCII(qo(c)); print(" = "); print_ASCII(accent_c);
+      print(" "); print_ASCII(base_c); print(" in font ");
+      slow_print(font_name[f]); print_char("!"); end_diagnostic(false);
+      goto continue;
+      end;
+  begin_diagnostic;
+  print_nl("Missing character: There is no "); print("substitution for ");
+@.Missing character@>
+  print_ASCII(qo(c)); print(" in font ");
+  slow_print(font_name[f]); print_char("!"); end_diagnostic(false);
+  goto continue
+
+
+@ For |tracinglostchars>99| the substitution is shown in the log file.
+
+@<Print character substition tracing log@>=
+ if tracing_lost_chars>99 then
+   begin begin_diagnostic;
+   print_nl("Using character substitution: ");
+   print_ASCII(qo(c)); print(" = ");
+   print_ASCII(accent_c); print(" "); print_ASCII(base_c);
+   print(" in font "); slow_print(font_name[f]); print_char(".");
+   end_diagnostic(false);
+   end
+
+
+@ This outputs the accent and the base character given in the
+substitution.  It uses code virtually identical to the |make_accent|
+procedure, but without the node creation steps.
+
+Additionally if the accent character has to be shifted vertically it
+does {\it not\/} create the same code.  The original routine in
+|make_accent| and former versions of ML\TeX{} creates a box node
+resulting in |push| and |pop| operations, whereas this code simply
+produces vertical positioning operations.  This can influence the
+pixel rounding algorithm in some \.{DVI} drivers---and therefore will
+probably be changed in one of the next ML\TeX{} versions.
+
+@<Rebuild character using substitution information@>=
+  base_x_height:=x_height(f);
+  base_slant:=slant(f)/float_constant(65536);
+@^real division@>
+  accent_slant:=base_slant; {slant of accent character font}
+  base_width:=char_width(f)(ib_c);
+  base_height:=char_height(f)(height_depth(ib_c));
+  accent_width:=char_width(f)(ia_c);
+  accent_height:=char_height(f)(height_depth(ia_c));
+  @/{compute necessary horizontal shift (don't forget slant)}@/
+  delta:=round((base_width-accent_width)/float_constant(2)+
+            base_height*base_slant-base_x_height*accent_slant);
+@^real multiplication@>
+@^real addition@>
+  dvi_h:=cur_h;  {update |dvi_h|, similar to the last statement in module 620}
+  @/{1. For centering/horizontal shifting insert a kern node.}@/
+  cur_h:=cur_h+delta; synch_h;
+  @/{2. Then insert the accent character possibly shifted up or down.}@/
+  if ((base_height<>base_x_height) and (accent_height>0)) then
+    begin {the accent must be shifted up or down}
+    cur_v:=base_line+(base_x_height-base_height); synch_v;
+    if accent_c>=128 then dvi_out(set1);
+    dvi_out(accent_c);@/
+    cur_v:=base_line;
+    end
+  else begin synch_v;
+    if accent_c>=128 then dvi_out(set1);
+    dvi_out(accent_c);@/
+    end;
+  cur_h:=cur_h+accent_width; dvi_h:=cur_h;
+  @/{3. For centering/horizontal shifting insert another kern node.}@/
+  cur_h:=cur_h+(-accent_width-delta);
+  @/{4. Output the base character.}@/
+  synch_h; synch_v;
+  if base_c>=128 then dvi_out(set1);
+  dvi_out(base_c);@/
+  cur_h:=cur_h+base_width;
+  dvi_h:=cur_h {update of |dvi_h| is unnecessary, will be set in module 620}
+
+@ Dumping ML\TeX-related material.  This is just the flag in the
+format that tells us whether ML\TeX{} is enabled.
+
+@<Dump ML\TeX-specific data@>=
+dump_int(@"4D4C5458);  {ML\TeX's magic constant: "MLTX"}
+if mltex_p then dump_int(1)
+else dump_int(0);
+
+@ Undump ML\TeX-related material, which is just a flag in the format
+that tells us whether ML\TeX{} is enabled.
+
+@<Undump ML\TeX-specific data@>=
+undump_int(x);   {check magic constant of ML\TeX}
+if x<>@"4D4C5458 then goto bad_fmt;
+undump_int(x);   {undump |mltex_p| flag into |mltex_enabled_p|}
+if x=1 then mltex_enabled_p:=true
+else if x<>0 then goto bad_fmt;
+
+
+@* \[55/p\TeX] System-dependent changes for p\TeX.
+This section described extended variables, procesures, functions and so on
+for pTeX.
+
+@<Declare procedures that scan font-related stuff@>=
+function get_jfm_pos(@!kcode:KANJI_code;@!f:internal_font_number):eight_bits;
+var @!jc:KANJI_code; {temporary register for KANJI}
+@!sp,@!mp,@!ep:pointer;
+begin@/
+if f=null_font then
+  begin get_jfm_pos:=kchar_type(null_font)(0); return;
+  end;
+jc:=toDVI(kcode);
+sp:=1; { start position }
+ep:=font_num_ext[f]-1; { end position }
+if (ep>=1)and(kchar_code(f)(sp)<=jc)and(jc<=kchar_code(f)(ep)) then
+  begin while (sp <= ep) do
+    begin mp:=sp+((ep-sp) div 2);
+    if jc<kchar_code(f)(mp) then ep:=mp-1
+    else if jc>kchar_code(f)(mp) then sp:=mp+1
+    else
+      begin get_jfm_pos:=kchar_type(f)(mp); return;
+      end;
+    end;
+  end;
+get_jfm_pos:=kchar_type(f)(0);
+end;
+
+@ Following codes are used to calcutation a KANJI width and height.
+
+@<Local variables for dimension calculations@>=
+@!t: eight_bits;
+
+@ @<The KANJI width for |cur_jfont|@>=
+if direction=dir_tate then
+  v:=char_width(cur_tfont)(orig_char_info(cur_tfont)(qi(0)))
+else
+  v:=char_width(cur_jfont)(orig_char_info(cur_jfont)(qi(0)))
+
+@ @<The KANJI height for |cur_jfont|@>=
+if direction=dir_tate then begin
+  t:=height_depth(orig_char_info(cur_tfont)(qi(0)));
+  v:=char_height(cur_tfont)(t)+char_depth(cur_tfont)(t);
+end else begin
+  t:=height_depth(orig_char_info(cur_jfont)(qi(0)));
+  v:=char_height(cur_jfont)(t)+char_depth(cur_jfont)(t);
+end
+
+@ set a kansuji character.
+
+@ @<Put each...@>=
+primitive("kansujichar",set_kansuji_char,0);
+@!@:kansujichar_}{\.{\\kansujichar} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+set_kansuji_char: print_esc("kansujichar");
+
+@ @<Assignments@>=
+set_kansuji_char:
+begin p:=cur_chr; scan_int; n:=cur_val; scan_optional_equals; scan_int;
+if not is_char_kanji(cur_val) then
+  begin print_err("Invalid KANSUJI char (");
+  print_hex(cur_val); print_char(")");
+@.Invalid KANSUJI char@>
+  help1("I'm skip this control sequences.");@/
+  error; return;
+  end
+else if (n<0)or(n>9) then
+  begin print_err("Invalid KANSUJI number ("); print_int(n); print_char(")");
+@.Invalid KANSUJI number@>
+  help1("I'm skip this control sequences.");@/
+  error; return;
+  end
+else
+  define(kansuji_base+n,n,tokanji(toDVI(cur_val)));
+end;
+
+@ |print_kansuji| procedure converts a number to KANJI number.
+
+@ @<Declare procedures needed in |scan_something_internal|@>=
+procedure print_kansuji(@!n:integer);
+var @!k:0..23; {index to current digit; we assume that $|n|<10^{23}$}
+@!cx: KANJI_code; {temporary register for KANJI}
+begin k:=0;
+  if n<0 then return; {nonpositive input produces no output}
+  repeat dig[k]:=n mod 10; n:=n div 10; incr(k);
+  until n=0;
+  begin while k>0 do
+    begin decr(k);
+       cx:=kansuji_char(dig[k]);
+       print_kanji(fromDVI(cx));
+    end;
+  end;
+end;
+
+@ pTeX inserts a glue specified by \.{\\kanjiskip} between 2byte-characters,
+automatically, if \.{\\autospacing}.  This glue is suppressed by
+\.{\\noautospacing}.
+\.{\\xkanjiskip}, \.{\\noautoxspacing}, \.{\\autoxspacing}, \.{\\xspcode} is
+used to control between 2byte and 1byte characters.
+
+@d reset_auto_spacing_code=0
+@d set_auto_spacing_code=1
+@d reset_auto_xspacing_code=2
+@d set_auto_xspacing_code=3
+
+@<Put each...@>=
+primitive("autospacing",set_auto_spacing,set_auto_spacing_code);
+@!@:auto_spacing_}{\.{\\autospacing} primitive@>
+primitive("noautospacing",set_auto_spacing,reset_auto_spacing_code);
+@!@:no_auto_spacing_}{\.{\\noautospacing} primitive@>
+primitive("autoxspacing",set_auto_spacing,set_auto_xspacing_code);
+@!@:auto_xspacing_}{\.{\\autoxspacing} primitive@>
+primitive("noautoxspacing",set_auto_spacing,reset_auto_xspacing_code);
+@!@:no_auto_xspacing_}{\.{\\noautoxspacing} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+set_auto_spacing:begin
+  if (chr_code mod 2)=0 then print_esc("noauto") else print_esc("auto");
+  if chr_code<2 then print("spacing") else print("xspacing");
+end;
+
+@ @<Assignments@>=
+set_auto_spacing:begin
+  if cur_chr<2 then p:=auto_spacing_code
+  else begin p:=auto_xspacing_code; cur_chr:=(cur_chr mod 2); end;
+  define(p,data,cur_chr);
+end;
+
+@ Following codes are used in section 49.
+
+@<Show the current japanese processing mode@>=
+begin print_nl("> ");
+if auto_spacing>0 then print("auto spacing mode; ")
+  else print("no auto spacing mode; ");
+print_nl("> ");
+if auto_xspacing>0 then print("auto xspacing mode")
+  else print("no auto xspacing mode");
+goto common_ending;
+end
+
+@ The \.{\\inhibitglue} primitive control to insert a glue specified
+JFM (Japanese Font Metic) file.  The \.{\\inhibitxspcode} is used to control
+inserting a space between 2byte-char and 1byte-char.
+
+@d inhibit_both=0     {disable to insert space before 2byte-char and after it}
+@d inhibit_previous=1 {disable to insert space before 2byte-char}
+@d inhibit_after=2    {disable to insert space after 2byte-char}
+@d no_entry=1000
+@d new_pos=0
+@d cur_pos=1
+
+@<Global...@>=
+  inhibit_glue_flag:boolean;
+
+@ @<Set init...@>=
+  inhibit_glue_flag:=false;
+
+@ @<Cases of |main_control| that don't...@>=
+  any_mode(inhibit_glue): inhibit_glue_flag:=true;
+
+@ @<Put each...@>=
+primitive("inhibitglue",inhibit_glue,0);
+@!@:inhibit_glue_}{\.{\\inhibitglue} primitive@>
+primitive("inhibitxspcode",assign_inhibit_xsp_code,inhibit_xsp_code_base);
+@!@:inhibit_xsp_code_}{\.{\\inhibitxspcode} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+inhibit_glue: print_esc("inhibitglue");
+assign_inhibit_xsp_code: print_esc("inhibitxspcode");
+
+@ @<Declare procedures needed in |scan_something_internal|@>=
+function get_inhibit_pos(c:KANJI_code; n:small_number):pointer;
+label done, done1;
+var p,s:pointer;
+begin s:=calc_pos(c); p:=s;
+if n=new_pos then
+  begin repeat
+  if (inhibit_xsp_code(p)=0)or(inhibit_xsp_code(p)=c) then goto done;
+  incr(p); if p>255 then p:=0;
+  until s=p; p:=no_entry;
+  end
+else
+  begin repeat
+  if inhibit_xsp_code(p)=0 then goto done1;
+  if inhibit_xsp_code(p)=c then goto done;
+  incr(p); if p>255 then p:=0;
+  until s=p;
+done1: p:=no_entry;
+  end;
+done: get_inhibit_pos:=p;
+end;
+
+@ @<Assignments@>=
+assign_inhibit_xsp_code:
+begin p:=cur_chr; scan_int; n:=cur_val; scan_optional_equals; scan_int;
+if is_char_kanji(n) then
+  begin j:=get_inhibit_pos(tokanji(n),new_pos);
+  if j=no_entry then
+    begin print_err("Inhibit table is full!!");
+    help1("I'm skip this control sequences.");@/
+    error; return;
+  end;
+  define(inhibit_xsp_code_base+j,cur_val,n);
+  end
+else
+  begin print_err("Invalid KANJI code ("); print_hex(n); print_char(")");
+@.Invalid KANJI code@>
+  help1("I'm skip this control sequences.");@/
+  error; return;
+  end;
+end;
+
+@ @<Fetch inhibit type from some table@>=
+begin scan_int; q:=get_inhibit_pos(tokanji(cur_val),cur_pos);
+cur_val_level:=int_val; cur_val:=3;
+if q<>no_entry then cur_val:=inhibit_xsp_type(q);
+end
+
+@ The \.{\\prebreakpenalty} is used to specified amount of penalties inserted
+before the 2byte-char which is first argument of this primitive.
+The \.{\\postbreakpenalty} is inserted after the 2byte-char.
+
+@d pre_break_penalty_code=1
+@d post_break_penalty_code=2
+
+@<Put each...@>=
+primitive("prebreakpenalty",assign_kinsoku,pre_break_penalty_code);
+@!@:pre_break_penalty_}{\.{\\prebreakpenalty} primitive@>
+primitive("postbreakpenalty",assign_kinsoku,post_break_penalty_code);
+@!@:post_break_penalty_}{\.{\\postbreakpenalty} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+assign_kinsoku: case chr_code of
+  pre_break_penalty_code: print_esc("prebreakpenalty");
+  post_break_penalty_code: print_esc("postbreakpenalty");
+  endcases;
+
+@ @<Declare procedures needed in |scan_something_internal|@>=
+function get_kinsoku_pos(c:KANJI_code; n:small_number):pointer;
+label done, done1;
+var p,s:pointer;
+begin s:=calc_pos(c); p:=s;
+@!debug
+print_ln; print("c:="); print_int(c); print(", p:="); print_int(s);
+if p+kinsoku_base<0 then
+  begin print("p is negative value"); print_ln;
+  end;
+gubed
+if n=new_pos then
+  begin repeat
+  if (kinsoku_type(p)=0)or(kinsoku_code(p)=c) then goto done;
+  incr(p); if p>255 then p:=0;
+  until s=p;
+  p:=no_entry;
+  end
+else
+  begin repeat
+  if kinsoku_type(p)=0 then goto done1;
+  if kinsoku_code(p)=c then goto done;
+  incr(p); if p>255 then p:=0;
+  until s=p;
+done1: p:=no_entry;
+  end;
+done: get_kinsoku_pos:=p;
+end;
+
+@ @<Assignments@>=
+assign_kinsoku:
+begin p:=cur_chr; scan_int; n:=cur_val; scan_optional_equals; scan_int;
+if is_char_ascii(n) or is_char_kanji(n) then
+  begin j:=get_kinsoku_pos(tokanji(n),new_pos);
+  if j=no_entry then
+    begin print_err("KINSOKU table is full!!");
+    help1("I'm skip this control sequences.");@/
+    error; return;
+    end;
+  if (p=pre_break_penalty_code)or(p=post_break_penalty_code) then
+    begin define(kinsoku_base+j,p,tokanji(n));
+    word_define(kinsoku_penalty_base+j,cur_val);
+    end
+  else confusion("kinsoku");
+@:this can't happen kinsoku}{\quad kinsoku@>
+  end
+else
+  begin print_err("Invalid KANJI code for ");
+  if p=pre_break_penalty_code then print("pre")
+  else if p=post_break_penalty_code then print("post")
+  else print_char("?");
+  print("breakpenalty ("); print_hex(n); print_char(")");
+@.Invalid KANJI code@>
+  help1("I'm skip this control sequences.");@/
+  error; return;
+  end;
+end;
+
+@ @<Fetch breaking penalty from some table@>=
+begin scan_int; q:=get_kinsoku_pos(tokanji(cur_val),cur_pos);
+cur_val_level:=int_val; cur_val:=0;
+if (q<>no_entry)and(m=kinsoku_type(q)) then
+    scanned_result(kinsoku_penalty(q))(int_val);
+end
+
+@ Following codes are used in |main_control|.
+
+@<Insert kinsoku penalty@>=
+begin kp:=get_kinsoku_pos(cx,cur_pos);
+if kp<>no_entry then
+  begin if kinsoku_type(kp)=pre_break_penalty_code then
+    begin if not is_char_node(cur_q)and(type(cur_q)=penalty_node) then
+      penalty(cur_q):=penalty(cur_q)+kinsoku_penalty(kp)
+    else
+      begin main_p:=link(cur_q); link(cur_q):=new_penalty(kinsoku_penalty(kp));
+      subtype(link(cur_q)):=kinsoku_pena; link(link(cur_q)):=main_p;
+      end;
+    end
+  else if kinsoku_type(kp)=post_break_penalty_code then
+    begin tail_append(new_penalty(kinsoku_penalty(kp)));
+    subtype(tail):=kinsoku_pena;
+    end;
+  end;
+end;
+
+@ @<Insert |pre_break_penalty| of |cur_chr|@>=
+begin kp:=get_kinsoku_pos(cur_chr,cur_pos);
+if kp<>no_entry then
+  begin if kinsoku_type(kp)=pre_break_penalty_code then
+    if not is_char_node(tail)and(type(tail)=penalty_node) then
+      penalty(tail):=penalty(tail)+kinsoku_penalty(kp)
+    else
+      begin tail_append(new_penalty(kinsoku_penalty(kp)));
+      subtype(tail):=kinsoku_pena;
+      end;
+  end;
+end;
+
+@ @<Insert |post_break_penalty|@>=
+begin kp:=get_kinsoku_pos(cx,cur_pos);
+if kp<>no_entry then
+  begin if kinsoku_type(kp)=post_break_penalty_code then
+    begin tail_append(new_penalty(kinsoku_penalty(kp)));
+    subtype(tail):=kinsoku_pena;
+    end;
+  end;
+end;
+
+@ This is a part of section 32.
+
+The procedure |synch_dir| is used in |hlist_out| and |vlist_out|.
+
+@d dvi_yoko=0
+@d dvi_tate=1
+@d dvi_dtou=3
+
+@<Glob...@>=
+@!dvi_dir:integer; {a \.{DVI} reader program thinks we direct to}
+@!cur_dir_hv:integer; {\TeX\ thinks we direct to}
+@!page_dir:eight_bits;
+
+@ @<Set init...@>=
+page_dir:=dir_yoko;
+
+@ @<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+procedure synch_dir;
+var tmp:scaled; {temporary resister}
+begin
+  case cur_dir_hv of
+  dir_yoko:
+    if dvi_dir<>cur_dir_hv then begin
+      synch_h; synch_v; dvi_out(dirchg); dvi_out(dvi_yoko);
+      dir_used:=true;
+      case dvi_dir of
+        dir_tate: begin tmp:=cur_h; cur_h:=-cur_v; cur_v:=tmp end;
+        dir_dtou: begin tmp:=cur_h; cur_h:=cur_v; cur_v:=-tmp end;
+      endcases;
+      dvi_h:=cur_h; dvi_v:=cur_v; dvi_dir:=cur_dir_hv;
+    end;
+  dir_tate:
+    if dvi_dir<>cur_dir_hv then begin
+      synch_h; synch_v; dvi_out(dirchg); dvi_out(dvi_tate);
+      dir_used:=true;
+      case dvi_dir of
+        dir_yoko: begin tmp:=cur_h; cur_h:=cur_v; cur_v:=-tmp end;
+        dir_dtou: begin cur_v:=-cur_v; cur_h:=-cur_h; end;
+      endcases;
+      dvi_h:=cur_h; dvi_v:=cur_v; dvi_dir:=cur_dir_hv;
+    end;
+  dir_dtou:
+    if dvi_dir<>cur_dir_hv then begin
+      synch_h; synch_v; dvi_out(dirchg); dvi_out(dvi_dtou);
+      dir_used:=true;
+      case dvi_dir of
+        dir_yoko: begin tmp:=cur_h; cur_h:=-cur_v; cur_v:=tmp end;
+        dir_tate: begin cur_v:=-cur_v; cur_h:=-cur_h; end;
+      endcases;
+      dvi_h:=cur_h; dvi_v:=cur_v; dvi_dir:=cur_dir_hv;
+    end;
+  othercases
+    confusion("synch_dir");
+  endcases
+end;
+
+@ This function is called from |adjust_hlist| to used to check, whether
+a list which pointed |box_p| contain a printing character.
+If the list contain such a character, then return `true', otherwise `false'.
+If the first matter is a character, |first_char| is stored it.
+|last_char| is stored a last character.  If no printing characters exist
+in the list, |first_char| and |last_char| is null.
+@^recursion@>
+
+Note that |first_char| and |last_char| may be |math_node|.
+
+@<Glob...@>=
+@!first_char:pointer; {first printable character}
+@!last_char:pointer; {last printable character}
+@!find_first_char:boolean; {find for a first printable character?}
+
+@ @<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+function check_box(box_p:pointer):boolean;
+label done;
+var @!p:pointer; {run through the current box}
+@!flag:boolean; {found any printable character?}
+begin flag:=false; p:=box_p;
+while p<>null do
+  begin if is_char_node(p) then
+    repeat
+    if find_first_char then
+      begin first_char:=p; find_first_char:=false
+      end;
+    last_char:=p; flag:=true;
+    if font_dir[font(p)]<>dir_default then p:=link(p);
+    p:=link(p);
+    if p=null then goto done;
+    until not is_char_node(p);
+  case type(p) of
+  hlist_node:
+    begin flag:=true;
+      if shift_amount(p)=0 then
+        begin if check_box(list_ptr(p)) then flag:=true;
+        end
+      else if find_first_char then find_first_char:=false
+        else last_char:=null;
+    end;
+  ligature_node: if check_box(lig_ptr(p)) then flag:=true;
+  ins_node,disp_node,mark_node,adjust_node,whatsit_node,penalty_node:
+    do_nothing;
+  math_node:
+    if (subtype(p)=before)or(subtype(p)=after) then
+      begin if find_first_char then
+        begin find_first_char:=false; first_char:=p;
+        end;
+        last_char:=p; flag:=true;
+      end
+    else do_nothing; {\.{\\beginR} etc.}
+  othercases begin flag:=true;
+    if find_first_char then find_first_char:=false
+    else last_char:=null;
+    end;
+  endcases;
+  p:=link(p);
+  end;
+done: check_box:=flag;
+end;
+
+@ Following procedure |adjust_hlist| inserts \.{\\xkanjiskip} between
+2byte-char and 1byte-char in hlist which pointed |p|.
+Note that the skip is inserted into a place where too difficult to decide
+whether inserting or not (i.e, before penalty, after penalty).
+
+If |pf| is true then insert |jchr_widow_penalty| that is penalty for
+creating a widow KANJI character line.
+
+@d no_skip=0
+@d after_schar=1 {denote after single byte character}
+@d after_wchar=2 {denote after double bytes character}
+
+@<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+procedure adjust_hlist(p:pointer;pf:boolean);
+label exit;
+var q,s,t,u,v,x,z:pointer;
+  i,k:halfword;
+  a: pointer; { temporary pointer for accent }
+  insert_skip:no_skip..after_wchar;
+  cx:KANJI_code; {temporaly register for KANJI character}
+  ax:ASCII_code; {temporaly register for ASCII character}
+  do_ins:boolean; {for inserting |xkanji_skip| into prevous (or after) KANJI}
+begin if link(p)=null then goto exit;
+if auto_spacing>0 then
+  begin delete_glue_ref(space_ptr(p)); space_ptr(p):=kanji_skip;
+  add_glue_ref(kanji_skip);
+  end;
+if auto_xspacing>0 then
+  begin delete_glue_ref(xspace_ptr(p)); xspace_ptr(p):=xkanji_skip;
+  add_glue_ref(xkanji_skip);
+  end;
+u:=space_ptr(p); add_glue_ref(u);
+s:=xspace_ptr(p); add_glue_ref(s);
+if not is_char_node(link(p)) {p1.0.9d}
+    and(type(link(p))=glue_node)and(subtype(link(p))=jfm_skip+1) then
+  begin v:=link(p); link(p):=link(v);
+  fast_delete_glue_ref(glue_ptr(v)); free_node(v,small_node_size);
+  end;
+i:=0; insert_skip:=no_skip; p:=link(p); v:=p; q:=p;
+while p<>null do
+  begin if is_char_node(p) then
+    begin repeat @<Insert a space around the character |p|@>;
+      q:=p; p:=link(p); incr(i);
+      if (i>5)and pf then
+        begin if is_char_node(v) then
+        if font_dir[font(v)]<>dir_default then v:=link(v);
+        v:=link(v);
+        end;
+    until not is_char_node(p);
+    end
+  else
+    begin case type(p) of
+    hlist_node: @<Insert hbox surround spacing@>;
+    ligature_node: @<Insert ligature surround spacing@>;
+    penalty_node,disp_node: @<Insert penalty or displace surround spacing@>;
+    kern_node: if subtype(p)=explicit then insert_skip:=no_skip
+      else if subtype(p)=acc_kern then begin
+        { When we insert \.{\\xkanjiskip}, we first ignore accent (and kerns) and
+          insert \.{\\xkanjiskip}, then we recover the accent. }
+        if q=p then begin t:=link(p);
+          { if p is beginning on the list, we have only to ignore nodes. }
+          if is_char_node(t) then
+            if font_dir[font(t)]<>dir_default then t:=link(t);
+          p:=link(link(t));
+         if font_dir[font(p)]<>dir_default then
+            begin p:=link(p); insert_skip:=after_wchar; end
+          else  insert_skip:=after_schar;
+          end
+        else begin
+          a:=p; t:=link(p);
+          if is_char_node(t) then
+            if font_dir[font(t)]<>dir_default then t:=link(t);
+          t:=link(link(t)); link(q):=t; p:=t;
+          @<Insert a space around the character |p|@>; incr(i);
+          if (i>5)and pf then
+            begin if is_char_node(v) then
+            if font_dir[font(v)]<>dir_default then v:=link(v);
+            v:=link(v);
+            end;
+          if link(q)<>t then link(link(q)):=a else link(q):=a;
+          end;
+        end;
+    math_node: @<Insert math surround spacing@>;
+    mark_node,adjust_node,ins_node,whatsit_node:
+      {These nodes are vanished when typeset is done}
+      do_nothing;
+    othercases insert_skip:=no_skip;
+    endcases;
+    q:=p; p:=link(p);
+    end;
+  end;
+if not is_char_node(q)and(type(q)=glue_node)and(subtype(q)=jfm_skip+1) then
+  begin fast_delete_glue_ref(glue_ptr(q));
+  glue_ptr(q):=zero_glue; add_glue_ref(zero_glue);
+  end;
+delete_glue_ref(u); delete_glue_ref(s);
+if (v<>null)and pf and(i>5) then @<Make |jchr_widow_penalty| node@>;
+exit:
+end;
+
+@ @<Insert a space around the character |p|@>=
+if font_dir[font(p)]<>dir_default then
+  begin KANJI(cx):=info(link(p));
+  if insert_skip=after_schar then @<Insert ASCII-KANJI spacing@>;
+  p:=link(p); insert_skip:=after_wchar;
+  end
+else
+  begin ax:=qo(character(p));
+  if insert_skip=after_wchar then @<Insert KANJI-ASCII spacing@>;
+  if auto_xsp_code(ax)>=2 then
+    insert_skip:=after_schar else insert_skip:=no_skip;
+  end
+
+@ @<Insert hbox surround spacing@>=
+begin find_first_char:=true; first_char:=null; last_char:=null;
+if shift_amount(p)=0 then
+  begin if check_box(list_ptr(p)) then
+    begin if first_char<>null then @<Insert a space before the |first_char|@>;
+    if last_char<>null then
+      begin @<Insert a space after the |last_char|@>;
+      end else insert_skip:=no_skip;
+    end else insert_skip:=no_skip;
+  end else insert_skip:=no_skip;
+end
+
+@ @<Insert a space before the |first_char|@>=
+if type(first_char)=math_node then
+  begin ax:=qo("0");
+  if insert_skip=after_wchar then @<Insert KANJI-ASCII spacing@>;
+  end
+else if font_dir[font(first_char)]<>dir_default then
+  begin KANJI(cx):=info(link(first_char));
+  if insert_skip=after_schar then @<Insert ASCII-KANJI spacing@>
+  else if insert_skip=after_wchar then @<Insert KANJI-KANJI spacing@>;
+  end
+else
+  begin ax:=qo(character(first_char));
+  if insert_skip=after_wchar then @<Insert KANJI-ASCII spacing@>;
+  end;
+
+@ @<Insert a space after the |last_char|@>=
+if type(last_char)=math_node then
+  begin ax:=qo("0");
+  if auto_xsp_code(ax)>=2 then
+    insert_skip:=after_schar else insert_skip:=no_skip;
+  end
+else if font_dir[font(last_char)]<>dir_default then
+  begin insert_skip:=after_wchar; KANJI(cx):=info(link(last_char));
+  if is_char_node(link(p))and(font_dir[font(link(p))]<>dir_default) then
+    begin @<Append KANJI-KANJI spacing@>; p:=link(p);
+    end;
+  end
+else
+  begin ax:=qo(character(last_char));
+  if auto_xsp_code(ax)>=2 then
+    insert_skip:=after_schar else insert_skip:=no_skip;
+  end;
+
+@ @<Insert math surround spacing@>=
+begin if (subtype(p)=before)and(insert_skip=after_wchar) then
+  begin ax:=qo("0"); @<Insert KANJI-ASCII spacing@>;
+  insert_skip:=no_skip;
+  end
+else if subtype(p)=after then
+  begin ax:=qo("0");
+  if auto_xsp_code(ax)>=2 then
+    insert_skip:=after_schar else insert_skip:=no_skip;
+  end
+else insert_skip:=no_skip;
+end
+
+@ @<Insert ligature surround spacing@>=
+begin t:=lig_ptr(p);
+if is_char_node(t) then
+  begin ax:=qo(character(t));
+  if insert_skip=after_wchar then @<Insert KANJI-ASCII spacing@>;
+  while link(t)<>null do t:=link(t);
+  if is_char_node(t) then
+    begin ax:=qo(character(t));
+    if auto_xsp_code(ax)>=2 then
+      insert_skip:=after_schar else insert_skip:=no_skip;
+    end;
+  end;
+end
+
+@ @<Insert penalty or displace surround spacing@>=
+begin if is_char_node(link(p)) then
+  begin q:=p; p:=link(p);
+  if font_dir[font(p)]<>dir_default then
+    begin KANJI(cx):=info(link(p));
+    if insert_skip=after_schar then @<Insert ASCII-KANJI spacing@>
+    else if insert_skip=after_wchar then @<Insert KANJI-KANJI spacing@>;
+    p:=link(p); insert_skip:=after_wchar;
+    end
+  else
+    begin ax:=qo(character(p));
+    if insert_skip=after_wchar then @<Insert KANJI-ASCII spacing@>;
+    if auto_xsp_code(ax)>=2 then
+      insert_skip:=after_schar else insert_skip:=no_skip;
+    end;
+  end
+end
+
+@ @<Insert ASCII-KANJI spacing@>=
+begin
+  begin x:=get_inhibit_pos(cx,cur_pos);
+  if x<>no_entry then
+    if (inhibit_xsp_type(x)=inhibit_both)or
+       (inhibit_xsp_type(x)=inhibit_previous) then
+      do_ins:=false else do_ins:=true
+  else do_ins:=true;
+  end;
+if do_ins then
+  begin z:=new_glue(s); subtype(z):=xkanji_skip_code+1;
+  link(z):=link(q); link(q):=z; q:=z;
+  end;
+end
+
+@ @<Insert KANJI-ASCII spacing@>=
+begin if (auto_xsp_code(ax) mod 2)=1 then
+  begin x:=get_inhibit_pos(cx,cur_pos);
+  if x<>no_entry then
+    if (inhibit_xsp_type(x)=inhibit_both)or
+       (inhibit_xsp_type(x)=inhibit_after) then
+      do_ins:=false else do_ins:=true
+  else do_ins:=true;
+  end
+else do_ins:=false;
+if do_ins then
+  begin z:=new_glue(s); subtype(z):=xkanji_skip_code+1;
+  link(z):=link(q); link(q):=z; q:=z;
+  end;
+end
+
+@ @<Insert KANJI-KANJI spacing@>=
+begin z:=new_glue(u); subtype(z):=kanji_skip_code+1;
+link(z):=link(q); link(q):=z; q:=z;
+end
+
+@ @<Append KANJI-KANJI spacing@>=
+begin z:=new_glue(u); subtype(z):=kanji_skip_code+1;
+link(z):=link(p); link(p):=z; p:=link(z); q:=z;
+end
+
+@ @<Make |jchr_widow_penalty| node@>=
+begin q:=v; p:=link(v);
+if is_char_node(v)and(font_dir[font(v)]<>dir_default) then
+  begin q:=p; p:=link(p);
+  end;
+t:=q; s:=null;
+@<Seek list and make |t| pointing widow penalty position@>;
+if s<>null then
+  begin s:=link(t);
+    if not is_char_node(s)and(type(s)=penalty_node) then
+      penalty(s):=penalty(s)+jchr_widow_penalty
+    else if jchr_widow_penalty<>0 then
+      begin s:=new_penalty(jchr_widow_penalty); subtype(s):=widow_pena;
+      link(s):=link(t); link(t):=s; t:=link(s);
+      while(not is_char_node(t)) do
+        begin if (type(t)=glue_node)or(type(t)=kern_node) then goto exit;
+        t:=link(t);
+        end;
+      z:=new_glue(u); subtype(z):=kanji_skip_code+1;
+      link(z):=link(s); link(s):=z;
+      end;
+  end;
+end;
+
+@ @<Seek list and make |t| pointing widow penalty position@>=
+while(p<>null) do
+begin if is_char_node(p) then
+  begin if font_dir[font(p)]<>dir_default then
+    begin KANJI(cx):=info(link(p)); i:=kcat_code(kcatcodekey(cx)); k:=0;
+    if (i=kanji)or(i=kana) then begin t:=q; s:=p; end;
+    p:=link(p); q:=p;
+    end
+  else begin k:=k+1;
+    if k>1 then begin q:=p; s:=null; end;
+    end;
+  end
+else begin case type(p) of
+  penalty_node,mark_node,adjust_node,whatsit_node,
+  glue_node,kern_node,math_node,disp_node:
+    do_nothing;
+  othercases begin q:=p; s:=null; end;
+  endcases;
+  end;
+p:=link(p);
+end
+
+@ @<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+procedure dir_out;
+var @!this_box: pointer; {pointer to containing box}
+begin this_box:=temp_ptr;
+  temp_ptr:=list_ptr(this_box);
+  if (type(temp_ptr)<>hlist_node)and(type(temp_ptr)<>vlist_node) then
+    confusion("dir_out");
+  case box_dir(this_box) of
+  dir_yoko:
+    case box_dir(temp_ptr) of
+    dir_tate: {Tate in Yoko}
+      begin cur_v:=cur_v-height(this_box); cur_h:=cur_h+depth(temp_ptr) end;
+    dir_dtou: {DtoU in Yoko}
+      begin cur_v:=cur_v+depth(this_box); cur_h:=cur_h+height(temp_ptr) end;
+    endcases;
+  dir_tate:
+    case box_dir(temp_ptr) of
+    dir_yoko: {Yoko in Tate}
+      begin cur_v:=cur_v+depth(this_box); cur_h:=cur_h+height(temp_ptr) end;
+    dir_dtou: {DtoU in Tate}
+      begin
+        cur_v:=cur_v+depth(this_box)-height(temp_ptr);
+        cur_h:=cur_h+width(temp_ptr)
+      end;
+    endcases;
+  dir_dtou:
+    case box_dir(temp_ptr) of
+    dir_yoko: {Yoko in DtoU}
+      begin cur_v:=cur_v-height(this_box); cur_h:=cur_h+depth(temp_ptr) end;
+    dir_tate: {Tate in DtoU}
+      begin
+        cur_v:=cur_v+depth(this_box)-height(temp_ptr);
+        cur_h:=cur_h+width(temp_ptr)
+      end;
+    endcases;
+  endcases;
+  cur_dir_hv:=box_dir(temp_ptr);
+  if type(temp_ptr)=vlist_node then vlist_out@+else hlist_out;
+end;
+
+@ These routines are used to output diagnostic which related direction.
+
+@ @<Basic printing procedures@>=
+procedure print_dir(@!dir:eight_bits); {prints |dir| data}
+begin if dir=dir_yoko then print_char("Y")
+else if dir=dir_tate then print_char("T")
+else if dir=dir_dtou then print_char("D")
+end;
+@#
+procedure print_direction(@!d:integer); {print the direction represented by d}
+begin case abs(d) of
+dir_yoko: print("yoko");
+dir_tate: print("tate");
+dir_dtou: print("dtou");
+end;
+if d<0 then print("(math)");
+print(" direction");
+end;
+
+@ The procedure |set_math_kchar| is same as |set_math_char| which
+written in section 48.
+
+@<Declare act...@>=
+procedure set_math_kchar(@!c:integer);
+var p:pointer; {the new noad}
+begin p:=new_noad; math_type(nucleus(p)):=math_jchar;
+inhibit_glue_flag:=false;
+character(nucleus(p)):=qi(0);
+math_kcode(p):=c; fam(nucleus(p)):=cur_jfam;
+if font_dir[fam_fnt(fam(nucleus(p))+cur_size)]=dir_default then
+  begin print_err("Not two-byte family");
+  help1("IGNORE.");@/
+  error;
+  end;
+type(p):=ord_noad;
+link(tail):=p; tail:=p;
+end;
+
+@ This section is a part of |main_control|.
+
+@<Append KANJI-character |cur_chr| ...@>=
+if is_char_node(tail) then
+  begin cx:=qo(character(tail)); @<Insert |post_break_penalty|@>;
+  end
+else if type(tail)=ligature_node then
+  begin cx:=qo(character(lig_char(tail))); @<Insert |post_break_penalty|@>;
+  end;
+if direction=dir_tate then
+  begin if font_dir[main_f]=dir_tate then disp:=0
+  else if font_dir[main_f]=dir_yoko then disp:=t_baseline_shift-y_baseline_shift
+  else disp:=t_baseline_shift;
+  main_f:=cur_tfont;
+  end
+else
+  begin if font_dir[main_f]=dir_yoko then disp:=0
+  else if font_dir[main_f]=dir_tate then disp:=y_baseline_shift-t_baseline_shift
+  else disp:=y_baseline_shift;
+  main_f:=cur_jfont;
+  end;
+@<Append |disp_node| at end of displace area@>;
+ins_kp:=false; ligature_present:=false;
+cur_l:=qi(get_jfm_pos(KANJI(cur_chr),main_f));
+main_i:=orig_char_info(main_f)(qi(0));
+goto main_loop_j+3;
+@#
+main_loop_j+1: space_factor:=1000;
+  if main_f<>null_font then
+    begin fast_get_avail(main_p); font(main_p):=main_f; character(main_p):=cur_l;
+    link(tail):=main_p; tail:=main_p; last_jchr:=tail;
+    fast_get_avail(main_p); info(main_p):=KANJI(cur_chr);
+    link(tail):=main_p; tail:=main_p;
+    cx:=cur_chr; @<Insert kinsoku penalty@>;
+  end;
+  ins_kp:=false;
+again_2:
+  get_next;
+  main_i:=orig_char_info(main_f)(cur_l);
+  case cur_cmd of
+    kanji,kana,other_kchar: begin
+      cur_l:=qi(get_jfm_pos(KANJI(cur_chr),main_f)); goto main_loop_j+3;
+      end;
+    letter,other_char: begin ins_kp:=true; cur_l:=qi(0); goto main_loop_j+3;
+      end;
+  endcases;
+  x_token;
+  case cur_cmd of
+    kanji,kana,other_kchar: cur_l:=qi(get_jfm_pos(KANJI(cur_chr),main_f));
+    letter,other_char: begin ins_kp:=true; cur_l:=qi(0); end;
+    char_given: begin
+      if is_char_ascii(cur_chr) then
+        begin ins_kp:=true; cur_l:=qi(0);
+        end
+      else cur_l:=qi(get_jfm_pos(KANJI(cur_chr),main_f));
+      end;
+    char_num: begin scan_char_num; cur_chr:=cur_val;
+      if is_char_ascii(cur_chr) then
+        begin ins_kp:=true; cur_l:=qi(0);
+        end
+      else cur_l:=qi(get_jfm_pos(KANJI(cur_chr),main_f));
+      end;
+    inhibit_glue: begin inhibit_glue_flag:=true; goto again_2; end;
+    othercases begin ins_kp:=max_halfword;
+      cur_l:=qi(0); cur_r:=non_char; lig_stack:=null;
+      end;
+  endcases;
+@#
+main_loop_j+3:
+  if ins_kp=true then @<Insert |pre_break_penalty| of |cur_chr|@>;
+  if main_f<>null_font then
+    begin @<Look ahead for glue or kerning@>;
+    end
+  else inhibit_glue_flag:=false;
+  if ins_kp=false then begin { Kanji -> Kanji }
+    goto main_loop_j+1;
+  end else if ins_kp=true then begin { Kanji -> Ascii }
+    {@@<Append |disp_node| at begin of displace area@@>;}
+    ins_kp:=false; goto main_loop;
+  end else begin { Kanji -> cs }
+    {@@<Append |disp_node| at begin of displace area@@>;}
+    goto reswitch;
+  end;
+
+@ @<Append |disp_node| at begin ...@>=
+begin if not is_char_node(tail)and(type(tail)=disp_node) then
+  begin if prev_disp=disp then
+    begin free_node(tail,small_node_size); tail:=prev_node; link(tail):=null;
+    end
+  else disp_dimen(tail):=disp;
+  end
+else
+  if disp<>0 then
+    begin prev_node:=tail; tail_append(get_node(small_node_size));
+    type(tail):=disp_node; disp_dimen(tail):=disp; prev_disp:=disp;
+    end;
+end;
+
+@ @<Append |disp_node| at end ...@>=
+if disp<>0 then
+begin if not is_char_node(tail)and(type(tail)=disp_node) then
+  begin disp_dimen(tail):=0;
+  end
+else
+  begin prev_node:=tail; tail_append(get_node(small_node_size));
+  type(tail):=disp_node; disp_dimen(tail):=0; prev_disp:=disp;
+  end;
+end;
+
+@ @<Look ahead for glue or kerning@>=
+cur_q:=tail;
+if inhibit_glue_flag<>true then
+  begin if char_tag(main_i)=gk_tag then
+    begin main_k:=glue_kern_start(main_f)(main_i);
+    repeat main_j:=font_info[main_k].qqqq;
+    if next_char(main_j)=cur_l then
+      begin if op_byte(main_j)<kern_flag then
+        begin gp:=font_glue[main_f]; cur_r:=rem_byte(main_j);
+        if gp<>null then
+          begin while((type(gp)<>cur_r)and(link(gp)<>null)) do gp:=link(gp);
+          gq:=glue_ptr(gp);
+          end
+        else
+          begin gp:=get_node(small_node_size); font_glue[main_f]:=gp;
+          gq:=null;
+          end;
+        if gq=null then
+          begin type(gp):=cur_r; gq:=new_spec(zero_glue);
+          glue_ptr(gp):=gq;
+          main_k:=exten_base[main_f]+qi((qo(cur_r))*3);
+          width(gq):=font_info[main_k].sc;
+          stretch(gq):=font_info[main_k+1].sc;
+          shrink(gq):=font_info[main_k+2].sc;
+          add_glue_ref(gq); link(gp):=get_node(small_node_size);
+          gp:=link(gp); glue_ptr(gp):=null; link(gp):=null;
+          end;
+        tail_append(new_glue(gq)); subtype(tail):=jfm_skip+1;
+        goto skip_loop;
+        end
+      else  begin
+        tail_append(new_kern(char_kern(main_f)(main_j)));
+        goto skip_loop;
+        end;
+    end;
+  incr(main_k);
+  until skip_byte(main_j)>=stop_flag;
+  end;
+end;
+skip_loop: inhibit_glue_flag:=false;
+
+@ @<Basic printing...@>=
+procedure print_kanji(@!s:KANJI_code); {prints a single character}
+begin
+if s>255 then
+  begin print_char(Hi(s)); print_char(Lo(s));
+  end else print_char(s);
+end;
+
+@* \[56] System-dependent changes.
+This section should be replaced, if necessary, by any special
+modifications of the program
+that are necessary to make \TeX\ work at a particular installation.
+It is usually best to design your change file so that all changes to
+previous sections preserve the section numbering; then everybody's version
+will be consistent with the published program. More extensive changes,
+which introduce new sections, can be inserted here; then only the index
+itself will get a new section number.
+@^system dependencies@>
+
+
+@ @<Declare action procedures for use by |main_control|@>=
+
+procedure insert_src_special;
+var toklist, p, q : pointer;
+begin
+  if (source_filename_stack[in_open] > 0 and is_new_source (source_filename_stack[in_open]
+, line)) then begin
+    toklist := get_avail;
+    p := toklist;
+    info(p) := cs_token_flag+frozen_special;
+    link(p) := get_avail; p := link(p);
+    info(p) := left_brace_token+"{";
+    q := str_toks (make_src_special (source_filename_stack[in_open], line));
+    link(p) := link(temp_head);
+    p := q;
+    link(p) := get_avail; p := link(p);
+    info(p) := right_brace_token+"}";
+    ins_list (toklist);
+    remember_source_info (source_filename_stack[in_open], line);
+  end;
+end;
+
+procedure append_src_special;
+var q : pointer;
+begin
+  if (source_filename_stack[in_open] > 0 and is_new_source (source_filename_stack[in_open]
+, line)) then begin
+    new_whatsit (special_node, write_node_size);
+    write_stream(tail) := 0;
+    def_ref := get_avail;
+    token_ref_count(def_ref) := null;
+    q := str_toks (make_src_special (source_filename_stack[in_open], line));
+    link(def_ref) := link(temp_head);
+    write_tokens(tail) := def_ref;
+    remember_source_info (source_filename_stack[in_open], line);
+  end;
+end;
+
+@ This function used to be in pdftex, but is useful in tex too.
+
+@p function get_nullstr: str_number;
+begin
+    get_nullstr := "";
+end;
+
+@* \[55] Index.
+Here is where you can find all uses of each identifier in the program,
+with underlined entries pointing to where the identifier was defined.
+If the identifier is only one letter long, however, you get to see only
+the underlined entries. {\sl All references are to section numbers instead of
+page numbers.}
+
+This index also lists error messages and other aspects of the program
+that you might want to look up some day. For example, the entry
+for ``system dependencies'' lists all sections that should receive
+special attention from people who are installing \TeX\ in a new
+operating environment. A list of various things that can't happen appears
+under ``this can't happen''. Approximately 40 sections are listed under
+``inner loop''; these account for about 60\pct! of \TeX's running time,
+exclusive of input and output.