diff options
Diffstat (limited to 'web/web2w/ctex.tex')
-rw-r--r-- | web/web2w/ctex.tex | 38140 |
1 files changed, 38140 insertions, 0 deletions
diff --git a/web/web2w/ctex.tex b/web/web2w/ctex.tex new file mode 100644 index 0000000000..03e8cd6ad3 --- /dev/null +++ b/web/web2w/ctex.tex @@ -0,0 +1,38140 @@ +\input cwebmac +% 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). +% Version 3.14159265 was similar (January 2014). + +% 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@> + +\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 to 1in{\hfil##1.\ }} + } +\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...>" + +\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings + \let\\=\BS % backslash in a string + \let\'=\RQ % right quote in a string + \let\`=\LQ % left quote in a string + \let\{=\LB % left brace in a string + \let\}=\RB % right brace in a string + \let\~=\TL % tilde in a string + \let\ =\SP % space in a string + \let\_=\UL % underline in a string + \let\&=\AM % ampersand in a string + #1\kern.05em}} +\def\^{\ifmmode\mathchar"222 \else\char`^ \fi} % pointer or hat +\def\LQ{{\tt\char'22}} % left quote in a string +\def\RQ{{\tt\char'23}} % right quote in a string +\def\dotdot{\mathrel{.\,.}} % double dot, used only in math mode + +\N{1}{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 + +\M{2}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]. + +\Y\B\4\D$\\{banner}$ \5 +\.{"This\ is\ TeX,\ Versio}\)\.{n\ 3.14159265\ (HINT)"}\C{printed when \TeX\ starts}\par +\fi + +\M{3}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 +\&{double} $\K$ \&{int}; 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 + +\M{4}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. + +Actually the heading shown here is not quite normal: The line +does not mention any \\{output} file, because \ph\ would ask the \TeX\ user +to specify a file name if \\{output} were specified here. + +\Y\B\F\\{type} \5 +\\{true}\C{but `\\{type}' will not be treated as a reserved word}\par +\Y\B\hbox{\4}\X9:Compiler directives\X\C{all file names are defined dynamically}\6 +\X6:Labels in the outer block\X\6 +\X11:Constants in the outer block\X\6 +\X18:Types in the outer block\X\6 +\X13:Global variables\X\7 +\&{void} \\{initialize}(\&{void})\C{this procedure gets things started properly}\6 +${}\{{}$\5 +\1\X19:Local variables for initialization\X\6 +\X8:Initialize whatever \TeX\ might access\X;\6 +\4${}\}{}$\2\7 +\hbox{\4}\X57:Basic printing procedures\X\6 +\hbox{\4}\X78:Error handling procedures\X\par +\fi + +\M{5}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 + +\M{6}Three labels must be declared in the main program, so we give them +symbolic names. + +\Y\B\4\X6:Labels in the outer block\X${}\E{}$\6 +\hbox{\hskip-2pt}\hbox{\hskip-2pt}\,\C{key control points}\par +\U4.\fi + +\M{7}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\\{debug}$', 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}. + +\fi + +\M{8}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}$'. + +\Y\B\4\X8:Initialize whatever \TeX\ might access\X${}\E{}$\6 +\X21:Set initial values of key variables\X\6 +\8\#\&{ifdef} \.{INIT}\6 +\X164:Initialize table entries (done by \.{INITEX} only)\X\6 +\8\#\&{endif}\par +\U4.\fi + +\M{9}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\B\4\X9:Compiler directives\X${}\E{}$\6 +\8\#\&{include} \.{<stdint.h>}\6 +\8\#\&{include} \.{<stdbool.h>}\6 +\8\#\&{include} \.{<stdio.h>}\6 +\8\#\&{include} \.{<stdlib.h>}\6 +\8\#\&{include} \.{<string.h>}\6 +\8\#\&{include} \.{<math.h>}\6 +\8\#\&{define} \\{odd}(\|X) \5${}((\|X)\AND\T{1}){}$\6 +\8\#\&{define} \\{chr}(\|X) \5((\&{unsigned} \&{char})(\|X))\6 +\8\#\&{define} \\{ord}(\|X) \5((\&{int})(\|X))\6 +\8\#\&{if} ${}\.{\_\_SIZEOF\_FLOAT\_\_}\E\T{4}{}$\6 +\&{typedef} \&{float} \&{float32\_t};\6 +\8\#\&{else}\6 +\8\#\&{error} \&{float} \\{type}\\{must}\\{have}\\{size}\T{4} \6 +\8\#\&{endif}\6 +\ATH\par +\A56. +\U4.\fi + +\M{10}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\cr +1: $\langle\,$code for $x=1\,\rangle$;\cr +3: $\langle\,$code for $x=3\,\rangle$;\cr +\&{default}: $\langle\,$code for $\|x\I\T{1}$ and $\|x\I\T{3}$$\,\rangle$\cr +$\}$\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 `\&{default}::' as a default label, and other \PASCAL s allow +syntaxes like `\&{else}' or `\&{otherwise}' or `\\{otherwise}:', etc. The +definitions of \&{default}: and $\}$ should be changed to agree with +local conventions. Note that no semicolon appears before $\}$ in +this program, so the definition of $\}$ 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!) + +\fi + +\M{11}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\B\4\X11:Constants in the outer block\X${}\E{}$\6 +\&{enum} ${}\{{}$\5 +\1${}\\{mem\_max}\K{}$\T{30000}\5 +\2${}\}{}$;\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 +\&{enum} ${}\{{}$\5 +\1${}\\{mem\_min}\K{}$\T{0}\5 +\2${}\}{}$;\C{smallest index in \TeX's internal \\{mem} array; must be \\{min\_halfword} or more; must be equal to \\{mem\_bot} in \.{INITEX}, otherwise $\Z$ \\{mem\_bot}}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{buf\_size}\K{}$\T{500}\5 +\2${}\}{}$;\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 +\&{enum} ${}\{{}$\5 +\1${}\\{error\_line}\K{}$\T{72}\5 +\2${}\}{}$;\C{width of context lines on terminal error messages}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{half\_error\_line}\K{}$\T{42}\5 +\2${}\}{}$;\C{width of first lines of contexts in terminal error messages; should be between 30 and $\\{error\_line}-\T{15}$}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{max\_print\_line}\K{}$\T{79}\5 +\2${}\}{}$;\C{width of longest text lines output; should be at least 60}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{stack\_size}\K{}$\T{200}\5 +\2${}\}{}$;\C{maximum number of simultaneous input sources}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{max\_in\_open}\K{}$\T{6}\5 +\2${}\}{}$;\C{maximum number of input files and error insertions that can be going on simultaneously}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{font\_max}\K{}$\T{75}\5 +\2${}\}{}$;\C{maximum internal font number; must not exceed \\{max\_quarterword} and must be at most $\\{font\_base}+\T{256}$}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{font\_mem\_size}\K{}$\T{20000}\5 +\2${}\}{}$;\C{number of words of \\{font\_info} for all fonts}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{param\_size}\K{}$\T{60}\5 +\2${}\}{}$;\C{maximum number of simultaneous macro parameters}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{nest\_size}\K{}$\T{40}\5 +\2${}\}{}$;\C{maximum number of semantic levels simultaneously active}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{max\_strings}\K{}$\T{3000}\5 +\2${}\}{}$;\C{maximum number of strings; must not exceed \\{max\_halfword}}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{string\_vacancies}\K{}$\T{8000}\5 +\2${}\}{}$;\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 +\&{enum} ${}\{{}$\5 +\1${}\\{pool\_size}\K{}$\T{32000}\5 +\2${}\}{}$;\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 +\&{enum} ${}\{{}$\5 +\1${}\\{save\_size}\K{}$\T{600}\5 +\2${}\}{}$;\C{space for saving values outside of current group; must be at most \\{max\_halfword}}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{trie\_size}\K{}$\T{8000}\5 +\2${}\}{}$;\C{space for hyphenation patterns; should be larger for \.{INITEX} than it is in production versions of \TeX}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{trie\_op\_size}\K{}$\T{500}\5 +\2${}\}{}$;\C{space for ``opcodes'' in the hyphenation patterns}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{dvi\_buf\_size}\K{}$\T{800}\5 +\2${}\}{}$;\C{size of the output buffer; must be a multiple of 8}\6 +\&{enum} ${}\{{}$\5 +\1${}\\{file\_name\_size}\K{}$\T{40}\5 +\2${}\}{}$;\C{file names shouldn't be longer than this}\6 +\&{const} \&{char} ${}{*}\\{pool\_name}\K\.{"TeXformats:TEX.POOL}\)\.{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }\)\.{\ "}{}$;\C{string of length \\{file\_name\_size}; tells where the string pool appears}\par +\U4.\fi + +\M{12}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 list, in order to +emphasize this distinction. + +\Y\B\4\D$\\{mem\_bot}$ \5 +\T{0}\C{smallest index in the \\{mem} array dumped by \.{INITEX}; must not be less than \\{mem\_min}}\par +\B\4\D$\\{mem\_top}$ \5 +\T{30000}\C{largest index in the \\{mem} array dumped by \.{INITEX}; must be substantially larger than \\{mem\_bot} and not greater than \\{mem\_max}}\par +\B\4\D$\\{font\_base}$ \5 +\T{0}\C{smallest internal font number; must not be less than \\{min\_quarterword}}\par +\B\4\D$\\{hash\_size}$ \5 +\T{2100}\C{maximum number of control sequences; it should be at most about $(\\{mem\_max}-\\{mem\_min})/{}$(\&{double}) \T{10}}\par +\B\4\D$\\{hash\_prime}$ \5 +\T{1777}\C{a prime number equal to about 85\pct! of \\{hash\_size}}\par +\B\4\D$\\{hyph\_size}$ \5 +\T{307}\C{another prime; the number of \.{\\hyphenation} exceptions}\par +\fi + +\M{13}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\B\4\X13:Global variables\X${}\E{}$\6 +\&{int} \\{bad};\C{is some ``constant'' wrong?}\par +\As20, 26, 30, 32, 39, 50, 54, 73, 76, 79, 96, 104, 115, 116, 117, 118, 124, 165, 173, 181, 213, 246, 253, 256, 271, 286, 297, 301, 304, 305, 308, 309, 310, 333, 361, 382, 387, 388, 410, 438, 447, 480, 489, 493, 512, 513, 520, 526, 532, 539, 549, 550, +555, 592, 595, 605, 616, 646, 647, 661, 684, 719, 724, 764, 770, 814, 821, 823, 825, 828, 833, 839, 847, 872, 892, 900, 905, 907, 921, 926, 943, 947, 950, 971, 980, 982, 989, 1032, 1074, 1266, 1281, 1299, 1305, 1331, 1342\ETs1345. +\U4.\fi + +\M{14}Later on we will say `\ignorespaces\&{if} ${}(\\{mem\_max}\G\\{max\_halfword})$ $\\{bad}\K\T{14}$', +or something similar. (We can't do that until \\{max\_halfword} has been defined.) + +\Y\B\4\X14:Check the ``constant'' values for consistency\X${}\E{}$\6 +$\\{bad}\K\T{0};{}$\6 +\&{if} ${}((\\{half\_error\_line}<\T{30})\V(\\{half\_error\_line}>\\{error\_line}-\T{15})){}$\1\5 +${}\\{bad}\K\T{1};{}$\2\6 +\&{if} ${}(\\{max\_print\_line}<\T{60}){}$\1\5 +${}\\{bad}\K\T{2};{}$\2\6 +\&{if} ${}(\\{dvi\_buf\_size}\MOD\T{8}\I\T{0}){}$\1\5 +${}\\{bad}\K\T{3};{}$\2\6 +\&{if} ${}(\\{mem\_bot}+\T{1100}>\\{mem\_top}){}$\1\5 +${}\\{bad}\K\T{4};{}$\2\6 +\&{if} ${}(\\{hash\_prime}>\\{hash\_size}){}$\1\5 +${}\\{bad}\K\T{5};{}$\2\6 +\&{if} ${}(\\{max\_in\_open}\G\T{128}){}$\1\5 +${}\\{bad}\K\T{6};{}$\2\6 +\&{if} ${}(\\{mem\_top}<\T{256}+\T{11}){}$\1\5 +${}\\{bad}\K\T{7}{}$;\C{we will want $\\{null\_list}>\T{255}$}\2\par +\As111, 290, 521\ETs1249. +\U1332.\fi + +\M{15}Labels are given symbolic names by the following definitions, so that +occasional \&{goto} statements will be meaningful. We insert the label +`\\{end}' just before the `\ignorespaces$\}$\unskip' of a procedure in +which we have used the `\&{goto} \\{end}' 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 +`\\{resume}'. 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\B\4\D$\\{done6}$ \5 +\T{36}\C{for exiting the sixth loop in a block}\par +\fi + +\M{16}Here are some macros for common programming idioms. + +\Y\B\4\D$\\{incr}(\|X)$ \5 +$\|X\K\|X+{}$\T{1}\C{increase a variable by unity}\par +\B\4\D$\\{decr}(\|X)$ \5 +$\|X\K\|X-{}$\T{1}\C{decrease a variable by unity}\par +\B\4\D$\\{negate}(\|X)$ \5 +$\|X\K{-}{}$\|X\C{change the sign of a variable}\par +\B\4\D$\&{loop}$ \5 +\&{while} (\\{true})\5 +\C{repeat over and over until a \&{goto} happens}\par +\B\F\\{loop} \5 +\\{else}\C{\.{WEB}'s \&{else} acts like `\ignorespaces\&{while} \\{true} \&{do}\unskip'}\par +\B\4\D$\\{do\_nothing}$ \C{empty statement}\par +\B\4\D$\\{empty}$ \5 +\T{0}\C{symbolic name for a null constant}\par +\fi + +\N{1}{17}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=0101$, 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 + +\M{18}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\B\4\X18:Types in the outer block\X${}\E{}$\6 +\&{typedef} \&{uint8\_t} \&{ASCII\_code};\C{eight-bit numbers}\par +\As25, 38, 101, 109, 113, 150, 212, 269, 300, 548, 594, 920\ETs925. +\U4.\fi + +\M{19}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 040 through 0176; 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 \&{unsigned} \&{char} for the +characters in text files, even though there now are more than 64 such +characters, while other \PASCAL s consider \&{unsigned} \&{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\B\4\D$\\{text\_char}$ \5 +\&{unsigned} \&{char}\C{the data type of characters in text files}\par +\B\4\D$\\{first\_text\_char}$ \5 +\T{0}\C{ordinal number of the smallest element of \\{text\_char}}\par +\B\4\D$\\{last\_text\_char}$ \5 +\T{255}\C{ordinal number of the largest element of \\{text\_char}}\par +\Y\B\4\X19:Local variables for initialization\X${}\E{}$\6 +\&{int} \|i;\par +\As163\ET927. +\U4.\fi + +\M{20}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{ASCII\_code} \\{xord}[\T{256}];\C{specifies conversion of input characters}\6 +\&{uint8\_t} \\{xchr}[\T{256}];\C{specifies conversion of output characters}\par +\fi + +\M{21}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\B\4\X21:Set initial values of key variables\X${}\E{}$\6 +$\\{xchr}[\T{\~40}]\K\.{'\ '};{}$\5 +${}\\{xchr}[\T{\~41}]\K\.{'!'};{}$\5 +${}\\{xchr}[\T{\~42}]\K\.{'"'};{}$\5 +${}\\{xchr}[\T{\~43}]\K\.{'\#'};{}$\5 +${}\\{xchr}[\T{\~44}]\K\.{'\$'};{}$\5 +${}\\{xchr}[\T{\~45}]\K\.{'\%'};{}$\5 +${}\\{xchr}[\T{\~46}]\K\.{'\&'};{}$\5 +${}\\{xchr}[\T{\~47}]\K\.{'\\''}{}$;\6 +${}\\{xchr}[\T{\~50}]\K\.{'('};{}$\5 +${}\\{xchr}[\T{\~51}]\K\.{')'};{}$\5 +${}\\{xchr}[\T{\~52}]\K\.{'*'};{}$\5 +${}\\{xchr}[\T{\~53}]\K\.{'+'};{}$\5 +${}\\{xchr}[\T{\~54}]\K\.{','};{}$\5 +${}\\{xchr}[\T{\~55}]\K\.{'-'};{}$\5 +${}\\{xchr}[\T{\~56}]\K\.{'.'};{}$\5 +${}\\{xchr}[\T{\~57}]\K\.{'/'}{}$;\6 +${}\\{xchr}[\T{\~60}]\K\.{'0'};{}$\5 +${}\\{xchr}[\T{\~61}]\K\.{'1'};{}$\5 +${}\\{xchr}[\T{\~62}]\K\.{'2'};{}$\5 +${}\\{xchr}[\T{\~63}]\K\.{'3'};{}$\5 +${}\\{xchr}[\T{\~64}]\K\.{'4'};{}$\5 +${}\\{xchr}[\T{\~65}]\K\.{'5'};{}$\5 +${}\\{xchr}[\T{\~66}]\K\.{'6'};{}$\5 +${}\\{xchr}[\T{\~67}]\K\.{'7'}{}$;\6 +${}\\{xchr}[\T{\~70}]\K\.{'8'};{}$\5 +${}\\{xchr}[\T{\~71}]\K\.{'9'};{}$\5 +${}\\{xchr}[\T{\~72}]\K\.{':'};{}$\5 +${}\\{xchr}[\T{\~73}]\K\.{';'};{}$\5 +${}\\{xchr}[\T{\~74}]\K\.{'<'};{}$\5 +${}\\{xchr}[\T{\~75}]\K\.{'='};{}$\5 +${}\\{xchr}[\T{\~76}]\K\.{'>'};{}$\5 +${}\\{xchr}[\T{\~77}]\K\.{'?'}{}$;\6 +${}\\{xchr}[\T{\~100}]\K\.{'@'};{}$\5 +${}\\{xchr}[\T{\~101}]\K\.{'A'};{}$\5 +${}\\{xchr}[\T{\~102}]\K\.{'B'};{}$\5 +${}\\{xchr}[\T{\~103}]\K\.{'C'};{}$\5 +${}\\{xchr}[\T{\~104}]\K\.{'D'};{}$\5 +${}\\{xchr}[\T{\~105}]\K\.{'E'};{}$\5 +${}\\{xchr}[\T{\~106}]\K\.{'F'};{}$\5 +${}\\{xchr}[\T{\~107}]\K\.{'G'}{}$;\6 +${}\\{xchr}[\T{\~110}]\K\.{'H'};{}$\5 +${}\\{xchr}[\T{\~111}]\K\.{'I'};{}$\5 +${}\\{xchr}[\T{\~112}]\K\.{'J'};{}$\5 +${}\\{xchr}[\T{\~113}]\K\.{'K'};{}$\5 +${}\\{xchr}[\T{\~114}]\K\.{'L'};{}$\5 +${}\\{xchr}[\T{\~115}]\K\.{'M'};{}$\5 +${}\\{xchr}[\T{\~116}]\K\.{'N'};{}$\5 +${}\\{xchr}[\T{\~117}]\K\.{'O'}{}$;\6 +${}\\{xchr}[\T{\~120}]\K\.{'P'};{}$\5 +${}\\{xchr}[\T{\~121}]\K\.{'Q'};{}$\5 +${}\\{xchr}[\T{\~122}]\K\.{'R'};{}$\5 +${}\\{xchr}[\T{\~123}]\K\.{'S'};{}$\5 +${}\\{xchr}[\T{\~124}]\K\.{'T'};{}$\5 +${}\\{xchr}[\T{\~125}]\K\.{'U'};{}$\5 +${}\\{xchr}[\T{\~126}]\K\.{'V'};{}$\5 +${}\\{xchr}[\T{\~127}]\K\.{'W'}{}$;\6 +${}\\{xchr}[\T{\~130}]\K\.{'X'};{}$\5 +${}\\{xchr}[\T{\~131}]\K\.{'Y'};{}$\5 +${}\\{xchr}[\T{\~132}]\K\.{'Z'};{}$\5 +${}\\{xchr}[\T{\~133}]\K\.{'['};{}$\5 +${}\\{xchr}[\T{\~134}]\K\.{'\\\\'};{}$\5 +${}\\{xchr}[\T{\~135}]\K\.{']'};{}$\5 +${}\\{xchr}[\T{\~136}]\K\.{'\^'};{}$\5 +${}\\{xchr}[\T{\~137}]\K\.{'\_'}{}$;\6 +${}\\{xchr}[\T{\~140}]\K\.{'`'};{}$\5 +${}\\{xchr}[\T{\~141}]\K\.{'a'};{}$\5 +${}\\{xchr}[\T{\~142}]\K\.{'b'};{}$\5 +${}\\{xchr}[\T{\~143}]\K\.{'c'};{}$\5 +${}\\{xchr}[\T{\~144}]\K\.{'d'};{}$\5 +${}\\{xchr}[\T{\~145}]\K\.{'e'};{}$\5 +${}\\{xchr}[\T{\~146}]\K\.{'f'};{}$\5 +${}\\{xchr}[\T{\~147}]\K\.{'g'}{}$;\6 +${}\\{xchr}[\T{\~150}]\K\.{'h'};{}$\5 +${}\\{xchr}[\T{\~151}]\K\.{'i'};{}$\5 +${}\\{xchr}[\T{\~152}]\K\.{'j'};{}$\5 +${}\\{xchr}[\T{\~153}]\K\.{'k'};{}$\5 +${}\\{xchr}[\T{\~154}]\K\.{'l'};{}$\5 +${}\\{xchr}[\T{\~155}]\K\.{'m'};{}$\5 +${}\\{xchr}[\T{\~156}]\K\.{'n'};{}$\5 +${}\\{xchr}[\T{\~157}]\K\.{'o'}{}$;\6 +${}\\{xchr}[\T{\~160}]\K\.{'p'};{}$\5 +${}\\{xchr}[\T{\~161}]\K\.{'q'};{}$\5 +${}\\{xchr}[\T{\~162}]\K\.{'r'};{}$\5 +${}\\{xchr}[\T{\~163}]\K\.{'s'};{}$\5 +${}\\{xchr}[\T{\~164}]\K\.{'t'};{}$\5 +${}\\{xchr}[\T{\~165}]\K\.{'u'};{}$\5 +${}\\{xchr}[\T{\~166}]\K\.{'v'};{}$\5 +${}\\{xchr}[\T{\~167}]\K\.{'w'}{}$;\6 +${}\\{xchr}[\T{\~170}]\K\.{'x'};{}$\5 +${}\\{xchr}[\T{\~171}]\K\.{'y'};{}$\5 +${}\\{xchr}[\T{\~172}]\K\.{'z'};{}$\5 +${}\\{xchr}[\T{\~173}]\K\.{'\{'};{}$\5 +${}\\{xchr}[\T{\~174}]\K\.{'|'};{}$\5 +${}\\{xchr}[\T{\~175}]\K\.{'\}'};{}$\5 +${}\\{xchr}[\T{\~176}]\K\.{'\~'}{}$;\par +\As23, 24, 74, 77, 80, 97, 166, 215, 254, 257, 272, 287, 383, 439, 481, 490, 551, 556, 593, 596, 606, 648, 662, 685, 771, 928, 990, 1033, 1267, 1282, 1300\ETs1343. +\U8.\fi + +\M{22}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\B\4\D$\\{null\_code}$ \5 +\T{\~0}\C{ASCII code that might disappear}\par +\B\4\D$\\{carriage\_return}$ \5 +\T{\~15}\C{ASCII code used at end of line}\par +\B\4\D$\\{invalid\_code}$ \5 +\T{\~177}\C{ASCII code that many systems prohibit in text files}\par +\fi + +\M{23}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}[\T{0}\dotdot\T{\~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~040. +To get the most ``permissive'' character set, change \.{'\ '} on the +right of these assignment statements to \\{chr}(\|i). + +\Y\B\4\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|i\K\T{0};{}$ ${}\|i\Z\T{\~37};{}$ ${}\|i\PP){}$\1\5 +${}\\{xchr}[\|i]\K\.{'\ '};{}$\2\6 +\&{for} ${}(\|i\K\T{\~177};{}$ ${}\|i\Z\T{\~377};{}$ ${}\|i\PP){}$\1\5 +${}\\{xchr}[\|i]\K\.{'\ '}{}$;\2\par +\fi + +\M{24}The following system-independent code makes the \\{xord} array contain a +suitable inverse to the information in \\{xchr}. Note that if $\\{xchr}[\|i]\E\\{xchr}[\|j]$ +where $\|i<\|j<\T{\~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 040 in case there is a coincidence. + +\Y\B\4\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|i\K\\{first\_text\_char};{}$ ${}\|i\Z\\{last\_text\_char};{}$ ${}\|i\PP){}$\1\5 +${}\\{xord}[\\{chr}(\|i)]\K\\{invalid\_code};{}$\2\6 +\&{for} ${}(\|i\K\T{\~200};{}$ ${}\|i\Z\T{\~377};{}$ ${}\|i\PP){}$\1\5 +${}\\{xord}[\\{xchr}[\|i]]\K\|i;{}$\2\6 +\&{for} ${}(\|i\K\T{0};{}$ ${}\|i\Z\T{\~176};{}$ ${}\|i\PP){}$\1\5 +${}\\{xord}[\\{xchr}[\|i]]\K\|i{}$;\2\par +\fi + +\N{1}{25}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\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{uint8\_t} \&{eight\_bits};\C{unsigned one-byte quantity}\6 +\&{typedef} \&{struct} ${}\{{}$\5 +\1\&{FILE} ${}{*}\|f{}$;\5 +\\{text\_char}\,\|d;\5 +\2${}\}{}$ \&{alpha\_file};\C{files that contain textual data}\6 +\&{typedef} \&{struct} ${}\{{}$\5 +\1\&{FILE} ${}{*}\|f{}$;\5 +\&{eight\_bits}\, \|d;\5 +\2${}\}{}$ \&{byte\_file};\C{files that contain binary data}\par +\fi + +\M{26}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{uint8\_t} ${}\\{name\_of\_file0}[\\{file\_name\_size}+\T{1}]\K\{\T{0}\},{}$ ${}{*\&{const}\ }\\{name\_of\_file}\K\\{name\_of\_file0}-\T{1};{}$\C{on some systems this may be a \&{record} variable}\7 +\&{uint8\_t} \\{name\_length};\C{this many characters are actually relevant in \\{name\_of\_file} (the rest are blank)}\par +\fi + +\M{27}The \ph\ compiler with which the present version of \TeX\ was prepared has +extended the rules of \PASCAL\ in a very convenient way. To open file~\|f, +we can write +$$\vbox{\halign{#\hfil\qquad&#\hfil\cr +\\{reset} $(\|f,$ $\hbox{\\{name}},$ \.{"/O"} )&for input;\cr +\\{rewrite} $(\|f,$ $\hbox{\\{name}},$ \.{"/O"} )&for output.\cr}}$$ +The `\\{name}' parameter, which is of type `{\bf packed array +$[\langle\\{any}\rangle]$ of \\{char}}', stands for the name of +the external file that is being opened for input or output. +Blank spaces that might appear in \\{name} are ignored. + +The `\.{/O}' parameter tells the operating system not to issue its own +error messages if something goes wrong. If a file of the specified name +cannot be found, or if such a file cannot be opened for some other reason +(e.g., someone may already be trying to write the same file), we will have +$\\{erstat}(\|f)\I\T{0}$ after an unsuccessful \\{reset} or \\{rewrite}. This allows +\TeX\ to undertake appropriate corrective action. + +\TeX's file-opening procedures return \\{false} if no file identified by +\\{name\_of\_file} could be opened. + +\Y\B\4\D$\\{reset\_OK}(\|X)$ \5 +$\\{erstat}(\|X)\E{}$\T{0}\par +\B\4\D$\\{rewrite\_OK}(\|X)$ \5 +$\\{erstat}(\|X)\E{}$\T{0}\par +\Y\B\&{bool} \\{a\_open\_in}(\&{alpha\_file} ${}{*}\|f{}$)\C{open a text file for input}\6 +${}\{{}$\5 +\1${}\\{reset}(({*}\|f),\39\\{name\_of\_file},\39\.{"r"});{}$\5 +\&{return} \\{reset\_OK}${}(({*}\|f));{}$\6 +\4${}\}{}$\2\7 +\&{bool} \\{a\_open\_out}(\&{alpha\_file} ${}{*}\|f{}$)\C{open a text file for output}\6 +${}\{{}$\5 +\1${}\\{rewrite}(({*}\|f),\39\\{name\_of\_file},\39\.{"w"});{}$\5 +\&{return} \\{rewrite\_OK}${}(({*}\|f));{}$\6 +\4${}\}{}$\2\7 +\&{bool} \\{b\_open\_in}(\&{byte\_file} ${}{*}\|f{}$)\C{open a binary file for input}\6 +${}\{{}$\5 +\1${}\\{reset}(({*}\|f),\39\\{name\_of\_file},\39\.{"rb"});{}$\5 +\&{return} \\{reset\_OK}${}(({*}\|f));{}$\6 +\4${}\}{}$\2\7 +\&{bool} \\{b\_open\_out}(\&{byte\_file} ${}{*}\|f{}$)\C{open a binary file for output}\6 +${}\{{}$\5 +\1${}\\{rewrite}(({*}\|f),\39\\{name\_of\_file},\39\.{"wb"});{}$\5 +\&{return} \\{rewrite\_OK}${}(({*}\|f));{}$\6 +\4${}\}{}$\2\7 +\&{bool} ${}\\{w\_open\_in}(\\{word\_file}*\|f{}$)\C{open a word file for input}\6 +${}\{{}$\5 +\1${}\\{reset}(({*}\|f),\39\\{name\_of\_file},\39\.{"rb"});{}$\5 +\&{return} \\{reset\_OK}${}(({*}\|f));{}$\6 +\4${}\}{}$\2\7 +\&{bool} ${}\\{w\_open\_out}(\\{word\_file}*\|f{}$)\C{open a word file for output}\6 +${}\{{}$\5 +\1${}\\{rewrite}(({*}\|f),\39\\{name\_of\_file},\39\.{"wb"});{}$\5 +\&{return} \\{rewrite\_OK}${}(({*}\|f));{}$\6 +\4${}\}{}$\2\par +\fi + +\M{28}Files can be closed with the \ph\ routine `\\{close}(\|f)', which +should be used when all input or output with respect to \|f has been completed. +This makes \|f available to be opened again, if desired; and if \|f was used for +output, the \\{close} operation makes the corresponding external file appear +on the user's area, ready to be read. + +These procedures should not generate error messages if a file is +being closed before it has been successfully opened. + +\Y\B\&{void} \\{a\_close}(\&{alpha\_file} ${}{*}\|f{}$)\C{close a text file}\6 +${}\{{}$\5 +\1${}\\{close}(({*}\|f));{}$\6 +\4${}\}{}$\2\7 +\&{void} \\{b\_close}(\&{byte\_file} ${}{*}\|f{}$)\C{close a binary file}\6 +${}\{{}$\5 +\1${}\\{close}(({*}\|f));{}$\6 +\4${}\}{}$\2\7 +\&{void} ${}\\{w\_close}(\\{word\_file}*\|f{}$)\C{close a word file}\6 +${}\{{}$\5 +\1${}\\{close}(({*}\|f));{}$\6 +\4${}\}{}$\2\par +\fi + +\M{29}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 + +\M{30}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{ASCII\_code} ${}\\{buffer}[\\{buf\_size}+\T{1}]{}$;\C{lines of characters being read}\6 +\&{uint16\_t} \\{first};\C{the first unused position in \\{buffer}}\6 +\&{uint16\_t} \\{last};\C{end of the line just input to \\{buffer}}\6 +\&{uint16\_t} \\{max\_buf\_stack};\C{largest index used in \\{buffer}}\par +\fi + +\M{31}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}+\T{1}]$, \dots, $\\{buffer}[\\{last}-\T{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}\E\\{first}$ +(in which case the line was entirely blank) or $\\{buffer}[\\{last}-\T{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}+\T{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.\|d$. 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.\|d$ 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. + +\Y\B\&{bool} \\{input\_ln}(\&{alpha\_file} ${}{*}\|f,\39{}$\&{bool} \\{bypass\_eoln})\C{inputs the next line or returns \\{false}}\6 +${}\{{}$\5 +\1\&{uint16\_t} \\{last\_nonblank};\C{\\{last} with trailing blanks removed}\7 +\&{if} (\\{bypass\_eoln})\1\6 +\&{if} ${}(\R\\{eof}(({*}\|f))){}$\1\5 +${}\\{get}(({*}\|f)){}$;\C{input the first character of the line into $\|f.\|d$}\2\2\6 +${}\\{last}\K\\{first}{}$;\C{cf.\ Matthew 19\thinspace:\thinspace30}\6 +\&{if} ${}(\\{eof}(({*}\|f))){}$\1\5 +\&{return} \\{false};\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{last\_nonblank}\K\\{first};{}$\6 +\&{while} ${}(\R\\{eoln}(({*}\|f))){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{last}\G\\{max\_buf\_stack}){}$\5 +${}\{{}$\5 +\1${}\\{max\_buf\_stack}\K\\{last}+\T{1};{}$\6 +\&{if} ${}(\\{max\_buf\_stack}\E\\{buf\_size}){}$\1\5 +\X35:Report overflow of the input buffer, and abort\X;\2\6 +\4${}\}{}$\2\6 +${}\\{buffer}[\\{last}]\K\\{xord}[({*}\|f).\|d];{}$\5 +${}\\{get}(({*}\|f));{}$\5 +\\{incr}(\\{last});\6 +\&{if} ${}(\\{buffer}[\\{last}-\T{1}]\I\.{'\ '}){}$\1\5 +${}\\{last\_nonblank}\K\\{last};{}$\2\6 +\4${}\}{}$\2\6 +${}\\{last}\K\\{last\_nonblank};{}$\5 +\&{return} \\{true};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{32}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{alpha\_file} \\{term\_in};\C{the terminal as an input file}\6 +\&{alpha\_file} \\{term\_out};\C{the terminal as an output file}\par +\fi + +\M{33}Here is how to open the terminal files +in \ph. The `\.{/I}' switch suppresses the first \\{get}. + +\Y\B\4\D$\\{t\_open\_in}$ \5 +$\\{term\_in}.\|f\K{}$\\{stdin}\C{open the terminal for text input}\par +\B\4\D$\\{t\_open\_out}$ \5 +$\\{term\_out}.\|f\K{}$\\{stdout}\C{open the terminal for text output}\par +\fi + +\M{34}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 in \ph: + +\Y\B\4\D$\\{update\_terminal}$ \5 +$\\{fflush}(\\{term\_out}.\|f{}$)\C{empty the terminal output buffer}\par +\B\4\D$\\{clear\_terminal}$ \5 +$\\{fflush}(\\{term\_in}.\|f{}$)\C{clear the terminal input buffer}\par +\B\4\D$\\{wake\_up\_terminal}$ \5 +\\{do\_nothing}\C{cancel the user's cancellation of output}\par +\fi + +\M{35}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} \\{exit}(\T{0})' should be replaced by something that +quietly terminates the program.) + +\Y\B\4\X35:Report overflow of the input buffer, and abort\X${}\E{}$\6 +\&{if} ${}(\\{format\_ident}\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{write\_ln}(\\{term\_out},\39\.{"Buffer\ size\ exceede}\)\.{d!"});{}$\5 +\\{exit}(\T{0});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_input}.\\{loc\_field}\K\\{first};{}$\5 +${}\\{cur\_input}.\\{limit\_field}\K\\{last}-\T{1};{}$\5 +${}\\{overflow}(\.{"buffer\ size"},\39\\{buf\_size});{}$\6 +\4${}\}{}$\2\par +\U31.\fi + +\M{36}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}-\T{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\B\4\D$\\{loc}$ \5 +$\\{cur\_input}.{}$\\{loc\_field}\C{location of first unread character in \\{buffer}}\par +\fi + +\M{37}The following program does the required initialization +without retrieving a possible command line. +It should be clear how to modify this routine to deal with command lines, +if the system permits them. + +\Y\B\&{bool} \\{init\_terminal}(\&{void})\C{gets the terminal input started}\6 +${}\{{}$\5 +\1\\{t\_open\_in};\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{wake\_up\_terminal};\5 +${}\\{write}(\\{term\_out},\39\.{"**"});{}$\5 +\\{update\_terminal};\6 +\&{if} ${}(\R\\{input\_ln}({\AND}\\{term\_in},\39\\{true}){}$)\C{this shouldn't happen}\6 +${}\{{}$\5 +\1\\{write\_ln}(\\{term\_out});\5 +${}\\{write}(\\{term\_out},\39\.{"!\ End\ of\ file\ on\ th}\)\.{e\ terminal...\ why?"});{}$\5 +\&{return} \\{false};\6 +\4${}\}{}$\2\6 +${}\\{loc}\K\\{first};{}$\6 +\&{while} ${}((\\{loc}<\\{last})\W(\\{buffer}[\\{loc}]\E\.{'\ '})){}$\1\5 +\\{incr}(\\{loc});\2\6 +\&{if} ${}(\\{loc}<\\{last}){}$\5 +${}\{{}$\5 +\1\&{return} \\{true};\C{return unless the line was all blank}\6 +\4${}\}{}$\2\6 +${}\\{write\_ln}(\\{term\_out},\39\.{"Please\ type\ the\ nam}\)\.{e\ of\ your\ input\ file}\)\.{."});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\N{1}{38}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]\Z\|j<\\{str\_start}[\|s+\T{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 ${-}\T{128}\dotdot\T{127}$. To accommodate such systems +we access the string pool only via macros that can easily be redefined. + +\Y\B\4\D$\\{si}(\|X)$ \5 +\|X\C{convert from \&{ASCII\_code} to \\{packed\_ASCII\_code}}\par +\B\4\D$\\{so}(\|X)$ \5 +\|X\C{convert from \\{packed\_ASCII\_code} to \&{ASCII\_code}}\par +\Y\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{uint16\_t} \&{pool\_pointer};\C{for variables that point into \\{str\_pool}}\6 +\&{typedef} \&{uint16\_t} \&{str\_number};\C{for variables that point into \\{str\_start}}\6 +\&{typedef} \&{uint8\_t} \&{packed\_ASCII\_code};\C{elements of \\{str\_pool} array}\par +\fi + +\M{39}\B\X13:Global variables\X${}\mathrel+\E{}$\6 +\X1795:prepare for string pool initialization\X\6 +\&{packed\_ASCII\_code} ${}\\{str\_pool}[\\{pool\_size}+\T{1}]$ $\K$ \X1793:\\{str\_pool} initialization\X;\C{the characters}\7 +\&{pool\_pointer} ${}\\{str\_start}[\\{max\_strings}+\T{1}]\K\{\X1794:\\{str\_start} initialization\X\}{}$;\C{the starting pointers}\6 +\&{pool\_pointer} \\{pool\_ptr} $\K$ \X1796:\\{pool\_ptr} initialization\X;\C{first unused position in \\{str\_pool}}\6 +\&{str\_number} \\{str\_ptr} $\K$ \X1797:\\{str\_ptr} initialization\X;\C{number of the current string being created}\7 +\&{pool\_pointer} \\{init\_pool\_ptr};\C{the starting value of \\{pool\_ptr}}\6 +\&{str\_number} \\{init\_str\_ptr};\C{the starting value of \\{str\_ptr}}\par +\fi + +\M{40}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\B\4\D$\\{length}(\|X)$ \5 +$(\\{str\_start}[\|X+\T{1}]-\\{str\_start}[\|X]{}$)\C{the number of characters in string number \#}\par +\fi + +\M{41}The length of the current string is called \\{cur\_length}: + +\Y\B\4\D$\\{cur\_length}$ \5 +$(\\{pool\_ptr}-\\{str\_start}[\\{str\_ptr}]{}$)\par +\fi + +\M{42}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\B\4\D$\\{append\_char}(\|X)$ \C{put \&{ASCII\_code} \# at the end of \\{str\_pool}}\6 +${}\{{}$\5 +\1${}\\{str\_pool}[\\{pool\_ptr}]\K\\{si}(\|X);{}$\5 +\\{incr}(\\{pool\_ptr});\6 +\4${}\}{}$\2\par +\B\4\D$\\{flush\_char}$ \5 +\\{decr}(\\{pool\_ptr})\C{forget the last character in the pool}\par +\B\4\D$\\{str\_room}(\|X)$ \C{make sure that the pool hasn't overflowed}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{pool\_ptr}+\|X>\\{pool\_size}){}$\1\5 +${}\\{overflow}(\.{"pool\ size"},\39\\{pool\_size}-\\{init\_pool\_ptr});{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{43}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\B\&{str\_number} \\{make\_string}(\&{void})\C{current string enters the pool}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{str\_ptr}\E\\{max\_strings}){}$\1\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 +\&{return} \\{str\_ptr}${}-\T{1};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{44}To destroy the most recently made string, we say \\{flush\_string}. + +\Y\B\4\D$\\{flush\_string}$ \6 +${}\{{}$\5 +\1\\{decr}(\\{str\_ptr});\5 +${}\\{pool\_ptr}\K\\{str\_start}[\\{str\_ptr}];{}$\6 +\4${}\}{}$\2\par +\fi + +\M{45}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\B\&{bool} \\{str\_eq\_buf}(\&{str\_number} \|s${},\39{}$\&{int} \|k)\C{test equality of strings}\6 +${}\{{}$\5 +\C{loop exit}\1\6 +\&{pool\_pointer} \|j;\C{running index}\6 +\&{bool} \\{result};\C{result of comparison}\7 +${}\|j\K\\{str\_start}[\|s];{}$\6 +\&{while} ${}(\|j<\\{str\_start}[\|s+\T{1}]){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{so}(\\{str\_pool}[\|j])\I\\{buffer}[\|k]){}$\5 +${}\{{}$\5 +\1${}\\{result}\K\\{false};{}$\5 +\&{goto} \\{not\_found};\6 +\4${}\}{}$\2\6 +\\{incr}(\|j);\5 +\\{incr}(\|k);\6 +\4${}\}{}$\2\6 +${}\\{result}\K\\{true};{}$\6 +\4\\{not\_found}:\5 +\&{return} \\{result};\6 +\4${}\}{}$\2\par +\fi + +\M{46}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\B\&{bool} \\{str\_eq\_str}(\&{str\_number} \|s${},\39{}$\&{str\_number} \|t)\C{test equality of strings}\6 +${}\{{}$\5 +\C{loop exit}\1\6 +\&{pool\_pointer} \|j${},{}$ \|k;\C{running indices}\6 +\&{bool} \\{result};\C{result of comparison}\7 +${}\\{result}\K\\{false};{}$\6 +\&{if} ${}(\\{length}(\|s)\I\\{length}(\|t)){}$\1\5 +\&{goto} \\{not\_found};\2\6 +${}\|j\K\\{str\_start}[\|s];{}$\5 +${}\|k\K\\{str\_start}[\|t];{}$\6 +\&{while} ${}(\|j<\\{str\_start}[\|s+\T{1}]){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{str\_pool}[\|j]\I\\{str\_pool}[\|k]){}$\1\5 +\&{goto} \\{not\_found};\2\6 +\\{incr}(\|j);\5 +\\{incr}(\|k);\6 +\4${}\}{}$\2\6 +${}\\{result}\K\\{true};{}$\6 +\4\\{not\_found}:\5 +\&{return} \\{result};\6 +\4${}\}{}$\2\par +\fi + +\M{47}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\B\8\#\&{ifdef} \.{INIT}\6 +\&{bool} \\{get\_strings\_started}(\&{void})\C{initializes the string pool, but returns \\{false} if something goes wrong}\6 +${}\{{}$\5 +\1\&{int} \|k${},{}$ \|l;\C{small indices or counters}\6 +\&{uint8\_t} \|m${},{}$ \|n;\C{characters input from \\{pool\_file}}\6 +\&{str\_number} \|g;\C{garbage}\6 +\&{int} \|a;\C{accumulator for check sum}\6 +\&{bool} \|c;\C{check sum has been checked}\7 +${}\\{pool\_ptr}\K\T{0};{}$\5 +${}\\{str\_ptr}\K\T{0};{}$\5 +${}\\{str\_start}[\T{0}]\K\T{0};{}$\5 +\X48:Make the first 256 strings\X;\6 +\X51:Read the other strings from the \.{TEX.POOL} file and return \\{true}, or give an error message and return \\{false}\X;\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\M{48}\B\D$\\{app\_lc\_hex}(\|X)$ \5 +$\|l\K\|X;$ \6 +\&{if} ${}(\|l<\T{10}){}$\1\5 +${}\\{append\_char}(\|l+\.{'0'}){}$\5 +\2\&{else} $\\{append\_char}(\|l-\T{10}+\.{'a'}{}$)\par +\Y\B\4\X48:Make the first 256 strings\X${}\E{}$\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{255};{}$ ${}\|k\PP){}$\5 +${}\{{}$\1\6 +\&{if} (\X49:Character \|k cannot be printed\X)\5 +${}\{{}$\1\6 +\\{append\_char}(\.{'\^'});\5 +\\{append\_char}(\.{'\^'});\6 +\&{if} ${}(\|k<\T{\~100}){}$\1\5 +${}\\{append\_char}(\|k+\T{\~100}){}$\2\6 +\&{else} \&{if} ${}(\|k<\T{\~200}){}$\1\5 +${}\\{append\_char}(\|k-\T{\~100}){}$\2\6 +\&{else}\5 +${}\{{}$\1\6 +${}\\{app\_lc\_hex}(\|k/\T{16});{}$\5 +${}\\{app\_lc\_hex}(\|k\MOD\T{16});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{append\_char}(\|k);\2\6 +${}\|g\K\\{make\_string}(\,);{}$\6 +\4${}\}{}$\2\par +\U47.\fi + +\M{49}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}[\T{\~32}] $\E\hbox{\.{\'^^Z\'}}$, +would like string 032 to be the single character 032 instead of the +three characters 0136, 0136, 0132 (\.{\^\^Z}). On the other hand, +even people with an extended character set will want to represent string +015 by \.{\^\^M}, since 015 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[\T{0},\T{\~10}\dotdot\T{\~12},\T{\~14},\T{\~15},\T{\~33},\T{\~177}\dotdot\T{\~377}]$'. +If character \|k cannot be printed, and $\|k<\T{\~200}$, then character $\|k+\T{\~100}$ or +$\|k-\T{\~100}$ must be printable; moreover, ASCII codes $[\T{\~41}\dotdot\T{\~46},\T{\~60}\dotdot\T{\~71},\T{\~136},\T{\~141}\dotdot\T{\~146},\T{\~160}\dotdot\T{\~171}]$ must be printable. +Thus, at least 81 printable characters are needed. + +\Y\B\4\X49:Character \|k cannot be printed\X${}\E{}$\6 +$(\|k<\.{'\ '})\V(\|k>\.{'\~'}{}$)\par +\U48.\fi + +\M{50}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{INIT}\6 +\&{alpha\_file} \\{pool\_file};\C{the string-pool file output by \.{TANGLE}}\6 +\8\#\&{endif}\par +\fi + +\M{51}\B\D$\\{bad\_pool}(\|X)$ \6 +${}\{{}$\5 +\1\\{wake\_up\_terminal};\5 +${}\\{write\_ln}(\\{term\_out},\39\|X);{}$\5 +${}\\{a\_close}({\AND}\\{pool\_file});{}$\5 +\&{return} \\{false};\6 +\4${}\}{}$\2\par +\Y\B\4\X51:Read the other strings from the \.{TEX.POOL} file and return \\{true}, or give an error message and return \\{false}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{int} \|k;\5 +\&{for} ${}(\|k\K\T{1};{}$ ${}\|k\Z\\{file\_name\_size};{}$ ${}\|k\PP){}$\1\5 +${}\\{name\_of\_file}[\|k]\K\\{pool\_name}[\|k-\T{1}]{}$;\5 +\2${}\}{}$\C{we needn't set \\{name\_length}}\2\6 +\&{if} ${}(\\{a\_open\_in}({\AND}\\{pool\_file})){}$\5 +${}\{{}$\5 +\1${}\|c\K\\{false}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\X52:Read one string, but return \\{false} if the string memory space is getting too tight for comfort\X;\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|c));{}$\5 +${}\\{a\_close}({\AND}\\{pool\_file});{}$\5 +\&{return} \\{true};\6 +\4${}\}{}$\2\6 +\&{else} \\{bad\_pool}(\.{"!\ I\ can't\ read\ TEX.}\)\.{POOL."})\par +\U47.\fi + +\M{52}\B\X52:Read one string, but return \\{false} if the string memory space is getting too tight for comfort\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} (\\{eof}(\\{pool\_file}))\1\5 +\\{bad\_pool}(\.{"!\ TEX.POOL\ has\ no\ c}\)\.{heck\ sum."});\2\6 +${}\\{read}(\\{pool\_file},\39\|m){}$;\5 +${}\\{read}(\\{pool\_file},\39\|n){}$;\C{read two digits of string length}\6 +\&{if} ${}(\|m\E\.{'*'}){}$\1\5 +\X53:Check the pool check sum\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}((\\{xord}[\|m]<\.{'0'})\V(\\{xord}[\|m]>\.{'9'})\V\30(\\{xord}[\|n]<\.{'0'})\V(\\{xord}[\|n]>\.{'9'})){}$\1\5 +\\{bad\_pool}(\.{"!\ TEX.POOL\ line\ doe}\)\.{sn't\ begin\ with\ two\ }\)\.{digits."});\2\6 +${}\|l\K\\{xord}[\|m]*\T{10}+\\{xord}[\|n]-\.{'0'}*\T{11}{}$;\C{compute the length}\6 +\&{if} ${}(\\{pool\_ptr}+\|l+\\{string\_vacancies}>\\{pool\_size}){}$\1\5 +\\{bad\_pool}(\.{"!\ You\ have\ to\ incre}\)\.{ase\ POOLSIZE."});\2\6 +\&{for} ${}(\|k\K\T{1};{}$ ${}\|k\Z\|l;{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1\&{if} (\\{eoln}(\\{pool\_file}))\1\5 +${}\|m\K\.{'\ '}{}$;\5 +\2\&{else}\1\5 +${}\\{read}(\\{pool\_file},\39\|m);{}$\2\6 +\\{append\_char}(\\{xord}[\|m]);\6 +\4${}\}{}$\2\6 +\\{read\_ln}(\\{pool\_file});\5 +${}\|g\K\\{make\_string}(\,);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U51.\fi + +\M{53}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\B\4\X53:Check the pool check sum\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|a\K\T{0};{}$\5 +${}\|k\K\T{1};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}((\\{xord}[\|n]<\.{'0'})\V(\\{xord}[\|n]>\.{'9'})){}$\1\5 +\\{bad\_pool}(\.{"!\ TEX.POOL\ check\ su}\)\.{m\ doesn't\ have\ nine\ }\)\.{digits."});\2\6 +${}\|a\K\T{10}*\|a+\\{xord}[\|n]-\.{'0'};{}$\6 +\&{if} ${}(\|k\E\T{9}){}$\1\5 +\&{goto} \\{done};\2\6 +\\{incr}(\|k);\5 +${}\\{read}(\\{pool\_file},\39\|n);{}$\6 +\4${}\}{}$\2\6 +\4\\{done}:\6 +\&{if} ${}(\|a\I\T{0}){}$\1\5 +\\{bad\_pool}(\.{"!\ TEX.POOL\ doesn't\ }\)\.{match;\ TANGLE\ me\ aga}\)\.{in."});\2\6 +${}\|c\K\\{true};{}$\6 +\4${}\}{}$\2\par +\U52.\fi + +\N{1}{54}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}+\T{1}\E\\{term\_only}$, +$\\{no\_print}+\T{2}\E\\{log\_only}$, $\\{term\_only}+\T{2}\E\\{log\_only}+\T{1}\E\\{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\B\4\D$\\{no\_print}$ \5 +\T{16}\C{\\{selector} setting that makes data disappear}\par +\B\4\D$\\{term\_only}$ \5 +\T{17}\C{printing is destined for the terminal only}\par +\B\4\D$\\{log\_only}$ \5 +\T{18}\C{printing is destined for the transcript file only}\par +\B\4\D$\\{term\_and\_log}$ \5 +\T{19}\C{normal \\{selector} setting}\par +\B\4\D$\\{pseudo}$ \5 +\T{20}\C{special \\{selector} setting for \\{show\_context}}\par +\B\4\D$\\{new\_string}$ \5 +\T{21}\C{printing is deflected to the string pool}\par +\B\4\D$\\{max\_selector}$ \5 +\T{21}\C{highest selector setting}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{alpha\_file} \\{log\_file};\C{transcript of \TeX\ session}\6 +\&{uint8\_t} \\{selector};\C{where to print a message}\6 +\&{uint8\_t} \\{dig}[\T{23}];\C{digits in a number being output}\6 +\&{int} \\{tally};\C{the number of characters recently printed}\6 +\&{uint8\_t} \\{term\_offset};\C{the number of characters on the current terminal line}\6 +\&{uint8\_t} \\{file\_offset};\C{the number of characters on the current file line}\6 +\&{ASCII\_code} ${}\\{trick\_buf}[\\{error\_line}+\T{1}]{}$;\C{circular buffer for pseudoprinting}\6 +\&{int} \\{trick\_count};\C{threshold for pseudoprinting, explained later}\6 +\&{int} \\{first\_count};\C{another variable for pseudoprinting}\par +\fi + +\M{55}\B\X55:Initialize the output routines\X${}\E{}$\6 +$\\{selector}\K\\{term\_only};{}$\5 +${}\\{tally}\K\T{0};{}$\5 +${}\\{term\_offset}\K\T{0};{}$\5 +${}\\{file\_offset}\K\T{0}{}$;\par +\As61, 527\ETs533. +\U1332.\fi + +\M{56}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\B\4\X9:Compiler directives\X${}\mathrel+\E{}$\6 +\8\#\&{define} \\{put}(\\{file}) \5${}\\{fwrite}({\AND}((\\{file}).\|d),\39{}$\&{sizeof} ${}((\\{file}).\|d),\39\T{1},\39(\\{file}).\|f){}$\6 +\8\#\&{define} \\{get}(\\{file}) \5${}\\{fread}({\AND}((\\{file}).\|d),\39{}$\&{sizeof} ${}((\\{file}).\|d),\39\T{1},\39(\\{file}).\|f){}$\6 +\8\#\&{define} ${}\\{reset}(\\{file},\39\\{name},\39\\{mode}) \5((\\{file}).\|f\K\\{fopen}{}$((\&{char} ${}{*})(\\{name})+\T{1},\39\\{mode}),\39(\\{file}).\|f\I\NULL\?\\{get}(\\{file}):\T{0}){}$\6 +\8\#\&{define} ${}\\{rewrite}(\\{file},\39\\{name},\39\\{mode}) \5((\\{file}).\|f\K\\{fopen}{}$((\&{char} ${}{*})(\\{name})+\T{1},\39\\{mode})){}$\6 +\8\#\&{define} \\{close}(\\{file}) \5${}\\{fclose}((\\{file}).\|f){}$\6 +\8\#\&{define} \\{eof}(\\{file}) \5${}\\{feof}((\\{file}).\|f){}$\6 +\8\#\&{define} \\{eoln}(\\{file}) \5${}((\\{file}).\|d\E\.{'\\n'}\V\\{eof}(\\{file})){}$\6 +\8\#\&{define} \\{erstat}(\\{file}) \5${}((\\{file}).\|f\E\NULL\?{-}\T{1}:\\{ferror}((\\{file}).\|f)){}$\6 +\8\#\&{define} ${}\\{read}(\\{file},\39\|x) \5((\|x)\K(\\{file}).\|d,\39\\{get}(\\{file})){}$\6 +\8\#\&{define} \\{read\_ln}(\\{file}) \5\&{do}\\{get}(\\{file});\&{while} ${}(\R\\{eoln}(\\{file})){}$\6 +\8\#\&{define} ${}\\{write}(\\{file},\39\\{format},\39\,\ldots\,) \5\\{fprintf}(\\{file}.\|f,\39\\{format},\39{\#}{\#}\.{\_\_VA\_ARGS\_\_}){}$\6 +\8\#\&{define} ${}\\{write\_ln}(\\{file},\39\,\ldots\,) \5\\{write}(\\{file},\39\.{\_\_VA\_ARGS\_\_}\.{"\\n"}){}$\6 +\8\#\&{define} ${}\\{wterm}(\\{format},\39\,\ldots\,) \5\\{write}(\\{term\_out},\39\\{format},\39{\#}{\#}\.{\_\_VA\_ARGS\_\_}){}$\6 +\8\#\&{define} ${}\\{wterm\_ln}(\\{format},\39\,\ldots\,) \5\\{wterm}(\\{format}\.{"\\n"},\39{\#}{\#}\.{\_\_VA\_ARGS\_\_}){}$\6 +\8\#\&{define} \\{wterm\_cr} \5${}\\{write}(\\{term\_out},\39\.{"\\n"}){}$\6 +\8\#\&{define} ${}\\{wlog}(\\{format},\39\,\ldots\,) \5\\{write}(\\{log\_file},\39\\{format},\39{\#}{\#}\.{\_\_VA\_ARGS\_\_}){}$\6 +\8\#\&{define} ${}\\{wlog\_ln}(\\{format},\39\,\ldots\,) \5\\{wlog}(\\{format}\.{"\\n"},\39{\#}{\#}\.{\_\_VA\_ARGS\_\_}){}$\6 +\8\#\&{define} \\{wlog\_cr} \5${}\\{write}(\\{log\_file},\39\.{"\\n"}){}$\par +\fi + +\M{57}To end a line of text output, we call \\{print\_ln}. + +\Y\B\4\X57:Basic printing procedures\X${}\E{}$\6 +\&{void} \\{print\_ln}(\&{void})\C{prints an end-of-line}\6 +${}\{{}$\5 +\1\&{switch} (\\{selector})\5 +${}\{{}$\1\6 +\4\&{case} \\{term\_and\_log}:\6 +${}\{{}$\5 +\1\\{wterm\_cr};\5 +\\{wlog\_cr};\5 +${}\\{term\_offset}\K\T{0};{}$\5 +${}\\{file\_offset}\K\T{0};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{log\_only}:\6 +${}\{{}$\5 +\1\\{wlog\_cr};\5 +${}\\{file\_offset}\K\T{0};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{term\_only}:\6 +${}\{{}$\5 +\1\\{wterm\_cr};\5 +${}\\{term\_offset}\K\T{0};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{no\_print}:\5 +\&{case} \\{pseudo}:\5 +\&{case} \\{new\_string}:\5 +\\{do\_nothing};\5 +\&{break};\6 +\4\&{default}:\5 +\\{write\_ln}(\\{write\_file}[\\{selector}]);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\C{\\{tally} is not affected}\2\par +\As58, 59, 60, 62, 63, 64, 65, 262, 263, 518, 699\ETs1355. +\U4.\fi + +\M{58}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\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_char}(\&{ASCII\_code} \|s)\C{prints a single character}\6 +${}\{{}$\5 +\1\&{if} (\X244:Character \|s is the current new-line character\X)\1\6 +\&{if} ${}(\\{selector}<\\{pseudo}){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\&{return};\6 +\4${}\}{}$\2\2\6 +\&{switch} (\\{selector})\5 +${}\{{}$\1\6 +\4\&{case} \\{term\_and\_log}:\6 +${}\{{}$\5 +\1${}\\{wterm}(\.{"\%c"},\39\\{xchr}[\|s]);{}$\5 +${}\\{wlog}(\.{"\%c"},\39\\{xchr}[\|s]);{}$\5 +\\{incr}(\\{term\_offset});\5 +\\{incr}(\\{file\_offset});\6 +\&{if} ${}(\\{term\_offset}\E\\{max\_print\_line}){}$\5 +${}\{{}$\5 +\1\\{wterm\_cr};\5 +${}\\{term\_offset}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{file\_offset}\E\\{max\_print\_line}){}$\5 +${}\{{}$\5 +\1\\{wlog\_cr};\5 +${}\\{file\_offset}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{log\_only}:\6 +${}\{{}$\5 +\1${}\\{wlog}(\.{"\%c"},\39\\{xchr}[\|s]);{}$\5 +\\{incr}(\\{file\_offset});\6 +\&{if} ${}(\\{file\_offset}\E\\{max\_print\_line}){}$\1\5 +\\{print\_ln}(\,);\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{term\_only}:\6 +${}\{{}$\5 +\1${}\\{wterm}(\.{"\%c"},\39\\{xchr}[\|s]);{}$\5 +\\{incr}(\\{term\_offset});\6 +\&{if} ${}(\\{term\_offset}\E\\{max\_print\_line}){}$\1\5 +\\{print\_ln}(\,);\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{no\_print}:\5 +\\{do\_nothing};\5 +\&{break};\6 +\4\&{case} \\{pseudo}:\6 +\&{if} ${}(\\{tally}<\\{trick\_count}){}$\1\5 +${}\\{trick\_buf}[\\{tally}\MOD\\{error\_line}]\K\|s{}$;\5 +\2\&{break};\6 +\4\&{case} \\{new\_string}:\6 +${}\{{}$\5 +\1\&{if} ${}(\\{pool\_ptr}<\\{pool\_size}){}$\1\5 +\\{append\_char}(\|s);\2\6 +\4${}\}{}$\5 +\2\&{break};\C{we drop characters if the string space is full}\6 +\4\&{default}:\5 +${}\\{write}(\\{write\_file}[\\{selector}],\39\.{"\%c"},\39\\{xchr}[\|s]);{}$\6 +\4${}\}{}$\2\6 +\\{incr}(\\{tally});\6 +\4${}\}{}$\2\par +\fi + +\M{59}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'}\E\T{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\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print}(\&{int} \|s)\C{prints string \|s}\6 +${}\{{}$\5 +\1\&{pool\_pointer} \|j;\C{current character code position}\6 +\&{int} \\{nl};\C{new-line character to restore}\7 +\&{if} ${}(\|s\G\\{str\_ptr}){}$\1\5 +${}\|s\K\X1381:\.{"???"}\X{}$;\C{this can't happen}\2\6 +\&{else} \&{if} ${}(\|s<\T{256}){}$\1\6 +\&{if} ${}(\|s<\T{0}){}$\1\5 +${}\|s\K\X1381:\.{"???"}\X{}$;\C{can't happen}\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{selector}>\\{pseudo}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\|s);\5 +\&{return};\C{internal strings are not expanded}\6 +\4${}\}{}$\2\6 +\&{if} ((\X244:Character \|s is the current new-line character\X))\1\6 +\&{if} ${}(\\{selector}<\\{pseudo}){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\&{return};\6 +\4${}\}{}$\2\2\6 +${}\\{nl}\K\\{new\_line\_char};{}$\5 +${}\\{new\_line\_char}\K{-}\T{1}{}$;\C{temporarily disable new-line character}\6 +${}\|j\K\\{str\_start}[\|s];{}$\6 +\&{while} ${}(\|j<\\{str\_start}[\|s+\T{1}]){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\\{so}(\\{str\_pool}[\|j]));\5 +\\{incr}(\|j);\6 +\4${}\}{}$\2\6 +${}\\{new\_line\_char}\K\\{nl};{}$\5 +\&{return};\6 +\4${}\}{}$\2\2\6 +${}\|j\K\\{str\_start}[\|s];{}$\6 +\&{while} ${}(\|j<\\{str\_start}[\|s+\T{1}]){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\\{so}(\\{str\_pool}[\|j]));\5 +\\{incr}(\|j);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\7 +\&{void} \\{print\_str}(\&{char} ${}{*}\|s{}$)\C{ the simple version }\6 +${}\{{}$\1\6 +\&{while} ${}({*}\|s\I\T{0}){}$\1\5 +${}\\{print\_char}({*}\|s\PP){}$;\5 +\2${}\}{}$\2\par +\fi + +\M{60}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\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{slow\_print}(\&{int} \|s)\C{prints string \|s}\6 +${}\{{}$\5 +\1\&{pool\_pointer} \|j;\C{current character code position}\7 +\&{if} ${}((\|s\G\\{str\_ptr})\V(\|s<\T{256})){}$\1\5 +\\{print}(\|s);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|j\K\\{str\_start}[\|s];{}$\6 +\&{while} ${}(\|j<\\{str\_start}[\|s+\T{1}]){}$\5 +${}\{{}$\5 +\1\\{print}(\\{so}(\\{str\_pool}[\|j]));\5 +\\{incr}(\|j);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{61}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\B\4\X55:Initialize the output routines\X${}\mathrel+\E{}$\6 +$\\{wterm}(\.{"\%s"},\39\\{banner});{}$\6 +\&{if} ${}(\\{format\_ident}\E\T{0}){}$\1\5 +\\{wterm\_ln}(\.{"\ (no\ format\ preload}\)\.{ed)"});\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{slow\_print}(\\{format\_ident});\5 +\\{print\_ln}(\,);\6 +\4${}\}{}$\2\6 +\\{update\_terminal};\par +\fi + +\M{62}The procedure \\{print\_nl} is like \\{print}, but it makes sure that the +string appears at the beginning of a new line. + +\Y\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_nl}(\&{char} ${}{*}\|s{}$)\C{prints string \|s at beginning of line}\6 +${}\{{}$\5 +\1\&{if} ${}(((\\{term\_offset}>\T{0})\W(\\{odd}(\\{selector})))\V\30((\\{file\_offset}>\T{0})\W(\\{selector}\G\\{log\_only}))){}$\1\5 +\\{print\_ln}(\,);\2\6 +\\{print\_str}(\|s);\6 +\4${}\}{}$\2\par +\fi + +\M{63}The procedure \\{print\_esc} prints a string that is preceded by +the user's escape character (which is usually a backslash). + +\Y\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_esc}(\&{str\_number} \|s)\C{prints escape character, then \|s}\6 +${}\{{}$\5 +\1\&{int} \|c;\C{the escape character code}\7 +\X243:Set variable \|c to the current escape character\X;\6 +\&{if} ${}(\|c\G\T{0}){}$\1\6 +\&{if} ${}(\|c<\T{256}){}$\1\5 +\\{print}(\|c);\2\2\6 +\\{slow\_print}(\|s);\6 +\4${}\}{}$\2\par +\fi + +\M{64}An array of digits in the range $\T{0}\dotdot\T{15}$ is printed by \\{print\_the\_digs}. + +\Y\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_the\_digs}(\&{eight\_bits} \|k)\C{prints $\\{dig}[\|k-\T{1}]$$\,\ldots\,$\\{dig}[\T{0}]}\6 +${}\{{}$\5 +\1\&{while} ${}(\|k>\T{0}){}$\5 +${}\{{}$\5 +\1\\{decr}(\|k);\6 +\&{if} ${}(\\{dig}[\|k]<\T{10}){}$\1\5 +${}\\{print\_char}(\.{'0'}+\\{dig}[\|k]);{}$\2\6 +\&{else}\1\5 +${}\\{print\_char}(\.{'A'}-\T{10}+\\{dig}[\|k]);{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{65}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\E\T{0}$ or if $({-}\|n)$ would cause overflow. It does not apply $\MOD$ or $/$ +to negative arguments, since such operations are not implemented consistently +by all \PASCAL\ compilers. + +\Y\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_int}(\&{int} \|n)\C{prints an integer in decimal form}\6 +${}\{{}$\5 +\1\&{uint8\_t} \|k;\C{index to current digit; we assume that $\|n<10^{23}$}\6 +\&{int} \|m;\C{used to negate \|n in possibly dangerous cases}\7 +${}\|k\K\T{0};{}$\6 +\&{if} ${}(\|n<\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{'-'});\6 +\&{if} ${}(\|n>{-}\T{100000000}){}$\1\5 +\\{negate}(\|n);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|m\K{-}\T{1}-\|n;{}$\5 +${}\|n\K\|m/\T{10};{}$\5 +${}\|m\K(\|m\MOD\T{10})+\T{1};{}$\5 +${}\|k\K\T{1};{}$\6 +\&{if} ${}(\|m<\T{10}){}$\1\5 +${}\\{dig}[\T{0}]\K\|m;{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{dig}[\T{0}]\K\T{0};{}$\5 +\\{incr}(\|n);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{do}\5 +${}\{{}$\1\6 +${}\\{dig}[\|k]\K\|n\MOD\T{10};{}$\5 +${}\|n\K\|n/\T{10};{}$\5 +\\{incr}(\|k);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|n\E\T{0}));{}$\5 +\\{print\_the\_digs}(\|k);\6 +\4${}\}{}$\2\par +\fi + +\M{66}Here is a trivial procedure to print two digits; it is usually called with +a parameter in the range $\T{0}\Z\|n\Z\T{99}$. + +\Y\B\&{void} \\{print\_two}(\&{int} \|n)\C{prints two least significant digits}\6 +${}\{{}$\5 +\1${}\|n\K\\{abs}(\|n)\MOD\T{100};{}$\5 +${}\\{print\_char}(\.{'0'}+(\|n/\T{10}));{}$\5 +${}\\{print\_char}(\.{'0'}+(\|n\MOD\T{10}));{}$\6 +\4${}\}{}$\2\par +\fi + +\M{67}Hexadecimal printing of nonnegative integers is accomplished by \\{print\_hex}. + +\Y\B\&{void} \\{print\_hex}(\&{int} \|n)\C{prints a positive integer in hexadecimal form}\6 +${}\{{}$\5 +\1\&{uint8\_t} \|k;\C{index to current digit; we assume that $0\L n<16^{22}$}\7 +${}\|k\K\T{0};{}$\5 +\\{print\_char}(\.{'"'});\6 +\&{do}\5 +${}\{{}$\1\6 +${}\\{dig}[\|k]\K\|n\MOD\T{16};{}$\5 +${}\|n\K\|n/\T{16};{}$\5 +\\{incr}(\|k);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|n\E\T{0}));{}$\5 +\\{print\_the\_digs}(\|k);\6 +\4${}\}{}$\2\par +\fi + +\M{68}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\B\4\D$\\{print\_ASCII}$ \5 +\\{print}\par +\fi + +\M{69}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\B\&{void} \\{print\_roman\_int}(\&{int} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pool\_pointer} \|j${},{}$ \|k;\C{mysterious indices into \\{str\_pool}}\7 +${}\\{nonnegative\_integer}\|u,\39\|v{}$;\C{mysterious numbers}\6 +${}\|j\K\\{str\_start}[\X1382:\.{"m2d5c2l5x2v5i"}\X];{}$\5 +${}\|v\K\T{1000};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{while} ${}(\|n\G\|v){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\\{so}(\\{str\_pool}[\|j]));\5 +${}\|n\K\|n-\|v;{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|n\Z\T{0}){}$\1\5 +\&{return};\C{nonpositive input produces no output}\2\6 +${}\|k\K\|j+\T{2};{}$\5 +${}\|u\K\|v/(\\{so}(\\{str\_pool}[\|k-\T{1}])-\.{'0'});{}$\6 +\&{if} ${}(\\{str\_pool}[\|k-\T{1}]\E\\{si}(\.{'2'})){}$\5 +${}\{{}$\5 +\1${}\|k\K\|k+\T{2};{}$\5 +${}\|u\K\|u/(\\{so}(\\{str\_pool}[\|k-\T{1}])-\.{'0'});{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|n+\|u\G\|v){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\\{so}(\\{str\_pool}[\|k]));\5 +${}\|n\K\|n+\|u;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|j\K\|j+\T{2};{}$\5 +${}\|v\K\|v/(\\{so}(\\{str\_pool}[\|j-\T{1}])-\.{'0'});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{70}The \\{print} subroutine will not print a string that is still being +created. The following procedure will. + +\Y\B\&{void} \\{print\_current\_string}(\&{void})\C{prints a yet-unmade string}\6 +${}\{{}$\5 +\1\&{pool\_pointer} \|j;\C{points to current character code}\7 +${}\|j\K\\{str\_start}[\\{str\_ptr}];{}$\6 +\&{while} ${}(\|j<\\{pool\_ptr}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\\{so}(\\{str\_pool}[\|j]));\5 +\\{incr}(\|j);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{71}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}-\T{1}$ of the +\\{buffer} array, and echoed on the transcript file if appropriate. + +This procedure is never called when $\\{interaction}<\\{scroll\_mode}$. + +\Y\B\4\D$\\{prompt\_input}(\|X)$ \6 +${}\{{}$\5 +\1\\{wake\_up\_terminal};\5 +\\{print\_str}(\|X);\5 +\\{term\_input}(\,);\6 +\4${}\}{}$\C{prints a string and gets a line of input}\2\par +\Y\B\&{void} \\{term\_input}(\&{void})\C{gets a line from the terminal}\6 +${}\{{}$\5 +\1\&{int} \|k;\C{index into \\{buffer}}\7 +\\{update\_terminal};\C{now the user sees the prompt for sure}\6 +\&{if} ${}(\R\\{input\_ln}({\AND}\\{term\_in},\39\\{true})){}$\1\5 +\\{fatal\_error}(\.{"End\ of\ file\ on\ the\ }\)\.{terminal!"});\2\6 +${}\\{term\_offset}\K\T{0}{}$;\C{the user's line ended with \<\rm return>}\6 +\\{decr}(\\{selector});\C{prepare to echo the input}\6 +\&{if} ${}(\\{last}\I\\{first}){}$\1\6 +\&{for} ${}(\|k\K\\{first};{}$ ${}\|k\Z\\{last}-\T{1};{}$ ${}\|k\PP){}$\1\5 +\\{print}(\\{buffer}[\|k]);\2\2\6 +\\{print\_ln}(\,);\5 +\\{incr}(\\{selector});\C{restore previous status}\6 +\4${}\}{}$\2\par +\fi + +\N{1}{72}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\ l}\)\.{ine\ of\ my\ offer\ to\ h}\)\.{elp."})\cr +(\.{"This\ is\ the\ second\ }\)\.{line.\ I'm\ trying\ to"})\cr +(\.{"explain\ the\ best\ wa}\)\.{y\ 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}\E\\{error\_stop\_mode}$, +it also enters into a dialog with the user, during which time the help +message may be printed. + +\fi + +\M{73}The global variable \\{interaction} has four settings, representing increasing +amounts of user interaction: + +\Y\B\4\D$\\{batch\_mode}$ \5 +\T{0}\C{omits all stops and omits terminal output}\par +\B\4\D$\\{nonstop\_mode}$ \5 +\T{1}\C{omits all stops}\par +\B\4\D$\\{scroll\_mode}$ \5 +\T{2}\C{omits error stops}\par +\B\4\D$\\{error\_stop\_mode}$ \5 +\T{3}\C{stops at every opportunity to interact}\par +\B\4\D$\\{print\_err}(\|X)$ \6 +${}\{{}$\5 +\1\&{if} ${}(\\{interaction}\E\\{error\_stop\_mode}){}$\1\5 +\\{wake\_up\_terminal};\2\6 +\\{print\_nl}(\.{"!\ "});\5 +\\{print\_str}(\|X);\6 +\4${}\}{}$\2\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{uint8\_t} \\{interaction};\C{current level of interaction}\par +\fi + +\M{74}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{interaction}\K\\{error\_stop\_mode}{}$;\par +\fi + +\M{75}\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}\E\\{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}\E\\{batch\_mode}$ and \\{log\_file} is open); + +\hang\\{term\_and\_log} (when $\\{interaction}>\\{batch\_mode}$ and \\{log\_file} is open). + +\Y\B\4\X75:Initialize the print \\{selector} based on \\{interaction}\X${}\E{}$\6 +\&{if} ${}(\\{interaction}\E\\{batch\_mode}){}$\1\5 +${}\\{selector}\K\\{no\_print}{}$;\5 +\2\&{else} $\\{selector}\K{}$\\{term\_only}\par +\Us1265\ET1337.\fi + +\M{76}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\B\4\D$\\{spotless}$ \5 +\T{0}\C{\\{history} value when nothing has been amiss yet}\par +\B\4\D$\\{warning\_issued}$ \5 +\T{1}\C{\\{history} value when \\{begin\_diagnostic} has been called}\par +\B\4\D$\\{error\_message\_issued}$ \5 +\T{2}\C{\\{history} value when \&{error} has been called}\par +\B\4\D$\\{fatal\_error\_stop}$ \5 +\T{3}\C{\\{history} value when termination was premature}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{bool} \\{deletions\_allowed};\C{is it safe for \&{error} to call \\{get\_token}?}\6 +\&{bool} \\{set\_box\_allowed};\C{is it safe to do a \.{\\setbox} assignment?}\6 +\&{uint8\_t} \\{history};\C{has the source input been clean so far?}\6 +\&{int8\_t} \\{error\_count};\C{the number of scrolled errors since the last paragraph ended}\par +\fi + +\M{77}The value of \\{history} is initially \\{fatal\_error\_stop}, but it will +be changed to \\{spotless} if \TeX\ survives the initialization process. + +\Y\B\4\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{deletions\_allowed}\K\\{true};{}$\5 +${}\\{set\_box\_allowed}\K\\{true};{}$\5 +${}\\{error\_count}\K\T{0}{}$;\C{\\{history} is initialized elsewhere}\par +\fi + +\M{78}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\B\4\X78:Error handling procedures\X${}\E{}$\6 +\&{void} \\{normalize\_selector}(\&{void});\6 +\&{void} \\{get\_token}(\&{void});\6 +\&{void} \\{term\_input}(\&{void});\6 +\&{void} \\{show\_context}(\&{void});\6 +\&{void} \\{begin\_file\_reading}(\&{void});\6 +\&{void} \\{open\_log\_file}(\&{void});\6 +\&{void} \\{close\_files\_and\_terminate}(\&{void});\6 +\&{void} \\{clear\_for\_error\_prompt}(\&{void});\6 +\&{void} \\{give\_err\_help}(\&{void});\6 +\8\#\&{ifdef} \.{DEBUG}\6 +\&{void} \\{debug\_help}(\&{void});\6 +\8\#\&{else}\6 +\8\#\&{define} \\{debug\_help}(\,) \5\\{do\_nothing}\6 +\8\#\&{endif}\par +\As81, 82, 93, 94\ETs95. +\U4.\fi + +\M{79}Individual lines of help are recorded in the array \\{help\_line}, which +contains entries in positions $\T{0}\dotdot(\\{help\_ptr}-\T{1})$. They should be printed +in reverse order, i.e., with \\{help\_line}[\T{0}] appearing last. + +\Y\B\4\D$\\{hlp1}(\|X)$ \5 +$\\{help\_line}[\T{0}]\K\|X{}$;\5 +$\}{}$\par +\B\4\D$\\{hlp2}(\|X)$ \5 +$\\{help\_line}[\T{1}]\K\|X;$ \\{hlp1}\par +\B\4\D$\\{hlp3}(\|X)$ \5 +$\\{help\_line}[\T{2}]\K\|X;$ \\{hlp2}\par +\B\4\D$\\{hlp4}(\|X)$ \5 +$\\{help\_line}[\T{3}]\K\|X;$ \\{hlp3}\par +\B\4\D$\\{hlp5}(\|X)$ \5 +$\\{help\_line}[\T{4}]\K\|X;$ \\{hlp4}\par +\B\4\D$\\{hlp6}(\|X)$ \5 +$\\{help\_line}[\T{5}]\K\|X;$ \\{hlp5}\par +\B\4\D$\\{help0}$ \5 +$\\{help\_ptr}\K{}$\T{0}\C{sometimes there might be no help}\par +\B\4\D$\\{help1}$ \5 +$\{{}$\5 +$\\{help\_ptr}\K\T{1};$ \\{hlp1}\C{use this with one help line}\par +\B\4\D$\\{help2}$ \5 +$\{{}$\5 +$\\{help\_ptr}\K\T{2};$ \\{hlp2}\C{use this with two help lines}\par +\B\4\D$\\{help3}$ \5 +$\{{}$\5 +$\\{help\_ptr}\K\T{3};$ \\{hlp3}\C{use this with three help lines}\par +\B\4\D$\\{help4}$ \5 +$\{{}$\5 +$\\{help\_ptr}\K\T{4};$ \\{hlp4}\C{use this with four help lines}\par +\B\4\D$\\{help5}$ \5 +$\{{}$\5 +$\\{help\_ptr}\K\T{5};$ \\{hlp5}\C{use this with five help lines}\par +\B\4\D$\\{help6}$ \5 +$\{{}$\5 +$\\{help\_ptr}\K\T{6};$ \\{hlp6}\C{use this with six help lines}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{char} ${}{*}\\{help\_line}[\T{6}]{}$;\C{helps for the next \&{error}}\6 +\&{uint8\_t} \\{help\_ptr};\C{the number of help lines present}\6 +\&{bool} \\{use\_err\_help};\C{should the \\{err\_help} list be shown?}\par +\fi + +\M{80}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{help\_ptr}\K\T{0};{}$\5 +${}\\{use\_err\_help}\K\\{false}{}$;\par +\fi + +\M{81}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\B\4\X78:Error handling procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{jump\_out}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{close\_files\_and\_terminate}(\,);\5 +\\{exit}(\T{0});\6 +\4${}\}{}$\2\par +\fi + +\M{82}Here now is the general \&{error} routine. + +\Y\B\4\X78:Error handling procedures\X${}\mathrel+\E{}$\6 +\&{void} \&{error} (\&{void})\C{completes the job of error reporting}\6 +${}\{{}$\5 +\1\&{ASCII\_code} \|c;\C{what the user types}\6 +\&{int} \\{s1}${},{}$ \\{s2}${},{}$ \\{s3}${},{}$ \\{s4};\C{used to save global variables when deleting tokens}\7 +\&{if} ${}(\\{history}<\\{error\_message\_issued}){}$\1\5 +${}\\{history}\K\\{error\_message\_issued};{}$\2\6 +\\{print\_char}(\.{'.'});\5 +\\{show\_context}(\,);\6 +\&{if} ${}(\\{interaction}\E\\{error\_stop\_mode}){}$\1\5 +\X83:Get user's advice and \&{return}\X;\2\6 +\\{incr}(\\{error\_count});\6 +\&{if} ${}(\\{error\_count}\E\T{100}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"(That\ makes\ 100\ err}\)\.{ors;\ please\ try\ agai}\)\.{n.)"});\5 +${}\\{history}\K\\{fatal\_error\_stop};{}$\5 +\\{jump\_out}(\,);\6 +\4${}\}{}$\2\6 +\X90:Put help message on the transcript file\X;\6 +\4${}\}{}$\2\par +\fi + +\M{83}\B\X83:Get user's advice and \&{return}\X${}\E{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{resume}:\5 +\\{clear\_for\_error\_prompt}(\,);\5 +\\{prompt\_input}(\.{"?\ "});\6 +\&{if} ${}(\\{last}\E\\{first}){}$\1\5 +\&{return};\2\6 +${}\|c\K\\{buffer}[\\{first}];{}$\6 +\&{if} ${}(\|c\G\.{'a'}){}$\1\5 +${}\|c\K\|c+\.{'A'}-\.{'a'}{}$;\C{convert to uppercase}\2\6 +\X84:Interpret code \|c and \&{return} if done\X;\6 +\4${}\}{}$\2\par +\U82.\fi + +\M{84}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. But such an extension requires some system +wizardry, so the present implementation simply types out the name of the +file that should be +edited and the relevant line number. + +There is a secret `\.D' option available when the debugging routines haven't +been commented~out. + +\Y\B\4\X84:Interpret code \|c and \&{return} if done\X${}\E{}$\6 +\&{switch} (\|c)\5 +${}\{{}$\1\6 +\4\&{case} \.{'0'}:\5 +\&{case} \.{'1'}:\5 +\&{case} \.{'2'}:\5 +\&{case} \.{'3'}:\5 +\&{case} \.{'4'}:\5 +\&{case} \.{'5'}:\5 +\&{case} \.{'6'}:\5 +\&{case} \.{'7'}:\5 +\&{case} \.{'8'}:\5 +\&{case} \.{'9'}:\6 +\&{if} (\\{deletions\_allowed})\1\5 +\X88:Delete \(c)$\|c-\.{"0"}$ tokens and \&{goto} \&{continue}\X\5 +\2\&{break};\5 +\hbox{\4\4}\6 +\8\#\&{ifdef} \.{DEBUG}\6 +\4\&{case} \.{'D'}:\6 +${}\{{}$\5 +\1\\{debug\_help}(\,);\5 +\&{goto} \\{resume};\5 +${}\}{}$\2\6 +\8\#\&{endif}\6 +\4\&{case} \.{'E'}:\6 +\&{if} ${}(\\{base\_ptr}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"You\ want\ to\ edit\ fi}\)\.{le\ "});\5 +${}\\{slow\_print}(\\{input\_stack}[\\{base\_ptr}].\\{name\_field});{}$\5 +\\{print\_str}(\.{"\ at\ line\ "});\5 +\\{print\_int}(\\{line});\5 +${}\\{interaction}\K\\{scroll\_mode};{}$\5 +\\{jump\_out}(\,);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \.{'H'}:\5 +\X89:Print the help information and \&{goto} \&{continue}\X\6 +\4\&{case} \.{'I'}:\5 +\X87:Introduce new material from the terminal and \&{return}\X\6 +\4\&{case} \.{'Q'}:\5 +\&{case} \.{'R'}:\5 +\&{case} \.{'S'}:\5 +\X86:Change the interaction level and \&{return}\X\6 +\4\&{case} \.{'X'}:\6 +${}\{{}$\5 +\1${}\\{interaction}\K\\{scroll\_mode};{}$\5 +\\{jump\_out}(\,);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\6 +\X85:Print the menu of available options\X\par +\U83.\fi + +\M{85}\B\X85:Print the menu of available options\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"Type\ <return>\ to\ pr}\)\.{oceed,\ S\ to\ scroll\ f}\)\.{uture\ error\ messages}\)\.{,"});\6 +\\{print\_nl}(\.{"R\ to\ run\ without\ st}\)\.{opping,\ Q\ to\ run\ qui}\)\.{etly,"});\6 +\\{print\_nl}(\.{"I\ to\ insert\ somethi}\)\.{ng,\ "});\6 +\&{if} ${}(\\{base\_ptr}>\T{0}){}$\1\5 +\\{print\_str}(\.{"E\ to\ edit\ your\ file}\)\.{,"});\2\6 +\&{if} (\\{deletions\_allowed})\1\5 +\\{print\_nl}(\.{"1\ or\ ...\ or\ 9\ to\ ig}\)\.{nore\ the\ next\ 1\ to\ 9}\)\.{\ tokens\ of\ input,"});\2\6 +\\{print\_nl}(\.{"H\ for\ help,\ X\ to\ qu}\)\.{it."});\6 +\4${}\}{}$\2\par +\U84.\fi + +\M{86}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\B\4\X86:Change the interaction level and \&{return}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{error\_count}\K\T{0};{}$\5 +${}\\{interaction}\K\\{batch\_mode}+\|c-\.{'Q'};{}$\5 +\\{print\_str}(\.{"OK,\ entering\ "});\6 +\&{switch} (\|c)\5 +${}\{{}$\1\6 +\4\&{case} \.{'Q'}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1383:\.{"batchmode"}\X);\5 +\\{decr}(\\{selector});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \.{'R'}:\5 +\\{print\_esc}(\X1384:\.{"nonstopmode"}\X);\5 +\&{break};\6 +\4\&{case} \.{'S'}:\5 +\\{print\_esc}(\X1385:\.{"scrollmode"}\X);\6 +\4${}\}{}$\C{there are no other cases}\2\6 +\\{print\_str}(\.{"..."});\5 +\\{print\_ln}(\,);\5 +\\{update\_terminal};\5 +\&{return};\6 +\4${}\}{}$\2\par +\U84.\fi + +\M{87}When the following code is executed, $\\{buffer}[(\\{first}+\T{1})\dotdot(\\{last}-\T{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\B\4\X87:Introduce new material from the terminal and \&{return}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{begin\_file\_reading}(\,);\C{enter a new syntactic level for terminal input}\C{now $\\{state}\E\\{mid\_line}$, so an initial blank space will count as a blank}\6 +\&{if} ${}(\\{last}>\\{first}+\T{1}){}$\5 +${}\{{}$\5 +\1${}\\{loc}\K\\{first}+\T{1};{}$\5 +${}\\{buffer}[\\{first}]\K\.{'\ '};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{prompt\_input}(\.{"insert>"});\5 +${}\\{loc}\K\\{first};{}$\6 +\4${}\}{}$\2\6 +${}\\{first}\K\\{last};{}$\5 +${}\\{cur\_input}.\\{limit\_field}\K\\{last}-\T{1}{}$;\C{no \\{end\_line\_char} ends this line}\6 +\&{return};\6 +\4${}\}{}$\2\par +\U84.\fi + +\M{88}We allow deletion of up to 99 tokens at a time. + +\Y\B\4\X88:Delete \(c)$\|c-\.{"0"}$ tokens and \&{goto} \&{continue}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{s1}\K\\{cur\_tok};{}$\5 +${}\\{s2}\K\\{cur\_cmd};{}$\5 +${}\\{s3}\K\\{cur\_chr};{}$\5 +${}\\{s4}\K\\{align\_state};{}$\5 +${}\\{align\_state}\K\T{1000000};{}$\5 +${}\\{OK\_to\_interrupt}\K\\{false};{}$\6 +\&{if} ${}((\\{last}>\\{first}+\T{1})\W(\\{buffer}[\\{first}+\T{1}]\G\.{'0'})\W(\\{buffer}[\\{first}+\T{1}]\Z\.{'9'})){}$\1\5 +${}\|c\K\|c*\T{10}+\\{buffer}[\\{first}+\T{1}]-\.{'0'}*\T{11};{}$\2\6 +\&{else}\1\5 +${}\|c\K\|c-\.{'0'};{}$\2\6 +\&{while} ${}(\|c>\T{0}){}$\5 +${}\{{}$\5 +\1\\{get\_token}(\,);\C{one-level recursive call of \&{error} is possible}\6 +\\{decr}(\|c);\6 +\4${}\}{}$\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\ a}\)\.{sked."})\6 +(\.{"You\ can\ now\ delete\ }\)\.{more,\ or\ insert,\ or\ }\)\.{whatever."});\5 +\\{show\_context}(\,);\5 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\par +\U84.\fi + +\M{89}\B\X89:Print the help information and \&{goto} \&{continue}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} (\\{use\_err\_help})\5 +${}\{{}$\5 +\1\\{give\_err\_help}(\,);\5 +${}\\{use\_err\_help}\K\\{false};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{help\_ptr}\E\T{0}){}$\1\5 +\\{help2}(\.{"Sorry,\ I\ don't\ know}\)\.{\ how\ to\ help\ in\ this}\)\.{\ situation."})\6 +\hbox{\kern1em}(\.{"Maybe\ you\ should\ tr}\)\.{y\ asking\ a\ human?"});\2\6 +\&{do}\5 +${}\{{}$\1\6 +\\{decr}(\\{help\_ptr});\5 +\\{print\_str}(\\{help\_line}[\\{help\_ptr}]);\5 +\\{print\_ln}(\,);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{help\_ptr}\E\T{0}));{}$\6 +\4${}\}{}$\2\6 +\\{help4}(\.{"Sorry,\ I\ already\ ga}\)\.{ve\ what\ help\ I\ could}\)\.{..."})\6 +(\.{"Maybe\ you\ should\ tr}\)\.{y\ asking\ a\ human?"})\6 +(\.{"An\ error\ might\ have}\)\.{\ occurred\ before\ I\ n}\)\.{oticed\ any\ problems.}\)\.{"})\6 +(\.{"``If\ all\ else\ fails}\)\.{,\ read\ the\ instructi}\)\.{ons.'"});\6 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\par +\U84.\fi + +\M{90}\B\X90:Put help message on the transcript file\X${}\E{}$\6 +\&{if} ${}(\\{interaction}>\\{batch\_mode}){}$\1\5 +\\{decr}(\\{selector});\C{avoid terminal output}\2\6 +\&{if} (\\{use\_err\_help})\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\\{give\_err\_help}(\,);\6 +\4${}\}{}$\2\6 +\&{else}\1\6 +\&{while} ${}(\\{help\_ptr}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{decr}(\\{help\_ptr});\5 +\\{print\_nl}(\\{help\_line}[\\{help\_ptr}]);\6 +\4${}\}{}$\2\2\6 +\\{print\_ln}(\,);\6 +\&{if} ${}(\\{interaction}>\\{batch\_mode}){}$\1\5 +\\{incr}(\\{selector});\C{re-enable terminal output}\2\6 +\\{print\_ln}(\,)\par +\U82.\fi + +\M{91}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\B\&{void} \\{int\_error}(\&{int} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ ("});\5 +\\{print\_int}(\|n);\5 +\\{print\_char}(\.{')'});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\fi + +\M{92}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\B\&{void} \\{normalize\_selector}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} (\\{log\_opened})\1\5 +${}\\{selector}\K\\{term\_and\_log};{}$\2\6 +\&{else}\1\5 +${}\\{selector}\K\\{term\_only};{}$\2\6 +\&{if} ${}(\\{job\_name}\E\T{0}){}$\1\5 +\\{open\_log\_file}(\,);\2\6 +\&{if} ${}(\\{interaction}\E\\{batch\_mode}){}$\1\5 +\\{decr}(\\{selector});\2\6 +\4${}\}{}$\2\par +\fi + +\M{93}The following procedure prints \TeX's last words before dying. + +\Y\B\4\D$\\{succumb}$ \6 +${}\{{}$\5 +\1\&{if} ${}(\\{interaction}\E\\{error\_stop\_mode}){}$\1\5 +${}\\{interaction}\K\\{scroll\_mode}{}$;\C{no more interaction}\2\6 +\&{if} (\\{log\_opened})\1\6 +\&{error} (\,)\1\5 +;\2\2\6 +\&{if} ${}(\\{interaction}>\\{batch\_mode}){}$\1\5 +\\{debug\_help}(\,);\2\6 +${}\\{history}\K\\{fatal\_error\_stop};{}$\5 +\\{jump\_out}(\,);\C{irrecoverable error}\6 +\4${}\}{}$\2\par +\Y\B\4\X78:Error handling procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{fatal\_error}(\&{char} ${}{*}\|s{}$)\C{prints \|s, and that's it}\6 +${}\{{}$\5 +\1\\{normalize\_selector}(\,);\6 +\\{print\_err}(\.{"Emergency\ stop"});\5 +\\{help1}(\|s);\5 +\\{succumb};\6 +\4${}\}{}$\2\par +\fi + +\M{94}Here is the most dreaded error message. + +\Y\B\4\X78:Error handling procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{overflow}(\&{char} ${}{*}\|s,\39{}$\&{int} \|n)\C{stop due to finiteness}\6 +${}\{{}$\5 +\1\\{normalize\_selector}(\,);\5 +\\{print\_err}(\.{"TeX\ capacity\ exceed}\)\.{ed,\ sorry\ ["});\5 +\\{print\_str}(\|s);\5 +\\{print\_char}(\.{'='});\5 +\\{print\_int}(\|n);\5 +\\{print\_char}(\.{']'});\5 +\\{help2}(\.{"If\ you\ really\ absol}\)\.{utely\ need\ more\ capa}\)\.{city,"})\6 +(\.{"you\ can\ ask\ a\ wizar}\)\.{d\ to\ enlarge\ me."});\5 +\\{succumb};\6 +\4${}\}{}$\2\par +\fi + +\M{95}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\B\4\X78:Error handling procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{confusion}(\&{str\_number} \|s)\C{consistency check violated; \|s tells where}\6 +${}\{{}$\5 +\1\\{normalize\_selector}(\,);\6 +\&{if} ${}(\\{history}<\\{error\_message\_issued}){}$\5 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"I\ can't\ go\ on\ meeti}\)\.{ng\ you\ like\ this"});\5 +\\{help2}(\.{"One\ of\ your\ faux\ pa}\)\.{s\ seems\ to\ have\ woun}\)\.{ded\ me\ deeply..."})\6 +(\.{"in\ fact,\ I'm\ barely}\)\.{\ conscious.\ Please\ f}\)\.{ix\ it\ and\ try\ again.}\)\.{"});\6 +\4${}\}{}$\2\6 +\\{succumb};\6 +\4${}\}{}$\2\par +\fi + +\M{96}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\B\4\D$\\{check\_interrupt}$ \6 +${}\{{}$\5 +\1\&{if} ${}(\\{interrupt}\I\T{0}){}$\1\5 +\\{pause\_for\_instructions}(\,);\2\6 +\4${}\}{}$\2\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{interrupt};\C{should \TeX\ pause for instructions?}\6 +\&{bool} \\{OK\_to\_interrupt};\C{should interrupts be observed?}\par +\fi + +\M{97}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{interrupt}\K\T{0};{}$\5 +${}\\{OK\_to\_interrupt}\K\\{true}{}$;\par +\fi + +\M{98}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\B\&{void} \\{pause\_for\_instructions}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} (\\{OK\_to\_interrupt})\5 +${}\{{}$\5 +\1${}\\{interaction}\K\\{error\_stop\_mode};{}$\6 +\&{if} ${}((\\{selector}\E\\{log\_only})\V(\\{selector}\E\\{no\_print})){}$\1\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\ wan}\)\.{t\ to\ quit\ by\ typing\ }\)\.{`X'."});\5 +${}\\{deletions\_allowed}\K\\{false};{}$\6 +\&{error} (\,)\1\5 +;\2\6 +${}\\{deletions\_allowed}\K\\{true};{}$\5 +${}\\{interrupt}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\N{1}{99}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 $/$ with a possibly negative +numerator. These are harmless; see $/$ 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 $/$.) + +\fi + +\M{100}Here is a routine that calculates half of an integer, using an +unambiguous convention with respect to signed odd numbers. + +\Y\B\&{int} \\{half}(\&{int} \|x)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} (\\{odd}(\|x))\1\5 +\&{return} ${}(\|x+\T{1})/\T{2};{}$\2\6 +\&{else}\1\5 +\&{return} \|x${}/\T{2};{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{101}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\B\4\D$\\{unity}$ \5 +\T{\~200000}\C{$2^{16}$, represents 1.00000}\par +\B\4\D$\\{two}$ \5 +\T{\~400000}\C{$2^{17}$, represents 2.00000}\par +\Y\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{int} \&{scaled};\C{this type is used for scaled integers}\6 +\&{typedef} \&{uint32\_t}\\{nonnegative\_integer};\C{$0\L x<2^{31}$}\6 +\&{typedef} \&{uint8\_t} \&{small\_number};\C{this type is self-explanatory}\par +\fi + +\M{102}The following function is used to create a scaled integer from a given decimal +fraction $(.d_0d_1\ldots d_{k-1})$, where $\T{0}\Z\|k\Z\T{17}$. The digit $d_i$ is +given in \\{dig}[\|i], and the calculation produces a correctly rounded result. + +\Y\B\&{scaled} \\{round\_decimals}(\&{small\_number} \|k)\C{converts a decimal fraction}\6 +${}\{{}$\5 +\1\&{int} \|a;\C{the accumulator}\7 +${}\|a\K\T{0};{}$\6 +\&{while} ${}(\|k>\T{0}){}$\5 +${}\{{}$\5 +\1\\{decr}(\|k);\5 +${}\|a\K(\|a+\\{dig}[\|k]*\\{two})/\T{10};{}$\6 +\4${}\}{}$\2\6 +\&{return} ${}(\|a+\T{1})/\T{2};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{103}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\B\&{void} \\{print\_scaled}(\&{scaled} \|s)\C{prints scaled real, rounded to five digits}\6 +${}\{{}$\5 +\1\&{scaled} \\{delta};\C{amount of allowable inaccuracy}\7 +\&{if} ${}(\|s<\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{'-'});\5 +\\{negate}(\|s);\C{print the sign, if negative}\6 +\4${}\}{}$\2\6 +${}\\{print\_int}(\|s/\\{unity}){}$;\C{print the integer part}\6 +\\{print\_char}(\.{'.'});\5 +${}\|s\K\T{10}*(\|s\MOD\\{unity})+\T{5};{}$\5 +${}\\{delta}\K\T{10}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\&{if} ${}(\\{delta}>\\{unity}){}$\1\5 +${}\|s\K\|s+\T{\~100000}-\T{50000}{}$;\C{round the last digit}\2\6 +${}\\{print\_char}(\.{'0'}+(\|s/\\{unity}));{}$\5 +${}\|s\K\T{10}*(\|s\MOD\\{unity});{}$\5 +${}\\{delta}\K\\{delta}*\T{10};{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|s\Z\\{delta}));{}$\6 +\4${}\}{}$\2\par +\fi + +\M{104}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\T{\~10000000000}{}$) \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, +\\{rem}, holds the remainder after a division. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{bool} \\{arith\_error};\C{has arithmetic overflow occurred recently?}\6 +\&{scaled} \\{rem};\C{amount subtracted to get an exact division}\par +\fi + +\M{105}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\B\4\D$\\{nx\_plus\_y}(\|X,\|Y,\|Z)$ \5 +$\\{mult\_and\_add}(\|X,\39\|Y,\39\|Z,\39\T{\~7777777777}{}$)\par +\B\4\D$\\{mult\_integers}(\|X,\|Y)$ \5 +$\\{mult\_and\_add}(\|X,\39\|Y,\39\T{0},\39\T{\~17777777777}{}$)\par +\Y\B\&{scaled} \\{mult\_and\_add}(\&{int} \|n${},\39{}$\&{scaled} \|x${},\39{}$\&{scaled} \|y${},\39{}$\&{scaled} \\{max\_answer})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\|n<\T{0}){}$\5 +${}\{{}$\5 +\1\\{negate}(\|x);\5 +\\{negate}(\|n);\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|n\E\T{0}){}$\1\5 +\&{return} \|y;\2\6 +\&{else} \&{if} ${}(((\|x\Z(\\{max\_answer}-\|y)/\|n)\W({-}\|x\Z(\\{max\_answer}+\|y)/\|n))){}$\1\5 +\&{return} \|n${}*\|x+\|y;{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{arith\_error}\K\\{true};{}$\5 +\&{return} \T{0};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{106}We also need to divide scaled dimensions by integers. + +\Y\B\&{scaled} \\{x\_over\_n}(\&{scaled} \|x${},\39{}$\&{int} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\&{bool} \\{negative};\C{should \\{rem} be negated?}\6 +\&{scaled} \\{x\_over\_n};\7 +${}\\{negative}\K\\{false};{}$\6 +\&{if} ${}(\|n\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{arith\_error}\K\\{true};{}$\5 +${}\\{x\_over\_n}\K\T{0};{}$\5 +${}\\{rem}\K\|x;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\|n<\T{0}){}$\5 +${}\{{}$\5 +\1\\{negate}(\|x);\5 +\\{negate}(\|n);\5 +${}\\{negative}\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|x\G\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{x\_over\_n}\K\|x/\|n;{}$\5 +${}\\{rem}\K\|x\MOD\|n;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{x\_over\_n}\K{-}(({-}\|x)/\|n);{}$\5 +${}\\{rem}\K{-}(({-}\|x)\MOD\|n);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} (\\{negative})\1\5 +\\{negate}(\\{rem});\2\6 +\&{return} \\{x\_over\_n};\6 +\4${}\}{}$\2\par +\fi + +\M{107}Then comes the multiplication of a scaled number by a fraction $\|n/{}$(\&{double}) \|d, +where \|n and \|d are nonnegative integers $\Z\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\B\&{scaled} \\{xn\_over\_d}(\&{scaled} \|x${},\39{}$\&{int} \|n${},\39{}$\&{int} \|d)\1\1\2\2\6 +${}\{{}$\5 +\1\&{bool} \\{positive};\C{was $\|x\G\T{0}$?}\7 +${}\\{nonnegative\_integer}\|t,\39\|u,\39\|v{}$;\C{intermediate quantities}\7 +\&{scaled} \\{xn\_over\_d};\7 +\&{if} ${}(\|x\G\T{0}){}$\1\5 +${}\\{positive}\K\\{true};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{negate}(\|x);\5 +${}\\{positive}\K\\{false};{}$\6 +\4${}\}{}$\2\6 +${}\|t\K(\|x\MOD\T{\~100000})*\|n;{}$\5 +${}\|u\K(\|x/\T{\~100000})*\|n+(\|t/\T{\~100000});{}$\5 +${}\|v\K(\|u\MOD\|d)*\T{\~100000}+(\|t\MOD\T{\~100000});{}$\6 +\&{if} ${}(\|u/\|d\G\T{\~100000}){}$\1\5 +${}\\{arith\_error}\K\\{true};{}$\2\6 +\&{else}\1\5 +${}\|u\K\T{\~100000}*(\|u/\|d)+(\|v/\|d);{}$\2\6 +\&{if} (\\{positive})\5 +${}\{{}$\5 +\1${}\\{xn\_over\_d}\K\|u;{}$\5 +${}\\{rem}\K\|v\MOD\|d;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{xn\_over\_d}\K{-}\|u;{}$\5 +${}\\{rem}\K{-}(\|v\MOD\|d);{}$\6 +\4${}\}{}$\2\6 +\&{return} \\{xn\_over\_d};\6 +\4${}\}{}$\2\par +\fi + +\M{108}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+\T{1},\|s)\G\\{badness}(\|t,\|s)\G\\{badness}(\|t,\|s+\T{1})$}.$$ The badness function defined here is capable of +computing at most 1095 distinct values, but that is plenty. + +\Y\B\4\D$\\{inf\_bad}$ \5 +\T{10000}\C{infinitely bad value}\par +\Y\B\&{halfword} \\{badness}(\&{scaled} \|t${},\39{}$\&{scaled} \|s)\C{compute badness, given $\|t\G\T{0}$}\6 +${}\{{}$\5 +\1\&{int} \|r;\C{approximation to $\alpha t/s$, where $\alpha^3\approx 100\cdot2^{18}$}\7 +\&{if} ${}(\|t\E\T{0}){}$\1\5 +\&{return} \T{0};\2\6 +\&{else} \&{if} ${}(\|s\Z\T{0}){}$\1\5 +\&{return} \\{inf\_bad};\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\|t\Z\T{7230584}){}$\1\5 +${}\|r\K(\|t*\T{297})/\|s{}$;\C{$297^3=99.94\times2^{18}$}\2\6 +\&{else} \&{if} ${}(\|s\G\T{1663497}){}$\1\5 +${}\|r\K\|t/(\|s/\T{297});{}$\2\6 +\&{else}\1\5 +${}\|r\K\|t;{}$\2\6 +\&{if} ${}(\|r>\T{1290}){}$\1\5 +\&{return} \\{inf\_bad};\C{$1290^3<2^{31}<1291^3$}\2\6 +\&{else}\1\5 +\&{return} ${}(\|r*\|r*\|r+\T{\~400000})/\T{\~1000000};{}$\2\6 +\4${}\}{}$\C{that was $r^3/2^{18}$, rounded to the nearest integer}\2\6 +\4${}\}{}$\2\par +\fi + +\M{109}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 +\&{int} (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\B\4\D$\\{set\_glue\_ratio\_zero}(\|X)$ \5 +$\|X\K{}$\T{0.0}\C{store the representation of zero ratio}\par +\B\4\D$\\{set\_glue\_ratio\_one}(\|X)$ \5 +$\|X\K{}$\T{1.0}\C{store the representation of unit ratio}\par +\B\4\D$\&{float}(\|X)$ \5 +((\&{double})(\|X))\C{convert from \\{glue\_ratio} to type \&{double}}\par +\B\4\D$\\{unfloat}(\|X)$ \5 +((\\{glue\_ratio})(\|X))\C{convert from \&{double} to type \\{glue\_ratio}}\par +\B\4\D$\\{float\_constant}(\|X)$ \5 +((\&{double})(\|X))\C{convert \&{int} constant to \&{double}}\par +\Y\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{float32\_t} \&{glue\_ratio};\C{one-word representation of a glue expansion factor}\par +\fi + +\N{1}{110}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&.\|i&(an \&{int})\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 \&{double} on some computers. Some +\PASCAL\ compilers will pack an integer whose subrange is `$\T{0}\dotdot\T{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 `${-}\T{128}\dotdot\T{127}$'. + +The present implementation tries to accommodate as many variations as possible, +so it makes few assumptions. If integers having the subrange +`$\\{min\_quarterword}\dotdot\\{max\_quarterword}$' can be packed into a quarterword, +and if integers having the subrange `$\\{min\_halfword}\dotdot\\{max\_halfword}$' +can be packed into a halfword, everything should work satisfactorily. + +It is usually most efficient to have $\\{min\_quarterword}\E\\{min\_halfword}\E\T{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\B\4\D$\\{min\_quarterword}$ \5 +\T{0}\C{smallest allowable value in a \\{quarterword}}\par +\B\4\D$\\{max\_quarterword}$ \5 +\T{255}\C{largest allowable value in a \\{quarterword}}\par +\B\4\D$\\{min\_halfword}$ \5 +\T{0}\C{smallest allowable value in a \&{halfword}}\par +\B\4\D$\\{max\_halfword}$ \5 +\T{65535}\C{largest allowable value in a \&{halfword}}\par +\fi + +\M{111}Here are the inequalities that the quarterword and halfword values +must satisfy (or rather, the inequalities that they mustn't satisfy): + +\Y\B\4\X14:Check the ``constant'' values for consistency\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{INIT}\6 +\&{if} ${}((\\{mem\_min}\I\\{mem\_bot})\V(\\{mem\_max}\I\\{mem\_top})){}$\1\5 +${}\\{bad}\K\T{10};{}$\2\6 +\8\#\&{endif}\6 +\&{if} ${}((\\{mem\_min}>\\{mem\_bot})\V(\\{mem\_max}<\\{mem\_top})){}$\1\5 +${}\\{bad}\K\T{10};{}$\2\6 +\&{if} ${}((\\{min\_quarterword}>\T{0})\V(\\{max\_quarterword}<\T{127})){}$\1\5 +${}\\{bad}\K\T{11};{}$\2\6 +\&{if} ${}((\\{min\_halfword}>\T{0})\V(\\{max\_halfword}<\T{32767})){}$\1\5 +${}\\{bad}\K\T{12};{}$\2\6 +\&{if} ${}((\\{min\_quarterword}<\\{min\_halfword})\V\30(\\{max\_quarterword}>\\{max\_halfword})){}$\1\5 +${}\\{bad}\K\T{13};{}$\2\6 +\&{if} ${}((\\{mem\_min}<\\{min\_halfword})\V(\\{mem\_max}\G\\{max\_halfword})\V\30(\\{mem\_bot}-\\{mem\_min}>\\{max\_halfword}+\T{1})){}$\1\5 +${}\\{bad}\K\T{14};{}$\2\6 +\&{if} ${}((\\{font\_base}<\\{min\_quarterword})\V(\\{font\_max}>\\{max\_quarterword})){}$\1\5 +${}\\{bad}\K\T{15};{}$\2\6 +\&{if} ${}(\\{font\_max}>\\{font\_base}+\T{256}){}$\1\5 +${}\\{bad}\K\T{16};{}$\2\6 +\&{if} ${}((\\{save\_size}>\\{max\_halfword})\V(\\{max\_strings}>\\{max\_halfword})){}$\1\5 +${}\\{bad}\K\T{17};{}$\2\6 +\&{if} ${}(\\{buf\_size}>\\{max\_halfword}){}$\1\5 +${}\\{bad}\K\T{18};{}$\2\6 +\&{if} ${}(\\{max\_quarterword}-\\{min\_quarterword}<\T{255}){}$\1\5 +${}\\{bad}\K\T{19}{}$;\2\par +\fi + +\M{112}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+\T{0}$' and `$\|x-\T{0}$', if these +macros are simplified in the obvious way when $\\{min\_quarterword}\E\T{0}$. + +\Y\B\4\D$\\{qi}(\|X)$ \5 +$\|X+{}$\\{min\_quarterword}\C{to put an \&{eight\_bits} item into a quarterword}\par +\B\4\D$\\{qo}(\|X)$ \5 +$\|X-{}$\\{min\_quarterword}\C{to take an \&{eight\_bits} item out of a quarterword}\par +\B\4\D$\\{hi}(\|X)$ \5 +$\|X+{}$\\{min\_halfword}\C{to put a sixteen-bit item into a halfword}\par +\B\4\D$\\{ho}(\|X)$ \5 +$\|X-{}$\\{min\_halfword}\C{to take a sixteen-bit item from a halfword}\par +\fi + +\M{113}The reader should study the following definitions closely: + +\Y\B\4\D$\\{sc}$ \5 +\|i\C{\&{scaled} data is equivalent to \&{int}}\par +\Y\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{uint8\_t} \&{quarterword};\C{1/4 of a word}\6 +\&{typedef} \&{uint16\_t} \&{halfword};\C{1/2 of a word}\6 +\&{typedef} \&{uint8\_t} \&{two\_choices};\C{used when there are two variants in a record}\6 +\&{typedef} \&{uint8\_t} \&{four\_choices};\C{used when there are four variants in a record}\6 +\&{typedef} \&{struct} ${}\{{}$\1\7 +\&{halfword} \\{rh};\6 +\&{union} ${}\{{}$\1\6 +\&{halfword} \\{lh};\6 +\&{struct} ${}\{{}$\1\6 +\&{quarterword} \\{b0};\6 +\&{quarterword} \\{b1};\2\6 +${}\};{}$\2\6 +${}\};{}$\2\6 +${}\}{}$ \&{two\_halves};\6 +\&{typedef} \&{struct} ${}\{{}$\1\7 +\&{quarterword} \\{b0};\6 +\&{quarterword} \\{b1};\6 +\&{quarterword} \\{b2};\6 +\&{quarterword} \\{b3};\2\6 +${}\}{}$ \&{four\_quarters};\6 +\&{typedef} \&{struct} ${}\{{}$\1\7 +\&{union} ${}\{{}$\1\6 +\&{int} \|i;\6 +\&{glue\_ratio} \\{gr};\6 +\&{two\_halves} \\{hh};\6 +\&{four\_quarters} \\{qqqq};\2\6 +${}\};{}$\2\6 +${}\}{}$ \&{memory\_word};\6 +\&{typedef} \&{struct} ${}\{{}$\5 +\1\&{FILE} ${}{*}\|f{}$;\5 +\&{memory\_word}\, \|d;\5 +\2${}\}{}$ \&{word\_file};\par +\fi + +\M{114}When debugging, we may want to print a \&{memory\_word} without knowing +what type it is; so we print it in all modes. + +\Y\B\8\#\&{ifdef} \.{DEBUG}\6 +\&{void} \\{print\_word}(\&{memory\_word} \|w)\C{prints \|w in all ways}\6 +${}\{{}$\5 +\1${}\\{print\_int}(\|w.\|i);{}$\5 +\\{print\_char}(\.{'\ '});\6 +${}\\{print\_scaled}(\|w.\\{sc});{}$\5 +\\{print\_char}(\.{'\ '});\6 +${}\\{print\_scaled}(\\{round}(\\{unity}*\&{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 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\N{1}{115}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\B\4\D$\&{pointer}$ \5 +\&{halfword}\C{a flag or a location in \\{mem} or \\{eqtb}}\par +\B\4\D$\\{null}$ \5 +\\{min\_halfword}\C{the null pointer}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{temp\_ptr};\C{a pointer variable for occasional emergency use}\par +\fi + +\M{116}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}\Z\\{mem\_min}\Z\\{mem\_bot}<\\{lo\_mem\_max}<\\{hi\_mem\_min}<\\{mem\_top}\Z\\{mem\_end}\Z\\{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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{memory\_word} ${}\\{mem0}[\\{mem\_max}-\\{mem\_min}+\T{1}],{}$ ${}{*\&{const}\ }\\{mem}\K\\{mem0}-\\{mem\_min}{}$;\C{the big dynamic storage area}\6 +\&{pointer} \\{lo\_mem\_max};\C{the largest location of variable-size memory in use}\6 +\&{pointer} \\{hi\_mem\_min};\C{the smallest location of one-word memory in use}\par +\fi + +\M{117}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 \#\&{ifdef} \.{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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{var\_used}${},{}$ \\{dyn\_used};\C{how much memory is in use}\6 +\8\#\&{ifdef} \.{DEBUG}\6 +\8\#\&{define} \\{incr\_dyn\_used} \5\\{incr}(\\{dyn\_used})\6 +\8\#\&{define} \\{decr\_dyn\_used} \5\\{decr}(\\{dyn\_used})\6 +\8\#\&{else}\6 +\8\#\&{define} \\{incr\_dyn\_used}\6 +\8\#\&{define} \\{decr\_dyn\_used}\6 +\8\#\&{endif}\par +\fi + +\M{118}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\B\4\D$\\{link}(\|X)$ \5 +$\\{mem}[\|X].\\{hh}.{}$\\{rh}\C{the \\{link} field of a memory word}\par +\B\4\D$\\{info}(\|X)$ \5 +$\\{mem}[\|X].\\{hh}.{}$\\{lh}\C{the \\{info} field of a memory word}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{avail};\C{head of the list of available one-word nodes}\6 +\&{pointer} \\{mem\_end};\C{the last one-word node used in \\{mem}}\par +\fi + +\M{119}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\B\X292:Declare the procedure called \\{show\_token\_list}\X\6 +\X306:Declare the procedure called \\{runaway}\X\par +\fi + +\M{120}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}\E\\{null}$, +we try first to increase \\{mem\_end}. If that cannot be done, i.e., if +$\\{mem\_end}\E\\{mem\_max}$, we try to decrease \\{hi\_mem\_min}. If that cannot be +done, i.e., if $\\{hi\_mem\_min}\E\\{lo\_mem\_max}+\T{1}$, we have to quit. + +\Y\B\&{pointer} \\{get\_avail}(\&{void})\C{single-word node allocation}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node being got}\7 +${}\|p\K\\{avail}{}$;\C{get top location in the \\{avail} stack}\6 +\&{if} ${}(\|p\I\\{null}){}$\1\5 +${}\\{avail}\K\\{link}(\\{avail}){}$;\C{and pop it off}\2\6 +\&{else} \&{if} ${}(\\{mem\_end}<\\{mem\_max}{}$)\C{or go into virgin territory}\6 +${}\{{}$\5 +\1\\{incr}(\\{mem\_end});\5 +${}\|p\K\\{mem\_end};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{decr}(\\{hi\_mem\_min});\5 +${}\|p\K\\{hi\_mem\_min};{}$\6 +\&{if} ${}(\\{hi\_mem\_min}\Z\\{lo\_mem\_max}){}$\5 +${}\{{}$\5 +\1\\{runaway}(\,);\C{if memory is exhausted, display possible runaway text}\6 +${}\\{overflow}(\.{"main\ memory\ size"},\39\\{mem\_max}+\T{1}-\\{mem\_min}){}$;\C{quit; all one-word nodes are busy}\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +${}\\{link}(\|p)\K\\{null}{}$;\C{provide an oft-desired initialization of the new node}\6 +\\{incr\_dyn\_used};\C{maintain statistics}\6 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{121}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\B\4\D$\\{free\_avail}(\|X)$ \C{single-word node liberation}\6 +${}\{{}$\5 +\1${}\\{link}(\|X)\K\\{avail};{}$\5 +${}\\{avail}\K\|X;{}$\5 +\\{decr\_dyn\_used};\6 +\4${}\}{}$\2\par +\fi + +\M{122}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\B\4\D$\\{fast\_get\_avail}(\|X)$ \5 +\hbox{}\6 +${}\{{}$\5 +\1${}\|X\K\\{avail}{}$;\C{avoid \\{get\_avail} if possible, to save time}\6 +\&{if} ${}(\|X\E\\{null}){}$\1\5 +${}\|X\K\\{get\_avail}(\,);{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{avail}\K\\{link}(\|X);{}$\5 +${}\\{link}(\|X)\K\\{null};{}$\5 +\\{incr\_dyn\_used};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{123}The procedure \\{flush\_list}(\|p) frees an entire linked list of +one-word nodes that starts at position \|p. + +\Y\B\&{void} \\{flush\_list}(\&{pointer} \|p)\C{makes list of single-word nodes available}\6 +${}\{{}$\5 +\1\&{pointer} \|q${},{}$ \|r;\C{list traversers}\7 +\&{if} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\|r\K\|p{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|q\K\|r;{}$\5 +${}\|r\K\\{link}(\|r);{}$\5 +\\{decr\_dyn\_used};\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|r\E\\{null})){}$;\C{now \|q is the last node on the list}\6 +${}\\{link}(\|q)\K\\{avail};{}$\5 +${}\\{avail}\K\|p;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{124}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\B\4\D$\\{empty\_flag}$ \5 +\\{max\_halfword}\C{the \\{link} of an empty variable-size node}\par +\B\4\D$\\{is\_empty}(\|X)$ \5 +$(\\{link}(\|X)\E\\{empty\_flag}{}$)\C{tests for empty node}\par +\B\4\D$\\{node\_size}$ \5 +\\{info}\C{the size field in empty variable-size nodes}\par +\B\4\D$\\{llink}(\|X)$ \5 +$\\{info}(\|X+\T{1}{}$)\C{left link in doubly-linked list of empty nodes}\par +\B\4\D$\\{rlink}(\|X)$ \5 +$\\{link}(\|X+\T{1}{}$)\C{right link in doubly-linked list of empty nodes}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{rover};\C{points to some node in the list of empties}\par +\fi + +\M{125}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\B\&{pointer} \\{get\_node}(\&{int} \|s)\C{variable-size node allocation}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the node currently under inspection}\6 +\&{pointer} \|q;\C{the node physically after node \|p}\6 +\&{int} \|r;\C{the newly allocated node, or a candidate for this honor}\6 +\&{int} \|t;\C{temporary register}\7 +\4\\{restart}:\5 +${}\|p\K\\{rover}{}$;\C{start at some free node in the ring}\6 +\&{do}\5 +${}\{{}$\1\6 +\X127: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${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|p\E\\{rover})){}$;\C{repeat until the whole list has been traversed}\6 +\&{if} ${}(\|s\E\T{\~10000000000}){}$\5 +${}\{{}$\5 +\1\&{return} \\{max\_halfword};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{lo\_mem\_max}+\T{2}<\\{hi\_mem\_min}){}$\1\6 +\&{if} ${}(\\{lo\_mem\_max}+\T{2}\Z\\{mem\_bot}+\\{max\_halfword}){}$\1\5 +\X126:Grow more variable-size memory and \&{goto} \\{restart}\X;\2\2\6 +${}\\{overflow}(\.{"main\ memory\ size"},\39\\{mem\_max}+\T{1}-\\{mem\_min}){}$;\C{sorry, nothing satisfactory is left}\6 +\4\\{found}:\5 +${}\\{link}(\|r)\K\\{null}{}$;\C{this node is now nonempty}\6 +\8\#\&{ifdef} \.{STAT}\6 +${}\\{var\_used}\K\\{var\_used}+\|s{}$;\C{maintain usage statistics}\6 +\8\#\&{endif}\6 +\&{return} \|r;\6 +\4${}\}{}$\2\par +\fi + +\M{126}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\B\4\X126:Grow more variable-size memory and \&{goto} \\{restart}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{hi\_mem\_min}-\\{lo\_mem\_max}\G\T{1998}){}$\1\5 +${}\|t\K\\{lo\_mem\_max}+\T{1000};{}$\2\6 +\&{else}\1\5 +${}\|t\K\\{lo\_mem\_max}+\T{1}+(\\{hi\_mem\_min}-\\{lo\_mem\_max})/\T{2}{}$;\C{$\\{lo\_mem\_max}+\T{2}\Z\|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\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} \\{restart};\6 +\4${}\}{}$\2\par +\U125.\fi + +\M{127}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+\T{1}$ about 95\pct! of the time. + +\Y\B\4\X127:Try to allocate within node \|p and its physical successors, and \&{goto} \\{found} if allocation was possible\X${}\E{}$\6 +$\|q\K\|p+\\{node\_size}(\|p){}$;\C{find the physical successor}\6 +\&{while} (\\{is\_empty}(\|q))\C{merge node \|p with node \|q}\6 +${}\{{}$\5 +\1${}\|t\K\\{rlink}(\|q);{}$\6 +\&{if} ${}(\|q\E\\{rover}){}$\1\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 +\4${}\}{}$\2\6 +${}\|r\K\|q-\|s;{}$\6 +\&{if} ${}(\|r>\|p+\T{1}){}$\1\5 +\X128:Allocate from the top of node \|p and \&{goto} \\{found}\X;\2\6 +\&{if} ${}(\|r\E\|p){}$\1\6 +\&{if} ${}(\\{rlink}(\|p)\I\|p){}$\1\5 +\X129: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 +\U125.\fi + +\M{128}\B\X128:Allocate from the top of node \|p and \&{goto} \\{found}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{node\_size}(\|p)\K\|r-\|p{}$;\C{store the remaining size}\6 +${}\\{rover}\K\|p{}$;\C{start searching here next time}\6 +\&{goto} \\{found};\6 +\4${}\}{}$\2\par +\U127.\fi + +\M{129}Here we delete node \|p from the ring, and let \\{rover} rove around. + +\Y\B\4\X129:Allocate entire node \|p and \&{goto} \\{found}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{rover}\K\\{rlink}(\|p);{}$\5 +${}\|t\K\\{llink}(\|p);{}$\5 +${}\\{llink}(\\{rover})\K\|t;{}$\5 +${}\\{rlink}(\|t)\K\\{rover};{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\par +\U127.\fi + +\M{130}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\B\&{void} \\{free\_node}(\&{pointer} \|p${},\39{}$\&{halfword} \|s)\C{variable-size node liberation}\6 +${}\{{}$\5 +\1\&{pointer} \|q;\C{\\{llink}(\\{rover})}\7 +${}\\{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 +\8\#\&{ifdef} \.{STAT}\6 +${}\\{var\_used}\K\\{var\_used}-\|s;{}$\6 +\8\#\&{endif}\C{maintain statistics}\6 +\4${}\}{}$\2\par +\fi + +\M{131}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\B\8\#\&{ifdef} \.{INIT}\6 +\&{void} \\{sort\_avail}(\&{void})\C{sorts the available variable-size nodes by location}\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|q${},{}$ \|r;\C{indices into \\{mem}}\6 +\&{pointer} \\{old\_rover};\C{initial \\{rover} setting}\7 +${}\|p\K\\{get\_node}(\T{\~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\5 +\X132: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}){}$\5 +${}\{{}$\5 +\1${}\\{llink}(\\{rlink}(\|p))\K\|p;{}$\5 +${}\|p\K\\{rlink}(\|p);{}$\6 +\4${}\}{}$\2\6 +${}\\{rlink}(\|p)\K\\{rover};{}$\5 +${}\\{llink}(\\{rover})\K\|p;{}$\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\M{132}The following \&{while} loop is guaranteed to +terminate, since the list that starts at +\\{rover} ends with \\{max\_halfword} during the sorting procedure. + +\Y\B\4\X132:Sort \(p)\|p into the list starting at \\{rover} and advance \|p to \\{rlink}(\|p)\X${}\E{}$\6 +\&{if} ${}(\|p<\\{rover}){}$\5 +${}\{{}$\5 +\1${}\|q\K\|p;{}$\5 +${}\|p\K\\{rlink}(\|q);{}$\5 +${}\\{rlink}(\|q)\K\\{rover};{}$\5 +${}\\{rover}\K\|q;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{rover};{}$\6 +\&{while} ${}(\\{rlink}(\|q)<\|p){}$\1\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 +\4${}\}{}$\2\par +\U131.\fi + +\N{1}{133}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\B\4\D$\\{type}(\|X)$ \5 +$\\{mem}[\|X].\\{hh}.{}$\\{b0}\C{identifies what kind of node this is}\par +\B\4\D$\\{subtype}(\|X)$ \5 +$\\{mem}[\|X].\\{hh}.{}$\\{b1}\C{secondary identification in some cases}\par +\fi + +\M{134}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}\E\\{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\B\4\D$\\{is\_char\_node}(\|X)$ \5 +$(\|X\G\\{hi\_mem\_min}{}$)\C{does the argument point to a \\{char\_node}?}\par +\B\4\D$\\{font}$ \5 +\\{type}\C{the font code in a \\{char\_node}}\par +\B\4\D$\\{character}$ \5 +\\{subtype}\C{the character code in a \\{char\_node}}\par +\fi + +\M{135}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. + +\Y\B\4\D$\\{hlist\_node}$ \5 +\T{0}\C{\\{type} of hlist nodes}\par +\B\4\D$\\{box\_node\_size}$ \5 +\T{7}\C{number of words to allocate for a box node}\par +\B\4\D$\\{width\_offset}$ \5 +\T{1}\C{position of \\{width} field in a box node}\par +\B\4\D$\\{depth\_offset}$ \5 +\T{2}\C{position of \\{depth} field in a box node}\par +\B\4\D$\\{height\_offset}$ \5 +\T{3}\C{position of \\{height} field in a box node}\par +\B\4\D$\\{width}(\|X)$ \5 +$\\{mem}[\|X+\\{width\_offset}].{}$\\{sc}\C{width of the box, in sp}\par +\B\4\D$\\{depth}(\|X)$ \5 +$\\{mem}[\|X+\\{depth\_offset}].{}$\\{sc}\C{depth of the box, in sp}\par +\B\4\D$\\{height}(\|X)$ \5 +$\\{mem}[\|X+\\{height\_offset}].{}$\\{sc}\C{height of the box, in sp}\par +\B\4\D$\\{shift\_amount}(\|X)$ \5 +$\\{mem}[\|X+\T{4}].{}$\\{sc}\C{repositioning distance, in sp}\par +\B\4\D$\\{list\_offset}$ \5 +\T{5}\C{position of \\{list\_ptr} field in a box node}\par +\B\4\D$\\{list\_ptr}(\|X)$ \5 +$\\{link}(\|X+\\{list\_offset}{}$)\C{beginning of the list inside the box}\par +\B\4\D$\\{glue\_order}(\|X)$ \5 +$\\{subtype}(\|X+\\{list\_offset}{}$)\C{applicable order of infinity}\par +\B\4\D$\\{glue\_sign}(\|X)$ \5 +$\\{type}(\|X+\\{list\_offset}{}$)\C{stretching or shrinking}\par +\B\4\D$\\{normal}$ \5 +\T{0}\C{the most common case when several cases are named}\par +\B\4\D$\\{stretching}$ \5 +\T{1}\C{glue setting applies to the stretch components}\par +\B\4\D$\\{shrinking}$ \5 +\T{2}\C{glue setting applies to the shrink components}\par +\B\4\D$\\{glue\_offset}$ \5 +\T{6}\C{position of \\{glue\_set} in a box node}\par +\B\4\D$\\{glue\_set}(\|X)$ \5 +$\\{mem}[\|X+\\{glue\_offset}].{}$\\{gr}\C{a word of type \&{glue\_ratio} for glue setting}\par +\fi + +\M{136}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\B\&{pointer} \\{new\_null\_box}(\&{void})\C{creates a new box node}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{get\_node}(\\{box\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{hlist\_node};{}$\5 +${}\\{subtype}(\|p)\K\\{min\_quarterword};{}$\5 +${}\\{width}(\|p)\K\T{0};{}$\5 +${}\\{depth}(\|p)\K\T{0};{}$\5 +${}\\{height}(\|p)\K\T{0};{}$\5 +${}\\{shift\_amount}(\|p)\K\T{0};{}$\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 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{137}A \\{vlist\_node} is like an \\{hlist\_node} in all respects except that it +contains a vertical list. + +\Y\B\4\D$\\{vlist\_node}$ \5 +\T{1}\C{\\{type} of vlist nodes}\par +\fi + +\M{138}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\B\4\D$\\{rule\_node}$ \5 +\T{2}\C{\\{type} of rule nodes}\par +\B\4\D$\\{rule\_node\_size}$ \5 +\T{4}\C{number of words to allocate for a rule node}\par +\B\4\D$\\{null\_flag}$ \5 +${-}{}$\T{\~10000000000}\C{$-2^{30}$, signifies a missing item}\par +\B\4\D$\\{is\_running}(\|X)$ \5 +$(\|X\E\\{null\_flag}{}$)\C{tests for a running dimension}\par +\fi + +\M{139}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\B\&{pointer} \\{new\_rule}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{get\_node}(\\{rule\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{rule\_node};{}$\5 +${}\\{subtype}(\|p)\K\T{0}{}$;\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 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{140}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 $\T{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\B\4\D$\\{ins\_node}$ \5 +\T{3}\C{\\{type} of insertion nodes}\par +\B\4\D$\\{ins\_node\_size}$ \5 +\T{5}\C{number of words to allocate for an insertion}\par +\B\4\D$\\{float\_cost}(\|X)$ \5 +$\\{mem}[\|X+\T{1}].{}$\|i\C{the \\{floating\_penalty} to be used}\par +\B\4\D$\\{ins\_ptr}(\|X)$ \5 +$\\{info}(\|X+\T{4}{}$)\C{the vertical list to be inserted}\par +\B\4\D$\\{split\_top\_ptr}(\|X)$ \5 +$\\{link}(\|X+\T{4}{}$)\C{the \\{split\_top\_skip} to be used}\par +\fi + +\M{141}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\B\4\D$\\{mark\_node}$ \5 +\T{4}\C{\\{type} of a mark node}\par +\B\4\D$\\{small\_node\_size}$ \5 +\T{2}\C{number of words to allocate for most node types}\par +\B\4\D$\\{mark\_ptr}(\|X)$ \5 +$\\{mem}[\|X+\T{1}].{}$\|i\C{head of the token list for a mark}\par +\fi + +\M{142}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\B\4\D$\\{adjust\_node}$ \5 +\T{5}\C{\\{type} of an adjust node}\par +\B\4\D$\\{adjust\_ptr}$ \5 +\\{mark\_ptr}\C{vertical list to be moved out of horizontal list}\par +\fi + +\M{143}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\B\4\D$\\{ligature\_node}$ \5 +\T{6}\C{\\{type} of a ligature node}\par +\B\4\D$\\{lig\_char}(\|X)$ \5 +$\|X+{}$\T{1}\C{the word where the ligature is to be found}\par +\B\4\D$\\{lig\_ptr}(\|X)$ \5 +\\{link}(\\{lig\_char}(\|X))\C{the list of characters}\par +\fi + +\M{144}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\B\&{pointer} \\{new\_ligature}(\&{quarterword} \|f${},\39{}$\&{quarterword} \|c${},\39{}$\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|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)\K\T{0};{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\7 +\&{pointer} \\{new\_lig\_item}(\&{quarterword} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{character}(\|p)\K\|c;{}$\5 +${}\\{lig\_ptr}(\|p)\K\\{null};{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{145}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}\E\\{null}$, +and $\\{replace\_count}\E\T{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)\E\\{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\B\4\D$\\{disc\_node}$ \5 +\T{7}\C{\\{type} of a discretionary node}\par +\B\4\D$\\{replace\_count}$ \5 +\\{subtype}\C{how many subsequent nodes to replace}\par +\B\4\D$\\{pre\_break}$ \5 +\\{llink}\C{text that precedes a discretionary break}\par +\B\4\D$\\{post\_break}$ \5 +\\{rlink}\C{text that follows a discretionary break}\par +\Y\B\&{pointer} \\{new\_disc}(\&{void})\C{creates an empty \\{disc\_node}}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{disc\_node};{}$\5 +${}\\{replace\_count}(\|p)\K\T{0};{}$\5 +${}\\{pre\_break}(\|p)\K\\{null};{}$\5 +${}\\{post\_break}(\|p)\K\\{null};{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{146}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\B\4\D$\\{whatsit\_node}$ \5 +\T{8}\C{\\{type} of special extension nodes}\par +\fi + +\M{147}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\B\4\D$\\{math\_node}$ \5 +\T{9}\C{\\{type} of a math node}\par +\B\4\D$\\{before}$ \5 +\T{0}\C{\\{subtype} for math node that introduces a formula}\par +\B\4\D$\\{after}$ \5 +\T{1}\C{\\{subtype} for math node that winds up a formula}\par +\Y\B\&{pointer} \\{new\_math}(\&{scaled} \|w${},\39{}$\&{small\_number} \|s)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{math\_node};{}$\5 +${}\\{subtype}(\|p)\K\|s;{}$\5 +${}\\{width}(\|p)\K\|w;{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{148}\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\B\4\D$\\{precedes\_break}(\|X)$ \5 +$(\\{type}(\|X)<\\{math\_node}{}$)\par +\B\4\D$\\{non\_discardable}(\|X)$ \5 +$(\\{type}(\|X)<\\{math\_node}{}$)\par +\fi + +\M{149}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}\E\T{0}$, $\\{baseline\_skip\_code}\E\T{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\B\4\D$\\{glue\_node}$ \5 +\T{10}\C{\\{type} of node that points to a glue specification}\par +\B\4\D$\\{cond\_math\_glue}$ \5 +\T{98}\C{special \\{subtype} to suppress glue in the next node}\par +\B\4\D$\\{mu\_glue}$ \5 +\T{99}\C{\\{subtype} for math glue}\par +\B\4\D$\\{a\_leaders}$ \5 +\T{100}\C{\\{subtype} for aligned leaders}\par +\B\4\D$\\{c\_leaders}$ \5 +\T{101}\C{\\{subtype} for centered leaders}\par +\B\4\D$\\{x\_leaders}$ \5 +\T{102}\C{\\{subtype} for expanded leaders}\par +\B\4\D$\\{glue\_ptr}$ \5 +\\{llink}\C{pointer to a glue specification}\par +\B\4\D$\\{leader\_ptr}$ \5 +\\{rlink}\C{pointer to box or rule node for leaders}\par +\fi + +\M{150}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\B\4\D$\\{glue\_spec\_size}$ \5 +\T{4}\C{number of words to allocate for a glue specification}\par +\B\4\D$\\{glue\_ref\_count}(\|X)$ \5 +\\{link}(\|X)\C{reference count of a glue specification}\par +\B\4\D$\\{stretch}(\|X)$ \5 +$\\{mem}[\|X+\T{2}].{}$\\{sc}\C{the stretchability of this glob of glue}\par +\B\4\D$\\{shrink}(\|X)$ \5 +$\\{mem}[\|X+\T{3}].{}$\\{sc}\C{the shrinkability of this glob of glue}\par +\B\4\D$\\{stretch\_order}$ \5 +\\{type}\C{order of infinity for stretching}\par +\B\4\D$\\{shrink\_order}$ \5 +\\{subtype}\C{order of infinity for shrinking}\par +\B\4\D$\\{fil}$ \5 +\T{1}\C{first-order infinity}\par +\B\4\D$\\{fill}$ \5 +\T{2}\C{second-order infinity}\par +\B\4\D$\\{filll}$ \5 +\T{3}\C{third-order infinity}\par +\Y\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{uint8\_t} \&{glue\_ord};\C{infinity to the 0, 1, 2, or 3 power}\par +\fi + +\M{151}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\B\&{pointer} \\{new\_spec}(\&{pointer} \|p)\C{duplicates a glue specification}\6 +${}\{{}$\5 +\1\&{pointer} \|q;\C{the new spec}\7 +${}\|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 +\&{return} \|q;\6 +\4${}\}{}$\2\par +\fi + +\M{152}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\B\&{pointer} \\{new\_param\_glue}(\&{small\_number} \|n)\1\1 $\{{}$\5 +\&{pointer} \|p;\C{the new node}\6 +\&{pointer} \|q;\C{the glue specification}\7 +${}\|p\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{glue\_node};{}$\5 +${}\\{subtype}(\|p)\K\|n+\T{1};{}$\5 +${}\\{leader\_ptr}(\|p)\K\\{null}{}$;\6 +\|q $\K$ \X224:Current \\{mem} equivalent of glue parameter number \|n\X\hbox{};\6 +${}\\{glue\_ptr}(\|p)\K\|q;{}$\5 +\\{incr}(\\{glue\_ref\_count}(\|q));\5 +\&{return} \|p; $\}{}$\par +\fi + +\M{153}Glue nodes that are more or less anonymous are created by \\{new\_glue}, +whose argument points to a glue specification. + +\Y\B\&{pointer} \\{new\_glue}(\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|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 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{154}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\B\&{pointer} \\{new\_skip\_param}(\&{small\_number} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\\{temp\_ptr}\K\\{new\_spec}(\X224: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+\T{1};{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{155}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\B\4\D$\\{kern\_node}$ \5 +\T{11}\C{\\{type} of a kern node}\par +\B\4\D$\&{explicit}$ \5 +\T{1}\C{\\{subtype} of kern nodes from \.{\\kern} and \.{\\/}}\par +\B\4\D$\\{acc\_kern}$ \5 +\T{2}\C{\\{subtype} of kern nodes from accents}\par +\fi + +\M{156}The \\{new\_kern} function creates a kern node having a given width. + +\Y\B\&{pointer} \\{new\_kern}(\&{scaled} \|w)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{kern\_node};{}$\5 +${}\\{subtype}(\|p)\K\\{normal};{}$\5 +${}\\{width}(\|p)\K\|w;{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{157}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 $\G$ \T{10000} is +treated as infinity, and no break will be allowed for such high values. +Similarly, any penalty $\Z$ ${-}\T{10000}$ is treated as negative infinity, and a +break will be forced. + +\Y\B\4\D$\\{penalty\_node}$ \5 +\T{12}\C{\\{type} of a penalty node}\par +\B\4\D$\\{inf\_penalty}$ \5 +\\{inf\_bad}\C{``infinite'' penalty value}\par +\B\4\D$\\{eject\_penalty}$ \5 +$({-}\\{inf\_penalty}{}$)\C{``negatively infinite'' penalty value}\par +\B\4\D$\\{penalty}(\|X)$ \5 +$\\{mem}[\|X+\T{1}].{}$\|i\C{the added cost of breaking a list here}\par +\fi + +\M{158}Anyone who has been reading the last few sections of the program will +be able to guess what comes next. + +\Y\B\&{pointer} \\{new\_penalty}(\&{int} \|m)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{penalty\_node};{}$\5 +${}\\{subtype}(\|p)\K\T{0}{}$;\C{the \\{subtype} is not used}\6 +${}\\{penalty}(\|p)\K\|m;{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{159}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})+\T{1}$ columns. +Unset nodes will be changed to box nodes when alignment is completed. + +\Y\B\4\D$\\{unset\_node}$ \5 +\T{13}\C{\\{type} for an unset node}\par +\B\4\D$\\{glue\_stretch}(\|X)$ \5 +$\\{mem}[\|X+\\{glue\_offset}].{}$\\{sc}\C{total stretch in an unset node}\par +\B\4\D$\\{glue\_shrink}$ \5 +\\{shift\_amount}\C{total shrink in an unset node}\par +\B\4\D$\\{span\_count}$ \5 +\\{subtype}\C{indicates the number of spanned columns}\par +\fi + +\M{160}In fact, there are still more types coming. When we get to math formula +processing we will see that a \\{style\_node} has $\\{type}\E\T{14}$; and a number +of larger type codes will also be defined, for use in math mode only. + +\fi + +\M{161}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 + +\N{1}{162}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}+\T{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\B\4\D$\\{zero\_glue}$ \5 +\\{mem\_bot}\C{specification for \.{0pt plus 0pt minus 0pt}}\par +\B\4\D$\\{fil\_glue}$ \5 +$\\{zero\_glue}+{}$\\{glue\_spec\_size}\C{\.{0pt plus 1fil minus 0pt}}\par +\B\4\D$\\{fill\_glue}$ \5 +$\\{fil\_glue}+{}$\\{glue\_spec\_size}\C{\.{0pt plus 1fill minus 0pt}}\par +\B\4\D$\\{ss\_glue}$ \5 +$\\{fill\_glue}+{}$\\{glue\_spec\_size}\C{\.{0pt plus 1fil minus 1fil}}\par +\B\4\D$\\{fil\_neg\_glue}$ \5 +$\\{ss\_glue}+{}$\\{glue\_spec\_size}\C{\.{0pt plus -1fil minus 0pt}}\par +\B\4\D$\\{lo\_mem\_stat\_max}$ \5 +$\\{fil\_neg\_glue}+\\{glue\_spec\_size}-{}$\T{1}\C{largest statically allocated word in the variable-size \\{mem}}\Y\par +\B\4\D$\\{page\_ins\_head}$ \5 +\\{mem\_top}\C{list of insertion data for current page}\par +\B\4\D$\\{contrib\_head}$ \5 +$\\{mem\_top}-{}$\T{1}\C{vlist of items not yet on current page}\par +\B\4\D$\\{page\_head}$ \5 +$\\{mem\_top}-{}$\T{2}\C{vlist for current page}\par +\B\4\D$\\{temp\_head}$ \5 +$\\{mem\_top}-{}$\T{3}\C{head of a temporary list of some kind}\par +\B\4\D$\\{hold\_head}$ \5 +$\\{mem\_top}-{}$\T{4}\C{head of a temporary list of another kind}\par +\B\4\D$\\{adjust\_head}$ \5 +$\\{mem\_top}-{}$\T{5}\C{head of adjustment list returned by \\{hpack}}\par +\B\4\D$\\{active}$ \5 +$\\{mem\_top}-{}$\T{7}\C{head of active list in \\{line\_break}, needs two words}\par +\B\4\D$\\{align\_head}$ \5 +$\\{mem\_top}-{}$\T{8}\C{head of preamble list for alignments}\par +\B\4\D$\\{end\_span}$ \5 +$\\{mem\_top}-{}$\T{9}\C{tail of spanned-width lists}\par +\B\4\D$\\{omit\_template}$ \5 +$\\{mem\_top}-{}$\T{10}\C{a constant token list}\par +\B\4\D$\\{null\_list}$ \5 +$\\{mem\_top}-{}$\T{11}\C{permanently empty list}\par +\B\4\D$\\{lig\_trick}$ \5 +$\\{mem\_top}-{}$\T{12}\C{a ligature masquerading as a \\{char\_node}}\par +\B\4\D$\\{garbage}$ \5 +$\\{mem\_top}-{}$\T{12}\C{used for scrap information}\par +\B\4\D$\\{backup\_head}$ \5 +$\\{mem\_top}-{}$\T{13}\C{head of token list built by \\{scan\_keyword}}\par +\B\4\D$\\{hi\_mem\_stat\_min}$ \5 +$\\{mem\_top}-{}$\T{13}\C{smallest statically allocated word in the one-word \\{mem}}\par +\B\4\D$\\{hi\_mem\_stat\_usage}$ \5 +\T{14}\C{the number of one-word nodes always present}\par +\fi + +\M{163}The following code gets \\{mem} off to a good start, when \TeX\ is +initializing itself the slow~way. + +\Y\B\4\X19:Local variables for initialization\X${}\mathrel+\E{}$\6 +\&{int} \|k;\C{index into \\{mem}, \\{eqtb}, etc.}\par +\fi + +\M{164}\B\X164:Initialize table entries (done by \.{INITEX} only)\X${}\E{}$\6 +\&{for} ${}(\|k\K\\{mem\_bot}+\T{1};{}$ ${}\|k\Z\\{lo\_mem\_stat\_max};{}$ ${}\|k\PP){}$\1\5 +${}\\{mem}[\|k].\\{sc}\K\T{0}{}$;\C{all glue dimensions are zeroed}\2\6 +${}\|k\K\\{mem\_bot}{}$;\5 +\&{while} ${}(\|k\Z\\{lo\_mem\_stat\_max}{}$)\C{set first words of glue specifications}\6 +${}\{{}$\5 +\1${}\\{glue\_ref\_count}(\|k)\K\\{null}+\T{1};{}$\5 +${}\\{stretch\_order}(\|k)\K\\{normal};{}$\5 +${}\\{shrink\_order}(\|k)\K\\{normal};{}$\5 +${}\|k\K\|k+\\{glue\_spec\_size};{}$\6 +\4${}\}{}$\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}+\T{1};{}$\5 +${}\\{link}(\\{rover})\K\\{empty\_flag}{}$;\C{now initialize the dynamic memory}\6 +${}\\{node\_size}(\\{rover})\K\T{1000}{}$;\C{which is a 1000-word available node}\6 +${}\\{llink}(\\{rover})\K\\{rover};{}$\5 +${}\\{rlink}(\\{rover})\K\\{rover}{}$;\6 +${}\\{lo\_mem\_max}\K\\{rover}+\T{1000};{}$\5 +${}\\{link}(\\{lo\_mem\_max})\K\\{null};{}$\5 +${}\\{info}(\\{lo\_mem\_max})\K\\{null}{}$;\6 +\&{for} ${}(\|k\K\\{hi\_mem\_stat\_min};{}$ ${}\|k\Z\\{mem\_top};{}$ ${}\|k\PP){}$\1\5 +${}\\{mem}[\|k]\K\\{mem}[\\{lo\_mem\_max}]{}$;\C{clear list heads}\2\6 +\X790: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}+\T{1}-\\{mem\_bot};{}$\5 +${}\\{dyn\_used}\K\\{hi\_mem\_stat\_usage}{}$;\C{initialize statistics}\par +\As222, 228, 232, 240, 250, 258, 552, 946, 951, 1216, 1301\ETs1369. +\U8.\fi + +\M{165}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 \\{is\_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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{DEBUG}\6 +\&{bool} ${}\\{is\_free0}[\\{mem\_max}-\\{mem\_min}+\T{1}],{}$ ${}{*\&{const}\ }\\{is\_free}\K\\{is\_free0}-\\{mem\_min}{}$;\C{free cells}\6 +\hbox{\hskip10pt}\&{bool} ${}\\{was\_free0}[\\{mem\_max}-\\{mem\_min}+\T{1}],{}$ ${}{*\&{const}\ }\\{was\_free}\K\\{was\_free0}-\\{mem\_min}{}$;\C{previously free cells}\6 +\hbox{\hskip10pt}\&{pointer} \\{was\_mem\_end}${},{}$ \\{was\_lo\_max}${},{}$ \\{was\_hi\_min};\C{previous \\{mem\_end}, \\{lo\_mem\_max}, and \\{hi\_mem\_min}}\6 +\hbox{\hskip10pt}\&{bool} \\{panicking};\C{do we want to check memory constantly?}\6 +\8\#\&{endif}\par +\fi + +\M{166}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{DEBUG}\6 +$\\{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 +\8\#\&{endif}\par +\fi + +\M{167}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\B\8\#\&{ifdef} \.{DEBUG}\6 +\&{void} \\{check\_mem}(\&{bool} \\{print\_locs})\1\1\2\2\6 +${}\{{}$\5 +\C{loop exits}\1\6 +\&{pointer} \|p${},{}$ \|q;\C{current locations of interest in \\{mem}}\6 +\&{bool} \\{clobbered};\C{is something amiss?}\7 +\&{for} ${}(\|p\K\\{mem\_min};{}$ ${}\|p\Z\\{lo\_mem\_max};{}$ ${}\|p\PP){}$\1\5 +${}\\{is\_free}[\|p]\K\\{false}{}$;\C{you can probably do this faster}\2\6 +\&{for} ${}(\|p\K\\{hi\_mem\_min};{}$ ${}\|p\Z\\{mem\_end};{}$ ${}\|p\PP){}$\1\5 +${}\\{is\_free}[\|p]\K\\{false}{}$;\C{ditto}\2\6 +\X168:Check single-word \\{avail} list\X;\6 +\X169:Check variable-size \\{avail} list\X;\6 +\X170:Check flags of unavailable nodes\X;\6 +\&{if} (\\{print\_locs})\1\5 +\X171:Print newly busy locations\X;\2\6 +\&{for} ${}(\|p\K\\{mem\_min};{}$ ${}\|p\Z\\{lo\_mem\_max};{}$ ${}\|p\PP){}$\1\5 +${}\\{was\_free}[\|p]\K\\{is\_free}[\|p];{}$\2\6 +\&{for} ${}(\|p\K\\{hi\_mem\_min};{}$ ${}\|p\Z\\{mem\_end};{}$ ${}\|p\PP){}$\1\5 +${}\\{was\_free}[\|p]\K\\{is\_free}[\|p]{}$;\C{$\\{was\_free}\K\\{is\_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 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\M{168}\B\X168:Check single-word \\{avail} list\X${}\E{}$\6 +$\|p\K\\{avail};{}$\5 +${}\|q\K\\{null};{}$\5 +${}\\{clobbered}\K\\{false};{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}((\|p>\\{mem\_end})\V(\|p<\\{hi\_mem\_min})){}$\1\5 +${}\\{clobbered}\K\\{true};{}$\2\6 +\&{else} \&{if} (\\{is\_free}[\|p])\1\5 +${}\\{clobbered}\K\\{true};{}$\2\6 +\&{if} (\\{clobbered})\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"AVAIL\ list\ clobbere}\)\.{d\ at\ "});\5 +\\{print\_int}(\|q);\5 +\&{goto} \\{done1};\6 +\4${}\}{}$\2\6 +${}\\{is\_free}[\|p]\K\\{true};{}$\5 +${}\|q\K\|p;{}$\5 +${}\|p\K\\{link}(\|q);{}$\6 +\4${}\}{}$\2\6 +\\{done1}:\par +\U167.\fi + +\M{169}\B\X169:Check variable-size \\{avail} list\X${}\E{}$\6 +$\|p\K\\{rover};{}$\5 +${}\|q\K\\{null};{}$\5 +${}\\{clobbered}\K\\{false}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\&{if} ${}((\|p\G\\{lo\_mem\_max})\V(\|p<\\{mem\_min})){}$\1\5 +${}\\{clobbered}\K\\{true};{}$\2\6 +\&{else} \&{if} ${}((\\{rlink}(\|p)\G\\{lo\_mem\_max})\V(\\{rlink}(\|p)<\\{mem\_min})){}$\1\5 +${}\\{clobbered}\K\\{true};{}$\2\6 +\&{else} \&{if} ${}(\R(\\{is\_empty}(\|p))\V(\\{node\_size}(\|p)<\T{2})\V\30(\|p+\\{node\_size}(\|p)>\\{lo\_mem\_max})\V\30(\\{llink}(\\{rlink}(\|p))\I\|p)){}$\1\5 +${}\\{clobbered}\K\\{true};{}$\2\6 +\&{if} (\\{clobbered})\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"Double-AVAIL\ list\ c}\)\.{lobbered\ at\ "});\5 +\\{print\_int}(\|q);\5 +\&{goto} \\{done2};\6 +\4${}\}{}$\2\6 +\&{for} ${}(\|q\K\|p;{}$ ${}\|q\Z\|p+\\{node\_size}(\|p)-\T{1};{}$ ${}\|q\PP{}$)\C{mark all locations free}\6 +${}\{{}$\5 +\1\&{if} (\\{is\_free}[\|q])\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"Doubly\ free\ locatio}\)\.{n\ at\ "});\5 +\\{print\_int}(\|q);\5 +\&{goto} \\{done2};\6 +\4${}\}{}$\2\6 +${}\\{is\_free}[\|q]\K\\{true};{}$\6 +\4${}\}{}$\2\6 +${}\|q\K\|p;{}$\5 +${}\|p\K\\{rlink}(\|p);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|p\E\\{rover}));$ \\{done2}:\par +\U167.\fi + +\M{170}\B\X170:Check flags of unavailable nodes\X${}\E{}$\6 +$\|p\K\\{mem\_min};{}$\6 +\&{while} ${}(\|p\Z\\{lo\_mem\_max}{}$)\C{node \|p should not be empty}\6 +${}\{{}$\5 +\1\&{if} (\\{is\_empty}(\|p))\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"Bad\ flag\ at\ "});\5 +\\{print\_int}(\|p);\6 +\4${}\}{}$\2\6 +\&{while} ${}((\|p\Z\\{lo\_mem\_max})\W\R\\{is\_free}[\|p]){}$\1\5 +\\{incr}(\|p);\2\6 +\&{while} ${}((\|p\Z\\{lo\_mem\_max})\W\\{is\_free}[\|p]){}$\1\5 +\\{incr}(\|p);\2\6 +\4${}\}{}$\2\par +\U167.\fi + +\M{171}\B\X171:Print newly busy locations\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_nl}(\.{"New\ busy\ locs:"});\6 +\&{for} ${}(\|p\K\\{mem\_min};{}$ ${}\|p\Z\\{lo\_mem\_max};{}$ ${}\|p\PP){}$\1\6 +\&{if} ${}(\R\\{is\_free}[\|p]\W((\|p>\\{was\_lo\_max})\V\\{was\_free}[\|p])){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{'\ '});\5 +\\{print\_int}(\|p);\6 +\4${}\}{}$\2\2\6 +\&{for} ${}(\|p\K\\{hi\_mem\_min};{}$ ${}\|p\Z\\{mem\_end};{}$ ${}\|p\PP){}$\1\6 +\&{if} ${}(\R\\{is\_free}[\|p]\W((\|p<\\{was\_hi\_min})\V(\|p>\\{was\_mem\_end})\V\\{was\_free}[\|p])){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{'\ '});\5 +\\{print\_int}(\|p);\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\par +\U167.\fi + +\M{172}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\B\8\#\&{ifdef} \.{DEBUG}\6 +\&{void} \\{search\_mem}(\&{pointer} \|p)\C{look for pointers to \|p}\6 +${}\{{}$\5 +\1\&{int} \|q;\C{current position being searched}\7 +\&{for} ${}(\|q\K\\{mem\_min};{}$ ${}\|q\Z\\{lo\_mem\_max};{}$ ${}\|q\PP){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{link}(\|q)\E\|p){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"LINK("});\5 +\\{print\_int}(\|q);\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{info}(\|q)\E\|p){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"INFO("});\5 +\\{print\_int}(\|q);\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{for} ${}(\|q\K\\{hi\_mem\_min};{}$ ${}\|q\Z\\{mem\_end};{}$ ${}\|q\PP){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{link}(\|q)\E\|p){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"LINK("});\5 +\\{print\_int}(\|q);\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{info}(\|q)\E\|p){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"INFO("});\5 +\\{print\_int}(\|q);\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\X255:Search \\{eqtb} for equivalents equal to \|p\X;\6 +\X285:Search \\{save\_stack} for equivalents that point to \|p\X;\6 +\X933:Search \\{hyph\_list} for pointers to \|p\X;\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\N{1}{173}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{font\_in\_short\_display};\C{an internal font number}\par +\fi + +\M{174}Boxes, rules, inserts, whatsits, marks, and things in general that are +sort of ``complicated'' are indicated only by printing `\.{[]}'. + +\Y\B\&{void} \\{short\_display}(\&{int} \|p)\C{prints highlights of list \|p}\6 +${}\{{}$\5 +\1\&{int} \|n;\C{for replacement counts}\7 +\&{while} ${}(\|p>\\{mem\_min}){}$\5 +${}\{{}$\5 +\1\&{if} (\\{is\_char\_node}(\|p))\5 +${}\{{}$\5 +\1\&{if} ${}(\|p\Z\\{mem\_end}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{font}(\|p)\I\\{font\_in\_short\_display}){}$\5 +${}\{{}$\5 +\1\&{if} ${}((\\{font}(\|p)<\\{font\_base})\V(\\{font}(\|p)>\\{font\_max})){}$\1\5 +\\{print\_char}(\.{'*'});\2\6 +\&{else}\1\5 +\X267:Print the font identifier for \\{font}(\|p)\X;\2\6 +\\{print\_char}(\.{'\ '});\5 +${}\\{font\_in\_short\_display}\K\\{font}(\|p);{}$\6 +\4${}\}{}$\2\6 +\\{print\_ASCII}(\\{qo}(\\{character}(\|p)));\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\X175:Print a short indication of the contents of node \|p\X;\2\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{175}\B\X175:Print a short indication of the contents of node \|p\X${}\E{}$\6 +\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{ins\_node}:\5 +\&{case} \\{whatsit\_node}:\5 +\&{case} \\{mark\_node}:\5 +\&{case} \\{adjust\_node}:\5 +\&{case} \\{unset\_node}:\5 +\\{print\_str}(\.{"[]"});\5 +\&{break};\6 +\4\&{case} \\{rule\_node}:\5 +\\{print\_char}(\.{'|'});\5 +\&{break};\6 +\4\&{case} \\{glue\_node}:\6 +\&{if} ${}(\\{glue\_ptr}(\|p)\I\\{zero\_glue}){}$\1\5 +\\{print\_char}(\.{'\ '});\5 +\2\&{break};\6 +\4\&{case} \\{math\_node}:\5 +\\{print\_char}(\.{'\$'});\5 +\&{break};\6 +\4\&{case} \\{ligature\_node}:\5 +\\{short\_display}(\\{lig\_ptr}(\|p));\5 +\&{break};\6 +\4\&{case} \\{disc\_node}:\6 +${}\{{}$\5 +\1\\{short\_display}(\\{pre\_break}(\|p));\5 +\\{short\_display}(\\{post\_break}(\|p));\6 +${}\|n\K\\{replace\_count}(\|p);{}$\6 +\&{while} ${}(\|n>\T{0}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{link}(\|p)\I\\{null}){}$\1\5 +${}\|p\K\\{link}(\|p);{}$\2\6 +\\{decr}(\|n);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\par +\U174.\fi + +\M{176}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\B\&{void} \\{print\_font\_and\_char}(\&{int} \|p)\C{prints \\{char\_node} data}\6 +${}\{{}$\5 +\1\&{if} ${}(\|p>\\{mem\_end}){}$\1\5 +\\{print\_esc}(\X1386:\.{"CLOBBERED."}\X);\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}((\\{font}(\|p)<\\{font\_base})\V(\\{font}(\|p)>\\{font\_max})){}$\1\5 +\\{print\_char}(\.{'*'});\2\6 +\&{else}\1\5 +\X267:Print the font identifier for \\{font}(\|p)\X;\2\6 +\\{print\_char}(\.{'\ '});\5 +\\{print\_ASCII}(\\{qo}(\\{character}(\|p)));\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\7 +\&{void} \\{print\_mark}(\&{int} \|p)\C{prints token list data in braces}\6 +${}\{{}$\5 +\1\\{print\_char}(\.{'\{'});\6 +\&{if} ${}((\|p<\\{hi\_mem\_min})\V(\|p>\\{mem\_end})){}$\1\5 +\\{print\_esc}(\X1386:\.{"CLOBBERED."}\X);\2\6 +\&{else}\1\5 +${}\\{show\_token\_list}(\\{link}(\|p),\39\\{null},\39\\{max\_print\_line}-\T{10});{}$\2\6 +\\{print\_char}(\.{'\}'});\6 +\4${}\}{}$\2\7 +\&{void} \\{print\_rule\_dimen}(\&{scaled} \|d)\C{prints dimension in rule node}\6 +${}\{{}$\5 +\1\&{if} (\\{is\_running}(\|d))\1\5 +\\{print\_char}(\.{'*'});\2\6 +\&{else}\1\5 +\\{print\_scaled}(\|d);\2\6 +\4${}\}{}$\2\par +\fi + +\M{177}Then there is a subroutine that prints glue stretch and shrink, possibly +followed by the name of finite units: + +\Y\B\&{void} \\{print\_glue}(\&{scaled} \|d${},\39{}$\&{int} \\{order}${},\39{}$\&{str\_number} \|s)\C{prints a glue component}\6 +${}\{{}$\5 +\1\\{print\_scaled}(\|d);\6 +\&{if} ${}((\\{order}<\\{normal})\V(\\{order}>\\{filll})){}$\1\5 +\\{print\_str}(\.{"foul"});\2\6 +\&{else} \&{if} ${}(\\{order}>\\{normal}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"fil"});\6 +\&{while} ${}(\\{order}>\\{fil}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{'l'});\5 +\\{decr}(\\{order});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|s\I\T{0}){}$\1\5 +\\{print}(\|s);\2\6 +\4${}\}{}$\2\par +\fi + +\M{178}The next subroutine prints a whole glue specification. + +\Y\B\&{void} \\{print\_spec}(\&{int} \|p${},\39{}$\&{str\_number} \|s)\C{prints a glue specification}\6 +${}\{{}$\5 +\1\&{if} ${}((\|p<\\{mem\_min})\V(\|p\G\\{lo\_mem\_max})){}$\1\5 +\\{print\_char}(\.{'*'});\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_scaled}(\\{width}(\|p));\6 +\&{if} ${}(\|s\I\T{0}){}$\1\5 +\\{print}(\|s);\2\6 +\&{if} ${}(\\{stretch}(\|p)\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ plus\ "});\5 +${}\\{print\_glue}(\\{stretch}(\|p),\39\\{stretch\_order}(\|p),\39\|s);{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{shrink}(\|p)\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ minus\ "});\5 +${}\\{print\_glue}(\\{shrink}(\|p),\39\\{shrink\_order}(\|p),\39\|s);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{179}We also need to declare some procedures that appear later in this +documentation. + +\Y\B\X691:Declare procedures needed for displaying the elements of mlists\X\6 +\X225:Declare the procedure called \\{print\_skip\_param}\X\par +\fi + +\M{180}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\B\4\D$\\{node\_list\_display}(\|X)$ \6 +${}\{{}$\5 +\1\\{append\_char}(\.{'.'});\5 +\\{show\_node\_list}(\|X);\5 +\\{flush\_char};\6 +\4${}\}{}$\C{\\{str\_room} need not be checked; see \\{show\_box} below}\2\par +\fi + +\M{181}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}\E\T{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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{depth\_threshold};\C{maximum nesting depth in box displays}\6 +\&{int} \\{breadth\_max};\C{maximum number of items shown at the same list level}\par +\fi + +\M{182}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\B\&{void} \\{show\_node\_list}(\&{int} \|p)\C{prints a node list symbolically}\6 +${}\{{}$\5 +\1\&{int} \|n;\C{the number of items already printed at this level}\6 +\&{double} \|g;\C{a glue ratio, as a floating point number}\7 +\&{if} ${}(\\{cur\_length}>\\{depth\_threshold}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|p>\\{null}){}$\1\5 +\\{print\_str}(\.{"\ []"});\C{indicate that there's been some truncation}\2\6 +\&{return};\6 +\4${}\}{}$\2\6 +${}\|n\K\T{0};{}$\6 +\&{while} ${}(\|p>\\{mem\_min}){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\\{print\_current\_string}(\,);\C{display the nesting history}\6 +\&{if} ${}(\|p>\\{mem\_end}{}$)\C{pointer out of range}\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"Bad\ link,\ display\ a}\)\.{borted."});\5 +\&{return};\6 +\4${}\}{}$\2\6 +\\{incr}(\|n);\6 +\&{if} ${}(\|n>\\{breadth\_max}{}$)\C{time to stop}\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"etc."});\5 +\&{return};\6 +\4${}\}{}$\2\6 +\X183:Display node \|p\X;\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{183}\B\X183:Display node \|p\X${}\E{}$\6 +\&{if} (\\{is\_char\_node}(\|p))\1\5 +\\{print\_font\_and\_char}(\|p);\2\6 +\&{else}\1\6 +\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{unset\_node}:\5 +\X184:Display box \|p\X\5 +\&{break};\6 +\4\&{case} \\{rule\_node}:\5 +\X187:Display rule \|p\X\5 +\&{break};\6 +\4\&{case} \\{ins\_node}:\5 +\X188:Display insertion \|p\X\5 +\&{break};\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1356:Display the whatsit node \|p\X\5 +\&{break};\6 +\4\&{case} \\{glue\_node}:\5 +\X189:Display glue \|p\X\5 +\&{break};\6 +\4\&{case} \\{kern\_node}:\5 +\X191:Display kern \|p\X\5 +\&{break};\6 +\4\&{case} \\{math\_node}:\5 +\X192:Display math node \|p\X\5 +\&{break};\6 +\4\&{case} \\{ligature\_node}:\5 +\X193:Display ligature \|p\X\5 +\&{break};\6 +\4\&{case} \\{penalty\_node}:\5 +\X194:Display penalty \|p\X\5 +\&{break};\6 +\4\&{case} \\{disc\_node}:\5 +\X195:Display discretionary \|p\X\5 +\&{break};\6 +\4\&{case} \\{mark\_node}:\5 +\X196:Display mark \|p\X\5 +\&{break};\6 +\4\&{case} \\{adjust\_node}:\5 +\X197:Display adjustment \|p\X\5 +\&{break};\5 +\hbox{\4}\X690:Cases of \\{show\_node\_list} that arise in mlists only\X\6 +\4\&{default}:\5 +\\{print\_str}(\.{"Unknown\ node\ type!"});\6 +\4${}\}{}$\2\2\par +\U182.\fi + +\M{184}\B\X184:Display box \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{type}(\|p)\E\\{hlist\_node}){}$\1\5 +\\{print\_esc}(\.{'h'});\2\6 +\&{else} \&{if} ${}(\\{type}(\|p)\E\\{vlist\_node}){}$\1\5 +\\{print\_esc}(\.{'v'});\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1388:\.{"unset"}\X);\2\6 +\\{print\_str}(\.{"box("});\5 +\\{print\_scaled}(\\{height}(\|p));\5 +\\{print\_char}(\.{'+'});\5 +\\{print\_scaled}(\\{depth}(\|p));\5 +\\{print\_str}(\.{")x"});\5 +\\{print\_scaled}(\\{width}(\|p));\6 +\&{if} ${}(\\{type}(\|p)\E\\{unset\_node}){}$\1\5 +\X185:Display special fields of the unset node \|p\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\X186:Display the value of \\{glue\_set}(\|p)\X;\6 +\&{if} ${}(\\{shift\_amount}(\|p)\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{",\ shifted\ "});\5 +\\{print\_scaled}(\\{shift\_amount}(\|p));\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\\{node\_list\_display}(\\{list\_ptr}(\|p));\C{recursive call}\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{185}\B\X185:Display special fields of the unset node \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{span\_count}(\|p)\I\\{min\_quarterword}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ ("});\5 +${}\\{print\_int}(\\{qo}(\\{span\_count}(\|p))+\T{1});{}$\5 +\\{print\_str}(\.{"\ columns)"});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{glue\_stretch}(\|p)\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{",\ stretch\ "});\5 +${}\\{print\_glue}(\\{glue\_stretch}(\|p),\39\\{glue\_order}(\|p),\39\T{0});{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{glue\_shrink}(\|p)\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{",\ shrink\ "});\5 +${}\\{print\_glue}(\\{glue\_shrink}(\|p),\39\\{glue\_sign}(\|p),\39\T{0});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U184.\fi + +\M{186}The code will have to change in this place if \&{glue\_ratio} is +a structured type instead of an ordinary \&{double}. 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 \&{double} 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\B\4\X186:Display the value of \\{glue\_set}(\|p)\X${}\E{}$\6 +$\|g\K\&{float}(\\{glue\_set}(\|p));{}$\6 +\&{if} ${}((\|g\I\\{float\_constant}(\T{0}))\W(\\{glue\_sign}(\|p)\I\\{normal})){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{",\ glue\ set\ "});\6 +\&{if} ${}(\\{glue\_sign}(\|p)\E\\{shrinking}){}$\1\5 +\\{print\_str}(\.{"-\ "});\2\6 +\&{if} ${}(\\{abs}(\\{mem}[\|p+\\{glue\_offset}].\|i)<\T{\~4000000}){}$\1\5 +\\{print\_str}(\.{"?.?"});\2\6 +\&{else} \&{if} ${}(\\{abs}(\|g)>\\{float\_constant}(\T{20000})){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|g>\\{float\_constant}(\T{0})){}$\1\5 +\\{print\_char}(\.{'>'});\2\6 +\&{else}\1\5 +\\{print\_str}(\.{"<\ -"});\2\6 +${}\\{print\_glue}(\T{20000}*\\{unity},\39\\{glue\_order}(\|p),\39\T{0});{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{print\_glue}(\\{round}(\\{unity}*\|g),\39\\{glue\_order}(\|p),\39\T{0});{}$\2\6 +\4${}\}{}$\2\par +\U184.\fi + +\M{187}\B\X187:Display rule \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1389:\.{"rule("}\X);\5 +\\{print\_rule\_dimen}(\\{height}(\|p));\5 +\\{print\_char}(\.{'+'});\5 +\\{print\_rule\_dimen}(\\{depth}(\|p));\5 +\\{print\_str}(\.{")x"});\5 +\\{print\_rule\_dimen}(\\{width}(\|p));\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{188}\B\X188:Display insertion \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1390:\.{"insert"}\X);\5 +\\{print\_int}(\\{qo}(\\{subtype}(\|p)));\5 +\\{print\_str}(\.{",\ natural\ size\ "});\5 +\\{print\_scaled}(\\{height}(\|p));\5 +\\{print\_str}(\.{";\ split("});\5 +${}\\{print\_spec}(\\{split\_top\_ptr}(\|p),\39\T{0});{}$\5 +\\{print\_char}(\.{','});\5 +\\{print\_scaled}(\\{depth}(\|p));\5 +\\{print\_str}(\.{");\ float\ cost\ "});\5 +\\{print\_int}(\\{float\_cost}(\|p));\5 +\\{node\_list\_display}(\\{ins\_ptr}(\|p));\C{recursive call}\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{189}\B\X189:Display glue \|p\X${}\E{}$\6 +\&{if} ${}(\\{subtype}(\|p)\G\\{a\_leaders}){}$\1\5 +\X190:Display leaders \|p\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1391:\.{"glue"}\X);\6 +\&{if} ${}(\\{subtype}(\|p)\I\\{normal}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{'('});\6 +\&{if} ${}(\\{subtype}(\|p)<\\{cond\_math\_glue}){}$\1\5 +${}\\{print\_skip\_param}(\\{subtype}(\|p)-\T{1});{}$\2\6 +\&{else} \&{if} ${}(\\{subtype}(\|p)\E\\{cond\_math\_glue}){}$\1\5 +\\{print\_esc}(\X1392:\.{"nonscript"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1393:\.{"mskip"}\X);\2\6 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{subtype}(\|p)\I\\{cond\_math\_glue}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{'\ '});\6 +\&{if} ${}(\\{subtype}(\|p)<\\{cond\_math\_glue}){}$\1\5 +${}\\{print\_spec}(\\{glue\_ptr}(\|p),\39\T{0});{}$\2\6 +\&{else}\1\5 +${}\\{print\_spec}(\\{glue\_ptr}(\|p),\39\X1394:\.{"mu"}\X);{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{190}\B\X190:Display leaders \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\\{empty\_string});\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{c\_leaders}){}$\1\5 +\\{print\_char}(\.{'c'});\2\6 +\&{else} \&{if} ${}(\\{subtype}(\|p)\E\\{x\_leaders}){}$\1\5 +\\{print\_char}(\.{'x'});\2\6 +\\{print\_str}(\.{"leaders\ "});\5 +${}\\{print\_spec}(\\{glue\_ptr}(\|p),\39\T{0});{}$\5 +\\{node\_list\_display}(\\{leader\_ptr}(\|p));\C{recursive call}\6 +\4${}\}{}$\2\par +\U189.\fi + +\M{191}An ``explicit'' kern value is indicated implicitly by an explicit space. + +\Y\B\4\X191:Display kern \|p\X${}\E{}$\6 +\&{if} ${}(\\{subtype}(\|p)\I\\{mu\_glue}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1396:\.{"kern"}\X);\6 +\&{if} ${}(\\{subtype}(\|p)\I\\{normal}){}$\1\5 +\\{print\_char}(\.{'\ '});\2\6 +\\{print\_scaled}(\\{width}(\|p));\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{acc\_kern}){}$\1\5 +\\{print\_str}(\.{"\ (for\ accent)"});\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1397:\.{"mkern"}\X);\5 +\\{print\_scaled}(\\{width}(\|p));\5 +\\{print\_str}(\.{"mu"});\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{192}\B\X192:Display math node \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1398:\.{"math"}\X);\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{before}){}$\1\5 +\\{print\_str}(\.{"on"});\2\6 +\&{else}\1\5 +\\{print\_str}(\.{"off"});\2\6 +\&{if} ${}(\\{width}(\|p)\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{",\ surrounded\ "});\5 +\\{print\_scaled}(\\{width}(\|p));\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{193}\B\X193:Display ligature \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_font\_and\_char}(\\{lig\_char}(\|p));\5 +\\{print\_str}(\.{"\ (ligature\ "});\6 +\&{if} ${}(\\{subtype}(\|p)>\T{1}){}$\1\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\5 +\\{print\_char}(\.{'|'});\2\6 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{194}\B\X194:Display penalty \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1399:\.{"penalty\ "}\X);\5 +\\{print\_int}(\\{penalty}(\|p));\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{195}The \\{post\_break} list of a discretionary node is indicated by a prefixed +`\.{\char'174}' instead of the `\..' before the \\{pre\_break} list. + +\Y\B\4\X195:Display discretionary \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1400:\.{"discretionary"}\X);\6 +\&{if} ${}(\\{replace\_count}(\|p)>\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ replacing\ "});\5 +\\{print\_int}(\\{replace\_count}(\|p));\6 +\4${}\}{}$\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 +\4${}\}{}$\2\par +\U183.\fi + +\M{196}\B\X196:Display mark \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1401:\.{"mark"}\X);\5 +\\{print\_mark}(\\{mark\_ptr}(\|p));\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{197}\B\X197:Display adjustment \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1402:\.{"vadjust"}\X);\5 +\\{node\_list\_display}(\\{adjust\_ptr}(\|p));\C{recursive call}\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{198}The recursive machinery is started by calling \\{show\_box}. + +\Y\B\&{void} \\{show\_box}(\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\X236:Assign the values \\{depth\_threshold}: $\K$ \\{show\_box\_depth} and \\{breadth\_max}: $\K$ \\{show\_box\_breadth}\X;\6 +\&{if} ${}(\\{breadth\_max}\Z\T{0}){}$\1\5 +${}\\{breadth\_max}\K\T{5};{}$\2\6 +\&{if} ${}(\\{pool\_ptr}+\\{depth\_threshold}\G\\{pool\_size}){}$\1\5 +${}\\{depth\_threshold}\K\\{pool\_size}-\\{pool\_ptr}-\T{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 +\4${}\}{}$\2\par +\fi + +\N{1}{199}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 + +\M{200}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\B\4\D$\\{token\_ref\_count}(\|X)$ \5 +\\{info}(\|X)\C{reference count preceding a token list}\par +\Y\B\&{void} \\{delete\_token\_ref}(\&{pointer} \|p)\C{\|p points to the reference count of a token list that is losing one reference}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{token\_ref\_count}(\|p)\E\\{null}){}$\1\5 +\\{flush\_list}(\|p);\2\6 +\&{else}\1\5 +\\{decr}(\\{token\_ref\_count}(\|p));\2\6 +\4${}\}{}$\2\par +\fi + +\M{201}Similarly, \\{delete\_glue\_ref} is called when a pointer to a glue +specification is being withdrawn. +\Y\B\4\D$\\{fast\_delete\_glue\_ref}(\|X)$ \5 +\hbox{}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{glue\_ref\_count}(\|X)\E\\{null}){}$\1\5 +${}\\{free\_node}(\|X,\39\\{glue\_spec\_size});{}$\2\6 +\&{else}\1\5 +\\{decr}(\\{glue\_ref\_count}(\|X));\2\6 +\4${}\}{}$\2\par +\Y\B\&{void} \\{delete\_glue\_ref}(\&{pointer} \|p)\C{\|p points to a glue specification}\6 +\\{fast\_delete\_glue\_ref}(\|p)\par +\fi + +\M{202}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\B\&{void} \\{flush\_node\_list}(\&{pointer} \|p)\C{erase list of nodes starting at \|p}\6 +${}\{{}$\5 +\C{go here when node \|p has been freed}\1\6 +\&{pointer} \|q;\C{successor to node \|p}\7 +\&{while} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\|q\K\\{link}(\|p);{}$\6 +\&{if} (\\{is\_char\_node}(\|p))\1\5 +\\{free\_avail}(\|p)\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{unset\_node}:\6 +${}\{{}$\5 +\1\\{flush\_node\_list}(\\{list\_ptr}(\|p));\5 +${}\\{free\_node}(\|p,\39\\{box\_node\_size});{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{rule\_node}:\6 +${}\{{}$\5 +\1${}\\{free\_node}(\|p,\39\\{rule\_node\_size});{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{ins\_node}:\6 +${}\{{}$\5 +\1\\{flush\_node\_list}(\\{ins\_ptr}(\|p));\5 +\\{delete\_glue\_ref}(\\{split\_top\_ptr}(\|p));\5 +${}\\{free\_node}(\|p,\39\\{ins\_node\_size});{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1358:Wipe out the whatsit node \|p and \&{goto} \\{done}\X\6 +\4\&{case} \\{glue\_node}:\6 +${}\{{}$\5 +\1\\{fast\_delete\_glue\_ref}(\\{glue\_ptr}(\|p));\6 +\&{if} ${}(\\{leader\_ptr}(\|p)\I\\{null}){}$\1\5 +\\{flush\_node\_list}(\\{leader\_ptr}(\|p));\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{kern\_node}:\5 +\&{case} \\{math\_node}:\5 +\&{case} \\{penalty\_node}:\5 +\\{do\_nothing};\5 +\&{break};\6 +\4\&{case} \\{ligature\_node}:\5 +\\{flush\_node\_list}(\\{lig\_ptr}(\|p));\5 +\&{break};\6 +\4\&{case} \\{mark\_node}:\5 +\\{delete\_token\_ref}(\\{mark\_ptr}(\|p));\5 +\&{break};\6 +\4\&{case} \\{disc\_node}:\6 +${}\{{}$\5 +\1\\{flush\_node\_list}(\\{pre\_break}(\|p));\5 +\\{flush\_node\_list}(\\{post\_break}(\|p));\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{adjust\_node}:\5 +\\{flush\_node\_list}(\\{adjust\_ptr}(\|p));\5 +\&{break};\5 +\hbox{\4}\X698:Cases of \\{flush\_node\_list} that arise in mlists only\X\6 +\4\&{default}:\5 +\\{confusion}(\X1403:\.{"flushing"}\X);\6 +\4${}\}{}$\2\6 +${}\\{free\_node}(\|p,\39\\{small\_node\_size});{}$\6 +\4\\{done}:\5 +;\6 +\4${}\}{}$\2\6 +${}\|p\K\|q;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\N{1}{203}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\B\4\D$\\{add\_token\_ref}(\|X)$ \5 +\\{incr}(\\{token\_ref\_count}(\|X))\C{new reference to a token list}\par +\B\4\D$\\{add\_glue\_ref}(\|X)$ \5 +\\{incr}(\\{glue\_ref\_count}(\|X))\C{new reference to a glue spec}\par +\fi + +\M{204}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\B\&{pointer} \\{copy\_node\_list}(\&{pointer} \|p)\C{makes a duplicate of the node list that starts at \|p and returns a pointer to the new list}\6 +${}\{{}$\5 +\1\&{pointer} \|h;\C{temporary head of copied list}\6 +\&{pointer} \|q;\C{previous position in new list}\6 +\&{pointer} \|r;\C{current node being fabricated for new list}\6 +\&{uint8\_t} \\{words};\C{number of words remaining to be copied}\7 +${}\|h\K\\{get\_avail}(\,);{}$\5 +${}\|q\K\|h;{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1\X205: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 +\4${}\}{}$\2\6 +${}\\{link}(\|q)\K\\{null};{}$\5 +${}\|q\K\\{link}(\|h);{}$\5 +\\{free\_avail}(\|h);\5 +\&{return} \|q;\6 +\4${}\}{}$\2\par +\fi + +\M{205}\B\X205:Make a copy of node \|p in node \|r\X${}\E{}$\6 +$\\{words}\K\T{1}{}$;\C{this setting occurs in more branches than any other}\6 +\&{if} (\\{is\_char\_node}(\|p))\1\5 +${}\|r\K\\{get\_avail}(\,);{}$\2\6 +\&{else}\1\5 +\X206:Case statement to copy different types and set \\{words} to the number of initial words not yet copied\X;\2\6 +\&{while} ${}(\\{words}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{decr}(\\{words});\5 +${}\\{mem}[\|r+\\{words}]\K\\{mem}[\|p+\\{words}];{}$\6 +\4${}\}{}$\2\par +\U204.\fi + +\M{206}\B\X206:Case statement to copy different types and set \\{words} to the number of initial words not yet copied\X${}\E{}$\6 +\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{unset\_node}:\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_node}(\\{box\_node\_size});{}$\5 +${}\\{mem}[\|r+\T{6}]\K\\{mem}[\|p+\T{6}];{}$\5 +${}\\{mem}[\|r+\T{5}]\K\\{mem}[\|p+\T{5}]{}$;\C{copy the last two words}\6 +${}\\{list\_ptr}(\|r)\K\\{copy\_node\_list}(\\{list\_ptr}(\|p)){}$;\C{this affects $\\{mem}[\|r+\T{5}]$}\6 +${}\\{words}\K\T{5};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{rule\_node}:\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_node}(\\{rule\_node\_size});{}$\5 +${}\\{words}\K\\{rule\_node\_size};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{ins\_node}:\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_node}(\\{ins\_node\_size});{}$\5 +${}\\{mem}[\|r+\T{4}]\K\\{mem}[\|p+\T{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+\T{4}]$}\6 +${}\\{words}\K\\{ins\_node\_size}-\T{1};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1357: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\5 +\&{break};\6 +\4\&{case} \\{glue\_node}:\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{kern\_node}:\5 +\&{case} \\{math\_node}:\5 +\&{case} \\{penalty\_node}:\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{words}\K\\{small\_node\_size};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{ligature\_node}:\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{disc\_node}:\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{mark\_node}:\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_node}(\\{small\_node\_size});{}$\5 +\\{add\_token\_ref}(\\{mark\_ptr}(\|p));\5 +${}\\{words}\K\\{small\_node\_size};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{adjust\_node}:\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{adjust\_ptr}(\|r)\K\\{copy\_node\_list}(\\{adjust\_ptr}(\|p));{}$\6 +\4${}\}{}$\5 +\2\&{break};\C{$\\{words}\E\T{1}\E\\{small\_node\_size}-\T{1}$}\6 +\4\&{default}:\5 +\\{confusion}(\X1404:\.{"copying"}\X);\6 +\4${}\}{}$\2\par +\U205.\fi + +\N{1}{207}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\B\4\D$\\{escape}$ \5 +\T{0}\C{escape delimiter (called \.\\ in {\sl The \TeX book\/})}\par +\B\4\D$\\{relax}$ \5 +\T{0}\C{do nothing ( \.{\\relax} )}\par +\B\4\D$\\{left\_brace}$ \5 +\T{1}\C{beginning of a group ( \.\{ )}\par +\B\4\D$\\{right\_brace}$ \5 +\T{2}\C{ending of a group ( \.\} )}\par +\B\4\D$\\{math\_shift}$ \5 +\T{3}\C{mathematics shift character ( \.\$ )}\par +\B\4\D$\\{tab\_mark}$ \5 +\T{4}\C{alignment delimiter ( \.\&, \.{\\span} )}\par +\B\4\D$\\{car\_ret}$ \5 +\T{5}\C{end of line ( \\{carriage\_return}, \.{\\cr}, \.{\\crcr} )}\par +\B\4\D$\\{out\_param}$ \5 +\T{5}\C{output a macro parameter}\par +\B\4\D$\\{mac\_param}$ \5 +\T{6}\C{macro parameter symbol ( \.\# )}\par +\B\4\D$\\{sup\_mark}$ \5 +\T{7}\C{superscript ( \.{\char'136} )}\par +\B\4\D$\\{sub\_mark}$ \5 +\T{8}\C{subscript ( \.{\char'137} )}\par +\B\4\D$\\{ignore}$ \5 +\T{9}\C{characters to ignore ( \.{\^\^@} )}\par +\B\4\D$\\{endv}$ \5 +\T{9}\C{end of \<v_j> list in alignment template}\par +\B\4\D$\\{spacer}$ \5 +\T{10}\C{characters equivalent to blank space ( \.{\ } )}\par +\B\4\D$\\{letter}$ \5 +\T{11}\C{characters regarded as letters ( \.{A..Z}, \.{a..z} )}\par +\B\4\D$\\{other\_char}$ \5 +\T{12}\C{none of the special character types}\par +\B\4\D$\\{active\_char}$ \5 +\T{13}\C{characters that invoke macros ( \.{\char`\~} )}\par +\B\4\D$\\{par\_end}$ \5 +\T{13}\C{end of paragraph ( \.{\\par} )}\par +\B\4\D$\\{match}$ \5 +\T{13}\C{match a macro parameter}\par +\B\4\D$\\{comment}$ \5 +\T{14}\C{characters that introduce comments ( \.\% )}\par +\B\4\D$\\{end\_match}$ \5 +\T{14}\C{end of parameters to macro}\par +\B\4\D$\\{stop}$ \5 +\T{14}\C{end of job ( \.{\\end}, \.{\\dump} )}\par +\B\4\D$\\{invalid\_char}$ \5 +\T{15}\C{characters that shouldn't appear ( \.{\^\^?} )}\par +\B\4\D$\\{delim\_num}$ \5 +\T{15}\C{specify delimiter numerically ( \.{\\delimiter} )}\par +\B\4\D$\\{max\_char\_code}$ \5 +\T{15}\C{largest catcode for individual characters}\par +\fi + +\M{208}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\B\4\D$\\{char\_num}$ \5 +\T{16}\C{character specified numerically ( \.{\\char} )}\par +\B\4\D$\\{math\_char\_num}$ \5 +\T{17}\C{explicit math code ( \.{\\mathchar} )}\par +\B\4\D$\\{mark}$ \5 +\T{18}\C{mark definition ( \.{\\mark} )}\par +\B\4\D$\\{xray}$ \5 +\T{19}\C{peek inside of \TeX\ ( \.{\\show}, \.{\\showbox}, etc.~)}\par +\B\4\D$\\{make\_box}$ \5 +\T{20}\C{make a box ( \.{\\box}, \.{\\copy}, \.{\\hbox}, etc.~)}\par +\B\4\D$\\{hmove}$ \5 +\T{21}\C{horizontal motion ( \.{\\moveleft}, \.{\\moveright} )}\par +\B\4\D$\\{vmove}$ \5 +\T{22}\C{vertical motion ( \.{\\raise}, \.{\\lower} )}\par +\B\4\D$\\{un\_hbox}$ \5 +\T{23}\C{unglue a box ( \.{\\unhbox}, \.{\\unhcopy} )}\par +\B\4\D$\\{un\_vbox}$ \5 +\T{24}\C{unglue a box ( \.{\\unvbox}, \.{\\unvcopy} )}\par +\B\4\D$\\{remove\_item}$ \5 +\T{25}\C{nullify last item ( \.{\\unpenalty}, \.{\\unkern}, \.{\\unskip} )}\par +\B\4\D$\\{hskip}$ \5 +\T{26}\C{horizontal glue ( \.{\\hskip}, \.{\\hfil}, etc.~)}\par +\B\4\D$\\{vskip}$ \5 +\T{27}\C{vertical glue ( \.{\\vskip}, \.{\\vfil}, etc.~)}\par +\B\4\D$\\{mskip}$ \5 +\T{28}\C{math glue ( \.{\\mskip} )}\par +\B\4\D$\\{kern}$ \5 +\T{29}\C{fixed space ( \.{\\kern})}\par +\B\4\D$\\{mkern}$ \5 +\T{30}\C{math kern ( \.{\\mkern} )}\par +\B\4\D$\\{leader\_ship}$ \5 +\T{31}\C{use a box ( \.{\\shipout}, \.{\\leaders}, etc.~)}\par +\B\4\D$\\{halign}$ \5 +\T{32}\C{horizontal table alignment ( \.{\\halign} )}\par +\B\4\D$\\{valign}$ \5 +\T{33}\C{vertical table alignment ( \.{\\valign} )}\par +\B\4\D$\\{no\_align}$ \5 +\T{34}\C{temporary escape from alignment ( \.{\\noalign} )}\par +\B\4\D$\\{vrule}$ \5 +\T{35}\C{vertical rule ( \.{\\vrule} )}\par +\B\4\D$\\{hrule}$ \5 +\T{36}\C{horizontal rule ( \.{\\hrule} )}\par +\B\4\D$\\{insert}$ \5 +\T{37}\C{vlist inserted in box ( \.{\\insert} )}\par +\B\4\D$\\{vadjust}$ \5 +\T{38}\C{vlist inserted in enclosing paragraph ( \.{\\vadjust} )}\par +\B\4\D$\\{ignore\_spaces}$ \5 +\T{39}\C{gobble \\{spacer} tokens ( \.{\\ignorespaces} )}\par +\B\4\D$\\{after\_assignment}$ \5 +\T{40}\C{save till assignment is done ( \.{\\afterassignment} )}\par +\B\4\D$\\{after\_group}$ \5 +\T{41}\C{save till group is done ( \.{\\aftergroup} )}\par +\B\4\D$\\{break\_penalty}$ \5 +\T{42}\C{additional badness ( \.{\\penalty} )}\par +\B\4\D$\\{start\_par}$ \5 +\T{43}\C{begin paragraph ( \.{\\indent}, \.{\\noindent} )}\par +\B\4\D$\\{ital\_corr}$ \5 +\T{44}\C{italic correction ( \.{\\/} )}\par +\B\4\D$\\{accent}$ \5 +\T{45}\C{attach accent in text ( \.{\\accent} )}\par +\B\4\D$\\{math\_accent}$ \5 +\T{46}\C{attach accent in math ( \.{\\mathaccent} )}\par +\B\4\D$\\{discretionary}$ \5 +\T{47}\C{discretionary texts ( \.{\\-}, \.{\\discretionary} )}\par +\B\4\D$\\{eq\_no}$ \5 +\T{48}\C{equation number ( \.{\\eqno}, \.{\\leqno} )}\par +\B\4\D$\\{left\_right}$ \5 +\T{49}\C{variable delimiter ( \.{\\left}, \.{\\right} )}\par +\B\4\D$\\{math\_comp}$ \5 +\T{50}\C{component of formula ( \.{\\mathbin}, etc.~)}\par +\B\4\D$\\{limit\_switch}$ \5 +\T{51}\C{diddle limit conventions ( \.{\\displaylimits}, etc.~)}\par +\B\4\D$\\{above}$ \5 +\T{52}\C{generalized fraction ( \.{\\above}, \.{\\atop}, etc.~)}\par +\B\4\D$\\{math\_style}$ \5 +\T{53}\C{style specification ( \.{\\displaystyle}, etc.~)}\par +\B\4\D$\\{math\_choice}$ \5 +\T{54}\C{choice specification ( \.{\\mathchoice} )}\par +\B\4\D$\\{non\_script}$ \5 +\T{55}\C{conditional math glue ( \.{\\nonscript} )}\par +\B\4\D$\\{vcenter}$ \5 +\T{56}\C{vertically center a vbox ( \.{\\vcenter} )}\par +\B\4\D$\\{case\_shift}$ \5 +\T{57}\C{force specific case ( \.{\\lowercase}, \.{\\uppercase}~)}\par +\B\4\D$\\{message}$ \5 +\T{58}\C{send to user ( \.{\\message}, \.{\\errmessage} )}\par +\B\4\D$\\{extension}$ \5 +\T{59}\C{extensions to \TeX\ ( \.{\\write}, \.{\\special}, etc.~)}\par +\B\4\D$\\{in\_stream}$ \5 +\T{60}\C{files for reading ( \.{\\openin}, \.{\\closein} )}\par +\B\4\D$\\{begin\_group}$ \5 +\T{61}\C{begin local grouping ( \.{\\begingroup} )}\par +\B\4\D$\\{end\_group}$ \5 +\T{62}\C{end local grouping ( \.{\\endgroup} )}\par +\B\4\D$\\{omit}$ \5 +\T{63}\C{omit alignment template ( \.{\\omit} )}\par +\B\4\D$\\{ex\_space}$ \5 +\T{64}\C{explicit space ( \.{\\\ } )}\par +\B\4\D$\\{no\_boundary}$ \5 +\T{65}\C{suppress boundary ligatures ( \.{\\noboundary} )}\par +\B\4\D$\\{radical}$ \5 +\T{66}\C{square root and similar signs ( \.{\\radical} )}\par +\B\4\D$\\{end\_cs\_name}$ \5 +\T{67}\C{end control sequence ( \.{\\endcsname} )}\par +\B\4\D$\\{min\_internal}$ \5 +\T{68}\C{the smallest code that can follow \.{\\the}}\par +\B\4\D$\\{char\_given}$ \5 +\T{68}\C{character code defined by \.{\\chardef}}\par +\B\4\D$\\{math\_given}$ \5 +\T{69}\C{math code defined by \.{\\mathchardef}}\par +\B\4\D$\\{last\_item}$ \5 +\T{70}\C{most recent item ( \.{\\lastpenalty}, \.{\\lastkern}, \.{\\lastskip} )}\par +\B\4\D$\\{max\_non\_prefixed\_command}$ \5 +\T{70}\C{largest command code that can't be \.{\\global}}\par +\fi + +\M{209}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\B\4\D$\\{toks\_register}$ \5 +\T{71}\C{token list register ( \.{\\toks} )}\par +\B\4\D$\\{assign\_toks}$ \5 +\T{72}\C{special token list ( \.{\\output}, \.{\\everypar}, etc.~)}\par +\B\4\D$\\{assign\_int}$ \5 +\T{73}\C{user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)}\par +\B\4\D$\\{assign\_dimen}$ \5 +\T{74}\C{user-defined length ( \.{\\hsize}, etc.~)}\par +\B\4\D$\\{assign\_glue}$ \5 +\T{75}\C{user-defined glue ( \.{\\baselineskip}, etc.~)}\par +\B\4\D$\\{assign\_mu\_glue}$ \5 +\T{76}\C{user-defined muglue ( \.{\\thinmuskip}, etc.~)}\par +\B\4\D$\\{assign\_font\_dimen}$ \5 +\T{77}\C{user-defined font dimension ( \.{\\fontdimen} )}\par +\B\4\D$\\{assign\_font\_int}$ \5 +\T{78}\C{user-defined font integer ( \.{\\hyphenchar}, \.{\\skewchar} )}\par +\B\4\D$\\{set\_aux}$ \5 +\T{79}\C{specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )}\par +\B\4\D$\\{set\_prev\_graf}$ \5 +\T{80}\C{specify state info ( \.{\\prevgraf} )}\par +\B\4\D$\\{set\_page\_dimen}$ \5 +\T{81}\C{specify state info ( \.{\\pagegoal}, etc.~)}\par +\B\4\D$\\{set\_page\_int}$ \5 +\T{82}\C{specify state info ( \.{\\deadcycles}, \.{\\insertpenalties} )}\par +\B\4\D$\\{set\_box\_dimen}$ \5 +\T{83}\C{change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )}\par +\B\4\D$\\{set\_shape}$ \5 +\T{84}\C{specify fancy paragraph shape ( \.{\\parshape} )}\par +\B\4\D$\\{def\_code}$ \5 +\T{85}\C{define a character code ( \.{\\catcode}, etc.~)}\par +\B\4\D$\\{def\_family}$ \5 +\T{86}\C{declare math fonts ( \.{\\textfont}, etc.~)}\par +\B\4\D$\\{set\_font}$ \5 +\T{87}\C{set current font ( font identifiers )}\par +\B\4\D$\\{def\_font}$ \5 +\T{88}\C{define a font file ( \.{\\font} )}\par +\B\4\D$\&{register}$ \5 +\T{89}\C{internal register ( \.{\\count}, \.{\\dimen}, etc.~)}\par +\B\4\D$\\{max\_internal}$ \5 +\T{89}\C{the largest code that can follow \.{\\the}}\par +\B\4\D$\\{advance}$ \5 +\T{90}\C{advance a register or parameter ( \.{\\advance} )}\par +\B\4\D$\\{multiply}$ \5 +\T{91}\C{multiply a register or parameter ( \.{\\multiply} )}\par +\B\4\D$\\{divide}$ \5 +\T{92}\C{divide a register or parameter ( \.{\\divide} )}\par +\B\4\D$\\{prefix}$ \5 +\T{93}\C{qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}\par +\B\4\D$\\{let}$ \5 +\T{94}\C{assign a command code ( \.{\\let}, \.{\\futurelet} )}\par +\B\4\D$\\{shorthand\_def}$ \5 +\T{95}\C{code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}\par +\B\4\D$\\{read\_to\_cs}$ \5 +\T{96}\C{read into a control sequence ( \.{\\read} )}\par +\B\4\D$\\{def}$ \5 +\T{97}\C{macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}\par +\B\4\D$\\{set\_box}$ \5 +\T{98}\C{set a box ( \.{\\setbox} )}\par +\B\4\D$\\{hyph\_data}$ \5 +\T{99}\C{hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}\par +\B\4\D$\\{set\_interaction}$ \5 +\T{100}\C{define level of interaction ( \.{\\batchmode}, etc.~)}\par +\B\4\D$\\{max\_command}$ \5 +\T{100}\C{the largest command code seen at \\{big\_switch}}\par +\fi + +\M{210}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\B\4\D$\\{undefined\_cs}$ \5 +$(\\{max\_command}+\T{1}{}$)\C{initial state of most \\{eq\_type} fields}\par +\B\4\D$\\{expand\_after}$ \5 +$(\\{max\_command}+\T{2}{}$)\C{special expansion ( \.{\\expandafter} )}\par +\B\4\D$\\{no\_expand}$ \5 +$(\\{max\_command}+\T{3}{}$)\C{special nonexpansion ( \.{\\noexpand} )}\par +\B\4\D$\\{input}$ \5 +$(\\{max\_command}+\T{4}{}$)\C{input a source file ( \.{\\input}, \.{\\endinput} )}\par +\B\4\D$\\{if\_test}$ \5 +$(\\{max\_command}+\T{5}{}$)\C{conditional text ( \.{\\if}, \.{\\ifcase}, etc.~)}\par +\B\4\D$\\{fi\_or\_else}$ \5 +$(\\{max\_command}+\T{6}{}$)\C{delimiters for conditionals ( \.{\\else}, etc.~)}\par +\B\4\D$\\{cs\_name}$ \5 +$(\\{max\_command}+\T{7}{}$)\C{make a control sequence from tokens ( \.{\\csname} )}\par +\B\4\D$\\{convert}$ \5 +$(\\{max\_command}+\T{8}{}$)\C{convert to text ( \.{\\number}, \.{\\string}, etc.~)}\par +\B\4\D$\\{the}$ \5 +$(\\{max\_command}+\T{9}{}$)\C{expand an internal quantity ( \.{\\the} )}\par +\B\4\D$\\{top\_bot\_mark}$ \5 +$(\\{max\_command}+\T{10}{}$)\C{inserted mark ( \.{\\topmark}, etc.~)}\par +\B\4\D$\\{call}$ \5 +$(\\{max\_command}+\T{11}{}$)\C{non-long, non-outer control sequence}\par +\B\4\D$\\{long\_call}$ \5 +$(\\{max\_command}+\T{12}{}$)\C{long, non-outer control sequence}\par +\B\4\D$\\{outer\_call}$ \5 +$(\\{max\_command}+\T{13}{}$)\C{non-long, outer control sequence}\par +\B\4\D$\\{long\_outer\_call}$ \5 +$(\\{max\_command}+\T{14}{}$)\C{long, outer control sequence}\par +\B\4\D$\\{end\_template}$ \5 +$(\\{max\_command}+\T{15}{}$)\C{end of an alignment template}\par +\B\4\D$\\{dont\_expand}$ \5 +$(\\{max\_command}+\T{16}{}$)\C{the following token was marked by \.{\\noexpand}}\par +\B\4\D$\\{glue\_ref}$ \5 +$(\\{max\_command}+\T{17}{}$)\C{the equivalent points to a glue specification}\par +\B\4\D$\\{shape\_ref}$ \5 +$(\\{max\_command}+\T{18}{}$)\C{the equivalent points to a parshape specification}\par +\B\4\D$\\{box\_ref}$ \5 +$(\\{max\_command}+\T{19}{}$)\C{the equivalent points to a box node, or is \\{null}}\par +\B\4\D$\\{data}$ \5 +$(\\{max\_command}+\T{20}{}$)\C{the equivalent is simply a halfword number}\par +\fi + +\N{1}{211}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\B\4\D$\\{vmode}$ \5 +\T{1}\C{vertical mode}\par +\B\4\D$\\{hmode}$ \5 +$(\\{vmode}+\\{max\_command}+\T{1}{}$)\C{horizontal mode}\par +\B\4\D$\\{mmode}$ \5 +$(\\{hmode}+\\{max\_command}+\T{1}{}$)\C{math mode}\par +\Y\B\&{void} \\{print\_mode}(\&{int} \|m)\C{prints the mode represented by \|m}\6 +${}\{{}$\5 +\1\&{if} ${}(\|m>\T{0}){}$\1\6 +\&{switch} ${}(\|m/(\\{max\_command}+\T{1})){}$\5 +${}\{{}$\1\6 +\4\&{case} \T{0}:\5 +\\{print\_str}(\.{"vertical"});\5 +\&{break};\6 +\4\&{case} \T{1}:\5 +\\{print\_str}(\.{"horizontal"});\5 +\&{break};\6 +\4\&{case} \T{2}:\5 +\\{print\_str}(\.{"display\ math"});\6 +\4${}\}{}$\2\2\6 +\&{else} \&{if} ${}(\|m\E\T{0}){}$\1\5 +\\{print\_str}(\.{"no"});\2\6 +\&{else}\1\6 +\&{switch} ${}(({-}\|m)/(\\{max\_command}+\T{1})){}$\5 +${}\{{}$\1\6 +\4\&{case} \T{0}:\5 +\\{print\_str}(\.{"internal\ vertical"});\5 +\&{break};\6 +\4\&{case} \T{1}:\5 +\\{print\_str}(\.{"restricted\ horizont}\)\.{al"});\5 +\&{break};\6 +\4\&{case} \T{2}:\5 +\\{print\_str}(\.{"math"});\6 +\4${}\}{}$\2\2\6 +\\{print\_str}(\.{"\ mode"});\6 +\4${}\}{}$\2\par +\fi + +\M{212}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}\E\\{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 $\Z$ ${-}\T{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\B\4\D$\\{ignore\_depth}$ \5 +${-}{}$\T{65536000}\C{\\{prev\_depth} value that is ignored}\par +\Y\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{struct} ${}\{{}$\1\6 +\\{int16\_t}\\{mode\_field};\5 +\&{pointer} \\{head\_field}${},{}$ \\{tail\_field};\6 +\&{int} \\{pg\_field}${},{}$ \\{ml\_field};\5 +\&{memory\_word} \\{aux\_field};\2\6 +${}\}{}$ \&{list\_state\_record};\par +\fi + +\M{213}\B\D$\\{mode}$ \5 +$\\{cur\_list}.{}$\\{mode\_field}\C{current mode}\par +\B\4\D$\\{head}$ \5 +$\\{cur\_list}.{}$\\{head\_field}\C{header node of current list}\par +\B\4\D$\\{tail}$ \5 +$\\{cur\_list}.{}$\\{tail\_field}\C{final node on current list}\par +\B\4\D$\\{prev\_graf}$ \5 +$\\{cur\_list}.{}$\\{pg\_field}\C{number of paragraph lines accumulated}\par +\B\4\D$\\{aux}$ \5 +$\\{cur\_list}.{}$\\{aux\_field}\C{auxiliary data about the current list}\par +\B\4\D$\\{prev\_depth}$ \5 +$\\{aux}.{}$\\{sc}\C{the name of \\{aux} in vertical mode}\par +\B\4\D$\\{space\_factor}$ \5 +$\\{aux}.\\{hh}.{}$\\{lh}\C{part of \\{aux} in horizontal mode}\par +\B\4\D$\\{clang}$ \5 +$\\{aux}.\\{hh}.{}$\\{rh}\C{the other part of \\{aux} in horizontal mode}\par +\B\4\D$\\{incompleat\_noad}$ \5 +$\\{aux}.{}$\|i\C{the name of \\{aux} in math mode}\par +\B\4\D$\\{mode\_line}$ \5 +$\\{cur\_list}.{}$\\{ml\_field}\C{source file line number at beginning of list}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{list\_state\_record} ${}\\{nest}[\\{nest\_size}+\T{1}];{}$\6 +\&{uint8\_t} \\{nest\_ptr};\C{first unused location of \\{nest}}\6 +\&{uint8\_t} \\{max\_nest\_stack};\C{maximum of \\{nest\_ptr} when pushing}\6 +\&{list\_state\_record} \\{cur\_list};\C{the ``top'' semantic state}\7 +\\{int16\_t}\\{shown\_mode};\C{most recent mode shown by \.{\\tracingcommands}}\par +\fi + +\M{214}Here is a common way to make the current list grow: + +\Y\B\4\D$\\{tail\_append}(\|X)$ \6 +${}\{{}$\5 +\1${}\\{link}(\\{tail})\K\|X;{}$\5 +${}\\{tail}\K\\{link}(\\{tail});{}$\6 +\4${}\}{}$\2\par +\fi + +\M{215}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\B\4\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{nest\_ptr}\K\T{0};{}$\5 +${}\\{max\_nest\_stack}\K\T{0};{}$\5 +${}\\{mode}\K\\{vmode};{}$\5 +${}\\{head}\K\\{contrib\_head};{}$\5 +${}\\{tail}\K\\{contrib\_head};{}$\5 +${}\\{prev\_depth}\K\\{ignore\_depth};{}$\5 +${}\\{mode\_line}\K\T{0};{}$\5 +${}\\{prev\_graf}\K\T{0};{}$\5 +${}\\{shown\_mode}\K\T{0};{}$\5 +\X991:Start a new current page\X;\par +\fi + +\M{216}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\B\&{void} \\{push\_nest}(\&{void})\C{enter a new semantic level, save the old}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{nest\_ptr}>\\{max\_nest\_stack}){}$\5 +${}\{{}$\5 +\1${}\\{max\_nest\_stack}\K\\{nest\_ptr};{}$\6 +\&{if} ${}(\\{nest\_ptr}\E\\{nest\_size}){}$\1\5 +${}\\{overflow}(\.{"semantic\ nest\ size"},\39\\{nest\_size});{}$\2\6 +\4${}\}{}$\2\6 +${}\\{nest}[\\{nest\_ptr}]\K\\{cur\_list}{}$;\C{stack the record}\6 +\\{incr}(\\{nest\_ptr});\5 +${}\\{head}\K\\{get\_avail}(\,);{}$\5 +${}\\{tail}\K\\{head};{}$\5 +${}\\{prev\_graf}\K\T{0};{}$\5 +${}\\{mode\_line}\K\\{line};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{217}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\B\&{void} \\{pop\_nest}(\&{void})\C{leave a semantic level, re-enter the old}\6 +${}\{{}$\5 +\1\\{free\_avail}(\\{head});\5 +\\{decr}(\\{nest\_ptr});\5 +${}\\{cur\_list}\K\\{nest}[\\{nest\_ptr}];{}$\6 +\4${}\}{}$\2\par +\fi + +\M{218}Here is a procedure that displays what \TeX\ is working on, at all levels. + +\Y\B\&{void} \\{print\_totals}(\&{void});\7 +\&{void} \\{show\_activities}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|p;\C{index into \\{nest}}\7 +\\{int16\_t}\|m;\C{mode}\7 +\&{memory\_word} \|a;\C{auxiliary}\6 +\&{pointer} \|q${},{}$ \|r;\C{for showing the current page}\6 +\&{int} \|t;\C{ditto}\7 +${}\\{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};{}$ ${}\|p\G\T{0};{}$ ${}\|p\MM){}$\5 +${}\{{}$\5 +\1${}\|m\K\\{nest}[\|p].\\{mode\_field};{}$\5 +${}\|a\K\\{nest}[\|p].\\{aux\_field};{}$\5 +\\{print\_nl}(\.{"\#\#\#\ "});\5 +\\{print\_mode}(\|m);\5 +\\{print\_str}(\.{"\ entered\ at\ line\ "});\5 +${}\\{print\_int}(\\{abs}(\\{nest}[\|p].\\{ml\_field}));{}$\6 +\&{if} ${}(\|m\E\\{hmode}){}$\1\6 +\&{if} ${}(\\{nest}[\|p].\\{pg\_field}\I\T{\~40600000}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ (language"});\5 +${}\\{print\_int}(\\{nest}[\|p].\\{pg\_field}\MOD\T{\~200000});{}$\5 +\\{print\_str}(\.{":hyphenmin"});\5 +${}\\{print\_int}(\\{nest}[\|p].\\{pg\_field}/\T{\~20000000});{}$\5 +\\{print\_char}(\.{','});\5 +${}\\{print\_int}((\\{nest}[\|p].\\{pg\_field}/\T{\~200000})\MOD\T{\~100});{}$\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\2\6 +\&{if} ${}(\\{nest}[\|p].\\{ml\_field}<\T{0}){}$\1\5 +\\{print\_str}(\.{"\ (\\\\output\ routine)}\)\.{"});\2\6 +\&{if} ${}(\|p\E\T{0}){}$\5 +${}\{{}$\5 +\1\X986:Show the status of the current page\X;\6 +\&{if} ${}(\\{link}(\\{contrib\_head})\I\\{null}){}$\1\5 +\\{print\_nl}(\.{"\#\#\#\ recent\ contribu}\)\.{tions:"});\2\6 +\4${}\}{}$\2\6 +${}\\{show\_box}(\\{link}(\\{nest}[\|p].\\{head\_field}));{}$\5 +\X219:Show the auxiliary field, \|a\X;\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{219}\B\X219:Show the auxiliary field, \|a\X${}\E{}$\6 +\&{switch} ${}(\\{abs}(\|m)/(\\{max\_command}+\T{1})){}$\5 +${}\{{}$\1\6 +\4\&{case} \T{0}:\6 +${}\{{}$\5 +\1\\{print\_nl}(\.{"prevdepth\ "});\6 +\&{if} ${}(\|a.\\{sc}\Z\\{ignore\_depth}){}$\1\5 +\\{print\_str}(\.{"ignored"});\2\6 +\&{else}\1\5 +${}\\{print\_scaled}(\|a.\\{sc});{}$\2\6 +\&{if} ${}(\\{nest}[\|p].\\{pg\_field}\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{",\ prevgraf\ "});\5 +${}\\{print\_int}(\\{nest}[\|p].\\{pg\_field});{}$\5 +\\{print\_str}(\.{"\ line"});\6 +\&{if} ${}(\\{nest}[\|p].\\{pg\_field}\I\T{1}){}$\1\5 +\\{print\_char}(\.{'s'});\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \T{1}:\6 +${}\{{}$\5 +\1\\{print\_nl}(\.{"spacefactor\ "});\5 +${}\\{print\_int}(\|a.\\{hh}.\\{lh});{}$\6 +\&{if} ${}(\|m>\T{0}{}$)\5 +\1\&{if} ${}(\|a.\\{hh}.\\{rh}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{",\ current\ language\ }\)\.{"});\5 +${}\\{print\_int}(\|a.\\{hh}.\\{rh}){}$;\5 +${}\}{}$\2\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \T{2}:\6 +\&{if} ${}(\|a.\|i\I\\{null}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"this\ will\ be\ denomi}\)\.{nator\ of:"});\5 +${}\\{show\_box}(\|a.\|i){}$;\5 +${}\}{}$\2\6 +\4${}\}{}$\C{there are no other cases}\2\par +\U218.\fi + +\N{1}{220}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}\dotdot(\\{hash\_base}-\T{1})]$ holds the current +equivalents of single-character control sequences. + +\yskip\hangg 2) $\\{eqtb}[\\{hash\_base}\dotdot(\\{glue\_base}-\T{1})]$ holds the current +equivalents of multiletter control sequences. + +\yskip\hangg 3) $\\{eqtb}[\\{glue\_base}\dotdot(\\{local\_base}-\T{1})]$ holds the current +equivalents of glue parameters like the current baselineskip. + +\yskip\hangg 4) $\\{eqtb}[\\{local\_base}\dotdot(\\{int\_base}-\T{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. + +\yskip\hangg 5) $\\{eqtb}[\\{int\_base}\dotdot(\\{dimen\_base}-\T{1})]$ holds the current +equivalents of fullword integer parameters like the current hyphenation +penalty. + +\yskip\hangg 6) $\\{eqtb}[\\{dimen\_base}\dotdot\\{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 + +\M{221}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\B\4\D$\\{eq\_level\_field}(\|X)$ \5 +$\|X.\\{hh}.{}$\\{b1}\par +\B\4\D$\\{eq\_type\_field}(\|X)$ \5 +$\|X.\\{hh}.{}$\\{b0}\par +\B\4\D$\\{equiv\_field}(\|X)$ \5 +$\|X.\\{hh}.{}$\\{rh}\par +\B\4\D$\\{eq\_level}(\|X)$ \5 +\\{eq\_level\_field}(\\{eqtb}[\|X])\C{level of definition}\par +\B\4\D$\\{eq\_type}(\|X)$ \5 +\\{eq\_type\_field}(\\{eqtb}[\|X])\C{command code for equivalent}\par +\B\4\D$\\{equiv}(\|X)$ \5 +\\{equiv\_field}(\\{eqtb}[\|X])\C{equivalent value}\par +\B\4\D$\\{level\_zero}$ \5 +\\{min\_quarterword}\C{level for undefined quantities}\par +\B\4\D$\\{level\_one}$ \5 +$(\\{level\_zero}+\T{1}{}$)\C{outermost level for defined quantities}\par +\fi + +\M{222}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\B\4\D$\\{active\_base}$ \5 +\T{1}\C{beginning of region 1, for active character equivalents}\par +\B\4\D$\\{single\_base}$ \5 +$(\\{active\_base}+\T{256}{}$)\C{equivalents of one-character control sequences}\par +\B\4\D$\\{null\_cs}$ \5 +$(\\{single\_base}+\T{256}{}$)\C{equivalent of \.{\\csname\\endcsname}}\par +\B\4\D$\\{hash\_base}$ \5 +$(\\{null\_cs}+\T{1}{}$)\C{beginning of region 2, for the hash table}\par +\B\4\D$\\{frozen\_control\_sequence}$ \5 +$(\\{hash\_base}+\\{hash\_size}{}$)\C{for error recovery}\par +\B\4\D$\\{frozen\_protection}$ \5 +\\{frozen\_control\_sequence}\C{inaccessible but definable}\par +\B\4\D$\\{frozen\_cr}$ \5 +$(\\{frozen\_control\_sequence}+\T{1}{}$)\C{permanent `\.{\\cr}'}\par +\B\4\D$\\{frozen\_end\_group}$ \5 +$(\\{frozen\_control\_sequence}+\T{2}{}$)\C{permanent `\.{\\endgroup}'}\par +\B\4\D$\\{frozen\_right}$ \5 +$(\\{frozen\_control\_sequence}+\T{3}{}$)\C{permanent `\.{\\right}'}\par +\B\4\D$\\{frozen\_fi}$ \5 +$(\\{frozen\_control\_sequence}+\T{4}{}$)\C{permanent `\.{\\fi}'}\par +\B\4\D$\\{frozen\_end\_template}$ \5 +$(\\{frozen\_control\_sequence}+\T{5}{}$)\C{permanent `\.{\\endtemplate}'}\par +\B\4\D$\\{frozen\_endv}$ \5 +$(\\{frozen\_control\_sequence}+\T{6}{}$)\C{second permanent `\.{\\endtemplate}'}\par +\B\4\D$\\{frozen\_relax}$ \5 +$(\\{frozen\_control\_sequence}+\T{7}{}$)\C{permanent `\.{\\relax}'}\par +\B\4\D$\\{end\_write}$ \5 +$(\\{frozen\_control\_sequence}+\T{8}{}$)\C{permanent `\.{\\endwrite}'}\par +\B\4\D$\\{frozen\_dont\_expand}$ \5 +$(\\{frozen\_control\_sequence}+\T{9}{}$)\C{permanent `\.{\\notexpanded:}'}\par +\B\4\D$\\{frozen\_null\_font}$ \5 +$(\\{frozen\_control\_sequence}+\T{10}{}$)\C{permanent `\.{\\nullfont}'}\par +\B\4\D$\\{font\_id\_base}$ \5 +$(\\{frozen\_null\_font}-\\{font\_base}{}$)\C{begins table of 257 permanent font identifiers}\par +\B\4\D$\\{undefined\_control\_sequence}$ \5 +$(\\{frozen\_null\_font}+\T{257}{}$)\C{dummy location}\par +\B\4\D$\\{glue\_base}$ \5 +$(\\{undefined\_control\_sequence}+\T{1}{}$)\C{beginning of region 3}\par +\Y\B\4\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\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};{}$ ${}\|k\Z\\{undefined\_control\_sequence}-\T{1};{}$ ${}\|k\PP){}$\1\5 +${}\\{eqtb}[\|k]\K\\{eqtb}[\\{undefined\_control\_sequence}]{}$;\2\par +\fi + +\M{223}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\B\4\X223:Show equivalent \|n, in region 1 or 2\X${}\E{}$\6 +${}\{{}$\5 +\1\\{sprint\_cs}(\|n);\5 +\\{print\_char}(\.{'='});\5 +${}\\{print\_cmd\_chr}(\\{eq\_type}(\|n),\39\\{equiv}(\|n));{}$\6 +\&{if} ${}(\\{eq\_type}(\|n)\G\\{call}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{':'});\5 +${}\\{show\_token\_list}(\\{link}(\\{equiv}(\|n)),\39\\{null},\39\T{32});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U252.\fi + +\M{224}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\B\4\D$\\{line\_skip\_code}$ \5 +\T{0}\C{interline glue if \\{baseline\_skip} is infeasible}\par +\B\4\D$\\{baseline\_skip\_code}$ \5 +\T{1}\C{desired glue between baselines}\par +\B\4\D$\\{par\_skip\_code}$ \5 +\T{2}\C{extra glue just above a paragraph}\par +\B\4\D$\\{above\_display\_skip\_code}$ \5 +\T{3}\C{extra glue just above displayed math}\par +\B\4\D$\\{below\_display\_skip\_code}$ \5 +\T{4}\C{extra glue just below displayed math}\par +\B\4\D$\\{above\_display\_short\_skip\_code}$ \5 +\T{5}\C{glue above displayed math following short lines}\par +\B\4\D$\\{below\_display\_short\_skip\_code}$ \5 +\T{6}\C{glue below displayed math following short lines}\par +\B\4\D$\\{left\_skip\_code}$ \5 +\T{7}\C{glue at left of justified lines}\par +\B\4\D$\\{right\_skip\_code}$ \5 +\T{8}\C{glue at right of justified lines}\par +\B\4\D$\\{top\_skip\_code}$ \5 +\T{9}\C{glue at top of main pages}\par +\B\4\D$\\{split\_top\_skip\_code}$ \5 +\T{10}\C{glue at top of split pages}\par +\B\4\D$\\{tab\_skip\_code}$ \5 +\T{11}\C{glue between aligned entries}\par +\B\4\D$\\{space\_skip\_code}$ \5 +\T{12}\C{glue between words (if not \\{zero\_glue})}\par +\B\4\D$\\{xspace\_skip\_code}$ \5 +\T{13}\C{glue after sentences (if not \\{zero\_glue})}\par +\B\4\D$\\{par\_fill\_skip\_code}$ \5 +\T{14}\C{glue on last line of paragraph}\par +\B\4\D$\\{thin\_mu\_skip\_code}$ \5 +\T{15}\C{thin space in math formula}\par +\B\4\D$\\{med\_mu\_skip\_code}$ \5 +\T{16}\C{medium space in math formula}\par +\B\4\D$\\{thick\_mu\_skip\_code}$ \5 +\T{17}\C{thick space in math formula}\par +\B\4\D$\\{glue\_pars}$ \5 +\T{18}\C{total number of glue parameters}\par +\B\4\D$\\{skip\_base}$ \5 +$(\\{glue\_base}+\\{glue\_pars}{}$)\C{table of 256 ``skip'' registers}\par +\B\4\D$\\{mu\_skip\_base}$ \5 +$(\\{skip\_base}+\T{256}{}$)\C{table of 256 ``muskip'' registers}\par +\B\4\D$\\{local\_base}$ \5 +$(\\{mu\_skip\_base}+\T{256}{}$)\C{beginning of region 4}\Y\par +\B\4\D$\\{skip}(\|X)$ \5 +$\\{equiv}(\\{skip\_base}+\|X{}$)\C{\\{mem} location of glue specification}\par +\B\4\D$\\{mu\_skip}(\|X)$ \5 +$\\{equiv}(\\{mu\_skip\_base}+\|X{}$)\C{\\{mem} location of math glue spec}\par +\B\4\D$\\{glue\_par}(\|X)$ \5 +$\\{equiv}(\\{glue\_base}+\|X{}$)\C{\\{mem} location of glue specification}\par +\B\4\D$\\{line\_skip}$ \5 +\\{glue\_par}(\\{line\_skip\_code})\par +\B\4\D$\\{baseline\_skip}$ \5 +\\{glue\_par}(\\{baseline\_skip\_code})\par +\B\4\D$\\{par\_skip}$ \5 +\\{glue\_par}(\\{par\_skip\_code})\par +\B\4\D$\\{above\_display\_skip}$ \5 +\\{glue\_par}(\\{above\_display\_skip\_code})\par +\B\4\D$\\{below\_display\_skip}$ \5 +\\{glue\_par}(\\{below\_display\_skip\_code})\par +\B\4\D$\\{above\_display\_short\_skip}$ \5 +\\{glue\_par}(\\{above\_display\_short\_skip\_code})\par +\B\4\D$\\{below\_display\_short\_skip}$ \5 +\\{glue\_par}(\\{below\_display\_short\_skip\_code})\par +\B\4\D$\\{left\_skip}$ \5 +\\{glue\_par}(\\{left\_skip\_code})\par +\B\4\D$\\{right\_skip}$ \5 +\\{glue\_par}(\\{right\_skip\_code})\par +\B\4\D$\\{top\_skip}$ \5 +\\{glue\_par}(\\{top\_skip\_code})\par +\B\4\D$\\{split\_top\_skip}$ \5 +\\{glue\_par}(\\{split\_top\_skip\_code})\par +\B\4\D$\\{tab\_skip}$ \5 +\\{glue\_par}(\\{tab\_skip\_code})\par +\B\4\D$\\{space\_skip}$ \5 +\\{glue\_par}(\\{space\_skip\_code})\par +\B\4\D$\\{xspace\_skip}$ \5 +\\{glue\_par}(\\{xspace\_skip\_code})\par +\B\4\D$\\{par\_fill\_skip}$ \5 +\\{glue\_par}(\\{par\_fill\_skip\_code})\par +\B\4\D$\\{thin\_mu\_skip}$ \5 +\\{glue\_par}(\\{thin\_mu\_skip\_code})\par +\B\4\D$\\{med\_mu\_skip}$ \5 +\\{glue\_par}(\\{med\_mu\_skip\_code})\par +\B\4\D$\\{thick\_mu\_skip}$ \5 +\\{glue\_par}(\\{thick\_mu\_skip\_code})\par +\Y\B\4\X224:Current \\{mem} equivalent of glue parameter number \|n\X${}\E{}$\6 +\\{glue\_par}(\|n)\par +\Us152\ET154.\fi + +\M{225}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\B\4\X225:Declare the procedure called \\{print\_skip\_param}\X${}\E{}$\6 +\&{void} \\{print\_skip\_param}(\&{int} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\&{switch} (\|n)\5 +${}\{{}$\1\6 +\4\&{case} \\{line\_skip\_code}:\5 +\\{print\_esc}(\X1405:\.{"lineskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{baseline\_skip\_code}:\5 +\\{print\_esc}(\X1406:\.{"baselineskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{par\_skip\_code}:\5 +\\{print\_esc}(\X1407:\.{"parskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{above\_display\_skip\_code}:\5 +\\{print\_esc}(\X1408:\.{"abovedisplayskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{below\_display\_skip\_code}:\5 +\\{print\_esc}(\X1409:\.{"belowdisplayskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{above\_display\_short\_skip\_code}:\5 +\\{print\_esc}(\X1410:\.{"abovedisplayshortsk}\)\.{ip"}\X);\5 +\&{break};\6 +\4\&{case} \\{below\_display\_short\_skip\_code}:\5 +\\{print\_esc}(\X1411:\.{"belowdisplayshortsk}\)\.{ip"}\X);\5 +\&{break};\6 +\4\&{case} \\{left\_skip\_code}:\5 +\\{print\_esc}(\X1412:\.{"leftskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{right\_skip\_code}:\5 +\\{print\_esc}(\X1413:\.{"rightskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{top\_skip\_code}:\5 +\\{print\_esc}(\X1414:\.{"topskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{split\_top\_skip\_code}:\5 +\\{print\_esc}(\X1415:\.{"splittopskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{tab\_skip\_code}:\5 +\\{print\_esc}(\X1416:\.{"tabskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{space\_skip\_code}:\5 +\\{print\_esc}(\X1417:\.{"spaceskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{xspace\_skip\_code}:\5 +\\{print\_esc}(\X1418:\.{"xspaceskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{par\_fill\_skip\_code}:\5 +\\{print\_esc}(\X1419:\.{"parfillskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{thin\_mu\_skip\_code}:\5 +\\{print\_esc}(\X1420:\.{"thinmuskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{med\_mu\_skip\_code}:\5 +\\{print\_esc}(\X1421:\.{"medmuskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{thick\_mu\_skip\_code}:\5 +\\{print\_esc}(\X1422:\.{"thickmuskip"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_str}(\.{"[unknown\ glue\ param}\)\.{eter!]"});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U179.\fi + +\M{226}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\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\E{}$\6 +$\\{primitive}(\X1405:\.{"lineskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{line\_skip\_code}){}$;\6 +${}\\{primitive}(\X1406:\.{"baselineskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{baseline\_skip\_code}){}$;\6 +${}\\{primitive}(\X1407:\.{"parskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{par\_skip\_code}){}$;\6 +${}\\{primitive}(\X1408:\.{"abovedisplayskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{above\_display\_skip\_code}){}$;\6 +${}\\{primitive}(\X1409:\.{"belowdisplayskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{below\_display\_skip\_code}){}$;\6 +${}\\{primitive}(\X1410:\.{"abovedisplayshortsk}\)\.{ip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{above\_display\_short\_skip\_code}){}$;\6 +${}\\{primitive}(\X1411:\.{"belowdisplayshortsk}\)\.{ip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{below\_display\_short\_skip\_code}){}$;\6 +${}\\{primitive}(\X1412:\.{"leftskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{left\_skip\_code}){}$;\6 +${}\\{primitive}(\X1413:\.{"rightskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{right\_skip\_code}){}$;\6 +${}\\{primitive}(\X1414:\.{"topskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{top\_skip\_code}){}$;\6 +${}\\{primitive}(\X1415:\.{"splittopskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{split\_top\_skip\_code}){}$;\6 +${}\\{primitive}(\X1416:\.{"tabskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{tab\_skip\_code}){}$;\6 +${}\\{primitive}(\X1417:\.{"spaceskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{space\_skip\_code}){}$;\6 +${}\\{primitive}(\X1418:\.{"xspaceskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{xspace\_skip\_code}){}$;\6 +${}\\{primitive}(\X1419:\.{"parfillskip"}\X,\39\\{assign\_glue},\39\\{glue\_base}+\\{par\_fill\_skip\_code}){}$;\6 +${}\\{primitive}(\X1420:\.{"thinmuskip"}\X,\39\\{assign\_mu\_glue},\39\\{glue\_base}+\\{thin\_mu\_skip\_code}){}$;\6 +${}\\{primitive}(\X1421:\.{"medmuskip"}\X,\39\\{assign\_mu\_glue},\39\\{glue\_base}+\\{med\_mu\_skip\_code}){}$;\6 +${}\\{primitive}(\X1422:\.{"thickmuskip"}\X,\39\\{assign\_mu\_glue},\39\\{glue\_base}+\\{thick\_mu\_skip\_code}){}$;\par +\As230, 238, 248, 265, 334, 376, 384, 411, 416, 468, 487, 491, 553, 780, 983, 1052, 1058, 1071, 1088, 1107, 1114, 1141, 1156, 1169, 1178, 1188, 1208, 1219, 1222, 1230, 1250, 1254, 1262, 1272, 1277, 1286, 1291\ETs1344. +\U1336.\fi + +\M{227}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\E{}$\6 +\4\&{case} \\{assign\_glue}:\5 +\&{case} \\{assign\_mu\_glue}:\6 +\&{if} ${}(\\{chr\_code}<\\{skip\_base}){}$\1\5 +${}\\{print\_skip\_param}(\\{chr\_code}-\\{glue\_base});{}$\2\6 +\&{else} \&{if} ${}(\\{chr\_code}<\\{mu\_skip\_base}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1423:\.{"skip"}\X);\5 +${}\\{print\_int}(\\{chr\_code}-\\{skip\_base});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1424:\.{"muskip"}\X);\5 +${}\\{print\_int}(\\{chr\_code}-\\{mu\_skip\_base});{}$\6 +\4${}\}{}$\5 +\2\&{break};\par +\As231, 239, 249, 266, 335, 377, 385, 412, 417, 469, 488, 492, 781, 984, 1053, 1059, 1072, 1089, 1108, 1115, 1143, 1157, 1170, 1179, 1189, 1209, 1220, 1223, 1231, 1251, 1255, 1261, 1263, 1273, 1278, 1287, 1292, 1295\ETs1346. +\U298.\fi + +\M{228}All glue parameters and registers are initially `\.{0pt plus0pt minus0pt}'. + +\Y\B\4\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\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}+\T{1};{}$ ${}\|k\Z\\{local\_base}-\T{1};{}$ ${}\|k\PP){}$\1\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 + +\M{229}\B\X229:Show equivalent \|n, in region 3\X${}\E{}$\6 +\&{if} ${}(\|n<\\{skip\_base}){}$\5 +${}\{{}$\5 +\1${}\\{print\_skip\_param}(\|n-\\{glue\_base});{}$\5 +\\{print\_char}(\.{'='});\6 +\&{if} ${}(\|n<\\{glue\_base}+\\{thin\_mu\_skip\_code}){}$\1\5 +${}\\{print\_spec}(\\{equiv}(\|n),\39\X1425:\.{"pt"}\X);{}$\2\6 +\&{else}\1\5 +${}\\{print\_spec}(\\{equiv}(\|n),\39\X1394:\.{"mu"}\X);{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|n<\\{mu\_skip\_base}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1423:\.{"skip"}\X);\5 +${}\\{print\_int}(\|n-\\{skip\_base});{}$\5 +\\{print\_char}(\.{'='});\5 +${}\\{print\_spec}(\\{equiv}(\|n),\39\X1425:\.{"pt"}\X);{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1424:\.{"muskip"}\X);\5 +${}\\{print\_int}(\|n-\\{mu\_skip\_base});{}$\5 +\\{print\_char}(\.{'='});\5 +${}\\{print\_spec}(\\{equiv}(\|n),\39\X1394:\.{"mu"}\X);{}$\6 +\4${}\}{}$\2\par +\U252.\fi + +\M{230}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\B\4\D$\\{par\_shape\_loc}$ \5 +\\{local\_base}\C{specifies paragraph shape}\par +\B\4\D$\\{output\_routine\_loc}$ \5 +$(\\{local\_base}+\T{1}{}$)\C{points to token list for \.{\\output}}\par +\B\4\D$\\{every\_par\_loc}$ \5 +$(\\{local\_base}+\T{2}{}$)\C{points to token list for \.{\\everypar}}\par +\B\4\D$\\{every\_math\_loc}$ \5 +$(\\{local\_base}+\T{3}{}$)\C{points to token list for \.{\\everymath}}\par +\B\4\D$\\{every\_display\_loc}$ \5 +$(\\{local\_base}+\T{4}{}$)\C{points to token list for \.{\\everydisplay}}\par +\B\4\D$\\{every\_hbox\_loc}$ \5 +$(\\{local\_base}+\T{5}{}$)\C{points to token list for \.{\\everyhbox}}\par +\B\4\D$\\{every\_vbox\_loc}$ \5 +$(\\{local\_base}+\T{6}{}$)\C{points to token list for \.{\\everyvbox}}\par +\B\4\D$\\{every\_job\_loc}$ \5 +$(\\{local\_base}+\T{7}{}$)\C{points to token list for \.{\\everyjob}}\par +\B\4\D$\\{every\_cr\_loc}$ \5 +$(\\{local\_base}+\T{8}{}$)\C{points to token list for \.{\\everycr}}\par +\B\4\D$\\{err\_help\_loc}$ \5 +$(\\{local\_base}+\T{9}{}$)\C{points to token list for \.{\\errhelp}}\par +\B\4\D$\\{toks\_base}$ \5 +$(\\{local\_base}+\T{10}{}$)\C{table of 256 token list registers}\par +\B\4\D$\\{box\_base}$ \5 +$(\\{toks\_base}+\T{256}{}$)\C{table of 256 box registers}\par +\B\4\D$\\{cur\_font\_loc}$ \5 +$(\\{box\_base}+\T{256}{}$)\C{internal font number outside math mode}\par +\B\4\D$\\{math\_font\_base}$ \5 +$(\\{cur\_font\_loc}+\T{1}{}$)\C{table of 48 math font numbers}\par +\B\4\D$\\{cat\_code\_base}$ \5 +$(\\{math\_font\_base}+\T{48}{}$)\C{table of 256 command codes (the ``catcodes'')}\par +\B\4\D$\\{lc\_code\_base}$ \5 +$(\\{cat\_code\_base}+\T{256}{}$)\C{table of 256 lowercase mappings}\par +\B\4\D$\\{uc\_code\_base}$ \5 +$(\\{lc\_code\_base}+\T{256}{}$)\C{table of 256 uppercase mappings}\par +\B\4\D$\\{sf\_code\_base}$ \5 +$(\\{uc\_code\_base}+\T{256}{}$)\C{table of 256 spacefactor mappings}\par +\B\4\D$\\{math\_code\_base}$ \5 +$(\\{sf\_code\_base}+\T{256}{}$)\C{table of 256 math mode mappings}\par +\B\4\D$\\{int\_base}$ \5 +$(\\{math\_code\_base}+\T{256}{}$)\C{beginning of region 5}\Y\par +\B\4\D$\\{par\_shape\_ptr}$ \5 +\\{equiv}(\\{par\_shape\_loc})\par +\B\4\D$\\{output\_routine}$ \5 +\\{equiv}(\\{output\_routine\_loc})\par +\B\4\D$\\{every\_par}$ \5 +\\{equiv}(\\{every\_par\_loc})\par +\B\4\D$\\{every\_math}$ \5 +\\{equiv}(\\{every\_math\_loc})\par +\B\4\D$\\{every\_display}$ \5 +\\{equiv}(\\{every\_display\_loc})\par +\B\4\D$\\{every\_hbox}$ \5 +\\{equiv}(\\{every\_hbox\_loc})\par +\B\4\D$\\{every\_vbox}$ \5 +\\{equiv}(\\{every\_vbox\_loc})\par +\B\4\D$\\{every\_job}$ \5 +\\{equiv}(\\{every\_job\_loc})\par +\B\4\D$\\{every\_cr}$ \5 +\\{equiv}(\\{every\_cr\_loc})\par +\B\4\D$\\{err\_help}$ \5 +\\{equiv}(\\{err\_help\_loc})\par +\B\4\D$\\{toks}(\|X)$ \5 +$\\{equiv}(\\{toks\_base}+\|X{}$)\par +\B\4\D$\\{box}(\|X)$ \5 +$\\{equiv}(\\{box\_base}+\|X{}$)\par +\B\4\D$\\{cur\_font}$ \5 +\\{equiv}(\\{cur\_font\_loc})\par +\B\4\D$\\{fam\_fnt}(\|X)$ \5 +$\\{equiv}(\\{math\_font\_base}+\|X{}$)\par +\B\4\D$\\{cat\_code}(\|X)$ \5 +$\\{equiv}(\\{cat\_code\_base}+\|X{}$)\par +\B\4\D$\\{lc\_code}(\|X)$ \5 +$\\{equiv}(\\{lc\_code\_base}+\|X{}$)\par +\B\4\D$\\{uc\_code}(\|X)$ \5 +$\\{equiv}(\\{uc\_code\_base}+\|X{}$)\par +\B\4\D$\\{sf\_code}(\|X)$ \5 +$\\{equiv}(\\{sf\_code\_base}+\|X{}$)\par +\B\4\D$\\{math\_code}(\|X)$ \5 +$\\{equiv}(\\{math\_code\_base}+\|X{}$)\C{Note: \\{math\_code}(\|c) is the true math code plus \\{min\_halfword}}\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1426:\.{"output"}\X,\39\\{assign\_toks},\39\\{output\_routine\_loc});{}$\5 +${}\\{primitive}(\X1427:\.{"everypar"}\X,\39\\{assign\_toks},\39\\{every\_par\_loc});{}$\5 +${}\\{primitive}(\X1428:\.{"everymath"}\X,\39\\{assign\_toks},\39\\{every\_math\_loc});{}$\5 +${}\\{primitive}(\X1429:\.{"everydisplay"}\X,\39\\{assign\_toks},\39\\{every\_display\_loc});{}$\5 +${}\\{primitive}(\X1430:\.{"everyhbox"}\X,\39\\{assign\_toks},\39\\{every\_hbox\_loc});{}$\5 +${}\\{primitive}(\X1431:\.{"everyvbox"}\X,\39\\{assign\_toks},\39\\{every\_vbox\_loc});{}$\5 +${}\\{primitive}(\X1432:\.{"everyjob"}\X,\39\\{assign\_toks},\39\\{every\_job\_loc});{}$\5 +${}\\{primitive}(\X1433:\.{"everycr"}\X,\39\\{assign\_toks},\39\\{every\_cr\_loc});{}$\5 +${}\\{primitive}(\X1434:\.{"errhelp"}\X,\39\\{assign\_toks},\39\\{err\_help\_loc}){}$;\par +\fi + +\M{231}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{assign\_toks}:\6 +\&{if} ${}(\\{chr\_code}\G\\{toks\_base}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1435:\.{"toks"}\X);\5 +${}\\{print\_int}(\\{chr\_code}-\\{toks\_base});{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{output\_routine\_loc}:\5 +\\{print\_esc}(\X1426:\.{"output"}\X);\5 +\&{break};\6 +\4\&{case} \\{every\_par\_loc}:\5 +\\{print\_esc}(\X1427:\.{"everypar"}\X);\5 +\&{break};\6 +\4\&{case} \\{every\_math\_loc}:\5 +\\{print\_esc}(\X1428:\.{"everymath"}\X);\5 +\&{break};\6 +\4\&{case} \\{every\_display\_loc}:\5 +\\{print\_esc}(\X1429:\.{"everydisplay"}\X);\5 +\&{break};\6 +\4\&{case} \\{every\_hbox\_loc}:\5 +\\{print\_esc}(\X1430:\.{"everyhbox"}\X);\5 +\&{break};\6 +\4\&{case} \\{every\_vbox\_loc}:\5 +\\{print\_esc}(\X1431:\.{"everyvbox"}\X);\5 +\&{break};\6 +\4\&{case} \\{every\_job\_loc}:\5 +\\{print\_esc}(\X1432:\.{"everyjob"}\X);\5 +\&{break};\6 +\4\&{case} \\{every\_cr\_loc}:\5 +\\{print\_esc}(\X1433:\.{"everycr"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1434:\.{"errhelp"}\X);\6 +\4${}\}{}$\5 +\2\2\&{break};\par +\fi + +\M{232}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\B\4\D$\\{null\_font}$ \5 +\\{font\_base}\par +\B\4\D$\\{var\_code}$ \5 +\T{\~70000}\C{math code meaning ``use the current family''}\par +\Y\B\4\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\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};{}$ ${}\|k\Z\\{toks\_base}+\T{255};{}$ ${}\|k\PP){}$\1\5 +${}\\{eqtb}[\|k]\K\\{eqtb}[\\{undefined\_control\_sequence}];{}$\2\6 +${}\\{box}(\T{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}+\T{1};{}$ ${}\|k\Z\\{box\_base}+\T{255};{}$ ${}\|k\PP){}$\1\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 +\&{for} ${}(\|k\K\\{math\_font\_base};{}$ ${}\|k\Z\\{math\_font\_base}+\T{47};{}$ ${}\|k\PP){}$\1\5 +${}\\{eqtb}[\|k]\K\\{eqtb}[\\{cur\_font\_loc}];{}$\2\6 +${}\\{equiv}(\\{cat\_code\_base})\K\T{0};{}$\5 +${}\\{eq\_type}(\\{cat\_code\_base})\K\\{data};{}$\5 +${}\\{eq\_level}(\\{cat\_code\_base})\K\\{level\_one}{}$;\6 +\&{for} ${}(\|k\K\\{cat\_code\_base}+\T{1};{}$ ${}\|k\Z\\{int\_base}-\T{1};{}$ ${}\|k\PP){}$\1\5 +${}\\{eqtb}[\|k]\K\\{eqtb}[\\{cat\_code\_base}];{}$\2\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{255};{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1${}\\{cat\_code}(\|k)\K\\{other\_char};{}$\5 +${}\\{math\_code}(\|k)\K\\{hi}(\|k);{}$\5 +${}\\{sf\_code}(\|k)\K\T{1000};{}$\6 +\4${}\}{}$\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'};{}$ ${}\|k\Z\.{'9'};{}$ ${}\|k\PP){}$\1\5 +${}\\{math\_code}(\|k)\K\\{hi}(\|k+\\{var\_code});{}$\2\6 +\&{for} ${}(\|k\K\.{'A'};{}$ ${}\|k\Z\.{'Z'};{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1${}\\{cat\_code}(\|k)\K\\{letter};{}$\5 +${}\\{cat\_code}(\|k+\.{'a'}-\.{'A'})\K\\{letter}{}$;\6 +${}\\{math\_code}(\|k)\K\\{hi}(\|k+\\{var\_code}+\T{\^100});{}$\5 +${}\\{math\_code}(\|k+\.{'a'}-\.{'A'})\K\\{hi}(\|k+\.{'a'}-\.{'A'}+\\{var\_code}+\T{\^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 +${}\\{sf\_code}(\|k)\K\T{999};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{233}\B\X233:Show equivalent \|n, in region 4\X${}\E{}$\6 +\&{if} ${}(\|n\E\\{par\_shape\_loc}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1436:\.{"parshape"}\X);\5 +\\{print\_char}(\.{'='});\6 +\&{if} ${}(\\{par\_shape\_ptr}\E\\{null}){}$\1\5 +\\{print\_char}(\.{'0'});\2\6 +\&{else}\1\5 +\\{print\_int}(\\{info}(\\{par\_shape\_ptr}));\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|n<\\{toks\_base}){}$\5 +${}\{{}$\5 +\1${}\\{print\_cmd\_chr}(\\{assign\_toks},\39\|n);{}$\5 +\\{print\_char}(\.{'='});\6 +\&{if} ${}(\\{equiv}(\|n)\I\\{null}){}$\1\5 +${}\\{show\_token\_list}(\\{link}(\\{equiv}(\|n)),\39\\{null},\39\T{32});{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|n<\\{box\_base}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1435:\.{"toks"}\X);\5 +${}\\{print\_int}(\|n-\\{toks\_base});{}$\5 +\\{print\_char}(\.{'='});\6 +\&{if} ${}(\\{equiv}(\|n)\I\\{null}){}$\1\5 +${}\\{show\_token\_list}(\\{link}(\\{equiv}(\|n)),\39\\{null},\39\T{32});{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|n<\\{cur\_font\_loc}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1437:\.{"box"}\X);\5 +${}\\{print\_int}(\|n-\\{box\_base});{}$\5 +\\{print\_char}(\.{'='});\6 +\&{if} ${}(\\{equiv}(\|n)\E\\{null}){}$\1\5 +\\{print\_str}(\.{"void"});\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{depth\_threshold}\K\T{0};{}$\5 +${}\\{breadth\_max}\K\T{1};{}$\5 +\\{show\_node\_list}(\\{equiv}(\|n));\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|n<\\{cat\_code\_base}){}$\1\5 +\X234:Show the font identifier in \\{eqtb}[\|n]\X\2\6 +\&{else}\1\5 +\X235:Show the halfword code in \\{eqtb}[\|n]\X\2\par +\U252.\fi + +\M{234}\B\X234:Show the font identifier in \\{eqtb}[\|n]\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\|n\E\\{cur\_font\_loc}){}$\1\5 +\\{print\_str}(\.{"current\ font"});\2\6 +\&{else} \&{if} ${}(\|n<\\{math\_font\_base}+\T{16}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1438:\.{"textfont"}\X);\5 +${}\\{print\_int}(\|n-\\{math\_font\_base});{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|n<\\{math\_font\_base}+\T{32}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1439:\.{"scriptfont"}\X);\5 +${}\\{print\_int}(\|n-\\{math\_font\_base}-\T{16});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1440:\.{"scriptscriptfont"}\X);\5 +${}\\{print\_int}(\|n-\\{math\_font\_base}-\T{32});{}$\6 +\4${}\}{}$\2\6 +\\{print\_char}(\.{'='});\6 +${}\\{print\_esc}(\\{hash}[\\{font\_id\_base}+\\{equiv}(\|n)].\\{rh}){}$;\C{that's \\{font\_id\_text}(\\{equiv}(\|n))}\6 +\4${}\}{}$\2\par +\U233.\fi + +\M{235}\B\X235:Show the halfword code in \\{eqtb}[\|n]\X${}\E{}$\6 +\&{if} ${}(\|n<\\{math\_code\_base}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|n<\\{lc\_code\_base}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1441:\.{"catcode"}\X);\5 +${}\\{print\_int}(\|n-\\{cat\_code\_base});{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|n<\\{uc\_code\_base}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1442:\.{"lccode"}\X);\5 +${}\\{print\_int}(\|n-\\{lc\_code\_base});{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|n<\\{sf\_code\_base}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1443:\.{"uccode"}\X);\5 +${}\\{print\_int}(\|n-\\{uc\_code\_base});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1444:\.{"sfcode"}\X);\5 +${}\\{print\_int}(\|n-\\{sf\_code\_base});{}$\6 +\4${}\}{}$\2\6 +\\{print\_char}(\.{'='});\5 +\\{print\_int}(\\{equiv}(\|n));\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1445:\.{"mathcode"}\X);\5 +${}\\{print\_int}(\|n-\\{math\_code\_base});{}$\5 +\\{print\_char}(\.{'='});\5 +\\{print\_int}(\\{ho}(\\{equiv}(\|n)));\6 +\4${}\}{}$\2\par +\U233.\fi + +\M{236}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}\dotdot\\{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\B\4\D$\\{pretolerance\_code}$ \5 +\T{0}\C{badness tolerance before hyphenation}\par +\B\4\D$\\{tolerance\_code}$ \5 +\T{1}\C{badness tolerance after hyphenation}\par +\B\4\D$\\{line\_penalty\_code}$ \5 +\T{2}\C{added to the badness of every line}\par +\B\4\D$\\{hyphen\_penalty\_code}$ \5 +\T{3}\C{penalty for break after discretionary hyphen}\par +\B\4\D$\\{ex\_hyphen\_penalty\_code}$ \5 +\T{4}\C{penalty for break after explicit hyphen}\par +\B\4\D$\\{club\_penalty\_code}$ \5 +\T{5}\C{penalty for creating a club line}\par +\B\4\D$\\{widow\_penalty\_code}$ \5 +\T{6}\C{penalty for creating a widow line}\par +\B\4\D$\\{display\_widow\_penalty\_code}$ \5 +\T{7}\C{ditto, just before a display}\par +\B\4\D$\\{broken\_penalty\_code}$ \5 +\T{8}\C{penalty for breaking a page at a broken line}\par +\B\4\D$\\{bin\_op\_penalty\_code}$ \5 +\T{9}\C{penalty for breaking after a binary operation}\par +\B\4\D$\\{rel\_penalty\_code}$ \5 +\T{10}\C{penalty for breaking after a relation}\par +\B\4\D$\\{pre\_display\_penalty\_code}$ \5 +\T{11}\C{penalty for breaking just before a displayed formula}\par +\B\4\D$\\{post\_display\_penalty\_code}$ \5 +\T{12}\C{penalty for breaking just after a displayed formula}\par +\B\4\D$\\{inter\_line\_penalty\_code}$ \5 +\T{13}\C{additional penalty between lines}\par +\B\4\D$\\{double\_hyphen\_demerits\_code}$ \5 +\T{14}\C{demerits for double hyphen break}\par +\B\4\D$\\{final\_hyphen\_demerits\_code}$ \5 +\T{15}\C{demerits for final hyphen break}\par +\B\4\D$\\{adj\_demerits\_code}$ \5 +\T{16}\C{demerits for adjacent incompatible lines}\par +\B\4\D$\\{mag\_code}$ \5 +\T{17}\C{magnification ratio}\par +\B\4\D$\\{delimiter\_factor\_code}$ \5 +\T{18}\C{ratio for variable-size delimiters}\par +\B\4\D$\\{looseness\_code}$ \5 +\T{19}\C{change in number of lines for a paragraph}\par +\B\4\D$\\{time\_code}$ \5 +\T{20}\C{current time of day}\par +\B\4\D$\\{day\_code}$ \5 +\T{21}\C{current day of the month}\par +\B\4\D$\\{month\_code}$ \5 +\T{22}\C{current month of the year}\par +\B\4\D$\\{year\_code}$ \5 +\T{23}\C{current year of our Lord}\par +\B\4\D$\\{show\_box\_breadth\_code}$ \5 +\T{24}\C{nodes per level in \\{show\_box}}\par +\B\4\D$\\{show\_box\_depth\_code}$ \5 +\T{25}\C{maximum level in \\{show\_box}}\par +\B\4\D$\\{hbadness\_code}$ \5 +\T{26}\C{hboxes exceeding this badness will be shown by \\{hpack}}\par +\B\4\D$\\{vbadness\_code}$ \5 +\T{27}\C{vboxes exceeding this badness will be shown by \\{vpack}}\par +\B\4\D$\\{pausing\_code}$ \5 +\T{28}\C{pause after each line is read from a file}\par +\B\4\D$\\{tracing\_online\_code}$ \5 +\T{29}\C{show diagnostic output on terminal}\par +\B\4\D$\\{tracing\_macros\_code}$ \5 +\T{30}\C{show macros as they are being expanded}\par +\B\4\D$\\{tracing\_stats\_code}$ \5 +\T{31}\C{show memory usage if \TeX\ knows it}\par +\B\4\D$\\{tracing\_paragraphs\_code}$ \5 +\T{32}\C{show line-break calculations}\par +\B\4\D$\\{tracing\_pages\_code}$ \5 +\T{33}\C{show page-break calculations}\par +\B\4\D$\\{tracing\_output\_code}$ \5 +\T{34}\C{show boxes when they are shipped out}\par +\B\4\D$\\{tracing\_lost\_chars\_code}$ \5 +\T{35}\C{show characters that aren't in the font}\par +\B\4\D$\\{tracing\_commands\_code}$ \5 +\T{36}\C{show command codes at \\{big\_switch}}\par +\B\4\D$\\{tracing\_restores\_code}$ \5 +\T{37}\C{show equivalents when they are restored}\par +\B\4\D$\\{uc\_hyph\_code}$ \5 +\T{38}\C{hyphenate words beginning with a capital letter}\par +\B\4\D$\\{output\_penalty\_code}$ \5 +\T{39}\C{penalty found at current page break}\par +\B\4\D$\\{max\_dead\_cycles\_code}$ \5 +\T{40}\C{bound on consecutive dead cycles of output}\par +\B\4\D$\\{hang\_after\_code}$ \5 +\T{41}\C{hanging indentation changes after this many lines}\par +\B\4\D$\\{floating\_penalty\_code}$ \5 +\T{42}\C{penalty for insertions heldover after a split}\par +\B\4\D$\\{global\_defs\_code}$ \5 +\T{43}\C{override \.{\\global} specifications}\par +\B\4\D$\\{cur\_fam\_code}$ \5 +\T{44}\C{current family}\par +\B\4\D$\\{escape\_char\_code}$ \5 +\T{45}\C{escape character for token output}\par +\B\4\D$\\{default\_hyphen\_char\_code}$ \5 +\T{46}\C{value of \.{\\hyphenchar} when a font is loaded}\par +\B\4\D$\\{default\_skew\_char\_code}$ \5 +\T{47}\C{value of \.{\\skewchar} when a font is loaded}\par +\B\4\D$\\{end\_line\_char\_code}$ \5 +\T{48}\C{character placed at the right end of the buffer}\par +\B\4\D$\\{new\_line\_char\_code}$ \5 +\T{49}\C{character that prints as \\{print\_ln}}\par +\B\4\D$\\{language\_code}$ \5 +\T{50}\C{current hyphenation table}\par +\B\4\D$\\{left\_hyphen\_min\_code}$ \5 +\T{51}\C{minimum left hyphenation fragment size}\par +\B\4\D$\\{right\_hyphen\_min\_code}$ \5 +\T{52}\C{minimum right hyphenation fragment size}\par +\B\4\D$\\{holding\_inserts\_code}$ \5 +\T{53}\C{do not remove insertion nodes from \.{\\box255}}\par +\B\4\D$\\{error\_context\_lines\_code}$ \5 +\T{54}\C{maximum intermediate line pairs shown}\par +\B\4\D$\\{int\_pars}$ \5 +\T{55}\C{total number of integer parameters}\par +\B\4\D$\\{count\_base}$ \5 +$(\\{int\_base}+\\{int\_pars}{}$)\C{256 user \.{\\count} registers}\par +\B\4\D$\\{del\_code\_base}$ \5 +$(\\{count\_base}+\T{256}{}$)\C{256 delimiter code mappings}\par +\B\4\D$\\{dimen\_base}$ \5 +$(\\{del\_code\_base}+\T{256}{}$)\C{beginning of region 6}\Y\par +\B\4\D$\\{del\_code}(\|X)$ \5 +$\\{eqtb}[\\{del\_code\_base}+\|X].{}$\|i\par +\B\4\D$\\{count}(\|X)$ \5 +$\\{eqtb}[\\{count\_base}+\|X].{}$\|i\par +\B\4\D$\\{int\_par}(\|X)$ \5 +$\\{eqtb}[\\{int\_base}+\|X].{}$\|i\C{an integer parameter}\par +\B\4\D$\\{pretolerance}$ \5 +\\{int\_par}(\\{pretolerance\_code})\par +\B\4\D$\\{tolerance}$ \5 +\\{int\_par}(\\{tolerance\_code})\par +\B\4\D$\\{line\_penalty}$ \5 +\\{int\_par}(\\{line\_penalty\_code})\par +\B\4\D$\\{hyphen\_penalty}$ \5 +\\{int\_par}(\\{hyphen\_penalty\_code})\par +\B\4\D$\\{ex\_hyphen\_penalty}$ \5 +\\{int\_par}(\\{ex\_hyphen\_penalty\_code})\par +\B\4\D$\\{club\_penalty}$ \5 +\\{int\_par}(\\{club\_penalty\_code})\par +\B\4\D$\\{widow\_penalty}$ \5 +\\{int\_par}(\\{widow\_penalty\_code})\par +\B\4\D$\\{display\_widow\_penalty}$ \5 +\\{int\_par}(\\{display\_widow\_penalty\_code})\par +\B\4\D$\\{broken\_penalty}$ \5 +\\{int\_par}(\\{broken\_penalty\_code})\par +\B\4\D$\\{bin\_op\_penalty}$ \5 +\\{int\_par}(\\{bin\_op\_penalty\_code})\par +\B\4\D$\\{rel\_penalty}$ \5 +\\{int\_par}(\\{rel\_penalty\_code})\par +\B\4\D$\\{pre\_display\_penalty}$ \5 +\\{int\_par}(\\{pre\_display\_penalty\_code})\par +\B\4\D$\\{post\_display\_penalty}$ \5 +\\{int\_par}(\\{post\_display\_penalty\_code})\par +\B\4\D$\\{inter\_line\_penalty}$ \5 +\\{int\_par}(\\{inter\_line\_penalty\_code})\par +\B\4\D$\\{double\_hyphen\_demerits}$ \5 +\\{int\_par}(\\{double\_hyphen\_demerits\_code})\par +\B\4\D$\\{final\_hyphen\_demerits}$ \5 +\\{int\_par}(\\{final\_hyphen\_demerits\_code})\par +\B\4\D$\\{adj\_demerits}$ \5 +\\{int\_par}(\\{adj\_demerits\_code})\par +\B\4\D$\\{mag}$ \5 +\\{int\_par}(\\{mag\_code})\par +\B\4\D$\\{delimiter\_factor}$ \5 +\\{int\_par}(\\{delimiter\_factor\_code})\par +\B\4\D$\\{looseness}$ \5 +\\{int\_par}(\\{looseness\_code})\par +\B\4\D$\\{time}$ \5 +\\{int\_par}(\\{time\_code})\par +\B\4\D$\\{day}$ \5 +\\{int\_par}(\\{day\_code})\par +\B\4\D$\\{month}$ \5 +\\{int\_par}(\\{month\_code})\par +\B\4\D$\\{year}$ \5 +\\{int\_par}(\\{year\_code})\par +\B\4\D$\\{show\_box\_breadth}$ \5 +\\{int\_par}(\\{show\_box\_breadth\_code})\par +\B\4\D$\\{show\_box\_depth}$ \5 +\\{int\_par}(\\{show\_box\_depth\_code})\par +\B\4\D$\\{hbadness}$ \5 +\\{int\_par}(\\{hbadness\_code})\par +\B\4\D$\\{vbadness}$ \5 +\\{int\_par}(\\{vbadness\_code})\par +\B\4\D$\\{pausing}$ \5 +\\{int\_par}(\\{pausing\_code})\par +\B\4\D$\\{tracing\_online}$ \5 +\\{int\_par}(\\{tracing\_online\_code})\par +\B\4\D$\\{tracing\_macros}$ \5 +\\{int\_par}(\\{tracing\_macros\_code})\par +\B\4\D$\\{tracing\_stats}$ \5 +\\{int\_par}(\\{tracing\_stats\_code})\par +\B\4\D$\\{tracing\_paragraphs}$ \5 +\\{int\_par}(\\{tracing\_paragraphs\_code})\par +\B\4\D$\\{tracing\_pages}$ \5 +\\{int\_par}(\\{tracing\_pages\_code})\par +\B\4\D$\\{tracing\_output}$ \5 +\\{int\_par}(\\{tracing\_output\_code})\par +\B\4\D$\\{tracing\_lost\_chars}$ \5 +\\{int\_par}(\\{tracing\_lost\_chars\_code})\par +\B\4\D$\\{tracing\_commands}$ \5 +\\{int\_par}(\\{tracing\_commands\_code})\par +\B\4\D$\\{tracing\_restores}$ \5 +\\{int\_par}(\\{tracing\_restores\_code})\par +\B\4\D$\\{uc\_hyph}$ \5 +\\{int\_par}(\\{uc\_hyph\_code})\par +\B\4\D$\\{output\_penalty}$ \5 +\\{int\_par}(\\{output\_penalty\_code})\par +\B\4\D$\\{max\_dead\_cycles}$ \5 +\\{int\_par}(\\{max\_dead\_cycles\_code})\par +\B\4\D$\\{hang\_after}$ \5 +\\{int\_par}(\\{hang\_after\_code})\par +\B\4\D$\\{floating\_penalty}$ \5 +\\{int\_par}(\\{floating\_penalty\_code})\par +\B\4\D$\\{global\_defs}$ \5 +\\{int\_par}(\\{global\_defs\_code})\par +\B\4\D$\\{cur\_fam}$ \5 +\\{int\_par}(\\{cur\_fam\_code})\par +\B\4\D$\\{escape\_char}$ \5 +\\{int\_par}(\\{escape\_char\_code})\par +\B\4\D$\\{default\_hyphen\_char}$ \5 +\\{int\_par}(\\{default\_hyphen\_char\_code})\par +\B\4\D$\\{default\_skew\_char}$ \5 +\\{int\_par}(\\{default\_skew\_char\_code})\par +\B\4\D$\\{end\_line\_char}$ \5 +\\{int\_par}(\\{end\_line\_char\_code})\par +\B\4\D$\\{new\_line\_char}$ \5 +\\{int\_par}(\\{new\_line\_char\_code})\par +\B\4\D$\\{language}$ \5 +\\{int\_par}(\\{language\_code})\par +\B\4\D$\\{left\_hyphen\_min}$ \5 +\\{int\_par}(\\{left\_hyphen\_min\_code})\par +\B\4\D$\\{right\_hyphen\_min}$ \5 +\\{int\_par}(\\{right\_hyphen\_min\_code})\par +\B\4\D$\\{holding\_inserts}$ \5 +\\{int\_par}(\\{holding\_inserts\_code})\par +\B\4\D$\\{error\_context\_lines}$ \5 +\\{int\_par}(\\{error\_context\_lines\_code})\par +\Y\B\4\X236:Assign the values \\{depth\_threshold}: $\K$ \\{show\_box\_depth} and \\{breadth\_max}: $\K$ \\{show\_box\_breadth}\X${}\E{}$\6 +$\\{depth\_threshold}\K\\{show\_box\_depth};$ $\\{breadth\_max}\K{}$\\{show\_box\_breadth}\par +\U198.\fi + +\M{237}We can print the symbolic name of an integer parameter as follows. + +\Y\B\&{void} \\{print\_param}(\&{int} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\&{switch} (\|n)\5 +${}\{{}$\1\6 +\4\&{case} \\{pretolerance\_code}:\5 +\\{print\_esc}(\X1446:\.{"pretolerance"}\X);\5 +\&{break};\6 +\4\&{case} \\{tolerance\_code}:\5 +\\{print\_esc}(\X1447:\.{"tolerance"}\X);\5 +\&{break};\6 +\4\&{case} \\{line\_penalty\_code}:\5 +\\{print\_esc}(\X1448:\.{"linepenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{hyphen\_penalty\_code}:\5 +\\{print\_esc}(\X1449:\.{"hyphenpenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{ex\_hyphen\_penalty\_code}:\5 +\\{print\_esc}(\X1450:\.{"exhyphenpenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{club\_penalty\_code}:\5 +\\{print\_esc}(\X1451:\.{"clubpenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{widow\_penalty\_code}:\5 +\\{print\_esc}(\X1452:\.{"widowpenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{display\_widow\_penalty\_code}:\5 +\\{print\_esc}(\X1453:\.{"displaywidowpenalty}\)\.{"}\X);\5 +\&{break};\6 +\4\&{case} \\{broken\_penalty\_code}:\5 +\\{print\_esc}(\X1454:\.{"brokenpenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{bin\_op\_penalty\_code}:\5 +\\{print\_esc}(\X1455:\.{"binoppenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{rel\_penalty\_code}:\5 +\\{print\_esc}(\X1456:\.{"relpenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{pre\_display\_penalty\_code}:\5 +\\{print\_esc}(\X1457:\.{"predisplaypenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{post\_display\_penalty\_code}:\5 +\\{print\_esc}(\X1458:\.{"postdisplaypenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{inter\_line\_penalty\_code}:\5 +\\{print\_esc}(\X1459:\.{"interlinepenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{double\_hyphen\_demerits\_code}:\5 +\\{print\_esc}(\X1460:\.{"doublehyphendemerit}\)\.{s"}\X);\5 +\&{break};\6 +\4\&{case} \\{final\_hyphen\_demerits\_code}:\5 +\\{print\_esc}(\X1461:\.{"finalhyphendemerits}\)\.{"}\X);\5 +\&{break};\6 +\4\&{case} \\{adj\_demerits\_code}:\5 +\\{print\_esc}(\X1462:\.{"adjdemerits"}\X);\5 +\&{break};\6 +\4\&{case} \\{mag\_code}:\5 +\\{print\_esc}(\X1463:\.{"mag"}\X);\5 +\&{break};\6 +\4\&{case} \\{delimiter\_factor\_code}:\5 +\\{print\_esc}(\X1464:\.{"delimiterfactor"}\X);\5 +\&{break};\6 +\4\&{case} \\{looseness\_code}:\5 +\\{print\_esc}(\X1465:\.{"looseness"}\X);\5 +\&{break};\6 +\4\&{case} \\{time\_code}:\5 +\\{print\_esc}(\X1466:\.{"time"}\X);\5 +\&{break};\6 +\4\&{case} \\{day\_code}:\5 +\\{print\_esc}(\X1467:\.{"day"}\X);\5 +\&{break};\6 +\4\&{case} \\{month\_code}:\5 +\\{print\_esc}(\X1468:\.{"month"}\X);\5 +\&{break};\6 +\4\&{case} \\{year\_code}:\5 +\\{print\_esc}(\X1469:\.{"year"}\X);\5 +\&{break};\6 +\4\&{case} \\{show\_box\_breadth\_code}:\5 +\\{print\_esc}(\X1470:\.{"showboxbreadth"}\X);\5 +\&{break};\6 +\4\&{case} \\{show\_box\_depth\_code}:\5 +\\{print\_esc}(\X1471:\.{"showboxdepth"}\X);\5 +\&{break};\6 +\4\&{case} \\{hbadness\_code}:\5 +\\{print\_esc}(\X1472:\.{"hbadness"}\X);\5 +\&{break};\6 +\4\&{case} \\{vbadness\_code}:\5 +\\{print\_esc}(\X1473:\.{"vbadness"}\X);\5 +\&{break};\6 +\4\&{case} \\{pausing\_code}:\5 +\\{print\_esc}(\X1474:\.{"pausing"}\X);\5 +\&{break};\6 +\4\&{case} \\{tracing\_online\_code}:\5 +\\{print\_esc}(\X1475:\.{"tracingonline"}\X);\5 +\&{break};\6 +\4\&{case} \\{tracing\_macros\_code}:\5 +\\{print\_esc}(\X1476:\.{"tracingmacros"}\X);\5 +\&{break};\6 +\4\&{case} \\{tracing\_stats\_code}:\5 +\\{print\_esc}(\X1477:\.{"tracingstats"}\X);\5 +\&{break};\6 +\4\&{case} \\{tracing\_paragraphs\_code}:\5 +\\{print\_esc}(\X1478:\.{"tracingparagraphs"}\X);\5 +\&{break};\6 +\4\&{case} \\{tracing\_pages\_code}:\5 +\\{print\_esc}(\X1479:\.{"tracingpages"}\X);\5 +\&{break};\6 +\4\&{case} \\{tracing\_output\_code}:\5 +\\{print\_esc}(\X1480:\.{"tracingoutput"}\X);\5 +\&{break};\6 +\4\&{case} \\{tracing\_lost\_chars\_code}:\5 +\\{print\_esc}(\X1481:\.{"tracinglostchars"}\X);\5 +\&{break};\6 +\4\&{case} \\{tracing\_commands\_code}:\5 +\\{print\_esc}(\X1482:\.{"tracingcommands"}\X);\5 +\&{break};\6 +\4\&{case} \\{tracing\_restores\_code}:\5 +\\{print\_esc}(\X1483:\.{"tracingrestores"}\X);\5 +\&{break};\6 +\4\&{case} \\{uc\_hyph\_code}:\5 +\\{print\_esc}(\X1484:\.{"uchyph"}\X);\5 +\&{break};\6 +\4\&{case} \\{output\_penalty\_code}:\5 +\\{print\_esc}(\X1485:\.{"outputpenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{max\_dead\_cycles\_code}:\5 +\\{print\_esc}(\X1486:\.{"maxdeadcycles"}\X);\5 +\&{break};\6 +\4\&{case} \\{hang\_after\_code}:\5 +\\{print\_esc}(\X1487:\.{"hangafter"}\X);\5 +\&{break};\6 +\4\&{case} \\{floating\_penalty\_code}:\5 +\\{print\_esc}(\X1488:\.{"floatingpenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{global\_defs\_code}:\5 +\\{print\_esc}(\X1489:\.{"globaldefs"}\X);\5 +\&{break};\6 +\4\&{case} \\{cur\_fam\_code}:\5 +\\{print\_esc}(\X1490:\.{"fam"}\X);\5 +\&{break};\6 +\4\&{case} \\{escape\_char\_code}:\5 +\\{print\_esc}(\X1491:\.{"escapechar"}\X);\5 +\&{break};\6 +\4\&{case} \\{default\_hyphen\_char\_code}:\5 +\\{print\_esc}(\X1492:\.{"defaulthyphenchar"}\X);\5 +\&{break};\6 +\4\&{case} \\{default\_skew\_char\_code}:\5 +\\{print\_esc}(\X1493:\.{"defaultskewchar"}\X);\5 +\&{break};\6 +\4\&{case} \\{end\_line\_char\_code}:\5 +\\{print\_esc}(\X1494:\.{"endlinechar"}\X);\5 +\&{break};\6 +\4\&{case} \\{new\_line\_char\_code}:\5 +\\{print\_esc}(\X1495:\.{"newlinechar"}\X);\5 +\&{break};\6 +\4\&{case} \\{language\_code}:\5 +\\{print\_esc}(\X1496:\.{"language"}\X);\5 +\&{break};\6 +\4\&{case} \\{left\_hyphen\_min\_code}:\5 +\\{print\_esc}(\X1497:\.{"lefthyphenmin"}\X);\5 +\&{break};\6 +\4\&{case} \\{right\_hyphen\_min\_code}:\5 +\\{print\_esc}(\X1498:\.{"righthyphenmin"}\X);\5 +\&{break};\6 +\4\&{case} \\{holding\_inserts\_code}:\5 +\\{print\_esc}(\X1499:\.{"holdinginserts"}\X);\5 +\&{break};\6 +\4\&{case} \\{error\_context\_lines\_code}:\5 +\\{print\_esc}(\X1500:\.{"errorcontextlines"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_str}(\.{"[unknown\ integer\ pa}\)\.{rameter!]"});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{238}The integer parameter names must be entered into the hash table. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1446:\.{"pretolerance"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{pretolerance\_code}){}$;\6 +${}\\{primitive}(\X1447:\.{"tolerance"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tolerance\_code}){}$;\6 +${}\\{primitive}(\X1448:\.{"linepenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{line\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1449:\.{"hyphenpenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{hyphen\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1450:\.{"exhyphenpenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{ex\_hyphen\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1451:\.{"clubpenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{club\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1452:\.{"widowpenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{widow\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1453:\.{"displaywidowpenalty}\)\.{"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{display\_widow\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1454:\.{"brokenpenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{broken\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1455:\.{"binoppenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{bin\_op\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1456:\.{"relpenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{rel\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1457:\.{"predisplaypenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{pre\_display\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1458:\.{"postdisplaypenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{post\_display\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1459:\.{"interlinepenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{inter\_line\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1460:\.{"doublehyphendemerit}\)\.{s"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{double\_hyphen\_demerits\_code}){}$;\6 +${}\\{primitive}(\X1461:\.{"finalhyphendemerits}\)\.{"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{final\_hyphen\_demerits\_code}){}$;\6 +${}\\{primitive}(\X1462:\.{"adjdemerits"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{adj\_demerits\_code}){}$;\6 +${}\\{primitive}(\X1463:\.{"mag"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{mag\_code}){}$;\6 +${}\\{primitive}(\X1464:\.{"delimiterfactor"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{delimiter\_factor\_code}){}$;\6 +${}\\{primitive}(\X1465:\.{"looseness"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{looseness\_code}){}$;\6 +${}\\{primitive}(\X1466:\.{"time"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{time\_code}){}$;\6 +${}\\{primitive}(\X1467:\.{"day"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{day\_code}){}$;\6 +${}\\{primitive}(\X1468:\.{"month"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{month\_code}){}$;\6 +${}\\{primitive}(\X1469:\.{"year"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{year\_code}){}$;\6 +${}\\{primitive}(\X1470:\.{"showboxbreadth"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{show\_box\_breadth\_code}){}$;\6 +${}\\{primitive}(\X1471:\.{"showboxdepth"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{show\_box\_depth\_code}){}$;\6 +${}\\{primitive}(\X1472:\.{"hbadness"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{hbadness\_code}){}$;\6 +${}\\{primitive}(\X1473:\.{"vbadness"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{vbadness\_code}){}$;\6 +${}\\{primitive}(\X1474:\.{"pausing"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{pausing\_code}){}$;\6 +${}\\{primitive}(\X1475:\.{"tracingonline"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tracing\_online\_code}){}$;\6 +${}\\{primitive}(\X1476:\.{"tracingmacros"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tracing\_macros\_code}){}$;\6 +${}\\{primitive}(\X1477:\.{"tracingstats"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tracing\_stats\_code}){}$;\6 +${}\\{primitive}(\X1478:\.{"tracingparagraphs"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tracing\_paragraphs\_code}){}$;\6 +${}\\{primitive}(\X1479:\.{"tracingpages"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tracing\_pages\_code}){}$;\6 +${}\\{primitive}(\X1480:\.{"tracingoutput"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tracing\_output\_code}){}$;\6 +${}\\{primitive}(\X1481:\.{"tracinglostchars"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tracing\_lost\_chars\_code}){}$;\6 +${}\\{primitive}(\X1482:\.{"tracingcommands"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tracing\_commands\_code}){}$;\6 +${}\\{primitive}(\X1483:\.{"tracingrestores"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{tracing\_restores\_code}){}$;\6 +${}\\{primitive}(\X1484:\.{"uchyph"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{uc\_hyph\_code}){}$;\6 +${}\\{primitive}(\X1485:\.{"outputpenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{output\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1486:\.{"maxdeadcycles"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{max\_dead\_cycles\_code}){}$;\6 +${}\\{primitive}(\X1487:\.{"hangafter"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{hang\_after\_code}){}$;\6 +${}\\{primitive}(\X1488:\.{"floatingpenalty"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{floating\_penalty\_code}){}$;\6 +${}\\{primitive}(\X1489:\.{"globaldefs"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{global\_defs\_code}){}$;\6 +${}\\{primitive}(\X1490:\.{"fam"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{cur\_fam\_code}){}$;\6 +${}\\{primitive}(\X1491:\.{"escapechar"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{escape\_char\_code}){}$;\6 +${}\\{primitive}(\X1492:\.{"defaulthyphenchar"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{default\_hyphen\_char\_code}){}$;\6 +${}\\{primitive}(\X1493:\.{"defaultskewchar"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{default\_skew\_char\_code}){}$;\6 +${}\\{primitive}(\X1494:\.{"endlinechar"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{end\_line\_char\_code}){}$;\6 +${}\\{primitive}(\X1495:\.{"newlinechar"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{new\_line\_char\_code}){}$;\6 +${}\\{primitive}(\X1496:\.{"language"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{language\_code}){}$;\6 +${}\\{primitive}(\X1497:\.{"lefthyphenmin"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{left\_hyphen\_min\_code}){}$;\6 +${}\\{primitive}(\X1498:\.{"righthyphenmin"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{right\_hyphen\_min\_code}){}$;\6 +${}\\{primitive}(\X1499:\.{"holdinginserts"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{holding\_inserts\_code}){}$;\6 +${}\\{primitive}(\X1500:\.{"errorcontextlines"}\X,\39\\{assign\_int},\39\\{int\_base}+\\{error\_context\_lines\_code}){}$;\par +\fi + +\M{239}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{assign\_int}:\6 +\&{if} ${}(\\{chr\_code}<\\{count\_base}){}$\1\5 +${}\\{print\_param}(\\{chr\_code}-\\{int\_base});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1501:\.{"count"}\X);\5 +${}\\{print\_int}(\\{chr\_code}-\\{count\_base});{}$\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{240}The integer parameters should really be initialized by a macro package; +the following initialization does the minimum to keep \TeX\ from +complete failure. + +\Y\B\4\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|k\K\\{int\_base};{}$ ${}\|k\Z\\{del\_code\_base}-\T{1};{}$ ${}\|k\PP){}$\1\5 +${}\\{eqtb}[\|k].\|i\K\T{0};{}$\2\6 +${}\\{mag}\K\T{1000};{}$\5 +${}\\{tolerance}\K\T{10000};{}$\5 +${}\\{hang\_after}\K\T{1};{}$\5 +${}\\{max\_dead\_cycles}\K\T{25};{}$\5 +${}\\{escape\_char}\K\.{'\\\\'};{}$\5 +${}\\{end\_line\_char}\K\\{carriage\_return};{}$\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{255};{}$ ${}\|k\PP){}$\1\5 +${}\\{del\_code}(\|k)\K{-}\T{1};{}$\2\6 +${}\\{del\_code}(\.{'.'})\K\T{0}{}$;\C{this null delimiter is used in error recovery}\par +\fi + +\M{241}The following procedure, which is called just before \TeX\ initializes its +input and output, establishes the initial values of the date and time. +Since standard \PASCAL\ cannot provide such information, something special +is needed. The program here simply specifies July 4, 1776, at noon; but +users probably want a better approximation to the truth. + +\Y\B\&{void} \\{fix\_date\_and\_time}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{time}\K\T{12}*\T{60}{}$;\C{minutes since midnight}\6 +${}\\{day}\K\T{4}{}$;\C{fourth day of the month}\6 +${}\\{month}\K\T{7}{}$;\C{seventh month of the year}\6 +${}\\{year}\K\T{1776}{}$;\C{Anno Domini}\6 +\4${}\}{}$\2\par +\fi + +\M{242}\B\X242:Show equivalent \|n, in region 5\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\|n<\\{count\_base}){}$\1\5 +${}\\{print\_param}(\|n-\\{int\_base});{}$\2\6 +\&{else} \&{if} ${}(\|n<\\{del\_code\_base}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1501:\.{"count"}\X);\5 +${}\\{print\_int}(\|n-\\{count\_base});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1502:\.{"delcode"}\X);\5 +${}\\{print\_int}(\|n-\\{del\_code\_base});{}$\6 +\4${}\}{}$\2\6 +\\{print\_char}(\.{'='});\5 +${}\\{print\_int}(\\{eqtb}[\|n].\|i);{}$\6 +\4${}\}{}$\2\par +\U252.\fi + +\M{243}\B\X243:Set variable \|c to the current escape character\X${}\E{}$\6 +$\|c\K{}$\\{escape\_char}\par +\U63.\fi + +\M{244}\B\X244:Character \|s is the current new-line character\X${}\E{}$\6 +$\|s\E{}$\\{new\_line\_char}\par +\Us58\ET59.\fi + +\M{245}\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\B\&{void} \\{begin\_diagnostic}(\&{void})\C{prepare to do some tracing}\6 +${}\{{}$\5 +\1${}\\{old\_setting}\K\\{selector};{}$\6 +\&{if} ${}((\\{tracing\_online}\Z\T{0})\W(\\{selector}\E\\{term\_and\_log})){}$\5 +${}\{{}$\5 +\1\\{decr}(\\{selector});\6 +\&{if} ${}(\\{history}\E\\{spotless}){}$\1\5 +${}\\{history}\K\\{warning\_issued};{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\7 +\&{void} \\{end\_diagnostic}(\&{bool} \\{blank\_line})\C{restore proper conditions after tracing}\6 +${}\{{}$\5 +\1\\{print\_nl}(\.{""});\6 +\&{if} (\\{blank\_line})\1\5 +\\{print\_ln}(\,);\2\6 +${}\\{selector}\K\\{old\_setting};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{246}Of course we had better declare another global variable, if the previous +routines are going to work. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{uint8\_t} \\{old\_setting};\par +\fi + +\M{247}The final region of \\{eqtb} contains the dimension parameters defined +here, and the 256 \.{\\dimen} registers. + +\Y\B\4\D$\\{par\_indent\_code}$ \5 +\T{0}\C{indentation of paragraphs}\par +\B\4\D$\\{math\_surround\_code}$ \5 +\T{1}\C{space around math in text}\par +\B\4\D$\\{line\_skip\_limit\_code}$ \5 +\T{2}\C{threshold for \\{line\_skip} instead of \\{baseline\_skip}}\par +\B\4\D$\\{hsize\_code}$ \5 +\T{3}\C{line width in horizontal mode}\par +\B\4\D$\\{vsize\_code}$ \5 +\T{4}\C{page height in vertical mode}\par +\B\4\D$\\{max\_depth\_code}$ \5 +\T{5}\C{maximum depth of boxes on main pages}\par +\B\4\D$\\{split\_max\_depth\_code}$ \5 +\T{6}\C{maximum depth of boxes on split pages}\par +\B\4\D$\\{box\_max\_depth\_code}$ \5 +\T{7}\C{maximum depth of explicit vboxes}\par +\B\4\D$\\{hfuzz\_code}$ \5 +\T{8}\C{tolerance for overfull hbox messages}\par +\B\4\D$\\{vfuzz\_code}$ \5 +\T{9}\C{tolerance for overfull vbox messages}\par +\B\4\D$\\{delimiter\_shortfall\_code}$ \5 +\T{10}\C{maximum amount uncovered by variable delimiters}\par +\B\4\D$\\{null\_delimiter\_space\_code}$ \5 +\T{11}\C{blank space in null delimiters}\par +\B\4\D$\\{script\_space\_code}$ \5 +\T{12}\C{extra space after subscript or superscript}\par +\B\4\D$\\{pre\_display\_size\_code}$ \5 +\T{13}\C{length of text preceding a display}\par +\B\4\D$\\{display\_width\_code}$ \5 +\T{14}\C{length of line for displayed equation}\par +\B\4\D$\\{display\_indent\_code}$ \5 +\T{15}\C{indentation of line for displayed equation}\par +\B\4\D$\\{overfull\_rule\_code}$ \5 +\T{16}\C{width of rule that identifies overfull hboxes}\par +\B\4\D$\\{hang\_indent\_code}$ \5 +\T{17}\C{amount of hanging indentation}\par +\B\4\D$\\{h\_offset\_code}$ \5 +\T{18}\C{amount of horizontal offset when shipping pages out}\par +\B\4\D$\\{v\_offset\_code}$ \5 +\T{19}\C{amount of vertical offset when shipping pages out}\par +\B\4\D$\\{emergency\_stretch\_code}$ \5 +\T{20}\C{reduces badnesses on final pass of line-breaking}\par +\B\4\D$\\{dimen\_pars}$ \5 +\T{21}\C{total number of dimension parameters}\par +\B\4\D$\\{scaled\_base}$ \5 +$(\\{dimen\_base}+\\{dimen\_pars}{}$)\C{table of 256 user-defined \.{\\dimen} registers}\par +\B\4\D$\\{eqtb\_size}$ \5 +$(\\{scaled\_base}+\T{255}{}$)\C{largest subscript of \\{eqtb}}\Y\par +\B\4\D$\\{dimen}(\|X)$ \5 +$\\{eqtb}[\\{scaled\_base}+\|X].{}$\\{sc}\par +\B\4\D$\\{dimen\_par}(\|X)$ \5 +$\\{eqtb}[\\{dimen\_base}+\|X].{}$\\{sc}\C{a scaled quantity}\par +\B\4\D$\\{par\_indent}$ \5 +\\{dimen\_par}(\\{par\_indent\_code})\par +\B\4\D$\\{math\_surround}$ \5 +\\{dimen\_par}(\\{math\_surround\_code})\par +\B\4\D$\\{line\_skip\_limit}$ \5 +\\{dimen\_par}(\\{line\_skip\_limit\_code})\par +\B\4\D$\\{hsize}$ \5 +\\{dimen\_par}(\\{hsize\_code})\par +\B\4\D$\\{vsize}$ \5 +\\{dimen\_par}(\\{vsize\_code})\par +\B\4\D$\\{max\_depth}$ \5 +\\{dimen\_par}(\\{max\_depth\_code})\par +\B\4\D$\\{split\_max\_depth}$ \5 +\\{dimen\_par}(\\{split\_max\_depth\_code})\par +\B\4\D$\\{box\_max\_depth}$ \5 +\\{dimen\_par}(\\{box\_max\_depth\_code})\par +\B\4\D$\\{hfuzz}$ \5 +\\{dimen\_par}(\\{hfuzz\_code})\par +\B\4\D$\\{vfuzz}$ \5 +\\{dimen\_par}(\\{vfuzz\_code})\par +\B\4\D$\\{delimiter\_shortfall}$ \5 +\\{dimen\_par}(\\{delimiter\_shortfall\_code})\par +\B\4\D$\\{null\_delimiter\_space}$ \5 +\\{dimen\_par}(\\{null\_delimiter\_space\_code})\par +\B\4\D$\\{script\_space}$ \5 +\\{dimen\_par}(\\{script\_space\_code})\par +\B\4\D$\\{pre\_display\_size}$ \5 +\\{dimen\_par}(\\{pre\_display\_size\_code})\par +\B\4\D$\\{display\_width}$ \5 +\\{dimen\_par}(\\{display\_width\_code})\par +\B\4\D$\\{display\_indent}$ \5 +\\{dimen\_par}(\\{display\_indent\_code})\par +\B\4\D$\\{overfull\_rule}$ \5 +\\{dimen\_par}(\\{overfull\_rule\_code})\par +\B\4\D$\\{hang\_indent}$ \5 +\\{dimen\_par}(\\{hang\_indent\_code})\par +\B\4\D$\\{h\_offset}$ \5 +\\{dimen\_par}(\\{h\_offset\_code})\par +\B\4\D$\\{v\_offset}$ \5 +\\{dimen\_par}(\\{v\_offset\_code})\par +\B\4\D$\\{emergency\_stretch}$ \5 +\\{dimen\_par}(\\{emergency\_stretch\_code})\par +\Y\B\&{void} \\{print\_length\_param}(\&{int} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\&{switch} (\|n)\5 +${}\{{}$\1\6 +\4\&{case} \\{par\_indent\_code}:\5 +\\{print\_esc}(\X1503:\.{"parindent"}\X);\5 +\&{break};\6 +\4\&{case} \\{math\_surround\_code}:\5 +\\{print\_esc}(\X1504:\.{"mathsurround"}\X);\5 +\&{break};\6 +\4\&{case} \\{line\_skip\_limit\_code}:\5 +\\{print\_esc}(\X1505:\.{"lineskiplimit"}\X);\5 +\&{break};\6 +\4\&{case} \\{hsize\_code}:\5 +\\{print\_esc}(\X1506:\.{"hsize"}\X);\5 +\&{break};\6 +\4\&{case} \\{vsize\_code}:\5 +\\{print\_esc}(\X1507:\.{"vsize"}\X);\5 +\&{break};\6 +\4\&{case} \\{max\_depth\_code}:\5 +\\{print\_esc}(\X1508:\.{"maxdepth"}\X);\5 +\&{break};\6 +\4\&{case} \\{split\_max\_depth\_code}:\5 +\\{print\_esc}(\X1509:\.{"splitmaxdepth"}\X);\5 +\&{break};\6 +\4\&{case} \\{box\_max\_depth\_code}:\5 +\\{print\_esc}(\X1510:\.{"boxmaxdepth"}\X);\5 +\&{break};\6 +\4\&{case} \\{hfuzz\_code}:\5 +\\{print\_esc}(\X1511:\.{"hfuzz"}\X);\5 +\&{break};\6 +\4\&{case} \\{vfuzz\_code}:\5 +\\{print\_esc}(\X1512:\.{"vfuzz"}\X);\5 +\&{break};\6 +\4\&{case} \\{delimiter\_shortfall\_code}:\5 +\\{print\_esc}(\X1513:\.{"delimitershortfall"}\X);\5 +\&{break};\6 +\4\&{case} \\{null\_delimiter\_space\_code}:\5 +\\{print\_esc}(\X1514:\.{"nulldelimiterspace"}\X);\5 +\&{break};\6 +\4\&{case} \\{script\_space\_code}:\5 +\\{print\_esc}(\X1515:\.{"scriptspace"}\X);\5 +\&{break};\6 +\4\&{case} \\{pre\_display\_size\_code}:\5 +\\{print\_esc}(\X1516:\.{"predisplaysize"}\X);\5 +\&{break};\6 +\4\&{case} \\{display\_width\_code}:\5 +\\{print\_esc}(\X1517:\.{"displaywidth"}\X);\5 +\&{break};\6 +\4\&{case} \\{display\_indent\_code}:\5 +\\{print\_esc}(\X1518:\.{"displayindent"}\X);\5 +\&{break};\6 +\4\&{case} \\{overfull\_rule\_code}:\5 +\\{print\_esc}(\X1519:\.{"overfullrule"}\X);\5 +\&{break};\6 +\4\&{case} \\{hang\_indent\_code}:\5 +\\{print\_esc}(\X1520:\.{"hangindent"}\X);\5 +\&{break};\6 +\4\&{case} \\{h\_offset\_code}:\5 +\\{print\_esc}(\X1521:\.{"hoffset"}\X);\5 +\&{break};\6 +\4\&{case} \\{v\_offset\_code}:\5 +\\{print\_esc}(\X1522:\.{"voffset"}\X);\5 +\&{break};\6 +\4\&{case} \\{emergency\_stretch\_code}:\5 +\\{print\_esc}(\X1523:\.{"emergencystretch"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_str}(\.{"[unknown\ dimen\ para}\)\.{meter!]"});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{248}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1503:\.{"parindent"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{par\_indent\_code}){}$;\6 +${}\\{primitive}(\X1504:\.{"mathsurround"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{math\_surround\_code}){}$;\6 +${}\\{primitive}(\X1505:\.{"lineskiplimit"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{line\_skip\_limit\_code}){}$;\6 +${}\\{primitive}(\X1506:\.{"hsize"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{hsize\_code}){}$;\6 +${}\\{primitive}(\X1507:\.{"vsize"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{vsize\_code}){}$;\6 +${}\\{primitive}(\X1508:\.{"maxdepth"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{max\_depth\_code}){}$;\6 +${}\\{primitive}(\X1509:\.{"splitmaxdepth"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{split\_max\_depth\_code}){}$;\6 +${}\\{primitive}(\X1510:\.{"boxmaxdepth"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{box\_max\_depth\_code}){}$;\6 +${}\\{primitive}(\X1511:\.{"hfuzz"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{hfuzz\_code}){}$;\6 +${}\\{primitive}(\X1512:\.{"vfuzz"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{vfuzz\_code}){}$;\6 +${}\\{primitive}(\X1513:\.{"delimitershortfall"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{delimiter\_shortfall\_code}){}$;\6 +${}\\{primitive}(\X1514:\.{"nulldelimiterspace"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{null\_delimiter\_space\_code}){}$;\6 +${}\\{primitive}(\X1515:\.{"scriptspace"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{script\_space\_code}){}$;\6 +${}\\{primitive}(\X1516:\.{"predisplaysize"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{pre\_display\_size\_code}){}$;\6 +${}\\{primitive}(\X1517:\.{"displaywidth"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{display\_width\_code}){}$;\6 +${}\\{primitive}(\X1518:\.{"displayindent"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{display\_indent\_code}){}$;\6 +${}\\{primitive}(\X1519:\.{"overfullrule"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{overfull\_rule\_code}){}$;\6 +${}\\{primitive}(\X1520:\.{"hangindent"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{hang\_indent\_code}){}$;\6 +${}\\{primitive}(\X1521:\.{"hoffset"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{h\_offset\_code}){}$;\6 +${}\\{primitive}(\X1522:\.{"voffset"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{v\_offset\_code}){}$;\6 +${}\\{primitive}(\X1523:\.{"emergencystretch"}\X,\39\\{assign\_dimen},\39\\{dimen\_base}+\\{emergency\_stretch\_code}){}$;\par +\fi + +\M{249}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{assign\_dimen}:\6 +\&{if} ${}(\\{chr\_code}<\\{scaled\_base}){}$\1\5 +${}\\{print\_length\_param}(\\{chr\_code}-\\{dimen\_base});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1524:\.{"dimen"}\X);\5 +${}\\{print\_int}(\\{chr\_code}-\\{scaled\_base});{}$\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{250}\B\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|k\K\\{dimen\_base};{}$ ${}\|k\Z\\{eqtb\_size};{}$ ${}\|k\PP){}$\1\5 +${}\\{eqtb}[\|k].\\{sc}\K\T{0}{}$;\2\par +\fi + +\M{251}\B\X251:Show equivalent \|n, in region 6\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\|n<\\{scaled\_base}){}$\1\5 +${}\\{print\_length\_param}(\|n-\\{dimen\_base});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1524:\.{"dimen"}\X);\5 +${}\\{print\_int}(\|n-\\{scaled\_base});{}$\6 +\4${}\}{}$\2\6 +\\{print\_char}(\.{'='});\5 +${}\\{print\_scaled}(\\{eqtb}[\|n].\\{sc});{}$\5 +\\{print\_str}(\.{"pt"});\6 +\4${}\}{}$\2\par +\U252.\fi + +\M{252}Here is a procedure that displays the contents of \\{eqtb}[\|n] +symbolically. + +\Y\B\hbox{\4}\X298:Declare the procedure called \\{print\_cmd\_chr}\X\6 +\8\#\&{ifdef} \.{STAT}\7 +\&{void} \\{show\_eqtb}(\&{pointer} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\|n<\\{active\_base}){}$\1\5 +\\{print\_char}(\.{'?'});\C{this can't happen}\2\6 +\&{else} \&{if} ${}(\|n<\\{glue\_base}){}$\1\5 +\X223:Show equivalent \|n, in region 1 or 2\X\2\6 +\&{else} \&{if} ${}(\|n<\\{local\_base}){}$\1\5 +\X229:Show equivalent \|n, in region 3\X\2\6 +\&{else} \&{if} ${}(\|n<\\{int\_base}){}$\1\5 +\X233:Show equivalent \|n, in region 4\X\2\6 +\&{else} \&{if} ${}(\|n<\\{dimen\_base}){}$\1\5 +\X242:Show equivalent \|n, in region 5\X\2\6 +\&{else} \&{if} ${}(\|n\Z\\{eqtb\_size}){}$\1\5 +\X251:Show equivalent \|n, in region 6\X\2\6 +\&{else}\1\5 +\\{print\_char}(\.{'?'});\C{this can't happen either}\2\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\M{253}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{memory\_word} ${}\\{eqtb0}[\\{eqtb\_size}-\\{active\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{eqtb}\K\\{eqtb0}-\\{active\_base};{}$\6 +\&{quarterword} ${}\\{xeq\_level0}[\\{eqtb\_size}-\\{int\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{xeq\_level}\K\\{xeq\_level0}-\\{int\_base}{}$;\par +\fi + +\M{254}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|k\K\\{int\_base};{}$ ${}\|k\Z\\{eqtb\_size};{}$ ${}\|k\PP){}$\1\5 +${}\\{xeq\_level}[\|k]\K\\{level\_one}{}$;\2\par +\fi + +\M{255}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\B\4\X255:Search \\{eqtb} for equivalents equal to \|p\X${}\E{}$\6 +\&{for} ${}(\|q\K\\{active\_base};{}$ ${}\|q\Z\\{box\_base}+\T{255};{}$ ${}\|q\PP){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{equiv}(\|q)\E\|p){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"EQUIV("});\5 +\\{print\_int}(\|q);\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U172.\fi + +\N{1}{256}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)\E\T{0}$; if position \|p is either empty or the end of a coalesced +hash list, we have $\\{next}(\|p)\E\T{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\B\4\D$\\{next}(\|X)$ \5 +$\\{hash}[\|X].{}$\\{lh}\C{link for coalesced lists}\par +\B\4\D$\\{text}(\|X)$ \5 +$\\{hash}[\|X].{}$\\{rh}\C{string number for control sequence name}\par +\B\4\D$\\{hash\_is\_full}$ \5 +$(\\{hash\_used}\E\\{hash\_base}{}$)\C{test if all positions are occupied}\par +\B\4\D$\\{font\_id\_text}(\|X)$ \5 +$\\{text}(\\{font\_id\_base}+\|X{}$)\C{a frozen font identifier's name}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{two\_halves} ${}\\{hash0}[\\{undefined\_control\_sequence}-\\{hash\_base}],{}$ ${}{*\&{const}\ }\\{hash}\K\\{hash0}-\\{hash\_base}{}$;\C{the hash table}\6 +\&{pointer} \\{hash\_used};\C{allocation pointer for \\{hash}}\6 +\&{bool} \\{no\_new\_control\_sequence};\C{are new identifiers legal?}\6 +\&{int} \\{cs\_count};\C{total number of known identifiers}\par +\fi + +\M{257}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{no\_new\_control\_sequence}\K\\{true}{}$;\C{new identifiers are usually forbidden}\6 +${}\\{next}(\\{hash\_base})\K\T{0};{}$\5 +${}\\{text}(\\{hash\_base})\K\T{0};{}$\6 +\&{for} ${}(\|k\K\\{hash\_base}+\T{1};{}$ ${}\|k\Z\\{undefined\_control\_sequence}-\T{1};{}$ ${}\|k\PP){}$\1\5 +${}\\{hash}[\|k]\K\\{hash}[\\{hash\_base}]{}$;\2\par +\fi + +\M{258}\B\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\6 +$\\{hash\_used}\K\\{frozen\_control\_sequence}{}$;\C{nothing is used}\6 +${}\\{cs\_count}\K\T{0};{}$\5 +${}\\{eq\_type}(\\{frozen\_dont\_expand})\K\\{dont\_expand};{}$\5 +${}\\{text}(\\{frozen\_dont\_expand})\K\X1525:\.{"notexpanded:"}\X{}$;\par +\fi + +\M{259}Here is the subroutine that searches the hash table for an identifier +that matches a given string of length $\|l>\T{1}$ appearing in $\\{buffer}[\|j\dotdot(\|j+\|l-\T{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\B\&{pointer} \\{id\_lookup}(\&{int} \|j${},\39{}$\&{int} \|l)\C{search the hash table}\6 +${}\{{}$\5 +\C{go here if you found it}\1\6 +\&{int} \|h;\C{hash code}\6 +\&{int} \|d;\C{number of characters in incomplete current string}\6 +\&{pointer} \|p;\C{index in \\{hash} array}\6 +\&{pointer} \|k;\C{index in \\{buffer} array}\7 +\X261:Compute the hash code \|h\X;\6 +${}\|p\K\|h+\\{hash\_base}{}$;\C{we start searching here; note that $\T{0}\Z\|h<\\{hash\_prime}$}\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{text}(\|p)>\T{0}){}$\1\6 +\&{if} ${}(\\{length}(\\{text}(\|p))\E\|l){}$\1\6 +\&{if} ${}(\\{str\_eq\_buf}(\\{text}(\|p),\39\|j)){}$\1\5 +\&{goto} \\{found};\2\2\2\6 +\&{if} ${}(\\{next}(\|p)\E\T{0}){}$\5 +${}\{{}$\5 +\1\&{if} (\\{no\_new\_control\_sequence})\1\5 +${}\|p\K\\{undefined\_control\_sequence};{}$\2\6 +\&{else}\1\5 +\X260:Insert a new control sequence after \|p, then make \|p point to it\X;\2\6 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +${}\|p\K\\{next}(\|p);{}$\6 +\4${}\}{}$\2\6 +\4\\{found}:\5 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{260}\B\X260:Insert a new control sequence after \|p, then make \|p point to it\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{text}(\|p)>\T{0}){}$\5 +${}\{{}$\5 +\1\&{do}\5 +${}\{{}$\1\6 +\&{if} (\\{hash\_is\_full})\1\5 +${}\\{overflow}(\.{"hash\ size"},\39\\{hash\_size});{}$\2\6 +\\{decr}(\\{hash\_used});\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{text}(\\{hash\_used})\E\T{0})){}$;\C{search for an empty location in \\{hash}}\6 +${}\\{next}(\|p)\K\\{hash\_used};{}$\5 +${}\|p\K\\{hash\_used};{}$\6 +\4${}\}{}$\2\6 +\\{str\_room}(\|l);\5 +${}\|d\K\\{cur\_length};{}$\6 +\&{while} ${}(\\{pool\_ptr}>\\{str\_start}[\\{str\_ptr}]){}$\5 +${}\{{}$\5 +\1\\{decr}(\\{pool\_ptr});\5 +${}\\{str\_pool}[\\{pool\_ptr}+\|l]\K\\{str\_pool}[\\{pool\_ptr}];{}$\6 +\4${}\}{}$\C{move current string up to make room for another}\2\6 +\&{for} ${}(\|k\K\|j;{}$ ${}\|k\Z\|j+\|l-\T{1};{}$ ${}\|k\PP){}$\1\5 +\\{append\_char}(\\{buffer}[\|k]);\2\6 +${}\\{text}(\|p)\K\\{make\_string}(\,);{}$\5 +${}\\{pool\_ptr}\K\\{pool\_ptr}+\|d;{}$\6 +\8\#\&{ifdef} \.{STAT}\6 +\\{incr}(\\{cs\_count});\6 +\8\#\&{endif}\6 +\4${}\}{}$\2\par +\U259.\fi + +\M{261}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\B\4\X261:Compute the hash code \|h\X${}\E{}$\6 +$\|h\K\\{buffer}[\|j];{}$\6 +\&{for} ${}(\|k\K\|j+\T{1};{}$ ${}\|k\Z\|j+\|l-\T{1};{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1${}\|h\K\|h+\|h+\\{buffer}[\|k];{}$\6 +\&{while} ${}(\|h\G\\{hash\_prime}){}$\1\5 +${}\|h\K\|h-\\{hash\_prime};{}$\2\6 +\4${}\}{}$\2\par +\U259.\fi + +\M{262}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\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_cs}(\&{int} \|p)\C{prints a purported control sequence}\6 +${}\{{}$\5 +\1\&{if} ${}(\|p<\\{hash\_base}{}$)\C{single character}\1\6 +\&{if} ${}(\|p\G\\{single\_base}){}$\1\6 +\&{if} ${}(\|p\E\\{null\_cs}){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1526:\.{"csname"}\X);\5 +\\{print\_esc}(\X1527:\.{"endcsname"}\X);\5 +\\{print\_char}(\.{'\ '});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{print\_esc}(\|p-\\{single\_base});{}$\6 +\&{if} ${}(\\{cat\_code}(\|p-\\{single\_base})\E\\{letter}){}$\1\5 +\\{print\_char}(\.{'\ '});\2\6 +\4${}\}{}$\2\2\6 +\&{else} \&{if} ${}(\|p<\\{active\_base}){}$\1\5 +\\{print\_esc}(\X1528:\.{"IMPOSSIBLE."}\X);\2\6 +\&{else}\1\5 +${}\\{print}(\|p-\\{active\_base});{}$\2\2\6 +\&{else} \&{if} ${}(\|p\G\\{undefined\_control\_sequence}){}$\1\5 +\\{print\_esc}(\X1528:\.{"IMPOSSIBLE."}\X);\2\6 +\&{else} \&{if} ${}((\\{text}(\|p)<\T{0})\V(\\{text}(\|p)\G\\{str\_ptr})){}$\1\5 +\\{print\_esc}(\X1529:\.{"NONEXISTENT."}\X);\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\\{text}(\|p));\5 +\\{print\_char}(\.{'\ '});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{263}Here is a similar procedure; it avoids the error checks, and it never +prints a space after the control sequence. + +\Y\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{sprint\_cs}(\&{pointer} \|p)\C{prints a control sequence}\6 +${}\{{}$\5 +\1\&{if} ${}(\|p<\\{hash\_base}){}$\1\6 +\&{if} ${}(\|p<\\{single\_base}){}$\1\5 +${}\\{print}(\|p-\\{active\_base});{}$\2\6 +\&{else} \&{if} ${}(\|p<\\{null\_cs}){}$\1\5 +${}\\{print\_esc}(\|p-\\{single\_base});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1526:\.{"csname"}\X);\5 +\\{print\_esc}(\X1527:\.{"endcsname"}\X);\6 +\4${}\}{}$\2\2\6 +\&{else}\1\5 +\\{print\_esc}(\\{text}(\|p));\2\6 +\4${}\}{}$\2\par +\fi + +\M{264}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\B\8\#\&{ifdef} \.{INIT}\6 +\&{void} \\{primitive}(\&{str\_number} \|s${},\39{}$\&{quarterword} \|c${},\39{}$\&{halfword} \|o)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pool\_pointer} \|k;\C{index into \\{str\_pool}}\6 +\&{int} \|j;\C{index into \\{buffer}}\6 +\&{small\_number} \|l;\C{length of the string}\7 +\&{if} ${}(\|s<\T{256}){}$\1\5 +${}\\{cur\_val}\K\|s+\\{single\_base};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|k\K\\{str\_start}[\|s];{}$\5 +${}\|l\K\\{str\_start}[\|s+\T{1}]-\|k{}$;\C{we will move \|s into the (empty) \\{buffer}}\6 +\&{for} ${}(\|j\K\T{0};{}$ ${}\|j\Z\|l-\T{1};{}$ ${}\|j\PP){}$\1\5 +${}\\{buffer}[\|j]\K\\{so}(\\{str\_pool}[\|k+\|j]);{}$\2\6 +${}\\{cur\_val}\K\\{id\_lookup}(\T{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 +\4${}\}{}$\2\6 +${}\\{eq\_level}(\\{cur\_val})\K\\{level\_one};{}$\5 +${}\\{eq\_type}(\\{cur\_val})\K\|c;{}$\5 +${}\\{equiv}(\\{cur\_val})\K\|o;{}$\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\M{265}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\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\.{'\ '},\39\\{ex\_space},\39\T{0}){}$;\6 +${}\\{primitive}(\.{'/'},\39\\{ital\_corr},\39\T{0}){}$;\6 +${}\\{primitive}(\X1530:\.{"accent"}\X,\39\\{accent},\39\T{0}){}$;\6 +${}\\{primitive}(\X1531:\.{"advance"}\X,\39\\{advance},\39\T{0}){}$;\6 +${}\\{primitive}(\X1532:\.{"afterassignment"}\X,\39\\{after\_assignment},\39\T{0}){}$;\6 +${}\\{primitive}(\X1533:\.{"aftergroup"}\X,\39\\{after\_group},\39\T{0}){}$;\6 +${}\\{primitive}(\X1534:\.{"begingroup"}\X,\39\\{begin\_group},\39\T{0}){}$;\6 +${}\\{primitive}(\X1535:\.{"char"}\X,\39\\{char\_num},\39\T{0}){}$;\6 +${}\\{primitive}(\X1526:\.{"csname"}\X,\39\\{cs\_name},\39\T{0}){}$;\6 +${}\\{primitive}(\X1536:\.{"delimiter"}\X,\39\\{delim\_num},\39\T{0}){}$;\6 +${}\\{primitive}(\X1537:\.{"divide"}\X,\39\\{divide},\39\T{0}){}$;\6 +${}\\{primitive}(\X1527:\.{"endcsname"}\X,\39\\{end\_cs\_name},\39\T{0}){}$;\6 +${}\\{primitive}(\X1538:\.{"endgroup"}\X,\39\\{end\_group},\39\T{0});{}$\5 +${}\\{text}(\\{frozen\_end\_group})\K\X1538:\.{"endgroup"}\X;{}$\5 +${}\\{eqtb}[\\{frozen\_end\_group}]\K\\{eqtb}[\\{cur\_val}]{}$;\6 +${}\\{primitive}(\X1539:\.{"expandafter"}\X,\39\\{expand\_after},\39\T{0}){}$;\6 +${}\\{primitive}(\X1540:\.{"font"}\X,\39\\{def\_font},\39\T{0}){}$;\6 +${}\\{primitive}(\X1541:\.{"fontdimen"}\X,\39\\{assign\_font\_dimen},\39\T{0}){}$;\6 +${}\\{primitive}(\X1542:\.{"halign"}\X,\39\\{halign},\39\T{0}){}$;\6 +${}\\{primitive}(\X1543:\.{"hrule"}\X,\39\\{hrule},\39\T{0}){}$;\6 +${}\\{primitive}(\X1544:\.{"ignorespaces"}\X,\39\\{ignore\_spaces},\39\T{0}){}$;\6 +${}\\{primitive}(\X1390:\.{"insert"}\X,\39\\{insert},\39\T{0}){}$;\6 +${}\\{primitive}(\X1401:\.{"mark"}\X,\39\\{mark},\39\T{0}){}$;\6 +${}\\{primitive}(\X1545:\.{"mathaccent"}\X,\39\\{math\_accent},\39\T{0}){}$;\6 +${}\\{primitive}(\X1546:\.{"mathchar"}\X,\39\\{math\_char\_num},\39\T{0}){}$;\6 +${}\\{primitive}(\X1547:\.{"mathchoice"}\X,\39\\{math\_choice},\39\T{0}){}$;\6 +${}\\{primitive}(\X1548:\.{"multiply"}\X,\39\\{multiply},\39\T{0}){}$;\6 +${}\\{primitive}(\X1549:\.{"noalign"}\X,\39\\{no\_align},\39\T{0}){}$;\6 +${}\\{primitive}(\X1550:\.{"noboundary"}\X,\39\\{no\_boundary},\39\T{0}){}$;\6 +${}\\{primitive}(\X1551:\.{"noexpand"}\X,\39\\{no\_expand},\39\T{0}){}$;\6 +${}\\{primitive}(\X1392:\.{"nonscript"}\X,\39\\{non\_script},\39\T{0}){}$;\6 +${}\\{primitive}(\X1552:\.{"omit"}\X,\39\\{omit},\39\T{0}){}$;\6 +${}\\{primitive}(\X1436:\.{"parshape"}\X,\39\\{set\_shape},\39\T{0}){}$;\6 +${}\\{primitive}(\X1553:\.{"penalty"}\X,\39\\{break\_penalty},\39\T{0}){}$;\6 +${}\\{primitive}(\X1554:\.{"prevgraf"}\X,\39\\{set\_prev\_graf},\39\T{0}){}$;\6 +${}\\{primitive}(\X1555:\.{"radical"}\X,\39\\{radical},\39\T{0}){}$;\6 +${}\\{primitive}(\X1556:\.{"read"}\X,\39\\{read\_to\_cs},\39\T{0}){}$;\6 +${}\\{primitive}(\X1557:\.{"relax"}\X,\39\\{relax},\39\T{256}){}$;\C{cf.\ \\{scan\_file\_name}}\6 +${}\\{text}(\\{frozen\_relax})\K\X1557:\.{"relax"}\X;{}$\5 +${}\\{eqtb}[\\{frozen\_relax}]\K\\{eqtb}[\\{cur\_val}]{}$;\6 +${}\\{primitive}(\X1558:\.{"setbox"}\X,\39\\{set\_box},\39\T{0}){}$;\6 +${}\\{primitive}(\X1559:\.{"the"}\X,\39\\{the},\39\T{0}){}$;\6 +${}\\{primitive}(\X1435:\.{"toks"}\X,\39\\{toks\_register},\39\T{0}){}$;\6 +${}\\{primitive}(\X1402:\.{"vadjust"}\X,\39\\{vadjust},\39\T{0}){}$;\6 +${}\\{primitive}(\X1560:\.{"valign"}\X,\39\\{valign},\39\T{0}){}$;\6 +${}\\{primitive}(\X1561:\.{"vcenter"}\X,\39\\{vcenter},\39\T{0}){}$;\6 +${}\\{primitive}(\X1562:\.{"vrule"}\X,\39\\{vrule},\39\T{0}){}$;\par +\fi + +\M{266}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\B\4\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{accent}:\5 +\\{print\_esc}(\X1530:\.{"accent"}\X);\5 +\&{break};\6 +\4\&{case} \\{advance}:\5 +\\{print\_esc}(\X1531:\.{"advance"}\X);\5 +\&{break};\6 +\4\&{case} \\{after\_assignment}:\5 +\\{print\_esc}(\X1532:\.{"afterassignment"}\X);\5 +\&{break};\6 +\4\&{case} \\{after\_group}:\5 +\\{print\_esc}(\X1533:\.{"aftergroup"}\X);\5 +\&{break};\6 +\4\&{case} \\{assign\_font\_dimen}:\5 +\\{print\_esc}(\X1541:\.{"fontdimen"}\X);\5 +\&{break};\6 +\4\&{case} \\{begin\_group}:\5 +\\{print\_esc}(\X1534:\.{"begingroup"}\X);\5 +\&{break};\6 +\4\&{case} \\{break\_penalty}:\5 +\\{print\_esc}(\X1553:\.{"penalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{char\_num}:\5 +\\{print\_esc}(\X1535:\.{"char"}\X);\5 +\&{break};\6 +\4\&{case} \\{cs\_name}:\5 +\\{print\_esc}(\X1526:\.{"csname"}\X);\5 +\&{break};\6 +\4\&{case} \\{def\_font}:\5 +\\{print\_esc}(\X1540:\.{"font"}\X);\5 +\&{break};\6 +\4\&{case} \\{delim\_num}:\5 +\\{print\_esc}(\X1536:\.{"delimiter"}\X);\5 +\&{break};\6 +\4\&{case} \\{divide}:\5 +\\{print\_esc}(\X1537:\.{"divide"}\X);\5 +\&{break};\6 +\4\&{case} \\{end\_cs\_name}:\5 +\\{print\_esc}(\X1527:\.{"endcsname"}\X);\5 +\&{break};\6 +\4\&{case} \\{end\_group}:\5 +\\{print\_esc}(\X1538:\.{"endgroup"}\X);\5 +\&{break};\6 +\4\&{case} \\{ex\_space}:\5 +\\{print\_esc}(\.{'\ '});\5 +\&{break};\6 +\4\&{case} \\{expand\_after}:\5 +\\{print\_esc}(\X1539:\.{"expandafter"}\X);\5 +\&{break};\6 +\4\&{case} \\{halign}:\5 +\\{print\_esc}(\X1542:\.{"halign"}\X);\5 +\&{break};\6 +\4\&{case} \\{hrule}:\5 +\\{print\_esc}(\X1543:\.{"hrule"}\X);\5 +\&{break};\6 +\4\&{case} \\{ignore\_spaces}:\5 +\\{print\_esc}(\X1544:\.{"ignorespaces"}\X);\5 +\&{break};\6 +\4\&{case} \\{insert}:\5 +\\{print\_esc}(\X1390:\.{"insert"}\X);\5 +\&{break};\6 +\4\&{case} \\{ital\_corr}:\5 +\\{print\_esc}(\.{'/'});\5 +\&{break};\6 +\4\&{case} \\{mark}:\5 +\\{print\_esc}(\X1401:\.{"mark"}\X);\5 +\&{break};\6 +\4\&{case} \\{math\_accent}:\5 +\\{print\_esc}(\X1545:\.{"mathaccent"}\X);\5 +\&{break};\6 +\4\&{case} \\{math\_char\_num}:\5 +\\{print\_esc}(\X1546:\.{"mathchar"}\X);\5 +\&{break};\6 +\4\&{case} \\{math\_choice}:\5 +\\{print\_esc}(\X1547:\.{"mathchoice"}\X);\5 +\&{break};\6 +\4\&{case} \\{multiply}:\5 +\\{print\_esc}(\X1548:\.{"multiply"}\X);\5 +\&{break};\6 +\4\&{case} \\{no\_align}:\5 +\\{print\_esc}(\X1549:\.{"noalign"}\X);\5 +\&{break};\6 +\4\&{case} \\{no\_boundary}:\5 +\\{print\_esc}(\X1550:\.{"noboundary"}\X);\5 +\&{break};\6 +\4\&{case} \\{no\_expand}:\5 +\\{print\_esc}(\X1551:\.{"noexpand"}\X);\5 +\&{break};\6 +\4\&{case} \\{non\_script}:\5 +\\{print\_esc}(\X1392:\.{"nonscript"}\X);\5 +\&{break};\6 +\4\&{case} \\{omit}:\5 +\\{print\_esc}(\X1552:\.{"omit"}\X);\5 +\&{break};\6 +\4\&{case} \\{radical}:\5 +\\{print\_esc}(\X1555:\.{"radical"}\X);\5 +\&{break};\6 +\4\&{case} \\{read\_to\_cs}:\5 +\\{print\_esc}(\X1556:\.{"read"}\X);\5 +\&{break};\6 +\4\&{case} \\{relax}:\5 +\\{print\_esc}(\X1557:\.{"relax"}\X);\5 +\&{break};\6 +\4\&{case} \\{set\_box}:\5 +\\{print\_esc}(\X1558:\.{"setbox"}\X);\5 +\&{break};\6 +\4\&{case} \\{set\_prev\_graf}:\5 +\\{print\_esc}(\X1554:\.{"prevgraf"}\X);\5 +\&{break};\6 +\4\&{case} \\{set\_shape}:\5 +\\{print\_esc}(\X1436:\.{"parshape"}\X);\5 +\&{break};\6 +\4\&{case} \\{the}:\5 +\\{print\_esc}(\X1559:\.{"the"}\X);\5 +\&{break};\6 +\4\&{case} \\{toks\_register}:\5 +\\{print\_esc}(\X1435:\.{"toks"}\X);\5 +\&{break};\6 +\4\&{case} \\{vadjust}:\5 +\\{print\_esc}(\X1402:\.{"vadjust"}\X);\5 +\&{break};\6 +\4\&{case} \\{valign}:\5 +\\{print\_esc}(\X1560:\.{"valign"}\X);\5 +\&{break};\6 +\4\&{case} \\{vcenter}:\5 +\\{print\_esc}(\X1561:\.{"vcenter"}\X);\5 +\&{break};\6 +\4\&{case} \\{vrule}:\5 +\\{print\_esc}(\X1562:\.{"vrule"}\X);\5 +\&{break};\par +\fi + +\M{267}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 $\X1555:\.{"radical"}\X$ 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\B\4\X267:Print the font identifier for \\{font}(\|p)\X${}\E{}$\6 +\\{print\_esc}(\\{font\_id\_text}(\\{font}(\|p)))\par +\Us174\ET176.\fi + +\N{1}{268}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\E\\{save\_ptr}-\T{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)\E\\{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-\T{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)\E\\{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)\E\\{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)\E\\{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\B\4\D$\\{save\_type}(\|X)$ \5 +$\\{save\_stack}[\|X].\\{hh}.{}$\\{b0}\C{classifies a \\{save\_stack} entry}\par +\B\4\D$\\{save\_level}(\|X)$ \5 +$\\{save\_stack}[\|X].\\{hh}.{}$\\{b1}\C{saved level for regions 5 and 6, or group code}\par +\B\4\D$\\{save\_index}(\|X)$ \5 +$\\{save\_stack}[\|X].\\{hh}.{}$\\{rh}\C{\\{eqtb} location or token or \\{save\_stack} location}\par +\B\4\D$\\{restore\_old\_value}$ \5 +\T{0}\C{\\{save\_type} when a value should be restored later}\par +\B\4\D$\\{restore\_zero}$ \5 +\T{1}\C{\\{save\_type} when an undefined entry should be restored}\par +\B\4\D$\\{insert\_token}$ \5 +\T{2}\C{\\{save\_type} when a token is being saved for later use}\par +\B\4\D$\\{level\_boundary}$ \5 +\T{3}\C{\\{save\_type} corresponding to beginning of group}\par +\fi + +\M{269}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\B\4\D$\\{bottom\_level}$ \5 +\T{0}\C{group code for the outside world}\par +\B\4\D$\\{simple\_group}$ \5 +\T{1}\C{group code for local structure only}\par +\B\4\D$\\{hbox\_group}$ \5 +\T{2}\C{code for `\.{\\hbox}\grp'}\par +\B\4\D$\\{adjusted\_hbox\_group}$ \5 +\T{3}\C{code for `\.{\\hbox}\grp' in vertical mode}\par +\B\4\D$\\{vbox\_group}$ \5 +\T{4}\C{code for `\.{\\vbox}\grp'}\par +\B\4\D$\\{vtop\_group}$ \5 +\T{5}\C{code for `\.{\\vtop}\grp'}\par +\B\4\D$\\{align\_group}$ \5 +\T{6}\C{code for `\.{\\halign}\grp', `\.{\\valign}\grp'}\par +\B\4\D$\\{no\_align\_group}$ \5 +\T{7}\C{code for `\.{\\noalign}\grp'}\par +\B\4\D$\\{output\_group}$ \5 +\T{8}\C{code for output routine}\par +\B\4\D$\\{math\_group}$ \5 +\T{9}\C{code for, e.g., `\.{\char'136}\grp'}\par +\B\4\D$\\{disc\_group}$ \5 +\T{10}\C{code for `\.{\\discretionary}\grp\grp\grp'}\par +\B\4\D$\\{insert\_group}$ \5 +\T{11}\C{code for `\.{\\insert}\grp', `\.{\\vadjust}\grp'}\par +\B\4\D$\\{vcenter\_group}$ \5 +\T{12}\C{code for `\.{\\vcenter}\grp'}\par +\B\4\D$\\{math\_choice\_group}$ \5 +\T{13}\C{code for `\.{\\mathchoice}\grp\grp\grp\grp'}\par +\B\4\D$\\{semi\_simple\_group}$ \5 +\T{14}\C{code for `\.{\\begingroup...\\endgroup}'}\par +\B\4\D$\\{math\_shift\_group}$ \5 +\T{15}\C{code for `\.{\$...\$}'}\par +\B\4\D$\\{math\_left\_group}$ \5 +\T{16}\C{code for `\.{\\left...\\right}'}\par +\B\4\D$\\{max\_group\_code}$ \5 +\T{16}\par +\Y\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{uint8\_t} \&{group\_code};\C{\\{save\_level} for a level boundary}\par +\fi + +\M{270}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 + +\M{271}\B\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{memory\_word} ${}\\{save\_stack}[\\{save\_size}+\T{1}];{}$\6 +\&{uint16\_t} \\{save\_ptr};\C{first unused entry on \\{save\_stack}}\6 +\&{uint16\_t} \\{max\_save\_stack};\C{maximum usage of save stack}\6 +\&{quarterword} \\{cur\_level};\C{current nesting level for groups}\6 +\&{group\_code} \\{cur\_group};\C{current group type}\6 +\&{uint16\_t} \\{cur\_boundary};\C{where the current level begins}\par +\fi + +\M{272}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\B\4\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{save\_ptr}\K\T{0};{}$\5 +${}\\{cur\_level}\K\\{level\_one};{}$\5 +${}\\{cur\_group}\K\\{bottom\_level};{}$\5 +${}\\{cur\_boundary}\K\T{0};{}$\5 +${}\\{max\_save\_stack}\K\T{0}{}$;\par +\fi + +\M{273}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\B\4\D$\\{check\_full\_save\_stack}$ \6 +\&{if} ${}(\\{save\_ptr}>\\{max\_save\_stack}){}$\5 +${}\{{}$\5 +\1${}\\{max\_save\_stack}\K\\{save\_ptr};{}$\6 +\&{if} ${}(\\{max\_save\_stack}>\\{save\_size}-\T{6}){}$\1\5 +${}\\{overflow}(\.{"save\ size"},\39\\{save\_size});{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{274}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\B\4\D$\\{saved}(\|X)$ \5 +$\\{save\_stack}[\\{save\_ptr}+\|X].{}$\|i\par +\Y\B\&{void} \\{new\_save\_level}(\&{group\_code} \|c)\C{begin a new level of grouping}\6 +${}\{{}$\5 +\1\\{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}\E\\{max\_quarterword}){}$\1\5 +${}\\{overflow}(\.{"grouping\ levels"},\39\\{max\_quarterword}-\\{min\_quarterword}){}$;\C{quit if $(\\{cur\_level}+\T{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 +\4${}\}{}$\2\par +\fi + +\M{275}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\B\&{void} \\{eq\_destroy}(\&{memory\_word} \|w)\C{gets ready to forget \|w}\6 +${}\{{}$\5 +\1\&{pointer} \|q;\C{\\{equiv} field of \|w}\7 +\&{switch} (\\{eq\_type\_field}(\|w))\5 +${}\{{}$\1\6 +\4\&{case} \\{call}:\5 +\&{case} \\{long\_call}:\5 +\&{case} \\{outer\_call}:\5 +\&{case} \\{long\_outer\_call}:\5 +\\{delete\_token\_ref}(\\{equiv\_field}(\|w));\5 +\&{break};\6 +\4\&{case} \\{glue\_ref}:\5 +\\{delete\_glue\_ref}(\\{equiv\_field}(\|w));\5 +\&{break};\6 +\4\&{case} \\{shape\_ref}:\6 +${}\{{}$\5 +\1${}\|q\K\\{equiv\_field}(\|w){}$;\C{we need to free a \.{\\parshape} block}\6 +\&{if} ${}(\|q\I\\{null}){}$\1\5 +${}\\{free\_node}(\|q,\39\\{info}(\|q)+\\{info}(\|q)+\T{1});{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\C{such a block is $\T{2}\|n+\T{1}$ words long, where $\|n\E\\{info}(\|q)$}\6 +\4\&{case} \\{box\_ref}:\5 +\\{flush\_node\_list}(\\{equiv\_field}(\|w));\5 +\&{break};\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{276}To save a value of \\{eqtb}[\|p] that was established at level \|l, we +can use the following subroutine. + +\Y\B\&{void} \\{eq\_save}(\&{pointer} \|p${},\39{}$\&{quarterword} \|l)\C{saves \\{eqtb}[\|p]}\6 +${}\{{}$\5 +\1\\{check\_full\_save\_stack};\6 +\&{if} ${}(\|l\E\\{level\_zero}){}$\1\5 +${}\\{save\_type}(\\{save\_ptr})\K\\{restore\_zero};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{save\_stack}[\\{save\_ptr}]\K\\{eqtb}[\|p];{}$\5 +\\{incr}(\\{save\_ptr});\5 +${}\\{save\_type}(\\{save\_ptr})\K\\{restore\_old\_value};{}$\6 +\4${}\}{}$\2\6 +${}\\{save\_level}(\\{save\_ptr})\K\|l;{}$\5 +${}\\{save\_index}(\\{save\_ptr})\K\|p;{}$\5 +\\{incr}(\\{save\_ptr});\6 +\4${}\}{}$\2\par +\fi + +\M{277}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\B\&{void} \\{eq\_define}(\&{pointer} \|p${},\39{}$\&{quarterword} \|t${},\39{}$\&{halfword} \|e)\C{new data for \\{eqtb}}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{eq\_level}(\|p)\E\\{cur\_level}){}$\1\5 +\\{eq\_destroy}(\\{eqtb}[\|p]);\2\6 +\&{else} \&{if} ${}(\\{cur\_level}>\\{level\_one}){}$\1\5 +${}\\{eq\_save}(\|p,\39\\{eq\_level}(\|p));{}$\2\6 +${}\\{eq\_level}(\|p)\K\\{cur\_level};{}$\5 +${}\\{eq\_type}(\|p)\K\|t;{}$\5 +${}\\{equiv}(\|p)\K\|e;{}$\6 +\4${}\}{}$\2\par +\fi + +\M{278}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\B\&{void} \\{eq\_word\_define}(\&{pointer} \|p${},\39{}$\&{int} \|w)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{xeq\_level}[\|p]\I\\{cur\_level}){}$\5 +${}\{{}$\5 +\1${}\\{eq\_save}(\|p,\39\\{xeq\_level}[\|p]);{}$\5 +${}\\{xeq\_level}[\|p]\K\\{cur\_level};{}$\6 +\4${}\}{}$\2\6 +${}\\{eqtb}[\|p].\|i\K\|w;{}$\6 +\4${}\}{}$\2\par +\fi + +\M{279}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\B\&{void} \\{geq\_define}(\&{pointer} \|p${},\39{}$\&{quarterword} \|t${},\39{}$\&{halfword} \|e)\C{global \\{eq\_define}}\6 +${}\{{}$\5 +\1\\{eq\_destroy}(\\{eqtb}[\|p]);\5 +${}\\{eq\_level}(\|p)\K\\{level\_one};{}$\5 +${}\\{eq\_type}(\|p)\K\|t;{}$\5 +${}\\{equiv}(\|p)\K\|e;{}$\6 +\4${}\}{}$\2\7 +\&{void} \\{geq\_word\_define}(\&{pointer} \|p${},\39{}$\&{int} \|w)\C{global \\{eq\_word\_define}}\6 +${}\{{}$\5 +\1${}\\{eqtb}[\|p].\|i\K\|w;{}$\5 +${}\\{xeq\_level}[\|p]\K\\{level\_one};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{280}Subroutine \\{save\_for\_after} puts a token on the stack for save-keeping. + +\Y\B\&{void} \\{save\_for\_after}(\&{halfword} \|t)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_level}>\\{level\_one}){}$\5 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{281}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\B\hbox{\4}\X284:Declare the procedure called \\{restore\_trace}\X\7 +\&{void} \\{back\_input}(\&{void});\7 +\&{void} \\{unsave}(\&{void})\C{pops the top level off the save stack}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{position to be restored}\6 +\&{quarterword} \|l;\C{saved level, if in fullword regions of \\{eqtb}}\6 +\&{halfword} \|t;\C{saved value of \\{cur\_tok}}\7 +\&{if} ${}(\\{cur\_level}>\\{level\_one}){}$\5 +${}\{{}$\5 +\1\\{decr}(\\{cur\_level});\5 +\X282:Clear off top level from \\{save\_stack}\X;\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{confusion}(\X1563:\.{"curlevel"}\X);\C{\\{unsave} is not used when $\\{cur\_group}\E\\{bottom\_level}$}\2\6 +\4${}\}{}$\2\par +\fi + +\M{282}\B\X282:Clear off top level from \\{save\_stack}\X${}\E{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{decr}(\\{save\_ptr});\6 +\&{if} ${}(\\{save\_type}(\\{save\_ptr})\E\\{level\_boundary}){}$\1\5 +\&{goto} \\{done};\2\6 +${}\|p\K\\{save\_index}(\\{save\_ptr});{}$\6 +\&{if} ${}(\\{save\_type}(\\{save\_ptr})\E\\{insert\_token}){}$\1\5 +\X326:Insert token \|p into \TeX's input\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{save\_type}(\\{save\_ptr})\E\\{restore\_old\_value}){}$\5 +${}\{{}$\5 +\1${}\|l\K\\{save\_level}(\\{save\_ptr});{}$\5 +\\{decr}(\\{save\_ptr});\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{save\_stack}[\\{save\_ptr}]\K\\{eqtb}[\\{undefined\_control\_sequence}];{}$\2\6 +\X283:Store \(s)\\{save\_stack}[\\{save\_ptr}] in \\{eqtb}[\|p], unless \\{eqtb}[\|p] holds a global value\X;\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4\\{done}:\5 +${}\\{cur\_group}\K\\{save\_level}(\\{save\_ptr});$ $\\{cur\_boundary}\K\\{save\_index}{}$(\\{save\_ptr})\par +\U281.\fi + +\M{283}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\B\4\X283:Store \(s)\\{save\_stack}[\\{save\_ptr}] in \\{eqtb}[\|p], unless \\{eqtb}[\|p] holds a global value\X${}\E{}$\6 +\&{if} ${}(\|p<\\{int\_base}){}$\1\6 +\&{if} ${}(\\{eq\_level}(\|p)\E\\{level\_one}){}$\5 +${}\{{}$\5 +\1\\{eq\_destroy}(\\{save\_stack}[\\{save\_ptr}]);\C{destroy the saved value}\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_restores}>\T{0}){}$\1\5 +${}\\{restore\_trace}(\|p,\39\X1564:\.{"retaining"}\X);{}$\2\6 +\8\#\&{endif}\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{eq\_destroy}(\\{eqtb}[\|p]);\C{destroy the current value}\6 +${}\\{eqtb}[\|p]\K\\{save\_stack}[\\{save\_ptr}]{}$;\C{restore the saved value}\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_restores}>\T{0}){}$\1\5 +${}\\{restore\_trace}(\|p,\39\X1565:\.{"restoring"}\X);{}$\2\6 +\8\#\&{endif}\6 +\4${}\}{}$\2\2\6 +\&{else} \&{if} ${}(\\{xeq\_level}[\|p]\I\\{level\_one}){}$\5 +${}\{{}$\5 +\1${}\\{eqtb}[\|p]\K\\{save\_stack}[\\{save\_ptr}];{}$\5 +${}\\{xeq\_level}[\|p]\K\|l;{}$\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_restores}>\T{0}){}$\1\5 +${}\\{restore\_trace}(\|p,\39\X1565:\.{"restoring"}\X);{}$\2\6 +\8\#\&{endif}\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\6 +\8\#\&{ifdef} \.{STAT}\1\6 +\&{if} ${}(\\{tracing\_restores}>\T{0}){}$\1\5 +${}\\{restore\_trace}(\|p,\39\X1564:\.{"retaining"}\X);{}$\2\6 +\8\#\&{endif}\6 +\4${}\}{}$\2\par +\U282.\fi + +\M{284}\B\X284:Declare the procedure called \\{restore\_trace}\X${}\E{}$\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{void} \\{restore\_trace}(\&{pointer} \|p${},\39{}$\&{str\_number} \|s)\C{\\{eqtb}[\|p] has just been restored or retained}\6 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_char}(\.{'\{'});\5 +\\{print}(\|s);\5 +\\{print\_char}(\.{'\ '});\5 +\\{show\_eqtb}(\|p);\5 +\\{print\_char}(\.{'\}'});\5 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\U281.\fi + +\M{285}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\B\4\X285:Search \\{save\_stack} for equivalents that point to \|p\X${}\E{}$\6 +\&{if} ${}(\\{save\_ptr}>\T{0}){}$\1\6 +\&{for} ${}(\|q\K\T{0};{}$ ${}\|q\Z\\{save\_ptr}-\T{1};{}$ ${}\|q\PP){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{equiv\_field}(\\{save\_stack}[\|q])\E\|p){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"SAVE("});\5 +\\{print\_int}(\|q);\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\2\par +\U172.\fi + +\M{286}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{mag\_set};\C{if nonzero, this magnification should be used henceforth}\par +\fi + +\M{287}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{mag\_set}\K\T{0}{}$;\par +\fi + +\M{288}The \\{prepare\_mag} subroutine is called whenever \TeX\ wants to use \\{mag} +for magnification. + +\Y\B\&{void} \\{prepare\_mag}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}((\\{mag\_set}>\T{0})\W(\\{mag}\I\\{mag\_set})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Incompatible\ magnif}\)\.{ication\ ("});\5 +\\{print\_int}(\\{mag});\5 +\\{print\_str}(\.{");"});\5 +\\{print\_nl}(\.{"\ the\ previous\ value}\)\.{\ will\ be\ retained"});\5 +\\{help2}(\.{"I\ can\ handle\ only\ o}\)\.{ne\ magnification\ rat}\)\.{io\ per\ job.\ So\ I've"})\6 +(\.{"reverted\ to\ the\ mag}\)\.{nification\ 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 +\4${}\}{}$\2\6 +\&{if} ${}((\\{mag}\Z\T{0})\V(\\{mag}>\T{32768})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Illegal\ magnificati}\)\.{on\ has\ been\ changed\ }\)\.{to\ 1000"});\6 +\\{help1}(\.{"The\ magnification\ r}\)\.{atio\ must\ be\ between}\)\.{\ 1\ and\ 32768."});\5 +\\{int\_error}(\\{mag});\5 +${}\\{geq\_word\_define}(\\{int\_base}+\\{mag\_code},\39\T{1000});{}$\6 +\4${}\}{}$\2\6 +${}\\{mag\_set}\K\\{mag};{}$\6 +\4${}\}{}$\2\par +\fi + +\N{1}{289}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 $\T{1}\Z\|m\Z\T{14}$. (2)~A control +sequence whose \\{eqtb} address is \|p is represented as the number +$\\{cs\_token\_flag}+\|p$. Here \\{cs\_token\_flag} $\E\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}\Z\|t<\\{right\_brace\_limit}$; and it represents a \\{match} or +\\{end\_match} command if and only if $\\{match\_token}\Z\|t\Z\\{end\_match\_token}$. +The following definitions take care of these token-oriented constants +and a few others. + +\Y\B\4\D$\\{cs\_token\_flag}$ \5 +\T{\~7777}\C{amount added to the \\{eqtb} location in a token that stands for a control sequence; is a multiple of~256, less~1}\par +\B\4\D$\\{left\_brace\_token}$ \5 +\T{\~0400}\C{$2^8\cdot\\{left\_brace}$}\par +\B\4\D$\\{left\_brace\_limit}$ \5 +\T{\~1000}\C{$2^8\cdot(\\{left\_brace}+1)$}\par +\B\4\D$\\{right\_brace\_token}$ \5 +\T{\~1000}\C{$2^8\cdot\\{right\_brace}$}\par +\B\4\D$\\{right\_brace\_limit}$ \5 +\T{\~1400}\C{$2^8\cdot(\\{right\_brace}+1)$}\par +\B\4\D$\\{math\_shift\_token}$ \5 +\T{\~1400}\C{$2^8\cdot\\{math\_shift}$}\par +\B\4\D$\\{tab\_token}$ \5 +\T{\~2000}\C{$2^8\cdot\\{tab\_mark}$}\par +\B\4\D$\\{out\_param\_token}$ \5 +\T{\~2400}\C{$2^8\cdot\\{out\_param}$}\par +\B\4\D$\\{space\_token}$ \5 +\T{\~5040}\C{$2^8\cdot\\{spacer}+\.{'\ '}$}\par +\B\4\D$\\{letter\_token}$ \5 +\T{\~5400}\C{$2^8\cdot\\{letter}$}\par +\B\4\D$\\{other\_token}$ \5 +\T{\~6000}\C{$2^8\cdot\\{other\_char}$}\par +\B\4\D$\\{match\_token}$ \5 +\T{\~6400}\C{$2^8\cdot\\{match}$}\par +\B\4\D$\\{end\_match\_token}$ \5 +\T{\~7000}\C{$2^8\cdot\\{end\_match}$}\par +\fi + +\M{290}\B\X14:Check the ``constant'' values for consistency\X${}\mathrel+\E{}$\6 +\&{if} ${}(\\{cs\_token\_flag}+\\{undefined\_control\_sequence}>\\{max\_halfword}){}$\1\5 +${}\\{bad}\K\T{21}{}$;\2\par +\fi + +\M{291}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\E\\{match}$, it means that \TeX\ should scan a parameter +for the current macro; when $\|m\E\\{end\_match}$, it means that parameter +matching should end and \TeX\ should start reading the macro text; and +when $\|m\E\\{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 + +\M{292}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\B\4\X292:Declare the procedure called \\{show\_token\_list}\X${}\E{}$\6 +\&{void} \\{show\_token\_list}(\&{int} \|p${},\39{}$\&{int} \|q${},\39{}$\&{int} \|l)\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|m${},{}$ \|c;\C{pieces of a token}\6 +\&{ASCII\_code} \\{match\_chr};\C{character used in a `\\{match}'}\6 +\&{ASCII\_code} \|n;\C{the highest parameter number, as an ASCII digit}\7 +${}\\{match\_chr}\K\.{'\#'};{}$\5 +${}\|n\K\.{'0'};{}$\5 +${}\\{tally}\K\T{0};{}$\6 +\&{while} ${}((\|p\I\\{null})\W(\\{tally}<\|l)){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|p\E\|q){}$\1\5 +\X320:Do magic computation\X;\2\6 +\X293:Display token \|p, and \&{return} if there are problems\X;\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|p\I\\{null}){}$\1\5 +\\{print\_esc}(\X1566:\.{"ETC."}\X);\2\6 +\4${}\}{}$\2\par +\U119.\fi + +\M{293}\B\X293:Display token \|p, and \&{return} if there are problems\X${}\E{}$\6 +\&{if} ${}((\|p<\\{hi\_mem\_min})\V(\|p>\\{mem\_end})){}$\5 +${}\{{}$\5 +\1\\{print\_esc}(\X1386:\.{"CLOBBERED."}\X);\5 +\&{return};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{info}(\|p)\G\\{cs\_token\_flag}){}$\1\5 +${}\\{print\_cs}(\\{info}(\|p)-\\{cs\_token\_flag});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|m\K\\{info}(\|p)/\T{\~400};{}$\5 +${}\|c\K\\{info}(\|p)\MOD\T{\~400};{}$\6 +\&{if} ${}(\\{info}(\|p)<\T{0}){}$\1\5 +\\{print\_esc}(\X1567:\.{"BAD."}\X);\2\6 +\&{else}\1\5 +\X294:Display the token $(\|m,\|c)$\X;\2\6 +\4${}\}{}$\2\par +\U292.\fi + +\M{294}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\B\4\X294:Display the token $(\|m,\|c)$\X${}\E{}$\6 +\&{switch} (\|m)\5 +${}\{{}$\1\6 +\4\&{case} \\{left\_brace}:\5 +\&{case} \\{right\_brace}:\5 +\&{case} \\{math\_shift}:\5 +\&{case} \\{tab\_mark}:\5 +\&{case} \\{sup\_mark}:\5 +\&{case} \\{sub\_mark}:\5 +\&{case} \\{spacer}:\5 +\&{case} \\{letter}:\5 +\&{case} \\{other\_char}:\5 +\\{print}(\|c);\5 +\&{break};\6 +\4\&{case} \\{mac\_param}:\6 +${}\{{}$\5 +\1\\{print}(\|c);\5 +\\{print}(\|c);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{out\_param}:\6 +${}\{{}$\5 +\1\\{print}(\\{match\_chr});\6 +\&{if} ${}(\|c\Z\T{9}){}$\1\5 +${}\\{print\_char}(\|c+\.{'0'});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_char}(\.{'!'});\5 +\&{return};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{match}:\6 +${}\{{}$\5 +\1${}\\{match\_chr}\K\|c;{}$\5 +\\{print}(\|c);\5 +\\{incr}(\|n);\5 +\\{print\_char}(\|n);\6 +\&{if} ${}(\|n>\.{'9'}){}$\1\5 +\&{return};\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{end\_match}:\5 +\\{print\_str}(\.{"->"});\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1567:\.{"BAD."}\X);\6 +\4${}\}{}$\2\par +\U293.\fi + +\M{295}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\B\&{void} \\{token\_show}(\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\|p\I\\{null}){}$\1\5 +${}\\{show\_token\_list}(\\{link}(\|p),\39\\{null},\39\T{10000000});{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{296}The \\{print\_meaning} subroutine displays \\{cur\_cmd} and \\{cur\_chr} in +symbolic form, including the expansion of a macro or mark. + +\Y\B\&{void} \\{print\_meaning}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr});{}$\6 +\&{if} ${}(\\{cur\_cmd}\G\\{call}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{':'});\5 +\\{print\_ln}(\,);\5 +\\{token\_show}(\\{cur\_chr});\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}\E\\{top\_bot\_mark}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{':'});\5 +\\{print\_ln}(\,);\5 +\\{token\_show}(\\{cur\_mark}[\\{cur\_chr}]);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\N{1}{297}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{eight\_bits} \\{cur\_cmd};\C{current command set by \\{get\_next}}\6 +\&{halfword} \\{cur\_chr};\C{operand of current command}\6 +\&{pointer} \\{cur\_cs};\C{control sequence found here, zero if none found}\6 +\&{halfword} \\{cur\_tok};\C{packed representative of \\{cur\_cmd} and \\{cur\_chr}}\par +\fi + +\M{298}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\B\4\D$\\{chr\_cmd}(\|X)$ \6 +${}\{{}$\5 +\1\\{print\_str}(\|X);\5 +\\{print\_ASCII}(\\{chr\_code});\6 +\4${}\}{}$\2\par +\Y\B\4\X298:Declare the procedure called \\{print\_cmd\_chr}\X${}\E{}$\6 +\&{void} \\{print\_cmd\_chr}(\&{quarterword} \\{cmd}${},\39{}$\&{halfword} \\{chr\_code})\1\1\2\2\6 +${}\{{}$\5 +\1\&{switch} (\\{cmd})\5 +${}\{{}$\1\6 +\4\&{case} \\{left\_brace}:\5 +\\{chr\_cmd}(\.{"begin-group\ charact}\)\.{er\ "})\5 +\&{break};\6 +\4\&{case} \\{right\_brace}:\5 +\\{chr\_cmd}(\.{"end-group\ character}\)\.{\ "})\5 +\&{break};\6 +\4\&{case} \\{math\_shift}:\5 +\\{chr\_cmd}(\.{"math\ shift\ characte}\)\.{r\ "})\5 +\&{break};\6 +\4\&{case} \\{mac\_param}:\5 +\\{chr\_cmd}(\.{"macro\ parameter\ cha}\)\.{racter\ "})\5 +\&{break};\6 +\4\&{case} \\{sup\_mark}:\5 +\\{chr\_cmd}(\.{"superscript\ charact}\)\.{er\ "})\5 +\&{break};\6 +\4\&{case} \\{sub\_mark}:\5 +\\{chr\_cmd}(\.{"subscript\ character}\)\.{\ "})\5 +\&{break};\6 +\4\&{case} \\{endv}:\5 +\\{print\_str}(\.{"end\ of\ alignment\ te}\)\.{mplate"});\5 +\&{break};\6 +\4\&{case} \\{spacer}:\5 +\\{chr\_cmd}(\.{"blank\ space\ "})\5 +\&{break};\6 +\4\&{case} \\{letter}:\5 +\\{chr\_cmd}(\.{"the\ letter\ "})\5 +\&{break};\6 +\4\&{case} \\{other\_char}:\5 +\\{chr\_cmd}(\.{"the\ character\ "})\5 +\&{break};\5 +\hbox{\4}\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X\6 +\4\&{default}:\5 +\\{print\_str}(\.{"[unknown\ command\ co}\)\.{de!]"});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U252.\fi + +\M{299}Here is a procedure that displays the current command. + +\Y\B\&{void} \\{show\_cur\_cmd\_chr}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{"\{"});\6 +\&{if} ${}(\\{mode}\I\\{shown\_mode}){}$\5 +${}\{{}$\5 +\1\\{print\_mode}(\\{mode});\5 +\\{print\_str}(\.{":\ "});\5 +${}\\{shown\_mode}\K\\{mode};{}$\6 +\4${}\}{}$\2\6 +${}\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr});{}$\5 +\\{print\_char}(\.{'\}'});\5 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\par +\fi + +\N{1}{300}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\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{struct} ${}\{{}$\1\6 +\&{quarterword} \\{state\_field}${},{}$ \\{index\_field};\6 +\&{halfword} \\{start\_field}${},{}$ \\{loc\_field}${},{}$ \\{limit\_field}${},{}$ \\{name\_field};\2\6 +${}\}{}$ \&{in\_state\_record};\par +\fi + +\M{301}\B\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{in\_state\_record} ${}\\{input\_stack}[\\{stack\_size}+\T{1}];{}$\6 +\&{uint8\_t} \\{input\_ptr};\C{first unused location of \\{input\_stack}}\6 +\&{uint8\_t} \\{max\_in\_stack};\C{largest value of \\{input\_ptr} when pushing}\6 +\&{in\_state\_record} \\{cur\_input};\C{the ``top'' input state, according to convention (1)}\par +\fi + +\M{302}We've already defined the special variable $\\{loc}\MRL{{\E}{\E}}\\{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\B\4\D$\\{state}$ \5 +$\\{cur\_input}.{}$\\{state\_field}\C{current scanner state}\par +\B\4\D$\\{index}$ \5 +$\\{cur\_input}.{}$\\{index\_field}\C{reference for buffer information}\par +\B\4\D$\\{start}$ \5 +$\\{cur\_input}.{}$\\{start\_field}\C{starting position in \\{buffer}}\par +\B\4\D$\\{limit}$ \5 +$\\{cur\_input}.{}$\\{limit\_field}\C{end of current line in \\{buffer}}\par +\B\4\D$\\{name}$ \5 +$\\{cur\_input}.{}$\\{name\_field}\C{name of the current file}\par +\fi + +\M{303}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+\T{1}$ if we are reading from +input stream \|n, where $\T{0}\Z\|n\Z\T{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}\E\\{mid\_line}$ is the normal state.\cr +2) $\\{state}\E\\{skip\_blanks}$ is like \\{mid\_line}, but blanks are ignored.\cr +3) $\\{state}\E\\{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\B\4\D$\\{mid\_line}$ \5 +\T{1}\C{\\{state} code when scanning a line of characters}\par +\B\4\D$\\{skip\_blanks}$ \5 +$(\T{2}+\\{max\_char\_code}{}$)\C{\\{state} code when ignoring blanks}\par +\B\4\D$\\{new\_line}$ \5 +$(\T{3}+\\{max\_char\_code}+\\{max\_char\_code}{}$)\C{\\{state} code at start of line}\par +\fi + +\M{304}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}\E\T{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}\E\T{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}+\T{1}$, and we have $\\{in\_open}\E\\{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}\E\T{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}[\T{1}\dotdot\\{max\_in\_open}]{}$ \&{int}\unskip' +by analogy with \\{line\_stack}. + +\Y\B\4\D$\\{terminal\_input}$ \5 +$(\\{name}\E\T{0}{}$)\C{are we reading from the terminal?}\par +\B\4\D$\\{cur\_file}$ \5 +\\{input\_file}[\\{index}]\C{the current \&{alpha\_file} variable}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{uint8\_t} \\{in\_open};\C{the number of lines in the buffer, less one}\6 +\&{uint8\_t} \\{open\_parens};\C{the number of open text files}\6 +\&{alpha\_file} \\{input\_file0}[\\{max\_in\_open}]${},{}$ ${}{*\&{const}\ }\\{input\_file}\K\\{input\_file0}-\T{1};{}$\6 +\&{int} \\{line};\C{current line number in the current source file}\6 +\&{int} \\{line\_stack0}[\\{max\_in\_open}]${},{}$ ${}{*\&{const}\ }\\{line\_stack}\K\\{line\_stack0}-\T{1}{}$;\par +\fi + +\M{305}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\B\4\D$\\{skipping}$ \5 +\T{1}\C{\\{scanner\_status} when passing conditional text}\par +\B\4\D$\\{defining}$ \5 +\T{2}\C{\\{scanner\_status} when reading a macro definition}\par +\B\4\D$\\{matching}$ \5 +\T{3}\C{\\{scanner\_status} when reading macro arguments}\par +\B\4\D$\\{aligning}$ \5 +\T{4}\C{\\{scanner\_status} when reading an alignment preamble}\par +\B\4\D$\\{absorbing}$ \5 +\T{5}\C{\\{scanner\_status} when reading a balanced text}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{uint8\_t} \\{scanner\_status};\C{can a subfile end now?}\6 +\&{pointer} \\{warning\_index};\C{identifier relevant to non-\\{normal} scanner status}\6 +\&{pointer} \\{def\_ref};\C{reference count of token list being defined}\par +\fi + +\M{306}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\B\4\X306:Declare the procedure called \\{runaway}\X${}\E{}$\6 +\&{void} \\{runaway}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{head of runaway list}\7 +\&{if} ${}(\\{scanner\_status}>\\{skipping}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"Runaway\ "});\6 +\&{switch} (\\{scanner\_status})\5 +${}\{{}$\1\6 +\4\&{case} \\{defining}:\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"definition"});\5 +${}\|p\K\\{def\_ref};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{matching}:\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"argument"});\5 +${}\|p\K\\{temp\_head};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{aligning}:\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"preamble"});\5 +${}\|p\K\\{hold\_head};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{absorbing}:\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"text"});\5 +${}\|p\K\\{def\_ref};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\C{there are no other cases}\2\6 +\\{print\_char}(\.{'?'});\5 +\\{print\_ln}(\,);\5 +${}\\{show\_token\_list}(\\{link}(\|p),\39\\{null},\39\\{error\_line}-\T{10});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U119.\fi + +\M{307}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}\E\\{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}\E\\{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\B\4\D$\\{token\_list}$ \5 +\T{0}\C{\\{state} code when scanning a token list}\par +\B\4\D$\\{token\_type}$ \5 +\\{index}\C{type of current token list}\par +\B\4\D$\\{param\_start}$ \5 +\\{limit}\C{base of macro parameters in \\{param\_stack}}\par +\B\4\D$\\{parameter}$ \5 +\T{0}\C{\\{token\_type} code for parameter}\par +\B\4\D$\\{u\_template}$ \5 +\T{1}\C{\\{token\_type} code for \<u_j> template}\par +\B\4\D$\\{v\_template}$ \5 +\T{2}\C{\\{token\_type} code for \<v_j> template}\par +\B\4\D$\\{backed\_up}$ \5 +\T{3}\C{\\{token\_type} code for text to be reread}\par +\B\4\D$\\{inserted}$ \5 +\T{4}\C{\\{token\_type} code for inserted texts}\par +\B\4\D$\\{macro}$ \5 +\T{5}\C{\\{token\_type} code for defined control sequences}\par +\B\4\D$\\{output\_text}$ \5 +\T{6}\C{\\{token\_type} code for output routines}\par +\B\4\D$\\{every\_par\_text}$ \5 +\T{7}\C{\\{token\_type} code for \.{\\everypar}}\par +\B\4\D$\\{every\_math\_text}$ \5 +\T{8}\C{\\{token\_type} code for \.{\\everymath}}\par +\B\4\D$\\{every\_display\_text}$ \5 +\T{9}\C{\\{token\_type} code for \.{\\everydisplay}}\par +\B\4\D$\\{every\_hbox\_text}$ \5 +\T{10}\C{\\{token\_type} code for \.{\\everyhbox}}\par +\B\4\D$\\{every\_vbox\_text}$ \5 +\T{11}\C{\\{token\_type} code for \.{\\everyvbox}}\par +\B\4\D$\\{every\_job\_text}$ \5 +\T{12}\C{\\{token\_type} code for \.{\\everyjob}}\par +\B\4\D$\\{every\_cr\_text}$ \5 +\T{13}\C{\\{token\_type} code for \.{\\everycr}}\par +\B\4\D$\\{mark\_text}$ \5 +\T{14}\C{\\{token\_type} code for \.{\\topmark}, etc.}\par +\B\4\D$\\{write\_text}$ \5 +\T{15}\C{\\{token\_type} code for \.{\\write}}\par +\fi + +\M{308}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} ${}\\{param\_stack}[\\{param\_size}+\T{1}]{}$;\C{token list pointers for parameters}\6 +\&{uint8\_t} \\{param\_ptr};\C{first unused entry in \\{param\_stack}}\6 +\&{int} \\{max\_param\_stack};\C{largest value of \\{param\_ptr}, will be $\Z$ $\\{param\_size}+\T{9}$}\par +\fi + +\M{309}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}\E\T{0}$. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{align\_state};\C{group level with respect to current alignment}\par +\fi + +\M{310}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{uint8\_t} \\{base\_ptr};\C{shallowest level shown by \\{show\_context}}\par +\fi + +\M{311}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\B\&{void} \\{show\_context}(\&{void})\C{prints where the scanner is}\6 +${}\{{}$\5 +\1\&{uint8\_t} \\{old\_setting};\C{saved \\{selector} setting}\6 +\&{int} \\{nn};\C{number of contexts shown so far, less one}\6 +\&{bool} \\{bottom\_line};\C{have we reached the final context to be shown?}\7 +\X315:Local variables for formatting calculations\X\6 +${}\\{base\_ptr}\K\\{input\_ptr};{}$\5 +${}\\{input\_stack}[\\{base\_ptr}]\K\\{cur\_input}{}$;\C{store current state}\6 +${}\\{nn}\K{-}\T{1};{}$\5 +${}\\{bottom\_line}\K\\{false};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1${}\\{cur\_input}\K\\{input\_stack}[\\{base\_ptr}]{}$;\C{enter into the context}\6 +\&{if} ${}((\\{state}\I\\{token\_list})){}$\1\6 +\&{if} ${}((\\{name}>\T{17})\V(\\{base\_ptr}\E\T{0})){}$\1\5 +${}\\{bottom\_line}\K\\{true};{}$\2\2\6 +\&{if} ${}((\\{base\_ptr}\E\\{input\_ptr})\V\\{bottom\_line}\V(\\{nn}<\\{error\_context\_lines})){}$\1\5 +\X312:Display the current context\X\2\6 +\&{else} \&{if} ${}(\\{nn}\E\\{error\_context\_lines}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"..."});\5 +\\{incr}(\\{nn});\C{omitted if $\\{error\_context\_lines}<\T{0}$}\6 +\4${}\}{}$\2\6 +\&{if} (\\{bottom\_line})\1\5 +\&{goto} \\{done};\2\6 +\\{decr}(\\{base\_ptr});\6 +\4${}\}{}$\2\6 +\4\\{done}:\5 +${}\\{cur\_input}\K\\{input\_stack}[\\{input\_ptr}]{}$;\C{restore original state}\6 +\4${}\}{}$\2\par +\fi + +\M{312}\B\X312:Display the current context\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}((\\{base\_ptr}\E\\{input\_ptr})\V(\\{state}\I\\{token\_list})\V(\\{token\_type}\I\\{backed\_up})\V(\\{loc}\I\\{null}){}$)\C{we omit backed-up token lists that have already been read}\6 +${}\{{}$\5 +\1${}\\{tally}\K\T{0}{}$;\C{get ready to count characters}\6 +${}\\{old\_setting}\K\\{selector};{}$\6 +\&{if} ${}(\\{state}\I\\{token\_list}){}$\5 +${}\{{}$\5 +\1\X313:Print location of current line\X;\6 +\X318:Pseudoprint the line\X;\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\X314:Print type of token list\X;\6 +\X319:Pseudoprint the token list\X;\6 +\4${}\}{}$\2\6 +${}\\{selector}\K\\{old\_setting}{}$;\C{stop pseudoprinting}\6 +\X317:Print two lines using the tricky pseudoprinted information\X;\6 +\\{incr}(\\{nn});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U311.\fi + +\M{313}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\B\4\X313:Print location of current line\X${}\E{}$\6 +\&{if} ${}(\\{name}\Z\T{17}){}$\1\6 +\&{if} (\\{terminal\_input})\1\6 +\&{if} ${}(\\{base\_ptr}\E\T{0}){}$\1\5 +\\{print\_nl}(\.{"<*>"});\2\6 +\&{else}\1\5 +\\{print\_nl}(\.{"<insert>\ "});\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"<read\ "});\6 +\&{if} ${}(\\{name}\E\T{17}){}$\1\5 +\\{print\_char}(\.{'*'});\5 +\2\&{else}\1\5 +${}\\{print\_int}(\\{name}-\T{1});{}$\2\6 +\\{print\_char}(\.{'>'});\6 +\4${}\}{}$\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"l."});\5 +\\{print\_int}(\\{line});\6 +\4${}\}{}$\2\6 +\\{print\_char}(\.{'\ '})\par +\U312.\fi + +\M{314}\B\X314:Print type of token list\X${}\E{}$\6 +\&{switch} (\\{token\_type})\5 +${}\{{}$\1\6 +\4\&{case} \\{parameter}:\5 +\\{print\_nl}(\.{"<argument>\ "});\5 +\&{break};\6 +\4\&{case} \\{u\_template}:\5 +\&{case} \\{v\_template}:\5 +\\{print\_nl}(\.{"<template>\ "});\5 +\&{break};\6 +\4\&{case} \\{backed\_up}:\6 +\&{if} ${}(\\{loc}\E\\{null}){}$\1\5 +\\{print\_nl}(\.{"<recently\ read>\ "});\2\6 +\&{else}\1\5 +\\{print\_nl}(\.{"<to\ be\ read\ again>\ }\)\.{"});\5 +\2\&{break};\6 +\4\&{case} \\{inserted}:\5 +\\{print\_nl}(\.{"<inserted\ text>\ "});\5 +\&{break};\6 +\4\&{case} \\{macro}:\6 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\\{print\_cs}(\\{name});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{output\_text}:\5 +\\{print\_nl}(\.{"<output>\ "});\5 +\&{break};\6 +\4\&{case} \\{every\_par\_text}:\5 +\\{print\_nl}(\.{"<everypar>\ "});\5 +\&{break};\6 +\4\&{case} \\{every\_math\_text}:\5 +\\{print\_nl}(\.{"<everymath>\ "});\5 +\&{break};\6 +\4\&{case} \\{every\_display\_text}:\5 +\\{print\_nl}(\.{"<everydisplay>\ "});\5 +\&{break};\6 +\4\&{case} \\{every\_hbox\_text}:\5 +\\{print\_nl}(\.{"<everyhbox>\ "});\5 +\&{break};\6 +\4\&{case} \\{every\_vbox\_text}:\5 +\\{print\_nl}(\.{"<everyvbox>\ "});\5 +\&{break};\6 +\4\&{case} \\{every\_job\_text}:\5 +\\{print\_nl}(\.{"<everyjob>\ "});\5 +\&{break};\6 +\4\&{case} \\{every\_cr\_text}:\5 +\\{print\_nl}(\.{"<everycr>\ "});\5 +\&{break};\6 +\4\&{case} \\{mark\_text}:\5 +\\{print\_nl}(\.{"<mark>\ "});\5 +\&{break};\6 +\4\&{case} \\{write\_text}:\5 +\\{print\_nl}(\.{"<write>\ "});\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_nl}(\.{"?"});\C{this should never happen}\6 +\4${}\}{}$\2\par +\U312.\fi + +\M{315}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}\K\T{0}$ and $\\{trick\_count}\K\T{1000000}$; 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}+\T{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\E\\{first\_count}$, and the length of the context information +gathered for line~2 is $m=\min(\\{tally}, \\{trick\_count})-k$. If $\|l+\|k\Z\|h$, +where $\|h\E\\{half\_error\_line}$, we print $\\{trick\_buf}[\T{0}\dotdot\|k-\T{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+\T{3})\dotdot\|k-\T{1}]$,}$$ +where subscripts of \\{trick\_buf} are circular modulo \\{error\_line}. The +second line consists of \|n~spaces followed by $\\{trick\_buf}[\|k\dotdot(\|k+\|m-\T{1})]$, +unless $\|n+\|m>\\{error\_line}$; in the latter case, further cropping is done. +This is easier to program than to explain. + +\Y\B\4\X315:Local variables for formatting calculations\X${}\E{}$\6 +\&{int} \|i;\C{index into \\{buffer}}\6 +\&{uint16\_t} \|j;\C{end of current line in \\{buffer}}\6 +\&{uint8\_t} \|l;\C{length of descriptive information on line 1}\6 +\&{int} \|m;\C{context information gathered for line 2}\6 +\&{uint8\_t} \|n;\C{length of line 1}\6 +\&{int} \|p;\C{starting or ending place in \\{trick\_buf}}\6 +\&{int} \|q;\C{temporary index}\par +\U311.\fi + +\M{316}The following code sets up the print routines so that they will gather +the desired information. + +\Y\B\4\D$\\{begin\_pseudoprint}$ \6 +${}\{{}$\5 +\1${}\|l\K\\{tally};{}$\5 +${}\\{tally}\K\T{0};{}$\5 +${}\\{selector}\K\\{pseudo};{}$\5 +${}\\{trick\_count}\K\T{1000000};{}$\6 +\4${}\}{}$\2\par +\B\4\D$\\{set\_trick\_count}$ \6 +${}\{{}$\5 +\1${}\\{first\_count}\K\\{tally};{}$\5 +${}\\{trick\_count}\K\\{tally}+\T{1}+\\{error\_line}-\\{half\_error\_line};{}$\6 +\&{if} ${}(\\{trick\_count}<\\{error\_line}){}$\1\5 +${}\\{trick\_count}\K\\{error\_line};{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{317}And the following code uses the information after it has been gathered. + +\Y\B\4\X317:Print two lines using the tricky pseudoprinted information\X${}\E{}$\6 +\&{if} ${}(\\{trick\_count}\E\T{1000000}){}$\1\5 +\\{set\_trick\_count};\C{\\{set\_trick\_count} must be performed}\2\6 +\&{if} ${}(\\{tally}<\\{trick\_count}){}$\1\5 +${}\|m\K\\{tally}-\\{first\_count};{}$\2\6 +\&{else}\1\5 +${}\|m\K\\{trick\_count}-\\{first\_count}{}$;\C{context on line 2}\2\6 +\&{if} ${}(\|l+\\{first\_count}\Z\\{half\_error\_line}){}$\5 +${}\{{}$\5 +\1${}\|p\K\T{0};{}$\5 +${}\|n\K\|l+\\{first\_count};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"..."});\5 +${}\|p\K\|l+\\{first\_count}-\\{half\_error\_line}+\T{3};{}$\5 +${}\|n\K\\{half\_error\_line};{}$\6 +\4${}\}{}$\2\6 +\&{for} ${}(\|q\K\|p;{}$ ${}\|q\Z\\{first\_count}-\T{1};{}$ ${}\|q\PP){}$\1\5 +${}\\{print\_char}(\\{trick\_buf}[\|q\MOD\\{error\_line}]);{}$\2\6 +\\{print\_ln}(\,);\6 +\&{for} ${}(\|q\K\T{1};{}$ ${}\|q\Z\|n;{}$ ${}\|q\PP){}$\1\5 +\\{print\_char}(\.{'\ '});\C{print \|n spaces to begin line~2}\2\6 +\&{if} ${}(\|m+\|n\Z\\{error\_line}){}$\1\5 +${}\|p\K\\{first\_count}+\|m;{}$\2\6 +\&{else}\1\5 +${}\|p\K\\{first\_count}+(\\{error\_line}-\|n-\T{3});{}$\2\6 +\&{for} ${}(\|q\K\\{first\_count};{}$ ${}\|q\Z\|p-\T{1};{}$ ${}\|q\PP){}$\1\5 +${}\\{print\_char}(\\{trick\_buf}[\|q\MOD\\{error\_line}]);{}$\2\6 +\&{if} ${}(\|m+\|n>\\{error\_line})$ \\{print\_str}(\.{"..."})\par +\U312.\fi + +\M{318}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\B\4\X318:Pseudoprint the line\X${}\E{}$\6 +\\{begin\_pseudoprint};\6 +\&{if} ${}(\\{buffer}[\\{limit}]\E\\{end\_line\_char}){}$\1\5 +${}\|j\K\\{limit};{}$\2\6 +\&{else}\1\5 +${}\|j\K\\{limit}+\T{1}{}$;\C{determine the effective end of the line}\2\6 +\&{if} ${}(\|j>\T{0}){}$\1\6 +\&{for} ${}(\|i\K\\{start};{}$ ${}\|i\Z\|j-\T{1};{}$ ${}\|i\PP){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|i\E\\{loc}){}$\1\5 +\\{set\_trick\_count};\2\6 +\\{print}(\\{buffer}[\|i]);\6 +\4${}\}{}$\2\2\par +\U312.\fi + +\M{319}\B\X319:Pseudoprint the token list\X${}\E{}$\6 +\\{begin\_pseudoprint}; \6 +\&{if} ${}(\\{token\_type}<\\{macro}){}$\1\5 +${}\\{show\_token\_list}(\\{start},\39\\{loc},\39\T{100000});{}$\2\6 +\&{else} $\\{show\_token\_list}(\\{link}(\\{start}),\39\\{loc},\39\T{100000}{}$)\C{avoid reference count}\par +\U312.\fi + +\M{320}Here is the missing piece of \\{show\_token\_list} that is activated when the +token beginning line~2 is about to be shown: + +\Y\B\4\X320:Do magic computation\X${}\E{}$\6 +\\{set\_trick\_count}\par +\U292.\fi + +\N{1}{321}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\B\4\D$\\{push\_input}$ \5 +\hbox{}\C{enter a new input level, save the old}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{input\_ptr}>\\{max\_in\_stack}){}$\5 +${}\{{}$\5 +\1${}\\{max\_in\_stack}\K\\{input\_ptr};{}$\6 +\&{if} ${}(\\{input\_ptr}\E\\{stack\_size}){}$\1\5 +${}\\{overflow}(\.{"input\ stack\ size"},\39\\{stack\_size});{}$\2\6 +\4${}\}{}$\2\6 +${}\\{input\_stack}[\\{input\_ptr}]\K\\{cur\_input}{}$;\C{stack the record}\6 +\\{incr}(\\{input\_ptr});\6 +\4${}\}{}$\2\par +\fi + +\M{322}And of course what goes up must come down. + +\Y\B\4\D$\\{pop\_input}$ \5 +\hbox{}\C{leave an input level, re-enter the old}\6 +${}\{{}$\5 +\1\\{decr}(\\{input\_ptr});\5 +${}\\{cur\_input}\K\\{input\_stack}[\\{input\_ptr}];{}$\6 +\4${}\}{}$\2\par +\fi + +\M{323}Here is a procedure that starts a new level of token-list input, given +a token list \|p and its type \|t. If $\|t\E\\{macro}$, the calling routine should +set \\{name} and \\{loc}. + +\Y\B\4\D$\\{back\_list}(\|X)$ \5 +$\\{begin\_token\_list}(\|X,\39\\{backed\_up}{}$)\C{backs up a simple token list}\par +\B\4\D$\\{ins\_list}(\|X)$ \5 +$\\{begin\_token\_list}(\|X,\39\\{inserted}{}$)\C{inserts a simple token list}\par +\Y\B\&{void} \\{begin\_token\_list}(\&{pointer} \|p${},\39{}$\&{quarterword} \|t)\1\1\2\2\6 +${}\{{}$\5 +\1\\{push\_input};\5 +${}\\{state}\K\\{token\_list};{}$\5 +${}\\{start}\K\|p;{}$\5 +${}\\{token\_type}\K\|t;{}$\6 +\&{if} ${}(\|t\G\\{macro}{}$)\C{the token list starts with a reference count}\6 +${}\{{}$\5 +\1\\{add\_token\_ref}(\|p);\6 +\&{if} ${}(\|t\E\\{macro}){}$\1\5 +${}\\{param\_start}\K\\{param\_ptr};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{loc}\K\\{link}(\|p);{}$\6 +\&{if} ${}(\\{tracing\_macros}>\T{1}){}$\5 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{""});\6 +\&{switch} (\|t)\5 +${}\{{}$\1\6 +\4\&{case} \\{mark\_text}:\5 +\\{print\_esc}(\X1401:\.{"mark"}\X);\5 +\&{break};\6 +\4\&{case} \\{write\_text}:\5 +\\{print\_esc}(\X1568:\.{"write"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +${}\\{print\_cmd\_chr}(\\{assign\_toks},\39\|t-\\{output\_text}+\\{output\_routine\_loc});{}$\6 +\4${}\}{}$\2\6 +\\{print\_str}(\.{"->"});\5 +\\{token\_show}(\|p);\5 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{loc}\K\|p;{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{324}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\B\&{void} \\{end\_token\_list}(\&{void})\C{leave a token-list input level}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{token\_type}\G\\{backed\_up}{}$)\C{token list to be deleted}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{token\_type}\Z\\{inserted}){}$\1\5 +\\{flush\_list}(\\{start});\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{delete\_token\_ref}(\\{start});\C{update reference count}\6 +\&{if} ${}(\\{token\_type}\E\\{macro}{}$)\C{parameters must be flushed}\1\6 +\&{while} ${}(\\{param\_ptr}>\\{param\_start}){}$\5 +${}\{{}$\5 +\1\\{decr}(\\{param\_ptr});\5 +\\{flush\_list}(\\{param\_stack}[\\{param\_ptr}]);\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{token\_type}\E\\{u\_template}){}$\1\6 +\&{if} ${}(\\{align\_state}>\T{500000}){}$\1\5 +${}\\{align\_state}\K\T{0};{}$\2\6 +\&{else}\1\5 +\\{fatal\_error}(\.{"(interwoven\ alignme}\)\.{nt\ preambles\ are\ not}\)\.{\ allowed)"});\2\2\6 +\\{pop\_input};\5 +\\{check\_interrupt};\6 +\4${}\}{}$\2\par +\fi + +\M{325}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\B\&{void} \\{back\_input}(\&{void})\C{undoes one token of input}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{a token list of length one}\7 +\&{while} ${}((\\{state}\E\\{token\_list})\W(\\{loc}\E\\{null})\W(\\{token\_type}\I\\{v\_template})){}$\1\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\6 +\&{if} ${}(\\{cur\_tok}<\\{left\_brace\_limit}){}$\1\5 +\\{decr}(\\{align\_state});\2\6 +\&{else}\1\5 +\\{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 +\4${}\}{}$\2\par +\fi + +\M{326}\B\X326:Insert token \|p into \TeX's input\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|t\K\\{cur\_tok};{}$\5 +${}\\{cur\_tok}\K\|p;{}$\5 +\\{back\_input}(\,);\5 +${}\\{cur\_tok}\K\|t;{}$\6 +\4${}\}{}$\2\par +\U282.\fi + +\M{327}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\B\&{void} \\{back\_error}(\&{void})\C{back up one token and call \&{error}}\6 +${}\{{}$\5 +\1${}\\{OK\_to\_interrupt}\K\\{false};{}$\5 +\\{back\_input}(\,);\5 +${}\\{OK\_to\_interrupt}\K\\{true};{}$\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\7 +\&{void} \\{ins\_error}(\&{void})\C{back up one inserted token and call \&{error}}\6 +${}\{{}$\5 +\1${}\\{OK\_to\_interrupt}\K\\{false};{}$\5 +\\{back\_input}(\,);\5 +${}\\{token\_type}\K\\{inserted};{}$\5 +${}\\{OK\_to\_interrupt}\K\\{true};{}$\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\fi + +\M{328}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\B\&{void} \\{begin\_file\_reading}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{in\_open}\E\\{max\_in\_open}){}$\1\5 +${}\\{overflow}(\.{"text\ input\ levels"},\39\\{max\_in\_open});{}$\2\6 +\&{if} ${}(\\{first}\E\\{buf\_size}){}$\1\5 +${}\\{overflow}(\.{"buffer\ size"},\39\\{buf\_size});{}$\2\6 +\\{incr}(\\{in\_open});\5 +\\{push\_input};\5 +${}\\{index}\K\\{in\_open};{}$\5 +${}\\{line\_stack}[\\{index}]\K\\{line};{}$\5 +${}\\{start}\K\\{first};{}$\5 +${}\\{state}\K\\{mid\_line};{}$\5 +${}\\{name}\K\T{0}{}$;\C{\\{terminal\_input} is now \\{true}}\6 +\4${}\}{}$\2\par +\fi + +\M{329}Conversely, the variables must be downdated when such a level of input +is finished: + +\Y\B\&{void} \\{end\_file\_reading}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{first}\K\\{start};{}$\5 +${}\\{line}\K\\{line\_stack}[\\{index}];{}$\6 +\&{if} ${}(\\{name}>\T{17}){}$\1\5 +${}\\{a\_close}({\AND}\\{cur\_file}){}$;\C{forget it}\2\6 +\\{pop\_input};\5 +\\{decr}(\\{in\_open});\6 +\4${}\}{}$\2\par +\fi + +\M{330}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\B\&{void} \\{clear\_for\_error\_prompt}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{while} ${}((\\{state}\I\\{token\_list})\W\\{terminal\_input}\W\30(\\{input\_ptr}>\T{0})\W(\\{loc}>\\{limit})){}$\1\5 +\\{end\_file\_reading}(\,);\2\6 +\\{print\_ln}(\,);\5 +\\{clear\_terminal};\6 +\4${}\}{}$\2\par +\fi + +\M{331}To get \TeX's whole input mechanism going, we perform the following +actions. + +\Y\B\4\X331:Initialize the input routines\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{input\_ptr}\K\T{0};{}$\5 +${}\\{max\_in\_stack}\K\T{0};{}$\5 +${}\\{in\_open}\K\T{0};{}$\5 +${}\\{open\_parens}\K\T{0};{}$\5 +${}\\{max\_buf\_stack}\K\T{0};{}$\5 +${}\\{param\_ptr}\K\T{0};{}$\5 +${}\\{max\_param\_stack}\K\T{0};{}$\5 +${}\\{first}\K\\{buf\_size}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\\{buffer}[\\{first}]\K\T{0};{}$\5 +\\{decr}(\\{first});\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{first}\E\T{0}));{}$\5 +${}\\{scanner\_status}\K\\{normal};{}$\5 +${}\\{warning\_index}\K\\{null};{}$\5 +${}\\{first}\K\T{1};{}$\5 +${}\\{state}\K\\{new\_line};{}$\5 +${}\\{start}\K\T{1};{}$\5 +${}\\{index}\K\T{0};{}$\5 +${}\\{line}\K\T{0};{}$\5 +${}\\{name}\K\T{0};{}$\5 +${}\\{force\_eof}\K\\{false};{}$\5 +${}\\{align\_state}\K\T{1000000}{}$;\6 +\&{if} ${}(\R\\{init\_terminal}(\,)){}$\1\5 +\\{exit}(\T{0});\2\6 +${}\\{limit}\K\\{last};{}$\5 +${}\\{first}\K\\{last}+\T{1}{}$;\C{\\{init\_terminal} has set \\{loc} and \\{last}}\6 +\4${}\}{}$\2\par +\U1337.\fi + +\N{1}{332}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}\E\\{cur\_chr}\E\\{cur\_cs}\E\T{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 + +\M{333}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{par\_loc};\C{location of `\.{\\par}' in \\{eqtb}}\6 +\&{halfword} \\{par\_token};\C{token representing `\.{\\par}'}\par +\fi + +\M{334}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1569:\.{"par"}\X,\39\\{par\_end},\39\T{256}){}$;\C{cf.\ \\{scan\_file\_name}}\6 +${}\\{par\_loc}\K\\{cur\_val};{}$\5 +${}\\{par\_token}\K\\{cs\_token\_flag}+\\{par\_loc}{}$;\par +\fi + +\M{335}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{par\_end}:\5 +\\{print\_esc}(\X1569:\.{"par"}\X);\5 +\&{break};\par +\fi + +\M{336}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\B\&{void} \\{check\_outer\_validity}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{points to inserted token list}\6 +\&{pointer} \|q;\C{auxiliary pointer}\7 +\&{if} ${}(\\{scanner\_status}\I\\{normal}){}$\5 +${}\{{}$\5 +\1${}\\{deletions\_allowed}\K\\{false};{}$\5 +\X337:Back up an outer control sequence so that it can be reread\X;\6 +\&{if} ${}(\\{scanner\_status}>\\{skipping}){}$\1\5 +\X338:Tell the user what has run away and try to recover\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Incomplete\ "});\5 +${}\\{print\_cmd\_chr}(\\{if\_test},\39\\{cur\_if});{}$\5 +\\{print\_str}(\.{";\ all\ text\ was\ igno}\)\.{red\ after\ line\ "});\5 +\\{print\_int}(\\{skip\_line});\5 +\\{help3}(\.{"A\ forbidden\ control}\)\.{\ sequence\ occurred\ i}\)\.{n\ skipped\ text."})\6 +(\.{"This\ kind\ of\ error\ }\)\.{happens\ when\ you\ say}\)\.{\ `\\\\if...'\ and\ forge}\)\.{t"})\6 +(\.{"the\ matching\ `\\\\fi'}\)\.{.\ I've\ inserted\ a\ `\\}\)\.{\\fi';\ this\ might\ wor}\)\.{k."});\6 +\&{if} ${}(\\{cur\_cs}\I\T{0}){}$\1\5 +${}\\{cur\_cs}\K\T{0};{}$\2\6 +\&{else}\1\5 +${}\\{help\_line}[\T{2}]\K\30\.{"The\ file\ ended\ whil}\)\.{e\ I\ was\ skipping\ con}\)\.{ditional\ text."};{}$\2\6 +${}\\{cur\_tok}\K\\{cs\_token\_flag}+\\{frozen\_fi};{}$\5 +\\{ins\_error}(\,);\6 +\4${}\}{}$\2\6 +${}\\{deletions\_allowed}\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{337}An outer control sequence that occurs in a \.{\\read} will not be reread, +since the error recovery for \.{\\read} is not very powerful. + +\Y\B\4\X337:Back up an outer control sequence so that it can be reread\X${}\E{}$\6 +\&{if} ${}(\\{cur\_cs}\I\T{0}){}$\5 +${}\{{}$\5 +\1\&{if} ${}((\\{state}\E\\{token\_list})\V(\\{name}<\T{1})\V(\\{name}>\T{17})){}$\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +${}\\{cur\_cmd}\K\\{spacer};{}$\5 +${}\\{cur\_chr}\K\.{'\ '}{}$;\C{replace it by a space}\6 +\4${}\}{}$\2\par +\U336.\fi + +\M{338}\B\X338:Tell the user what has run away and try to recover\X${}\E{}$\6 +${}\{{}$\5 +\1\\{runaway}(\,);\C{print a definition, argument, or preamble}\6 +\&{if} ${}(\\{cur\_cs}\E\T{0}){}$\1\5 +\\{print\_err}(\.{"File\ ended"})\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_cs}\K\T{0};{}$\5 +\\{print\_err}(\.{"Forbidden\ control\ s}\)\.{equence\ found"});\6 +\4${}\}{}$\2\6 +\\{print\_str}(\.{"\ while\ scanning\ "});\5 +\X339:Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `\.{text}', and insert tokens that should lead to recovery\X;\6 +\\{print\_str}(\.{"\ of\ "});\5 +\\{sprint\_cs}(\\{warning\_index});\5 +\\{help4}(\.{"I\ suspect\ you\ have\ }\)\.{forgotten\ a\ `\}',\ cau}\)\.{sing\ me"})\6 +(\.{"to\ read\ past\ where\ }\)\.{you\ wanted\ me\ to\ sto}\)\.{p."})\6 +(\.{"I'll\ try\ to\ recover}\)\.{;\ but\ if\ the\ error\ i}\)\.{s\ serious,"})\6 +(\.{"you'd\ better\ type\ `}\)\.{E'\ or\ `X'\ now\ and\ fi}\)\.{x\ your\ file."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U336.\fi + +\M{339}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\B\4\X339:Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `\.{text}', and insert tokens that should lead to recovery\X${}\E{}$\6 +$\|p\K\\{get\_avail}(\,);{}$\6 +\&{switch} (\\{scanner\_status})\5 +${}\{{}$\1\6 +\4\&{case} \\{defining}:\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"definition"});\5 +${}\\{info}(\|p)\K\\{right\_brace\_token}+\.{'\}'};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{matching}:\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"use"});\5 +${}\\{info}(\|p)\K\\{par\_token};{}$\5 +${}\\{long\_state}\K\\{outer\_call};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{aligning}:\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"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{-}\T{1000000};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{absorbing}:\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"text"});\5 +${}\\{info}(\|p)\K\\{right\_brace\_token}+\.{'\}'};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\C{there are no other cases}\2\6 +\\{ins\_list}(\|p)\par +\U338.\fi + +\M{340}We need to mention a procedure here that may be called by \\{get\_next}. + +\Y\B\&{void} \\{firm\_up\_the\_line}(\&{void});\par +\fi + +\M{341}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\B\&{void} \\{get\_next}(\&{void})\C{sets \\{cur\_cmd}, \\{cur\_chr}, \\{cur\_cs} to next token}\6 +${}\{{}$\5 +\C{go here to get the next input token}\C{go here to eat the next character from a file}\C{go here to digest it again}\C{go here to start looking for a control sequence}\C{go here when a control sequence has been found}\C{go here when the next input +token has been got}\1\6 +\&{uint16\_t} \|k;\C{an index into \\{buffer}}\6 +\&{halfword} \|t;\C{a token}\6 +\&{uint8\_t} \\{cat};\C{\\{cat\_code}(\\{cur\_chr}), usually}\6 +\&{ASCII\_code} \|c${},{}$ \\{cc};\C{constituents of a possible expanded code}\6 +\&{uint8\_t} \|d;\C{number of excess characters in an expanded code}\7 +\4\\{restart}:\5 +${}\\{cur\_cs}\K\T{0};{}$\6 +\&{if} ${}(\\{state}\I\\{token\_list}){}$\1\5 +\X343:Input from external file, \&{goto} \\{restart} if no input found\X\2\6 +\&{else}\1\5 +\X357:Input from token list, \&{goto} \\{restart} if end of list or if a parameter needs to be expanded\X;\2\6 +\X342:If an alignment entry has just ended, take appropriate action\X;\6 +\4${}\}{}$\2\par +\fi + +\M{342}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\B\4\X342:If an alignment entry has just ended, take appropriate action\X${}\E{}$\6 +\&{if} ${}(\\{cur\_cmd}\Z\\{car\_ret}){}$\1\6 +\&{if} ${}(\\{cur\_cmd}\G\\{tab\_mark}){}$\1\6 +\&{if} ${}(\\{align\_state}\E\T{0}){}$\1\5 +\X789:Insert the \(v)\<v_j> template and \&{goto} \\{restart}\X\2\2\2\par +\U341.\fi + +\M{343}\B\X343:Input from external file, \&{goto} \\{restart} if no input found\X${}\E{}$\6 +${}\{{}$\5 +\1\\{get\_cur\_chr}:\6 +\&{if} ${}(\\{loc}\Z\\{limit}{}$)\C{current line not yet finished}\6 +${}\{{}$\5 +\1${}\\{cur\_chr}\K\\{buffer}[\\{loc}];{}$\5 +\\{incr}(\\{loc});\6 +\4\\{reswitch}:\5 +${}\\{cur\_cmd}\K\\{cat\_code}(\\{cur\_chr});{}$\5 +\X344: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 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{state}\K\\{new\_line}{}$;\6 +\X360: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} \\{get\_cur\_chr};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U341.\fi + +\M{344}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}+\T{1}$, so we can add a character's +command code to the state to get a single number that characterizes both. + +\Y\B\4\D$\\{any\_state\_plus}(\|X)$ \5 +\&{case} \\{mid\_line}${}+\|X{}$:\5 +\&{case} \\{skip\_blanks}${}+\|X{}$: \&{case} \\{new\_line}${}+{}$\|X\par +\Y\B\4\X344: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${}\E{}$\6 +\&{switch} ${}(\\{state}+\\{cur\_cmd}){}$\5 +${}\{{}$\1\6 +\4\X345:Cases where character is ignored\X:\5 +\&{goto} \\{get\_cur\_chr};\6 +\4\\{any\_state\_plus}(\\{escape}):\5 +\X354:Scan a control sequence and set \\{state}: $\K$ \\{skip\_blanks} or \\{mid\_line}\X\5 +\&{break};\6 +\4\\{any\_state\_plus}(\\{active\_char}):\5 +\X353:Process an active-character control sequence and set \\{state}: $\K$ \\{mid\_line}\X\5 +\&{break};\6 +\4\\{any\_state\_plus}(\\{sup\_mark}):\5 +\X352:If this \\{sup\_mark} starts an expanded character like~\.{\^\^A} or~\.{\^\^df}, then \&{goto} \\{reswitch}, otherwise set \\{state}: $\K$ \\{mid\_line}\X\5 +\&{break};\6 +\4\\{any\_state\_plus}(\\{invalid\_char}):\5 +\X346:Decry the invalid character and \&{goto} \\{restart}\X\6 +\hbox{\4}\X347:Handle situations involving spaces, braces, changes of state\X\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\par +\U343.\fi + +\M{345}\B\X345:Cases where character is ignored\X${}\E{}$\6 +\\{any\_state\_plus}(\\{ignore}):\5 +\&{case} \\{skip\_blanks}${}+\\{spacer}{}$: \&{case} \\{new\_line}${}+{}$\\{spacer}\par +\U344.\fi + +\M{346}We go to \\{restart} instead of to \\{get\_cur\_chr}, because \\{state} might equal +\\{token\_list} after the error has been dealt with +(cf.\ \\{clear\_for\_error\_prompt}). + +\Y\B\4\X346:Decry the invalid character and \&{goto} \\{restart}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Text\ line\ contains\ }\)\.{an\ invalid\ character}\)\.{"});\5 +\\{help2}(\.{"A\ funny\ symbol\ that}\)\.{\ I\ can't\ read\ has\ ju}\)\.{st\ been\ input."})\6 +(\.{"Continue,\ and\ I'll\ }\)\.{forget\ that\ it\ ever\ }\)\.{happened."});\6 +${}\\{deletions\_allowed}\K\\{false};{}$\6 +\&{error} (\,)\1\5 +;\2\6 +${}\\{deletions\_allowed}\K\\{true};{}$\5 +\&{goto} \\{restart};\6 +\4${}\}{}$\2\par +\U344.\fi + +\M{347}\B\D$\\{add\_delims\_to}(\|X)$ \5 +$\|X+\\{math\_shift}{}$:\5 +${}\|X+\\{tab\_mark}{}$:\5 +${}\|X+\\{mac\_param}{}$:\5 +${}\|X+\\{sub\_mark}{}$:\5 +${}\|X+\\{letter}{}$: $\|X+{}$\\{other\_char}\par +\Y\B\4\X347:Handle situations involving spaces, braces, changes of state\X${}\E{}$\6 +\4\&{case} \\{mid\_line}${}+\\{spacer}{}$:\5 +\X349:Enter \\{skip\_blanks} state, emit a space\X\5 +\&{break};\6 +\4\&{case} \\{mid\_line}${}+\\{car\_ret}{}$:\5 +\X348:Finish line, emit a space\X\5 +\&{break};\6 +\4\&{case} \\{skip\_blanks}${}+\\{car\_ret}{}$:\5 +\\{any\_state\_plus}(\\{comment}):\5 +\X350:Finish line, \&{goto} \&{switch}\X\6 +\4\&{case} \\{new\_line}${}+\\{car\_ret}{}$:\5 +\X351:Finish line, emit a \.{\\par}\X\5 +\&{break};\6 +\4\&{case} \\{mid\_line}${}+\\{left\_brace}{}$:\5 +\\{incr}(\\{align\_state});\5 +\&{break};\6 +\4\&{case} \\{skip\_blanks}${}+\\{left\_brace}{}$:\5 +\&{case} \\{new\_line}${}+\\{left\_brace}{}$:\6 +${}\{{}$\5 +\1${}\\{state}\K\\{mid\_line};{}$\5 +\\{incr}(\\{align\_state});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{mid\_line}${}+\\{right\_brace}{}$:\5 +\\{decr}(\\{align\_state});\5 +\&{break};\6 +\4\&{case} \\{skip\_blanks}${}+\\{right\_brace}{}$:\5 +\&{case} \\{new\_line}${}+\\{right\_brace}{}$:\6 +${}\{{}$\5 +\1${}\\{state}\K\\{mid\_line};{}$\5 +\\{decr}(\\{align\_state});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\\{add\_delims\_to}(\&{case} \\{skip\_blanks}):\5 +\\{add\_delims\_to}(\&{case} \\{new\_line}):\5 +${}\\{state}\K\\{mid\_line}{}$;\5 +\&{break};\par +\U344.\fi + +\M{348}When a character of type \\{spacer} gets through, its character code is +changed to $\.{"\ "}=040$. 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\B\4\X348:Finish line, emit a space\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{loc}\K\\{limit}+\T{1};{}$\5 +${}\\{cur\_cmd}\K\\{spacer};{}$\5 +${}\\{cur\_chr}\K\.{'\ '};{}$\6 +\4${}\}{}$\2\par +\U347.\fi + +\M{349}The following code is performed only when $\\{cur\_cmd}\E\\{spacer}$. + +\Y\B\4\X349:Enter \\{skip\_blanks} state, emit a space\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{state}\K\\{skip\_blanks};{}$\5 +${}\\{cur\_chr}\K\.{'\ '};{}$\6 +\4${}\}{}$\2\par +\U347.\fi + +\M{350}\B\X350:Finish line, \&{goto} \&{switch}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{loc}\K\\{limit}+\T{1};{}$\5 +\&{goto} \\{get\_cur\_chr};\6 +\4${}\}{}$\2\par +\U347.\fi + +\M{351}\B\X351:Finish line, emit a \.{\\par}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{loc}\K\\{limit}+\T{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\5 +\\{check\_outer\_validity}(\,);\2\6 +\4${}\}{}$\2\par +\U347.\fi + +\M{352}Notice that a code like \.{\^\^8} becomes \.x if not followed by a hex digit. + +\Y\B\4\D$\\{is\_hex}(\|X)$ \5 +$(((\|X\G\.{'0'})\W(\|X\Z\.{'9'}))\V((\|X\G\.{'a'})\W(\|X\Z\.{'f'})){}$)\par +\B\4\D$\\{hex\_to\_cur\_chr}$ \6 +\&{if} ${}(\|c\Z\.{'9'}){}$\1\5 +${}\\{cur\_chr}\K\|c-\.{'0'}{}$;\5 +\2\&{else}\1\5 +${}\\{cur\_chr}\K\|c-\.{'a'}+\T{10};{}$\2\6 +\&{if} ${}(\\{cc}\Z\.{'9'}){}$\1\5 +${}\\{cur\_chr}\K\T{16}*\\{cur\_chr}+\\{cc}-\.{'0'};{}$\2\6 +\&{else} $\\{cur\_chr}\K\T{16}*\\{cur\_chr}+\\{cc}-\.{'a'}+{}$\T{10}\par +\Y\B\4\X352:If this \\{sup\_mark} starts an expanded character like~\.{\^\^A} or~\.{\^\^df}, then \&{goto} \\{reswitch}, otherwise set \\{state}: $\K$ \\{mid\_line}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_chr}\E\\{buffer}[\\{loc}]){}$\1\6 +\&{if} ${}(\\{loc}<\\{limit}){}$\5 +${}\{{}$\5 +\1${}\|c\K\\{buffer}[\\{loc}+\T{1}]{}$;\5 +\&{if} ${}(\|c<\T{\~200}{}$)\C{yes we have an expanded char}\6 +${}\{{}$\5 +\1${}\\{loc}\K\\{loc}+\T{2};{}$\6 +\&{if} (\\{is\_hex}(\|c))\1\6 +\&{if} ${}(\\{loc}\Z\\{limit}){}$\5 +${}\{{}$\5 +\1${}\\{cc}\K\\{buffer}[\\{loc}]{}$;\5 +\&{if} (\\{is\_hex}(\\{cc}))\5 +${}\{{}$\5 +\1\\{incr}(\\{loc});\5 +\\{hex\_to\_cur\_chr};\5 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\2\6 +\&{if} ${}(\|c<\T{\~100}){}$\1\5 +${}\\{cur\_chr}\K\|c+\T{\~100}{}$;\5 +\2\&{else}\1\5 +${}\\{cur\_chr}\K\|c-\T{\~100};{}$\2\6 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\2\6 +${}\\{state}\K\\{mid\_line};{}$\6 +\4${}\}{}$\2\par +\U344.\fi + +\M{353}\B\X353:Process an active-character control sequence and set \\{state}: $\K$ \\{mid\_line}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{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\5 +\\{check\_outer\_validity}(\,);\2\6 +\4${}\}{}$\2\par +\U344.\fi + +\M{354}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}+\T{1}]$, but it never looks at $\\{buffer}[\\{limit}+\T{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\B\4\X354:Scan a control sequence and set \\{state}: $\K$ \\{skip\_blanks} or \\{mid\_line}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{loc}>\\{limit}){}$\1\5 +${}\\{cur\_cs}\K\\{null\_cs}{}$;\C{\\{state} is irrelevant in this case}\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{start\_cs}:\5 +${}\|k\K\\{loc};{}$\5 +${}\\{cur\_chr}\K\\{buffer}[\|k];{}$\5 +${}\\{cat}\K\\{cat\_code}(\\{cur\_chr});{}$\5 +\\{incr}(\|k);\6 +\&{if} ${}(\\{cat}\E\\{letter}){}$\1\5 +${}\\{state}\K\\{skip\_blanks};{}$\2\6 +\&{else} \&{if} ${}(\\{cat}\E\\{spacer}){}$\1\5 +${}\\{state}\K\\{skip\_blanks};{}$\2\6 +\&{else}\1\5 +${}\\{state}\K\\{mid\_line};{}$\2\6 +\&{if} ${}((\\{cat}\E\\{letter})\W(\|k\Z\\{limit})){}$\1\5 +\X356: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\2\6 +\&{else}\1\5 +\X355:If an expanded code is present, reduce it and \&{goto} \\{start\_cs}\X;\2\6 +${}\\{cur\_cs}\K\\{single\_base}+\\{buffer}[\\{loc}];{}$\5 +\\{incr}(\\{loc});\6 +\4${}\}{}$\2\6 +\4\\{found}:\5 +${}\\{cur\_cmd}\K\\{eq\_type}(\\{cur\_cs});{}$\5 +${}\\{cur\_chr}\K\\{equiv}(\\{cur\_cs});{}$\6 +\&{if} ${}(\\{cur\_cmd}\G\\{outer\_call}){}$\1\5 +\\{check\_outer\_validity}(\,);\2\6 +\4${}\}{}$\2\par +\U344.\fi + +\M{355}Whenever we reach the following piece of code, we will have +$\\{cur\_chr}\E\\{buffer}[\|k-\T{1}]$ and $\|k\Z\\{limit}+\T{1}$ and $\\{cat}\E\\{cat\_code}(\\{cur\_chr})$. If an +expanded code like \.{\^\^A} or \.{\^\^df} appears in $\\{buffer}[(\|k-\T{1})\dotdot(\|k+\T{1})]$ +or $\\{buffer}[(\|k-\T{1})\dotdot(\|k+\T{2})]$, we +will store the corresponding code in $\\{buffer}[\|k-\T{1}]$ and shift the rest of +the buffer left two or three places. + +\Y\B\4\X355:If an expanded code is present, reduce it and \&{goto} \\{start\_cs}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{buffer}[\|k]\E\\{cur\_chr}{}$)\5 +\1\&{if} ${}(\\{cat}\E\\{sup\_mark}{}$)\5 +\1\&{if} ${}(\|k<\\{limit}){}$\5 +${}\{{}$\5 +\1${}\|c\K\\{buffer}[\|k+\T{1}]{}$;\5 +\&{if} ${}(\|c<\T{\~200}{}$)\C{yes, one is indeed present}\6 +${}\{{}$\5 +\1${}\|d\K\T{2};{}$\6 +\&{if} (\\{is\_hex}(\|c))\5 +\1\&{if} ${}(\|k+\T{2}\Z\\{limit}){}$\5 +${}\{{}$\5 +\1${}\\{cc}\K\\{buffer}[\|k+\T{2}]{}$;\5 +\&{if} (\\{is\_hex}(\\{cc}))\1\5 +\\{incr}(\|d);\2\6 +\4${}\}{}$\2\2\6 +\&{if} ${}(\|d>\T{2}){}$\5 +${}\{{}$\5 +\1\\{hex\_to\_cur\_chr};\5 +${}\\{buffer}[\|k-\T{1}]\K\\{cur\_chr};{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|c<\T{\~100}){}$\1\5 +${}\\{buffer}[\|k-\T{1}]\K\|c+\T{\~100};{}$\2\6 +\&{else}\1\5 +${}\\{buffer}[\|k-\T{1}]\K\|c-\T{\~100};{}$\2\6 +${}\\{limit}\K\\{limit}-\|d;{}$\5 +${}\\{first}\K\\{first}-\|d;{}$\6 +\&{while} ${}(\|k\Z\\{limit}){}$\5 +${}\{{}$\5 +\1${}\\{buffer}[\|k]\K\\{buffer}[\|k+\|d];{}$\5 +\\{incr}(\|k);\6 +\4${}\}{}$\2\6 +\&{goto} \\{start\_cs};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\2\2\6 +\4${}\}{}$\2\par +\Us354\ET356.\fi + +\M{356}\B\X356: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${}% +\E{}$\6 +${}\{{}$\5 +\1\&{do}\5 +${}\{{}$\1\6 +${}\\{cur\_chr}\K\\{buffer}[\|k];{}$\5 +${}\\{cat}\K\\{cat\_code}(\\{cur\_chr});{}$\5 +\\{incr}(\|k);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R((\\{cat}\I\\{letter})\V(\|k>\\{limit})));{}$\5 +\X355:If an expanded code is present, reduce it and \&{goto} \\{start\_cs}\X;\6 +\&{if} ${}(\\{cat}\I\\{letter}){}$\1\5 +\\{decr}(\|k);\C{now \|k points to first nonletter}\2\6 +\&{if} ${}(\|k>\\{loc}+\T{1}{}$)\C{multiletter control sequence has been scanned}\6 +${}\{{}$\5 +\1${}\\{cur\_cs}\K\\{id\_lookup}(\\{loc},\39\|k-\\{loc});{}$\5 +${}\\{loc}\K\|k;{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U354.\fi + +\M{357}Let's consider now what happens when \\{get\_next} is looking at a token list. + +\Y\B\4\X357:Input from token list, \&{goto} \\{restart} if end of list or if a parameter needs to be expanded\X${}\E{}$\6 +\&{if} ${}(\\{loc}\I\\{null}{}$)\C{list not exhausted}\6 +${}\{{}$\5 +\1${}\|t\K\\{info}(\\{loc});{}$\5 +${}\\{loc}\K\\{link}(\\{loc}){}$;\C{move to next}\6 +\&{if} ${}(\|t\G\\{cs\_token\_flag}{}$)\C{a control sequence token}\6 +${}\{{}$\5 +\1${}\\{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\6 +\&{if} ${}(\\{cur\_cmd}\E\\{dont\_expand}){}$\1\5 +\X358:Get the next token, suppressing expansion\X\2\6 +\&{else}\1\5 +\\{check\_outer\_validity}(\,);\2\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_cmd}\K\|t/\T{\~400};{}$\5 +${}\\{cur\_chr}\K\|t\MOD\T{\~400};{}$\6 +\&{switch} (\\{cur\_cmd})\5 +${}\{{}$\1\6 +\4\&{case} \\{left\_brace}:\5 +\\{incr}(\\{align\_state});\5 +\&{break};\6 +\4\&{case} \\{right\_brace}:\5 +\\{decr}(\\{align\_state});\5 +\&{break};\6 +\4\&{case} \\{out\_param}:\5 +\X359:Insert macro parameter and \&{goto} \\{restart}\X\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\C{we are done with this token list}\1\6 +\\{end\_token\_list}(\,);\5 +\&{goto} \\{restart};\C{resume previous level}\6 +\4${}\}{}$\2\par +\U341.\fi + +\M{358}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})\E\\{null}$. + +\Y\B\4\D$\\{no\_expand\_flag}$ \5 +\T{257}\C{this characterizes a special variant of \\{relax}}\par +\Y\B\4\X358:Get the next token, suppressing expansion\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{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}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_cmd}\K\\{relax};{}$\5 +${}\\{cur\_chr}\K\\{no\_expand\_flag};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U357.\fi + +\M{359}\B\X359:Insert macro parameter and \&{goto} \\{restart}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{begin\_token\_list}(\\{param\_stack}[\\{param\_start}+\\{cur\_chr}-\T{1}],\39\\{parameter});{}$\5 +\&{goto} \\{restart};\6 +\4${}\}{}$\2\par +\U357.\fi + +\M{360}All of the easy branches of \\{get\_next} have now been taken care of. +There is one more branch. + +\Y\B\4\D$\\{end\_line\_char\_inactive}$ \5 +$(\\{end\_line\_char}<\T{0})\V(\\{end\_line\_char}>\T{255}{}$)\par +\Y\B\4\X360:Move to next line of file, or \&{goto} \\{restart} if there is no next line, or \&{return} if a \.{\\read} line has finished\X${}\E{}$\6 +\&{if} ${}(\\{name}>\T{17}){}$\1\5 +\X362:Read next line of file into \\{buffer}, or \&{goto} \\{restart} if the file has ended\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\R\\{terminal\_input}{}$)\C{\.{\\read} line has ended}\6 +${}\{{}$\5 +\1${}\\{cur\_cmd}\K\T{0};{}$\5 +${}\\{cur\_chr}\K\T{0};{}$\5 +\&{return};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{input\_ptr}>\T{0}{}$)\C{text was inserted during error recovery}\6 +${}\{{}$\5 +\1\\{end\_file\_reading}(\,);\5 +\&{goto} \\{restart};\C{resume previous level}\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{selector}<\\{log\_only}){}$\1\5 +\\{open\_log\_file}(\,);\2\6 +\&{if} ${}(\\{interaction}>\\{nonstop\_mode}){}$\5 +${}\{{}$\5 +\1\&{if} (\\{end\_line\_char\_inactive})\1\5 +\\{incr}(\\{limit});\2\6 +\&{if} ${}(\\{limit}\E\\{start}{}$)\C{previous line was empty}\1\6 +\\{print\_nl}(\.{"(Please\ type\ a\ comm}\)\.{and\ 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\5 +\\{decr}(\\{limit});\2\6 +\&{else}\1\5 +${}\\{buffer}[\\{limit}]\K\\{end\_line\_char};{}$\2\6 +${}\\{first}\K\\{limit}+\T{1};{}$\5 +${}\\{loc}\K\\{start};{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{fatal\_error}(\.{"***\ (job\ aborted,\ n}\)\.{o\ legal\ \\\\end\ found)}\)\.{"});\C{nonstop mode, which is intended for overnight batch processing, never waits for on-line input}\2\6 +\4${}\}{}$\2\par +\U343.\fi + +\M{361}The global variable \\{force\_eof} is normally \\{false}; it is set \\{true} +by an \.{\\endinput} command. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{bool} \\{force\_eof};\C{should the next \.{\\input} be aborted early?}\par +\fi + +\M{362}\B\X362:Read next line of file into \\{buffer}, or \&{goto} \\{restart} if the file has ended\X${}\E{}$\6 +${}\{{}$\5 +\1\\{incr}(\\{line});\5 +${}\\{first}\K\\{start};{}$\6 +\&{if} ${}(\R\\{force\_eof}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{input\_ln}({\AND}\\{cur\_file},\39\\{true}){}$)\C{not end of file}\1\6 +\\{firm\_up\_the\_line}(\,);\C{this sets \\{limit}}\2\6 +\&{else}\1\5 +${}\\{force\_eof}\K\\{true};{}$\2\6 +\4${}\}{}$\2\6 +\&{if} (\\{force\_eof})\5 +${}\{{}$\5 +\1\\{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} \\{restart};\6 +\4${}\}{}$\2\6 +\&{if} (\\{end\_line\_char\_inactive})\1\5 +\\{decr}(\\{limit});\2\6 +\&{else}\1\5 +${}\\{buffer}[\\{limit}]\K\\{end\_line\_char};{}$\2\6 +${}\\{first}\K\\{limit}+\T{1};{}$\5 +${}\\{loc}\K\\{start}{}$;\C{ready to read}\6 +\4${}\}{}$\2\par +\U360.\fi + +\M{363}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\B\&{void} \\{firm\_up\_the\_line}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|k;\C{an index into \\{buffer}}\7 +${}\\{limit}\K\\{last};{}$\6 +\&{if} ${}(\\{pausing}>\T{0}){}$\1\6 +\&{if} ${}(\\{interaction}>\\{nonstop\_mode}){}$\5 +${}\{{}$\5 +\1\\{wake\_up\_terminal};\5 +\\{print\_ln}(\,);\6 +\&{if} ${}(\\{start}<\\{limit}){}$\1\6 +\&{for} ${}(\|k\K\\{start};{}$ ${}\|k\Z\\{limit}-\T{1};{}$ ${}\|k\PP){}$\1\5 +\\{print}(\\{buffer}[\|k]);\2\2\6 +${}\\{first}\K\\{limit};{}$\5 +\\{prompt\_input}(\.{"=>"});\C{wait for user response}\6 +\&{if} ${}(\\{last}>\\{first}){}$\5 +${}\{{}$\5 +\1\&{for} ${}(\|k\K\\{first};{}$ ${}\|k\Z\\{last}-\T{1};{}$ ${}\|k\PP{}$)\C{move line down in buffer}\1\6 +${}\\{buffer}[\|k+\\{start}-\\{first}]\K\\{buffer}[\|k];{}$\2\6 +${}\\{limit}\K\\{start}+\\{last}-\\{first};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\par +\fi + +\M{364}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 + +\M{365}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\B\&{void} \\{get\_token}(\&{void})\C{sets \\{cur\_cmd}, \\{cur\_chr}, \\{cur\_tok}}\6 +${}\{{}$\5 +\1${}\\{no\_new\_control\_sequence}\K\\{false};{}$\5 +\\{get\_next}(\,);\5 +${}\\{no\_new\_control\_sequence}\K\\{true};{}$\6 +\&{if} ${}(\\{cur\_cs}\E\T{0}){}$\1\5 +${}\\{cur\_tok}\K(\\{cur\_cmd}*\T{\~400})+\\{cur\_chr};{}$\2\6 +\&{else}\1\5 +${}\\{cur\_tok}\K\\{cs\_token\_flag}+\\{cur\_cs};{}$\2\6 +\4${}\}{}$\2\par +\fi + +\N{1}{366}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} + +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\B\hbox{\4}\X389:Declare the procedure called \\{macro\_call}\X\6 +\hbox{\4}\X379:Declare the procedure called \\{insert\_relax}\X\7 +\&{void} \\{pass\_text}(\&{void});\6 +\&{void} \\{start\_input}(\&{void});\6 +\&{void} \\{conditional}(\&{void});\6 +\&{void} \\{get\_x\_token}(\&{void});\6 +\&{void} \\{conv\_toks}(\&{void});\6 +\&{void} \\{ins\_the\_toks}(\&{void});\7 +\&{void} \\{expand}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{halfword} \|t;\C{token that is being ``expanded after''}\6 +\&{pointer} \|p${},{}$ \|q${},{}$ \|r;\C{for list manipulation}\6 +\&{uint16\_t} \|j;\C{index into \\{buffer}}\6 +\&{int} \\{cv\_backup};\C{to save the global quantity \\{cur\_val}}\6 +\&{small\_number} \\{cvl\_backup}${},{}$ \\{radix\_backup}${},{}$ \\{co\_backup};\C{to save \\{cur\_val\_level}, etc.}\6 +\&{pointer} \\{backup\_backup};\C{to save \\{link}(\\{backup\_head})}\6 +\&{small\_number} \\{save\_scanner\_status};\C{temporary storage of \\{scanner\_status}}\7 +${}\\{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\5 +\X367:Expand a nonmacro\X\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}<\\{end\_template}){}$\1\5 +\\{macro\_call}(\,);\2\6 +\&{else}\1\5 +\X375:Insert a token containing \\{frozen\_endv}\X;\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};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{367}\B\X367:Expand a nonmacro\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{tracing\_commands}>\T{1}){}$\1\5 +\\{show\_cur\_cmd\_chr}(\,);\2\6 +\&{switch} (\\{cur\_cmd})\5 +${}\{{}$\1\6 +\4\&{case} \\{top\_bot\_mark}:\5 +\X386:Insert the \(a)appropriate mark text into the scanner\X\5 +\&{break};\6 +\4\&{case} \\{expand\_after}:\5 +\X368:Expand the token after the next token\X\5 +\&{break};\6 +\4\&{case} \\{no\_expand}:\5 +\X369:Suppress expansion of the next token\X\5 +\&{break};\6 +\4\&{case} \\{cs\_name}:\5 +\X372:Manufacture a control sequence name\X\5 +\&{break};\6 +\4\&{case} \\{convert}:\5 +\\{conv\_toks}(\,);\5 +\&{break};\C{this procedure is discussed in Part 27 below}\6 +\4\&{case} \\{the}:\5 +\\{ins\_the\_toks}(\,);\5 +\&{break};\C{this procedure is discussed in Part 27 below}\6 +\4\&{case} \\{if\_test}:\5 +\\{conditional}(\,);\5 +\&{break};\C{this procedure is discussed in Part 28 below}\6 +\4\&{case} \\{fi\_or\_else}:\5 +\X510:Terminate the current conditional and skip to \.{\\fi}\X\5 +\&{break};\6 +\4\&{case} \\{input}:\5 +\X378:Initiate or terminate input from a file\X;\5 +\&{break};\6 +\4\&{default}:\5 +\X370:Complain about an undefined macro\X\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U366.\fi + +\M{368}It takes only a little shuffling to do what \TeX\ calls \.{\\expandafter}. + +\Y\B\4\X368:Expand the token after the next token\X${}\E{}$\6 +${}\{{}$\5 +\1\\{get\_token}(\,);\5 +${}\|t\K\\{cur\_tok};{}$\5 +\\{get\_token}(\,);\6 +\&{if} ${}(\\{cur\_cmd}>\\{max\_command}){}$\1\5 +\\{expand}(\,);\5 +\2\&{else}\1\5 +\\{back\_input}(\,);\2\6 +${}\\{cur\_tok}\K\|t;{}$\5 +\\{back\_input}(\,);\6 +\4${}\}{}$\2\par +\U367.\fi + +\M{369}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\B\4\X369:Suppress expansion of the next token\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{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}){}$\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U367.\fi + +\M{370}\B\X370:Complain about an undefined macro\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Undefined\ control\ s}\)\.{equence"});\5 +\\{help5}(\.{"The\ control\ sequenc}\)\.{e\ at\ the\ end\ of\ the\ }\)\.{top\ line"})\6 +(\.{"of\ your\ error\ messa}\)\.{ge\ was\ never\ \\\\def'e}\)\.{d.\ If\ you\ have"})\6 +(\.{"misspelled\ it\ (e.g.}\)\.{,\ `\\\\hobx'),\ type\ `I}\)\.{'\ and\ the\ correct"})\6 +(\.{"spelling\ (e.g.,\ `I\\}\)\.{\\hbox').\ Otherwise\ j}\)\.{ust\ continue,"})\6 +(\.{"and\ I'll\ forget\ abo}\)\.{ut\ whatever\ was\ unde}\)\.{fined."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U367.\fi + +\M{371}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\B\4\D$\\{store\_new\_token}(\|X)$ \6 +${}\{{}$\5 +\1${}\|q\K\\{get\_avail}(\,);{}$\5 +${}\\{link}(\|p)\K\|q;{}$\5 +${}\\{info}(\|q)\K\|X;{}$\5 +${}\|p\K\|q{}$;\C{\\{link}(\|p) is \\{null}}\6 +\4${}\}{}$\2\par +\B\4\D$\\{fast\_store\_new\_token}(\|X)$ \6 +${}\{{}$\5 +\1\\{fast\_get\_avail}(\|q);\5 +${}\\{link}(\|p)\K\|q;{}$\5 +${}\\{info}(\|q)\K\|X;{}$\5 +${}\|p\K\|q{}$;\C{\\{link}(\|p) is \\{null}}\6 +\4${}\}{}$\2\par +\fi + +\M{372}\B\X372:Manufacture a control sequence name\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_avail}(\,);{}$\5 +${}\|p\K\|r{}$;\C{head of the list of characters}\6 +\&{do}\5 +${}\{{}$\1\6 +\\{get\_x\_token}(\,);\6 +\&{if} ${}(\\{cur\_cs}\E\T{0}){}$\1\5 +\\{store\_new\_token}(\\{cur\_tok});\2\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{cur\_cs}\I\T{0}));{}$\6 +\&{if} ${}(\\{cur\_cmd}\I\\{end\_cs\_name}){}$\1\5 +\X373:Complain about missing \.{\\endcsname}\X;\2\6 +\X374: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})\E\\{undefined\_cs}){}$\5 +${}\{{}$\5 +\1${}\\{eq\_define}(\\{cur\_cs},\39\\{relax},\39\T{256}){}$;\C{N.B.: The \\{save\_stack} might change}\6 +\4${}\}{}$\C{the control sequence will now match `\.{\\relax}'}\2\6 +${}\\{cur\_tok}\K\\{cur\_cs}+\\{cs\_token\_flag};{}$\5 +\\{back\_input}(\,);\6 +\4${}\}{}$\2\par +\U367.\fi + +\M{373}\B\X373:Complain about missing \.{\\endcsname}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ "});\5 +\\{print\_esc}(\X1527:\.{"endcsname"}\X);\5 +\\{print\_str}(\.{"\ inserted"});\5 +\\{help2}(\.{"The\ control\ sequenc}\)\.{e\ marked\ <to\ be\ read}\)\.{\ again>\ should"})\6 +(\.{"not\ appear\ between\ }\)\.{\\\\csname\ and\ \\\\endcs}\)\.{name."});\5 +\\{back\_error}(\,);\6 +\4${}\}{}$\2\par +\U372.\fi + +\M{374}\B\X374:Look up the characters of list \|r in the hash table, and set \\{cur\_cs}\X${}\E{}$\6 +$\|j\K\\{first};{}$\5 +${}\|p\K\\{link}(\|r);{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|j\G\\{max\_buf\_stack}){}$\5 +${}\{{}$\5 +\1${}\\{max\_buf\_stack}\K\|j+\T{1};{}$\6 +\&{if} ${}(\\{max\_buf\_stack}\E\\{buf\_size}){}$\1\5 +${}\\{overflow}(\.{"buffer\ size"},\39\\{buf\_size});{}$\2\6 +\4${}\}{}$\2\6 +${}\\{buffer}[\|j]\K\\{info}(\|p)\MOD\T{\~400};{}$\5 +\\{incr}(\|j);\5 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|j>\\{first}+\T{1}){}$\5 +${}\{{}$\5 +\1${}\\{no\_new\_control\_sequence}\K\\{false};{}$\5 +${}\\{cur\_cs}\K\\{id\_lookup}(\\{first},\39\|j-\\{first});{}$\5 +${}\\{no\_new\_control\_sequence}\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|j\E\\{first}){}$\1\5 +${}\\{cur\_cs}\K\\{null\_cs}{}$;\C{the list is empty}\2\6 +\&{else} $\\{cur\_cs}\K\\{single\_base}+\\{buffer}{}$[\\{first}]\C{the list has length one}\par +\U372.\fi + +\M{375}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\B\4\X375:Insert a token containing \\{frozen\_endv}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{cur\_tok}\K\\{cs\_token\_flag}+\\{frozen\_endv};{}$\5 +\\{back\_input}(\,);\6 +\4${}\}{}$\2\par +\U366.\fi + +\M{376}The processing of \.{\\input} involves the \\{start\_input} subroutine, +which will be declared later; the processing of \.{\\endinput} is trivial. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1570:\.{"input"}\X,\39\\{input},\39\T{0}){}$;\6 +${}\\{primitive}(\X1571:\.{"endinput"}\X,\39\\{input},\39\T{1}){}$;\par +\fi + +\M{377}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{input}:\6 +\&{if} ${}(\\{chr\_code}\E\T{0}){}$\1\5 +\\{print\_esc}(\X1570:\.{"input"}\X);\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1571:\.{"endinput"}\X);\5 +\2\&{break};\par +\fi + +\M{378}\B\X378:Initiate or terminate input from a file\X${}\E{}$\6 +\&{if} ${}(\\{cur\_chr}>\T{0}){}$\1\5 +${}\\{force\_eof}\K\\{true};{}$\2\6 +\&{else} \&{if} (\\{name\_in\_progress})\1\5 +\\{insert\_relax}(\,);\2\6 +\&{else} \\{start\_input}(\,)\par +\U367.\fi + +\M{379}Sometimes the expansion looks too far ahead, so we want to insert +a harmless \.{\\relax} into the user's input. + +\Y\B\4\X379:Declare the procedure called \\{insert\_relax}\X${}\E{}$\6 +\&{void} \\{insert\_relax}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\par +\U366.\fi + +\M{380}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\B\&{void} \\{get\_x\_token}(\&{void})\C{sets \\{cur\_cmd}, \\{cur\_chr}, \\{cur\_tok}, and expands macros}\6 +${}\{{}$\5 +\1\\{restart}:\5 +\\{get\_next}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\Z\\{max\_command}){}$\1\5 +\&{goto} \\{done};\2\6 +\&{if} ${}(\\{cur\_cmd}\G\\{call}){}$\1\6 +\&{if} ${}(\\{cur\_cmd}<\\{end\_template}){}$\1\5 +\\{macro\_call}(\,);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_cs}\K\\{frozen\_endv};{}$\5 +${}\\{cur\_cmd}\K\\{endv};{}$\5 +\&{goto} \\{done};\C{$\\{cur\_chr}\E\\{null\_list}$}\6 +\4${}\}{}$\2\2\6 +\&{else}\1\5 +\\{expand}(\,);\2\6 +\&{goto} \\{restart};\6 +\4\\{done}:\6 +\&{if} ${}(\\{cur\_cs}\E\T{0}){}$\1\5 +${}\\{cur\_tok}\K(\\{cur\_cmd}*\T{\~400})+\\{cur\_chr};{}$\2\6 +\&{else}\1\5 +${}\\{cur\_tok}\K\\{cs\_token\_flag}+\\{cur\_cs};{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{381}The \\{get\_x\_token} procedure is equivalent to two consecutive +procedure calls: \\{get\_next}; \\{x\_token}. + +\Y\B\&{void} \\{x\_token}(\&{void})\C{\\{get\_x\_token} without the initial \\{get\_next}}\6 +${}\{{}$\5 +\1\&{while} ${}(\\{cur\_cmd}>\\{max\_command}){}$\5 +${}\{{}$\5 +\1\\{expand}(\,);\5 +\\{get\_next}(\,);\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_cs}\E\T{0}){}$\1\5 +${}\\{cur\_tok}\K(\\{cur\_cmd}*\T{\~400})+\\{cur\_chr};{}$\2\6 +\&{else}\1\5 +${}\\{cur\_tok}\K\\{cs\_token\_flag}+\\{cur\_cs};{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{382}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\B\4\D$\\{top\_mark\_code}$ \5 +\T{0}\C{the mark in effect at the previous page break}\par +\B\4\D$\\{first\_mark\_code}$ \5 +\T{1}\C{the first mark between \\{top\_mark} and \\{bot\_mark}}\par +\B\4\D$\\{bot\_mark\_code}$ \5 +\T{2}\C{the mark in effect at the current page break}\par +\B\4\D$\\{split\_first\_mark\_code}$ \5 +\T{3}\C{the first mark found by \.{\\vsplit}}\par +\B\4\D$\\{split\_bot\_mark\_code}$ \5 +\T{4}\C{the last mark found by \.{\\vsplit}}\par +\B\4\D$\\{top\_mark}$ \5 +\\{cur\_mark}[\\{top\_mark\_code}]\par +\B\4\D$\\{first\_mark}$ \5 +\\{cur\_mark}[\\{first\_mark\_code}]\par +\B\4\D$\\{bot\_mark}$ \5 +\\{cur\_mark}[\\{bot\_mark\_code}]\par +\B\4\D$\\{split\_first\_mark}$ \5 +\\{cur\_mark}[\\{split\_first\_mark\_code}]\par +\B\4\D$\\{split\_bot\_mark}$ \5 +\\{cur\_mark}[\\{split\_bot\_mark\_code}]\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} ${}\\{cur\_mark0}[\\{split\_bot\_mark\_code}-\\{top\_mark\_code}+\T{1}],{}$ ${}{*\&{const}\ }\\{cur\_mark}\K\\{cur\_mark0}-\\{top\_mark\_code}{}$;\C{token lists for marks}\par +\fi + +\M{383}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\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 + +\M{384}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1572:\.{"topmark"}\X,\39\\{top\_bot\_mark},\39\\{top\_mark\_code});{}$\5 +${}\\{primitive}(\X1573:\.{"firstmark"}\X,\39\\{top\_bot\_mark},\39\\{first\_mark\_code});{}$\5 +${}\\{primitive}(\X1574:\.{"botmark"}\X,\39\\{top\_bot\_mark},\39\\{bot\_mark\_code});{}$\5 +${}\\{primitive}(\X1575:\.{"splitfirstmark"}\X,\39\\{top\_bot\_mark},\39\\{split\_first\_mark\_code});{}$\5 +${}\\{primitive}(\X1576:\.{"splitbotmark"}\X,\39\\{top\_bot\_mark},\39\\{split\_bot\_mark\_code}){}$;\par +\fi + +\M{385}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{top\_bot\_mark}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{first\_mark\_code}:\5 +\\{print\_esc}(\X1573:\.{"firstmark"}\X);\5 +\&{break};\6 +\4\&{case} \\{bot\_mark\_code}:\5 +\\{print\_esc}(\X1574:\.{"botmark"}\X);\5 +\&{break};\6 +\4\&{case} \\{split\_first\_mark\_code}:\5 +\\{print\_esc}(\X1575:\.{"splitfirstmark"}\X);\5 +\&{break};\6 +\4\&{case} \\{split\_bot\_mark\_code}:\5 +\\{print\_esc}(\X1576:\.{"splitbotmark"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1572:\.{"topmark"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{386}The following code is activated when $\\{cur\_cmd}\E\\{top\_bot\_mark}$ and +when \\{cur\_chr} is a code like \\{top\_mark\_code}. + +\Y\B\4\X386:Insert the \(a)appropriate mark text into the scanner\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_mark}[\\{cur\_chr}]\I\\{null}){}$\1\5 +${}\\{begin\_token\_list}(\\{cur\_mark}[\\{cur\_chr}],\39\\{mark\_text});{}$\2\6 +\4${}\}{}$\2\par +\U367.\fi + +\M{387}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{uint8\_t} \\{long\_state};\C{governs the acceptance of \.{\\par}}\par +\fi + +\M{388}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{pstack}[\T{9}];\C{arguments supplied to a macro}\par +\fi + +\M{389}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\B\4\X389:Declare the procedure called \\{macro\_call}\X${}\E{}$\6 +\&{void} \\{macro\_call}(\&{void})\C{invokes a user-defined control sequence}\6 +${}\{{}$\5 +\1\&{pointer} \|r;\C{current node in the macro's token list}\6 +\&{pointer} \|p;\C{current node in parameter token list being built}\6 +\&{pointer} \|q;\C{new node being put into the token list}\6 +\&{pointer} \|s;\C{backup pointer for parameter matching}\6 +\&{pointer} \|t;\C{cycle pointer for backup recovery}\6 +\&{pointer} \|u${},{}$ \|v;\C{auxiliary pointers for backup recovery}\6 +\&{pointer} \\{rbrace\_ptr};\C{one step before the last \\{right\_brace} token}\6 +\&{small\_number} \|n;\C{the number of parameters scanned}\6 +\&{halfword} \\{unbalance};\C{unmatched left braces in current parameter}\6 +\&{int} \|m;\C{the number of tokens or groups (usually)}\6 +\&{pointer} \\{ref\_count};\C{start of the token list}\6 +\&{small\_number} \\{save\_scanner\_status};\C{\\{scanner\_status} upon entry}\6 +\&{pointer} \\{save\_warning\_index};\C{\\{warning\_index} upon entry}\6 +\&{ASCII\_code} \\{match\_chr};\C{character used in parameter}\7 +${}\\{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\K\T{0};{}$\6 +\&{if} ${}(\\{tracing\_macros}>\T{0}){}$\1\5 +\X401:Show the text of the macro being expanded\X;\2\6 +\&{if} ${}(\\{info}(\|r)\I\\{end\_match\_token}){}$\1\5 +\X391:Scan the parameters and make \\{link}(\|r) point to the macro body; but \&{return} if an illegal \.{\\par} is detected\X;\2\6 +\X390:Feed the macro body and its parameters to the scanner\X;\6 +\4\\{end}:\5 +${}\\{scanner\_status}\K\\{save\_scanner\_status};{}$\5 +${}\\{warning\_index}\K\\{save\_warning\_index};{}$\6 +\4${}\}{}$\2\par +\U366.\fi + +\M{390}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\B\4\X390:Feed the macro body and its parameters to the scanner\X${}\E{}$\6 +\&{while} ${}((\\{state}\E\\{token\_list})\W(\\{loc}\E\\{null})\W(\\{token\_type}\I\\{v\_template})){}$\1\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>\T{0}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{param\_ptr}+\|n>\\{max\_param\_stack}){}$\5 +${}\{{}$\5 +\1${}\\{max\_param\_stack}\K\\{param\_ptr}+\|n;{}$\6 +\&{if} ${}(\\{max\_param\_stack}>\\{param\_size}){}$\1\5 +${}\\{overflow}(\.{"parameter\ stack\ siz}\)\.{e"},\39\\{param\_size});{}$\2\6 +\4${}\}{}$\2\6 +\&{for} ${}(\|m\K\T{0};{}$ ${}\|m\Z\|n-\T{1};{}$ ${}\|m\PP){}$\1\5 +${}\\{param\_stack}[\\{param\_ptr}+\|m]\K\\{pstack}[\|m];{}$\2\6 +${}\\{param\_ptr}\K\\{param\_ptr}+\|n;{}$\6 +\4${}\}{}$\2\par +\U389.\fi + +\M{391}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\E\\{null}$ to +represent this restriction. Otherwise \|s will be set to the first token of +a string that will delimit the next parameter. + +\Y\B\4\X391:Scan the parameters and make \\{link}(\|r) point to the macro body; but \&{return} if an illegal \.{\\par} is detected\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{scanner\_status}\K\\{matching};{}$\5 +${}\\{unbalance}\K\T{0};{}$\5 +${}\\{long\_state}\K\\{eq\_type}(\\{cur\_cs});{}$\6 +\&{if} ${}(\\{long\_state}\G\\{outer\_call}){}$\1\5 +${}\\{long\_state}\K\\{long\_state}-\T{2}{}$;\2\6 +\&{do}\5 +${}\{{}$\1\6 +${}\\{link}(\\{temp\_head})\K\\{null};{}$\6 +\&{if} ${}((\\{info}(\|r)>\\{match\_token}+\T{255})\V(\\{info}(\|r)<\\{match\_token})){}$\1\5 +${}\|s\K\\{null};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{match\_chr}\K\\{info}(\|r)-\\{match\_token};{}$\5 +${}\|s\K\\{link}(\|r);{}$\5 +${}\|r\K\|s;{}$\5 +${}\|p\K\\{temp\_head};{}$\5 +${}\|m\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\X392:Scan a parameter until its delimiter string has been found; or, if $\|s\K\\{null}$, simply scan the delimiter string\X;\C{now \\{info}(\|r) is a token whose command code is either \\{match} or \\{end\_match}}\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{info}(\|r)\E\\{end\_match\_token}));{}$\6 +\4${}\}{}$\2\par +\U389.\fi + +\M{392}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}\E\\{info}(\|r)$' in the following algorithm. + +\Y\B\4\X392:Scan a parameter until its delimiter string has been found; or, if $\|s\K\\{null}$, simply scan the delimiter string\X${}\E{}$\6 +\4\\{resume}:\5 +\\{get\_token}(\,);\C{set \\{cur\_tok} to the next token of input}\6 +\&{if} ${}(\\{cur\_tok}\E\\{info}(\|r)){}$\1\5 +\X394:Advance \(r)\|r; \&{goto} \\{found} if the parameter delimiter has been fully matched, otherwise \&{goto} \&{continue}\X;\2\6 +\X397:Contribute the recently matched tokens to the current parameter, and \&{goto} \&{continue} if a partial match is still in effect; but abort if $\|s\K\\{null}$\X;\6 +\&{if} ${}(\\{cur\_tok}\E\\{par\_token}){}$\1\6 +\&{if} ${}(\\{long\_state}\I\\{long\_call}){}$\1\5 +\X396:Report a runaway argument and abort\X;\2\2\6 +\&{if} ${}(\\{cur\_tok}<\\{right\_brace\_limit}){}$\1\6 +\&{if} ${}(\\{cur\_tok}<\\{left\_brace\_limit}){}$\1\5 +\X399:Contribute an entire group to the current parameter\X\2\6 +\&{else}\1\5 +\X395:Report an extra right brace and \&{goto} \&{continue}\X\2\2\6 +\&{else}\1\5 +\X393: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\5 +\&{goto} \\{resume};\2\6 +\&{if} ${}(\\{info}(\|r)<\\{match\_token}){}$\1\5 +\&{goto} \\{resume};\2\6 +\4\\{found}:\6 +\&{if} ${}(\|s\I\\{null}){}$\1\5 +\X400:Tidy up the parameter just scanned, and tuck it away\X\2\par +\U391.\fi + +\M{393}\B\X393:Store the current token, but \&{goto} \&{continue} if it is a blank space that would become an undelimited parameter\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_tok}\E\\{space\_token}){}$\1\6 +\&{if} ${}(\\{info}(\|r)\Z\\{end\_match\_token}){}$\1\6 +\&{if} ${}(\\{info}(\|r)\G\\{match\_token}){}$\1\5 +\&{goto} \\{resume};\2\2\2\6 +\\{store\_new\_token}(\\{cur\_tok});\6 +\4${}\}{}$\2\par +\U392.\fi + +\M{394}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\B\4\X394:Advance \(r)\|r; \&{goto} \\{found} if the parameter delimiter has been fully matched, otherwise \&{goto} \&{continue}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|r\K\\{link}(\|r);{}$\6 +\&{if} ${}((\\{info}(\|r)\G\\{match\_token})\W(\\{info}(\|r)\Z\\{end\_match\_token})){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_tok}<\\{left\_brace\_limit}){}$\1\5 +\\{decr}(\\{align\_state});\2\6 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\&{goto} \\{resume};\2\6 +\4${}\}{}$\2\par +\U392.\fi + +\M{395}\B\X395:Report an extra right brace and \&{goto} \&{continue}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +\\{print\_err}(\.{"Argument\ of\ "});\5 +\\{sprint\_cs}(\\{warning\_index});\5 +\\{print\_str}(\.{"\ 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\ rep}\)\.{ort\ a\ runaway"})\6 +(\.{"argument\ that\ might}\)\.{\ be\ the\ root\ of\ the\ }\)\.{problem.\ But\ if"})\6 +(\.{"your\ `\}'\ was\ spurio}\)\.{us,\ just\ type\ `2'\ an}\)\.{d\ it\ will\ go\ away."});\5 +\\{incr}(\\{align\_state});\5 +${}\\{long\_state}\K\\{call};{}$\5 +${}\\{cur\_tok}\K\\{par\_token};{}$\5 +\\{ins\_error}(\,);\5 +\&{goto} \\{resume};\6 +\4${}\}{}$\C{a white lie; the \.{\\par} won't always trigger a runaway}\2\par +\U392.\fi + +\M{396}If $\\{long\_state}\E\\{outer\_call}$, a runaway argument has already been reported. + +\Y\B\4\X396:Report a runaway argument and abort\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{long\_state}\E\\{call}){}$\5 +${}\{{}$\5 +\1\\{runaway}(\,);\5 +\\{print\_err}(\.{"Paragraph\ ended\ bef}\)\.{ore\ "});\5 +\\{sprint\_cs}(\\{warning\_index});\5 +\\{print\_str}(\.{"\ was\ complete"});\5 +\\{help3}(\.{"I\ suspect\ you've\ fo}\)\.{rgotten\ a\ `\}',\ causi}\)\.{ng\ me\ to\ apply\ this"})\6 +(\.{"control\ sequence\ to}\)\.{\ too\ much\ text.\ How\ }\)\.{can\ we\ recover?"})\6 +(\.{"My\ plan\ is\ to\ forge}\)\.{t\ the\ whole\ thing\ an}\)\.{d\ hope\ for\ the\ best.}\)\.{"});\5 +\\{back\_error}(\,);\6 +\4${}\}{}$\2\6 +${}\\{pstack}[\|n]\K\\{link}(\\{temp\_head});{}$\5 +${}\\{align\_state}\K\\{align\_state}-\\{unbalance};{}$\6 +\&{for} ${}(\|m\K\T{0};{}$ ${}\|m\Z\|n;{}$ ${}\|m\PP){}$\1\5 +\\{flush\_list}(\\{pstack}[\|m]);\2\6 +\&{goto} \\{end};\6 +\4${}\}{}$\2\par +\Us392\ET399.\fi + +\M{397}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\E\|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\B\4\X397:Contribute the recently matched tokens to the current parameter, and \&{goto} \&{continue} if a partial match is still in effect; but abort if $\|s\K\\{null}$\X${}\E{}$\6 +\&{if} ${}(\|s\I\|r){}$\1\6 +\&{if} ${}(\|s\E\\{null}){}$\1\5 +\X398:Report an improper use of the macro and abort\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|t\K\|s{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\\{store\_new\_token}(\\{info}(\|t));\5 +\\{incr}(\|m);\5 +${}\|u\K\\{link}(\|t);{}$\5 +${}\|v\K\|s;{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\|u\E\|r){}$\1\6 +\&{if} ${}(\\{cur\_tok}\I\\{info}(\|v)){}$\1\5 +\&{goto} \\{done};\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|r\K\\{link}(\|v);{}$\5 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\2\6 +\&{if} ${}(\\{info}(\|u)\I\\{info}(\|v)){}$\1\5 +\&{goto} \\{done};\2\6 +${}\|u\K\\{link}(\|u);{}$\5 +${}\|v\K\\{link}(\|v);{}$\6 +\4${}\}{}$\2\6 +\4\\{done}:\5 +${}\|t\K\\{link}(\|t);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|t\E\|r));{}$\5 +${}\|r\K\|s{}$;\C{at this point, no tokens are recently matched}\6 +\4${}\}{}$\2\2\par +\U392.\fi + +\M{398}\B\X398:Report an improper use of the macro and abort\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Use\ of\ "});\5 +\\{sprint\_cs}(\\{warning\_index});\5 +\\{print\_str}(\.{"\ doesn't\ match\ its\ }\)\.{definition"});\5 +\\{help4}(\.{"If\ you\ say,\ e.g.,\ `}\)\.{\\\\def\\\\a1\{...\}',\ the}\)\.{n\ you\ must\ always"})\6 +(\.{"put\ `1'\ after\ `\\\\a'}\)\.{,\ since\ control\ sequ}\)\.{ence\ names\ are"})\6 +(\.{"made\ up\ of\ letters\ }\)\.{only.\ The\ macro\ here}\)\.{\ has\ not\ been"})\6 +(\.{"followed\ by\ the\ req}\)\.{uired\ stuff,\ so\ I'm\ }\)\.{ignoring\ it."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{goto} \\{end};\6 +\4${}\}{}$\2\par +\U397.\fi + +\M{399}\B\X399:Contribute an entire group to the current parameter\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{unbalance}\K\T{1};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{fast\_store\_new\_token}(\\{cur\_tok});\5 +\\{get\_token}(\,);\6 +\&{if} ${}(\\{cur\_tok}\E\\{par\_token}){}$\1\6 +\&{if} ${}(\\{long\_state}\I\\{long\_call}){}$\1\5 +\X396:Report a runaway argument and abort\X;\2\2\6 +\&{if} ${}(\\{cur\_tok}<\\{right\_brace\_limit}){}$\1\6 +\&{if} ${}(\\{cur\_tok}<\\{left\_brace\_limit}){}$\1\5 +\\{incr}(\\{unbalance});\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{decr}(\\{unbalance});\6 +\&{if} ${}(\\{unbalance}\E\T{0}){}$\1\5 +\&{goto} \\{done1};\2\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\6 +\4\\{done1}:\5 +${}\\{rbrace\_ptr}\K\|p;{}$\5 +\\{store\_new\_token}(\\{cur\_tok});\6 +\4${}\}{}$\2\par +\U392.\fi + +\M{400}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\B\4\X400:Tidy up the parameter just scanned, and tuck it away\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}((\|m\E\T{1})\W(\\{info}(\|p)<\\{right\_brace\_limit})\W(\|p\I\\{temp\_head})){}$\5 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{pstack}[\|n]\K\\{link}(\\{temp\_head});{}$\2\6 +\\{incr}(\|n);\6 +\&{if} ${}(\\{tracing\_macros}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{""});\5 +\\{print}(\\{match\_chr});\5 +\\{print\_int}(\|n);\5 +\\{print\_str}(\.{"<-"});\5 +${}\\{show\_token\_list}(\\{pstack}[\|n-\T{1}],\39\\{null},\39\T{1000});{}$\5 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U392.\fi + +\M{401}\B\X401:Show the text of the macro being expanded\X${}\E{}$\6 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_ln}(\,);\5 +\\{print\_cs}(\\{warning\_index});\5 +\\{token\_show}(\\{ref\_count});\5 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\par +\U389.\fi + +\N{1}{402}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 + +\M{403}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\B\&{void} \\{scan\_left\_brace}(\&{void})\C{reads a mandatory \\{left\_brace}}\6 +${}\{{}$\5 +\1\X404:Get the next non-blank non-relax non-call token\X;\6 +\&{if} ${}(\\{cur\_cmd}\I\\{left\_brace}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ \{\ inserted"});\5 +\\{help4}(\.{"A\ left\ brace\ was\ ma}\)\.{ndatory\ here,\ so\ I'v}\)\.{e\ put\ one\ in."})\6 +(\.{"You\ might\ want\ to\ d}\)\.{elete\ and/or\ insert\ }\)\.{some\ corrections"})\6 +(\.{"so\ that\ I\ will\ find}\)\.{\ a\ matching\ right\ br}\)\.{ace\ soon."})\6 +(\.{"(If\ you're\ confused}\)\.{\ by\ all\ this,\ try\ ty}\)\.{ping\ `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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{404}\B\X404:Get the next non-blank non-relax non-call token\X${}\E{}$\6 +\&{do}\5 +${}\{{}$\1\6 +\\{get\_x\_token}(\,);\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R((\\{cur\_cmd}\I\\{spacer})\W(\\{cur\_cmd}\I\\{relax})){}$)\par +\Us403, 1078, 1084, 1151, 1160, 1211, 1226\ETs1270.\fi + +\M{405}The \\{scan\_optional\_equals} routine looks for an optional `\.=' sign preceded +by optional spaces; `\.{\\relax}' is not ignored here. + +\Y\B\&{void} \\{scan\_optional\_equals}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\X406:Get the next non-blank non-call token\X;\6 +\&{if} ${}(\\{cur\_tok}\I\\{other\_token}+\.{'='}){}$\1\5 +\\{back\_input}(\,);\2\6 +\4${}\}{}$\2\par +\fi + +\M{406}\B\X406:Get the next non-blank non-call token\X${}\E{}$\6 +\&{do}\5 +${}\{{}$\1\6 +\\{get\_x\_token}(\,);\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R(\\{cur\_cmd}\I\\{spacer}){}$)\par +\Us405, 441, 455, 503, 525, 577, 785, 791\ETs1045.\fi + +\M{407}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\B\&{bool} \\{scan\_keyword}(\&{str\_number} \|s)\C{look for a given string}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{tail of the backup list}\6 +\&{pointer} \|q;\C{new node being added to the token list via \\{store\_new\_token}}\6 +\&{pool\_pointer} \|k;\C{index into \\{str\_pool}}\7 +${}\|p\K\\{backup\_head};{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\5 +${}\|k\K\\{str\_start}[\|s];{}$\6 +\&{while} ${}(\|k<\\{str\_start}[\|s+\T{1}]){}$\5 +${}\{{}$\5 +\1\\{get\_x\_token}(\,);\C{recursion is possible here}\6 +\&{if} ${}((\\{cur\_cs}\E\T{0})\W\30((\\{cur\_chr}\E\\{so}(\\{str\_pool}[\|k]))\V(\\{cur\_chr}\E\\{so}(\\{str\_pool}[\|k])-\.{'a'}+\.{'A'}))){}$\5 +${}\{{}$\5 +\1\\{store\_new\_token}(\\{cur\_tok});\5 +\\{incr}(\|k);\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}((\\{cur\_cmd}\I\\{spacer})\V(\|p\I\\{backup\_head})){}$\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\6 +\&{if} ${}(\|p\I\\{backup\_head}){}$\1\5 +\\{back\_list}(\\{link}(\\{backup\_head}));\2\6 +\&{return} \\{false};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\\{flush\_list}(\\{link}(\\{backup\_head}));\5 +\&{return} \\{true};\6 +\4${}\}{}$\2\par +\fi + +\M{408}Here is a procedure that sounds an alarm when mu and non-mu units +are being switched. + +\Y\B\&{void} \\{mu\_error}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Incompatible\ glue\ u}\)\.{nits"});\5 +\\{help1}(\.{"I'm\ going\ to\ assume}\)\.{\ that\ 1mu=1pt\ when\ t}\)\.{hey're\ mixed."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\fi + +\M{409}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\B\&{void} \\{scan\_int}(\&{void});\C{scans an integer value}\7 +\hbox{\4\4}\X433:Declare procedures that scan restricted classes of integers\X\6 +\hbox{\4\4}\X577:Declare procedures that scan font-related stuff\X\par +\fi + +\M{410}\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}\E\\{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\B\4\D$\\{int\_val}$ \5 +\T{0}\C{integer values}\par +\B\4\D$\\{dimen\_val}$ \5 +\T{1}\C{dimension values}\par +\B\4\D$\\{glue\_val}$ \5 +\T{2}\C{glue specifications}\par +\B\4\D$\\{mu\_val}$ \5 +\T{3}\C{math glue specifications}\par +\B\4\D$\\{ident\_val}$ \5 +\T{4}\C{font identifier}\par +\B\4\D$\\{tok\_val}$ \5 +\T{5}\C{token lists}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{cur\_val};\C{value returned by numeric scanners}\6 +\&{uint8\_t} \\{cur\_val\_level};\C{the ``level'' of this value}\par +\fi + +\M{411}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\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1501:\.{"count"}\X,\39\&{register},\39\\{int\_val});{}$\5 +${}\\{primitive}(\X1524:\.{"dimen"}\X,\39\&{register},\39\\{dimen\_val});{}$\5 +${}\\{primitive}(\X1423:\.{"skip"}\X,\39\&{register},\39\\{glue\_val});{}$\5 +${}\\{primitive}(\X1424:\.{"muskip"}\X,\39\&{register},\39\\{mu\_val}){}$;\par +\fi + +\M{412}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\&{case} \&{register} : \6 +\&{if} ${}(\\{chr\_code}\E\\{int\_val}){}$\1\5 +\\{print\_esc}(\X1501:\.{"count"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{dimen\_val}){}$\1\5 +\\{print\_esc}(\X1524:\.{"dimen"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{glue\_val}){}$\1\5 +\\{print\_esc}(\X1423:\.{"skip"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1424:\.{"muskip"}\X);\5 +\2\&{break};\par +\fi + +\M{413}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\B\4\D$\\{scanned\_result\_end}(\|X)$ \5 +$\\{cur\_val\_level}\K\|X{}$;\5 +$\}{}$\par +\B\4\D$\\{scanned\_result}(\|X)$ \5 +$\{{}$\5 +$\\{cur\_val}\K\|X;$ \\{scanned\_result\_end}\par +\Y\B\&{void} \\{scan\_something\_internal}(\&{small\_number} \\{level}${},\39{}$\&{bool} \\{negative})\C{fetch an internal parameter}\1\1\6 +$\{{}$\5 +\&{halfword} \|m;\C{\\{chr\_code} part of the operand token}\6 +\&{uint8\_t} \|p;\C{index into \\{nest}}\7 +${}\|m\K\\{cur\_chr};$ \&{switch} (\\{cur\_cmd}) $\{$ \6 +\4\&{case} \\{def\_code}:\5 +\X414:Fetch a character code from some table\X\5 +\&{break};\6 +\4\&{case} \\{toks\_register}:\5 +\&{case} \\{assign\_toks}:\5 +\&{case} \\{def\_family}:\5 +\&{case} \\{set\_font}:\5 +\&{case} \\{def\_font}:\5 +\X415:Fetch a token list or font identifier, provided that $\\{level}\K\\{tok\_val}$\X\5 +\&{break};\6 +\4\&{case} \\{assign\_int}:\5 +${}\\{scanned\_result}(\\{eqtb}[\|m].\|i)(\\{int\_val}){}$\5 +\&{break};\6 +\4\&{case} \\{assign\_dimen}:\5 +${}\\{scanned\_result}(\\{eqtb}[\|m].\\{sc})(\\{dimen\_val}){}$\5 +\&{break};\6 +\4\&{case} \\{assign\_glue}:\5 +\\{scanned\_result}(\\{equiv}(\|m))(\\{glue\_val})\5 +\&{break};\6 +\4\&{case} \\{assign\_mu\_glue}:\5 +\\{scanned\_result}(\\{equiv}(\|m))(\\{mu\_val})\5 +\&{break};\6 +\4\&{case} \\{set\_aux}:\5 +\X418:Fetch the \\{space\_factor} or the \\{prev\_depth}\X\5 +\&{break};\6 +\4\&{case} \\{set\_prev\_graf}:\5 +\X422:Fetch the \\{prev\_graf}\X\5 +\&{break};\6 +\4\&{case} \\{set\_page\_int}:\5 +\X419:Fetch the \\{dead\_cycles} or the \\{insert\_penalties}\X\5 +\&{break};\6 +\4\&{case} \\{set\_page\_dimen}:\5 +\X421:Fetch something on the \\{page\_so\_far}\X\5 +\&{break};\6 +\4\&{case} \\{set\_shape}:\5 +\X423:Fetch the \\{par\_shape} size\X\5 +\&{break};\6 +\4\&{case} \\{set\_box\_dimen}:\5 +\X420:Fetch a box dimension\X\5 +\&{break};\6 +\4\&{case} \\{char\_given}:\5 +\&{case} \\{math\_given}:\5 +\\{scanned\_result}(\\{cur\_chr})(\\{int\_val})\5 +\&{break};\6 +\4\&{case} \\{assign\_font\_dimen}:\5 +\X425:Fetch a font dimension\X\5 +\&{break};\6 +\4\&{case} \\{assign\_font\_int}:\5 +\X426:Fetch a font integer\X\5 +\&{break}; \&{case} \&{register} : \X427:Fetch a register\X\5 +\&{break};\6 +\4\&{case} \\{last\_item}:\5 +\X424:Fetch an item in the current node, if appropriate\X\5 +\&{break};\6 +\4\&{default}:\5 +\X428:Complain that \.{\\the} can't do this; give zero result\X\6 +$\}{}$\6 +\&{while} ${}(\\{cur\_val\_level}>\\{level}){}$\1\5 +\X429:Convert \(c)\\{cur\_val} to a lower level\X;\2\6 +\X430:Fix the reference count, if any, and negate \\{cur\_val} if \\{negative}\X;\6 +$\}{}$\par +\fi + +\M{414}\B\X414:Fetch a character code from some table\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_char\_num}(\,);\6 +\&{if} ${}(\|m\E\\{math\_code\_base}){}$\1\5 +\\{scanned\_result}(\\{ho}(\\{math\_code}(\\{cur\_val})))(\\{int\_val})\2\6 +\&{else} \&{if} ${}(\|m<\\{math\_code\_base}){}$\1\5 +${}\\{scanned\_result}(\\{equiv}(\|m+\\{cur\_val}))(\\{int\_val}){}$\2\6 +\&{else}\1\5 +${}\\{scanned\_result}(\\{eqtb}[\|m+\\{cur\_val}].\|i)(\\{int\_val});{}$\2\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{415}\B\X415:Fetch a token list or font identifier, provided that $\\{level}\K\\{tok\_val}$\X${}\E{}$\6 +\&{if} ${}(\\{level}\I\\{tok\_val}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ number,\ tre}\)\.{ated\ as\ zero"});\5 +\\{help3}(\.{"A\ number\ should\ hav}\)\.{e\ been\ here;\ I\ inser}\)\.{ted\ `0'."})\6 +(\.{"(If\ you\ can't\ figur}\)\.{e\ out\ why\ I\ needed\ t}\)\.{o\ see\ a\ number,"})\6 +(\.{"look\ up\ `weird\ erro}\)\.{r'\ in\ the\ index\ to\ T}\)\.{he\ TeXbook.)"});\5 +\\{back\_error}(\,);\5 +\\{scanned\_result}(\T{0})(\\{dimen\_val});\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}\Z\\{assign\_toks}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_cmd}<\\{assign\_toks}{}$)\C{$\\{cur\_cmd}\E\\{toks\_register}$}\6 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\5 +${}\|m\K\\{toks\_base}+\\{cur\_val};{}$\6 +\4${}\}{}$\2\6 +\\{scanned\_result}(\\{equiv}(\|m))(\\{tok\_val});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +\\{scan\_font\_ident}(\,);\5 +${}\\{scanned\_result}(\\{font\_id\_base}+\\{cur\_val})(\\{ident\_val});{}$\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{416}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\B\4\D$\\{input\_line\_no\_code}$ \5 +$(\\{glue\_val}+\T{1}{}$)\C{code for \.{\\inputlineno}}\par +\B\4\D$\\{badness\_code}$ \5 +$(\\{glue\_val}+\T{2}{}$)\C{code for \.{\\badness}}\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1577:\.{"spacefactor"}\X,\39\\{set\_aux},\39\\{hmode});{}$\5 +${}\\{primitive}(\X1578:\.{"prevdepth"}\X,\39\\{set\_aux},\39\\{vmode}){}$;\6 +${}\\{primitive}(\X1579:\.{"deadcycles"}\X,\39\\{set\_page\_int},\39\T{0});{}$\5 +${}\\{primitive}(\X1580:\.{"insertpenalties"}\X,\39\\{set\_page\_int},\39\T{1});{}$\5 +${}\\{primitive}(\X1581:\.{"wd"}\X,\39\\{set\_box\_dimen},\39\\{width\_offset});{}$\5 +${}\\{primitive}(\X1582:\.{"ht"}\X,\39\\{set\_box\_dimen},\39\\{height\_offset});{}$\5 +${}\\{primitive}(\X1583:\.{"dp"}\X,\39\\{set\_box\_dimen},\39\\{depth\_offset});{}$\5 +${}\\{primitive}(\X1584:\.{"lastpenalty"}\X,\39\\{last\_item},\39\\{int\_val});{}$\5 +${}\\{primitive}(\X1585:\.{"lastkern"}\X,\39\\{last\_item},\39\\{dimen\_val});{}$\5 +${}\\{primitive}(\X1586:\.{"lastskip"}\X,\39\\{last\_item},\39\\{glue\_val});{}$\5 +${}\\{primitive}(\X1587:\.{"inputlineno"}\X,\39\\{last\_item},\39\\{input\_line\_no\_code});{}$\5 +${}\\{primitive}(\X1588:\.{"badness"}\X,\39\\{last\_item},\39\\{badness\_code}){}$;\par +\fi + +\M{417}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{set\_aux}:\6 +\&{if} ${}(\\{chr\_code}\E\\{vmode}){}$\1\5 +\\{print\_esc}(\X1578:\.{"prevdepth"}\X);\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1577:\.{"spacefactor"}\X);\5 +\2\&{break};\6 +\4\&{case} \\{set\_page\_int}:\6 +\&{if} ${}(\\{chr\_code}\E\T{0}){}$\1\5 +\\{print\_esc}(\X1579:\.{"deadcycles"}\X);\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1580:\.{"insertpenalties"}\X);\5 +\2\&{break};\6 +\4\&{case} \\{set\_box\_dimen}:\6 +\&{if} ${}(\\{chr\_code}\E\\{width\_offset}){}$\1\5 +\\{print\_esc}(\X1581:\.{"wd"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{height\_offset}){}$\1\5 +\\{print\_esc}(\X1582:\.{"ht"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1583:\.{"dp"}\X);\5 +\2\&{break};\6 +\4\&{case} \\{last\_item}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{int\_val}:\5 +\\{print\_esc}(\X1584:\.{"lastpenalty"}\X);\5 +\&{break};\6 +\4\&{case} \\{dimen\_val}:\5 +\\{print\_esc}(\X1585:\.{"lastkern"}\X);\5 +\&{break};\6 +\4\&{case} \\{glue\_val}:\5 +\\{print\_esc}(\X1586:\.{"lastskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{input\_line\_no\_code}:\5 +\\{print\_esc}(\X1587:\.{"inputlineno"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1588:\.{"badness"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{418}\B\X418:Fetch the \\{space\_factor} or the \\{prev\_depth}\X${}\E{}$\6 +\&{if} ${}(\\{abs}(\\{mode})\I\|m){}$\5 +${}\{{}$\5 +\1\\{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\ ve}\)\.{rtical\ mode;\ and"})\6 +(\.{"neither\ of\ these\ is}\)\.{\ meaningful\ inside\ \\}\)\.{\\write.\ So"})\6 +(\.{"I'm\ forgetting\ what}\)\.{\ you\ said\ and\ using\ }\)\.{zero\ instead."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{if} ${}(\\{level}\I\\{tok\_val}){}$\1\5 +\\{scanned\_result}(\T{0})(\\{dimen\_val})\2\6 +\&{else}\1\5 +\\{scanned\_result}(\T{0})(\\{int\_val});\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|m\E\\{vmode}){}$\1\5 +\\{scanned\_result}(\\{prev\_depth})(\\{dimen\_val})\2\6 +\&{else} \\{scanned\_result}(\\{space\_factor})(\\{int\_val})\par +\U413.\fi + +\M{419}\B\X419:Fetch the \\{dead\_cycles} or the \\{insert\_penalties}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\|m\E\T{0}){}$\1\5 +${}\\{cur\_val}\K\\{dead\_cycles}{}$;\5 +\2\&{else}\1\5 +${}\\{cur\_val}\K\\{insert\_penalties};{}$\2\6 +${}\\{cur\_val\_level}\K\\{int\_val};{}$\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{420}\B\X420:Fetch a box dimension\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\6 +\&{if} ${}(\\{box}(\\{cur\_val})\E\\{null}){}$\1\5 +${}\\{cur\_val}\K\T{0}{}$;\5 +\2\&{else}\1\5 +${}\\{cur\_val}\K\\{mem}[\\{box}(\\{cur\_val})+\|m].\\{sc};{}$\2\6 +${}\\{cur\_val\_level}\K\\{dimen\_val};{}$\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{421}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\B\4\D$\\{max\_dimen}$ \5 +\T{\~7777777777}\C{$2^{30}-1$}\par +\Y\B\4\X421:Fetch something on the \\{page\_so\_far}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}((\\{page\_contents}\E\\{empty})\W(\R\\{output\_active})){}$\1\6 +\&{if} ${}(\|m\E\T{0}){}$\1\5 +${}\\{cur\_val}\K\\{max\_dimen}{}$;\5 +\2\&{else}\1\5 +${}\\{cur\_val}\K\T{0};{}$\2\2\6 +\&{else}\1\5 +${}\\{cur\_val}\K\\{page\_so\_far}[\|m];{}$\2\6 +${}\\{cur\_val\_level}\K\\{dimen\_val};{}$\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{422}\B\X422:Fetch the \\{prev\_graf}\X${}\E{}$\6 +\&{if} ${}(\\{mode}\E\T{0}){}$\1\5 +\\{scanned\_result}(\T{0})(\\{int\_val})\C{$\\{prev\_graf}\E\T{0}$ within \.{\\write}}\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{nest}[\\{nest\_ptr}]\K\\{cur\_list};{}$\5 +${}\|p\K\\{nest\_ptr};{}$\6 +\&{while} ${}(\\{abs}(\\{nest}[\|p].\\{mode\_field})\I\\{vmode}){}$\1\5 +\\{decr}(\|p);\2\6 +${}\\{scanned\_result}(\\{nest}[\|p].\\{pg\_field})(\\{int\_val});{}$\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{423}\B\X423:Fetch the \\{par\_shape} size\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{par\_shape\_ptr}\E\\{null}){}$\1\5 +${}\\{cur\_val}\K\T{0};{}$\2\6 +\&{else}\1\5 +${}\\{cur\_val}\K\\{info}(\\{par\_shape\_ptr});{}$\2\6 +${}\\{cur\_val\_level}\K\\{int\_val};{}$\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{424}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. + +\Y\B\4\X424:Fetch an item in the current node, if appropriate\X${}\E{}$\6 +\&{if} ${}(\\{cur\_chr}>\\{glue\_val}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_chr}\E\\{input\_line\_no\_code}){}$\1\5 +${}\\{cur\_val}\K\\{line};{}$\2\6 +\&{else}\1\5 +${}\\{cur\_val}\K\\{last\_badness}{}$;\C{$\\{cur\_chr}\E\\{badness\_code}$}\2\6 +${}\\{cur\_val\_level}\K\\{int\_val};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_chr}\E\\{glue\_val}){}$\1\5 +${}\\{cur\_val}\K\\{zero\_glue}{}$;\5 +\2\&{else}\1\5 +${}\\{cur\_val}\K\T{0};{}$\2\6 +${}\\{cur\_val\_level}\K\\{cur\_chr};{}$\6 +\&{if} ${}(\R\\{is\_char\_node}(\\{tail})\W(\\{mode}\I\T{0})){}$\1\6 +\&{switch} (\\{cur\_chr})\5 +${}\{{}$\1\6 +\4\&{case} \\{int\_val}:\6 +\&{if} ${}(\\{type}(\\{tail})\E\\{penalty\_node}){}$\1\5 +${}\\{cur\_val}\K\\{penalty}(\\{tail}){}$;\5 +\2\&{break};\6 +\4\&{case} \\{dimen\_val}:\6 +\&{if} ${}(\\{type}(\\{tail})\E\\{kern\_node}){}$\1\5 +${}\\{cur\_val}\K\\{width}(\\{tail}){}$;\5 +\2\&{break};\6 +\4\&{case} \\{glue\_val}:\6 +\&{if} ${}(\\{type}(\\{tail})\E\\{glue\_node}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_val}\K\\{glue\_ptr}(\\{tail});{}$\6 +\&{if} ${}(\\{subtype}(\\{tail})\E\\{mu\_glue}){}$\1\5 +${}\\{cur\_val\_level}\K\\{mu\_val};{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\C{there are no other cases}\2\2\6 +\&{else} \&{if} ${}((\\{mode}\E\\{vmode})\W(\\{tail}\E\\{head})){}$\1\6 +\&{switch} (\\{cur\_chr})\5 +${}\{{}$\1\6 +\4\&{case} \\{int\_val}:\5 +${}\\{cur\_val}\K\\{last\_penalty}{}$;\5 +\&{break};\6 +\4\&{case} \\{dimen\_val}:\5 +${}\\{cur\_val}\K\\{last\_kern}{}$;\5 +\&{break};\6 +\4\&{case} \\{glue\_val}:\6 +\&{if} ${}(\\{last\_glue}\I\\{max\_halfword}){}$\1\5 +${}\\{cur\_val}\K\\{last\_glue};{}$\2\6 +\4${}\}{}$\C{there are no other cases}\2\2\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{425}\B\X425:Fetch a font dimension\X${}\E{}$\6 +${}\{{}$\5 +\1\\{find\_font\_dimen}(\\{false});\5 +${}\\{font\_info}[\\{fmem\_ptr}].\\{sc}\K\T{0};{}$\5 +${}\\{scanned\_result}(\\{font\_info}[\\{cur\_val}].\\{sc})(\\{dimen\_val});{}$\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{426}\B\X426:Fetch a font integer\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_font\_ident}(\,);\6 +\&{if} ${}(\|m\E\T{0}){}$\1\5 +\\{scanned\_result}(\\{hyphen\_char}[\\{cur\_val}])(\\{int\_val})\2\6 +\&{else}\1\5 +\\{scanned\_result}(\\{skew\_char}[\\{cur\_val}])(\\{int\_val});\2\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{427}\B\X427:Fetch a register\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\6 +\&{switch} (\|m)\5 +${}\{{}$\1\6 +\4\&{case} \\{int\_val}:\5 +${}\\{cur\_val}\K\\{count}(\\{cur\_val}){}$;\5 +\&{break};\6 +\4\&{case} \\{dimen\_val}:\5 +${}\\{cur\_val}\K\\{dimen}(\\{cur\_val}){}$;\5 +\&{break};\6 +\4\&{case} \\{glue\_val}:\5 +${}\\{cur\_val}\K\\{skip}(\\{cur\_val}){}$;\5 +\&{break};\6 +\4\&{case} \\{mu\_val}:\5 +${}\\{cur\_val}\K\\{mu\_skip}(\\{cur\_val});{}$\6 +\4${}\}{}$\C{there are no other cases}\2\6 +${}\\{cur\_val\_level}\K\|m;{}$\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{428}\B\X428:Complain that \.{\\the} can't do this; give zero result\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"You\ can't\ use\ `"});\5 +${}\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr});{}$\5 +\\{print\_str}(\.{"'\ after\ "});\5 +\\{print\_esc}(\X1559:\.{"the"}\X);\5 +\\{help1}(\.{"I'm\ forgetting\ what}\)\.{\ you\ said\ and\ using\ }\)\.{zero\ instead."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{if} ${}(\\{level}\I\\{tok\_val}){}$\1\5 +\\{scanned\_result}(\T{0})(\\{dimen\_val})\2\6 +\&{else}\1\5 +\\{scanned\_result}(\T{0})(\\{int\_val});\2\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{429}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\B\4\X429:Convert \(c)\\{cur\_val} to a lower level\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_val\_level}\E\\{glue\_val}){}$\1\5 +${}\\{cur\_val}\K\\{width}(\\{cur\_val});{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_val\_level}\E\\{mu\_val}){}$\1\5 +\\{mu\_error}(\,);\2\6 +\\{decr}(\\{cur\_val\_level});\6 +\4${}\}{}$\2\par +\U413.\fi + +\M{430}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 $\Z$ \\{mu\_val}. + +\Y\B\4\X430:Fix the reference count, if any, and negate \\{cur\_val} if \\{negative}\X${}\E{}$\6 +\&{if} (\\{negative})\1\6 +\&{if} ${}(\\{cur\_val\_level}\G\\{glue\_val}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_val}\K\\{new\_spec}(\\{cur\_val});{}$\5 +\X431:Negate all three glue components of \\{cur\_val}\X;\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{negate}(\\{cur\_val});\2\2\6 +\&{else} \&{if} ${}((\\{cur\_val\_level}\G\\{glue\_val})\W(\\{cur\_val\_level}\Z\\{mu\_val}))$ \\{add\_glue\_ref}(\\{cur\_val})\par +\U413.\fi + +\M{431}\B\X431:Negate all three glue components of \\{cur\_val}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{negate}(\\{width}(\\{cur\_val}));\5 +\\{negate}(\\{stretch}(\\{cur\_val}));\5 +\\{negate}(\\{shrink}(\\{cur\_val}));\6 +\4${}\}{}$\2\par +\U430.\fi + +\M{432}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 + +\M{433}\B\X433:Declare procedures that scan restricted classes of integers\X${}\E{}$\6 +\&{void} \\{scan\_eight\_bit\_int}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{scan\_int}(\,);\6 +\&{if} ${}((\\{cur\_val}<\T{0})\V(\\{cur\_val}>\T{255})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Bad\ register\ code"});\5 +\\{help2}(\.{"A\ register\ number\ m}\)\.{ust\ be\ between\ 0\ and}\)\.{\ 255."})\6 +(\.{"I\ changed\ this\ one\ }\)\.{to\ zero."});\5 +\\{int\_error}(\\{cur\_val});\5 +${}\\{cur\_val}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\As434, 435, 436\ETs437. +\U409.\fi + +\M{434}\B\X433:Declare procedures that scan restricted classes of integers\X${}\mathrel+\E{}$\6 +\&{void} \\{scan\_char\_num}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{scan\_int}(\,);\6 +\&{if} ${}((\\{cur\_val}<\T{0})\V(\\{cur\_val}>\T{255})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Bad\ character\ code"});\5 +\\{help2}(\.{"A\ character\ number\ }\)\.{must\ be\ between\ 0\ an}\)\.{d\ 255."})\6 +(\.{"I\ changed\ this\ one\ }\)\.{to\ zero."});\5 +\\{int\_error}(\\{cur\_val});\5 +${}\\{cur\_val}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{435}While we're at it, we might as well deal with similar routines that +will be needed later. + +\Y\B\4\X433:Declare procedures that scan restricted classes of integers\X${}\mathrel+\E{}$\6 +\&{void} \\{scan\_four\_bit\_int}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{scan\_int}(\,);\6 +\&{if} ${}((\\{cur\_val}<\T{0})\V(\\{cur\_val}>\T{15})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Bad\ number"});\5 +\\{help2}(\.{"Since\ I\ expected\ to}\)\.{\ read\ a\ number\ betwe}\)\.{en\ 0\ and\ 15,"})\6 +(\.{"I\ changed\ this\ one\ }\)\.{to\ zero."});\5 +\\{int\_error}(\\{cur\_val});\5 +${}\\{cur\_val}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{436}\B\X433:Declare procedures that scan restricted classes of integers\X${}\mathrel+\E{}$\6 +\&{void} \\{scan\_fifteen\_bit\_int}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{scan\_int}(\,);\6 +\&{if} ${}((\\{cur\_val}<\T{0})\V(\\{cur\_val}>\T{\~77777})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Bad\ mathchar"});\5 +\\{help2}(\.{"A\ mathchar\ number\ m}\)\.{ust\ be\ between\ 0\ and}\)\.{\ 32767."})\6 +(\.{"I\ changed\ this\ one\ }\)\.{to\ zero."});\5 +\\{int\_error}(\\{cur\_val});\5 +${}\\{cur\_val}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{437}\B\X433:Declare procedures that scan restricted classes of integers\X${}\mathrel+\E{}$\6 +\&{void} \\{scan\_twenty\_seven\_bit\_int}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{scan\_int}(\,);\6 +\&{if} ${}((\\{cur\_val}<\T{0})\V(\\{cur\_val}>\T{\~777777777})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Bad\ delimiter\ code"});\5 +\\{help2}(\.{"A\ numeric\ delimiter}\)\.{\ code\ must\ be\ betwee}\)\.{n\ 0\ and\ 2\^\{27\}-1."})\6 +(\.{"I\ changed\ this\ one\ }\)\.{to\ zero."});\5 +\\{int\_error}(\\{cur\_val});\5 +${}\\{cur\_val}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{438}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\B\4\D$\\{octal\_token}$ \5 +$(\\{other\_token}+\.{'\\''}{}$)\C{apostrophe, indicates an octal constant}\par +\B\4\D$\\{hex\_token}$ \5 +$(\\{other\_token}+\.{'"'}{}$)\C{double quote, indicates a hex constant}\par +\B\4\D$\\{alpha\_token}$ \5 +$(\\{other\_token}+\.{'`'}{}$)\C{reverse apostrophe, precedes alpha constants}\par +\B\4\D$\\{point\_token}$ \5 +$(\\{other\_token}+\.{'.'}{}$)\C{decimal point}\par +\B\4\D$\\{continental\_point\_token}$ \5 +$(\\{other\_token}+\.{','}{}$)\C{decimal point, Eurostyle}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{small\_number} \\{radix};\C{\\{scan\_int} sets this to 8, 10, 16, or zero}\par +\fi + +\M{439}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\B\4\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{cur\_val}\K\T{0};{}$\5 +${}\\{cur\_val\_level}\K\\{int\_val};{}$\5 +${}\\{radix}\K\T{0};{}$\5 +${}\\{cur\_order}\K\\{normal}{}$;\par +\fi + +\M{440}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}\E\\{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\B\&{void} \\{scan\_int}(\&{void})\C{sets \\{cur\_val} to an integer}\6 +${}\{{}$\5 +\1\&{bool} \\{negative};\C{should the answer be negated?}\6 +\&{int} \|m;\C{$\hbox{$2^{31}$}/$ \\{radix}, the threshold of danger}\6 +\&{small\_number} \|d;\C{the digit just scanned}\6 +\&{bool} \\{vacuous};\C{have no digits appeared?}\6 +\&{bool} \\{OK\_so\_far};\C{has an error message been issued?}\7 +${}\\{radix}\K\T{0};{}$\5 +${}\\{OK\_so\_far}\K\\{true}{}$;\6 +\X441:Get the next non-blank non-sign token; set \\{negative} appropriately\X;\6 +\&{if} ${}(\\{cur\_tok}\E\\{alpha\_token}){}$\1\5 +\X442:Scan an alphabetic character code into \\{cur\_val}\X\2\6 +\&{else} \&{if} ${}((\\{cur\_cmd}\G\\{min\_internal})\W(\\{cur\_cmd}\Z\\{max\_internal})){}$\1\5 +${}\\{scan\_something\_internal}(\\{int\_val},\39\\{false});{}$\2\6 +\&{else}\1\5 +\X444:Scan a numeric constant\X;\2\6 +\&{if} (\\{negative})\1\5 +\\{negate}(\\{cur\_val});\2\6 +\4${}\}{}$\2\par +\fi + +\M{441}\B\X441:Get the next non-blank non-sign token; set \\{negative} appropriately\X${}\E{}$\6 +$\\{negative}\K\\{false}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\X406:Get the next non-blank non-call token\X;\6 +\&{if} ${}(\\{cur\_tok}\E\\{other\_token}+\.{'-'}){}$\5 +${}\{{}$\5 +\1${}\\{negative}\K\R\\{negative};{}$\5 +${}\\{cur\_tok}\K\\{other\_token}+\.{'+'};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R(\\{cur\_tok}\I\\{other\_token}+\.{'+'}){}$)\par +\Us440, 448\ETs461.\fi + +\M{442}A space is ignored after an alphabetic character constant, so that +such constants behave like numeric ones. + +\Y\B\4\X442:Scan an alphabetic character code into \\{cur\_val}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{get\_token}(\,);\C{suppress macro expansion}\6 +\&{if} ${}(\\{cur\_tok}<\\{cs\_token\_flag}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_val}\K\\{cur\_chr};{}$\6 +\&{if} ${}(\\{cur\_cmd}\Z\\{right\_brace}){}$\1\6 +\&{if} ${}(\\{cur\_cmd}\E\\{right\_brace}){}$\1\5 +\\{incr}(\\{align\_state});\2\6 +\&{else}\1\5 +\\{decr}(\\{align\_state});\2\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_tok}<\\{cs\_token\_flag}+\\{single\_base}){}$\1\5 +${}\\{cur\_val}\K\\{cur\_tok}-\\{cs\_token\_flag}-\\{active\_base};{}$\2\6 +\&{else}\1\5 +${}\\{cur\_val}\K\\{cur\_tok}-\\{cs\_token\_flag}-\\{single\_base};{}$\2\6 +\&{if} ${}(\\{cur\_val}>\T{255}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Improper\ alphabetic}\)\.{\ constant"});\5 +\\{help2}(\.{"A\ one-character\ con}\)\.{trol\ sequence\ belong}\)\.{s\ after\ a\ `\ mark."})\6 +(\.{"So\ I'm\ essentially\ }\)\.{inserting\ \\\\0\ here."});\5 +${}\\{cur\_val}\K\.{'0'};{}$\5 +\\{back\_error}(\,);\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\X443:Scan an optional space\X;\2\6 +\4${}\}{}$\2\par +\U440.\fi + +\M{443}\B\X443:Scan an optional space\X${}\E{}$\6 +${}\{{}$\5 +\1\\{get\_x\_token}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\I\\{spacer}){}$\1\5 +\\{back\_input}(\,);\2\6 +\4${}\}{}$\2\par +\Us442, 448, 455\ETs1200.\fi + +\M{444}\B\X444:Scan a numeric constant\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{radix}\K\T{10};{}$\5 +${}\|m\K\T{214748364};{}$\6 +\&{if} ${}(\\{cur\_tok}\E\\{octal\_token}){}$\5 +${}\{{}$\5 +\1${}\\{radix}\K\T{8};{}$\5 +${}\|m\K\T{\~2000000000};{}$\5 +\\{get\_x\_token}(\,);\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_tok}\E\\{hex\_token}){}$\5 +${}\{{}$\5 +\1${}\\{radix}\K\T{16};{}$\5 +${}\|m\K\T{\~1000000000};{}$\5 +\\{get\_x\_token}(\,);\6 +\4${}\}{}$\2\6 +${}\\{vacuous}\K\\{true};{}$\5 +${}\\{cur\_val}\K\T{0}{}$;\6 +\X445:Accumulate the constant until \\{cur\_tok} is not a suitable digit\X;\6 +\&{if} (\\{vacuous})\1\5 +\X446:Express astonishment that no number was here\X\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}\I\\{spacer}){}$\1\5 +\\{back\_input}(\,);\2\6 +\4${}\}{}$\2\par +\U440.\fi + +\M{445}\B\D$\\{infinity}$ \5 +\T{\~17777777777}\C{the largest positive value that \TeX\ knows}\par +\B\4\D$\\{zero\_token}$ \5 +$(\\{other\_token}+\.{'0'}{}$)\C{zero, the smallest digit}\par +\B\4\D$\\{A\_token}$ \5 +$(\\{letter\_token}+\.{'A'}{}$)\C{the smallest special hex digit}\par +\B\4\D$\\{other\_A\_token}$ \5 +$(\\{other\_token}+\.{'A'}{}$)\C{special hex digit of type \\{other\_char}}\par +\Y\B\4\X445:Accumulate the constant until \\{cur\_tok} is not a suitable digit\X${}\E{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}((\\{cur\_tok}<\\{zero\_token}+\\{radix})\W(\\{cur\_tok}\G\\{zero\_token})\W(\\{cur\_tok}\Z\\{zero\_token}+\T{9})){}$\1\5 +${}\|d\K\\{cur\_tok}-\\{zero\_token};{}$\2\6 +\&{else} \&{if} ${}(\\{radix}\E\T{16}){}$\1\6 +\&{if} ${}((\\{cur\_tok}\Z\\{A\_token}+\T{5})\W(\\{cur\_tok}\G\\{A\_token})){}$\1\5 +${}\|d\K\\{cur\_tok}-\\{A\_token}+\T{10};{}$\2\6 +\&{else} \&{if} ${}((\\{cur\_tok}\Z\\{other\_A\_token}+\T{5})\W(\\{cur\_tok}\G\\{other\_A\_token})){}$\1\5 +${}\|d\K\\{cur\_tok}-\\{other\_A\_token}+\T{10};{}$\2\6 +\&{else}\1\5 +\&{goto} \\{done};\2\2\6 +\&{else}\1\5 +\&{goto} \\{done};\2\6 +${}\\{vacuous}\K\\{false};{}$\6 +\&{if} ${}((\\{cur\_val}\G\|m)\W((\\{cur\_val}>\|m)\V(\|d>\T{7})\V(\\{radix}\I\T{10}))){}$\5 +${}\{{}$\5 +\1\&{if} (\\{OK\_so\_far})\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Number\ too\ big"});\5 +\\{help2}(\.{"I\ can\ only\ go\ up\ to}\)\.{\ 2147483647='1777777}\)\.{7777=\\"7FFFFFFF,"})\6 +(\.{"so\ I'm\ using\ that\ n}\)\.{umber\ instead\ of\ you}\)\.{rs."});\6 +\&{error} (\,)\1\5 +;\2\6 +${}\\{cur\_val}\K\\{infinity};{}$\5 +${}\\{OK\_so\_far}\K\\{false};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{cur\_val}\K\\{cur\_val}*\\{radix}+\|d;{}$\2\6 +\\{get\_x\_token}(\,);\6 +\4${}\}{}$\2\6 +\\{done}:\par +\U444.\fi + +\M{446}\B\X446:Express astonishment that no number was here\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ number,\ tre}\)\.{ated\ as\ zero"});\5 +\\{help3}(\.{"A\ number\ should\ hav}\)\.{e\ been\ here;\ I\ inser}\)\.{ted\ `0'."})\6 +(\.{"(If\ you\ can't\ figur}\)\.{e\ out\ why\ I\ needed\ t}\)\.{o\ see\ a\ number,"})\6 +(\.{"look\ up\ `weird\ erro}\)\.{r'\ in\ the\ index\ to\ T}\)\.{he\ TeXbook.)"});\5 +\\{back\_error}(\,);\6 +\4${}\}{}$\2\par +\U444.\fi + +\M{447}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{glue\_ord} \\{cur\_order};\C{order of infinity found by \\{scan\_dimen}}\par +\fi + +\M{448}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 \&{int} to \&{scaled}. + +\Y\B\4\D$\\{scan\_normal\_dimen}$ \5 +$\\{scan\_dimen}(\\{false},\39\\{false},\39\\{false}{}$)\par +\Y\B\&{void} \\{scan\_dimen}(\&{bool} \\{mu}${},\39{}$\&{bool} \\{inf}${},\39{}$\&{bool} \\{shortcut})\C{sets \\{cur\_val} to a dimension}\6 +${}\{{}$\5 +\1\&{bool} \\{negative};\C{should the answer be negated?}\6 +\&{int} \|f;\C{numerator of a fraction whose denominator is $2^{16}$}\7 +\X450:Local variables for dimension calculations\X\6 +${}\|f\K\T{0};{}$\5 +${}\\{arith\_error}\K\\{false};{}$\5 +${}\\{cur\_order}\K\\{normal};{}$\5 +${}\\{negative}\K\\{false};{}$\6 +\&{if} ${}(\R\\{shortcut}){}$\5 +${}\{{}$\5 +\1\X441:Get the next non-blank non-sign token; set \\{negative} appropriately\X;\6 +\&{if} ${}((\\{cur\_cmd}\G\\{min\_internal})\W(\\{cur\_cmd}\Z\\{max\_internal})){}$\1\5 +\X449:Fetch an internal dimension and \&{goto} \\{attach\_sign}, or fetch an internal integer\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\6 +\&{if} ${}(\\{cur\_tok}\E\\{continental\_point\_token}){}$\1\5 +${}\\{cur\_tok}\K\\{point\_token};{}$\2\6 +\&{if} ${}(\\{cur\_tok}\I\\{point\_token}){}$\1\5 +\\{scan\_int}(\,);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{radix}\K\T{10};{}$\5 +${}\\{cur\_val}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_tok}\E\\{continental\_point\_token}){}$\1\5 +${}\\{cur\_tok}\K\\{point\_token};{}$\2\6 +\&{if} ${}((\\{radix}\E\T{10})\W(\\{cur\_tok}\E\\{point\_token})){}$\1\5 +\X452:Scan decimal fraction\X;\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_val}<\T{0}{}$)\C{in this case $\|f\E\T{0}$}\6 +${}\{{}$\5 +\1${}\\{negative}\K\R\\{negative};{}$\5 +\\{negate}(\\{cur\_val});\6 +\4${}\}{}$\2\6 +\X453: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 +\X443:Scan an optional space\X;\6 +\4\\{attach\_sign}:\6 +\&{if} ${}(\\{arith\_error}\V(\\{abs}(\\{cur\_val})\G\T{\~10000000000})){}$\1\5 +\X460:Report that this dimension is out of range\X;\2\6 +\&{if} (\\{negative})\1\5 +\\{negate}(\\{cur\_val});\2\6 +\4${}\}{}$\2\par +\fi + +\M{449}\B\X449:Fetch an internal dimension and \&{goto} \\{attach\_sign}, or fetch an internal integer\X${}\E{}$\6 +\&{if} (\\{mu})\5 +${}\{{}$\5 +\1${}\\{scan\_something\_internal}(\\{mu\_val},\39\\{false});{}$\5 +\X451:Coerce glue to a dimension\X;\6 +\&{if} ${}(\\{cur\_val\_level}\E\\{mu\_val}){}$\1\5 +\&{goto} \\{attach\_sign};\2\6 +\&{if} ${}(\\{cur\_val\_level}\I\\{int\_val}){}$\1\5 +\\{mu\_error}(\,);\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{scan\_something\_internal}(\\{dimen\_val},\39\\{false});{}$\6 +\&{if} ${}(\\{cur\_val\_level}\E\\{dimen\_val}){}$\1\5 +\&{goto} \\{attach\_sign};\2\6 +\4${}\}{}$\2\par +\U448.\fi + +\M{450}\B\X450:Local variables for dimension calculations\X${}\E{}$\6 +\&{uint32\_t} \\{num}${},{}$ \\{denom};\C{conversion ratio for the scanned units}\6 +\&{int} \|k${},{}$ \\{kk};\C{number of digits in a decimal fraction}\6 +\&{pointer} \|p${},{}$ \|q;\C{top of decimal digit stack}\6 +\&{scaled} \|v;\C{an internal dimension}\6 +\&{int} \\{save\_cur\_val};\C{temporary storage of \\{cur\_val}}\par +\U448.\fi + +\M{451}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\B\4\X451:Coerce glue to a dimension\X${}\E{}$\6 +\&{if} ${}(\\{cur\_val\_level}\G\\{glue\_val}){}$\5 +${}\{{}$\5 +\1${}\|v\K\\{width}(\\{cur\_val});{}$\5 +\\{delete\_glue\_ref}(\\{cur\_val});\5 +${}\\{cur\_val}\K\|v;{}$\6 +\4${}\}{}$\2\par +\Us449\ET455.\fi + +\M{452}When the following code is executed, we have $\\{cur\_tok}\E\\{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\B\4\X452:Scan decimal fraction\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|k\K\T{0};{}$\5 +${}\|p\K\\{null};{}$\5 +\\{get\_token}(\,);\C{\\{point\_token} is being re-scanned}\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{get\_x\_token}(\,);\6 +\&{if} ${}((\\{cur\_tok}>\\{zero\_token}+\T{9})\V(\\{cur\_tok}<\\{zero\_token})){}$\1\5 +\&{goto} \\{done1};\2\6 +\&{if} ${}(\|k<\T{17}{}$)\C{digits for $\|k\G\T{17}$ cannot affect the result}\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4\\{done1}:\6 +\&{for} ${}(\\{kk}\K\|k;{}$ ${}\\{kk}\G\T{1};{}$ ${}\\{kk}\MM){}$\5 +${}\{{}$\5 +\1${}\\{dig}[\\{kk}-\T{1}]\K\\{info}(\|p);{}$\5 +${}\|q\K\|p;{}$\5 +${}\|p\K\\{link}(\|p);{}$\5 +\\{free\_avail}(\|q);\6 +\4${}\}{}$\2\6 +${}\|f\K\\{round\_decimals}(\|k);{}$\6 +\&{if} ${}(\\{cur\_cmd}\I\\{spacer}){}$\1\5 +\\{back\_input}(\,);\2\6 +\4${}\}{}$\2\par +\U448.\fi + +\M{453}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\B\4\X453: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${}\E{}$\6 +\&{if} (\\{inf})\1\5 +\X454:Scan for \(f)\.{fil} units; \&{goto} \\{attach\_fraction} if found\X;\2\6 +\X455:Scan for \(u)units that are internal dimensions; \&{goto} \\{attach\_sign} with \\{cur\_val} set if found\X;\6 +\&{if} (\\{mu})\1\5 +\X456:Scan for \(m)\.{mu} units and \&{goto} \\{attach\_fraction}\X;\2\6 +\&{if} (\\{scan\_keyword}(\X1589:\.{"true"}\X))\1\5 +\X457:Adjust \(f)for the magnification ratio\X;\2\6 +\&{if} (\\{scan\_keyword}(\X1425:\.{"pt"}\X))\1\5 +\&{goto} \\{attach\_fraction};\C{the easy case}\2\6 +\X458: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}:\6 +\&{if} ${}(\\{cur\_val}\G\T{\~40000}){}$\1\5 +${}\\{arith\_error}\K\\{true};{}$\2\6 +\&{else}\1\5 +${}\\{cur\_val}\K\\{cur\_val}*\\{unity}+\|f;{}$\2\6 +\\{done}:\par +\U448.\fi + +\M{454}A specification like `\.{filllll}' or `\.{fill L L L}' will lead to two +error messages (one for each additional keyword \.{"l"}). + +\Y\B\4\X454:Scan for \(f)\.{fil} units; \&{goto} \\{attach\_fraction} if found\X${}\E{}$\6 +\&{if} (\\{scan\_keyword}(\X1387:\.{"fil"}\X))\5 +${}\{{}$\5 +\1${}\\{cur\_order}\K\\{fil};{}$\6 +\&{while} (\\{scan\_keyword}(\.{'l'}))\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_order}\E\\{filll}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Illegal\ unit\ of\ mea}\)\.{sure\ ("});\5 +\\{print\_str}(\.{"replaced\ by\ filll)"});\5 +\\{help1}(\.{"I\ dddon't\ go\ any\ hi}\)\.{gher\ than\ filll."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{incr}(\\{cur\_order});\2\6 +\4${}\}{}$\2\6 +\&{goto} \\{attach\_fraction};\6 +\4${}\}{}$\2\par +\U453.\fi + +\M{455}\B\X455:Scan for \(u)units that are internal dimensions; \&{goto} \\{attach\_sign} with \\{cur\_val} set if found\X${}\E{}$\6 +$\\{save\_cur\_val}\K\\{cur\_val};{}$\5 +\X406:Get the next non-blank non-call token\X;\6 +\&{if} ${}((\\{cur\_cmd}<\\{min\_internal})\V(\\{cur\_cmd}>\\{max\_internal})){}$\1\5 +\\{back\_input}(\,);\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} (\\{mu})\5 +${}\{{}$\5 +\1${}\\{scan\_something\_internal}(\\{mu\_val},\39\\{false});{}$\5 +\X451:Coerce glue to a dimension\X;\6 +\&{if} ${}(\\{cur\_val\_level}\I\\{mu\_val}){}$\1\5 +\\{mu\_error}(\,);\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{scan\_something\_internal}(\\{dimen\_val},\39\\{false});{}$\2\6 +${}\|v\K\\{cur\_val};{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\&{if} (\\{mu})\1\5 +\&{goto} \\{not\_found};\2\6 +\&{if} (\\{scan\_keyword}(\X1590:\.{"em"}\X))\1\5 +${}\|v\K(\X558:The em width for \\{cur\_font}\X);{}$\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1591:\.{"ex"}\X))\1\5 +${}\|v\K(\X559:The x-height for \\{cur\_font}\X);{}$\2\6 +\&{else}\1\5 +\&{goto} \\{not\_found};\2\6 +\X443:Scan an optional space\X;\6 +\4\\{found}:\5 +${}\\{cur\_val}\K\\{nx\_plus\_y}(\\{save\_cur\_val},\39\|v,\39\\{xn\_over\_d}(\|v,\39\|f,\39\T{\~200000}));{}$\5 +\&{goto} \\{attach\_sign}; \\{not\_found}:\par +\U453.\fi + +\M{456}\B\X456:Scan for \(m)\.{mu} units and \&{goto} \\{attach\_fraction}\X${}\E{}$\6 +\&{if} (\\{scan\_keyword}(\X1394:\.{"mu"}\X))\1\5 +\&{goto} \\{attach\_fraction};\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Illegal\ unit\ of\ mea}\)\.{sure\ ("});\5 +\\{print\_str}(\.{"mu\ inserted)"});\5 +\\{help4}(\.{"The\ unit\ of\ measure}\)\.{ment\ in\ math\ glue\ mu}\)\.{st\ be\ mu."})\6 +(\.{"To\ recover\ graceful}\)\.{ly\ from\ this\ error,\ }\)\.{it's\ best\ to"})\6 +(\.{"delete\ the\ erroneou}\)\.{s\ units;\ e.g.,\ type\ }\)\.{`2'\ to\ delete"})\6 +(\.{"two\ letters.\ (See\ C}\)\.{hapter\ 27\ of\ The\ TeX}\)\.{book.)"});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{goto} \\{attach\_fraction};\6 +\4${}\}{}$\2\par +\U453.\fi + +\M{457}\B\X457:Adjust \(f)for the magnification ratio\X${}\E{}$\6 +${}\{{}$\5 +\1\\{prepare\_mag}(\,);\6 +\&{if} ${}(\\{mag}\I\T{1000}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_val}\K\\{xn\_over\_d}(\\{cur\_val},\39\T{1000},\39\\{mag});{}$\5 +${}\|f\K(\T{1000}*\|f+\T{\~200000}*\\{rem})/\\{mag};{}$\5 +${}\\{cur\_val}\K\\{cur\_val}+(\|f/\T{\~200000});{}$\5 +${}\|f\K\|f\MOD\T{\~200000};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U453.\fi + +\M{458}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\B\4\D$\\{set\_conversion\_end}(\|X)$ \5 +$\\{denom}\K\|X;$ $\}{}$\par +\B\4\D$\\{set\_conversion}(\|X)$ \5 +$\{{}$\5 +$\\{num}\K\|X;$ \\{set\_conversion\_end}\par +\Y\B\4\X458:Scan for \(a)all other units and adjust \\{cur\_val} and \|f accordingly; \&{goto} \\{done} in the case of scaled points\X${}\E{}$\6 +\&{if} (\\{scan\_keyword}(\X1592:\.{"in"}\X))\1\5 +\\{set\_conversion}(\T{7227})(\T{100})\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1593:\.{"pc"}\X))\1\5 +\\{set\_conversion}(\T{12})(\T{1})\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1594:\.{"cm"}\X))\1\5 +\\{set\_conversion}(\T{7227})(\T{254})\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1595:\.{"mm"}\X))\1\5 +\\{set\_conversion}(\T{7227})(\T{2540})\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1596:\.{"bp"}\X))\1\5 +\\{set\_conversion}(\T{7227})(\T{7200})\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1597:\.{"dd"}\X))\1\5 +\\{set\_conversion}(\T{1238})(\T{1157})\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1598:\.{"cc"}\X))\1\5 +\\{set\_conversion}(\T{14856})(\T{1157})\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1599:\.{"sp"}\X))\1\5 +\&{goto} \\{done};\2\6 +\&{else}\1\5 +\X459:Complain about unknown unit and \&{goto} \\{done2}\X;\2\6 +${}\\{cur\_val}\K\\{xn\_over\_d}(\\{cur\_val},\39\\{num},\39\\{denom});{}$\5 +${}\|f\K(\\{num}*\|f+\T{\~200000}*\\{rem})/\\{denom}{}$;\6 +${}\\{cur\_val}\K\\{cur\_val}+(\|f/\T{\~200000});{}$\5 +${}\|f\K\|f\MOD\T{\~200000};$ \\{done2}:\par +\U453.\fi + +\M{459}\B\X459:Complain about unknown unit and \&{goto} \\{done2}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Illegal\ unit\ of\ mea}\)\.{sure\ ("});\5 +\\{print\_str}(\.{"pt\ inserted)"});\5 +\\{help6}(\.{"Dimensions\ can\ be\ i}\)\.{n\ units\ of\ em,\ ex,\ i}\)\.{n,\ pt,\ pc,"})\6 +(\.{"cm,\ mm,\ dd,\ cc,\ bp,}\)\.{\ or\ sp;\ but\ yours\ is}\)\.{\ a\ new\ one!"})\6 +(\.{"I'll\ assume\ that\ yo}\)\.{u\ meant\ to\ say\ pt,\ f}\)\.{or\ printer's\ points.}\)\.{"})\6 +(\.{"To\ recover\ graceful}\)\.{ly\ from\ this\ error,\ }\)\.{it's\ best\ to"})\6 +(\.{"delete\ the\ erroneou}\)\.{s\ units;\ e.g.,\ type\ }\)\.{`2'\ to\ delete"})\6 +(\.{"two\ letters.\ (See\ C}\)\.{hapter\ 27\ of\ The\ TeX}\)\.{book.)"});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{goto} \\{done2};\6 +\4${}\}{}$\2\par +\U458.\fi + +\M{460}\B\X460:Report that this dimension is out of range\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Dimension\ too\ large}\)\.{"});\5 +\\{help2}(\.{"I\ can't\ work\ with\ s}\)\.{izes\ bigger\ than\ abo}\)\.{ut\ 19\ feet."})\6 +(\.{"Continue\ and\ I'll\ u}\)\.{se\ the\ largest\ value}\)\.{\ I\ can."});\6 +\&{error} (\,)\1\5 +;\2\6 +${}\\{cur\_val}\K\\{max\_dimen};{}$\5 +${}\\{arith\_error}\K\\{false};{}$\6 +\4${}\}{}$\2\par +\U448.\fi + +\M{461}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\B\&{void} \\{scan\_glue}(\&{small\_number} \\{level})\C{sets \\{cur\_val} to a glue spec pointer}\6 +${}\{{}$\5 +\1\&{bool} \\{negative};\C{should the answer be negated?}\6 +\&{pointer} \|q;\C{new glue specification}\6 +\&{bool} \\{mu};\C{does $\\{level}\E\\{mu\_val}$?}\7 +${}\\{mu}\K(\\{level}\E\\{mu\_val});{}$\5 +\X441:Get the next non-blank non-sign token; set \\{negative} appropriately\X;\6 +\&{if} ${}((\\{cur\_cmd}\G\\{min\_internal})\W(\\{cur\_cmd}\Z\\{max\_internal})){}$\5 +${}\{{}$\5 +\1${}\\{scan\_something\_internal}(\\{level},\39\\{negative});{}$\6 +\&{if} ${}(\\{cur\_val\_level}\G\\{glue\_val}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_val\_level}\I\\{level}){}$\1\5 +\\{mu\_error}(\,);\2\6 +\&{return};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_val\_level}\E\\{int\_val}){}$\1\5 +${}\\{scan\_dimen}(\\{mu},\39\\{false},\39\\{true});{}$\2\6 +\&{else} \&{if} ${}(\\{level}\E\\{mu\_val}){}$\1\5 +\\{mu\_error}(\,);\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +${}\\{scan\_dimen}(\\{mu},\39\\{false},\39\\{false});{}$\6 +\&{if} (\\{negative})\1\5 +\\{negate}(\\{cur\_val});\2\6 +\4${}\}{}$\2\6 +\X462:Create a new glue specification whose width is \\{cur\_val}; scan for its stretch and shrink components\X;\6 +\4${}\}{}$\2\par +\fi + +\M{462}\B\X462:Create a new glue specification whose width is \\{cur\_val}; scan for its stretch and shrink components\X${}\E{}$\6 +$\|q\K\\{new\_spec}(\\{zero\_glue});{}$\5 +${}\\{width}(\|q)\K\\{cur\_val};{}$\6 +\&{if} (\\{scan\_keyword}(\X1600:\.{"plus"}\X))\5 +${}\{{}$\5 +\1${}\\{scan\_dimen}(\\{mu},\39\\{true},\39\\{false});{}$\5 +${}\\{stretch}(\|q)\K\\{cur\_val};{}$\5 +${}\\{stretch\_order}(\|q)\K\\{cur\_order};{}$\6 +\4${}\}{}$\2\6 +\&{if} (\\{scan\_keyword}(\X1601:\.{"minus"}\X))\5 +${}\{{}$\5 +\1${}\\{scan\_dimen}(\\{mu},\39\\{true},\39\\{false});{}$\5 +${}\\{shrink}(\|q)\K\\{cur\_val};{}$\5 +${}\\{shrink\_order}(\|q)\K\\{cur\_order};{}$\6 +\4${}\}{}$\2\6 +$\\{cur\_val}\K{}$\|q\par +\U461.\fi + +\M{463}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\B\4\D$\\{default\_rule}$ \5 +\T{26214}\C{0.4\thinspace pt}\par +\Y\B\&{pointer} \\{scan\_rule\_spec}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|q;\C{the rule node being created}\7 +${}\|q\K\\{new\_rule}(\,){}$;\C{\\{width}, \\{depth}, and \\{height} all equal \\{null\_flag} now}\6 +\&{if} ${}(\\{cur\_cmd}\E\\{vrule}){}$\1\5 +${}\\{width}(\|q)\K\\{default\_rule};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{height}(\|q)\K\\{default\_rule};{}$\5 +${}\\{depth}(\|q)\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4\\{reswitch}:\6 +\&{if} (\\{scan\_keyword}(\X1602:\.{"width"}\X))\5 +${}\{{}$\5 +\1\\{scan\_normal\_dimen};\5 +${}\\{width}(\|q)\K\\{cur\_val};{}$\5 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\&{if} (\\{scan\_keyword}(\X1603:\.{"height"}\X))\5 +${}\{{}$\5 +\1\\{scan\_normal\_dimen};\5 +${}\\{height}(\|q)\K\\{cur\_val};{}$\5 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\&{if} (\\{scan\_keyword}(\X1604:\.{"depth"}\X))\5 +${}\{{}$\5 +\1\\{scan\_normal\_dimen};\5 +${}\\{depth}(\|q)\K\\{cur\_val};{}$\5 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\&{return} \|q;\6 +\4${}\}{}$\2\par +\fi + +\N{1}{464}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\E\\{temp\_head}$, the list is empty.) + +\Y\B\&{pointer} \\{str\_toks}(\&{pool\_pointer} \|b)\C{changes the string $\\{str\_pool}[\|b\dotdot\\{pool\_ptr}]$ to a token list}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{tail of the token list}\6 +\&{pointer} \|q;\C{new node being added to the token list via \\{store\_new\_token}}\6 +\&{halfword} \|t;\C{token being appended}\6 +\&{pool\_pointer} \|k;\C{index into \\{str\_pool}}\7 +\\{str\_room}(\T{1});\5 +${}\|p\K\\{temp\_head};{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\5 +${}\|k\K\|b;{}$\6 +\&{while} ${}(\|k<\\{pool\_ptr}){}$\5 +${}\{{}$\5 +\1${}\|t\K\\{so}(\\{str\_pool}[\|k]);{}$\6 +\&{if} ${}(\|t\E\.{'\ '}){}$\1\5 +${}\|t\K\\{space\_token};{}$\2\6 +\&{else}\1\5 +${}\|t\K\\{other\_token}+\|t;{}$\2\6 +\\{fast\_store\_new\_token}(\|t);\5 +\\{incr}(\|k);\6 +\4${}\}{}$\2\6 +${}\\{pool\_ptr}\K\|b;{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{465}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\B\&{pointer} \\{the\_toks}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \\{old\_setting};\C{holds \\{selector} setting}\6 +\&{pointer} \|p${},{}$ \|q${},{}$ \|r;\C{used for copying a token list}\6 +\&{pool\_pointer} \|b;\C{base of temporary string}\7 +\\{get\_x\_token}(\,);\5 +${}\\{scan\_something\_internal}(\\{tok\_val},\39\\{false});{}$\6 +\&{if} ${}(\\{cur\_val\_level}\G\\{ident\_val}){}$\1\5 +\X466:Copy the token list\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{old\_setting}\K\\{selector};{}$\5 +${}\\{selector}\K\\{new\_string};{}$\5 +${}\|b\K\\{pool\_ptr};{}$\6 +\&{switch} (\\{cur\_val\_level})\5 +${}\{{}$\1\6 +\4\&{case} \\{int\_val}:\5 +\\{print\_int}(\\{cur\_val});\5 +\&{break};\6 +\4\&{case} \\{dimen\_val}:\6 +${}\{{}$\5 +\1\\{print\_scaled}(\\{cur\_val});\5 +\\{print\_str}(\.{"pt"});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{glue\_val}:\6 +${}\{{}$\5 +\1${}\\{print\_spec}(\\{cur\_val},\39\X1425:\.{"pt"}\X);{}$\5 +\\{delete\_glue\_ref}(\\{cur\_val});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{mu\_val}:\6 +${}\{{}$\5 +\1${}\\{print\_spec}(\\{cur\_val},\39\X1394:\.{"mu"}\X);{}$\5 +\\{delete\_glue\_ref}(\\{cur\_val});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\C{there are no other cases}\2\6 +${}\\{selector}\K\\{old\_setting};{}$\5 +\&{return} \\{str\_toks}(\|b);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{466}\B\X466:Copy the token list\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|p\K\\{temp\_head};{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\6 +\&{if} ${}(\\{cur\_val\_level}\E\\{ident\_val}){}$\1\5 +${}\\{store\_new\_token}(\\{cs\_token\_flag}+\\{cur\_val}){}$\2\6 +\&{else} \&{if} ${}(\\{cur\_val}\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\|r\K\\{link}(\\{cur\_val}){}$;\C{do not copy the reference count}\6 +\&{while} ${}(\|r\I\\{null}){}$\5 +${}\{{}$\5 +\1\\{fast\_store\_new\_token}(\\{info}(\|r));\5 +${}\|r\K\\{link}(\|r);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\U465.\fi + +\M{467}Here's part of the \\{expand} subroutine that we are now ready to complete: + +\Y\B\&{void} \\{ins\_the\_toks}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{link}(\\{garbage})\K\\{the\_toks}(\,);{}$\5 +\\{ins\_list}(\\{link}(\\{temp\_head}));\6 +\4${}\}{}$\2\par +\fi + +\M{468}The primitives \.{\\number}, \.{\\romannumeral}, \.{\\string}, \.{\\meaning}, +\.{\\fontname}, and \.{\\jobname} are defined as follows. + +\Y\B\4\D$\\{number\_code}$ \5 +\T{0}\C{command code for \.{\\number}}\par +\B\4\D$\\{roman\_numeral\_code}$ \5 +\T{1}\C{command code for \.{\\romannumeral}}\par +\B\4\D$\\{string\_code}$ \5 +\T{2}\C{command code for \.{\\string}}\par +\B\4\D$\\{meaning\_code}$ \5 +\T{3}\C{command code for \.{\\meaning}}\par +\B\4\D$\\{font\_name\_code}$ \5 +\T{4}\C{command code for \.{\\fontname}}\par +\B\4\D$\\{job\_name\_code}$ \5 +\T{5}\C{command code for \.{\\jobname}}\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1605:\.{"number"}\X,\39\\{convert},\39\\{number\_code}){}$;\6 +${}\\{primitive}(\X1606:\.{"romannumeral"}\X,\39\\{convert},\39\\{roman\_numeral\_code}){}$;\6 +${}\\{primitive}(\X1607:\.{"string"}\X,\39\\{convert},\39\\{string\_code}){}$;\6 +${}\\{primitive}(\X1608:\.{"meaning"}\X,\39\\{convert},\39\\{meaning\_code}){}$;\6 +${}\\{primitive}(\X1609:\.{"fontname"}\X,\39\\{convert},\39\\{font\_name\_code}){}$;\6 +${}\\{primitive}(\X1610:\.{"jobname"}\X,\39\\{convert},\39\\{job\_name\_code}){}$;\par +\fi + +\M{469}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{convert}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{number\_code}:\5 +\\{print\_esc}(\X1605:\.{"number"}\X);\5 +\&{break};\6 +\4\&{case} \\{roman\_numeral\_code}:\5 +\\{print\_esc}(\X1606:\.{"romannumeral"}\X);\5 +\&{break};\6 +\4\&{case} \\{string\_code}:\5 +\\{print\_esc}(\X1607:\.{"string"}\X);\5 +\&{break};\6 +\4\&{case} \\{meaning\_code}:\5 +\\{print\_esc}(\X1608:\.{"meaning"}\X);\5 +\&{break};\6 +\4\&{case} \\{font\_name\_code}:\5 +\\{print\_esc}(\X1609:\.{"fontname"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1610:\.{"jobname"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{470}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\B\&{void} \\{conv\_toks}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \\{old\_setting};\C{holds \\{selector} setting}\6 +\&{uint8\_t} \|c;\C{desired type of conversion}\6 +\&{small\_number} \\{save\_scanner\_status};\C{\\{scanner\_status} upon entry}\6 +\&{pool\_pointer} \|b;\C{base of temporary string}\7 +${}\|c\K\\{cur\_chr};{}$\5 +\X471:Scan the argument for command \|c\X;\6 +${}\\{old\_setting}\K\\{selector};{}$\5 +${}\\{selector}\K\\{new\_string};{}$\5 +${}\|b\K\\{pool\_ptr};{}$\5 +\X472: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 +\4${}\}{}$\2\par +\fi + +\M{471}\B\X471:Scan the argument for command \|c\X${}\E{}$\6 +\&{switch} (\|c)\5 +${}\{{}$\1\6 +\4\&{case} \\{number\_code}:\5 +\&{case} \\{roman\_numeral\_code}:\5 +\\{scan\_int}(\,);\5 +\&{break};\6 +\4\&{case} \\{string\_code}:\5 +\&{case} \\{meaning\_code}:\6 +${}\{{}$\5 +\1${}\\{save\_scanner\_status}\K\\{scanner\_status};{}$\5 +${}\\{scanner\_status}\K\\{normal};{}$\5 +\\{get\_token}(\,);\5 +${}\\{scanner\_status}\K\\{save\_scanner\_status};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{font\_name\_code}:\5 +\\{scan\_font\_ident}(\,);\5 +\&{break};\6 +\4\&{case} \\{job\_name\_code}:\6 +\&{if} ${}(\\{job\_name}\E\T{0}){}$\1\5 +\\{open\_log\_file}(\,);\2\6 +\4${}\}{}$\C{there are no other cases}\2\par +\U470.\fi + +\M{472}\B\X472:Print the result of command \|c\X${}\E{}$\6 +\&{switch} (\|c)\5 +${}\{{}$\1\6 +\4\&{case} \\{number\_code}:\5 +\\{print\_int}(\\{cur\_val});\5 +\&{break};\6 +\4\&{case} \\{roman\_numeral\_code}:\5 +\\{print\_roman\_int}(\\{cur\_val});\5 +\&{break};\6 +\4\&{case} \\{string\_code}:\6 +\&{if} ${}(\\{cur\_cs}\I\T{0}){}$\1\5 +\\{sprint\_cs}(\\{cur\_cs});\2\6 +\&{else}\1\5 +\\{print\_char}(\\{cur\_chr});\5 +\2\&{break};\6 +\4\&{case} \\{meaning\_code}:\5 +\\{print\_meaning}(\,);\5 +\&{break};\6 +\4\&{case} \\{font\_name\_code}:\6 +${}\{{}$\5 +\1\\{print}(\\{font\_name}[\\{cur\_val}]);\6 +\&{if} ${}(\\{font\_size}[\\{cur\_val}]\I\\{font\_dsize}[\\{cur\_val}]){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ at\ "});\5 +\\{print\_scaled}(\\{font\_size}[\\{cur\_val}]);\5 +\\{print\_str}(\.{"pt"});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{job\_name\_code}:\5 +\\{print}(\\{job\_name});\6 +\4${}\}{}$\C{there are no other cases}\2\par +\U470.\fi + +\M{473}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\B\&{pointer} \\{scan\_toks}(\&{bool} \\{macro\_def}${},\39{}$\&{bool} \\{xpand})\1\1\2\2\6 +${}\{{}$\5 +\1\&{halfword} \|t;\C{token representing the highest parameter number}\6 +\&{halfword} \|s;\C{saved token}\6 +\&{pointer} \|p;\C{tail of the token list being built}\6 +\&{pointer} \|q;\C{new node being added to the token list via \\{store\_new\_token}}\6 +\&{halfword} \\{unbalance};\C{number of unmatched left braces}\6 +\&{halfword} \\{hash\_brace};\C{possible `\.{\#\{}' token}\7 +\&{if} (\\{macro\_def})\1\5 +${}\\{scanner\_status}\K\\{defining}{}$;\5 +\2\&{else}\1\5 +${}\\{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}\K\T{0};{}$\5 +${}\|t\K\\{zero\_token};{}$\6 +\&{if} (\\{macro\_def})\1\5 +\X474:Scan and build the parameter part of the macro definition\X\2\6 +\&{else}\1\5 +\\{scan\_left\_brace}(\,);\C{remove the compulsory left brace}\2\6 +\X477:Scan and build the body of the token list; \&{goto} \\{found} when finished\X;\6 +\4\\{found}:\5 +${}\\{scanner\_status}\K\\{normal};{}$\6 +\&{if} ${}(\\{hash\_brace}\I\T{0}){}$\1\5 +\\{store\_new\_token}(\\{hash\_brace});\2\6 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{474}\B\X474:Scan and build the parameter part of the macro definition\X${}\E{}$\6 +${}\{{}$\5 +\1\&{loop}\5 +${}\{{}$\5 +\1\\{get\_token}(\,);\C{set \\{cur\_cmd}, \\{cur\_chr}, \\{cur\_tok}}\6 +\&{if} ${}(\\{cur\_tok}<\\{right\_brace\_limit}){}$\1\5 +\&{goto} \\{done1};\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{mac\_param}){}$\1\5 +\X476: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 +\4${}\}{}$\2\6 +\4\\{done1}:\5 +\\{store\_new\_token}(\\{end\_match\_token});\6 +\&{if} ${}(\\{cur\_cmd}\E\\{right\_brace}){}$\1\5 +\X475:Express shock at the missing left brace; \&{goto} \\{found}\X;\2\6 +\4\\{done}:\5 +;\6 +\4${}\}{}$\2\par +\U473.\fi + +\M{475}\B\X475:Express shock at the missing left brace; \&{goto} \\{found}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ \{\ inserted"});\5 +\\{incr}(\\{align\_state});\5 +\\{help2}(\.{"Where\ was\ the\ left\ }\)\.{brace?\ You\ said\ some}\)\.{thing\ like\ `\\\\def\\\\a}\)\.{\}',"})\6 +(\.{"which\ I'm\ going\ to\ }\)\.{interpret\ as\ `\\\\def\\}\)\.{\\a\{\}'."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{goto} \\{found};\6 +\4${}\}{}$\2\par +\U474.\fi + +\M{476}\B\X476: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${}\E{}$\6 +${}\{{}$\5 +\1${}\|s\K\\{match\_token}+\\{cur\_chr};{}$\5 +\\{get\_token}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\E\\{left\_brace}){}$\5 +${}\{{}$\5 +\1${}\\{hash\_brace}\K\\{cur\_tok};{}$\5 +\\{store\_new\_token}(\\{cur\_tok});\5 +\\{store\_new\_token}(\\{end\_match\_token});\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|t\E\\{zero\_token}+\T{9}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"You\ already\ have\ ni}\)\.{ne\ parameters"});\5 +\\{help1}(\.{"I'm\ going\ to\ ignore}\)\.{\ the\ \#\ sign\ you\ just}\)\.{\ used."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{incr}(\|t);\6 +\&{if} ${}(\\{cur\_tok}\I\|t){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Parameters\ must\ be\ }\)\.{numbered\ consecutive}\)\.{ly"});\5 +\\{help2}(\.{"I've\ inserted\ the\ d}\)\.{igit\ you\ should\ have}\)\.{\ used\ after\ the\ \#."})\6 +(\.{"Type\ `1'\ to\ delete\ }\)\.{what\ you\ did\ use."});\5 +\\{back\_error}(\,);\6 +\4${}\}{}$\2\6 +${}\\{cur\_tok}\K\|s;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U474.\fi + +\M{477}\B\X477:Scan and build the body of the token list; \&{goto} \\{found} when finished\X${}\E{}$\6 +$\\{unbalance}\K\T{1};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} (\\{xpand})\1\5 +\X478:Expand the next part of the input\X\2\6 +\&{else}\1\5 +\\{get\_token}(\,);\2\6 +\&{if} ${}(\\{cur\_tok}<\\{right\_brace\_limit}){}$\1\6 +\&{if} ${}(\\{cur\_cmd}<\\{right\_brace}){}$\1\5 +\\{incr}(\\{unbalance});\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{decr}(\\{unbalance});\6 +\&{if} ${}(\\{unbalance}\E\T{0}){}$\1\5 +\&{goto} \\{found};\2\6 +\4${}\}{}$\2\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}\E\\{mac\_param}){}$\1\6 +\&{if} (\\{macro\_def})\1\5 +\X479:Look for parameter number or \.{\#\#}\X;\2\2\6 +\\{store\_new\_token}(\\{cur\_tok});\6 +\4${}\}{}$\2\par +\U473.\fi + +\M{478}Here we insert an entire token list created by \\{the\_toks} without +expanding it further. + +\Y\B\4\X478:Expand the next part of the input\X${}\E{}$\6 +${}\{{}$\5 +\1\&{loop}\5 +${}\{{}$\5 +\1\\{get\_next}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\Z\\{max\_command}){}$\1\5 +\&{goto} \\{done2};\2\6 +\&{if} ${}(\\{cur\_cmd}\I\\{the}){}$\1\5 +\\{expand}(\,);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{the\_toks}(\,);{}$\6 +\&{if} ${}(\\{link}(\\{temp\_head})\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|p)\K\\{link}(\\{temp\_head});{}$\5 +${}\|p\K\|q;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4\\{done2}:\5 +\\{x\_token}(\,);\6 +\4${}\}{}$\2\par +\U477.\fi + +\M{479}\B\X479:Look for parameter number or \.{\#\#}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|s\K\\{cur\_tok};{}$\6 +\&{if} (\\{xpand})\1\5 +\\{get\_x\_token}(\,);\2\6 +\&{else}\1\5 +\\{get\_token}(\,);\2\6 +\&{if} ${}(\\{cur\_cmd}\I\\{mac\_param}){}$\1\6 +\&{if} ${}((\\{cur\_tok}\Z\\{zero\_token})\V(\\{cur\_tok}>\|t)){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Illegal\ parameter\ n}\)\.{umber\ in\ definition\ }\)\.{of\ "});\5 +\\{sprint\_cs}(\\{warning\_index});\5 +\\{help3}(\.{"You\ meant\ to\ type\ \#}\)\.{\#\ instead\ of\ \#,\ righ}\)\.{t?"})\6 +(\.{"Or\ maybe\ a\ \}\ was\ fo}\)\.{rgotten\ somewhere\ ea}\)\.{rlier,\ and\ things"})\6 +(\.{"are\ all\ screwed\ up?}\)\.{\ I'm\ going\ to\ assume}\)\.{\ that\ you\ meant\ \#\#."});\5 +\\{back\_error}(\,);\5 +${}\\{cur\_tok}\K\|s;{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{cur\_tok}\K\\{out\_param\_token}-\.{'0'}+\\{cur\_chr};{}$\2\2\6 +\4${}\}{}$\2\par +\U477.\fi + +\M{480}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\B\4\D$\\{closed}$ \5 +\T{2}\C{not open, or at end of file}\par +\B\4\D$\\{just\_open}$ \5 +\T{1}\C{newly opened, first line not yet read}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{alpha\_file} \\{read\_file}[\T{16}];\C{used for \.{\\read}}\6 +\&{uint8\_t} \\{read\_open}[\T{17}];\C{state of \\{read\_file}[\|n]}\par +\fi + +\M{481}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{16};{}$ ${}\|k\PP){}$\1\5 +${}\\{read\_open}[\|k]\K\\{closed}{}$;\2\par +\fi + +\M{482}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\B\&{void} \\{read\_toks}(\&{int} \|n${},\39{}$\&{pointer} \|r)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{tail of the token list}\6 +\&{pointer} \|q;\C{new node being added to the token list via \\{store\_new\_token}}\6 +\&{int} \|s;\C{saved value of \\{align\_state}}\6 +\&{small\_number} \|m;\C{stream number}\7 +${}\\{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<\T{0})\V(\|n>\T{15})){}$\1\5 +${}\|m\K\T{16}{}$;\5 +\2\&{else}\1\5 +${}\|m\K\|n;{}$\2\6 +${}\|s\K\\{align\_state};{}$\5 +${}\\{align\_state}\K\T{1000000}{}$;\C{disable tab marks, etc.}\6 +\&{do}\5 +${}\{{}$\1\6 +\X483:Input and store tokens from the next line of the file\X;\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{align\_state}\E\T{1000000}));{}$\5 +${}\\{cur\_val}\K\\{def\_ref};{}$\5 +${}\\{scanner\_status}\K\\{normal};{}$\5 +${}\\{align\_state}\K\|s;{}$\6 +\4${}\}{}$\2\par +\fi + +\M{483}\B\X483:Input and store tokens from the next line of the file\X${}\E{}$\6 +\\{begin\_file\_reading}(\,);\5 +${}\\{name}\K\|m+\T{1};{}$\6 +\&{if} ${}(\\{read\_open}[\|m]\E\\{closed}){}$\1\5 +\X484:Input for \.{\\read} from the terminal\X;\2\6 +\&{else} \&{if} ${}(\\{read\_open}[\|m]\E\\{just\_open}){}$\1\5 +\X485:Input the first line of \\{read\_file}[\|m]\X\2\6 +\&{else}\1\5 +\X486:Input the next line of \\{read\_file}[\|m]\X;\2\6 +${}\\{limit}\K\\{last};{}$\6 +\&{if} (\\{end\_line\_char\_inactive})\1\5 +\\{decr}(\\{limit});\2\6 +\&{else}\1\5 +${}\\{buffer}[\\{limit}]\K\\{end\_line\_char};{}$\2\6 +${}\\{first}\K\\{limit}+\T{1};{}$\5 +${}\\{loc}\K\\{start};{}$\5 +${}\\{state}\K\\{new\_line}{}$;\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{get\_token}(\,);\6 +\&{if} ${}(\\{cur\_tok}\E\T{0}){}$\1\5 +\&{goto} \\{done};\C{$\\{cur\_cmd}\E\\{cur\_chr}\E\T{0}$ will occur at the end of the line}\2\6 +\&{if} ${}(\\{align\_state}<\T{1000000}{}$)\C{unmatched `\.\}' aborts the line}\6 +${}\{{}$\5 +\1\&{do}\5 +${}\{{}$\1\6 +\\{get\_token}(\,);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{cur\_tok}\E\T{0}));{}$\5 +${}\\{align\_state}\K\T{1000000};{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\\{store\_new\_token}(\\{cur\_tok});\6 +\4${}\}{}$\2\6 +\\{done}: \\{end\_file\_reading}(\,)\par +\U482.\fi + +\M{484}Here we input on-line into the \\{buffer} array, prompting the user explicitly +if $\|n\G\T{0}$. The value of \|n is set negative so that additional prompts +will not be given in the case of multi-line input. + +\Y\B\4\X484:Input for \.{\\read} from the terminal\X${}\E{}$\6 +\&{if} ${}(\\{interaction}>\\{nonstop\_mode}){}$\1\6 +\&{if} ${}(\|n<\T{0}){}$\1\5 +\\{prompt\_input}(\.{""})\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{wake\_up\_terminal};\5 +\\{print\_ln}(\,);\5 +\\{sprint\_cs}(\|r);\5 +\\{prompt\_input}(\.{"="});\5 +${}\|n\K{-}\T{1};{}$\6 +\4${}\}{}$\2\2\6 +\&{else} \\{fatal\_error}(\.{"***\ (cannot\ \\\\read\ }\)\.{from\ terminal\ in\ non}\)\.{stop\ modes)"})\par +\U483.\fi + +\M{485}The first line of a file must be treated specially, since \\{input\_ln} +must be told not to start with \\{get}. + +\Y\B\4\X485:Input the first line of \\{read\_file}[\|m]\X${}\E{}$\6 +\&{if} ${}(\\{input\_ln}({\AND}\\{read\_file}[\|m],\39\\{false})){}$\1\5 +${}\\{read\_open}[\|m]\K\\{normal};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{a\_close}({\AND}\\{read\_file}[\|m]);{}$\5 +${}\\{read\_open}[\|m]\K\\{closed};{}$\6 +\4${}\}{}$\2\par +\U483.\fi + +\M{486}An empty line is appended at the end of a \\{read\_file}. + +\Y\B\4\X486:Input the next line of \\{read\_file}[\|m]\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\R\\{input\_ln}({\AND}\\{read\_file}[\|m],\39\\{true})){}$\5 +${}\{{}$\5 +\1${}\\{a\_close}({\AND}\\{read\_file}[\|m]);{}$\5 +${}\\{read\_open}[\|m]\K\\{closed};{}$\6 +\&{if} ${}(\\{align\_state}\I\T{1000000}){}$\5 +${}\{{}$\5 +\1\\{runaway}(\,);\5 +\\{print\_err}(\.{"File\ ended\ within\ "});\5 +\\{print\_esc}(\X1556:\.{"read"}\X);\5 +\\{help1}(\.{"This\ \\\\read\ has\ unb}\)\.{alanced\ braces."});\5 +${}\\{align\_state}\K\T{1000000};{}$\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U483.\fi + +\N{1}{487}Conditional processing. +We consider now the way \TeX\ handles various kinds of \.{\\if} commands. + +\Y\B\4\D$\\{if\_char\_code}$ \5 +\T{0}\C{ `\.{\\if}' }\par +\B\4\D$\\{if\_cat\_code}$ \5 +\T{1}\C{ `\.{\\ifcat}' }\par +\B\4\D$\\{if\_int\_code}$ \5 +\T{2}\C{ `\.{\\ifnum}' }\par +\B\4\D$\\{if\_dim\_code}$ \5 +\T{3}\C{ `\.{\\ifdim}' }\par +\B\4\D$\\{if\_odd\_code}$ \5 +\T{4}\C{ `\.{\\ifodd}' }\par +\B\4\D$\\{if\_vmode\_code}$ \5 +\T{5}\C{ `\.{\\ifvmode}' }\par +\B\4\D$\\{if\_hmode\_code}$ \5 +\T{6}\C{ `\.{\\ifhmode}' }\par +\B\4\D$\\{if\_mmode\_code}$ \5 +\T{7}\C{ `\.{\\ifmmode}' }\par +\B\4\D$\\{if\_inner\_code}$ \5 +\T{8}\C{ `\.{\\ifinner}' }\par +\B\4\D$\\{if\_void\_code}$ \5 +\T{9}\C{ `\.{\\ifvoid}' }\par +\B\4\D$\\{if\_hbox\_code}$ \5 +\T{10}\C{ `\.{\\ifhbox}' }\par +\B\4\D$\\{if\_vbox\_code}$ \5 +\T{11}\C{ `\.{\\ifvbox}' }\par +\B\4\D$\\{ifx\_code}$ \5 +\T{12}\C{ `\.{\\ifx}' }\par +\B\4\D$\\{if\_eof\_code}$ \5 +\T{13}\C{ `\.{\\ifeof}' }\par +\B\4\D$\\{if\_true\_code}$ \5 +\T{14}\C{ `\.{\\iftrue}' }\par +\B\4\D$\\{if\_false\_code}$ \5 +\T{15}\C{ `\.{\\iffalse}' }\par +\B\4\D$\\{if\_case\_code}$ \5 +\T{16}\C{ `\.{\\ifcase}' }\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1611:\.{"if"}\X,\39\\{if\_test},\39\\{if\_char\_code});{}$\5 +${}\\{primitive}(\X1612:\.{"ifcat"}\X,\39\\{if\_test},\39\\{if\_cat\_code});{}$\5 +${}\\{primitive}(\X1613:\.{"ifnum"}\X,\39\\{if\_test},\39\\{if\_int\_code});{}$\5 +${}\\{primitive}(\X1614:\.{"ifdim"}\X,\39\\{if\_test},\39\\{if\_dim\_code});{}$\5 +${}\\{primitive}(\X1615:\.{"ifodd"}\X,\39\\{if\_test},\39\\{if\_odd\_code});{}$\5 +${}\\{primitive}(\X1616:\.{"ifvmode"}\X,\39\\{if\_test},\39\\{if\_vmode\_code});{}$\5 +${}\\{primitive}(\X1617:\.{"ifhmode"}\X,\39\\{if\_test},\39\\{if\_hmode\_code});{}$\5 +${}\\{primitive}(\X1618:\.{"ifmmode"}\X,\39\\{if\_test},\39\\{if\_mmode\_code});{}$\5 +${}\\{primitive}(\X1619:\.{"ifinner"}\X,\39\\{if\_test},\39\\{if\_inner\_code});{}$\5 +${}\\{primitive}(\X1620:\.{"ifvoid"}\X,\39\\{if\_test},\39\\{if\_void\_code});{}$\5 +${}\\{primitive}(\X1621:\.{"ifhbox"}\X,\39\\{if\_test},\39\\{if\_hbox\_code});{}$\5 +${}\\{primitive}(\X1622:\.{"ifvbox"}\X,\39\\{if\_test},\39\\{if\_vbox\_code});{}$\5 +${}\\{primitive}(\X1623:\.{"ifx"}\X,\39\\{if\_test},\39\\{ifx\_code});{}$\5 +${}\\{primitive}(\X1624:\.{"ifeof"}\X,\39\\{if\_test},\39\\{if\_eof\_code});{}$\5 +${}\\{primitive}(\X1625:\.{"iftrue"}\X,\39\\{if\_test},\39\\{if\_true\_code});{}$\5 +${}\\{primitive}(\X1626:\.{"iffalse"}\X,\39\\{if\_test},\39\\{if\_false\_code});{}$\5 +${}\\{primitive}(\X1627:\.{"ifcase"}\X,\39\\{if\_test},\39\\{if\_case\_code}){}$;\par +\fi + +\M{488}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{if\_test}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{if\_cat\_code}:\5 +\\{print\_esc}(\X1612:\.{"ifcat"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_int\_code}:\5 +\\{print\_esc}(\X1613:\.{"ifnum"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_dim\_code}:\5 +\\{print\_esc}(\X1614:\.{"ifdim"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_odd\_code}:\5 +\\{print\_esc}(\X1615:\.{"ifodd"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_vmode\_code}:\5 +\\{print\_esc}(\X1616:\.{"ifvmode"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_hmode\_code}:\5 +\\{print\_esc}(\X1617:\.{"ifhmode"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_mmode\_code}:\5 +\\{print\_esc}(\X1618:\.{"ifmmode"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_inner\_code}:\5 +\\{print\_esc}(\X1619:\.{"ifinner"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_void\_code}:\5 +\\{print\_esc}(\X1620:\.{"ifvoid"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_hbox\_code}:\5 +\\{print\_esc}(\X1621:\.{"ifhbox"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_vbox\_code}:\5 +\\{print\_esc}(\X1622:\.{"ifvbox"}\X);\5 +\&{break};\6 +\4\&{case} \\{ifx\_code}:\5 +\\{print\_esc}(\X1623:\.{"ifx"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_eof\_code}:\5 +\\{print\_esc}(\X1624:\.{"ifeof"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_true\_code}:\5 +\\{print\_esc}(\X1625:\.{"iftrue"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_false\_code}:\5 +\\{print\_esc}(\X1626:\.{"iffalse"}\X);\5 +\&{break};\6 +\4\&{case} \\{if\_case\_code}:\5 +\\{print\_esc}(\X1627:\.{"ifcase"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1611:\.{"if"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{489}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}\E\\{null}$, $\\{if\_limit}\E\\{normal}$, $\\{cur\_if}\E\T{0}$, $\\{if\_line}\E\T{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\B\4\D$\\{if\_node\_size}$ \5 +\T{2}\C{number of words in stack entry for conditionals}\par +\B\4\D$\\{if\_line\_field}(\|X)$ \5 +$\\{mem}[\|X+\T{1}].{}$\|i\par +\B\4\D$\\{if\_code}$ \5 +\T{1}\C{code for \.{\\if...} being evaluated}\par +\B\4\D$\\{fi\_code}$ \5 +\T{2}\C{code for \.{\\fi}}\par +\B\4\D$\\{else\_code}$ \5 +\T{3}\C{code for \.{\\else}}\par +\B\4\D$\\{or\_code}$ \5 +\T{4}\C{code for \.{\\or}}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{cond\_ptr};\C{top of the condition stack}\6 +\&{uint8\_t} \\{if\_limit};\C{upper bound on \\{fi\_or\_else} codes}\6 +\&{small\_number} \\{cur\_if};\C{type of conditional being worked on}\6 +\&{int} \\{if\_line};\C{line where that conditional began}\par +\fi + +\M{490}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{cond\_ptr}\K\\{null};{}$\5 +${}\\{if\_limit}\K\\{normal};{}$\5 +${}\\{cur\_if}\K\T{0};{}$\5 +${}\\{if\_line}\K\T{0}{}$;\par +\fi + +\M{491}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1628:\.{"fi"}\X,\39\\{fi\_or\_else},\39\\{fi\_code});{}$\5 +${}\\{text}(\\{frozen\_fi})\K\X1628:\.{"fi"}\X;{}$\5 +${}\\{eqtb}[\\{frozen\_fi}]\K\\{eqtb}[\\{cur\_val}];{}$\5 +${}\\{primitive}(\X1629:\.{"or"}\X,\39\\{fi\_or\_else},\39\\{or\_code});{}$\5 +${}\\{primitive}(\X1630:\.{"else"}\X,\39\\{fi\_or\_else},\39\\{else\_code}){}$;\par +\fi + +\M{492}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{fi\_or\_else}:\6 +\&{if} ${}(\\{chr\_code}\E\\{fi\_code}){}$\1\5 +\\{print\_esc}(\X1628:\.{"fi"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{or\_code}){}$\1\5 +\\{print\_esc}(\X1629:\.{"or"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1630:\.{"else"}\X);\5 +\2\&{break};\par +\fi + +\M{493}When we skip conditional text, we keep track of the line number +where skipping began, for use in error messages. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{skip\_line};\C{skipping began here}\par +\fi + +\M{494}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\B\&{void} \\{pass\_text}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|l;\C{level of $\.{\\if}\ldots\.{\\fi}$ nesting}\6 +\&{small\_number} \\{save\_scanner\_status};\C{\\{scanner\_status} upon entry}\7 +${}\\{save\_scanner\_status}\K\\{scanner\_status};{}$\5 +${}\\{scanner\_status}\K\\{skipping};{}$\5 +${}\|l\K\T{0};{}$\5 +${}\\{skip\_line}\K\\{line};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{get\_next}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\E\\{fi\_or\_else}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|l\E\T{0}){}$\1\5 +\&{goto} \\{done};\2\6 +\&{if} ${}(\\{cur\_chr}\E\\{fi\_code}){}$\1\5 +\\{decr}(\|l);\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}\E\\{if\_test}){}$\1\5 +\\{incr}(\|l);\2\6 +\4${}\}{}$\2\6 +\4\\{done}:\5 +${}\\{scanner\_status}\K\\{save\_scanner\_status};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{495}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\B\4\X495:Push the condition stack\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\par +\U498.\fi + +\M{496}\B\X496:Pop the condition stack\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\par +\Us498, 500, 509\ETs510.\fi + +\M{497}Here's a procedure that changes the \\{if\_limit} code corresponding to +a given value of \\{cond\_ptr}. + +\Y\B\&{void} \\{change\_if\_limit}(\&{small\_number} \|l${},\39{}$\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|q;\7 +\&{if} ${}(\|p\E\\{cond\_ptr}){}$\1\5 +${}\\{if\_limit}\K\|l{}$;\C{that's the easy case}\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{cond\_ptr};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\|q\E\\{null}){}$\1\5 +\\{confusion}(\X1611:\.{"if"}\X);\2\6 +\&{if} ${}(\\{link}(\|q)\E\|p){}$\5 +${}\{{}$\5 +\1${}\\{type}(\|q)\K\|l;{}$\5 +\&{return};\6 +\4${}\}{}$\2\6 +${}\|q\K\\{link}(\|q);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{498}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\B\&{void} \\{conditional}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{bool} \|b;\C{is the condition true?}\6 +\&{uint8\_t} \|r;\C{relation to be evaluated}\6 +\&{int} \|m${},{}$ \|n;\C{to be tested against the second operand}\6 +\&{pointer} \|p${},{}$ \|q;\C{for traversing token lists in \.{\\ifx} tests}\6 +\&{small\_number} \\{save\_scanner\_status};\C{\\{scanner\_status} upon entry}\6 +\&{pointer} \\{save\_cond\_ptr};\C{\\{cond\_ptr} corresponding to this conditional}\6 +\&{small\_number} \\{this\_if};\C{type of this conditional}\7 +\X495:Push the condition stack\X;\5 +${}\\{save\_cond\_ptr}\K\\{cond\_ptr};{}$\5 +${}\\{this\_if}\K\\{cur\_chr}{}$;\6 +\X501:Either process \.{\\ifcase} or set \|b to the value of a boolean condition\X;\6 +\&{if} ${}(\\{tracing\_commands}>\T{1}){}$\1\5 +\X502:Display the value of \|b\X;\2\6 +\&{if} (\|b)\5 +${}\{{}$\5 +\1${}\\{change\_if\_limit}(\\{else\_code},\39\\{save\_cond\_ptr});{}$\5 +\&{return};\C{wait for \.{\\else} or \.{\\fi}}\6 +\4${}\}{}$\2\6 +\X500:Skip to \.{\\else} or \.{\\fi}, then \&{goto} \\{common\_ending}\X;\6 +\4\\{common\_ending}:\6 +\&{if} ${}(\\{cur\_chr}\E\\{fi\_code}){}$\1\5 +\X496:Pop the condition stack\X\2\6 +\&{else}\1\5 +${}\\{if\_limit}\K\\{fi\_code}{}$;\C{wait for \.{\\fi}}\2\6 +\4${}\}{}$\2\par +\fi + +\M{499}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 + +\M{500}\B\X500:Skip to \.{\\else} or \.{\\fi}, then \&{goto} \\{common\_ending}\X${}\E{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{pass\_text}(\,);\6 +\&{if} ${}(\\{cond\_ptr}\E\\{save\_cond\_ptr}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_chr}\I\\{or\_code}){}$\1\5 +\&{goto} \\{common\_ending};\2\6 +\\{print\_err}(\.{"Extra\ "});\5 +\\{print\_esc}(\X1629:\.{"or"}\X);\5 +\\{help1}(\.{"I'm\ ignoring\ this;\ }\)\.{it\ doesn't\ match\ any}\)\.{\ \\\\if."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_chr}\E\\{fi\_code}){}$\1\5 +\X496:Pop the condition stack\X;\2\6 +\4${}\}{}$\2\par +\U498.\fi + +\M{501}\B\X501:Either process \.{\\ifcase} or set \|b to the value of a boolean condition\X${}\E{}$\6 +\&{switch} (\\{this\_if})\5 +${}\{{}$\1\6 +\4\&{case} \\{if\_char\_code}:\5 +\&{case} \\{if\_cat\_code}:\5 +\X506:Test if two characters match\X\5 +\&{break};\6 +\4\&{case} \\{if\_int\_code}:\5 +\&{case} \\{if\_dim\_code}:\5 +\X503:Test relation between integers or dimensions\X\5 +\&{break};\6 +\4\&{case} \\{if\_odd\_code}:\5 +\X504:Test if an integer is odd\X\5 +\&{break};\6 +\4\&{case} \\{if\_vmode\_code}:\5 +${}\|b\K(\\{abs}(\\{mode})\E\\{vmode}){}$;\5 +\&{break};\6 +\4\&{case} \\{if\_hmode\_code}:\5 +${}\|b\K(\\{abs}(\\{mode})\E\\{hmode}){}$;\5 +\&{break};\6 +\4\&{case} \\{if\_mmode\_code}:\5 +${}\|b\K(\\{abs}(\\{mode})\E\\{mmode}){}$;\5 +\&{break};\6 +\4\&{case} \\{if\_inner\_code}:\5 +${}\|b\K(\\{mode}<\T{0}){}$;\5 +\&{break};\6 +\4\&{case} \\{if\_void\_code}:\5 +\&{case} \\{if\_hbox\_code}:\5 +\&{case} \\{if\_vbox\_code}:\5 +\X505:Test box register status\X\5 +\&{break};\6 +\4\&{case} \\{ifx\_code}:\5 +\X507:Test if two tokens match\X\5 +\&{break};\6 +\4\&{case} \\{if\_eof\_code}:\6 +${}\{{}$\5 +\1\\{scan\_four\_bit\_int}(\,);\5 +${}\|b\K(\\{read\_open}[\\{cur\_val}]\E\\{closed});{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{if\_true\_code}:\5 +${}\|b\K\\{true}{}$;\5 +\&{break};\6 +\4\&{case} \\{if\_false\_code}:\5 +${}\|b\K\\{false}{}$;\5 +\&{break};\6 +\4\&{case} \\{if\_case\_code}:\5 +\X509:Select the appropriate case and \&{return} or \&{goto} \\{common\_ending}\X;\6 +\4${}\}{}$\C{there are no other cases}\2\par +\U498.\fi + +\M{502}\B\X502:Display the value of \|b\X${}\E{}$\6 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\6 +\&{if} (\|b)\1\5 +\\{print\_str}(\.{"\{true\}"});\5 +\2\&{else}\1\5 +\\{print\_str}(\.{"\{false\}"});\2\6 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\par +\U498.\fi + +\M{503}Here we use the fact that \.{'<'}, \.{'='}, and \.{'>'} are consecutive ASCII +codes. + +\Y\B\4\X503:Test relation between integers or dimensions\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{this\_if}\E\\{if\_int\_code}){}$\1\5 +\\{scan\_int}(\,);\5 +\2\&{else}\1\5 +\\{scan\_normal\_dimen};\2\6 +${}\|n\K\\{cur\_val};{}$\5 +\X406:Get the next non-blank non-call token\X;\6 +\&{if} ${}((\\{cur\_tok}\G\\{other\_token}+\.{'<'})\W(\\{cur\_tok}\Z\\{other\_token}+\.{'>'})){}$\1\5 +${}\|r\K\\{cur\_tok}-\\{other\_token};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\6 +\&{if} ${}(\\{this\_if}\E\\{if\_int\_code}){}$\1\5 +\\{scan\_int}(\,);\5 +\2\&{else}\1\5 +\\{scan\_normal\_dimen};\2\6 +\&{switch} (\|r)\5 +${}\{{}$\1\6 +\4\&{case} \.{'<'}:\5 +${}\|b\K(\|n<\\{cur\_val}){}$;\5 +\&{break};\6 +\4\&{case} \.{'='}:\5 +${}\|b\K(\|n\E\\{cur\_val}){}$;\5 +\&{break};\6 +\4\&{case} \.{'>'}:\5 +${}\|b\K(\|n>\\{cur\_val});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U501.\fi + +\M{504}\B\X504:Test if an integer is odd\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_int}(\,);\5 +${}\|b\K\\{odd}(\\{cur\_val});{}$\6 +\4${}\}{}$\2\par +\U501.\fi + +\M{505}\B\X505:Test box register status\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\5 +${}\|p\K\\{box}(\\{cur\_val});{}$\6 +\&{if} ${}(\\{this\_if}\E\\{if\_void\_code}){}$\1\5 +${}\|b\K(\|p\E\\{null});{}$\2\6 +\&{else} \&{if} ${}(\|p\E\\{null}){}$\1\5 +${}\|b\K\\{false};{}$\2\6 +\&{else} \&{if} ${}(\\{this\_if}\E\\{if\_hbox\_code}){}$\1\5 +${}\|b\K(\\{type}(\|p)\E\\{hlist\_node});{}$\2\6 +\&{else}\1\5 +${}\|b\K(\\{type}(\|p)\E\\{vlist\_node});{}$\2\6 +\4${}\}{}$\2\par +\U501.\fi + +\M{506}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\B\4\D$\\{get\_x\_token\_or\_active\_char}$ \5 +\hbox{}\6 +${}\{{}$\5 +\1\\{get\_x\_token}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\E\\{relax}){}$\1\6 +\&{if} ${}(\\{cur\_chr}\E\\{no\_expand\_flag}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_cmd}\K\\{active\_char};{}$\5 +${}\\{cur\_chr}\K\\{cur\_tok}-\\{cs\_token\_flag}-\\{active\_base};{}$\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\par +\Y\B\4\X506:Test if two characters match\X${}\E{}$\6 +${}\{{}$\5 +\1\\{get\_x\_token\_or\_active\_char};\6 +\&{if} ${}((\\{cur\_cmd}>\\{active\_char})\V(\\{cur\_chr}>\T{255}){}$)\C{not a character}\6 +${}\{{}$\5 +\1${}\|m\K\\{relax};{}$\5 +${}\|n\K\T{256};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|m\K\\{cur\_cmd};{}$\5 +${}\|n\K\\{cur\_chr};{}$\6 +\4${}\}{}$\2\6 +\\{get\_x\_token\_or\_active\_char};\6 +\&{if} ${}((\\{cur\_cmd}>\\{active\_char})\V(\\{cur\_chr}>\T{255})){}$\5 +${}\{{}$\5 +\1${}\\{cur\_cmd}\K\\{relax};{}$\5 +${}\\{cur\_chr}\K\T{256};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{this\_if}\E\\{if\_char\_code}){}$\1\5 +${}\|b\K(\|n\E\\{cur\_chr}){}$;\5 +\2\&{else}\1\5 +${}\|b\K(\|m\E\\{cur\_cmd});{}$\2\6 +\4${}\}{}$\2\par +\U501.\fi + +\M{507}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\B\4\X507:Test if two tokens match\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{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\5 +${}\|b\K\\{false};{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}<\\{call}){}$\1\5 +${}\|b\K(\\{cur\_chr}\E\|q);{}$\2\6 +\&{else}\1\5 +\X508:Test if two macro texts match\X;\2\6 +${}\\{scanner\_status}\K\\{save\_scanner\_status};{}$\6 +\4${}\}{}$\2\par +\U501.\fi + +\M{508}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\B\4\X508:Test if two macro texts match\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|p\K\\{link}(\\{cur\_chr});{}$\5 +${}\|q\K\\{link}(\\{equiv}(\|n)){}$;\C{omit reference counts}\6 +\&{if} ${}(\|p\E\|q){}$\1\5 +${}\|b\K\\{true};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{while} ${}((\|p\I\\{null})\W(\|q\I\\{null})){}$\1\6 +\&{if} ${}(\\{info}(\|p)\I\\{info}(\|q)){}$\1\5 +${}\|p\K\\{null};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|p\K\\{link}(\|p);{}$\5 +${}\|q\K\\{link}(\|q);{}$\6 +\4${}\}{}$\2\2\6 +${}\|b\K((\|p\E\\{null})\W(\|q\E\\{null}));{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U507.\fi + +\M{509}\B\X509:Select the appropriate case and \&{return} or \&{goto} \\{common\_ending}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_int}(\,);\5 +${}\|n\K\\{cur\_val}{}$;\C{\|n is the number of cases to pass}\6 +\&{if} ${}(\\{tracing\_commands}>\T{1}){}$\5 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_str}(\.{"\{case\ "});\5 +\\{print\_int}(\|n);\5 +\\{print\_char}(\.{'\}'});\5 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\6 +\&{while} ${}(\|n\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{pass\_text}(\,);\6 +\&{if} ${}(\\{cond\_ptr}\E\\{save\_cond\_ptr}){}$\1\6 +\&{if} ${}(\\{cur\_chr}\E\\{or\_code}){}$\1\5 +\\{decr}(\|n);\2\6 +\&{else}\1\5 +\&{goto} \\{common\_ending};\2\2\6 +\&{else} \&{if} ${}(\\{cur\_chr}\E\\{fi\_code}){}$\1\5 +\X496:Pop the condition stack\X;\2\6 +\4${}\}{}$\2\6 +${}\\{change\_if\_limit}(\\{or\_code},\39\\{save\_cond\_ptr});{}$\5 +\&{return};\C{wait for \.{\\or}, \.{\\else}, or \.{\\fi}}\6 +\4${}\}{}$\2\par +\U501.\fi + +\M{510}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\B\4\X510:Terminate the current conditional and skip to \.{\\fi}\X${}\E{}$\6 +\&{if} ${}(\\{cur\_chr}>\\{if\_limit}){}$\1\6 +\&{if} ${}(\\{if\_limit}\E\\{if\_code}){}$\1\5 +\\{insert\_relax}(\,);\C{condition not yet evaluated}\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{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."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{while} ${}(\\{cur\_chr}\I\\{fi\_code}){}$\1\5 +\\{pass\_text}(\,);\C{skip to \.{\\fi}}\2\6 +\X496:Pop the condition stack\X;\6 +\4${}\}{}$\2\par +\U367.\fi + +\N{1}{511}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 + +\M{512}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., +\\{empty\_string}), 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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{str\_number} \\{cur\_name};\C{name of file just scanned}\6 +\&{str\_number} \\{cur\_area};\C{file area just scanned, or \.{""}}\6 +\&{str\_number} \\{cur\_ext};\C{file extension just scanned, or \.{""}}\par +\fi + +\M{513}The file names we shall deal with for illustrative purposes have the +following structure: If the name contains `\.>' or `\.:', 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 first +remaining `\..' 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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pool\_pointer} \\{area\_delimiter};\C{the most recent `\.>' or `\.:', if any}\6 +\&{pool\_pointer} \\{ext\_delimiter};\C{the relevant `\..', if any}\par +\fi + +\M{514}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. + +\fi + +\M{515}Here now is the first of the system-dependent routines for file name scanning. + +\Y\B\&{void} \\{begin\_name}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{area\_delimiter}\K\T{0};{}$\5 +${}\\{ext\_delimiter}\K\T{0};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{516}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\B\&{bool} \\{more\_name}(\&{ASCII\_code} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\|c\E\.{'\ '}){}$\1\5 +\&{return} \\{false};\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{str\_room}(\T{1});\5 +\\{append\_char}(\|c);\C{contribute \|c to the current string}\6 +\&{if} ${}((\|c\E\.{'>'})\V(\|c\E\.{':'})){}$\5 +${}\{{}$\5 +\1${}\\{area\_delimiter}\K\\{cur\_length};{}$\5 +${}\\{ext\_delimiter}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}((\|c\E\.{'.'})\W(\\{ext\_delimiter}\E\T{0})){}$\1\5 +${}\\{ext\_delimiter}\K\\{cur\_length};{}$\2\6 +\&{return} \\{true};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{517}The third. + +\Y\B\&{void} \\{end\_name}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{str\_ptr}+\T{3}>\\{max\_strings}){}$\1\5 +${}\\{overflow}(\.{"number\ of\ strings"},\39\\{max\_strings}-\\{init\_str\_ptr});{}$\2\6 +\&{if} ${}(\\{area\_delimiter}\E\T{0}){}$\1\5 +${}\\{cur\_area}\K\\{empty\_string};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_area}\K\\{str\_ptr};{}$\5 +${}\\{str\_start}[\\{str\_ptr}+\T{1}]\K\\{str\_start}[\\{str\_ptr}]+\\{area\_delimiter};{}$\5 +\\{incr}(\\{str\_ptr});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{ext\_delimiter}\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_ext}\K\\{empty\_string};{}$\5 +${}\\{cur\_name}\K\\{make\_string}(\,);{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_name}\K\\{str\_ptr};{}$\5 +${}\\{str\_start}[\\{str\_ptr}+\T{1}]\K\\{str\_start}[\\{str\_ptr}]+\\{ext\_delimiter}-\\{area\_delimiter}-\T{1};{}$\5 +\\{incr}(\\{str\_ptr});\5 +${}\\{cur\_ext}\K\\{make\_string}(\,);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{518}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\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_file\_name}(\&{int} \|n${},\39{}$\&{int} \|a${},\39{}$\&{int} \|e)\1\1\2\2\6 +${}\{{}$\5 +\1\\{slow\_print}(\|a);\5 +\\{slow\_print}(\|n);\5 +\\{slow\_print}(\|e);\6 +\4${}\}{}$\2\par +\fi + +\M{519}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\B\4\D$\\{append\_to\_name}(\|X)$ \6 +${}\{{}$\5 +\1${}\|c\K\|X;{}$\5 +\\{incr}(\|k);\6 +\&{if} ${}(\|k\Z\\{file\_name\_size}){}$\1\5 +${}\\{name\_of\_file}[\|k]\K\\{xchr}[\|c];{}$\2\6 +\4${}\}{}$\2\par +\Y\B\&{void} \\{pack\_file\_name}(\&{str\_number} \|n${},\39{}$\&{str\_number} \|a${},\39{}$\&{str\_number} \|e)\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|k;\C{number of positions filled in \\{name\_of\_file}}\6 +\&{ASCII\_code} \|c;\C{character being packed}\6 +\&{int} \|j;\C{index into \\{str\_pool}}\7 +${}\|k\K\T{0};{}$\6 +\&{for} ${}(\|j\K\\{str\_start}[\|a];{}$ ${}\|j\Z\\{str\_start}[\|a+\T{1}]-\T{1};{}$ ${}\|j\PP){}$\1\5 +\\{append\_to\_name}(\\{so}(\\{str\_pool}[\|j]));\2\6 +\&{for} ${}(\|j\K\\{str\_start}[\|n];{}$ ${}\|j\Z\\{str\_start}[\|n+\T{1}]-\T{1};{}$ ${}\|j\PP){}$\1\5 +\\{append\_to\_name}(\\{so}(\\{str\_pool}[\|j]));\2\6 +\&{for} ${}(\|j\K\\{str\_start}[\|e];{}$ ${}\|j\Z\\{str\_start}[\|e+\T{1}]-\T{1};{}$ ${}\|j\PP){}$\1\5 +\\{append\_to\_name}(\\{so}(\\{str\_pool}[\|j]));\2\6 +\&{if} ${}(\|k\Z\\{file\_name\_size}){}$\1\5 +${}\\{name\_length}\K\|k{}$;\5 +\2\&{else}\1\5 +${}\\{name\_length}\K\\{file\_name\_size};{}$\2\6 +${}\\{name\_of\_file}[\\{name\_length}+\T{1}]\K\T{0};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{520}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. + +\Y\B\4\D$\\{format\_default\_length}$ \5 +\T{20}\C{length of the \\{TEX\_format\_default} string}\par +\B\4\D$\\{format\_area\_length}$ \5 +\T{11}\C{length of its area part}\par +\B\4\D$\\{format\_ext\_length}$ \5 +\T{4}\C{length of its `\.{.fmt}' part}\par +\B\4\D$\\{format\_extension\_str}$ \5 +\.{".fmt"}\C{the extension, as a \.{WEB} constant}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{ASCII\_code} ${}\\{TEX\_format\_default}[\T{1}+\\{format\_default\_length}+\T{1}]\K\.{"\ TeXformats/plain.f}\)\.{mt"}{}$;\par +\fi + +\M{521}\B\X14:Check the ``constant'' values for consistency\X${}\mathrel+\E{}$\6 +\&{if} ${}(\\{format\_default\_length}>\\{file\_name\_size}){}$\1\5 +${}\\{bad}\K\T{31}{}$;\2\par +\fi + +\M{522}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\dotdot\|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\B\&{void} \\{pack\_buffered\_name}(\&{small\_number} \|n${},\39{}$\&{int} \|a${},\39{}$\&{int} \|b)\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|k;\C{number of positions filled in \\{name\_of\_file}}\6 +\&{ASCII\_code} \|c;\C{character being packed}\6 +\&{int} \|j;\C{index into \\{buffer} or \\{TEX\_format\_default}}\7 +\&{if} ${}(\|n+\|b-\|a+\T{1}+\\{format\_ext\_length}>\\{file\_name\_size}){}$\1\5 +${}\|b\K\|a+\\{file\_name\_size}-\|n-\T{1}-\\{format\_ext\_length};{}$\2\6 +${}\|k\K\T{0};{}$\6 +\&{for} ${}(\|j\K\T{1};{}$ ${}\|j\Z\|n;{}$ ${}\|j\PP){}$\1\5 +\\{append\_to\_name}(\\{xord}[\\{TEX\_format\_default}[\|j]]);\2\6 +\&{for} ${}(\|j\K\|a;{}$ ${}\|j\Z\|b;{}$ ${}\|j\PP){}$\1\5 +\\{append\_to\_name}(\\{buffer}[\|j]);\2\6 +\&{for} ${}(\|j\K\\{format\_default\_length}-\\{format\_ext\_length}+\T{1};{}$ ${}\|j\Z\\{format\_default\_length};{}$ ${}\|j\PP){}$\1\5 +\\{append\_to\_name}(\\{xord}[\\{TEX\_format\_default}[\|j]]);\2\6 +\&{if} ${}(\|k\Z\\{file\_name\_size}){}$\1\5 +${}\\{name\_length}\K\|k{}$;\5 +\2\&{else}\1\5 +${}\\{name\_length}\K\\{file\_name\_size};{}$\2\6 +${}\\{name\_of\_file}[\\{name\_length}+\T{1}]\K\T{0};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{523}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}\dotdot(\\{last}-\T{1})]$, where +$\\{loc}<\\{last}$ and $\\{buffer}[\\{loc}]\I\.{'\ '}$. + +\Y\B\4\X523:Declare the function called \\{open\_fmt\_file}\X${}\E{}$\6 +\&{bool} \\{open\_fmt\_file}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint16\_t} \|j;\C{the first space after the format file name}\7 +${}\|j\K\\{loc};{}$\6 +\&{if} ${}(\\{buffer}[\\{loc}]\E\.{'\&'}){}$\5 +${}\{{}$\5 +\1\\{incr}(\\{loc});\5 +${}\|j\K\\{loc};{}$\5 +${}\\{buffer}[\\{last}]\K\.{'\ '};{}$\6 +\&{while} ${}(\\{buffer}[\|j]\I\.{'\ '}){}$\1\5 +\\{incr}(\|j);\2\6 +${}\\{pack\_buffered\_name}(\T{0},\39\\{loc},\39\|j-\T{1}){}$;\C{try first without the system file area}\6 +\&{if} ${}(\\{w\_open\_in}({\AND}\\{fmt\_file})){}$\1\5 +\&{goto} \\{found};\2\6 +${}\\{pack\_buffered\_name}(\\{format\_area\_length},\39\\{loc},\39\|j-\T{1}){}$;\C{now try the system format file area}\6 +\&{if} ${}(\\{w\_open\_in}({\AND}\\{fmt\_file})){}$\1\5 +\&{goto} \\{found};\2\6 +\\{wake\_up\_terminal};\5 +\\{wterm\_ln}(\.{"Sorry,\ I\ can't\ find}\)\.{\ that\ format;\ will\ t}\)\.{ry\ PLAIN."});\5 +\\{update\_terminal};\6 +\4${}\}{}$\C{now pull out all the stops: try for the system \.{plain} file}\2\6 +${}\\{pack\_buffered\_name}(\\{format\_default\_length}-\\{format\_ext\_length},\39\T{1},\39\T{0});{}$\6 +\&{if} ${}(\R\\{w\_open\_in}({\AND}\\{fmt\_file})){}$\5 +${}\{{}$\5 +\1\\{wake\_up\_terminal};\5 +\\{wterm\_ln}(\.{"I\ can't\ find\ the\ PL}\)\.{AIN\ format\ file!"});\5 +\&{return} \\{false};\6 +\4${}\}{}$\2\6 +\4\\{found}:\5 +${}\\{loc}\K\|j;{}$\5 +\&{return} \\{true};\6 +\4${}\}{}$\2\par +\U1303.\fi + +\M{524}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\B\&{str\_number} \\{make\_name\_string}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|k;\C{index into \\{name\_of\_file}}\7 +\&{if} ${}((\\{pool\_ptr}+\\{name\_length}>\\{pool\_size})\V(\\{str\_ptr}\E\\{max\_strings})\V(\\{cur\_length}>\T{0})){}$\1\5 +\&{return} \.{'?'};\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{for} ${}(\|k\K\T{1};{}$ ${}\|k\Z\\{name\_length};{}$ ${}\|k\PP){}$\1\5 +\\{append\_char}(\\{xord}[\\{name\_of\_file}[\|k]]);\2\6 +\&{return} \\{make\_string}(\,);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\7 +\&{str\_number} \\{a\_make\_name\_string}(\&{alpha\_file} ${}{*}\|f){}$\1\1\2\2\6 +${}\{{}$\5 +\1\&{return} \\{make\_name\_string}(\,);\6 +\4${}\}{}$\2\7 +\&{str\_number} \\{b\_make\_name\_string}(\&{byte\_file} ${}{*}\|f){}$\1\1\2\2\6 +${}\{{}$\5 +\1\&{return} \\{make\_name\_string}(\,);\6 +\4${}\}{}$\2\7 +\&{str\_number} \\{w\_make\_name\_string}(\&{word\_file} ${}{*}\|f){}$\1\1\2\2\6 +${}\{{}$\5 +\1\&{return} \\{make\_name\_string}(\,);\6 +\4${}\}{}$\2\par +\fi + +\M{525}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\B\&{void} \\{scan\_file\_name}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{name\_in\_progress}\K\\{true};{}$\5 +\\{begin\_name}(\,);\5 +\X406:Get the next non-blank non-call token\X;\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}((\\{cur\_cmd}>\\{other\_char})\V(\\{cur\_chr}>\T{255}){}$)\C{not a character}\6 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\R\\{more\_name}(\\{cur\_chr})){}$\1\5 +\&{goto} \\{done};\2\6 +\\{get\_x\_token}(\,);\6 +\4${}\}{}$\2\6 +\4\\{done}:\5 +\\{end\_name}(\,);\5 +${}\\{name\_in\_progress}\K\\{false};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{526}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{bool} \\{name\_in\_progress};\C{is a file name being scanned?}\6 +\&{str\_number} \\{job\_name};\C{principal file name}\6 +\&{bool} \\{log\_opened};\C{has the transcript file been opened?}\par +\fi + +\M{527}Initially $\\{job\_name}\E\T{0}$; it becomes nonzero as soon as the true name is known. +We have $\\{job\_name}\E\T{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\B\4\X55:Initialize the output routines\X${}\mathrel+\E{}$\6 +$\\{job\_name}\K\T{0};{}$\5 +${}\\{name\_in\_progress}\K\\{false};{}$\5 +${}\\{log\_opened}\K\\{false}{}$;\par +\fi + +\M{528}Here is a routine that manufactures the output file names, assuming that +$\\{job\_name}\I\T{0}$. It ignores and changes the current settings of \\{cur\_area} +and \\{cur\_ext}. + +\Y\B\4\D$\\{pack\_cur\_name}$ \5 +$\\{pack\_file\_name}(\\{cur\_name},\39\\{cur\_area},\39\\{cur\_ext}{}$)\par +\Y\B\&{void} \\{pack\_job\_name}(\&{str\_number} \|s)\C{$\|s\E\X1634:\.{".log"}\X$, $\X1635:\.{".dvi"}\X$, or \\{format\_extension}}\6 +${}\{{}$\5 +\1${}\\{cur\_area}\K\\{empty\_string};{}$\5 +${}\\{cur\_ext}\K\|s;{}$\5 +${}\\{cur\_name}\K\\{job\_name};{}$\5 +\\{pack\_cur\_name};\6 +\4${}\}{}$\2\par +\fi + +\M{529}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\B\&{void} \\{prompt\_file\_name}(\&{char} ${}{*}\|s,\39{}$\&{str\_number} \|e)\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint16\_t} \|k;\C{index into \\{buffer}}\7 +\&{if} ${}(\\{interaction}\E\\{scroll\_mode}){}$\1\5 +\\{wake\_up\_terminal};\2\6 +\&{if} ${}(\\{strcmp}(\|s,\39\.{"input\ file\ name"})\E\T{0}){}$\1\5 +\\{print\_err}(\.{"I\ can't\ find\ file\ `}\)\.{"})\2\6 +\&{else}\1\5 +\\{print\_err}(\.{"I\ can't\ write\ on\ fi}\)\.{le\ `"});\2\6 +${}\\{print\_file\_name}(\\{cur\_name},\39\\{cur\_area},\39\\{cur\_ext});{}$\5 +\\{print\_str}(\.{"'."});\6 +\&{if} ${}(\|e\E\X1637:\.{".tex"}\X){}$\1\5 +\\{show\_context}(\,);\2\6 +\\{print\_nl}(\.{"Please\ type\ another}\)\.{\ "});\5 +\\{print\_str}(\|s);\6 +\&{if} ${}(\\{interaction}<\\{scroll\_mode}){}$\1\5 +\\{fatal\_error}(\.{"***\ (job\ aborted,\ f}\)\.{ile\ error\ in\ nonstop}\)\.{\ mode)"});\2\6 +\\{clear\_terminal};\5 +\\{prompt\_input}(\.{":\ "});\5 +\X530:Scan file name in the buffer\X;\6 +\&{if} ${}(\\{cur\_ext}\E\\{empty\_string}){}$\1\5 +${}\\{cur\_ext}\K\|e;{}$\2\6 +\\{pack\_cur\_name};\6 +\4${}\}{}$\2\par +\fi + +\M{530}\B\X530:Scan file name in the buffer\X${}\E{}$\6 +${}\{{}$\5 +\1\\{begin\_name}(\,);\5 +${}\|k\K\\{first};{}$\6 +\&{while} ${}((\\{buffer}[\|k]\E\.{'\ '})\W(\|k<\\{last})){}$\1\5 +\\{incr}(\|k);\2\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\|k\E\\{last}){}$\1\5 +\&{goto} \\{done};\2\6 +\&{if} ${}(\R\\{more\_name}(\\{buffer}[\|k])){}$\1\5 +\&{goto} \\{done};\2\6 +\\{incr}(\|k);\6 +\4${}\}{}$\2\6 +\4\\{done}:\5 +\\{end\_name}(\,);\6 +\4${}\}{}$\2\par +\U529.\fi + +\M{531}Here's an example of how these conventions are used. Whenever it is time to +ship out a box of stuff, we shall use $\X531:ensure dvi open\X$. + +\Y\B\4\X531:ensure dvi open\X${}\E{}$\6 +\&{if} ${}(\\{output\_file\_name}\E\T{0}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{job\_name}\E\T{0}){}$\1\5 +\\{open\_log\_file}(\,);\2\6 +\\{pack\_job\_name}(\X1635:\.{".dvi"}\X);\6 +\&{while} ${}(\R\\{b\_open\_out}({\AND}\\{dvi\_file})){}$\1\5 +${}\\{prompt\_file\_name}(\.{"file\ name\ for\ outpu}\)\.{t"},\39\X1635:\.{".dvi"}\X);{}$\2\6 +${}\\{output\_file\_name}\K\\{b\_make\_name\_string}({\AND}\\{dvi\_file});{}$\6 +\4${}\}{}$\2\par +\Q531. +\U617.\fi + +\M{532}\B\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{byte\_file} \\{dvi\_file};\C{the device-independent output goes here}\6 +\&{str\_number} \\{output\_file\_name};\C{full name of the output file}\6 +\&{str\_number} \\{log\_name};\C{full name of the log file}\par +\fi + +\M{533}\B\X55:Initialize the output routines\X${}\mathrel+\E{}$\6 +$\\{output\_file\_name}\K\T{0}{}$;\par +\fi + +\M{534}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\B\&{void} \\{open\_log\_file}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \\{old\_setting};\C{previous \\{selector} setting}\6 +\&{int} \|k;\C{index into \\{months} and \\{buffer}}\6 +\&{uint16\_t} \|l;\C{end of first input line}\6 +\&{ASCII\_code} \\{months}[\,]${}\K\.{"\ JANFEBMARAPRMAYJUN}\)\.{JULAUGSEPOCTNOVDEC"}{}$;\C{abbreviations of month names}\7 +${}\\{old\_setting}\K\\{selector};{}$\6 +\&{if} ${}(\\{job\_name}\E\T{0}){}$\1\5 +${}\\{job\_name}\K\X1638:\.{"texput"}\X;{}$\2\6 +\\{pack\_job\_name}(\X1634:\.{".log"}\X);\6 +\&{while} ${}(\R\\{a\_open\_out}({\AND}\\{log\_file})){}$\1\5 +\X535:Try to get a different log file name\X;\2\6 +${}\\{log\_name}\K\\{a\_make\_name\_string}({\AND}\\{log\_file});{}$\5 +${}\\{selector}\K\\{log\_only};{}$\5 +${}\\{log\_opened}\K\\{true};{}$\5 +\X536:Print the banner line, including the date and time\X;\6 +${}\\{input\_stack}[\\{input\_ptr}]\K\\{cur\_input}{}$;\C{make sure bottom level is in memory}\6 +\\{print\_nl}(\.{"**"});\5 +${}\|l\K\\{input\_stack}[\T{0}].\\{limit\_field}{}$;\C{last position of first line}\6 +\&{if} ${}(\\{buffer}[\|l]\E\\{end\_line\_char}){}$\1\5 +\\{decr}(\|l);\2\6 +\&{for} ${}(\|k\K\T{1};{}$ ${}\|k\Z\|l;{}$ ${}\|k\PP){}$\1\5 +\\{print}(\\{buffer}[\|k]);\2\6 +\\{print\_ln}(\,);\C{now the transcript file contains the first line of input}\6 +${}\\{selector}\K\\{old\_setting}+\T{2}{}$;\C{\\{log\_only} or \\{term\_and\_log}}\6 +\4${}\}{}$\2\par +\fi + +\M{535}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\B\4\X535:Try to get a different log file name\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{selector}\K\\{term\_only};{}$\5 +${}\\{prompt\_file\_name}(\.{"transcript\ file\ nam}\)\.{e"},\39\X1634:\.{".log"}\X);{}$\6 +\4${}\}{}$\2\par +\U534.\fi + +\M{536}\B\X536:Print the banner line, including the date and time\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{wlog}(\.{"\%s"},\39\\{banner});{}$\5 +\\{slow\_print}(\\{format\_ident});\5 +\\{print\_str}(\.{"\ \ "});\5 +\\{print\_int}(\\{day});\5 +\\{print\_char}(\.{'\ '});\6 +\&{for} ${}(\|k\K\T{3}*\\{month}-\T{2};{}$ ${}\|k\Z\T{3}*\\{month};{}$ ${}\|k\PP){}$\1\5 +${}\\{wlog}(\.{"\%c"},\39\\{months}[\|k]);{}$\2\6 +\\{print\_char}(\.{'\ '});\5 +\\{print\_int}(\\{year});\5 +\\{print\_char}(\.{'\ '});\5 +${}\\{print\_two}(\\{time}/\T{60});{}$\5 +\\{print\_char}(\.{':'});\5 +${}\\{print\_two}(\\{time}\MOD\T{60});{}$\6 +\4${}\}{}$\2\par +\U534.\fi + +\M{537}Let's turn now to the procedure that is used to initiate file reading +when an `\.{\\input}' command is being processed. + +\Y\B\&{void} \\{start\_input}(\&{void})\C{\TeX\ will \.{\\input} something}\6 +${}\{{}$\5 +\1\\{scan\_file\_name}(\,);\C{set \\{cur\_name} to desired file name}\6 +\&{if} ${}(\\{cur\_ext}\E\\{empty\_string}){}$\1\5 +${}\\{cur\_ext}\K\X1637:\.{".tex"}\X;{}$\2\6 +\\{pack\_cur\_name};\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{begin\_file\_reading}(\,);\C{set up \\{cur\_file} and new level of input}\6 +\&{if} ${}(\\{a\_open\_in}({\AND}\\{cur\_file})){}$\1\5 +\&{goto} \\{done};\2\6 +\&{if} ${}(\\{cur\_area}\E\\{empty\_string}){}$\5 +${}\{{}$\5 +\1${}\\{pack\_file\_name}(\\{cur\_name},\39\\{TEX\_area},\39\\{cur\_ext});{}$\6 +\&{if} ${}(\\{a\_open\_in}({\AND}\\{cur\_file})){}$\1\5 +\&{goto} \\{done};\2\6 +\4${}\}{}$\2\6 +\\{end\_file\_reading}(\,);\C{remove the level that didn't work}\6 +${}\\{prompt\_file\_name}(\.{"input\ file\ name"},\39\X1637:\.{".tex"}\X);{}$\6 +\4${}\}{}$\2\6 +\4\\{done}:\5 +${}\\{name}\K\\{a\_make\_name\_string}({\AND}\\{cur\_file});{}$\6 +\&{if} ${}(\\{job\_name}\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{job\_name}\K\\{cur\_name};{}$\5 +\\{open\_log\_file}(\,);\6 +\4${}\}{}$\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}(\\{name})>\\{max\_print\_line}-\T{2}){}$\1\5 +\\{print\_ln}(\,);\2\6 +\&{else} \&{if} ${}((\\{term\_offset}>\T{0})\V(\\{file\_offset}>\T{0})){}$\1\5 +\\{print\_char}(\.{'\ '});\2\6 +\\{print\_char}(\.{'('});\5 +\\{incr}(\\{open\_parens});\5 +\\{slow\_print}(\\{name});\5 +\\{update\_terminal};\5 +${}\\{state}\K\\{new\_line};{}$\6 +\&{if} ${}(\\{name}\E\\{str\_ptr}-\T{1}{}$)\C{we can conserve string pool space now}\6 +${}\{{}$\5 +\1\\{flush\_string};\5 +${}\\{name}\K\\{cur\_name};{}$\6 +\4${}\}{}$\2\6 +\X538:Read the first line of the new file\X;\6 +\4${}\}{}$\2\par +\fi + +\M{538}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\B\4\X538:Read the first line of the new file\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{line}\K\T{1};{}$\6 +\&{if} ${}(\\{input\_ln}({\AND}\\{cur\_file},\39\\{false})){}$\1\5 +\\{do\_nothing};\2\6 +\\{firm\_up\_the\_line}(\,);\6 +\&{if} (\\{end\_line\_char\_inactive})\1\5 +\\{decr}(\\{limit});\2\6 +\&{else}\1\5 +${}\\{buffer}[\\{limit}]\K\\{end\_line\_char};{}$\2\6 +${}\\{first}\K\\{limit}+\T{1};{}$\5 +${}\\{loc}\K\\{start};{}$\6 +\4${}\}{}$\2\par +\U537.\fi + +\N{1}{539}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{byte\_file} \\{tfm\_file};\par +\fi + +\M{540}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}-\T{1}\Z\\{ec}\Z\T{255}$, +and +$$\hbox{$\\{lf}\E\T{6}+\\{lh}+(\\{ec}-\\{bc}+\T{1})+\\{nw}+\\{nh}+\\{nd}+\\{ni}+\\{nl}+\\{nk}+\\{ne}+\\{np}$.}$$ +Note that a font may contain as many as 256 characters (if $\\{bc}\E\T{0}$ and $\\{ec}\E\T{255}$), +and as few as 0 characters (if $\\{bc}\E\\{ec}+\T{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. + +\fi + +\M{541}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} +\def\PB#1{\arr#1} +\vbox{\halign{\hfil\\{#}&$\,:\,$#\hfil\cr +header&$[\T{0}\dotdot\\{lh}-\T{1}]\hbox{\\{stuff}}$\cr +char\_info&$[\\{bc}\dotdot\\{ec}]\\{char\_info\_word}$\cr +width&$[\T{0}\dotdot\\{nw}-\T{1}]\\{fix\_word}$\cr +height&$[\T{0}\dotdot\\{nh}-\T{1}]\\{fix\_word}$\cr +depth&$[\T{0}\dotdot\\{nd}-\T{1}]\\{fix\_word}$\cr +italic&$[\T{0}\dotdot\\{ni}-\T{1}]\\{fix\_word}$\cr +lig\_kern&$[\T{0}\dotdot\\{nl}-\T{1}]\\{lig\_kern\_command}$\cr +kern&$[\T{0}\dotdot\\{nk}-\T{1}]\\{fix\_word}$\cr +exten&$[\T{0}\dotdot\\{ne}-\T{1}]\\{extensible\_recipe}$\cr +param&$[\T{1}\dotdot\\{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 + +\M{542}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}[\T{0}] and \\{header}[\T{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}[\T{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}[\T{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}[\T{1}] (which denotes the slant ratio). Thus, for example, the value +of \\{param}[\T{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}[\T{1}] and \\{param}[\T{1}] are the only \\{fix\_word} +entries in the whole \.{TFM} file whose first byte might be something +besides 0 or 255. + +\fi + +\M{543}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: \\{rem} (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 + +\M{544}The \\{tag} field in a \\{char\_info\_word} has four values that explain how to +interpret the \\{rem} field. + +\yskip\hangg$\\{tag}\E\T{0}$ (\\{no\_tag}) means that \\{rem} is unused.\par +\hangg$\\{tag}\E\T{1}$ (\\{lig\_tag}) means that this character has a ligature/kerning +program starting at position \\{rem} in the \\{lig\_kern} array.\par +\hangg$\\{tag}\E\T{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 +\\{rem} field gives the character code of the next larger character.\par +\hangg$\\{tag}\E\T{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}[\\{rem}].\par +\yskip\noindent +Characters with $\\{tag}\E\T{2}$ and $\\{tag}\E\T{3}$ are treated as characters with $\\{tag}\E\T{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}. + +\Y\B\4\D$\\{no\_tag}$ \5 +\T{0}\C{vanilla character}\par +\B\4\D$\\{lig\_tag}$ \5 +\T{1}\C{character has a ligature/kerning program}\par +\B\4\D$\\{list\_tag}$ \5 +\T{2}\C{character has a successor in a charlist}\par +\B\4\D$\\{ext\_tag}$ \5 +\T{3}\C{character is extensible}\par +\fi + +\M{545}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: \\{rem}.\par +\yskip\noindent +In a kern step, an +additional space equal to $\\{kern}[\T{256}*(\\{op\_byte}-\T{128})+\\{rem}]$ 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 +\\{rem} 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}\E\T{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}\E\T{255}$, +there is a special ligature/kerning program for a left boundary character, +beginning at location $\T{256}*\\{op\_byte}+\\{rem}$. +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}>\T{128}$, the program actually begins in location +$\T{256}*\\{op\_byte}+\\{rem}$. This feature allows access to large \\{lig\_kern} +arrays, because the first instruction must otherwise +appear in a location $\Z$ \T{255}. + +Any instruction with $\\{skip\_byte}>\T{128}$ in the \\{lig\_kern} array must satisfy +the condition +$$\hbox{$\T{256}*\\{op\_byte}+\\{rem}<\\{nl}$.}$$ +If such an instruction is encountered during +normal program execution, it denotes an unconditional halt; no ligature +or kerning command is performed. + +\Y\B\4\D$\\{stop\_flag}$ \5 +\\{qi}(\T{128})\C{value indicating `\.{STOP}' in a lig/kern program}\par +\B\4\D$\\{kern\_flag}$ \5 +\\{qi}(\T{128})\C{op code for a kern step}\par +\B\4\D$\\{skip\_byte}(\|X)$ \5 +$\|X.{}$\\{b0}\par +\B\4\D$\\{next\_char}(\|X)$ \5 +$\|X.{}$\\{b1}\par +\B\4\D$\\{op\_byte}(\|X)$ \5 +$\|X.{}$\\{b2}\par +\B\4\D$\\{rem\_byte}(\|X)$ \5 +$\|X.{}$\\{b3}\par +\fi + +\M{546}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\G\T{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. + +\Y\B\4\D$\\{ext\_top}(\|X)$ \5 +$\|X.{}$\\{b0}\C{\\{top} piece in a recipe}\par +\B\4\D$\\{ext\_mid}(\|X)$ \5 +$\|X.{}$\\{b1}\C{\\{mid} piece in a recipe}\par +\B\4\D$\\{ext\_bot}(\|X)$ \5 +$\|X.{}$\\{b2}\C{\\{bot} piece in a recipe}\par +\B\4\D$\\{ext\_rep}(\|X)$ \5 +$\|X.{}$\\{b3}\C{\\{rep} piece in a recipe}\par +\fi + +\M{547}The final portion of a \.{TFM} file is the \\{param} array, which is another +sequence of \\{fix\_word} values. + +\yskip\hang$\\{param}[\T{1}]\E\\{slant}$ is the amount of italic slant, which is used +to help position accents. For example, $\\{slant}\E\T{.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}[\T{2}]\E\\{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}[\T{3}]\E\\{space\_stretch}$ is the amount of glue stretching between words. + +\hang$\\{param}[\T{4}]\E\\{space\_shrink}$ is the amount of glue shrinking between words. + +\hang$\\{param}[\T{5}]\E\\{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}[\T{6}]\E\\{quad}$ is the size of one em in the font. + +\hang$\\{param}[\T{7}]\E\\{extra\_space}$ is the amount added to \\{param}[\T{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\B\4\D$\\{slant\_code}$ \5 +\T{1}\par +\B\4\D$\\{space\_code}$ \5 +\T{2}\par +\B\4\D$\\{space\_stretch\_code}$ \5 +\T{3}\par +\B\4\D$\\{space\_shrink\_code}$ \5 +\T{4}\par +\B\4\D$\\{x\_height\_code}$ \5 +\T{5}\par +\B\4\D$\\{quad\_code}$ \5 +\T{6}\par +\B\4\D$\\{extra\_space\_code}$ \5 +\T{7}\par +\fi + +\M{548}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\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{uint8\_t} \&{internal\_font\_number};\C{\\{font} in a \\{char\_node}}\6 +\&{typedef} \&{uint16\_t} \&{font\_index};\C{index into \\{font\_info}}\par +\fi + +\M{549}Here now is the (rather formidable) array of font arrays. + +\Y\B\4\D$\\{non\_char}$ \5 +\\{qi}(\T{256})\C{a \&{halfword} code that can't match a real character}\par +\B\4\D$\\{non\_address}$ \5 +\T{0}\C{a spurious \\{bchar\_label}}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{memory\_word} ${}\\{font\_info}[\\{font\_mem\_size}+\T{1}]{}$;\C{the big collection of font data}\6 +\&{font\_index} \\{fmem\_ptr};\C{first unused word of \\{font\_info}}\6 +\&{internal\_font\_number} \\{font\_ptr};\C{largest internal font number in use}\6 +\&{four\_quarters} ${}\\{font\_check0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_check}\K\\{font\_check0}-\\{font\_base}{}$;\C{check sum}\6 +\&{scaled} ${}\\{font\_size0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_size}\K\\{font\_size0}-\\{font\_base}{}$;\C{``at'' size}\6 +\&{scaled} ${}\\{font\_dsize0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_dsize}\K\\{font\_dsize0}-\\{font\_base}{}$;\C{``design'' size}\6 +\&{font\_index} ${}\\{font\_params0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_params}\K\\{font\_params0}-\\{font\_base}{}$;\C{how many font parameters are present}\6 +\&{str\_number} ${}\\{font\_name0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_name}\K\\{font\_name0}-\\{font\_base}{}$;\C{name of the font}\6 +\&{str\_number} ${}\\{font\_area0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_area}\K\\{font\_area0}-\\{font\_base}{}$;\C{area of the font}\6 +\&{eight\_bits} ${}\\{font\_bc0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_bc}\K\\{font\_bc0}-\\{font\_base}{}$;\C{beginning (smallest) character code}\6 +\&{eight\_bits} ${}\\{font\_ec0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_ec}\K\\{font\_ec0}-\\{font\_base}{}$;\C{ending (largest) character code}\6 +\&{pointer} ${}\\{font\_glue0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_glue}\K\\{font\_glue0}-\\{font\_base}{}$;\C{glue specification for interword space, \\{null} if not allocated}\6 +\&{bool} ${}\\{font\_used0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_used}\K\\{font\_used0}-\\{font\_base}{}$;\C{has a character from this font actually appeared in the output?}\6 +\&{int} ${}\\{hyphen\_char0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{hyphen\_char}\K\\{hyphen\_char0}-\\{font\_base}{}$;\C{current \.{\\hyphenchar} values}\6 +\&{int} ${}\\{skew\_char0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{skew\_char}\K\\{skew\_char0}-\\{font\_base}{}$;\C{current \.{\\skewchar} values}\6 +\&{font\_index} ${}\\{bchar\_label0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{bchar\_label}\K\\{bchar\_label0}-\\{font\_base}{}$;\C{start of \\{lig\_kern} program for left boundary character, \\{non\_address} if there is none}\6 +\&{uint16\_t} ${}\\{font\_bchar0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_bchar}\K\\{font\_bchar0}-\\{font\_base}{}$;\C{right boundary character, \\{non\_char} if there is none}\6 +\&{uint16\_t} ${}\\{font\_false\_bchar0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{font\_false\_bchar}\K\\{font\_false\_bchar0}-\\{font\_base}{}$;\C{\\{font\_bchar} if it doesn't exist in the font, otherwise \\{non\_char}}\par +\fi + +\M{550}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} ${}\\{char\_base0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{char\_base}\K\\{char\_base0}-\\{font\_base}{}$;\C{base addresses for \\{char\_info}}\6 +\&{int} ${}\\{width\_base0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{width\_base}\K\\{width\_base0}-\\{font\_base}{}$;\C{base addresses for widths}\6 +\&{int} ${}\\{height\_base0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{height\_base}\K\\{height\_base0}-\\{font\_base}{}$;\C{base addresses for heights}\6 +\&{int} ${}\\{depth\_base0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{depth\_base}\K\\{depth\_base0}-\\{font\_base}{}$;\C{base addresses for depths}\6 +\&{int} ${}\\{italic\_base0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{italic\_base}\K\\{italic\_base0}-\\{font\_base}{}$;\C{base addresses for italic corrections}\6 +\&{int} ${}\\{lig\_kern\_base0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{lig\_kern\_base}\K\\{lig\_kern\_base0}-\\{font\_base}{}$;\C{base addresses for ligature/kerning programs}\6 +\&{int} ${}\\{kern\_base0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{kern\_base}\K\\{kern\_base0}-\\{font\_base}{}$;\C{base addresses for kerns}\6 +\&{int} ${}\\{exten\_base0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{exten\_base}\K\\{exten\_base0}-\\{font\_base}{}$;\C{base addresses for extensible recipes}\6 +\&{int} ${}\\{param\_base0}[\\{font\_max}-\\{font\_base}+\T{1}],{}$ ${}{*\&{const}\ }\\{param\_base}\K\\{param\_base0}-\\{font\_base}{}$;\C{base addresses for font parameters}\par +\fi + +\M{551}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|k\K\\{font\_base};{}$ ${}\|k\Z\\{font\_max};{}$ ${}\|k\PP){}$\1\5 +${}\\{font\_used}[\|k]\K\\{false}{}$;\2\par +\fi + +\M{552}\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\B\4\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\6 +$\\{font\_ptr}\K\\{null\_font};{}$\5 +${}\\{fmem\_ptr}\K\T{7};{}$\5 +${}\\{font\_name}[\\{null\_font}]\K\X1639:\.{"nullfont"}\X;{}$\5 +${}\\{font\_area}[\\{null\_font}]\K\\{empty\_string};{}$\5 +${}\\{hyphen\_char}[\\{null\_font}]\K\.{'-'};{}$\5 +${}\\{skew\_char}[\\{null\_font}]\K{-}\T{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}]\K\T{1};{}$\5 +${}\\{font\_ec}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{font\_size}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{font\_dsize}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{char\_base}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{width\_base}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{height\_base}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{depth\_base}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{italic\_base}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{lig\_kern\_base}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{kern\_base}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{exten\_base}[\\{null\_font}]\K\T{0};{}$\5 +${}\\{font\_glue}[\\{null\_font}]\K\\{null};{}$\5 +${}\\{font\_params}[\\{null\_font}]\K\T{7};{}$\5 +${}\\{param\_base}[\\{null\_font}]\K{-}\T{1};{}$\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{6};{}$ ${}\|k\PP){}$\1\5 +${}\\{font\_info}[\|k].\\{sc}\K\T{0}{}$;\2\par +\fi + +\M{553}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1639:\.{"nullfont"}\X,\39\\{set\_font},\39\\{null\_font});{}$\5 +${}\\{text}(\\{frozen\_null\_font})\K\X1639:\.{"nullfont"}\X;{}$\5 +${}\\{eqtb}[\\{frozen\_null\_font}]\K\\{eqtb}[\\{cur\_val}]{}$;\par +\fi + +\M{554}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\E\\{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. + +\Y\B\4\D$\\{char\_info\_end}(\|X)$ \5 +\|X ] $.$ \\{qqqq}\par +\B\4\D$\\{char\_info}(\|X)$ \5 +\\{font\_info} [ $\\{char\_base}[\|X]+{}$\\{char\_info\_end}\par +\B\4\D$\\{char\_width\_end}(\|X)$ \5 +$\|X.\\{b0}$ ] $.$ \\{sc}\par +\B\4\D$\\{char\_width}(\|X)$ \5 +\\{font\_info} [ $\\{width\_base}[\|X]+{}$\\{char\_width\_end}\par +\B\4\D$\\{char\_exists}(\|X)$ \5 +$(\|X.\\{b0}>\\{min\_quarterword}{}$)\par +\B\4\D$\\{char\_italic\_end}(\|X)$ \5 +$(\\{qo}(\|X.\\{b2}))/\T{4}$ ] $.$ \\{sc}\par +\B\4\D$\\{char\_italic}(\|X)$ \5 +\\{font\_info} [ $\\{italic\_base}[\|X]+{}$\\{char\_italic\_end}\par +\B\4\D$\\{height\_depth}(\|X)$ \5 +$\\{qo}(\|X.\\{b1}{}$)\par +\B\4\D$\\{char\_height\_end}(\|X)$ \5 +$(\|X)/\T{16}$ ] $.$ \\{sc}\par +\B\4\D$\\{char\_height}(\|X)$ \5 +\\{font\_info} [ $\\{height\_base}[\|X]+{}$\\{char\_height\_end}\par +\B\4\D$\\{char\_depth\_end}(\|X)$ \5 +$(\|X)\MOD\T{16}$ ] $.$ \\{sc}\par +\B\4\D$\\{char\_depth}(\|X)$ \5 +\\{font\_info} [ $\\{depth\_base}[\|X]+{}$\\{char\_depth\_end}\par +\B\4\D$\\{char\_tag}(\|X)$ \5 +$((\\{qo}(\|X.\\{b2}))\MOD\T{4}{}$)\par +\fi + +\M{555}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{four\_quarters} \\{null\_character};\C{nonexistent character information}\par +\fi + +\M{556}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\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 + +\M{557}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\E\\{font\_info}[\\{lig\_kern\_start}(\|f)(\|j)]$ or \\{font\_info}[\\{lig\_kern\_restart}(\|f)(\|i)], +depending on whether or not $\\{skip\_byte}(\|i)\Z\\{stop\_flag}$. + +The constant \\{kern\_base\_offset} should be simplified, for \PASCAL\ compilers +that do not do local optimization. + +\Y\B\4\D$\\{char\_kern\_end}(\|X)$ \5 +$\T{256}*\\{op\_byte}(\|X)+\\{rem\_byte}(\|X)$ ] $.$ \\{sc}\par +\B\4\D$\\{char\_kern}(\|X)$ \5 +\\{font\_info} [ $\\{kern\_base}[\|X]+{}$\\{char\_kern\_end}\par +\B\4\D$\\{kern\_base\_offset}$ \5 +$\T{256}*(\T{128}+\\{min\_quarterword}{}$)\par +\B\4\D$\\{lig\_kern\_start}(\|X)$ \5 +$\\{lig\_kern\_base}[\|X]+{}$\\{rem\_byte}\C{beginning of lig/kern program}\par +\B\4\D$\\{lig\_kern\_restart\_end}(\|X)$ \5 +$\T{256}*\\{op\_byte}(\|X)+\\{rem\_byte}(\|X)+\T{32768}-{}$\\{kern\_base\_offset}\par +\B\4\D$\\{lig\_kern\_restart}(\|X)$ \5 +$\\{lig\_kern\_base}[\|X]+{}$\\{lig\_kern\_restart\_end}\par +\fi + +\M{558}Font parameters are referred to as \\{slant}(\|f), \\{space}(\|f), etc. + +\Y\B\4\D$\\{param\_end}(\|X)$ \5 +\\{param\_base}[\|X] ] $.$ \\{sc}\par +\B\4\D$\\{param}(\|X)$ \5 +\\{font\_info} [ $\|X+{}$\\{param\_end}\par +\B\4\D$\\{slant}$ \5 +\\{param}(\\{slant\_code})\C{slant to the right, per unit distance upward}\par +\B\4\D$\\{space}$ \5 +\\{param}(\\{space\_code})\C{normal space between words}\par +\B\4\D$\\{space\_stretch}$ \5 +\\{param}(\\{space\_stretch\_code})\C{stretch between words}\par +\B\4\D$\\{space\_shrink}$ \5 +\\{param}(\\{space\_shrink\_code})\C{shrink between words}\par +\B\4\D$\\{x\_height}$ \5 +\\{param}(\\{x\_height\_code})\C{one ex}\par +\B\4\D$\\{quad}$ \5 +\\{param}(\\{quad\_code})\C{one em}\par +\B\4\D$\\{extra\_space}$ \5 +\\{param}(\\{extra\_space\_code})\C{additional space at end of sentence}\par +\Y\B\4\X558:The em width for \\{cur\_font}\X${}\E{}$\6 +\\{quad}(\\{cur\_font})\par +\U455.\fi + +\M{559}\B\X559:The x-height for \\{cur\_font}\X${}\E{}$\6 +\\{x\_height}(\\{cur\_font})\par +\U455.\fi + +\M{560}\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\E{-}\T{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\B\4\D$\\{abort}$ \5 +\&{goto} \\{bad\_tfm}\C{do this when the \.{TFM} data is wrong}\par +\Y\B\&{internal\_font\_number} \\{read\_font\_info}(\&{pointer} \|u${},\39{}$\&{str\_number} \\{nom}${},\39{}$\&{str\_number} \\{aire}${},\39{}$\&{scaled} \|s)\C{input a \.{TFM} file}\6 +${}\{{}$\5 +\1\&{font\_index} \|k;\C{index into \\{font\_info}}\6 +\&{bool} \\{file\_opened};\C{was \\{tfm\_file} successfully opened?}\6 +\&{halfword} \\{lf}${},{}$ \\{lh}${},{}$ \\{bc}${},{}$ \\{ec}${},{}$ \\{nw}${},{}$ \\{nh}${},{}$ \\{nd}${},{}$ \\{ni}${},{}$ \\{nl}${},{}$ \\{nk}${},{}$ \\{ne}${},{}$ \\{np};\C{sizes of subfiles}\6 +\&{internal\_font\_number} \|f;\C{the new font's number}\6 +\&{internal\_font\_number} \|g;\C{the number to return}\6 +\&{eight\_bits} \|a${},{}$ \|b${},{}$ \|c${},{}$ \|d;\C{byte variables}\6 +\&{four\_quarters} \\{qw};\6 +\&{scaled} \\{sw};\C{accumulators}\6 +\&{int} \\{bch\_label};\C{left boundary start location, or infinity}\6 +\&{uint16\_t} \\{bchar};\C{right boundary character, or 256}\6 +\&{scaled} \|z;\C{the design size or the ``at'' size}\6 +\&{int} \\{alpha};\6 +\&{uint8\_t} \\{beta};\C{auxiliary quantities used in fixed-point multiplication}\7 +${}\|g\K\\{null\_font}{}$;\6 +\X562: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}:\5 +\X561:Report that the font won't be loaded\X;\6 +\4\\{done}:\6 +\&{if} (\\{file\_opened})\1\5 +${}\\{b\_close}({\AND}\\{tfm\_file});{}$\2\6 +\&{return} \|g;\6 +\4${}\}{}$\2\par +\fi + +\M{561}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\B\4\D$\\{start\_font\_error\_message}$ \5 +\\{print\_err}(\.{"Font\ "});\5 +\\{sprint\_cs}(\|u);\5 +\\{print\_char}(\.{'='});\5 +${}\\{print\_file\_name}(\\{nom},\39\\{aire},\39\\{empty\_string});{}$\6 +\&{if} ${}(\|s\G\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ at\ "});\5 +\\{print\_scaled}(\|s);\5 +\\{print\_str}(\.{"pt"});\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|s\I{-}\T{1000}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ scaled\ "});\5 +${}\\{print\_int}({-}\|s);{}$\6 +\4${}\}{}$\2\par +\Y\B\4\X561:Report that the font won't be loaded\X${}\E{}$\6 +\\{start\_font\_error\_message};\6 +\&{if} (\\{file\_opened})\1\5 +\\{print\_str}(\.{"\ not\ loadable:\ Bad\ }\)\.{metric\ (TFM)\ file"});\2\6 +\&{else}\1\5 +\\{print\_str}(\.{"\ not\ loadable:\ Metr}\)\.{ic\ (TFM)\ file\ not\ fo}\)\.{und"});\2\6 +\\{help5}(\.{"I\ wasn't\ able\ to\ re}\)\.{ad\ the\ size\ data\ for}\)\.{\ this\ font,"})\6 +(\.{"so\ I\ will\ ignore\ th}\)\.{e\ font\ specification}\)\.{."})\6 +(\.{"[Wizards\ can\ fix\ TF}\)\.{M\ files\ using\ TFtoPL}\)\.{/PLtoTF.]"})\6 +(\.{"You\ might\ try\ inser}\)\.{ting\ a\ different\ fon}\)\.{t\ spec;"})\6 +(\.{"e.g.,\ type\ `I\\\\font}\)\.{<same\ font\ id>=<subs}\)\.{titute\ font\ name>'."}); \&{error} (\,)\par +\U560.\fi + +\M{562}\B\X562: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${}\E{}$\6 +\X563:Open \\{tfm\_file} for input\X;\6 +\X565:Read the {\.{TFM}} size fields\X;\6 +\X566:Use size fields to allocate font information\X;\6 +\X568:Read the {\.{TFM}} header\X;\6 +\X569:Read character data\X;\6 +\X571:Read box dimensions\X;\6 +\X573:Read ligature/kern program\X;\6 +\X574:Read extensible character recipes\X;\6 +\X575:Read font parameters\X;\6 +\X576:Make final adjustments and \&{goto} \\{done}\X\par +\U560.\fi + +\M{563}\B\X563:Open \\{tfm\_file} for input\X${}\E{}$\6 +$\\{file\_opened}\K\\{false};{}$\6 +\&{if} ${}(\\{aire}\E\\{empty\_string}){}$\1\5 +${}\\{pack\_file\_name}(\\{nom},\39\\{TEX\_font\_area},\39\X1640:\.{".tfm"}\X);{}$\2\6 +\&{else}\1\5 +${}\\{pack\_file\_name}(\\{nom},\39\\{aire},\39\X1640:\.{".tfm"}\X);{}$\2\6 +\&{if} ${}(\R\\{b\_open\_in}({\AND}\\{tfm\_file})){}$\1\5 +\\{abort};\2\6 +$\\{file\_opened}\K{}$\\{true}\par +\U562.\fi + +\M{564}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}.\|d$ 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$\{{}$ \\{get}(\\{tfm\_file}); + \&{if} (\\{eof}(\\{tfm\_file})) \\{abort}; $\}$\unskip'. + +\Y\B\4\D$\\{fget}$ \5 +\\{get}(\\{tfm\_file})\par +\B\4\D$\\{fbyte}$ \5 +$\\{tfm\_file}.{}$\|d\par +\B\4\D$\\{read\_sixteen}(\|X)$ \6 +${}\{{}$\5 +\1${}\|X\K\\{fbyte};{}$\6 +\&{if} ${}(\|X>\T{127}){}$\1\5 +\\{abort};\2\6 +\\{fget};\5 +${}\|X\K\|X*\T{\~400}+\\{fbyte};{}$\6 +\4${}\}{}$\2\par +\B\4\D$\\{store\_four\_quarters}(\|X)$ \6 +${}\{{}$\5 +\1\\{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 +${}\|X\K\\{qw};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{565}\B\X565:Read the {\.{TFM}} size fields\X${}\E{}$\6 +${}\{{}$\5 +\1\\{read\_sixteen}(\\{lf});\5 +\\{fget};\5 +\\{read\_sixteen}(\\{lh});\5 +\\{fget};\5 +\\{read\_sixteen}(\\{bc});\5 +\\{fget};\5 +\\{read\_sixteen}(\\{ec});\6 +\&{if} ${}((\\{bc}>\\{ec}+\T{1})\V(\\{ec}>\T{255})){}$\1\5 +\\{abort};\2\6 +\&{if} ${}(\\{bc}>\T{255}{}$)\C{$\\{bc}\E\T{256}$ and $\\{ec}\E\T{255}$}\6 +${}\{{}$\5 +\1${}\\{bc}\K\T{1};{}$\5 +${}\\{ec}\K\T{0};{}$\6 +\4${}\}{}$\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} ${}(\\{lf}\I\T{6}+\\{lh}+(\\{ec}-\\{bc}+\T{1})+\\{nw}+\\{nh}+\\{nd}+\\{ni}+\\{nl}+\\{nk}+\\{ne}+\\{np}){}$\1\5 +\\{abort};\2\6 +\&{if} ${}((\\{nw}\E\T{0})\V(\\{nh}\E\T{0})\V(\\{nd}\E\T{0})\V(\\{ni}\E\T{0})){}$\1\5 +\\{abort};\2\6 +\4${}\}{}$\2\par +\U562.\fi + +\M{566}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\B\4\X566:Use size fields to allocate font information\X${}\E{}$\6 +$\\{lf}\K\\{lf}-\T{6}-\\{lh}{}$;\C{\\{lf} words should be loaded into \\{font\_info}}\6 +\&{if} ${}(\\{np}<\T{7}){}$\1\5 +${}\\{lf}\K\\{lf}+\T{7}-\\{np}{}$;\C{at least seven parameters will appear}\2\6 +\&{if} ${}((\\{font\_ptr}\E\\{font\_max})\V(\\{fmem\_ptr}+\\{lf}>\\{font\_mem\_size})){}$\1\5 +\X567:Apologize for not loading the font, \&{goto} \\{done}\X;\2\6 +${}\|f\K\\{font\_ptr}+\T{1};{}$\5 +${}\\{char\_base}[\|f]\K\\{fmem\_ptr}-\\{bc};{}$\5 +${}\\{width\_base}[\|f]\K\\{char\_base}[\|f]+\\{ec}+\T{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};$ $\\{param\_base}[\|f]\K\\{exten\_base}[\|f]+{}$\\{ne}\par +\U562.\fi + +\M{567}\B\X567:Apologize for not loading the font, \&{goto} \\{done}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{start\_font\_error\_message};\5 +\\{print\_str}(\.{"\ not\ loaded:\ Not\ en}\)\.{ough\ room\ left"});\5 +\\{help4}(\.{"I'm\ afraid\ I\ won't\ }\)\.{be\ able\ to\ make\ use\ }\)\.{of\ this\ font,"})\6 +(\.{"because\ my\ memory\ f}\)\.{or\ character-size\ da}\)\.{ta\ is\ too\ small."})\6 +(\.{"If\ you're\ really\ st}\)\.{uck,\ ask\ a\ wizard\ to}\)\.{\ enlarge\ me."})\6 +(\.{"Or\ maybe\ try\ `I\\\\fo}\)\.{nt<same\ font\ id>=<na}\)\.{me\ of\ loaded\ font>'.}\)\.{"});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{goto} \\{done};\6 +\4${}\}{}$\2\par +\U566.\fi + +\M{568}Only the first two words of the header are needed by \TeX82. + +\Y\B\4\X568:Read the {\.{TFM}} header\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{lh}<\T{2}){}$\1\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*\T{\~400}+\\{fbyte};{}$\5 +\\{fget};\5 +${}\|z\K(\|z*\T{\~20})+(\\{fbyte}/\T{\~20});{}$\6 +\&{if} ${}(\|z<\\{unity}){}$\1\5 +\\{abort};\2\6 +\&{while} ${}(\\{lh}>\T{2}){}$\5 +${}\{{}$\5 +\1\\{fget};\5 +\\{fget};\5 +\\{fget};\5 +\\{fget};\5 +\\{decr}(\\{lh});\C{ignore the rest of the header}\6 +\4${}\}{}$\2\6 +${}\\{font\_dsize}[\|f]\K\|z;{}$\6 +\&{if} ${}(\|s\I{-}\T{1000}){}$\1\6 +\&{if} ${}(\|s\G\T{0}){}$\1\5 +${}\|z\K\|s;{}$\2\6 +\&{else}\1\5 +${}\|z\K\\{xn\_over\_d}(\|z,\39{-}\|s,\39\T{1000});{}$\2\2\6 +${}\\{font\_size}[\|f]\K\|z;{}$\6 +\4${}\}{}$\2\par +\U562.\fi + +\M{569}\B\X569:Read character data\X${}\E{}$\6 +\&{for} ${}(\|k\K\\{fmem\_ptr};{}$ ${}\|k\Z\\{width\_base}[\|f]-\T{1};{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1${}\\{store\_four\_quarters}(\\{font\_info}[\|k].\\{qqqq});{}$\6 +\&{if} ${}((\|a\G\\{nw})\V(\|b/\T{\~20}\G\\{nh})\V(\|b\MOD\T{\~20}\G\\{nd})\V(\|c/\T{4}\G\\{ni})){}$\1\5 +\\{abort};\2\6 +\&{switch} ${}(\|c\MOD\T{4}){}$\5 +${}\{{}$\1\6 +\4\&{case} \\{lig\_tag}:\6 +\&{if} ${}(\|d\G\\{nl}){}$\1\5 +\\{abort};\5 +\2\&{break};\6 +\4\&{case} \\{ext\_tag}:\6 +\&{if} ${}(\|d\G\\{ne}){}$\1\5 +\\{abort};\5 +\2\&{break};\6 +\4\&{case} \\{list\_tag}:\5 +\X570:Check for charlist cycle\X\5 +\&{break};\6 +\4\&{default}:\5 +\\{do\_nothing};\C{\\{no\_tag}}\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U562.\fi + +\M{570}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\B\4\D$\\{check\_byte\_range}(\|X)$ \6 +${}\{{}$\5 +\1\&{if} ${}((\|X<\\{bc})\V(\|X>\\{ec})){}$\1\5 +\\{abort};\5 +\2${}\}{}$\2\par +\B\4\D$\\{current\_character\_being\_worked\_on}$ \5 +$\|k+\\{bc}-{}$\\{fmem\_ptr}\par +\Y\B\4\X570:Check for charlist cycle\X${}\E{}$\6 +${}\{{}$\5 +\1\\{check\_byte\_range}(\|d);\6 +\&{while} ${}(\|d<\\{current\_character\_being\_worked\_on}){}$\5 +${}\{{}$\5 +\1${}\\{qw}\K\\{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\5 +\&{goto} \\{not\_found};\2\6 +${}\|d\K\\{qo}(\\{rem\_byte}(\\{qw})){}$;\C{next character on the list}\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|d\E\\{current\_character\_being\_worked\_on}){}$\1\5 +\\{abort};\C{yes, there's a cycle}\2\6 +\4\\{not\_found}:\5 +;\6 +\4${}\}{}$\2\par +\U569.\fi + +\M{571}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\B\4\D$\\{store\_scaled}(\|X)$ \6 +${}\{{}$\5 +\1\\{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*\|z)/\T{\~400})+(\|c*\|z))/\T{\~400})+(\|b*\|z))/\\{beta};{}$\6 +\&{if} ${}(\|a\E\T{0}){}$\1\5 +${}\|X\K\\{sw}{}$;\5 +\2\&{else} \&{if} ${}(\|a\E\T{255}){}$\1\5 +${}\|X\K\\{sw}-\\{alpha}{}$;\5 +\2\&{else}\1\5 +\\{abort};\2\6 +\4${}\}{}$\2\par +\Y\B\4\X571:Read box dimensions\X${}\E{}$\6 +${}\{{}$\5 +\1\X572:Replace \|z by $\|z^\prime$ and compute $\alpha,\beta$\X;\6 +\&{for} ${}(\|k\K\\{width\_base}[\|f];{}$ ${}\|k\Z\\{lig\_kern\_base}[\|f]-\T{1};{}$ ${}\|k\PP){}$\1\5 +${}\\{store\_scaled}(\\{font\_info}[\|k].\\{sc});{}$\2\6 +\&{if} ${}(\\{font\_info}[\\{width\_base}[\|f]].\\{sc}\I\T{0}){}$\1\5 +\\{abort};\C{\\{width}[0] must be zero}\2\6 +\&{if} ${}(\\{font\_info}[\\{height\_base}[\|f]].\\{sc}\I\T{0}){}$\1\5 +\\{abort};\C{\\{height}[0] must be zero}\2\6 +\&{if} ${}(\\{font\_info}[\\{depth\_base}[\|f]].\\{sc}\I\T{0}){}$\1\5 +\\{abort};\C{\\{depth}[0] must be zero}\2\6 +\&{if} ${}(\\{font\_info}[\\{italic\_base}[\|f]].\\{sc}\I\T{0}){}$\1\5 +\\{abort};\C{\\{italic}[0] must be zero}\2\6 +\4${}\}{}$\2\par +\U562.\fi + +\M{572}\B\X572:Replace \|z by $\|z^\prime$ and compute $\alpha,\beta$\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{alpha}\K\T{16};{}$\6 +\&{while} ${}(\|z\G\T{\~40000000}){}$\5 +${}\{{}$\5 +\1${}\|z\K\|z/\T{2};{}$\5 +${}\\{alpha}\K\\{alpha}+\\{alpha};{}$\6 +\4${}\}{}$\2\6 +${}\\{beta}\K\T{256}/\\{alpha};{}$\5 +${}\\{alpha}\K\\{alpha}*\|z;{}$\6 +\4${}\}{}$\2\par +\U571.\fi + +\M{573}\B\D$\\{check\_existence}(\|X)$ \5 +\hbox{}\6 +${}\{{}$\5 +\1\\{check\_byte\_range}(\|X);\5 +${}\\{qw}\K\\{char\_info}(\|f)(\|X){}$;\C{N.B.: not \\{qi}(\|X)}\6 +\&{if} ${}(\R\\{char\_exists}(\\{qw})){}$\1\5 +\\{abort};\2\6 +\4${}\}{}$\2\par +\Y\B\4\X573:Read ligature/kern program\X${}\E{}$\6 +$\\{bch\_label}\K\T{\~77777};{}$\5 +${}\\{bchar}\K\T{256};{}$\6 +\&{if} ${}(\\{nl}>\T{0}){}$\5 +${}\{{}$\5 +\1\&{for} ${}(\|k\K\\{lig\_kern\_base}[\|f];{}$ ${}\|k\Z\\{kern\_base}[\|f]+\\{kern\_base\_offset}-\T{1};{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1${}\\{store\_four\_quarters}(\\{font\_info}[\|k].\\{qqqq});{}$\6 +\&{if} ${}(\|a>\T{128}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\T{256}*\|c+\|d\G\\{nl}){}$\1\5 +\\{abort};\2\6 +\&{if} ${}(\|a\E\T{255}){}$\1\6 +\&{if} ${}(\|k\E\\{lig\_kern\_base}[\|f]){}$\1\5 +${}\\{bchar}\K\|b;{}$\2\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\|b\I\\{bchar}){}$\1\5 +\\{check\_existence}(\|b);\2\6 +\&{if} ${}(\|c<\T{128}){}$\1\5 +\\{check\_existence}(\|d)\C{check ligature}\2\6 +\&{else} \&{if} ${}(\T{256}*(\|c-\T{128})+\|d\G\\{nk}){}$\1\5 +\\{abort};\C{check kern}\2\6 +\&{if} ${}(\|a<\T{128}){}$\1\6 +\&{if} ${}(\|k-\\{lig\_kern\_base}[\|f]+\|a+\T{1}\G\\{nl}){}$\1\5 +\\{abort};\2\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|a\E\T{255}){}$\1\5 +${}\\{bch\_label}\K\T{256}*\|c+\|d;{}$\2\6 +\4${}\}{}$\2\6 +\&{for} ${}(\|k\K\\{kern\_base}[\|f]+\\{kern\_base\_offset};{}$ ${}\|k\Z\\{exten\_base}[\|f]-\T{1};{}$ ${}\|k\PP){}$\1\5 +${}\\{store\_scaled}(\\{font\_info}[\|k].\\{sc}){}$;\2\par +\U562.\fi + +\M{574}\B\X574:Read extensible character recipes\X${}\E{}$\6 +\&{for} ${}(\|k\K\\{exten\_base}[\|f];{}$ ${}\|k\Z\\{param\_base}[\|f]-\T{1};{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1${}\\{store\_four\_quarters}(\\{font\_info}[\|k].\\{qqqq});{}$\6 +\&{if} ${}(\|a\I\T{0}){}$\1\5 +\\{check\_existence}(\|a);\2\6 +\&{if} ${}(\|b\I\T{0}){}$\1\5 +\\{check\_existence}(\|b);\2\6 +\&{if} ${}(\|c\I\T{0}){}$\1\5 +\\{check\_existence}(\|c);\2\6 +\\{check\_existence}(\|d);\6 +\4${}\}{}$\2\par +\U562.\fi + +\M{575}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\B\4\X575:Read font parameters\X${}\E{}$\6 +${}\{{}$\5 +\1\&{for} ${}(\|k\K\T{1};{}$ ${}\|k\Z\\{np};{}$ ${}\|k\PP){}$\1\6 +\&{if} ${}(\|k\E\T{1}{}$)\C{the \\{slant} parameter is a pure number}\6 +${}\{{}$\5 +\1\\{fget};\5 +${}\\{sw}\K\\{fbyte};{}$\6 +\&{if} ${}(\\{sw}>\T{127}){}$\1\5 +${}\\{sw}\K\\{sw}-\T{256};{}$\2\6 +\\{fget};\5 +${}\\{sw}\K\\{sw}*\T{\~400}+\\{fbyte};{}$\5 +\\{fget};\5 +${}\\{sw}\K\\{sw}*\T{\~400}+\\{fbyte};{}$\5 +\\{fget};\5 +${}\\{font\_info}[\\{param\_base}[\|f]].\\{sc}\K(\\{sw}*\T{\~20})+(\\{fbyte}/\T{\~20});{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{store\_scaled}(\\{font\_info}[\\{param\_base}[\|f]+\|k-\T{1}].\\{sc});{}$\2\2\6 +\&{if} (\\{eof}(\\{tfm\_file}))\1\5 +\\{abort};\2\6 +\&{for} ${}(\|k\K\\{np}+\T{1};{}$ ${}\|k\Z\T{7};{}$ ${}\|k\PP){}$\1\5 +${}\\{font\_info}[\\{param\_base}[\|f]+\|k-\T{1}].\\{sc}\K\T{0};{}$\2\6 +\4${}\}{}$\2\par +\U562.\fi + +\M{576}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\B\4\D$\\{adjust}(\|X)$ \5 +$\|X[\|f]\K\\{qo}{}$(\|X[\|f])\C{correct for the excess \\{min\_quarterword} that was added}\par +\Y\B\4\X576:Make final adjustments and \&{goto} \\{done}\X${}\E{}$\6 +\&{if} ${}(\\{np}\G\T{7}){}$\1\5 +${}\\{font\_params}[\|f]\K\\{np}{}$;\5 +\2\&{else}\1\5 +${}\\{font\_params}[\|f]\K\T{7};{}$\2\6 +${}\\{hyphen\_char}[\|f]\K\\{default\_hyphen\_char};{}$\5 +${}\\{skew\_char}[\|f]\K\\{default\_skew\_char};{}$\6 +\&{if} ${}(\\{bch\_label}<\\{nl}){}$\1\5 +${}\\{bchar\_label}[\|f]\K\\{bch\_label}+\\{lig\_kern\_base}[\|f];{}$\2\6 +\&{else}\1\5 +${}\\{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}\Z\\{ec}){}$\1\6 +\&{if} ${}(\\{bchar}\G\\{bc}){}$\5 +${}\{{}$\5 +\1${}\\{qw}\K\\{char\_info}(\|f)(\\{bchar}){}$;\C{N.B.: not \\{qi}(\\{bchar})}\6 +\&{if} (\\{char\_exists}(\\{qw}))\1\5 +${}\\{font\_false\_bchar}[\|f]\K\\{non\_char};{}$\2\6 +\4${}\}{}$\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}(\\{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;$ \&{goto} \\{done}\par +\U562.\fi + +\M{577}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\B\4\X577:Declare procedures that scan font-related stuff\X${}\E{}$\6 +\&{void} \\{scan\_font\_ident}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{internal\_font\_number} \|f;\6 +\&{halfword} \|m;\7 +\X406:Get the next non-blank non-call token\X;\6 +\&{if} ${}(\\{cur\_cmd}\E\\{def\_font}){}$\1\5 +${}\|f\K\\{cur\_font};{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}\E\\{set\_font}){}$\1\5 +${}\|f\K\\{cur\_chr};{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}\E\\{def\_family}){}$\5 +${}\{{}$\5 +\1${}\|m\K\\{cur\_chr};{}$\5 +\\{scan\_four\_bit\_int}(\,);\5 +${}\|f\K\\{equiv}(\|m+\\{cur\_val});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ font\ identi}\)\.{fier"});\5 +\\{help2}(\.{"I\ was\ looking\ for\ a}\)\.{\ control\ sequence\ wh}\)\.{ose"})\6 +(\.{"current\ meaning\ has}\)\.{\ been\ defined\ by\ \\\\f}\)\.{ont."});\5 +\\{back\_error}(\,);\5 +${}\|f\K\\{null\_font};{}$\6 +\4${}\}{}$\2\6 +${}\\{cur\_val}\K\|f;{}$\6 +\4${}\}{}$\2\par +\A578. +\U409.\fi + +\M{578}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\B\4\X577:Declare procedures that scan font-related stuff\X${}\mathrel+\E{}$\6 +\&{void} \\{find\_font\_dimen}(\&{bool} \\{writing})\C{sets \\{cur\_val} to \\{font\_info} location}\6 +${}\{{}$\5 +\1\&{internal\_font\_number} \|f;\6 +\&{int} \|n;\C{the parameter number}\7 +\\{scan\_int}(\,);\5 +${}\|n\K\\{cur\_val};{}$\5 +\\{scan\_font\_ident}(\,);\5 +${}\|f\K\\{cur\_val};{}$\6 +\&{if} ${}(\|n\Z\T{0}){}$\1\5 +${}\\{cur\_val}\K\\{fmem\_ptr};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{writing}\W(\|n\Z\\{space\_shrink\_code})\W\30(\|n\G\\{space\_code})\W(\\{font\_glue}[\|f]\I\\{null})){}$\5 +${}\{{}$\5 +\1\\{delete\_glue\_ref}(\\{font\_glue}[\|f]);\5 +${}\\{font\_glue}[\|f]\K\\{null};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|n>\\{font\_params}[\|f]){}$\1\6 +\&{if} ${}(\|f<\\{font\_ptr}){}$\1\5 +${}\\{cur\_val}\K\\{fmem\_ptr};{}$\2\6 +\&{else}\1\5 +\X580:Increase the number of parameters in the last font\X\2\2\6 +\&{else}\1\5 +${}\\{cur\_val}\K\|n+\\{param\_base}[\|f];{}$\2\6 +\4${}\}{}$\2\6 +\X579:Issue an error message if $\\{cur\_val}\K\\{fmem\_ptr}$\X;\6 +\4${}\}{}$\2\par +\fi + +\M{579}\B\X579:Issue an error message if $\\{cur\_val}\K\\{fmem\_ptr}$\X${}\E{}$\6 +\&{if} ${}(\\{cur\_val}\E\\{fmem\_ptr}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Font\ "});\5 +\\{print\_esc}(\\{font\_id\_text}(\|f));\5 +\\{print\_str}(\.{"\ has\ only\ "});\5 +\\{print\_int}(\\{font\_params}[\|f]);\5 +\\{print\_str}(\.{"\ fontdimen\ paramete}\)\.{rs"});\5 +\\{help2}(\.{"To\ increase\ the\ num}\)\.{ber\ of\ font\ paramete}\)\.{rs,\ you\ must"})\6 +(\.{"use\ \\\\fontdimen\ imm}\)\.{ediately\ after\ the\ \\}\)\.{\\font\ is\ loaded."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U578.\fi + +\M{580}\B\X580:Increase the number of parameters in the last font\X${}\E{}$\6 +${}\{{}$\5 +\1\&{do}\5 +${}\{{}$\1\6 +\&{if} ${}(\\{fmem\_ptr}\E\\{font\_mem\_size}){}$\1\5 +${}\\{overflow}(\.{"font\ memory"},\39\\{font\_mem\_size});{}$\2\6 +${}\\{font\_info}[\\{fmem\_ptr}].\\{sc}\K\T{0};{}$\5 +\\{incr}(\\{fmem\_ptr});\5 +\\{incr}(\\{font\_params}[\|f]);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|n\E\\{font\_params}[\|f]));{}$\5 +${}\\{cur\_val}\K\\{fmem\_ptr}-\T{1}{}$;\C{this equals $\\{param\_base}[\|f]+\\{font\_params}[\|f]$}\6 +\4${}\}{}$\2\par +\U578.\fi + +\M{581}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\B\&{void} \\{char\_warning}(\&{internal\_font\_number} \|f${},\39{}$\&{eight\_bits} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{tracing\_lost\_chars}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{"Missing\ character:\ }\)\.{There\ is\ no\ "});\5 +\\{print\_ASCII}(\|c);\5 +\\{print\_str}(\.{"\ in\ font\ "});\5 +\\{slow\_print}(\\{font\_name}[\|f]);\5 +\\{print\_char}(\.{'!'});\5 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{582}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. + +\Y\B\&{pointer} \\{new\_character}(\&{internal\_font\_number} \|f${},\39{}$\&{eight\_bits} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{newly allocated node}\7 +\&{if} ${}(\\{font\_bc}[\|f]\Z\|c){}$\1\6 +\&{if} ${}(\\{font\_ec}[\|f]\G\|c){}$\1\6 +\&{if} (\\{char\_exists}(\\{char\_info}(\|f)(\\{qi}(\|c))))\5 +${}\{{}$\5 +\1${}\|p\K\\{get\_avail}(\,);{}$\5 +${}\\{font}(\|p)\K\|f;{}$\5 +${}\\{character}(\|p)\K\\{qi}(\|c);{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\2\2\6 +${}\\{char\_warning}(\|f,\39\|c);{}$\5 +\&{return} \\{null};\6 +\4${}\}{}$\2\par +\fi + +\N{1}{583}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 + +\M{584}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 + +\M{585}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[\T{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[\T{1}]. Same as \\{set\_char\_0}, except that character +number~\|c is typeset. \TeX82 uses this command for characters in the +range $\T{128}\Z\|c<\T{256}$. + +\yskip\hang\\{set2} 129 \|c[\T{2}]. Same as \\{set1}, except that \|c~is two +bytes long, so it is in the range $\T{0}\Z\|c<\T{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[\T{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[\T{4}]. Same as \\{set1}, except that \|c~is four +bytes long. Imagine that. + +\yskip\hang\\{set\_rule} 132 \|a[\T{4}] \|b[\T{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\Z\T{0}$ or $\|b\Z\T{0}$, nothing should be typeset. Note +that if $\|b<\T{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[\T{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[\T{2}]. Same as \\{set2}, except that \|h is not changed. + +\yskip\hang\\{put3} 135 \|c[\T{3}]. Same as \\{set3}, except that \|h is not changed. + +\yskip\hang\\{put4} 136 \|c[\T{4}]. Same as \\{set4}, except that \|h is not changed. + +\yskip\hang\\{put\_rule} 137 \|a[\T{4}] \|b[\T{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(\T{0},\T{0},\T{0},\T{0},\T{0},\T{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[\T{1}]. Set $\|h\K\|h+\|b$, i.e., move right \|b units. +The parameter is a signed number in two's complement notation, ${-}\T{128}\Z\|b<\T{128}$; +if $\|b<\T{0}$, the reference point moves left. + +\yskip\hang\\{right2} 144 \|b[\T{2}]. Same as \\{right1}, except that \|b is a +two-byte quantity in the range ${-}\T{32768}\Z\|b<\T{32768}$. + +\yskip\hang\\{right3} 145 \|b[\T{3}]. Same as \\{right1}, except that \|b is a +three-byte quantity in the range $\hbox{$-2^{23}$}\Z$ \|b $<$. + +\yskip\hang\\{right4} 146 \|b[\T{4}]. Same as \\{right1}, except that \|b is a +four-byte quantity in the range $\hbox{$-2^{31}$}\Z$ \|b $<$. + +\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[\T{1}]. Set $\|w\K\|b$ and $\|h\K\|h+\|b$. The value of \|b is a +signed quantity in two's complement notation, ${-}\T{128}\Z\|b<\T{128}$. This command +changes the current \|w~spacing and moves right by \|b. + +\yskip\hang\\{w2} 149 \|b[\T{2}]. Same as \\{w1}, but \|b is two bytes long, +${-}\T{32768}\Z\|b<\T{32768}$. + +\yskip\hang\\{w3} 150 \|b[\T{3}]. Same as \\{w1}, but \|b is three bytes long, +$\hbox{$-2^{23}$}\Z$ \|b $<$. + +\yskip\hang\\{w4} 151 \|b[\T{4}]. Same as \\{w1}, but \|b is four bytes long, +$\hbox{$-2^{31}$}\Z$ \|b $<$. + +\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[\T{1}]. Set $\|x\K\|b$ and $\|h\K\|h+\|b$. The value of \|b is a +signed quantity in two's complement notation, ${-}\T{128}\Z\|b<\T{128}$. This command +changes the current \|x~spacing and moves right by \|b. + +\yskip\hang\\{x2} 154 \|b[\T{2}]. Same as \\{x1}, but \|b is two bytes long, +${-}\T{32768}\Z\|b<\T{32768}$. + +\yskip\hang\\{x3} 155 \|b[\T{3}]. Same as \\{x1}, but \|b is three bytes long, +$\hbox{$-2^{23}$}\Z$ \|b $<$. + +\yskip\hang\\{x4} 156 \|b[\T{4}]. Same as \\{x1}, but \|b is four bytes long, +$\hbox{$-2^{31}$}\Z$ \|b $<$. + +\yskip\hang\\{down1} 157 \|a[\T{1}]. Set $\|v\K\|v+\|a$, i.e., move down \|a units. +The parameter is a signed number in two's complement notation, ${-}\T{128}\Z\|a<\T{128}$; +if $\|a<\T{0}$, the reference point moves up. + +\yskip\hang\\{down2} 158 \|a[\T{2}]. Same as \\{down1}, except that \|a is a +two-byte quantity in the range ${-}\T{32768}\Z\|a<\T{32768}$. + +\yskip\hang\\{down3} 159 \|a[\T{3}]. Same as \\{down1}, except that \|a is a +three-byte quantity in the range $\hbox{$-2^{23}$}\Z$ \|a $<$. + +\yskip\hang\\{down4} 160 \|a[\T{4}]. Same as \\{down1}, except that \|a is a +four-byte quantity in the range $\hbox{$-2^{31}$}\Z$ \|a $<$. + +\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[\T{1}]. Set $\|y\K\|a$ and $\|v\K\|v+\|a$. The value of \|a is a +signed quantity in two's complement notation, ${-}\T{128}\Z\|a<\T{128}$. This command +changes the current \|y~spacing and moves down by \|a. + +\yskip\hang\\{y2} 163 \|a[\T{2}]. Same as \\{y1}, but \|a is two bytes long, +${-}\T{32768}\Z\|a<\T{32768}$. + +\yskip\hang\\{y3} 164 \|a[\T{3}]. Same as \\{y1}, but \|a is three bytes long, +$\hbox{$-2^{23}$}\Z$ \|a $<$. + +\yskip\hang\\{y4} 165 \|a[\T{4}]. Same as \\{y1}, but \|a is four bytes long, +$\hbox{$-2^{31}$}\Z$ \|a $<$. + +\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[\T{1}]. Set $\|z\K\|a$ and $\|v\K\|v+\|a$. The value of \|a is a +signed quantity in two's complement notation, ${-}\T{128}\Z\|a<\T{128}$. This command +changes the current \|z~spacing and moves down by \|a. + +\yskip\hang\\{z2} 168 \|a[\T{2}]. Same as \\{z1}, but \|a is two bytes long, +${-}\T{32768}\Z\|a<\T{32768}$. + +\yskip\hang\\{z3} 169 \|a[\T{3}]. Same as \\{z1}, but \|a is three bytes long, +$\hbox{$-2^{23}$}\Z$ \|a $<$. + +\yskip\hang\\{z4} 170 \|a[\T{4}]. Same as \\{z1}, but \|a is four bytes long, +$\hbox{$-2^{31}$}\Z$ \|a $<$. + +\yskip\hang\\{fnt\_num\_0} 171. Set $\|f\K\T{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\K\T{1}$, \dots, \hbox{$\|f\K\T{63}$}, respectively. + +\yskip\hang\\{fnt1} 235 \|k[\T{1}]. Set $\|f\K\|k$. \TeX82 uses this command for font +numbers in the range $\T{64}\Z\|k<\T{256}$. + +\yskip\hang\\{fnt2} 236 \|k[\T{2}]. Same as \\{fnt1}, except that \|k~is two +bytes long, so it is in the range $\T{0}\Z\|k<\T{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[\T{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[\T{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[\T{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[\T{2}] \|x[\|k]. Like \\{xxx1}, but $\T{0}\Z\|k<\T{65536}$. + +\yskip\hang\\{xxx3} 241 \|k[\T{3}] \|x[\|k]. Like \\{xxx1}, but $\T{0}\Z\|k$ $<$. + +\yskip\hang\\{xxx4} 242 \|k[\T{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[\T{1}] \|c[\T{4}] \|s[\T{4}] \|d[\T{4}] \|a[\T{1}] \|l[\T{1}] $\|n[\|a+\|l]$. +Define font \|k, where $\T{0}\Z\|k<\T{256}$; font definitions will be explained shortly. + +\yskip\hang\\{fnt\_def2} 244 \|k[\T{2}] \|c[\T{4}] \|s[\T{4}] \|d[\T{4}] \|a[\T{1}] \|l[\T{1}] $\|n[\|a+\|l]$. +Define font \|k, where $\T{0}\Z\|k<\T{65536}$. + +\yskip\hang\\{fnt\_def3} 245 \|k[\T{3}] \|c[\T{4}] \|s[\T{4}] \|d[\T{4}] \|a[\T{1}] \|l[\T{1}] $\|n[\|a+\|l]$. +Define font \|k, where $\T{0}\Z\|k$ $<$. + +\yskip\hang\\{fnt\_def4} 246 \|k[\T{4}] \|c[\T{4}] \|s[\T{4}] \|d[\T{4}] \|a[\T{1}] \|l[\T{1}] $\|n[\|a+\|l]$. +Define font \|k, where $\hbox{$-2^{31}$}\Z$ \|k $<$. + +\yskip\hang\\{pre} 247 \|i[\T{1}] \\{num}[\T{4}] \\{den}[\T{4}] \\{mag}[\T{4}] \|k[\T{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 + +\M{586}\B\D$\\{set\_char\_0}$ \5 +\T{0}\C{typeset character 0 and move right}\par +\B\4\D$\\{set1}$ \5 +\T{128}\C{typeset a character and move right}\par +\B\4\D$\\{set\_rule}$ \5 +\T{132}\C{typeset a rule and move right}\par +\B\4\D$\\{put\_rule}$ \5 +\T{137}\C{typeset a rule}\par +\B\4\D$\\{nop}$ \5 +\T{138}\C{no operation}\par +\B\4\D$\\{bop}$ \5 +\T{139}\C{beginning of page}\par +\B\4\D$\\{eop}$ \5 +\T{140}\C{ending of page}\par +\B\4\D$\\{push}$ \5 +\T{141}\C{save the current positions}\par +\B\4\D$\\{pop}$ \5 +\T{142}\C{restore previous positions}\par +\B\4\D$\\{right1}$ \5 +\T{143}\C{move right}\par +\B\4\D$\\{w0}$ \5 +\T{147}\C{move right by \|w}\par +\B\4\D$\\{w1}$ \5 +\T{148}\C{move right and set \|w}\par +\B\4\D$\\{x0}$ \5 +\T{152}\C{move right by \|x}\par +\B\4\D$\\{x1}$ \5 +\T{153}\C{move right and set \|x}\par +\B\4\D$\\{down1}$ \5 +\T{157}\C{move down}\par +\B\4\D$\\{y0}$ \5 +\T{161}\C{move down by \|y}\par +\B\4\D$\\{y1}$ \5 +\T{162}\C{move down and set \|y}\par +\B\4\D$\\{z0}$ \5 +\T{166}\C{move down by \|z}\par +\B\4\D$\\{z1}$ \5 +\T{167}\C{move down and set \|z}\par +\B\4\D$\\{fnt\_num\_0}$ \5 +\T{171}\C{set current font to 0}\par +\B\4\D$\\{fnt1}$ \5 +\T{235}\C{set current font}\par +\B\4\D$\\{xxx1}$ \5 +\T{239}\C{extension to \.{DVI} primitives}\par +\B\4\D$\\{xxx4}$ \5 +\T{242}\C{potentially long extension to \.{DVI} primitives}\par +\B\4\D$\\{fnt\_def1}$ \5 +\T{243}\C{define the meaning of a font number}\par +\B\4\D$\\{pre}$ \5 +\T{247}\C{preamble}\par +\B\4\D$\\{post}$ \5 +\T{248}\C{postamble beginning}\par +\B\4\D$\\{post\_post}$ \5 +\T{249}\C{postamble ending}\par +\fi + +\M{587}The preamble contains basic information about the file as a whole. As +stated above, there are six parameters: +$$\hbox{\|i[\T{1}] \\{num}[\T{4}] \\{den}[\T{4}] \\{mag}[\T{4}] \|k[\T{1}] \|x[\|k].}$$ +The \|i byte identifies \.{DVI} format; currently this byte is always set +to~2. (The value $\|i\E\T{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\E\T{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 $\T{0}\Z\|k<\T{256}$. + +\Y\B\4\D$\\{id\_byte}$ \5 +\T{2}\C{identifies the kind of \.{DVI} files described here}\par +\fi + +\M{588}Font definitions for a given font number \|k contain further parameters +$$\hbox{\|c[\T{4}] \|s[\T{4}] \|d[\T{4}] \|a[\T{1}] \|l[\T{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\E\T{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 + +\M{589}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 +$\T{0}\Z\|x<\hbox{$\alpha$}\|b$ and $\T{0}\Z\|y<\hbox{$\alpha$}\|a$, where $\alpha$ is the number +of pixels per \.{DVI} unit. + +\fi + +\M{590}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[\T{4}] \\{num}[\T{4}] \\{den}[\T{4}] \\{mag}[\T{4}] \|l[\T{4}] \|u[\T{4}] \|s[\T{2}] \|t[\T{2}]\cr +$\langle\,$font definitions$\,\rangle$\cr +\\{post\_post} \|q[\T{4}] \|i[\T{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 + +\M{591}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 currently equals~2, as in the preamble. + +The \|i byte is followed by four or more bytes that are all equal to +the decimal number 223 (i.e., 0337 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 + +\N{1}{592}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{total\_pages};\C{the number of pages that have been shipped out}\6 +\&{scaled} \\{max\_v};\C{maximum height-plus-depth of pages shipped so far}\6 +\&{scaled} \\{max\_h};\C{maximum width of pages shipped so far}\6 +\&{int} \\{max\_push};\C{deepest nesting of \\{push} commands encountered so far}\6 +\&{int} \\{last\_bop};\C{location of previous \\{bop} in the \.{DVI} output}\6 +\&{int} \\{dead\_cycles};\C{recent outputs that didn't ship anything out}\6 +\&{bool} \\{doing\_leaders};\C{are we inside a leader box?}\7 +\&{quarterword} \|c${},{}$ \|f;\C{character and font in current \\{char\_node}}\6 +\&{scaled} \\{rule\_ht}${},{}$ \\{rule\_dp}${},{}$ \\{rule\_wd};\C{size of current rule being output}\6 +\&{pointer} \|g;\C{current glue specification}\6 +\&{int} \\{lq}${},{}$ \\{lr};\C{quantities used in calculations for leaders}\par +\fi + +\M{593}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{total\_pages}\K\T{0};{}$\5 +${}\\{max\_v}\K\T{0};{}$\5 +${}\\{max\_h}\K\T{0};{}$\5 +${}\\{max\_push}\K\T{0};{}$\5 +${}\\{last\_bop}\K{-}\T{1};{}$\5 +${}\\{doing\_leaders}\K\\{false};{}$\5 +${}\\{dead\_cycles}\K\T{0};{}$\5 +${}\\{cur\_s}\K{-}\T{1}{}$;\par +\fi + +\M{594}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}[\T{0}\dotdot\\{half\_buf}-\T{1}]$ constitute the first half, and those in +$\\{dvi\_buf}[\\{half\_buf}\dotdot\\{dvi\_buf\_size}-\T{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\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{uint16\_t} \&{dvi\_index};\C{an index into the output buffer}\par +\fi + +\M{595}Some systems may find it more efficient to make \\{dvi\_buf} a +array, since output of four bytes at once may be facilitated. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{eight\_bits} ${}\\{dvi\_buf}[\\{dvi\_buf\_size}+\T{1}]{}$;\C{buffer for \.{DVI} output}\6 +\&{dvi\_index} \\{half\_buf};\C{half of \\{dvi\_buf\_size}}\6 +\&{dvi\_index} \\{dvi\_limit};\C{end of the current half buffer}\6 +\&{dvi\_index} \\{dvi\_ptr};\C{the next available buffer address}\6 +\&{int} \\{dvi\_offset};\C{\\{dvi\_buf\_size} times the number of times the output buffer has been fully emptied}\6 +\&{int} \\{dvi\_gone};\C{the number of bytes already output to \\{dvi\_file}}\par +\fi + +\M{596}Initially the buffer is all in one piece; we will output half of it only +after it first fills up. + +\Y\B\4\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{half\_buf}\K\\{dvi\_buf\_size}/\T{2};{}$\5 +${}\\{dvi\_limit}\K\\{dvi\_buf\_size};{}$\5 +${}\\{dvi\_ptr}\K\T{0};{}$\5 +${}\\{dvi\_offset}\K\T{0};{}$\5 +${}\\{dvi\_gone}\K\T{0}{}$;\par +\fi + +\M{597}The actual output of $\\{dvi\_buf}[\|a\dotdot\|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+\T{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. + +\Y\B\&{void} \\{write\_dvi}(\&{dvi\_index} \|a${},\39{}$\&{dvi\_index} \|b)\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|k;\7 +\&{for} ${}(\|k\K\|a;{}$ ${}\|k\Z\|b;{}$ ${}\|k\PP){}$\1\5 +${}\\{write}(\\{dvi\_file},\39\.{"\%c"},\39\\{dvi\_buf}[\|k]);{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{598}To put a byte in the buffer without paying the cost of invoking a procedure +each time, we use the macro \\{dvi\_out}. + +\Y\B\4\D$\\{dvi\_out}(\|X)$ \5 +${}\{{}$\5 +\1${}\\{dvi\_buf}[\\{dvi\_ptr}]\K\|X;{}$\5 +\\{incr}(\\{dvi\_ptr});\6 +\&{if} ${}(\\{dvi\_ptr}\E\\{dvi\_limit}){}$\1\5 +\\{dvi\_swap}(\,);\2\6 +\4${}\}{}$\2\par +\Y\B\&{void} \\{dvi\_swap}(\&{void})\C{outputs half of the buffer}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{dvi\_limit}\E\\{dvi\_buf\_size}){}$\5 +${}\{{}$\5 +\1${}\\{write\_dvi}(\T{0},\39\\{half\_buf}-\T{1});{}$\5 +${}\\{dvi\_limit}\K\\{half\_buf};{}$\5 +${}\\{dvi\_offset}\K\\{dvi\_offset}+\\{dvi\_buf\_size};{}$\5 +${}\\{dvi\_ptr}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{write\_dvi}(\\{half\_buf},\39\\{dvi\_buf\_size}-\T{1});{}$\5 +${}\\{dvi\_limit}\K\\{dvi\_buf\_size};{}$\6 +\4${}\}{}$\2\6 +${}\\{dvi\_gone}\K\\{dvi\_gone}+\\{half\_buf};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{599}Here is how we clean out the buffer when \TeX\ is all through; \\{dvi\_ptr} +will be a multiple of~4. + +\Y\B\4\X599:Empty the last bytes out of \\{dvi\_buf}\X${}\E{}$\6 +\&{if} ${}(\\{dvi\_limit}\E\\{half\_buf}){}$\1\5 +${}\\{write\_dvi}(\\{half\_buf},\39\\{dvi\_buf\_size}-\T{1});{}$\2\6 +\&{if} ${}(\\{dvi\_ptr}>\T{0})$ $\\{write\_dvi}(\T{0},\39\\{dvi\_ptr}-\T{1}{}$)\par +\U642.\fi + +\M{600}The \\{dvi\_four} procedure outputs four bytes in two's complement notation, +without risking arithmetic overflow. + +\Y\B\&{void} \\{dvi\_four}(\&{int} \|x)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\|x\G\T{0}){}$\1\5 +${}\\{dvi\_out}(\|x/\T{\~100000000}){}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|x\K\|x+\T{\~10000000000};{}$\5 +${}\|x\K\|x+\T{\~10000000000};{}$\5 +${}\\{dvi\_out}((\|x/\T{\~100000000})+\T{128});{}$\6 +\4${}\}{}$\2\6 +${}\|x\K\|x\MOD\T{\~100000000};{}$\5 +${}\\{dvi\_out}(\|x/\T{\~200000});{}$\5 +${}\|x\K\|x\MOD\T{\~200000};{}$\5 +${}\\{dvi\_out}(\|x/\T{\~400});{}$\5 +${}\\{dvi\_out}(\|x\MOD\T{\~400});{}$\6 +\4${}\}{}$\2\par +\fi + +\M{601}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\B\&{void} \\{dvi\_pop}(\&{int} \|l)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}((\|l\E\\{dvi\_offset}+\\{dvi\_ptr})\W(\\{dvi\_ptr}>\T{0})){}$\1\5 +\\{decr}(\\{dvi\_ptr});\2\6 +\&{else}\1\5 +\\{dvi\_out}(\\{pop});\2\6 +\4${}\}{}$\2\par +\fi + +\M{602}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\B\&{void} \\{dvi\_font\_def}(\&{internal\_font\_number} \|f)\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|k;\C{index into \\{str\_pool}}\7 +\\{dvi\_out}(\\{fnt\_def1});\5 +${}\\{dvi\_out}(\|f-\\{font\_base}-\T{1}){}$;\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 +\X603:Output the font name whose internal number is \|f\X;\6 +\4${}\}{}$\2\par +\fi + +\M{603}\B\X603:Output the font name whose internal number is \|f\X${}\E{}$\6 +\&{for} ${}(\|k\K\\{str\_start}[\\{font\_area}[\|f]];{}$ ${}\|k\Z\\{str\_start}[\\{font\_area}[\|f]+\T{1}]-\T{1};{}$ ${}\|k\PP){}$\1\5 +\\{dvi\_out}(\\{so}(\\{str\_pool}[\|k]));\2\6 +\&{for} ${}(\|k\K\\{str\_start}[\\{font\_name}[\|f]];{}$ ${}\|k\Z\\{str\_start}[\\{font\_name}[\|f]+\T{1}]-\T{1};{}$ ${}\|k\PP)$ \\{dvi\_out}(\\{so}(\\{str\_pool}[\|k]))\par +\U602.\fi + +\M{604}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 + +\M{605}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\B\4\D$\\{movement\_node\_size}$ \5 +\T{3}\C{number of words per entry in the down and right stacks}\par +\B\4\D$\\{location}(\|X)$ \5 +$\\{mem}[\|X+\T{2}].{}$\|i\C{\.{DVI} byte number for a movement command}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{down\_ptr}${},{}$ \\{right\_ptr};\C{heads of the down and right stacks}\par +\fi + +\M{606}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{down\_ptr}\K\\{null};{}$\5 +${}\\{right\_ptr}\K\\{null}{}$;\par +\fi + +\M{607}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}\E\\{w1}-\\{right1}$ +and $\\{z1}-\\{down1}\E\\{x1}-\\{right1}$. + +\Y\B\&{void} \\{movement}(\&{scaled} \|w${},\39{}$\&{eight\_bits} \|o)\1\1\2\2\6 +${}\{{}$\5 +\1\&{small\_number} \\{mstate};\C{have we seen a \|y or \|z?}\6 +\&{pointer} \|p${},{}$ \|q;\C{current and top nodes on the stack}\6 +\&{int} \|k;\C{index into \\{dvi\_buf}, modulo \\{dvi\_buf\_size}}\7 +${}\|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\E\\{down1}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|q)\K\\{down\_ptr};{}$\5 +${}\\{down\_ptr}\K\|q;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{link}(\|q)\K\\{right\_ptr};{}$\5 +${}\\{right\_ptr}\K\|q;{}$\6 +\4${}\}{}$\2\6 +\X611: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 +\X610:Generate a \\{down} or \\{right} command for \|w and \&{return}\X;\6 +\4\\{found}:\5 +\X609:Generate a \\{y0} or \\{z0} command in order to reuse a previous appearance of~\|w\X;\6 +\4${}\}{}$\2\par +\fi + +\M{608}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\B\4\D$\\{y\_here}$ \5 +\T{1}\C{\\{info} when the movement entry points to a \|y command}\par +\B\4\D$\\{z\_here}$ \5 +\T{2}\C{\\{info} when the movement entry points to a \|z command}\par +\B\4\D$\\{yz\_OK}$ \5 +\T{3}\C{\\{info} corresponding to an unconstrained \\{down} command}\par +\B\4\D$\\{y\_OK}$ \5 +\T{4}\C{\\{info} corresponding to a \\{down} that can't become a \|z}\par +\B\4\D$\\{z\_OK}$ \5 +\T{5}\C{\\{info} corresponding to a \\{down} that can't become a \|y}\par +\B\4\D$\\{d\_fixed}$ \5 +\T{6}\C{\\{info} corresponding to a \\{down} that can't change}\par +\fi + +\M{609}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\B\4\X609:Generate a \\{y0} or \\{z0} command in order to reuse a previous appearance of~\|w\X${}\E{}$\6 +$\\{info}(\|q)\K\\{info}(\|p);{}$\6 +\&{if} ${}(\\{info}(\|q)\E\\{y\_here}){}$\5 +${}\{{}$\5 +\1${}\\{dvi\_out}(\|o+\\{y0}-\\{down1}){}$;\C{\\{y0} or \\{w0}}\6 +\&{while} ${}(\\{link}(\|q)\I\|p){}$\5 +${}\{{}$\5 +\1${}\|q\K\\{link}(\|q);{}$\6 +\&{switch} (\\{info}(\|q))\5 +${}\{{}$\1\6 +\4\&{case} \\{yz\_OK}:\5 +${}\\{info}(\|q)\K\\{z\_OK}{}$;\5 +\&{break};\6 +\4\&{case} \\{y\_OK}:\5 +${}\\{info}(\|q)\K\\{d\_fixed}{}$;\5 +\&{break};\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{dvi\_out}(\|o+\\{z0}-\\{down1}){}$;\C{\\{z0} or \\{x0}}\6 +\&{while} ${}(\\{link}(\|q)\I\|p){}$\5 +${}\{{}$\5 +\1${}\|q\K\\{link}(\|q);{}$\6 +\&{switch} (\\{info}(\|q))\5 +${}\{{}$\1\6 +\4\&{case} \\{yz\_OK}:\5 +${}\\{info}(\|q)\K\\{y\_OK}{}$;\5 +\&{break};\6 +\4\&{case} \\{z\_OK}:\5 +${}\\{info}(\|q)\K\\{d\_fixed}{}$;\5 +\&{break};\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U607.\fi + +\M{610}\B\X610:Generate a \\{down} or \\{right} command for \|w and \&{return}\X${}\E{}$\6 +$\\{info}(\|q)\K\\{yz\_OK};{}$\6 +\&{if} ${}(\\{abs}(\|w)\G\T{\~40000000}){}$\5 +${}\{{}$\5 +\1${}\\{dvi\_out}(\|o+\T{3}){}$;\C{\\{down4} or \\{right4}}\6 +\\{dvi\_four}(\|w);\5 +\&{return};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{abs}(\|w)\G\T{\~100000}){}$\5 +${}\{{}$\5 +\1${}\\{dvi\_out}(\|o+\T{2}){}$;\C{\\{down3} or \\{right3}}\6 +\&{if} ${}(\|w<\T{0}){}$\1\5 +${}\|w\K\|w+\T{\~100000000};{}$\2\6 +${}\\{dvi\_out}(\|w/\T{\~200000});{}$\5 +${}\|w\K\|w\MOD\T{\~200000};{}$\5 +\&{goto} \\{label2};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{abs}(\|w)\G\T{\~200}){}$\5 +${}\{{}$\5 +\1${}\\{dvi\_out}(\|o+\T{1}){}$;\C{\\{down2} or \\{right2}}\6 +\&{if} ${}(\|w<\T{0}){}$\1\5 +${}\|w\K\|w+\T{\~200000};{}$\2\6 +\&{goto} \\{label2};\6 +\4${}\}{}$\2\6 +\\{dvi\_out}(\|o);\C{\\{down1} or \\{right1}}\6 +\&{if} ${}(\|w<\T{0}){}$\1\5 +${}\|w\K\|w+\T{\~400};{}$\2\6 +\&{goto} \\{label1};\6 +\4\\{label2}:\5 +${}\\{dvi\_out}(\|w/\T{\~400});{}$\6 +\4\\{label1}:\5 +${}\\{dvi\_out}(\|w\MOD\T{\~400});$ \&{return}\par +\U607.\fi + +\M{611}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\B\4\D$\\{none\_seen}$ \5 +\T{0}\C{no \\{y\_here} or \\{z\_here} nodes have been encountered yet}\par +\B\4\D$\\{y\_seen}$ \5 +\T{6}\C{we have seen \\{y\_here} but not \\{z\_here}}\par +\B\4\D$\\{z\_seen}$ \5 +\T{12}\C{we have seen \\{z\_here} but not \\{y\_here}}\par +\Y\B\4\X611:Look at the other stack entries until deciding what sort of \.{DVI} command to generate; \&{goto} \\{found} if node \|p is a ``hit''\X${}\E{}$\6 +$\|p\K\\{link}(\|q);{}$\5 +${}\\{mstate}\K\\{none\_seen};{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{width}(\|p)\E\|w){}$\1\5 +\X612:Consider a node with matching width; \&{goto} \\{found} if it's a hit\X\2\6 +\&{else}\1\6 +\&{switch} ${}(\\{mstate}+\\{info}(\|p)){}$\5 +${}\{{}$\1\6 +\4\&{case} \\{none\_seen}${}+\\{y\_here}{}$:\5 +${}\\{mstate}\K\\{y\_seen}{}$;\5 +\&{break};\6 +\4\&{case} \\{none\_seen}${}+\\{z\_here}{}$:\5 +${}\\{mstate}\K\\{z\_seen}{}$;\5 +\&{break};\6 +\4\&{case} \\{y\_seen}${}+\\{z\_here}{}$:\5 +\&{case} \\{z\_seen}${}+\\{y\_here}{}$:\5 +\&{goto} \\{not\_found};\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\2\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\\{not\_found}:\par +\U607.\fi + +\M{612}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\B\4\X612:Consider a node with matching width; \&{goto} \\{found} if it's a hit\X${}\E{}$\6 +\&{switch} ${}(\\{mstate}+\\{info}(\|p)){}$\5 +${}\{{}$\1\6 +\4\&{case} \\{none\_seen}${}+\\{yz\_OK}{}$:\5 +\&{case} \\{none\_seen}${}+\\{y\_OK}{}$:\5 +\&{case} \\{z\_seen}${}+\\{yz\_OK}{}$:\5 +\&{case} \\{z\_seen}${}+\\{y\_OK}{}$:\5 +\hbox{}\6 +\&{if} ${}(\\{location}(\|p)<\\{dvi\_gone}){}$\1\5 +\&{goto} \\{not\_found};\2\6 +\&{else}\1\5 +\X613:Change buffered instruction to \|y or \|w and \&{goto} \\{found}\X\5 +\2\&{break};\6 +\4\&{case} \\{none\_seen}${}+\\{z\_OK}{}$:\5 +\&{case} \\{y\_seen}${}+\\{yz\_OK}{}$:\5 +\&{case} \\{y\_seen}${}+\\{z\_OK}{}$:\5 +\hbox{}\6 +\&{if} ${}(\\{location}(\|p)<\\{dvi\_gone}){}$\1\5 +\&{goto} \\{not\_found};\2\6 +\&{else}\1\5 +\X614:Change buffered instruction to \|z or \|x and \&{goto} \\{found}\X\5 +\2\&{break};\6 +\4\&{case} \\{none\_seen}${}+\\{y\_here}{}$:\5 +\&{case} \\{none\_seen}${}+\\{z\_here}{}$:\5 +\&{case} \\{y\_seen}${}+\\{z\_here}{}$:\5 +\&{case} \\{z\_seen}${}+\\{y\_here}{}$:\5 +\&{goto} \\{found};\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\par +\U611.\fi + +\M{613}\B\X613:Change buffered instruction to \|y or \|w and \&{goto} \\{found}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|k\K\\{location}(\|p)-\\{dvi\_offset};{}$\6 +\&{if} ${}(\|k<\T{0}){}$\1\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} \\{found};\6 +\4${}\}{}$\2\par +\U612.\fi + +\M{614}\B\X614:Change buffered instruction to \|z or \|x and \&{goto} \\{found}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|k\K\\{location}(\|p)-\\{dvi\_offset};{}$\6 +\&{if} ${}(\|k<\T{0}){}$\1\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} \\{found};\6 +\4${}\}{}$\2\par +\U612.\fi + +\M{615}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\B\&{void} \\{prune\_movements}(\&{int} \|l)\C{delete movement nodes with $\\{location}\G\|l$}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{node being deleted}\7 +\&{while} ${}(\\{down\_ptr}\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{location}(\\{down\_ptr})<\|l){}$\1\5 +\&{goto} \\{done};\2\6 +${}\|p\K\\{down\_ptr};{}$\5 +${}\\{down\_ptr}\K\\{link}(\|p);{}$\5 +${}\\{free\_node}(\|p,\39\\{movement\_node\_size});{}$\6 +\4${}\}{}$\2\6 +\4\\{done}:\6 +\&{while} ${}(\\{right\_ptr}\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{location}(\\{right\_ptr})<\|l){}$\1\5 +\&{return};\2\6 +${}\|p\K\\{right\_ptr};{}$\5 +${}\\{right\_ptr}\K\\{link}(\|p);{}$\5 +${}\\{free\_node}(\|p,\39\\{movement\_node\_size});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{616}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}\E\\{cur\_h}$ +or $\\{dvi\_v}\E\\{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\B\4\D$\\{synch\_h}$ \6 +\&{if} ${}(\\{cur\_h}\I\\{dvi\_h}){}$\5 +${}\{{}$\5 +\1${}\\{movement}(\\{cur\_h}-\\{dvi\_h},\39\\{right1});{}$\5 +${}\\{dvi\_h}\K\\{cur\_h};{}$\6 +\4${}\}{}$\2\par +\B\4\D$\\{synch\_v}$ \6 +\&{if} ${}(\\{cur\_v}\I\\{dvi\_v}){}$\5 +${}\{{}$\5 +\1${}\\{movement}(\\{cur\_v}-\\{dvi\_v},\39\\{down1});{}$\5 +${}\\{dvi\_v}\K\\{cur\_v};{}$\6 +\4${}\}{}$\2\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{scaled} \\{dvi\_h}${},{}$ \\{dvi\_v};\C{a \.{DVI} reader program thinks we are here}\6 +\&{scaled} \\{cur\_h}${},{}$ \\{cur\_v};\C{\TeX\ thinks we are here}\6 +\&{internal\_font\_number} \\{dvi\_f};\C{the current font}\6 +\&{int} \\{cur\_s};\C{current depth of output box nesting, initially $-1$}\par +\fi + +\M{617}\B\X617:Initialize variables as \\{ship\_out} begins\X${}\E{}$\6 +$\\{dvi\_h}\K\T{0};{}$\5 +${}\\{dvi\_v}\K\T{0};{}$\5 +${}\\{cur\_h}\K\\{h\_offset};{}$\5 +${}\\{dvi\_f}\K\\{null\_font};{}$\5 +\X531:ensure dvi open\X;\6 +\&{if} ${}(\\{total\_pages}\E\T{0}){}$\5 +${}\{{}$\5 +\1\\{dvi\_out}(\\{pre});\5 +\\{dvi\_out}(\\{id\_byte});\C{output the preamble}\6 +\\{dvi\_four}(\T{25400000});\5 +\\{dvi\_four}(\T{473628672});\C{conversion ratio for sp}\6 +\\{prepare\_mag}(\,);\5 +\\{dvi\_four}(\\{mag});\C{magnification factor is frozen}\6 +${}\\{old\_setting}\K\\{selector};{}$\5 +${}\\{selector}\K\\{new\_string};{}$\5 +\\{print\_str}(\.{"\ 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}/\T{60});{}$\5 +${}\\{print\_two}(\\{time}\MOD\T{60});{}$\5 +${}\\{selector}\K\\{old\_setting};{}$\5 +\\{dvi\_out}(\\{cur\_length});\6 +\&{for} ${}(\|s\K\\{str\_start}[\\{str\_ptr}];{}$ ${}\|s\Z\\{pool\_ptr}-\T{1};{}$ ${}\|s\PP){}$\1\5 +\\{dvi\_out}(\\{so}(\\{str\_pool}[\|s]));\2\6 +${}\\{pool\_ptr}\K\\{str\_start}[\\{str\_ptr}]{}$;\C{flush the current string}\6 +\4${}\}{}$\2\par +\U640.\fi + +\M{618}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\B\&{void} \\{vlist\_out}(\&{void});\C{\\{hlist\_out} and \\{vlist\_out} are mutually recursive}\par +\fi + +\M{619}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\B\hbox{\4}\X1368:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X\hbox{}\1\1\6 +\&{void} \\{hlist\_out}(\&{void})\C{output an \\{hlist\_node} box}\6 +${}\{{}$\5 +\1\&{scaled} \\{base\_line};\C{the baseline coordinate for this box}\6 +\&{scaled} \\{left\_edge};\C{the left coordinate for this box}\6 +\&{scaled} \\{save\_h}${},{}$ \\{save\_v};\C{what \\{dvi\_h} and \\{dvi\_v} should pop to}\6 +\&{pointer} \\{this\_box};\C{pointer to containing box}\6 +\&{glue\_ord} \\{g\_order};\C{applicable order of infinity for glue}\6 +\&{uint8\_t} \\{g\_sign};\C{selects type of glue}\6 +\&{pointer} \|p;\C{current position in the hlist}\6 +\&{int} \\{save\_loc};\C{\.{DVI} byte location upon entry}\6 +\&{pointer} \\{leader\_box};\C{the leader box being replicated}\6 +\&{scaled} \\{leader\_wd};\C{width of leader box being replicated}\6 +\&{scaled} \\{lx};\C{extra space between leader boxes}\6 +\&{bool} \\{outer\_doing\_leaders};\C{were we doing leaders?}\6 +\&{scaled} \\{edge};\C{left edge of sub-box, or right edge of leader space}\6 +\&{double} \\{glue\_temp};\C{glue value before rounding}\6 +\&{double} \\{cur\_glue};\C{glue seen so far}\6 +\&{scaled} \\{cur\_g};\C{rounded equivalent of \\{cur\_glue} times the glue ratio}\7 +${}\\{cur\_g}\K\T{0};{}$\5 +${}\\{cur\_glue}\K\\{float\_constant}(\T{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}>\T{0}){}$\1\5 +\\{dvi\_out}(\\{push});\2\6 +\&{if} ${}(\\{cur\_s}>\\{max\_push}){}$\1\5 +${}\\{max\_push}\K\\{cur\_s};{}$\2\6 +${}\\{save\_loc}\K\\{dvi\_offset}+\\{dvi\_ptr};{}$\5 +${}\\{base\_line}\K\\{cur\_v};{}$\5 +${}\\{left\_edge}\K\\{cur\_h};{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\1\5 +\X620:Output node \|p for \\{hlist\_out} and move to the next node, maintaining the condition $\\{cur\_v}\K\\{base\_line}$\X;\2\6 +\\{prune\_movements}(\\{save\_loc});\6 +\&{if} ${}(\\{cur\_s}>\T{0}){}$\1\5 +\\{dvi\_pop}(\\{save\_loc});\2\6 +\\{decr}(\\{cur\_s});\6 +\4${}\}{}$\2\par +\fi + +\M{620}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}\E\T{0}$. + +\Y\B\4\X620:Output node \|p for \\{hlist\_out} and move to the next node, maintaining the condition $\\{cur\_v}\K\\{base\_line}$\X${}\E{}$\6 +\4\\{reswitch}:\6 +\&{if} (\\{is\_char\_node}(\|p))\5 +${}\{{}$\5 +\1\\{synch\_h};\5 +\\{synch\_v};\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|f\K\\{font}(\|p);{}$\5 +${}\|c\K\\{character}(\|p);{}$\6 +\&{if} ${}(\|f\I\\{dvi\_f}){}$\1\5 +\X621:Change font \\{dvi\_f} to \|f\X;\2\6 +\&{if} ${}(\|c\G\\{qi}(\T{128})){}$\1\5 +\\{dvi\_out}(\\{set1});\2\6 +\\{dvi\_out}(\\{qo}(\|c));\6 +${}\\{cur\_h}\K\\{cur\_h}+\\{char\_width}(\|f)(\\{char\_info}(\|f)(\|c));{}$\5 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\R\\{is\_char\_node}(\|p)));{}$\5 +${}\\{dvi\_h}\K\\{cur\_h};{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\X622:Output the non-\\{char\_node} \|p for \\{hlist\_out} and move to the next node\X\2\par +\U619.\fi + +\M{621}\B\X621:Change font \\{dvi\_f} to \|f\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\R\\{font\_used}[\|f]){}$\5 +${}\{{}$\5 +\1\\{dvi\_font\_def}(\|f);\5 +${}\\{font\_used}[\|f]\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|f\Z\T{64}+\\{font\_base}){}$\1\5 +${}\\{dvi\_out}(\|f-\\{font\_base}-\T{1}+\\{fnt\_num\_0}){}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{dvi\_out}(\\{fnt1});\5 +${}\\{dvi\_out}(\|f-\\{font\_base}-\T{1});{}$\6 +\4${}\}{}$\2\6 +${}\\{dvi\_f}\K\|f;{}$\6 +\4${}\}{}$\2\par +\U620.\fi + +\M{622}\B\X622:Output the non-\\{char\_node} \|p for \\{hlist\_out} and move to the next node\X${}\E{}$\6 +${}\{{}$\5 +\1\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\X623:Output a box in an hlist\X\5 +\&{break};\6 +\4\&{case} \\{rule\_node}:\6 +${}\{{}$\5 +\1${}\\{rule\_ht}\K\\{height}(\|p);{}$\5 +${}\\{rule\_dp}\K\\{depth}(\|p);{}$\5 +${}\\{rule\_wd}\K\\{width}(\|p);{}$\5 +\&{goto} \\{fin\_rule};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1367:Output the whatsit node \|p in an hlist\X;\5 +\&{break};\6 +\4\&{case} \\{glue\_node}:\5 +\X625:Move right or output leaders\X\6 +\4\&{case} \\{kern\_node}:\5 +\&{case} \\{math\_node}:\5 +${}\\{cur\_h}\K\\{cur\_h}+\\{width}(\|p){}$;\5 +\&{break};\6 +\4\&{case} \\{ligature\_node}:\5 +\X652:Make node \|p look like a \\{char\_node} and \&{goto} \\{reswitch}\X\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\6 +\&{goto} \\{next\_p};\6 +\4\\{fin\_rule}:\5 +\X624:Output a rule in an hlist\X;\6 +\4\\{move\_past}:\5 +${}\\{cur\_h}\K\\{cur\_h}+\\{rule\_wd};{}$\6 +\4\\{next\_p}:\5 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\par +\U620.\fi + +\M{623}\B\X623:Output a box in an hlist\X${}\E{}$\6 +\&{if} ${}(\\{list\_ptr}(\|p)\E\\{null}){}$\1\5 +${}\\{cur\_h}\K\\{cur\_h}+\\{width}(\|p);{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{save\_h}\K\\{dvi\_h};{}$\5 +${}\\{save\_v}\K\\{dvi\_v};{}$\5 +${}\\{cur\_v}\K\\{base\_line}+\\{shift\_amount}(\|p){}$;\C{shift the box down}\6 +${}\\{temp\_ptr}\K\|p;{}$\5 +${}\\{edge}\K\\{cur\_h};{}$\6 +\&{if} ${}(\\{type}(\|p)\E\\{vlist\_node}){}$\1\5 +\\{vlist\_out}(\,);\5 +\2\&{else}\1\5 +\\{hlist\_out}(\,);\2\6 +${}\\{dvi\_h}\K\\{save\_h};{}$\5 +${}\\{dvi\_v}\K\\{save\_v};{}$\5 +${}\\{cur\_h}\K\\{edge}+\\{width}(\|p);{}$\5 +${}\\{cur\_v}\K\\{base\_line};{}$\6 +\4${}\}{}$\2\par +\U622.\fi + +\M{624}\B\X624:Output a rule in an hlist\X${}\E{}$\6 +\&{if} (\\{is\_running}(\\{rule\_ht}))\1\5 +${}\\{rule\_ht}\K\\{height}(\\{this\_box});{}$\2\6 +\&{if} (\\{is\_running}(\\{rule\_dp}))\1\5 +${}\\{rule\_dp}\K\\{depth}(\\{this\_box});{}$\2\6 +${}\\{rule\_ht}\K\\{rule\_ht}+\\{rule\_dp}{}$;\C{this is the rule thickness}\6 +\&{if} ${}((\\{rule\_ht}>\T{0})\W(\\{rule\_wd}>\T{0}){}$)\C{we don't output empty rules}\6 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\par +\U622.\fi + +\M{625}\B\D$\\{billion}$ \5 +\\{float\_constant}(\T{1000000000})\par +\B\4\D$\\{vet\_glue}(\|X)$ \5 +$\\{glue\_temp}\K\|X;$ \6 +\&{if} ${}(\\{glue\_temp}>\\{billion}){}$\1\5 +${}\\{glue\_temp}\K\\{billion};{}$\2\6 +\&{else} \&{if} ${}(\\{glue\_temp}<{-}\\{billion})$ $\\{glue\_temp}\K{-}{}$\\{billion}\par +\Y\B\4\X625:Move right or output leaders\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|g\K\\{glue\_ptr}(\|p);{}$\5 +${}\\{rule\_wd}\K\\{width}(\|g)-\\{cur\_g};{}$\6 +\&{if} ${}(\\{g\_sign}\I\\{normal}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{g\_sign}\E\\{stretching}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{stretch\_order}(\|g)\E\\{g\_order}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_glue}\K\\{cur\_glue}+\\{stretch}(\|g);{}$\5 +${}\\{vet\_glue}(\&{float}(\\{glue\_set}(\\{this\_box}))*\\{cur\_glue});{}$\5 +${}\\{cur\_g}\K\\{round}(\\{glue\_temp});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{shrink\_order}(\|g)\E\\{g\_order}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_glue}\K\\{cur\_glue}-\\{shrink}(\|g);{}$\5 +${}\\{vet\_glue}(\&{float}(\\{glue\_set}(\\{this\_box}))*\\{cur\_glue});{}$\5 +${}\\{cur\_g}\K\\{round}(\\{glue\_temp});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +${}\\{rule\_wd}\K\\{rule\_wd}+\\{cur\_g};{}$\6 +\&{if} ${}(\\{subtype}(\|p)\G\\{a\_leaders}){}$\1\5 +\X626:Output leaders in an hlist, \&{goto} \\{fin\_rule} if a rule or to \\{next\_p} if done\X;\2\6 +\&{goto} \\{move\_past};\6 +\4${}\}{}$\2\par +\U622.\fi + +\M{626}\B\X626:Output leaders in an hlist, \&{goto} \\{fin\_rule} if a rule or to \\{next\_p} if done\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{leader\_box}\K\\{leader\_ptr}(\|p);{}$\6 +\&{if} ${}(\\{type}(\\{leader\_box})\E\\{rule\_node}){}$\5 +${}\{{}$\5 +\1${}\\{rule\_ht}\K\\{height}(\\{leader\_box});{}$\5 +${}\\{rule\_dp}\K\\{depth}(\\{leader\_box});{}$\5 +\&{goto} \\{fin\_rule};\6 +\4${}\}{}$\2\6 +${}\\{leader\_wd}\K\\{width}(\\{leader\_box});{}$\6 +\&{if} ${}((\\{leader\_wd}>\T{0})\W(\\{rule\_wd}>\T{0})){}$\5 +${}\{{}$\5 +\1${}\\{rule\_wd}\K\\{rule\_wd}+\T{10}{}$;\C{compensate for floating-point rounding}\6 +${}\\{edge}\K\\{cur\_h}+\\{rule\_wd};{}$\5 +${}\\{lx}\K\T{0};{}$\5 +\X627: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}\Z\\{edge}){}$\1\5 +\X628:Output a leader box at \\{cur\_h}, then advance \\{cur\_h} by $\\{leader\_wd}+\\{lx}$\X;\2\6 +${}\\{cur\_h}\K\\{edge}-\T{10};{}$\5 +\&{goto} \\{next\_p};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U625.\fi + +\M{627}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 $/$ 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\B\4\X627:Let \\{cur\_h} be the position of the first box, and set $\\{leader\_wd}+\\{lx}$ to the spacing between corresponding parts of boxes\X${}\E{}$\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{a\_leaders}){}$\5 +${}\{{}$\5 +\1${}\\{save\_h}\K\\{cur\_h};{}$\5 +${}\\{cur\_h}\K\\{left\_edge}+\\{leader\_wd}*((\\{cur\_h}-\\{left\_edge})/\\{leader\_wd});{}$\6 +\&{if} ${}(\\{cur\_h}<\\{save\_h}){}$\1\5 +${}\\{cur\_h}\K\\{cur\_h}+\\{leader\_wd};{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{lq}\K\\{rule\_wd}/\\{leader\_wd}{}$;\C{the number of box copies}\6 +${}\\{lr}\K\\{rule\_wd}\MOD\\{leader\_wd}{}$;\C{the remaining space}\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{c\_leaders}){}$\1\5 +${}\\{cur\_h}\K\\{cur\_h}+(\\{lr}/\T{2});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{lx}\K\\{lr}/(\\{lq}+\T{1});{}$\5 +${}\\{cur\_h}\K\\{cur\_h}+((\\{lr}-(\\{lq}-\T{1})*\\{lx})/\T{2});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U626.\fi + +\M{628}The `\\{synch}' operations here are intended to decrease the number of +bytes needed to specify horizontal and vertical motion in the \.{DVI} output. + +\Y\B\4\X628:Output a leader box at \\{cur\_h}, then advance \\{cur\_h} by $\\{leader\_wd}+\\{lx}$\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{cur\_v}\K\\{base\_line}+\\{shift\_amount}(\\{leader\_box});{}$\5 +\\{synch\_v};\5 +${}\\{save\_v}\K\\{dvi\_v}{}$;\6 +\\{synch\_h};\5 +${}\\{save\_h}\K\\{dvi\_h};{}$\5 +${}\\{temp\_ptr}\K\\{leader\_box};{}$\5 +${}\\{outer\_doing\_leaders}\K\\{doing\_leaders};{}$\5 +${}\\{doing\_leaders}\K\\{true};{}$\6 +\&{if} ${}(\\{type}(\\{leader\_box})\E\\{vlist\_node}){}$\1\5 +\\{vlist\_out}(\,);\5 +\2\&{else}\1\5 +\\{hlist\_out}(\,);\2\6 +${}\\{doing\_leaders}\K\\{outer\_doing\_leaders};{}$\5 +${}\\{dvi\_v}\K\\{save\_v};{}$\5 +${}\\{dvi\_h}\K\\{save\_h};{}$\5 +${}\\{cur\_v}\K\\{base\_line};{}$\5 +${}\\{cur\_h}\K\\{save\_h}+\\{leader\_wd}+\\{lx};{}$\6 +\4${}\}{}$\2\par +\U626.\fi + +\M{629}The \\{vlist\_out} routine is similar to \\{hlist\_out}, but a bit simpler. + +\Y\B\&{void} \\{vlist\_out}(\&{void})\C{output a \\{vlist\_node} box}\6 +${}\{{}$\5 +\1\&{scaled} \\{left\_edge};\C{the left coordinate for this box}\6 +\&{scaled} \\{top\_edge};\C{the top coordinate for this box}\6 +\&{scaled} \\{save\_h}${},{}$ \\{save\_v};\C{what \\{dvi\_h} and \\{dvi\_v} should pop to}\6 +\&{pointer} \\{this\_box};\C{pointer to containing box}\6 +\&{glue\_ord} \\{g\_order};\C{applicable order of infinity for glue}\6 +\&{uint8\_t} \\{g\_sign};\C{selects type of glue}\6 +\&{pointer} \|p;\C{current position in the vlist}\6 +\&{int} \\{save\_loc};\C{\.{DVI} byte location upon entry}\6 +\&{pointer} \\{leader\_box};\C{the leader box being replicated}\6 +\&{scaled} \\{leader\_ht};\C{height of leader box being replicated}\6 +\&{scaled} \\{lx};\C{extra space between leader boxes}\6 +\&{bool} \\{outer\_doing\_leaders};\C{were we doing leaders?}\6 +\&{scaled} \\{edge};\C{bottom boundary of leader space}\6 +\&{double} \\{glue\_temp};\C{glue value before rounding}\6 +\&{double} \\{cur\_glue};\C{glue seen so far}\6 +\&{scaled} \\{cur\_g};\C{rounded equivalent of \\{cur\_glue} times the glue ratio}\7 +${}\\{cur\_g}\K\T{0};{}$\5 +${}\\{cur\_glue}\K\\{float\_constant}(\T{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}>\T{0}){}$\1\5 +\\{dvi\_out}(\\{push});\2\6 +\&{if} ${}(\\{cur\_s}>\\{max\_push}){}$\1\5 +${}\\{max\_push}\K\\{cur\_s};{}$\2\6 +${}\\{save\_loc}\K\\{dvi\_offset}+\\{dvi\_ptr};{}$\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\5 +\X630:Output node \|p for \\{vlist\_out} and move to the next node, maintaining the condition $\\{cur\_h}\K\\{left\_edge}$\X;\2\6 +\\{prune\_movements}(\\{save\_loc});\6 +\&{if} ${}(\\{cur\_s}>\T{0}){}$\1\5 +\\{dvi\_pop}(\\{save\_loc});\2\6 +\\{decr}(\\{cur\_s});\6 +\4${}\}{}$\2\par +\fi + +\M{630}\B\X630:Output node \|p for \\{vlist\_out} and move to the next node, maintaining the condition $\\{cur\_h}\K\\{left\_edge}$\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} (\\{is\_char\_node}(\|p))\1\5 +\\{confusion}(\X1641:\.{"vlistout"}\X);\2\6 +\&{else}\1\5 +\X631:Output the non-\\{char\_node} \|p for \\{vlist\_out}\X;\2\6 +\4\\{next\_p}:\5 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\par +\U629.\fi + +\M{631}\B\X631:Output the non-\\{char\_node} \|p for \\{vlist\_out}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\X632:Output a box in a vlist\X\5 +\&{break};\6 +\4\&{case} \\{rule\_node}:\6 +${}\{{}$\5 +\1${}\\{rule\_ht}\K\\{height}(\|p);{}$\5 +${}\\{rule\_dp}\K\\{depth}(\|p);{}$\5 +${}\\{rule\_wd}\K\\{width}(\|p);{}$\5 +\&{goto} \\{fin\_rule};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1366:Output the whatsit node \|p in a vlist\X;\5 +\&{break};\6 +\4\&{case} \\{glue\_node}:\5 +\X634:Move down or output leaders\X\6 +\4\&{case} \\{kern\_node}:\5 +${}\\{cur\_v}\K\\{cur\_v}+\\{width}(\|p){}$;\5 +\&{break};\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\6 +\&{goto} \\{next\_p};\6 +\4\\{fin\_rule}:\5 +\X633:Output a rule in a vlist, \&{goto} \\{next\_p}\X;\6 +\4\\{move\_past}:\5 +${}\\{cur\_v}\K\\{cur\_v}+\\{rule\_ht};{}$\6 +\4${}\}{}$\2\par +\U630.\fi + +\M{632}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\B\4\X632:Output a box in a vlist\X${}\E{}$\6 +\&{if} ${}(\\{list\_ptr}(\|p)\E\\{null}){}$\1\5 +${}\\{cur\_v}\K\\{cur\_v}+\\{height}(\|p)+\\{depth}(\|p);{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_v}\K\\{cur\_v}+\\{height}(\|p);{}$\5 +\\{synch\_v};\5 +${}\\{save\_h}\K\\{dvi\_h};{}$\5 +${}\\{save\_v}\K\\{dvi\_v};{}$\5 +${}\\{cur\_h}\K\\{left\_edge}+\\{shift\_amount}(\|p){}$;\C{shift the box right}\6 +${}\\{temp\_ptr}\K\|p;{}$\6 +\&{if} ${}(\\{type}(\|p)\E\\{vlist\_node}){}$\1\5 +\\{vlist\_out}(\,);\5 +\2\&{else}\1\5 +\\{hlist\_out}(\,);\2\6 +${}\\{dvi\_h}\K\\{save\_h};{}$\5 +${}\\{dvi\_v}\K\\{save\_v};{}$\5 +${}\\{cur\_v}\K\\{save\_v}+\\{depth}(\|p);{}$\5 +${}\\{cur\_h}\K\\{left\_edge};{}$\6 +\4${}\}{}$\2\par +\U631.\fi + +\M{633}\B\X633:Output a rule in a vlist, \&{goto} \\{next\_p}\X${}\E{}$\6 +\&{if} (\\{is\_running}(\\{rule\_wd}))\1\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}>\T{0})\W(\\{rule\_wd}>\T{0}){}$)\C{we don't output empty rules}\6 +${}\{{}$\5 +\1\\{synch\_h};\5 +\\{synch\_v};\5 +\\{dvi\_out}(\\{put\_rule});\5 +\\{dvi\_four}(\\{rule\_ht});\5 +\\{dvi\_four}(\\{rule\_wd});\6 +\4${}\}{}$\2\6 +\&{goto} \\{next\_p}\par +\U631.\fi + +\M{634}\B\X634:Move down or output leaders\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|g\K\\{glue\_ptr}(\|p);{}$\5 +${}\\{rule\_ht}\K\\{width}(\|g)-\\{cur\_g};{}$\6 +\&{if} ${}(\\{g\_sign}\I\\{normal}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{g\_sign}\E\\{stretching}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{stretch\_order}(\|g)\E\\{g\_order}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_glue}\K\\{cur\_glue}+\\{stretch}(\|g);{}$\5 +${}\\{vet\_glue}(\&{float}(\\{glue\_set}(\\{this\_box}))*\\{cur\_glue});{}$\5 +${}\\{cur\_g}\K\\{round}(\\{glue\_temp});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{shrink\_order}(\|g)\E\\{g\_order}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_glue}\K\\{cur\_glue}-\\{shrink}(\|g);{}$\5 +${}\\{vet\_glue}(\&{float}(\\{glue\_set}(\\{this\_box}))*\\{cur\_glue});{}$\5 +${}\\{cur\_g}\K\\{round}(\\{glue\_temp});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +${}\\{rule\_ht}\K\\{rule\_ht}+\\{cur\_g};{}$\6 +\&{if} ${}(\\{subtype}(\|p)\G\\{a\_leaders}){}$\1\5 +\X635:Output leaders in a vlist, \&{goto} \\{fin\_rule} if a rule or to \\{next\_p} if done\X;\2\6 +\&{goto} \\{move\_past};\6 +\4${}\}{}$\2\par +\U631.\fi + +\M{635}\B\X635:Output leaders in a vlist, \&{goto} \\{fin\_rule} if a rule or to \\{next\_p} if done\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{leader\_box}\K\\{leader\_ptr}(\|p);{}$\6 +\&{if} ${}(\\{type}(\\{leader\_box})\E\\{rule\_node}){}$\5 +${}\{{}$\5 +\1${}\\{rule\_wd}\K\\{width}(\\{leader\_box});{}$\5 +${}\\{rule\_dp}\K\T{0};{}$\5 +\&{goto} \\{fin\_rule};\6 +\4${}\}{}$\2\6 +${}\\{leader\_ht}\K\\{height}(\\{leader\_box})+\\{depth}(\\{leader\_box});{}$\6 +\&{if} ${}((\\{leader\_ht}>\T{0})\W(\\{rule\_ht}>\T{0})){}$\5 +${}\{{}$\5 +\1${}\\{rule\_ht}\K\\{rule\_ht}+\T{10}{}$;\C{compensate for floating-point rounding}\6 +${}\\{edge}\K\\{cur\_v}+\\{rule\_ht};{}$\5 +${}\\{lx}\K\T{0};{}$\5 +\X636: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}\Z\\{edge}){}$\1\5 +\X637:Output a leader box at \\{cur\_v}, then advance \\{cur\_v} by $\\{leader\_ht}+\\{lx}$\X;\2\6 +${}\\{cur\_v}\K\\{edge}-\T{10};{}$\5 +\&{goto} \\{next\_p};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U634.\fi + +\M{636}\B\X636:Let \\{cur\_v} be the position of the first box, and set $\\{leader\_ht}+\\{lx}$ to the spacing between corresponding parts of boxes\X${}\E{}$\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{a\_leaders}){}$\5 +${}\{{}$\5 +\1${}\\{save\_v}\K\\{cur\_v};{}$\5 +${}\\{cur\_v}\K\\{top\_edge}+\\{leader\_ht}*((\\{cur\_v}-\\{top\_edge})/\\{leader\_ht});{}$\6 +\&{if} ${}(\\{cur\_v}<\\{save\_v}){}$\1\5 +${}\\{cur\_v}\K\\{cur\_v}+\\{leader\_ht};{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{lq}\K\\{rule\_ht}/\\{leader\_ht}{}$;\C{the number of box copies}\6 +${}\\{lr}\K\\{rule\_ht}\MOD\\{leader\_ht}{}$;\C{the remaining space}\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{c\_leaders}){}$\1\5 +${}\\{cur\_v}\K\\{cur\_v}+(\\{lr}/\T{2});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{lx}\K\\{lr}/(\\{lq}+\T{1});{}$\5 +${}\\{cur\_v}\K\\{cur\_v}+((\\{lr}-(\\{lq}-\T{1})*\\{lx})/\T{2});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U635.\fi + +\M{637}When we reach this part of the program, \\{cur\_v} indicates the top of a +leader box, not its baseline. + +\Y\B\4\X637:Output a leader box at \\{cur\_v}, then advance \\{cur\_v} by $\\{leader\_ht}+\\{lx}$\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{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 +${}\\{temp\_ptr}\K\\{leader\_box};{}$\5 +${}\\{outer\_doing\_leaders}\K\\{doing\_leaders};{}$\5 +${}\\{doing\_leaders}\K\\{true};{}$\6 +\&{if} ${}(\\{type}(\\{leader\_box})\E\\{vlist\_node}){}$\1\5 +\\{vlist\_out}(\,);\5 +\2\&{else}\1\5 +\\{hlist\_out}(\,);\2\6 +${}\\{doing\_leaders}\K\\{outer\_doing\_leaders};{}$\5 +${}\\{dvi\_v}\K\\{save\_v};{}$\5 +${}\\{dvi\_h}\K\\{save\_h};{}$\5 +${}\\{cur\_h}\K\\{left\_edge};{}$\5 +${}\\{cur\_v}\K\\{save\_v}-\\{height}(\\{leader\_box})+\\{leader\_ht}+\\{lx};{}$\6 +\4${}\}{}$\2\par +\U635.\fi + +\M{638}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\B\&{void} \\{ship\_out}(\&{pointer} \|p)\C{output the box \|p}\6 +${}\{{}$\5 +\1\&{int} \\{page\_loc};\C{location of the current \\{bop}}\6 +\&{uint8\_t} \|j${},{}$ \|k;\C{indices to first ten count registers}\6 +\&{int} \|s;\C{index into \\{str\_pool}}\6 +\&{uint8\_t} \\{old\_setting};\C{saved \\{selector} setting}\7 +\&{if} ${}(\\{tracing\_output}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{""});\5 +\\{print\_ln}(\,);\5 +\\{print\_str}(\.{"Completed\ box\ being}\)\.{\ shipped\ out"});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{term\_offset}>\\{max\_print\_line}-\T{9}){}$\1\5 +\\{print\_ln}(\,);\2\6 +\&{else} \&{if} ${}((\\{term\_offset}>\T{0})\V(\\{file\_offset}>\T{0})){}$\1\5 +\\{print\_char}(\.{'\ '});\2\6 +\\{print\_char}(\.{'['});\5 +${}\|j\K\T{9};{}$\6 +\&{while} ${}((\\{count}(\|j)\E\T{0})\W(\|j>\T{0})){}$\1\5 +\\{decr}(\|j);\2\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\|j;{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1\\{print\_int}(\\{count}(\|k));\6 +\&{if} ${}(\|k<\|j){}$\1\5 +\\{print\_char}(\.{'.'});\2\6 +\4${}\}{}$\2\6 +\\{update\_terminal};\6 +\&{if} ${}(\\{tracing\_output}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_char}(\.{']'});\5 +\\{begin\_diagnostic}(\,);\5 +\\{show\_box}(\|p);\5 +\\{end\_diagnostic}(\\{true});\6 +\4${}\}{}$\2\6 +\X640:Ship box \|p out\X;\6 +\&{if} ${}(\\{tracing\_output}\Z\T{0}){}$\1\5 +\\{print\_char}(\.{']'});\2\6 +${}\\{dead\_cycles}\K\T{0};{}$\5 +\\{update\_terminal};\C{progress report}\6 +\X639:Flush the box from memory, showing statistics if requested\X;\6 +\4${}\}{}$\2\par +\fi + +\M{639}\B\X639:Flush the box from memory, showing statistics if requested\X${}\E{}$\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_stats}>\T{1}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"Memory\ usage\ before}\)\.{:\ "});\5 +\\{print\_int}(\\{var\_used});\5 +\\{print\_char}(\.{'\&'});\5 +\\{print\_int}(\\{dyn\_used});\5 +\\{print\_char}(\.{';'});\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\6 +\\{flush\_node\_list}(\|p);\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_stats}>\T{1}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ after:\ "});\5 +\\{print\_int}(\\{var\_used});\5 +\\{print\_char}(\.{'\&'});\5 +\\{print\_int}(\\{dyn\_used});\5 +\\{print\_str}(\.{";\ still\ untouched:\ }\)\.{"});\5 +${}\\{print\_int}(\\{hi\_mem\_min}-\\{lo\_mem\_max}-\T{1});{}$\5 +\\{print\_ln}(\,);\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\U638.\fi + +\M{640}\B\X640:Ship box \|p out\X${}\E{}$\6 +\X641:Update the values of \\{max\_h} and \\{max\_v}; but if the page is too large, \&{goto} \\{done}\X;\6 +\X617:Initialize variables as \\{ship\_out} begins\X;\6 +${}\\{page\_loc}\K\\{dvi\_offset}+\\{dvi\_ptr};{}$\5 +\\{dvi\_out}(\\{bop});\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{9};{}$ ${}\|k\PP){}$\1\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 +\&{if} ${}(\\{type}(\|p)\E\\{vlist\_node}){}$\1\5 +\\{vlist\_out}(\,);\5 +\2\&{else}\1\5 +\\{hlist\_out}(\,);\2\6 +\\{dvi\_out}(\\{eop});\5 +\\{incr}(\\{total\_pages});\5 +${}\\{cur\_s}\K{-}\T{1};$ \\{done}:\par +\U638.\fi + +\M{641}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\B\4\X641:Update the values of \\{max\_h} and \\{max\_v}; but if the page is too large, \&{goto} \\{done}\X${}\E{}$\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})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Huge\ page\ cannot\ be}\)\.{\ shipped\ out"});\5 +\\{help2}(\.{"The\ page\ just\ creat}\)\.{ed\ is\ more\ than\ 18\ f}\)\.{eet\ tall\ or"})\6 +(\.{"more\ than\ 18\ feet\ w}\)\.{ide,\ so\ I\ suspect\ so}\)\.{mething\ went\ wrong."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{if} ${}(\\{tracing\_output}\Z\T{0}){}$\5 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{"The\ following\ box\ h}\)\.{as\ been\ deleted:"});\5 +\\{show\_box}(\|p);\5 +\\{end\_diagnostic}(\\{true});\6 +\4${}\}{}$\2\6 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{height}(\|p)+\\{depth}(\|p)+\\{v\_offset}>\\{max\_v}){}$\1\5 +${}\\{max\_v}\K\\{height}(\|p)+\\{depth}(\|p)+\\{v\_offset};{}$\2\6 +\&{if} ${}(\\{width}(\|p)+\\{h\_offset}>\\{max\_h})$ $\\{max\_h}\K\\{width}(\|p)+{}$\\{h\_offset}\par +\U640.\fi + +\M{642}At the end of the program, we must finish things off by writing the +post\-amble. If $\\{total\_pages}\E\T{0}$, the \.{DVI} file was never opened. +If $\\{total\_pages}\G\T{65536}$, the \.{DVI} file will lie. And if +$\\{max\_push}\G\T{65536}$, the user deserves whatever chaos might ensue. + +An integer variable \|k will be declared for use by this routine. + +\Y\B\4\X642:Finish the \.{DVI} file\X${}\E{}$\6 +\&{while} ${}(\\{cur\_s}>{-}\T{1}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_s}>\T{0}){}$\1\5 +\\{dvi\_out}(\\{pop})\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{dvi\_out}(\\{eop});\5 +\\{incr}(\\{total\_pages});\6 +\4${}\}{}$\2\6 +\\{decr}(\\{cur\_s});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{total\_pages}\E\T{0}){}$\1\5 +\\{print\_nl}(\.{"No\ pages\ of\ output.}\)\.{"});\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{dvi\_out}(\\{post});\C{beginning of the postamble}\6 +\\{dvi\_four}(\\{last\_bop});\5 +${}\\{last\_bop}\K\\{dvi\_offset}+\\{dvi\_ptr}-\T{5}{}$;\C{\\{post} location}\6 +\\{dvi\_four}(\T{25400000});\5 +\\{dvi\_four}(\T{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}/\T{256});{}$\5 +${}\\{dvi\_out}(\\{max\_push}\MOD\T{256}){}$;\6 +${}\\{dvi\_out}((\\{total\_pages}/\T{256})\MOD\T{256});{}$\5 +${}\\{dvi\_out}(\\{total\_pages}\MOD\T{256}){}$;\6 +\X643:Output the font definitions for all fonts that were used\X;\6 +\\{dvi\_out}(\\{post\_post});\5 +\\{dvi\_four}(\\{last\_bop});\5 +\\{dvi\_out}(\\{id\_byte});\6 +${}\|k\K\T{4}+((\\{dvi\_buf\_size}-\\{dvi\_ptr})\MOD\T{4}){}$;\C{the number of 223's}\6 +\&{while} ${}(\|k>\T{0}){}$\5 +${}\{{}$\5 +\1\\{dvi\_out}(\T{223});\5 +\\{decr}(\|k);\6 +\4${}\}{}$\2\6 +\X599:Empty the last bytes out of \\{dvi\_buf}\X;\6 +\\{print\_nl}(\.{"Output\ written\ on\ "});\5 +\\{slow\_print}(\\{output\_file\_name});\5 +\\{print\_str}(\.{"\ ("});\5 +\\{print\_int}(\\{total\_pages});\5 +\\{print\_str}(\.{"\ page"});\6 +\&{if} ${}(\\{total\_pages}\I\T{1}){}$\1\5 +\\{print\_char}(\.{'s'});\2\6 +\\{print\_str}(\.{",\ "});\5 +${}\\{print\_int}(\\{dvi\_offset}+\\{dvi\_ptr});{}$\5 +\\{print\_str}(\.{"\ bytes)."});\5 +${}\\{b\_close}({\AND}\\{dvi\_file});{}$\6 +\4${}\}{}$\2\par +\U1333.\fi + +\M{643}\B\X643:Output the font definitions for all fonts that were used\X${}\E{}$\6 +\&{while} ${}(\\{font\_ptr}>\\{font\_base}){}$\5 +${}\{{}$\5 +\1\&{if} (\\{font\_used}[\\{font\_ptr}])\1\5 +\\{dvi\_font\_def}(\\{font\_ptr});\2\6 +\\{decr}(\\{font\_ptr});\6 +\4${}\}{}$\2\par +\U642.\fi + +\N{1}{644}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\B\4\D$\\{exactly}$ \5 +\T{0}\C{a box dimension is pre-specified}\par +\B\4\D$\\{additional}$ \5 +\T{1}\C{a box dimension is increased from the natural one}\par +\B\4\D$\\{natural}$ \5 +$\T{0},\39{}$\\{additional}\C{shorthand for parameters to \\{hpack} and \\{vpack}}\par +\fi + +\M{645}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}-\T{2};$\cr +$\\{hpack}(\|p,\\{saved}(\T{1}),\\{saved}(\T{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\B\&{void} \\{scan\_spec}(\&{group\_code} \|c${},\39{}$\&{bool} \\{three\_codes})\C{scans a box specification and left brace}\6 +${}\{{}$\5 +\1\&{int} \|s;\C{temporarily saved value}\6 +\&{uint8\_t} \\{spec\_code};\7 +\&{if} (\\{three\_codes})\1\5 +${}\|s\K\\{saved}(\T{0});{}$\2\6 +\&{if} (\\{scan\_keyword}(\X1642:\.{"to"}\X))\1\5 +${}\\{spec\_code}\K\\{exactly};{}$\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1643:\.{"spread"}\X))\1\5 +${}\\{spec\_code}\K\\{additional};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{spec\_code}\K\\{additional};{}$\5 +${}\\{cur\_val}\K\T{0};{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\\{scan\_normal\_dimen};\6 +\4\\{found}:\6 +\&{if} (\\{three\_codes})\5 +${}\{{}$\5 +\1${}\\{saved}(\T{0})\K\|s;{}$\5 +\\{incr}(\\{save\_ptr});\6 +\4${}\}{}$\2\6 +${}\\{saved}(\T{0})\K\\{spec\_code};{}$\5 +${}\\{saved}(\T{1})\K\\{cur\_val};{}$\5 +${}\\{save\_ptr}\K\\{save\_ptr}+\T{2};{}$\5 +\\{new\_save\_level}(\|c);\5 +\\{scan\_left\_brace}(\,);\6 +\4${}\}{}$\2\par +\fi + +\M{646}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{scaled} ${}\\{total\_stretch0}[\\{filll}-\\{normal}+\T{1}],{}$ ${}{*\&{const}\ }\\{total\_stretch}\K\\{total\_stretch0}-\\{normal},{}$ ${}\\{total\_shrink0}[\\{filll}-\\{normal}+\T{1}],{}$ ${}{*\&{const}\ }\\{total\_shrink}\K\\{total\_shrink0}-% +\\{normal}{}$;\C{glue found by \\{hpack} or \\{vpack}}\6 +\&{int} \\{last\_badness};\C{badness of the most recently packaged box}\par +\fi + +\M{647}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{adjust\_tail};\C{tail of adjustment list}\par +\fi + +\M{648}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{adjust\_tail}\K\\{null};{}$\5 +${}\\{last\_badness}\K\T{0}{}$;\par +\fi + +\M{649}Here now is \\{hpack}, which contains few if any surprises. + +\Y\B\&{pointer} \\{hpack}(\&{pointer} \|p${},\39{}$\&{scaled} \|w${},\39{}$\&{small\_number} \|m)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|r;\C{the box node that will be returned}\6 +\&{pointer} \|q;\C{trails behind \|p}\6 +\&{scaled} \|h${},{}$ \|d${},{}$ \|x;\C{height, depth, and natural width}\6 +\&{scaled} \|s;\C{shift amount}\6 +\&{pointer} \|g;\C{points to a glue specification}\6 +\&{glue\_ord} \|o;\C{order of infinity}\6 +\&{internal\_font\_number} \|f;\C{the font in a \\{char\_node}}\6 +\&{four\_quarters} \|i;\C{font information about a \\{char\_node}}\6 +\&{eight\_bits} \\{hd};\C{height and depth indices for a character}\7 +${}\\{last\_badness}\K\T{0};{}$\5 +${}\|r\K\\{get\_node}(\\{box\_node\_size});{}$\5 +${}\\{type}(\|r)\K\\{hlist\_node};{}$\5 +${}\\{subtype}(\|r)\K\\{min\_quarterword};{}$\5 +${}\\{shift\_amount}(\|r)\K\T{0};{}$\5 +${}\|q\K\|r+\\{list\_offset};{}$\5 +${}\\{link}(\|q)\K\|p{}$;\6 +${}\|h\K\T{0};{}$\5 +\X650:Clear dimensions to zero\X;\6 +\&{while} ${}(\|p\I\\{null}){}$\1\5 +\X651: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\5 +${}\\{link}(\\{adjust\_tail})\K\\{null};{}$\2\6 +${}\\{height}(\|r)\K\|h;{}$\5 +${}\\{depth}(\|r)\K\|d{}$;\6 +\X657:Determine the value of \\{width}(\|r) and the appropriate glue setting; then \&{return} or \&{goto} \\{common\_ending}\X;\6 +\4\\{common\_ending}:\5 +\X663:Finish issuing a diagnostic message for an overfull or underfull hbox\X;\6 +\4\\{end}:\5 +\&{return} \|r;\6 +\4${}\}{}$\2\par +\fi + +\M{650}\B\X650:Clear dimensions to zero\X${}\E{}$\6 +$\|d\K\T{0};{}$\5 +${}\|x\K\T{0};{}$\5 +${}\\{total\_stretch}[\\{normal}]\K\T{0};{}$\5 +${}\\{total\_shrink}[\\{normal}]\K\T{0};{}$\5 +${}\\{total\_stretch}[\\{fil}]\K\T{0};{}$\5 +${}\\{total\_shrink}[\\{fil}]\K\T{0};{}$\5 +${}\\{total\_stretch}[\\{fill}]\K\T{0};{}$\5 +${}\\{total\_shrink}[\\{fill}]\K\T{0};{}$\5 +${}\\{total\_stretch}[\\{filll}]\K\T{0};$ $\\{total\_shrink}[\\{filll}]\K{}$\T{0}\par +\Us649\ET668.\fi + +\M{651}\B\X651: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${}\E{}$\6 +${}\{{}$\5 +\1\\{reswitch}:\6 +\&{while} (\\{is\_char\_node}(\|p))\1\5 +\X654: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}){}$\5 +${}\{{}$\5 +\1\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\5 +\&{case} \\{unset\_node}:\5 +\X653:Incorporate box dimensions into the dimensions of the hbox that will contain~it\X\5 +\&{break};\6 +\4\&{case} \\{ins\_node}:\5 +\&{case} \\{mark\_node}:\5 +\&{case} \\{adjust\_node}:\6 +\&{if} ${}(\\{adjust\_tail}\I\\{null}){}$\1\5 +\X655:Transfer node \|p to the adjustment list\X\5 +\2\&{break};\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1360:Incorporate a whatsit node into an hbox\X;\5 +\&{break};\6 +\4\&{case} \\{glue\_node}:\5 +\X656:Incorporate glue into the horizontal totals\X\5 +\&{break};\6 +\4\&{case} \\{kern\_node}:\5 +\&{case} \\{math\_node}:\5 +${}\|x\K\|x+\\{width}(\|p){}$;\5 +\&{break};\6 +\4\&{case} \\{ligature\_node}:\5 +\X652:Make node \|p look like a \\{char\_node} and \&{goto} \\{reswitch}\X\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U649.\fi + +\M{652}\B\X652:Make node \|p look like a \\{char\_node} and \&{goto} \\{reswitch}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{mem}[\\{lig\_trick}]\K\\{mem}[\\{lig\_char}(\|p)];{}$\5 +${}\\{link}(\\{lig\_trick})\K\\{link}(\|p);{}$\5 +${}\|p\K\\{lig\_trick};{}$\5 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\par +\Us622, 651\ETs1147.\fi + +\M{653}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\B\4\X653:Incorporate box dimensions into the dimensions of the hbox that will contain~it\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|x\K\|x+\\{width}(\|p);{}$\6 +\&{if} ${}(\\{type}(\|p)\G\\{rule\_node}){}$\1\5 +${}\|s\K\T{0}{}$;\5 +\2\&{else}\1\5 +${}\|s\K\\{shift\_amount}(\|p);{}$\2\6 +\&{if} ${}(\\{height}(\|p)-\|s>\|h){}$\1\5 +${}\|h\K\\{height}(\|p)-\|s;{}$\2\6 +\&{if} ${}(\\{depth}(\|p)+\|s>\|d){}$\1\5 +${}\|d\K\\{depth}(\|p)+\|s;{}$\2\6 +\4${}\}{}$\2\par +\U651.\fi + +\M{654}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\B\4\X654:Incorporate character dimensions into the dimensions of the hbox that will contain~it, then move to the next node\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|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}){}$;\5 +\&{if} ${}(\|s>\|h){}$\1\5 +${}\|h\K\|s;{}$\2\6 +${}\|s\K\\{char\_depth}(\|f)(\\{hd}){}$;\5 +\&{if} ${}(\|s>\|d){}$\1\5 +${}\|d\K\|s;{}$\2\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\par +\U651.\fi + +\M{655}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\B\4\X655:Transfer node \|p to the adjustment list\X${}\E{}$\6 +${}\{{}$\5 +\1\&{while} ${}(\\{link}(\|q)\I\|p){}$\1\5 +${}\|q\K\\{link}(\|q);{}$\2\6 +\&{if} ${}(\\{type}(\|p)\E\\{adjust\_node}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\\{adjust\_tail})\K\\{adjust\_ptr}(\|p);{}$\6 +\&{while} ${}(\\{link}(\\{adjust\_tail})\I\\{null}){}$\1\5 +${}\\{adjust\_tail}\K\\{link}(\\{adjust\_tail});{}$\2\6 +${}\|p\K\\{link}(\|p);{}$\5 +${}\\{free\_node}(\\{link}(\|q),\39\\{small\_node\_size});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{link}(\\{adjust\_tail})\K\|p;{}$\5 +${}\\{adjust\_tail}\K\|p;{}$\5 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +${}\\{link}(\|q)\K\|p;{}$\5 +${}\|p\K\|q;{}$\6 +\4${}\}{}$\2\par +\U651.\fi + +\M{656}\B\X656:Incorporate glue into the horizontal totals\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|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}){}$\5 +${}\{{}$\5 +\1${}\|g\K\\{leader\_ptr}(\|p);{}$\6 +\&{if} ${}(\\{height}(\|g)>\|h){}$\1\5 +${}\|h\K\\{height}(\|g);{}$\2\6 +\&{if} ${}(\\{depth}(\|g)>\|d){}$\1\5 +${}\|d\K\\{depth}(\|g);{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U651.\fi + +\M{657}When we get to the present part of the program, \|x is the natural width +of the box being packaged. + +\Y\B\4\X657:Determine the value of \\{width}(\|r) and the appropriate glue setting; then \&{return} or \&{goto} \\{common\_ending}\X${}\E{}$\6 +\&{if} ${}(\|m\E\\{additional}){}$\1\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\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{normal};{}$\5 +${}\\{glue\_order}(\|r)\K\\{normal};{}$\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\5 +\&{goto} \\{end};\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|x>\T{0}){}$\1\5 +\X658:Determine horizontal glue stretch setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X\2\6 +\&{else}\1\5 +\X664:Determine horizontal glue shrink setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X\2\par +\U649.\fi + +\M{658}\B\X658:Determine horizontal glue stretch setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X${}\E{}$\6 +${}\{{}$\5 +\1\X659:Determine the stretch order\X;\6 +${}\\{glue\_order}(\|r)\K\|o;{}$\5 +${}\\{glue\_sign}(\|r)\K\\{stretching};{}$\6 +\&{if} ${}(\\{total\_stretch}[\|o]\I\T{0}){}$\1\5 +${}\\{glue\_set}(\|r)\K\\{unfloat}(\|x/{}$(\&{double}) \\{total\_stretch}[\|o]);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{normal};{}$\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\C{there's nothing to stretch}\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|o\E\\{normal}){}$\1\6 +\&{if} ${}(\\{list\_ptr}(\|r)\I\\{null}){}$\1\5 +\X660:Report an underfull hbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X;\2\2\6 +\&{goto} \\{end};\6 +\4${}\}{}$\2\par +\U657.\fi + +\M{659}\B\X659:Determine the stretch order\X${}\E{}$\6 +\&{if} ${}(\\{total\_stretch}[\\{filll}]\I\T{0}){}$\1\5 +${}\|o\K\\{filll};{}$\2\6 +\&{else} \&{if} ${}(\\{total\_stretch}[\\{fill}]\I\T{0}){}$\1\5 +${}\|o\K\\{fill};{}$\2\6 +\&{else} \&{if} ${}(\\{total\_stretch}[\\{fil}]\I\T{0}){}$\1\5 +${}\|o\K\\{fil};{}$\2\6 +\&{else} $\|o\K{}$\\{normal}\par +\Us658, 673\ETs796.\fi + +\M{660}\B\X660:Report an underfull hbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{last\_badness}\K\\{badness}(\|x,\39\\{total\_stretch}[\\{normal}]);{}$\6 +\&{if} ${}(\\{last\_badness}>\\{hbadness}){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\6 +\&{if} ${}(\\{last\_badness}>\T{100}){}$\1\5 +\\{print\_nl}(\.{"Underfull"});\5 +\2\&{else}\1\5 +\\{print\_nl}(\.{"Loose"});\2\6 +\\{print\_str}(\.{"\ \\\\hbox\ (badness\ "});\5 +\\{print\_int}(\\{last\_badness});\5 +\&{goto} \\{common\_ending};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U658.\fi + +\M{661}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{pack\_begin\_line};\C{source file line where the current paragraph or alignment began; a negative value denotes alignment}\par +\fi + +\M{662}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{pack\_begin\_line}\K\T{0}{}$;\par +\fi + +\M{663}\B\X663:Finish issuing a diagnostic message for an overfull or underfull hbox\X${}\E{}$\6 +\&{if} (\\{output\_active})\1\5 +\\{print\_str}(\.{")\ has\ occurred\ whil}\)\.{e\ \\\\output\ is\ active}\)\.{"});\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{pack\_begin\_line}\I\T{0}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{pack\_begin\_line}>\T{0}){}$\1\5 +\\{print\_str}(\.{")\ in\ paragraph\ at\ l}\)\.{ines\ "});\2\6 +\&{else}\1\5 +\\{print\_str}(\.{")\ in\ alignment\ at\ l}\)\.{ines\ "});\2\6 +\\{print\_int}(\\{abs}(\\{pack\_begin\_line}));\5 +\\{print\_str}(\.{"--"});\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{print\_str}(\.{")\ detected\ at\ line\ }\)\.{"});\2\6 +\\{print\_int}(\\{line});\6 +\4${}\}{}$\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); \\{end\_diagnostic}(\\{true})\par +\U649.\fi + +\M{664}\B\X664:Determine horizontal glue shrink setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X${}\E{}$\6 +${}\{{}$\5 +\1\X665:Determine the shrink order\X;\6 +${}\\{glue\_order}(\|r)\K\|o;{}$\5 +${}\\{glue\_sign}(\|r)\K\\{shrinking};{}$\6 +\&{if} ${}(\\{total\_shrink}[\|o]\I\T{0}){}$\1\5 +${}\\{glue\_set}(\|r)\K\\{unfloat}(({-}\|x)/{}$(\&{double}) \\{total\_shrink}[\|o]);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{normal};{}$\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\C{there's nothing to shrink}\6 +\4${}\}{}$\2\6 +\&{if} ${}((\\{total\_shrink}[\|o]<{-}\|x)\W(\|o\E\\{normal})\W(\\{list\_ptr}(\|r)\I\\{null})){}$\5 +${}\{{}$\5 +\1${}\\{last\_badness}\K\T{1000000};{}$\5 +\\{set\_glue\_ratio\_one}(\\{glue\_set}(\|r));\C{use the maximum shrinkage}\6 +\X666:Report an overfull hbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X;\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|o\E\\{normal}){}$\1\6 +\&{if} ${}(\\{list\_ptr}(\|r)\I\\{null}){}$\1\5 +\X667:Report a tight hbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X;\2\2\6 +\&{goto} \\{end};\6 +\4${}\}{}$\2\par +\U657.\fi + +\M{665}\B\X665:Determine the shrink order\X${}\E{}$\6 +\&{if} ${}(\\{total\_shrink}[\\{filll}]\I\T{0}){}$\1\5 +${}\|o\K\\{filll};{}$\2\6 +\&{else} \&{if} ${}(\\{total\_shrink}[\\{fill}]\I\T{0}){}$\1\5 +${}\|o\K\\{fill};{}$\2\6 +\&{else} \&{if} ${}(\\{total\_shrink}[\\{fil}]\I\T{0}){}$\1\5 +${}\|o\K\\{fil};{}$\2\6 +\&{else} $\|o\K{}$\\{normal}\par +\Us664, 676\ETs796.\fi + +\M{666}\B\X666:Report an overfull hbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X${}\E{}$\6 +\&{if} ${}(({-}\|x-\\{total\_shrink}[\\{normal}]>\\{hfuzz})\V(\\{hbadness}<\T{100})){}$\5 +${}\{{}$\5 +\1\&{if} ${}((\\{overfull\_rule}>\T{0})\W({-}\|x-\\{total\_shrink}[\\{normal}]>\\{hfuzz})){}$\5 +${}\{{}$\5 +\1\&{while} ${}(\\{link}(\|q)\I\\{null}){}$\1\5 +${}\|q\K\\{link}(\|q);{}$\2\6 +${}\\{link}(\|q)\K\\{new\_rule}(\,);{}$\5 +${}\\{width}(\\{link}(\|q))\K\\{overfull\_rule};{}$\6 +\4${}\}{}$\2\6 +\\{print\_ln}(\,);\5 +\\{print\_nl}(\.{"Overfull\ \\\\hbox\ ("});\5 +${}\\{print\_scaled}({-}\|x-\\{total\_shrink}[\\{normal}]);{}$\5 +\\{print\_str}(\.{"pt\ too\ wide"});\5 +\&{goto} \\{common\_ending};\6 +\4${}\}{}$\2\par +\U664.\fi + +\M{667}\B\X667:Report a tight hbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{last\_badness}\K\\{badness}({-}\|x,\39\\{total\_shrink}[\\{normal}]);{}$\6 +\&{if} ${}(\\{last\_badness}>\\{hbadness}){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\\{print\_nl}(\.{"Tight\ \\\\hbox\ (badne}\)\.{ss\ "});\5 +\\{print\_int}(\\{last\_badness});\5 +\&{goto} \\{common\_ending};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U664.\fi + +\M{668}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\B\8\#\&{define} ${}\\{vpack}(\,\ldots\,) \5\\{vpackage}(\.{\_\_VA\_ARGS\_\_},\39\\{max\_dimen}){}$\C{special case of unconstrained depth}\6 +\&{pointer} \\{vpackage}(\&{pointer} \|p${},\39{}$\&{scaled} \|h${},\39{}$\&{small\_number} \|m${},\39{}$\&{scaled} \|l)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|r;\C{the box node that will be returned}\6 +\&{scaled} \|w${},{}$ \|d${},{}$ \|x;\C{width, depth, and natural height}\6 +\&{scaled} \|s;\C{shift amount}\6 +\&{pointer} \|g;\C{points to a glue specification}\6 +\&{glue\_ord} \|o;\C{order of infinity}\7 +${}\\{last\_badness}\K\T{0};{}$\5 +${}\|r\K\\{get\_node}(\\{box\_node\_size});{}$\5 +${}\\{type}(\|r)\K\\{vlist\_node};{}$\5 +${}\\{subtype}(\|r)\K\\{min\_quarterword};{}$\5 +${}\\{shift\_amount}(\|r)\K\T{0};{}$\5 +${}\\{list\_ptr}(\|r)\K\|p{}$;\6 +${}\|w\K\T{0};{}$\5 +\X650:Clear dimensions to zero\X;\6 +\&{while} ${}(\|p\I\\{null}){}$\1\5 +\X669: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){}$\5 +${}\{{}$\5 +\1${}\|x\K\|x+\|d-\|l;{}$\5 +${}\\{depth}(\|r)\K\|l;{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{depth}(\|r)\K\|d;{}$\2\6 +\X672:Determine the value of \\{height}(\|r) and the appropriate glue setting; then \&{return} or \&{goto} \\{common\_ending}\X;\6 +\4\\{common\_ending}:\5 +\X675:Finish issuing a diagnostic message for an overfull or underfull vbox\X;\6 +\4\\{end}:\5 +\&{return} \|r;\6 +\4${}\}{}$\2\par +\fi + +\M{669}\B\X669: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${}\E{}$\6 +${}\{{}$\5 +\1\&{if} (\\{is\_char\_node}(\|p))\1\5 +\\{confusion}(\X1644:\.{"vpack"}\X);\2\6 +\&{else}\1\6 +\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\5 +\&{case} \\{unset\_node}:\5 +\X670:Incorporate box dimensions into the dimensions of the vbox that will contain~it\X\5 +\&{break};\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1359:Incorporate a whatsit node into a vbox\X;\5 +\&{break};\6 +\4\&{case} \\{glue\_node}:\5 +\X671:Incorporate glue into the vertical totals\X\5 +\&{break};\6 +\4\&{case} \\{kern\_node}:\6 +${}\{{}$\5 +\1${}\|x\K\|x+\|d+\\{width}(\|p);{}$\5 +${}\|d\K\T{0};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\2\2\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\par +\U668.\fi + +\M{670}\B\X670:Incorporate box dimensions into the dimensions of the vbox that will contain~it\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|x\K\|x+\|d+\\{height}(\|p);{}$\5 +${}\|d\K\\{depth}(\|p);{}$\6 +\&{if} ${}(\\{type}(\|p)\G\\{rule\_node}){}$\1\5 +${}\|s\K\T{0}{}$;\5 +\2\&{else}\1\5 +${}\|s\K\\{shift\_amount}(\|p);{}$\2\6 +\&{if} ${}(\\{width}(\|p)+\|s>\|w){}$\1\5 +${}\|w\K\\{width}(\|p)+\|s;{}$\2\6 +\4${}\}{}$\2\par +\U669.\fi + +\M{671}\B\X671:Incorporate glue into the vertical totals\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|x\K\|x+\|d;{}$\5 +${}\|d\K\T{0}{}$;\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}){}$\5 +${}\{{}$\5 +\1${}\|g\K\\{leader\_ptr}(\|p);{}$\6 +\&{if} ${}(\\{width}(\|g)>\|w){}$\1\5 +${}\|w\K\\{width}(\|g);{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U669.\fi + +\M{672}When we get to the present part of the program, \|x is the natural height +of the box being packaged. + +\Y\B\4\X672:Determine the value of \\{height}(\|r) and the appropriate glue setting; then \&{return} or \&{goto} \\{common\_ending}\X${}\E{}$\6 +\&{if} ${}(\|m\E\\{additional}){}$\1\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\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{normal};{}$\5 +${}\\{glue\_order}(\|r)\K\\{normal};{}$\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\5 +\&{goto} \\{end};\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|x>\T{0}){}$\1\5 +\X673:Determine vertical glue stretch setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X\2\6 +\&{else}\1\5 +\X676:Determine vertical glue shrink setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X\2\par +\U668.\fi + +\M{673}\B\X673:Determine vertical glue stretch setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X${}\E{}$\6 +${}\{{}$\5 +\1\X659:Determine the stretch order\X;\6 +${}\\{glue\_order}(\|r)\K\|o;{}$\5 +${}\\{glue\_sign}(\|r)\K\\{stretching};{}$\6 +\&{if} ${}(\\{total\_stretch}[\|o]\I\T{0}){}$\1\5 +${}\\{glue\_set}(\|r)\K\\{unfloat}(\|x/{}$(\&{double}) \\{total\_stretch}[\|o]);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{normal};{}$\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\C{there's nothing to stretch}\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|o\E\\{normal}){}$\1\6 +\&{if} ${}(\\{list\_ptr}(\|r)\I\\{null}){}$\1\5 +\X674:Report an underfull vbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X;\2\2\6 +\&{goto} \\{end};\6 +\4${}\}{}$\2\par +\U672.\fi + +\M{674}\B\X674:Report an underfull vbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{last\_badness}\K\\{badness}(\|x,\39\\{total\_stretch}[\\{normal}]);{}$\6 +\&{if} ${}(\\{last\_badness}>\\{vbadness}){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\6 +\&{if} ${}(\\{last\_badness}>\T{100}){}$\1\5 +\\{print\_nl}(\.{"Underfull"});\5 +\2\&{else}\1\5 +\\{print\_nl}(\.{"Loose"});\2\6 +\\{print\_str}(\.{"\ \\\\vbox\ (badness\ "});\5 +\\{print\_int}(\\{last\_badness});\5 +\&{goto} \\{common\_ending};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U673.\fi + +\M{675}\B\X675:Finish issuing a diagnostic message for an overfull or underfull vbox\X${}\E{}$\6 +\&{if} (\\{output\_active})\1\5 +\\{print\_str}(\.{")\ has\ occurred\ whil}\)\.{e\ \\\\output\ is\ active}\)\.{"});\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{pack\_begin\_line}\I\T{0}{}$)\C{it's actually negative}\6 +${}\{{}$\5 +\1\\{print\_str}(\.{")\ in\ alignment\ at\ l}\)\.{ines\ "});\5 +\\{print\_int}(\\{abs}(\\{pack\_begin\_line}));\5 +\\{print\_str}(\.{"--"});\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{print\_str}(\.{")\ detected\ at\ line\ }\)\.{"});\2\6 +\\{print\_int}(\\{line});\5 +\\{print\_ln}(\,);\6 +\4${}\}{}$\2\6 +\\{begin\_diagnostic}(\,);\5 +\\{show\_box}(\|r); \\{end\_diagnostic}(\\{true})\par +\U668.\fi + +\M{676}\B\X676:Determine vertical glue shrink setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X${}\E{}$\6 +${}\{{}$\5 +\1\X665:Determine the shrink order\X;\6 +${}\\{glue\_order}(\|r)\K\|o;{}$\5 +${}\\{glue\_sign}(\|r)\K\\{shrinking};{}$\6 +\&{if} ${}(\\{total\_shrink}[\|o]\I\T{0}){}$\1\5 +${}\\{glue\_set}(\|r)\K\\{unfloat}(({-}\|x)/{}$(\&{double}) \\{total\_shrink}[\|o]);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{normal};{}$\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\C{there's nothing to shrink}\6 +\4${}\}{}$\2\6 +\&{if} ${}((\\{total\_shrink}[\|o]<{-}\|x)\W(\|o\E\\{normal})\W(\\{list\_ptr}(\|r)\I\\{null})){}$\5 +${}\{{}$\5 +\1${}\\{last\_badness}\K\T{1000000};{}$\5 +\\{set\_glue\_ratio\_one}(\\{glue\_set}(\|r));\C{use the maximum shrinkage}\6 +\X677:Report an overfull vbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X;\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|o\E\\{normal}){}$\1\6 +\&{if} ${}(\\{list\_ptr}(\|r)\I\\{null}){}$\1\5 +\X678:Report a tight vbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X;\2\2\6 +\&{goto} \\{end};\6 +\4${}\}{}$\2\par +\U672.\fi + +\M{677}\B\X677:Report an overfull vbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X${}\E{}$\6 +\&{if} ${}(({-}\|x-\\{total\_shrink}[\\{normal}]>\\{vfuzz})\V(\\{vbadness}<\T{100})){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\\{print\_nl}(\.{"Overfull\ \\\\vbox\ ("});\5 +${}\\{print\_scaled}({-}\|x-\\{total\_shrink}[\\{normal}]);{}$\5 +\\{print\_str}(\.{"pt\ too\ high"});\5 +\&{goto} \\{common\_ending};\6 +\4${}\}{}$\2\par +\U676.\fi + +\M{678}\B\X678:Report a tight vbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{last\_badness}\K\\{badness}({-}\|x,\39\\{total\_shrink}[\\{normal}]);{}$\6 +\&{if} ${}(\\{last\_badness}>\\{vbadness}){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\\{print\_nl}(\.{"Tight\ \\\\vbox\ (badne}\)\.{ss\ "});\5 +\\{print\_int}(\\{last\_badness});\5 +\&{goto} \\{common\_ending};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U676.\fi + +\M{679}When a box is being appended to the current vertical list, the +baselineskip calculation is handled by the \\{append\_to\_vlist} routine. + +\Y\B\&{void} \\{append\_to\_vlist}(\&{pointer} \|b)\1\1\2\2\6 +${}\{{}$\5 +\1\&{scaled} \|d;\C{deficiency of space between baselines}\6 +\&{pointer} \|p;\C{a new glue node}\7 +\&{if} ${}(\\{prev\_depth}>\\{ignore\_depth}){}$\5 +${}\{{}$\5 +\1${}\|d\K\\{width}(\\{baseline\_skip})-\\{prev\_depth}-\\{height}(\|b);{}$\6 +\&{if} ${}(\|d<\\{line\_skip\_limit}){}$\1\5 +${}\|p\K\\{new\_param\_glue}(\\{line\_skip\_code});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|p\K\\{new\_skip\_param}(\\{baseline\_skip\_code});{}$\5 +${}\\{width}(\\{temp\_ptr})\K\|d{}$;\C{$\\{temp\_ptr}\E\\{glue\_ptr}(\|p)$}\6 +\4${}\}{}$\2\6 +${}\\{link}(\\{tail})\K\|p;{}$\5 +${}\\{tail}\K\|p;{}$\6 +\4${}\}{}$\2\6 +${}\\{link}(\\{tail})\K\|b;{}$\5 +${}\\{tail}\K\|b;{}$\5 +${}\\{prev\_depth}\K\\{depth}(\|b);{}$\6 +\4${}\}{}$\2\par +\fi + +\N{1}{680}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 + +\M{681}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\E\\{subscr}(\|p)$), there are several possibilities for the +subfields, depending on the \\{math\_type} of \|q. + +\yskip\hang$\\{math\_type}(\|q)\E\\{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)\E\\{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)\E\\{empty}$ indicates a field with no value (the +corresponding attribute of noad \|p is not present). + +\yskip\hang$\\{math\_type}(\|q)\E\\{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)\E\\{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)\E\\{null}$. This +is not the same as $\\{math\_type}(\|q)\E\\{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. + +\Y\B\4\D$\\{noad\_size}$ \5 +\T{4}\C{number of words in a normal noad}\par +\B\4\D$\\{nucleus}(\|X)$ \5 +$\|X+{}$\T{1}\C{the \\{nucleus} field of a noad}\par +\B\4\D$\\{supscr}(\|X)$ \5 +$\|X+{}$\T{2}\C{the \\{supscr} field of a noad}\par +\B\4\D$\\{subscr}(\|X)$ \5 +$\|X+{}$\T{3}\C{the \\{subscr} field of a noad}\par +\B\4\D$\\{math\_type}$ \5 +\\{link}\C{a \&{halfword} in \\{mem}}\par +\B\4\D$\\{fam}$ \5 +\\{font}\C{a \&{quarterword} in \\{mem}}\par +\B\4\D$\\{math\_char}$ \5 +\T{1}\C{\\{math\_type} when the attribute is simple}\par +\B\4\D$\\{sub\_box}$ \5 +\T{2}\C{\\{math\_type} when the attribute is a box}\par +\B\4\D$\\{sub\_mlist}$ \5 +\T{3}\C{\\{math\_type} when the attribute is a formula}\par +\B\4\D$\\{math\_text\_char}$ \5 +\T{4}\C{\\{math\_type} when italic correction is dubious}\par +\fi + +\M{682}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}\E\T{0}$, $\\{character}\E\T{\~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}\E\\{normal}$. The only exception is that an \\{op\_noad} might +have $\\{subtype}\E\\{limits}$ or \\{no\_limits}, if the normal positioning of +limits has been overridden for this operator. + +\Y\B\4\D$\\{ord\_noad}$ \5 +$(\\{unset\_node}+\T{3}{}$)\C{\\{type} of a noad classified Ord}\par +\B\4\D$\\{op\_noad}$ \5 +$(\\{ord\_noad}+\T{1}{}$)\C{\\{type} of a noad classified Op}\par +\B\4\D$\\{bin\_noad}$ \5 +$(\\{ord\_noad}+\T{2}{}$)\C{\\{type} of a noad classified Bin}\par +\B\4\D$\\{rel\_noad}$ \5 +$(\\{ord\_noad}+\T{3}{}$)\C{\\{type} of a noad classified Rel}\par +\B\4\D$\\{open\_noad}$ \5 +$(\\{ord\_noad}+\T{4}{}$)\C{\\{type} of a noad classified Ope}\par +\B\4\D$\\{close\_noad}$ \5 +$(\\{ord\_noad}+\T{5}{}$)\C{\\{type} of a noad classified Clo}\par +\B\4\D$\\{punct\_noad}$ \5 +$(\\{ord\_noad}+\T{6}{}$)\C{\\{type} of a noad classified Pun}\par +\B\4\D$\\{inner\_noad}$ \5 +$(\\{ord\_noad}+\T{7}{}$)\C{\\{type} of a noad classified Inn}\par +\B\4\D$\\{limits}$ \5 +\T{1}\C{\\{subtype} of \\{op\_noad} whose scripts are to be above, below}\par +\B\4\D$\\{no\_limits}$ \5 +\T{2}\C{\\{subtype} of \\{op\_noad} whose scripts are to be normal}\par +\fi + +\M{683}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})\E\\{math\_type}(\\{denominator})\E\\{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\B\4\D$\\{left\_delimiter}(\|X)$ \5 +$\|X+{}$\T{4}\C{first delimiter field of a noad}\par +\B\4\D$\\{right\_delimiter}(\|X)$ \5 +$\|X+{}$\T{5}\C{second delimiter field of a fraction noad}\par +\B\4\D$\\{radical\_noad}$ \5 +$(\\{inner\_noad}+\T{1}{}$)\C{\\{type} of a noad for square roots}\par +\B\4\D$\\{radical\_noad\_size}$ \5 +\T{5}\C{number of \\{mem} words in a radical noad}\par +\B\4\D$\\{fraction\_noad}$ \5 +$(\\{radical\_noad}+\T{1}{}$)\C{\\{type} of a noad for generalized fractions}\par +\B\4\D$\\{fraction\_noad\_size}$ \5 +\T{6}\C{number of \\{mem} words in a fraction noad}\par +\B\4\D$\\{small\_fam}(\|X)$ \5 +$\\{mem}[\|X].\\{qqqq}.{}$\\{b0}\C{\\{fam} for ``small'' delimiter}\par +\B\4\D$\\{small\_char}(\|X)$ \5 +$\\{mem}[\|X].\\{qqqq}.{}$\\{b1}\C{\\{character} for ``small'' delimiter}\par +\B\4\D$\\{large\_fam}(\|X)$ \5 +$\\{mem}[\|X].\\{qqqq}.{}$\\{b2}\C{\\{fam} for ``large'' delimiter}\par +\B\4\D$\\{large\_char}(\|X)$ \5 +$\\{mem}[\|X].\\{qqqq}.{}$\\{b3}\C{\\{character} for ``large'' delimiter}\par +\B\4\D$\\{thickness}$ \5 +\\{width}\C{\\{thickness} field in a fraction noad}\par +\B\4\D$\\{default\_code}$ \5 +\T{\~10000000000}\C{denotes \\{default\_rule\_thickness}}\par +\B\4\D$\\{numerator}$ \5 +\\{supscr}\C{\\{numerator} field in a fraction noad}\par +\B\4\D$\\{denominator}$ \5 +\\{subscr}\C{\\{denominator} field in a fraction noad}\par +\fi + +\M{684}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{two\_halves} \\{empty\_field};\6 +\&{four\_quarters} \\{null\_delimiter};\par +\fi + +\M{685}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{empty\_field}.\\{rh}\K\\{empty};{}$\5 +${}\\{empty\_field}.\\{lh}\K\\{null}{}$;\6 +${}\\{null\_delimiter}.\\{b0}\K\T{0};{}$\5 +${}\\{null\_delimiter}.\\{b1}\K\\{min\_quarterword}{}$;\6 +${}\\{null\_delimiter}.\\{b2}\K\T{0};{}$\5 +${}\\{null\_delimiter}.\\{b3}\K\\{min\_quarterword}{}$;\par +\fi + +\M{686}The \\{new\_noad} function creates an \\{ord\_noad} that is completely null. + +\Y\B\&{pointer} \\{new\_noad}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\7 +${}\|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 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{687}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))\E\\{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\B\4\D$\\{under\_noad}$ \5 +$(\\{fraction\_noad}+\T{1}{}$)\C{\\{type} of a noad for underlining}\par +\B\4\D$\\{over\_noad}$ \5 +$(\\{under\_noad}+\T{1}{}$)\C{\\{type} of a noad for overlining}\par +\B\4\D$\\{accent\_noad}$ \5 +$(\\{over\_noad}+\T{1}{}$)\C{\\{type} of a noad for accented subformulas}\par +\B\4\D$\\{accent\_noad\_size}$ \5 +\T{5}\C{number of \\{mem} words in an accent noad}\par +\B\4\D$\\{accent\_chr}(\|X)$ \5 +$\|X+{}$\T{4}\C{the \\{accent\_chr} field of an accent noad}\par +\B\4\D$\\{vcenter\_noad}$ \5 +$(\\{accent\_noad}+\T{1}{}$)\C{\\{type} of a noad for \.{\\vcenter}}\par +\B\4\D$\\{left\_noad}$ \5 +$(\\{vcenter\_noad}+\T{1}{}$)\C{\\{type} of a noad for \.{\\left}}\par +\B\4\D$\\{right\_noad}$ \5 +$(\\{left\_noad}+\T{1}{}$)\C{\\{type} of a noad for \.{\\right}}\par +\B\4\D$\\{delimiter}$ \5 +\\{nucleus}\C{\\{delimiter} field in left and right noads}\par +\B\4\D$\\{scripts\_allowed}(\|X)$ \5 +$(\\{type}(\|X)\G\\{ord\_noad})\W(\\{type}(\|X)<\\{left\_noad}{}$)\par +\fi + +\M{688}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\B\4\D$\\{style\_node}$ \5 +$(\\{unset\_node}+\T{1}{}$)\C{\\{type} of a style node}\par +\B\4\D$\\{style\_node\_size}$ \5 +\T{3}\C{number of words in a style node}\par +\B\4\D$\\{display\_style}$ \5 +\T{0}\C{\\{subtype} for \.{\\displaystyle}}\par +\B\4\D$\\{text\_style}$ \5 +\T{2}\C{\\{subtype} for \.{\\textstyle}}\par +\B\4\D$\\{script\_style}$ \5 +\T{4}\C{\\{subtype} for \.{\\scriptstyle}}\par +\B\4\D$\\{script\_script\_style}$ \5 +\T{6}\C{\\{subtype} for \.{\\scriptscriptstyle}}\par +\B\4\D$\\{cramped}$ \5 +\T{1}\C{add this to an uncramped style if you want to cramp it}\par +\Y\B\&{pointer} \\{new\_style}(\&{small\_number} \|s)\C{create a style node}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{get\_node}(\\{style\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{style\_node};{}$\5 +${}\\{subtype}(\|p)\K\|s;{}$\5 +${}\\{width}(\|p)\K\T{0};{}$\5 +${}\\{depth}(\|p)\K\T{0}{}$;\C{the \\{width} and \\{depth} are not used}\6 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{689}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\B\4\D$\\{choice\_node}$ \5 +$(\\{unset\_node}+\T{2}{}$)\C{\\{type} of a choice node}\par +\B\4\D$\\{display\_mlist}(\|X)$ \5 +$\\{info}(\|X+\T{1}{}$)\C{mlist to be used in display style}\par +\B\4\D$\\{text\_mlist}(\|X)$ \5 +$\\{link}(\|X+\T{1}{}$)\C{mlist to be used in text style}\par +\B\4\D$\\{script\_mlist}(\|X)$ \5 +$\\{info}(\|X+\T{2}{}$)\C{mlist to be used in script style}\par +\B\4\D$\\{script\_script\_mlist}(\|X)$ \5 +$\\{link}(\|X+\T{2}{}$)\C{mlist to be used in scriptscript style}\par +\Y\B\&{pointer} \\{new\_choice}(\&{void})\C{create a choice node}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{get\_node}(\\{style\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{choice\_node};{}$\5 +${}\\{subtype}(\|p)\K\T{0}{}$;\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 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{690}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\B\4\X690:Cases of \\{show\_node\_list} that arise in mlists only\X${}\E{}$\6 +\4\&{case} \\{style\_node}:\5 +\\{print\_style}(\\{subtype}(\|p));\5 +\&{break};\6 +\4\&{case} \\{choice\_node}:\5 +\X695:Display choice node \|p\X\5 +\&{break};\6 +\4\&{case} \\{ord\_noad}:\5 +\&{case} \\{op\_noad}:\5 +\&{case} \\{bin\_noad}:\5 +\&{case} \\{rel\_noad}:\5 +\&{case} \\{open\_noad}:\5 +\&{case} \\{close\_noad}:\5 +\&{case} \\{punct\_noad}:\5 +\&{case} \\{inner\_noad}:\5 +\&{case} \\{radical\_noad}:\5 +\&{case} \\{over\_noad}:\5 +\&{case} \\{under\_noad}:\5 +\&{case} \\{vcenter\_noad}:\5 +\&{case} \\{accent\_noad}:\5 +\&{case} \\{left\_noad}:\5 +\&{case} \\{right\_noad}:\5 +\X696:Display normal noad \|p\X\5 +\&{break};\6 +\4\&{case} \\{fraction\_noad}:\5 +\X697:Display fraction noad \|p\X\5 +\&{break};\par +\U183.\fi + +\M{691}Here are some simple routines used in the display of noads. + +\Y\B\4\X691:Declare procedures needed for displaying the elements of mlists\X${}\E{}$\6 +\&{void} \\{print\_fam\_and\_char}(\&{pointer} \|p)\C{prints family and character}\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1490:\.{"fam"}\X);\5 +\\{print\_int}(\\{fam}(\|p));\5 +\\{print\_char}(\.{'\ '});\5 +\\{print\_ASCII}(\\{qo}(\\{character}(\|p)));\6 +\4${}\}{}$\2\7 +\&{void} \\{print\_delimiter}(\&{pointer} \|p)\C{prints a delimiter as 24-bit hex value}\6 +${}\{{}$\5 +\1\&{int} \|a;\C{accumulator}\7 +${}\|a\K\\{small\_fam}(\|p)*\T{256}+\\{qo}(\\{small\_char}(\|p));{}$\5 +${}\|a\K\|a*\T{\^1000}+\\{large\_fam}(\|p)*\T{256}+\\{qo}(\\{large\_char}(\|p));{}$\6 +\&{if} ${}(\|a<\T{0}){}$\1\5 +\\{print\_int}(\|a);\C{this should never happen}\2\6 +\&{else}\1\5 +\\{print\_hex}(\|a);\2\6 +\4${}\}{}$\2\par +\As692\ET694. +\U179.\fi + +\M{692}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)\E\\{empty}$, because these are +not equivalent (as explained above). + +\Y\B\4\X691:Declare procedures needed for displaying the elements of mlists\X${}\mathrel+\E{}$\6 +\&{void} \\{show\_info}(\&{void});\C{\\{show\_node\_list}(\\{info}(\\{temp\_ptr}))}\7 +\&{void} \\{print\_subsidiary\_data}(\&{pointer} \|p${},\39{}$\&{ASCII\_code} \|c)\C{display a noad field}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_length}\G\\{depth\_threshold}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{math\_type}(\|p)\I\\{empty}){}$\1\5 +\\{print\_str}(\.{"\ []"});\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{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 +\&{switch} (\\{math\_type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{math\_char}:\6 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\\{print\_current\_string}(\,);\5 +\\{print\_fam\_and\_char}(\|p);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{sub\_box}:\5 +\\{show\_info}(\,);\5 +\&{break};\C{recursive call}\6 +\4\&{case} \\{sub\_mlist}:\6 +\&{if} ${}(\\{info}(\|p)\E\\{null}){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\\{print\_current\_string}(\,);\5 +\\{print\_str}(\.{"\{\}"});\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{show\_info}(\,);\5 +\2\&{break};\C{recursive call}\6 +\4\&{default}:\5 +\\{do\_nothing};\C{\\{empty}}\6 +\4${}\}{}$\2\6 +\\{flush\_char};\C{remove \|c from the recursion history}\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{693}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\B\&{void} \\{show\_info}(\&{void})\C{the reader will kindly forgive this}\6 +${}\{{}$\5 +\1\\{show\_node\_list}(\\{info}(\\{temp\_ptr}));\6 +\4${}\}{}$\2\par +\fi + +\M{694}\B\X691:Declare procedures needed for displaying the elements of mlists\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_style}(\&{int} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{switch} ${}(\|c/\T{2}){}$\5 +${}\{{}$\1\6 +\4\&{case} \T{0}:\5 +\\{print\_esc}(\X1645:\.{"displaystyle"}\X);\5 +\&{break};\C{$\\{display\_style}\E\T{0}$}\6 +\4\&{case} \T{1}:\5 +\\{print\_esc}(\X1646:\.{"textstyle"}\X);\5 +\&{break};\C{$\\{text\_style}\E\T{2}$}\6 +\4\&{case} \T{2}:\5 +\\{print\_esc}(\X1647:\.{"scriptstyle"}\X);\5 +\&{break};\C{$\\{script\_style}\E\T{4}$}\6 +\4\&{case} \T{3}:\5 +\\{print\_esc}(\X1648:\.{"scriptscriptstyle"}\X);\5 +\&{break};\C{$\\{script\_script\_style}\E\T{6}$}\6 +\4\&{default}:\5 +\\{print\_str}(\.{"Unknown\ style!"});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{695}\B\X695:Display choice node \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1547:\.{"mathchoice"}\X);\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 +\4${}\}{}$\2\par +\U690.\fi + +\M{696}\B\X696:Display normal noad \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{ord\_noad}:\5 +\\{print\_esc}(\X1649:\.{"mathord"}\X);\5 +\&{break};\6 +\4\&{case} \\{op\_noad}:\5 +\\{print\_esc}(\X1650:\.{"mathop"}\X);\5 +\&{break};\6 +\4\&{case} \\{bin\_noad}:\5 +\\{print\_esc}(\X1651:\.{"mathbin"}\X);\5 +\&{break};\6 +\4\&{case} \\{rel\_noad}:\5 +\\{print\_esc}(\X1652:\.{"mathrel"}\X);\5 +\&{break};\6 +\4\&{case} \\{open\_noad}:\5 +\\{print\_esc}(\X1653:\.{"mathopen"}\X);\5 +\&{break};\6 +\4\&{case} \\{close\_noad}:\5 +\\{print\_esc}(\X1654:\.{"mathclose"}\X);\5 +\&{break};\6 +\4\&{case} \\{punct\_noad}:\5 +\\{print\_esc}(\X1655:\.{"mathpunct"}\X);\5 +\&{break};\6 +\4\&{case} \\{inner\_noad}:\5 +\\{print\_esc}(\X1656:\.{"mathinner"}\X);\5 +\&{break};\6 +\4\&{case} \\{over\_noad}:\5 +\\{print\_esc}(\X1657:\.{"overline"}\X);\5 +\&{break};\6 +\4\&{case} \\{under\_noad}:\5 +\\{print\_esc}(\X1658:\.{"underline"}\X);\5 +\&{break};\6 +\4\&{case} \\{vcenter\_noad}:\5 +\\{print\_esc}(\X1561:\.{"vcenter"}\X);\5 +\&{break};\6 +\4\&{case} \\{radical\_noad}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1555:\.{"radical"}\X);\5 +\\{print\_delimiter}(\\{left\_delimiter}(\|p));\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{accent\_noad}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1530:\.{"accent"}\X);\5 +\\{print\_fam\_and\_char}(\\{accent\_chr}(\|p));\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{left\_noad}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1659:\.{"left"}\X);\5 +\\{print\_delimiter}(\\{delimiter}(\|p));\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{right\_noad}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1660:\.{"right"}\X);\5 +\\{print\_delimiter}(\\{delimiter}(\|p));\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{subtype}(\|p)\I\\{normal}){}$\1\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{limits}){}$\1\5 +\\{print\_esc}(\X1661:\.{"limits"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1662:\.{"nolimits"}\X);\2\2\6 +\&{if} ${}(\\{type}(\|p)<\\{left\_noad}){}$\1\5 +${}\\{print\_subsidiary\_data}(\\{nucleus}(\|p),\39\.{'.'});{}$\2\6 +${}\\{print\_subsidiary\_data}(\\{supscr}(\|p),\39\.{'\^'});{}$\5 +${}\\{print\_subsidiary\_data}(\\{subscr}(\|p),\39\.{'\_'});{}$\6 +\4${}\}{}$\2\par +\U690.\fi + +\M{697}\B\X697:Display fraction noad \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1663:\.{"fraction,\ thickness}\)\.{\ "}\X);\6 +\&{if} ${}(\\{thickness}(\|p)\E\\{default\_code}){}$\1\5 +\\{print\_str}(\.{"=\ default"});\2\6 +\&{else}\1\5 +\\{print\_scaled}(\\{thickness}(\|p));\2\6 +\&{if} ${}((\\{small\_fam}(\\{left\_delimiter}(\|p))\I\T{0})\V{}$\5 +${}(\\{small\_char}(\\{left\_delimiter}(\|p))\I\\{min\_quarterword})\V\30(\\{large\_fam}(\\{left\_delimiter}(\|p))\I\T{0})\V\30(\\{large\_char}(\\{left\_delimiter}(\|p))\I\\{min\_quarterword})){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{",\ left-delimiter\ "});\5 +\\{print\_delimiter}(\\{left\_delimiter}(\|p));\6 +\4${}\}{}$\2\6 +\&{if} ${}((\\{small\_fam}(\\{right\_delimiter}(\|p))\I\T{0})\V\30(\\{small\_char}(\\{right\_delimiter}(\|p))\I\\{min\_quarterword})\V\30(\\{large\_fam}(\\{right\_delimiter}(\|p))\I\T{0})\V\30(\\{large\_char}(\\{right\_delimiter}(\|p))\I\\{min% +\_quarterword})){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{",\ right-delimiter\ "});\5 +\\{print\_delimiter}(\\{right\_delimiter}(\|p));\6 +\4${}\}{}$\2\6 +${}\\{print\_subsidiary\_data}(\\{numerator}(\|p),\39\.{'\\\\'});{}$\5 +${}\\{print\_subsidiary\_data}(\\{denominator}(\|p),\39\.{'/'});{}$\6 +\4${}\}{}$\2\par +\U690.\fi + +\M{698}That which can be displayed can also be destroyed. + +\Y\B\4\X698:Cases of \\{flush\_node\_list} that arise in mlists only\X${}\E{}$\6 +\4\&{case} \\{style\_node}:\6 +${}\{{}$\5 +\1${}\\{free\_node}(\|p,\39\\{style\_node\_size});{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{choice\_node}:\6 +${}\{{}$\5 +\1\\{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} \\{done};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{ord\_noad}:\5 +\&{case} \\{op\_noad}:\5 +\&{case} \\{bin\_noad}:\5 +\&{case} \\{rel\_noad}:\5 +\&{case} \\{open\_noad}:\5 +\&{case} \\{close\_noad}:\5 +\&{case} \\{punct\_noad}:\5 +\&{case} \\{inner\_noad}:\5 +\&{case} \\{radical\_noad}:\5 +\&{case} \\{over\_noad}:\5 +\&{case} \\{under\_noad}:\5 +\&{case} \\{vcenter\_noad}:\5 +\&{case} \\{accent\_noad}:\5 +\hbox{}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{math\_type}(\\{nucleus}(\|p))\G\\{sub\_box}){}$\1\5 +\\{flush\_node\_list}(\\{info}(\\{nucleus}(\|p)));\2\6 +\&{if} ${}(\\{math\_type}(\\{supscr}(\|p))\G\\{sub\_box}){}$\1\5 +\\{flush\_node\_list}(\\{info}(\\{supscr}(\|p)));\2\6 +\&{if} ${}(\\{math\_type}(\\{subscr}(\|p))\G\\{sub\_box}){}$\1\5 +\\{flush\_node\_list}(\\{info}(\\{subscr}(\|p)));\2\6 +\&{if} ${}(\\{type}(\|p)\E\\{radical\_noad}){}$\1\5 +${}\\{free\_node}(\|p,\39\\{radical\_noad\_size});{}$\2\6 +\&{else} \&{if} ${}(\\{type}(\|p)\E\\{accent\_noad}){}$\1\5 +${}\\{free\_node}(\|p,\39\\{accent\_noad\_size});{}$\2\6 +\&{else}\1\5 +${}\\{free\_node}(\|p,\39\\{noad\_size});{}$\2\6 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{left\_noad}:\5 +\&{case} \\{right\_noad}:\6 +${}\{{}$\5 +\1${}\\{free\_node}(\|p,\39\\{noad\_size});{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{fraction\_noad}:\6 +${}\{{}$\5 +\1\\{flush\_node\_list}(\\{info}(\\{numerator}(\|p)));\5 +\\{flush\_node\_list}(\\{info}(\\{denominator}(\|p)));\5 +${}\\{free\_node}(\|p,\39\\{fraction\_noad\_size});{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\par +\U202.\fi + +\N{1}{699}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\B\4\D$\\{text\_size}$ \5 +\T{0}\C{size code for the largest size in a family}\par +\B\4\D$\\{script\_size}$ \5 +\T{16}\C{size code for the medium size in a family}\par +\B\4\D$\\{script\_script\_size}$ \5 +\T{32}\C{size code for the smallest size in a family}\par +\Y\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_size}(\&{int} \|s)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\|s\E\\{text\_size}){}$\1\5 +\\{print\_esc}(\X1438:\.{"textfont"}\X);\2\6 +\&{else} \&{if} ${}(\|s\E\\{script\_size}){}$\1\5 +\\{print\_esc}(\X1439:\.{"scriptfont"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1440:\.{"scriptscriptfont"}\X);\2\6 +\4${}\}{}$\2\par +\fi + +\M{700}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\B\4\D$\\{mathsy\_end}(\|X)$ \5 +$\\{fam\_fnt}(\T{2}+\|X)$ ] ] $.$ \\{sc}\par +\B\4\D$\\{mathsy}(\|X)$ \5 +\\{font\_info} [ $\|X+\\{param\_base}$ [ \\{mathsy\_end}\par +\B\4\D$\\{math\_x\_height}$ \5 +\\{mathsy}(\T{5})\C{height of `\.x'}\par +\B\4\D$\\{math\_quad}$ \5 +\\{mathsy}(\T{6})\C{\.{18mu}}\par +\B\4\D$\\{num1}$ \5 +\\{mathsy}(\T{8})\C{numerator shift-up in display styles}\par +\B\4\D$\\{num2}$ \5 +\\{mathsy}(\T{9})\C{numerator shift-up in non-display, non-\.{\\atop}}\par +\B\4\D$\\{num3}$ \5 +\\{mathsy}(\T{10})\C{numerator shift-up in non-display \.{\\atop}}\par +\B\4\D$\\{denom1}$ \5 +\\{mathsy}(\T{11})\C{denominator shift-down in display styles}\par +\B\4\D$\\{denom2}$ \5 +\\{mathsy}(\T{12})\C{denominator shift-down in non-display styles}\par +\B\4\D$\\{sup1}$ \5 +\\{mathsy}(\T{13})\C{superscript shift-up in uncramped display style}\par +\B\4\D$\\{sup2}$ \5 +\\{mathsy}(\T{14})\C{superscript shift-up in uncramped non-display}\par +\B\4\D$\\{sup3}$ \5 +\\{mathsy}(\T{15})\C{superscript shift-up in cramped styles}\par +\B\4\D$\\{sub1}$ \5 +\\{mathsy}(\T{16})\C{subscript shift-down if superscript is absent}\par +\B\4\D$\\{sub2}$ \5 +\\{mathsy}(\T{17})\C{subscript shift-down if superscript is present}\par +\B\4\D$\\{sup\_drop}$ \5 +\\{mathsy}(\T{18})\C{superscript baseline below top of large box}\par +\B\4\D$\\{sub\_drop}$ \5 +\\{mathsy}(\T{19})\C{subscript baseline below bottom of large box}\par +\B\4\D$\\{delim1}$ \5 +\\{mathsy}(\T{20})\C{size of \.{\\atopwithdelims} delimiters in display styles}\par +\B\4\D$\\{delim2}$ \5 +\\{mathsy}(\T{21})\C{size of \.{\\atopwithdelims} delimiters in non-displays}\par +\B\4\D$\\{axis\_height}$ \5 +\\{mathsy}(\T{22})\C{height of fraction lines above the baseline}\par +\B\4\D$\\{total\_mathsy\_params}$ \5 +\T{22}\par +\fi + +\M{701}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\B\4\D$\\{mathex}(\|X)$ \5 +$\\{font\_info}[\|X+\\{param\_base}[\\{fam\_fnt}(\T{3}+\\{cur\_size})]].{}$\\{sc}\par +\B\4\D$\\{default\_rule\_thickness}$ \5 +\\{mathex}(\T{8})\C{thickness of \.{\\over} bars}\par +\B\4\D$\\{big\_op\_spacing1}$ \5 +\\{mathex}(\T{9})\C{minimum clearance above a displayed op}\par +\B\4\D$\\{big\_op\_spacing2}$ \5 +\\{mathex}(\T{10})\C{minimum clearance below a displayed op}\par +\B\4\D$\\{big\_op\_spacing3}$ \5 +\\{mathex}(\T{11})\C{minimum baselineskip above displayed op}\par +\B\4\D$\\{big\_op\_spacing4}$ \5 +\\{mathex}(\T{12})\C{minimum baselineskip below displayed op}\par +\B\4\D$\\{big\_op\_spacing5}$ \5 +\\{mathex}(\T{13})\C{padding above and below displayed limits}\par +\B\4\D$\\{total\_mathex\_params}$ \5 +\T{13}\par +\fi + +\M{702}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\B\4\D$\\{cramped\_style}(\|X)$ \5 +$\T{2}*(\|X/\T{2})+{}$\\{cramped}\C{cramp the style}\par +\B\4\D$\\{sub\_style}(\|X)$ \5 +$\T{2}*(\|X/\T{4})+\\{script\_style}+{}$\\{cramped}\C{smaller and cramped}\par +\B\4\D$\\{sup\_style}(\|X)$ \5 +$\T{2}*(\|X/\T{4})+\\{script\_style}+(\|X\MOD\T{2}{}$)\C{smaller}\par +\B\4\D$\\{num\_style}(\|X)$ \5 +$\|X+\T{2}-\T{2}*(\|X/\T{6}{}$)\C{smaller unless already script-script}\par +\B\4\D$\\{denom\_style}(\|X)$ \5 +$\T{2}*(\|X/\T{2})+\\{cramped}+\T{2}-\T{2}*(\|X/\T{6}{}$)\C{smaller, cramped}\par +\fi + +\M{703}When the style changes, the following piece of program computes associated +information: + +\Y\B\4\X703:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur\_style}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_style}<\\{script\_style}){}$\1\5 +${}\\{cur\_size}\K\\{text\_size};{}$\2\6 +\&{else}\1\5 +${}\\{cur\_size}\K\T{16}*((\\{cur\_style}-\\{text\_style})/\T{2});{}$\2\6 +${}\\{cur\_mu}\K\\{x\_over\_n}(\\{math\_quad}(\\{cur\_size}),\39\T{18});{}$\6 +\4${}\}{}$\2\par +\Us720, 726, 730, 754, 760\ETs763.\fi + +\M{704}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\B\&{pointer} \\{fraction\_rule}(\&{scaled} \|t)\C{construct the bar for a fraction}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|p\K\\{new\_rule}(\,);{}$\5 +${}\\{height}(\|p)\K\|t;{}$\5 +${}\\{depth}(\|p)\K\T{0};{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{705}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\B\&{pointer} \\{overbar}(\&{pointer} \|b${},\39{}$\&{scaled} \|k${},\39{}$\&{scaled} \|t)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|q;\C{nodes being constructed}\7 +${}\|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 +\&{return} \\{vpack}${}(\|p,\39\\{natural});{}$\6 +\4${}\}{}$\2\par +\fi + +\M{706}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\B\hbox{\4}\X709:Declare subprocedures for \\{var\_delimiter}\X\7 +\&{pointer} \\{var\_delimiter}(\&{pointer} \|d${},\39{}$\&{small\_number} \|s${},\39{}$\&{scaled} \|v)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|b;\C{the box that will be constructed}\6 +\&{internal\_font\_number} \|f${},{}$ \|g;\C{best-so-far and tentative font codes}\6 +\&{quarterword} \|c${},{}$ \|x${},{}$ \|y;\C{best-so-far and tentative character codes}\6 +\&{int} \|m${},{}$ \|n;\C{the number of extensible pieces}\6 +\&{scaled} \|u;\C{height-plus-depth of a tentative character}\6 +\&{scaled} \|w;\C{largest height-plus-depth so far}\6 +\&{four\_quarters} \|q;\C{character info}\6 +\&{eight\_bits} \\{hd};\C{height-depth byte}\6 +\&{four\_quarters} \|r;\C{extensible pieces}\6 +\&{small\_number} \|z;\C{runs through font family members}\6 +\&{bool} \\{large\_attempt};\C{are we trying the ``large'' variant?}\7 +${}\|f\K\\{null\_font};{}$\5 +${}\|w\K\T{0};{}$\5 +${}\\{large\_attempt}\K\\{false};{}$\5 +${}\|z\K\\{small\_fam}(\|d);{}$\5 +${}\|x\K\\{small\_char}(\|d);{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\X707: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\5 +\&{goto} \\{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 +\4${}\}{}$\2\6 +\4\\{found}:\6 +\&{if} ${}(\|f\I\\{null\_font}){}$\1\5 +\X710:Make variable \|b point to a box for $(\|f,\|c)$\X;\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|b\K\\{new\_null\_box}(\,);{}$\5 +${}\\{width}(\|b)\K\\{null\_delimiter\_space}{}$;\C{use this width if no delimiter was found}\6 +\4${}\}{}$\2\6 +${}\\{shift\_amount}(\|b)\K\\{half}(\\{height}(\|b)-\\{depth}(\|b))-\\{axis\_height}(\|s);{}$\5 +\&{return} \|b;\6 +\4${}\}{}$\2\par +\fi + +\M{707}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\B\4\X707: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${}\E{}$\6 +\&{if} ${}((\|z\I\T{0})\V(\|x\I\\{min\_quarterword})){}$\5 +${}\{{}$\5 +\1${}\|z\K\|z+\|s+\T{16}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|z\K\|z-\T{16};{}$\5 +${}\|g\K\\{fam\_fnt}(\|z);{}$\6 +\&{if} ${}(\|g\I\\{null\_font}){}$\1\5 +\X708: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${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|z<\T{16}));{}$\6 +\4${}\}{}$\2\par +\U706.\fi + +\M{708}\B\X708: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${}\E{}$\6 +${}\{{}$\5 +\1${}\|y\K\|x;{}$\6 +\&{if} ${}((\\{qo}(\|y)\G\\{font\_bc}[\|g])\W(\\{qo}(\|y)\Z\\{font\_ec}[\|g])){}$\5 +${}\{{}$\5 +\1\\{resume}:\5 +${}\|q\K\\{char\_info}(\|g)(\|y);{}$\6 +\&{if} (\\{char\_exists}(\|q))\5 +${}\{{}$\5 +\1\&{if} ${}(\\{char\_tag}(\|q)\E\\{ext\_tag}){}$\5 +${}\{{}$\5 +\1${}\|f\K\|g;{}$\5 +${}\|c\K\|y;{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +${}\\{hd}\K\\{height\_depth}(\|q);{}$\5 +${}\|u\K\\{char\_height}(\|g)(\\{hd})+\\{char\_depth}(\|g)(\\{hd});{}$\6 +\&{if} ${}(\|u>\|w){}$\5 +${}\{{}$\5 +\1${}\|f\K\|g;{}$\5 +${}\|c\K\|y;{}$\5 +${}\|w\K\|u;{}$\6 +\&{if} ${}(\|u\G\|v){}$\1\5 +\&{goto} \\{found};\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{char\_tag}(\|q)\E\\{list\_tag}){}$\5 +${}\{{}$\5 +\1${}\|y\K\\{rem\_byte}(\|q);{}$\5 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U707.\fi + +\M{709}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\B\4\X709:Declare subprocedures for \\{var\_delimiter}\X${}\E{}$\6 +\&{pointer} \\{char\_box}(\&{internal\_font\_number} \|f${},\39{}$\&{quarterword} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{four\_quarters} \|q;\6 +\&{eight\_bits} \\{hd};\C{\\{height\_depth} byte}\6 +\&{pointer} \|b${},{}$ \|p;\C{the new box and its character node}\7 +${}\|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 +\&{return} \|b;\6 +\4${}\}{}$\2\par +\As711\ET712. +\U706.\fi + +\M{710}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\B\4\X710:Make variable \|b point to a box for $(\|f,\|c)$\X${}\E{}$\6 +\&{if} ${}(\\{char\_tag}(\|q)\E\\{ext\_tag}){}$\1\5 +\X713:Construct an extensible character in a new box \|b, using recipe \\{rem\_byte}(\|q) and font \|f\X\2\6 +\&{else} $\|b\K\\{char\_box}(\|f,\39\|c{}$)\par +\U706.\fi + +\M{711}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\B\4\X709:Declare subprocedures for \\{var\_delimiter}\X${}\mathrel+\E{}$\6 +\&{void} \\{stack\_into\_box}(\&{pointer} \|b${},\39{}$\&{internal\_font\_number} \|f${},\39{}$\&{quarterword} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{new node placed into \|b}\7 +${}\|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 +\4${}\}{}$\2\par +\fi + +\M{712}Another handy subroutine computes the height plus depth of +a given character: + +\Y\B\4\X709:Declare subprocedures for \\{var\_delimiter}\X${}\mathrel+\E{}$\6 +\&{scaled} \\{height\_plus\_depth}(\&{internal\_font\_number} \|f${},\39{}$\&{quarterword} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{four\_quarters} \|q;\6 +\&{eight\_bits} \\{hd};\C{\\{height\_depth} byte}\7 +${}\|q\K\\{char\_info}(\|f)(\|c);{}$\5 +${}\\{hd}\K\\{height\_depth}(\|q);{}$\5 +\&{return} \\{char\_height}(\|f)(\\{hd})${}+\\{char\_depth}(\|f)(\\{hd});{}$\6 +\4${}\}{}$\2\par +\fi + +\M{713}\B\X713:Construct an extensible character in a new box \|b, using recipe \\{rem\_byte}(\|q) and font \|f\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|b\K\\{new\_null\_box}(\,);{}$\5 +${}\\{type}(\|b)\K\\{vlist\_node};{}$\5 +${}\|r\K\\{font\_info}[\\{exten\_base}[\|f]+\\{rem\_byte}(\|q)].\\{qqqq}{}$;\6 +\X714: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\5 +${}\\{stack\_into\_box}(\|b,\39\|f,\39\|c);{}$\2\6 +${}\|c\K\\{ext\_rep}(\|r);{}$\6 +\&{for} ${}(\|m\K\T{1};{}$ ${}\|m\Z\|n;{}$ ${}\|m\PP){}$\1\5 +${}\\{stack\_into\_box}(\|b,\39\|f,\39\|c);{}$\2\6 +${}\|c\K\\{ext\_mid}(\|r);{}$\6 +\&{if} ${}(\|c\I\\{min\_quarterword}){}$\5 +${}\{{}$\5 +\1${}\\{stack\_into\_box}(\|b,\39\|f,\39\|c);{}$\5 +${}\|c\K\\{ext\_rep}(\|r);{}$\6 +\&{for} ${}(\|m\K\T{1};{}$ ${}\|m\Z\|n;{}$ ${}\|m\PP){}$\1\5 +${}\\{stack\_into\_box}(\|b,\39\|f,\39\|c);{}$\2\6 +\4${}\}{}$\2\6 +${}\|c\K\\{ext\_top}(\|r);{}$\6 +\&{if} ${}(\|c\I\\{min\_quarterword}){}$\1\5 +${}\\{stack\_into\_box}(\|b,\39\|f,\39\|c);{}$\2\6 +${}\\{depth}(\|b)\K\|w-\\{height}(\|b);{}$\6 +\4${}\}{}$\2\par +\U710.\fi + +\M{714}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\B\4\X714:Compute the minimum suitable height, \|w, and the corresponding number of extension steps, \|n; also set \\{width}(\|b)\X${}\E{}$\6 +$\|c\K\\{ext\_rep}(\|r);{}$\5 +${}\|u\K\\{height\_plus\_depth}(\|f,\39\|c);{}$\5 +${}\|w\K\T{0};{}$\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){}$;\5 +\&{if} ${}(\|c\I\\{min\_quarterword}){}$\1\5 +${}\|w\K\|w+\\{height\_plus\_depth}(\|f,\39\|c);{}$\2\6 +${}\|c\K\\{ext\_mid}(\|r){}$;\5 +\&{if} ${}(\|c\I\\{min\_quarterword}){}$\1\5 +${}\|w\K\|w+\\{height\_plus\_depth}(\|f,\39\|c);{}$\2\6 +${}\|c\K\\{ext\_top}(\|r){}$;\5 +\&{if} ${}(\|c\I\\{min\_quarterword}){}$\1\5 +${}\|w\K\|w+\\{height\_plus\_depth}(\|f,\39\|c);{}$\2\6 +${}\|n\K\T{0};{}$\6 +\&{if} ${}(\|u>\T{0}){}$\1\6 +\&{while} ${}(\|w<\|v){}$\5 +${}\{{}$\5 +\1${}\|w\K\|w+\|u;{}$\5 +\\{incr}(\|n);\6 +\&{if} ${}(\\{ext\_mid}(\|r)\I\\{min\_quarterword}){}$\1\5 +${}\|w\K\|w+\|u;{}$\2\6 +\4${}\}{}$\2\2\par +\U713.\fi + +\M{715}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\B\&{pointer} \\{rebox}(\&{pointer} \|b${},\39{}$\&{scaled} \|w)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{temporary register for list manipulation}\6 +\&{internal\_font\_number} \|f;\C{font in a one-character box}\6 +\&{scaled} \|v;\C{width of a character without italic correction}\7 +\&{if} ${}((\\{width}(\|b)\I\|w)\W(\\{list\_ptr}(\|b)\I\\{null})){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{type}(\|b)\E\\{vlist\_node}){}$\1\5 +${}\|b\K\\{hpack}(\|b,\39\\{natural});{}$\2\6 +${}\|p\K\\{list\_ptr}(\|b);{}$\6 +\&{if} ${}((\\{is\_char\_node}(\|p))\W(\\{link}(\|p)\E\\{null})){}$\5 +${}\{{}$\5 +\1${}\|f\K\\{font}(\|p);{}$\5 +${}\|v\K\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\|p)));{}$\6 +\&{if} ${}(\|v\I\\{width}(\|b)){}$\1\5 +${}\\{link}(\|p)\K\\{new\_kern}(\\{width}(\|b)-\|v);{}$\2\6 +\4${}\}{}$\2\6 +${}\\{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\5 +${}\|p\K\\{link}(\|p);{}$\2\6 +${}\\{link}(\|p)\K\\{new\_glue}(\\{ss\_glue});{}$\5 +\&{return} \\{hpack}${}(\|b,\39\|w,\39\\{exactly});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{width}(\|b)\K\|w;{}$\5 +\&{return} \|b;\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{716}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\B\4\D$\\{mu\_mult}(\|X)$ \5 +$\\{nx\_plus\_y}(\|n,\39\|X,\39\\{xn\_over\_d}(\|X,\39\|f,\39\T{\~200000}){}$)\par +\Y\B\&{pointer} \\{math\_glue}(\&{pointer} \|g${},\39{}$\&{scaled} \|m)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new glue specification}\6 +\&{int} \|n;\C{integer part of \|m}\6 +\&{scaled} \|f;\C{fraction part of \|m}\7 +${}\|n\K\\{x\_over\_n}(\|m,\39\T{\~200000});{}$\5 +${}\|f\K\\{rem}{}$;\6 +\&{if} ${}(\|f<\T{0}){}$\5 +${}\{{}$\5 +\1\\{decr}(\|n);\5 +${}\|f\K\|f+\T{\~200000};{}$\6 +\4${}\}{}$\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)\E\\{normal}){}$\1\5 +${}\\{stretch}(\|p)\K\\{mu\_mult}(\\{stretch}(\|g));{}$\2\6 +\&{else}\1\5 +${}\\{stretch}(\|p)\K\\{stretch}(\|g);{}$\2\6 +${}\\{shrink\_order}(\|p)\K\\{shrink\_order}(\|g);{}$\6 +\&{if} ${}(\\{shrink\_order}(\|p)\E\\{normal}){}$\1\5 +${}\\{shrink}(\|p)\K\\{mu\_mult}(\\{shrink}(\|g));{}$\2\6 +\&{else}\1\5 +${}\\{shrink}(\|p)\K\\{shrink}(\|g);{}$\2\6 +\&{return} \|p;\6 +\4${}\}{}$\2\par +\fi + +\M{717}The \\{math\_kern} subroutine removes \\{mu\_glue} from a kern node, given +the value of the math unit. + +\Y\B\&{void} \\{math\_kern}(\&{pointer} \|p${},\39{}$\&{scaled} \|m)\1\1 $\{{}$\5 +\&{int} \|n;\C{integer part of \|m}\6 +\&{scaled} \|f;\C{fraction part of \|m}\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{mu\_glue})$ $\{{}$\5 +$\|n\K\\{x\_over\_n}(\|m,\39\T{\~200000});{}$\5 +${}\|f\K\\{rem}{}$;\6 +\&{if} ${}(\|f<\T{0}){}$\5 +${}\{{}$\5 +\1\\{decr}(\|n);\5 +${}\|f\K\|f+\T{\~200000};{}$\6 +\4${}\}{}$\2\6 +${}\\{width}(\|p)\K\\{mu\_mult}(\\{width}(\|p));$ \\{subtype}(\|p) $\K$ \&{explicit}; $\}$ $\}{}$\par +\fi + +\M{718}Sometimes it is necessary to destroy an mlist. The following +subroutine empties the current list, assuming that $\\{abs}(\\{mode})\E\\{mmode}$. + +\Y\B\&{void} \\{flush\_math}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\par +\fi + +\N{1}{719}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{cur\_mlist};\C{beginning of mlist to be translated}\6 +\&{small\_number} \\{cur\_style};\C{style code at current place in the list}\6 +\&{small\_number} \\{cur\_size};\C{size code corresponding to \\{cur\_style}}\6 +\&{scaled} \\{cur\_mu};\C{the math unit width corresponding to \\{cur\_size}}\6 +\&{bool} \\{mlist\_penalties};\C{should \\{mlist\_to\_hlist} insert penalties?}\par +\fi + +\M{720}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\B\&{void} \\{mlist\_to\_hlist}(\&{void});\7 +\&{pointer} \\{clean\_box}(\&{pointer} \|p${},\39{}$\&{small\_number} \|s)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|q;\C{beginning of a list to be boxed}\6 +\&{small\_number} \\{save\_style};\C{\\{cur\_style} to be restored}\6 +\&{pointer} \|x;\C{box to be returned}\6 +\&{pointer} \|r;\C{temporary pointer}\7 +\&{switch} (\\{math\_type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{math\_char}:\6 +${}\{{}$\5 +\1${}\\{cur\_mlist}\K\\{new\_noad}(\,);{}$\5 +${}\\{mem}[\\{nucleus}(\\{cur\_mlist})]\K\\{mem}[\|p];{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{sub\_box}:\6 +${}\{{}$\5 +\1${}\|q\K\\{info}(\|p);{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{sub\_mlist}:\5 +${}\\{cur\_mlist}\K\\{info}(\|p){}$;\5 +\&{break};\6 +\4\&{default}:\6 +${}\{{}$\5 +\1${}\|q\K\\{new\_null\_box}(\,);{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\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 +\X703:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur\_style}\X;\6 +\4\\{found}:\6 +\&{if} ${}(\\{is\_char\_node}(\|q)\V(\|q\E\\{null})){}$\1\5 +${}\|x\K\\{hpack}(\|q,\39\\{natural});{}$\2\6 +\&{else} \&{if} ${}((\\{link}(\|q)\E\\{null})\W(\\{type}(\|q)\Z\\{vlist\_node})\W(\\{shift\_amount}(\|q)\E\T{0})){}$\1\5 +${}\|x\K\|q{}$;\C{it's already clean}\2\6 +\&{else}\1\5 +${}\|x\K\\{hpack}(\|q,\39\\{natural});{}$\2\6 +\X721:Simplify a trivial box\X;\6 +\&{return} \|x;\6 +\4${}\}{}$\2\par +\fi + +\M{721}Here we save memory space in a common case. + +\Y\B\4\X721:Simplify a trivial box\X${}\E{}$\6 +$\|q\K\\{list\_ptr}(\|x);{}$\6 +\&{if} (\\{is\_char\_node}(\|q))\5 +${}\{{}$\5 +\1${}\|r\K\\{link}(\|q);{}$\6 +\&{if} ${}(\|r\I\\{null}){}$\1\6 +\&{if} ${}(\\{link}(\|r)\E\\{null}){}$\1\6 +\&{if} ${}(\R\\{is\_char\_node}(\|r)){}$\1\6 +\&{if} ${}(\\{type}(\|r)\E\\{kern\_node}{}$)\C{unneeded italic correction}\6 +${}\{{}$\5 +\1${}\\{free\_node}(\|r,\39\\{small\_node\_size});{}$\5 +${}\\{link}(\|q)\K\\{null};{}$\6 +\4${}\}{}$\2\2\2\2\6 +\4${}\}{}$\2\par +\U720.\fi + +\M{722}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\B\&{void} \\{fetch}(\&{pointer} \|a)\C{unpack the \\{math\_char} field \|a}\6 +${}\{{}$\5 +\1${}\\{cur\_c}\K\\{character}(\|a);{}$\5 +${}\\{cur\_f}\K\\{fam\_fnt}(\\{fam}(\|a)+\\{cur\_size});{}$\6 +\&{if} ${}(\\{cur\_f}\E\\{null\_font}){}$\1\5 +\X723:Complain about an undefined family and set \\{cur\_i} null\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}((\\{qo}(\\{cur\_c})\G\\{font\_bc}[\\{cur\_f}])\W(\\{qo}(\\{cur\_c})\Z\\{font\_ec}[\\{cur\_f}])){}$\1\5 +${}\\{cur\_i}\K\\{char\_info}(\\{cur\_f})(\\{cur\_c});{}$\2\6 +\&{else}\1\5 +${}\\{cur\_i}\K\\{null\_character};{}$\2\6 +\&{if} ${}(\R(\\{char\_exists}(\\{cur\_i}))){}$\5 +${}\{{}$\5 +\1${}\\{char\_warning}(\\{cur\_f},\39\\{qo}(\\{cur\_c}));{}$\5 +${}\\{math\_type}(\|a)\K\\{empty};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{723}\B\X723:Complain about an undefined family and set \\{cur\_i} null\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{""});\5 +\\{print\_size}(\\{cur\_size});\5 +\\{print\_char}(\.{'\ '});\5 +\\{print\_int}(\\{fam}(\|a));\5 +\\{print\_str}(\.{"\ is\ undefined\ (char}\)\.{acter\ "});\5 +\\{print\_ASCII}(\\{qo}(\\{cur\_c}));\5 +\\{print\_char}(\.{')'});\5 +\\{help4}(\.{"Somewhere\ in\ the\ ma}\)\.{th\ formula\ just\ ende}\)\.{d,\ you\ used\ the"})\6 +(\.{"stated\ character\ fr}\)\.{om\ an\ undefined\ font}\)\.{\ family.\ For\ example}\)\.{,"})\6 +(\.{"plain\ TeX\ doesn't\ a}\)\.{llow\ \\\\it\ or\ \\\\sl\ in}\)\.{\ subscripts.\ Proceed}\)\.{,"})\6 +(\.{"and\ I'll\ try\ to\ for}\)\.{get\ that\ I\ needed\ th}\)\.{at\ character."});\6 +\&{error} (\,)\1\5 +;\2\6 +${}\\{cur\_i}\K\\{null\_character};{}$\5 +${}\\{math\_type}(\|a)\K\\{empty};{}$\6 +\4${}\}{}$\2\par +\U722.\fi + +\M{724}The outputs of \\{fetch} are placed in global variables. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{internal\_font\_number} \\{cur\_f};\C{the \\{font} field of a \\{math\_char}}\6 +\&{quarterword} \\{cur\_c};\C{the \\{character} field of a \\{math\_char}}\6 +\&{four\_quarters} \\{cur\_i};\C{the \\{char\_info} of a \\{math\_char}, or a lig/kern instruction}\par +\fi + +\M{725}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\B\4\D$\\{new\_hlist}(\|X)$ \5 +$\\{mem}[\\{nucleus}(\|X)].{}$\|i\C{the translation of an mlist}\par +\fi + +\M{726}Here is the overall plan of \\{mlist\_to\_hlist}, and the list of its +local variables. + +\Y\B\hbox{\4}\X734:Declare math construction procedures\X\7 +\&{void} \\{mlist\_to\_hlist}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \\{mlist};\C{beginning of the given list}\6 +\&{bool} \\{penalties};\C{should penalty nodes be inserted?}\6 +\&{small\_number} \\{style};\C{the given style}\6 +\&{small\_number} \\{save\_style};\C{holds \\{cur\_style} during recursion}\6 +\&{pointer} \|q;\C{runs through the mlist}\6 +\&{pointer} \|r;\C{the most recent noad preceding \|q}\6 +\&{small\_number} \\{r\_type};\C{the \\{type} of noad \|r, or \\{op\_noad} if $\|r\E\\{null}$}\6 +\&{small\_number} \|t;\C{the effective \\{type} of noad \|q during the second pass}\6 +\&{pointer} \|p${},{}$ \|x${},{}$ \|y${},{}$ \|z;\C{temporary registers for list construction}\6 +\&{int} \\{pen};\C{a penalty to be inserted}\6 +\&{small\_number} \|s;\C{the size of a noad to be deleted}\6 +\&{scaled} \\{max\_h}${},{}$ \\{max\_d};\C{maximum height and depth of the list translated so far}\6 +\&{scaled} \\{delta};\C{offset between subscript and superscript}\7 +${}\\{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}\K\T{0};{}$\5 +${}\\{max\_d}\K\T{0};{}$\5 +\X703:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur\_style}\X;\6 +\&{while} ${}(\|q\I\\{null}){}$\1\5 +\X727: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 +\X729:Convert \(a)a final \\{bin\_noad} to an \\{ord\_noad}\X;\6 +\X760:Make a second pass over the mlist, removing all noads and inserting the proper spacing and penalties\X;\6 +\4${}\}{}$\2\par +\fi + +\M{727}We use the fact that no character nodes appear in an mlist, hence +the field \\{type}(\|q) is always present. + +\Y\B\4\X727: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${}\E{}$\6 +${}\{{}$\5 +\1\X728: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}:\5 +${}\|z\K\\{hpack}(\\{new\_hlist}(\|q),\39\\{natural});{}$\6 +\&{if} ${}(\\{height}(\|z)>\\{max\_h}){}$\1\5 +${}\\{max\_h}\K\\{height}(\|z);{}$\2\6 +\&{if} ${}(\\{depth}(\|z)>\\{max\_d}){}$\1\5 +${}\\{max\_d}\K\\{depth}(\|z);{}$\2\6 +${}\\{free\_node}(\|z,\39\\{box\_node\_size});{}$\6 +\4\\{done\_with\_noad}:\5 +${}\|r\K\|q;{}$\5 +${}\\{r\_type}\K\\{type}(\|r);{}$\6 +\4\\{done\_with\_node}:\5 +${}\|q\K\\{link}(\|q);{}$\6 +\4${}\}{}$\2\par +\U726.\fi + +\M{728}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\B\4\X728: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${}\E{}$\6 +\4\\{reswitch}:\5 +${}\\{delta}\K\T{0};{}$\6 +\&{switch} (\\{type}(\|q))\5 +${}\{{}$\1\6 +\4\&{case} \\{bin\_noad}:\6 +\&{switch} (\\{r\_type})\5 +${}\{{}$\1\6 +\4\&{case} \\{bin\_noad}:\5 +\&{case} \\{op\_noad}:\5 +\&{case} \\{rel\_noad}:\5 +\&{case} \\{open\_noad}:\5 +\&{case} \\{punct\_noad}:\5 +\&{case} \\{left\_noad}:\6 +${}\{{}$\5 +\1${}\\{type}(\|q)\K\\{ord\_noad};{}$\5 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\4\&{default}:\5 +\\{do\_nothing};\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{rel\_noad}:\5 +\&{case} \\{close\_noad}:\5 +\&{case} \\{punct\_noad}:\5 +\&{case} \\{right\_noad}:\6 +${}\{{}$\5 +\1\hbox{}\6 +\X729:Convert \(a)a final \\{bin\_noad} to an \\{ord\_noad}\X;\6 +\&{if} ${}(\\{type}(\|q)\E\\{right\_noad}){}$\1\5 +\&{goto} \\{done\_with\_noad};\2\6 +\4${}\}{}$\5 +\2\&{break};\5 +\hbox{\4}\X733:Cases for noads that can follow a \\{bin\_noad}\X\6 +\hbox{\4}\X730:Cases for nodes that can appear in an mlist, after which we \&{goto} \\{done\_with\_node}\X\6 +\4\&{default}:\5 +\\{confusion}(\X1664:\.{"mlist1"}\X);\6 +\4${}\}{}$\2\6 +\X754:Convert \(n)\\{nucleus}(\|q) to an hlist and attach the sub/superscripts\X\par +\U727.\fi + +\M{729}\B\X729:Convert \(a)a final \\{bin\_noad} to an \\{ord\_noad}\X${}\E{}$\6 +\&{if} ${}(\\{r\_type}\E\\{bin\_noad})$ $\\{type}(\|r)\K{}$\\{ord\_noad}\par +\Us726\ET728.\fi + +\M{730}\B\X730:Cases for nodes that can appear in an mlist, after which we \&{goto} \\{done\_with\_node}\X${}\E{}$\6 +\4\&{case} \\{style\_node}:\6 +${}\{{}$\5 +\1${}\\{cur\_style}\K\\{subtype}(\|q);{}$\5 +\X703:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur\_style}\X;\6 +\&{goto} \\{done\_with\_node};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{choice\_node}:\5 +\X731:Change this node to a style node followed by the correct choice, then \&{goto} \\{done\_with\_node}\X\6 +\4\&{case} \\{ins\_node}:\5 +\&{case} \\{mark\_node}:\5 +\&{case} \\{adjust\_node}:\5 +\&{case} \\{whatsit\_node}:\5 +\&{case} \\{penalty\_node}:\5 +\&{case} \\{disc\_node}:\5 +\&{goto} \\{done\_with\_node};\6 +\4\&{case} \\{rule\_node}:\6 +${}\{{}$\5 +\1\&{if} ${}(\\{height}(\|q)>\\{max\_h}){}$\1\5 +${}\\{max\_h}\K\\{height}(\|q);{}$\2\6 +\&{if} ${}(\\{depth}(\|q)>\\{max\_d}){}$\1\5 +${}\\{max\_d}\K\\{depth}(\|q);{}$\2\6 +\&{goto} \\{done\_with\_node};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{glue\_node}:\6 +${}\{{}$\5 +\1\X732:Convert \(m)math glue to ordinary glue\X;\6 +\&{goto} \\{done\_with\_node};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{kern\_node}:\6 +${}\{{}$\5 +\1${}\\{math\_kern}(\|q,\39\\{cur\_mu});{}$\5 +\&{goto} \\{done\_with\_node};\6 +\4${}\}{}$\2\par +\U728.\fi + +\M{731}\B\D$\\{choose\_mlist}(\|X)$ \6 +${}\{{}$\5 +\1${}\|p\K\|X(\|q);{}$\5 +${}\|X(\|q)\K\\{null}{}$;\5 +${}\}{}$\2\par +\Y\B\4\X731:Change this node to a style node followed by the correct choice, then \&{goto} \\{done\_with\_node}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{switch} ${}(\\{cur\_style}/\T{2}){}$\5 +${}\{{}$\1\6 +\4\&{case} \T{0}:\5 +\\{choose\_mlist}(\\{display\_mlist})\5 +\&{break};\C{$\\{display\_style}\E\T{0}$}\6 +\4\&{case} \T{1}:\5 +\\{choose\_mlist}(\\{text\_mlist})\5 +\&{break};\C{$\\{text\_style}\E\T{2}$}\6 +\4\&{case} \T{2}:\5 +\\{choose\_mlist}(\\{script\_mlist})\5 +\&{break};\C{$\\{script\_style}\E\T{4}$}\6 +\4\&{case} \T{3}:\5 +\\{choose\_mlist}(\\{script\_script\_mlist});\C{$\\{script\_script\_style}\E\T{6}$}\6 +\4${}\}{}$\C{there are no other cases}\2\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)\K\T{0};{}$\5 +${}\\{depth}(\|q)\K\T{0};{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\|z\K\\{link}(\|q);{}$\5 +${}\\{link}(\|q)\K\|p;{}$\6 +\&{while} ${}(\\{link}(\|p)\I\\{null}){}$\1\5 +${}\|p\K\\{link}(\|p);{}$\2\6 +${}\\{link}(\|p)\K\|z;{}$\6 +\4${}\}{}$\2\6 +\&{goto} \\{done\_with\_node};\6 +\4${}\}{}$\2\par +\U730.\fi + +\M{732}Conditional math glue (`\.{\\nonscript}') results in a \\{glue\_node} +pointing to \\{zero\_glue}, with $\\{subtype}(\|q)\E\\{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\B\4\X732:Convert \(m)math glue to ordinary glue\X${}\E{}$\6 +\&{if} ${}(\\{subtype}(\|q)\E\\{mu\_glue}){}$\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}((\\{cur\_size}\I\\{text\_size})\W(\\{subtype}(\|q)\E\\{cond\_math\_glue})){}$\5 +${}\{{}$\5 +\1${}\|p\K\\{link}(\|q);{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\1\6 +\&{if} ${}((\\{type}(\|p)\E\\{glue\_node})\V(\\{type}(\|p)\E\\{kern\_node})){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|q)\K\\{link}(\|p);{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\5 +\\{flush\_node\_list}(\|p);\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\par +\U730.\fi + +\M{733}\B\X733:Cases for noads that can follow a \\{bin\_noad}\X${}\E{}$\6 +\4\&{case} \\{left\_noad}:\5 +\&{goto} \\{done\_with\_noad};\6 +\4\&{case} \\{fraction\_noad}:\6 +${}\{{}$\5 +\1\\{make\_fraction}(\|q);\5 +\&{goto} \\{check\_dimensions};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{op\_noad}:\6 +${}\{{}$\5 +\1${}\\{delta}\K\\{make\_op}(\|q);{}$\6 +\&{if} ${}(\\{subtype}(\|q)\E\\{limits}){}$\1\5 +\&{goto} \\{check\_dimensions};\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{ord\_noad}:\5 +\\{make\_ord}(\|q);\5 +\&{break};\6 +\4\&{case} \\{open\_noad}:\5 +\&{case} \\{inner\_noad}:\5 +\\{do\_nothing};\5 +\&{break};\6 +\4\&{case} \\{radical\_noad}:\5 +\\{make\_radical}(\|q);\5 +\&{break};\6 +\4\&{case} \\{over\_noad}:\5 +\\{make\_over}(\|q);\5 +\&{break};\6 +\4\&{case} \\{under\_noad}:\5 +\\{make\_under}(\|q);\5 +\&{break};\6 +\4\&{case} \\{accent\_noad}:\5 +\\{make\_math\_accent}(\|q);\5 +\&{break};\6 +\4\&{case} \\{vcenter\_noad}:\5 +\\{make\_vcenter}(\|q);\5 +\&{break};\par +\U728.\fi + +\M{734}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\B\4\X734:Declare math construction procedures\X${}\E{}$\6 +\&{void} \\{make\_over}(\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{info}(\\{nucleus}(\|q))\K\30\\{overbar}(\\{clean\_box}(\\{nucleus}(\|q),\39\\{cramped\_style}(\\{cur\_style})),\30\39\T{3}*\\{default\_rule\_thickness},\39\\{default\_rule\_thickness});{}$\5 +${}\\{math\_type}(\\{nucleus}(\|q))\K\\{sub\_box};{}$\6 +\4${}\}{}$\2\par +\As735, 736, 737, 738, 743, 749, 752, 756\ETs762. +\U726.\fi + +\M{735}\B\X734:Declare math construction procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{make\_under}(\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|x${},{}$ \|y;\C{temporary registers for box construction}\6 +\&{scaled} \\{delta};\C{overall height plus depth}\7 +${}\|x\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cur\_style});{}$\5 +${}\|p\K\\{new\_kern}(\T{3}*\\{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 +\4${}\}{}$\2\par +\fi + +\M{736}\B\X734:Declare math construction procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{make\_vcenter}(\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|v;\C{the box that should be centered vertically}\6 +\&{scaled} \\{delta};\C{its height plus depth}\7 +${}\|v\K\\{info}(\\{nucleus}(\|q));{}$\6 +\&{if} ${}(\\{type}(\|v)\I\\{vlist\_node}){}$\1\5 +\\{confusion}(\X1561:\.{"vcenter"}\X);\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 +\4${}\}{}$\2\par +\fi + +\M{737}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\B\4\X734:Declare math construction procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{make\_radical}(\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|x${},{}$ \|y;\C{temporary registers for box construction}\6 +\&{scaled} \\{delta}${},{}$ \\{clr};\C{dimensions involved in the calculation}\7 +${}\|x\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cramped\_style}(\\{cur\_style}));{}$\6 +\&{if} ${}(\\{cur\_style}<\\{text\_style}{}$)\C{display style}\1\6 +${}\\{clr}\K\\{default\_rule\_thickness}+(\\{abs}(\\{math\_x\_height}(\\{cur\_size}))/\T{4});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{clr}\K\\{default\_rule\_thickness};{}$\5 +${}\\{clr}\K\\{clr}+(\\{abs}(\\{clr})/\T{4});{}$\6 +\4${}\}{}$\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}>\T{0}){}$\1\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 +\4${}\}{}$\2\par +\fi + +\M{738}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\B\4\X734:Declare math construction procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{make\_math\_accent}(\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|x${},{}$ \|y;\C{temporary registers for box construction}\6 +\&{int} \|a;\C{address of lig/kern instruction}\6 +\&{quarterword} \|c;\C{accent character}\6 +\&{internal\_font\_number} \|f;\C{its font}\6 +\&{four\_quarters} \|i;\C{its \\{char\_info}}\6 +\&{scaled} \|s;\C{amount to skew the accent to the right}\6 +\&{scaled} \|h;\C{height of character being accented}\6 +\&{scaled} \\{delta};\C{space to remove between accent and accentee}\6 +\&{scaled} \|w;\C{width of the accentee, not including sub/superscripts}\7 +\\{fetch}(\\{accent\_chr}(\|q));\6 +\&{if} (\\{char\_exists}(\\{cur\_i}))\5 +${}\{{}$\5 +\1${}\|i\K\\{cur\_i};{}$\5 +${}\|c\K\\{cur\_c};{}$\5 +${}\|f\K\\{cur\_f}{}$;\6 +\X741:Compute the amount of skew\X;\6 +${}\|x\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cramped\_style}(\\{cur\_style}));{}$\5 +${}\|w\K\\{width}(\|x);{}$\5 +${}\|h\K\\{height}(\|x);{}$\5 +\X740:Switch to a larger accent if available and appropriate\X;\6 +\&{if} ${}(\|h<\\{x\_height}(\|f)){}$\1\5 +${}\\{delta}\K\|h{}$;\5 +\2\&{else}\1\5 +${}\\{delta}\K\\{x\_height}(\|f);{}$\2\6 +\&{if} ${}((\\{math\_type}(\\{supscr}(\|q))\I\\{empty})\V(\\{math\_type}(\\{subscr}(\|q))\I\\{empty})){}$\1\6 +\&{if} ${}(\\{math\_type}(\\{nucleus}(\|q))\E\\{math\_char}){}$\1\5 +\X742: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)\K\T{0};{}$\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\5 +\X739: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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{739}\B\X739:Make the height of box \|y equal to \|h\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\par +\U738.\fi + +\M{740}\B\X740:Switch to a larger accent if available and appropriate\X${}\E{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{char\_tag}(\|i)\I\\{list\_tag}){}$\1\5 +\&{goto} \\{done};\2\6 +${}\|y\K\\{rem\_byte}(\|i);{}$\5 +${}\|i\K\\{char\_info}(\|f)(\|y);{}$\6 +\&{if} ${}(\R\\{char\_exists}(\|i)){}$\1\5 +\&{goto} \\{done};\2\6 +\&{if} ${}(\\{char\_width}(\|f)(\|i)>\|w){}$\1\5 +\&{goto} \\{done};\2\6 +${}\|c\K\|y;{}$\6 +\4${}\}{}$\2\6 +\\{done}:\par +\U738.\fi + +\M{741}\B\X741:Compute the amount of skew\X${}\E{}$\6 +$\|s\K\T{0};{}$\6 +\&{if} ${}(\\{math\_type}(\\{nucleus}(\|q))\E\\{math\_char}){}$\5 +${}\{{}$\5 +\1\\{fetch}(\\{nucleus}(\|q));\6 +\&{if} ${}(\\{char\_tag}(\\{cur\_i})\E\\{lig\_tag}){}$\5 +${}\{{}$\5 +\1${}\|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}){}$\5 +${}\{{}$\5 +\1${}\|a\K\\{lig\_kern\_restart}(\\{cur\_f})(\\{cur\_i});{}$\5 +${}\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq};{}$\6 +\4${}\}{}$\2\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{qo}(\\{next\_char}(\\{cur\_i}))\E\\{skew\_char}[\\{cur\_f}]){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{op\_byte}(\\{cur\_i})\G\\{kern\_flag}){}$\1\6 +\&{if} ${}(\\{skip\_byte}(\\{cur\_i})\Z\\{stop\_flag}){}$\1\5 +${}\|s\K\\{char\_kern}(\\{cur\_f})(\\{cur\_i});{}$\2\2\6 +\&{goto} \\{done1};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{skip\_byte}(\\{cur\_i})\G\\{stop\_flag}){}$\1\5 +\&{goto} \\{done1};\2\6 +${}\|a\K\|a+\\{qo}(\\{skip\_byte}(\\{cur\_i}))+\T{1};{}$\5 +${}\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\\{done1}:\par +\U738.\fi + +\M{742}\B\X742:Swap the subscript and superscript into box \|x\X${}\E{}$\6 +${}\{{}$\5 +\1\\{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});{}$\5 +${}\\{delta}\K\\{delta}+\\{height}(\|x)-\|h;{}$\5 +${}\|h\K\\{height}(\|x);{}$\6 +\4${}\}{}$\2\par +\U738.\fi + +\M{743}The \\{make\_fraction} procedure is a bit different because it sets +\\{new\_hlist}(\|q) directly rather than making a sub-box. + +\Y\B\4\X734:Declare math construction procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{make\_fraction}(\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|v${},{}$ \|x${},{}$ \|y${},{}$ \|z;\C{temporary registers for box construction}\6 +\&{scaled} \\{delta}${},{}$ \\{delta1}${},{}$ \\{delta2}${},{}$ \\{shift\_up}${},{}$ \\{shift\_down}${},{}$ \\{clr};\C{dimensions for box calculations}\7 +\&{if} ${}(\\{thickness}(\|q)\E\\{default\_code}){}$\1\5 +${}\\{thickness}(\|q)\K\\{default\_rule\_thickness};{}$\2\6 +\X744: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)\E\T{0}){}$\1\5 +\X745:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of no fraction line\X\2\6 +\&{else}\1\5 +\X746:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of a fraction line\X;\2\6 +\X747:Construct a vlist box for the fraction, according to \\{shift\_up} and \\{shift\_down}\X;\6 +\X748:Put the \(f)fraction into a box with its delimiters, and make \\{new\_hlist}(\|q) point to it\X;\6 +\4${}\}{}$\2\par +\fi + +\M{744}\B\X744: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${}\E{}$\6 +$\|x\K\\{clean\_box}(\\{numerator}(\|q),\39\\{num\_style}(\\{cur\_style}));{}$\5 +${}\|z\K\\{clean\_box}(\\{denominator}(\|q),\39\\{denom\_style}(\\{cur\_style}));{}$\6 +\&{if} ${}(\\{width}(\|x)<\\{width}(\|z)){}$\1\5 +${}\|x\K\\{rebox}(\|x,\39\\{width}(\|z));{}$\2\6 +\&{else}\1\5 +${}\|z\K\\{rebox}(\|z,\39\\{width}(\|x));{}$\2\6 +\&{if} ${}(\\{cur\_style}<\\{text\_style}{}$)\C{display style}\6 +${}\{{}$\5 +\1${}\\{shift\_up}\K\\{num1}(\\{cur\_size});{}$\5 +${}\\{shift\_down}\K\\{denom1}(\\{cur\_size});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{shift\_down}\K\\{denom2}(\\{cur\_size});{}$\6 +\&{if} ${}(\\{thickness}(\|q)\I\T{0}){}$\1\5 +${}\\{shift\_up}\K\\{num2}(\\{cur\_size});{}$\2\6 +\&{else}\1\5 +${}\\{shift\_up}\K\\{num3}(\\{cur\_size});{}$\2\6 +\4${}\}{}$\2\par +\U743.\fi + +\M{745}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 \T{2}\\{delta}. + +\Y\B\4\X745:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of no fraction line\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_style}<\\{text\_style}){}$\1\5 +${}\\{clr}\K\T{7}*\\{default\_rule\_thickness};{}$\2\6 +\&{else}\1\5 +${}\\{clr}\K\T{3}*\\{default\_rule\_thickness};{}$\2\6 +${}\\{delta}\K\\{half}(\\{clr}-((\\{shift\_up}-\\{depth}(\|x))-(\\{height}(\|z)-\\{shift\_down})));{}$\6 +\&{if} ${}(\\{delta}>\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{shift\_up}\K\\{shift\_up}+\\{delta};{}$\5 +${}\\{shift\_down}\K\\{shift\_down}+\\{delta};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U743.\fi + +\M{746}In the case of a fraction line, the minimum clearance depends on the actual +thickness of the line. + +\Y\B\4\X746:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of a fraction line\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_style}<\\{text\_style}){}$\1\5 +${}\\{clr}\K\T{3}*\\{thickness}(\|q);{}$\2\6 +\&{else}\1\5 +${}\\{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}>\T{0}){}$\1\5 +${}\\{shift\_up}\K\\{shift\_up}+\\{delta1};{}$\2\6 +\&{if} ${}(\\{delta2}>\T{0}){}$\1\5 +${}\\{shift\_down}\K\\{shift\_down}+\\{delta2};{}$\2\6 +\4${}\}{}$\2\par +\U743.\fi + +\M{747}\B\X747:Construct a vlist box for the fraction, according to \\{shift\_up} and \\{shift\_down}\X${}\E{}$\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)\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\|p\K\\{new\_kern}((\\{shift\_up}-\\{depth}(\|x))-(\\{height}(\|z)-\\{shift\_down}));{}$\5 +${}\\{link}(\|p)\K\|z;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +${}\\{link}(\|x)\K\|p;$ $\\{list\_ptr}(\|v)\K{}$\|x\par +\U743.\fi + +\M{748}\B\X748:Put the \(f)fraction into a box with its delimiters, and make \\{new\_hlist}(\|q) point to it\X${}\E{}$\6 +\&{if} ${}(\\{cur\_style}<\\{text\_style}){}$\1\5 +${}\\{delta}\K\\{delim1}(\\{cur\_size});{}$\2\6 +\&{else}\1\5 +${}\\{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 +\U743.\fi + +\M{749}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\B\4\X734:Declare math construction procedures\X${}\mathrel+\E{}$\6 +\&{scaled} \\{make\_op}(\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1\&{scaled} \\{delta};\C{offset between subscript and superscript}\6 +\&{pointer} \|p${},{}$ \|v${},{}$ \|x${},{}$ \|y${},{}$ \|z;\C{temporary registers for box construction}\6 +\&{quarterword} \|c;\5 +\&{four\_quarters} \|i;\C{registers for character examination}\6 +\&{scaled} \\{shift\_up}${},{}$ \\{shift\_down};\C{dimensions for box calculation}\7 +\&{if} ${}((\\{subtype}(\|q)\E\\{normal})\W(\\{cur\_style}<\\{text\_style})){}$\1\5 +${}\\{subtype}(\|q)\K\\{limits};{}$\2\6 +\&{if} ${}(\\{math\_type}(\\{nucleus}(\|q))\E\\{math\_char}){}$\5 +${}\{{}$\5 +\1\\{fetch}(\\{nucleus}(\|q));\6 +\&{if} ${}((\\{cur\_style}<\\{text\_style})\W(\\{char\_tag}(\\{cur\_i})\E\\{list\_tag}){}$)\C{make it larger}\6 +${}\{{}$\5 +\1${}\|c\K\\{rem\_byte}(\\{cur\_i});{}$\5 +${}\|i\K\\{char\_info}(\\{cur\_f})(\|c);{}$\6 +\&{if} (\\{char\_exists}(\|i))\5 +${}\{{}$\5 +\1${}\\{cur\_c}\K\|c;{}$\5 +${}\\{cur\_i}\K\|i;{}$\5 +${}\\{character}(\\{nucleus}(\|q))\K\|c;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +${}\\{delta}\K\\{char\_italic}(\\{cur\_f})(\\{cur\_i});{}$\5 +${}\|x\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cur\_style});{}$\6 +\&{if} ${}((\\{math\_type}(\\{subscr}(\|q))\I\\{empty})\W(\\{subtype}(\|q)\I\\{limits})){}$\1\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 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{delta}\K\T{0};{}$\2\6 +\&{if} ${}(\\{subtype}(\|q)\E\\{limits}){}$\1\5 +\X750:Construct a box with limits above and below it, skewed by \\{delta}\X;\2\6 +\&{return} \\{delta};\6 +\4${}\}{}$\2\par +\fi + +\M{750}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\B\4\X750:Construct a box with limits above and below it, skewed by \\{delta}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|x\K\\{clean\_box}(\\{supscr}(\|q),\39\\{sup\_style}(\\{cur\_style}));{}$\5 +${}\|y\K\\{clean\_box}(\\{nucleus}(\|q),\39\\{cur\_style});{}$\5 +${}\|z\K\\{clean\_box}(\\{subscr}(\|q),\39\\{sub\_style}(\\{cur\_style}));{}$\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\5 +${}\\{width}(\|v)\K\\{width}(\|x);{}$\2\6 +\&{if} ${}(\\{width}(\|z)>\\{width}(\|v)){}$\1\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 +\X751:Attach the limits to \|y and adjust \\{height}(\|v), \\{depth}(\|v) to account for their presence\X;\6 +${}\\{new\_hlist}(\|q)\K\|v;{}$\6 +\4${}\}{}$\2\par +\U749.\fi + +\M{751}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\B\4\X751:Attach the limits to \|y and adjust \\{height}(\|v), \\{depth}(\|v) to account for their presence\X${}\E{}$\6 +\&{if} ${}(\\{math\_type}(\\{supscr}(\|q))\E\\{empty}){}$\5 +${}\{{}$\5 +\1${}\\{free\_node}(\|x,\39\\{box\_node\_size});{}$\5 +${}\\{list\_ptr}(\|v)\K\|y;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{shift\_up}\K\\{big\_op\_spacing3}-\\{depth}(\|x);{}$\6 +\&{if} ${}(\\{shift\_up}<\\{big\_op\_spacing1}){}$\1\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 +\4${}\}{}$\2\6 +\&{if} ${}(\\{math\_type}(\\{subscr}(\|q))\E\\{empty}){}$\1\5 +${}\\{free\_node}(\|z,\39\\{box\_node\_size});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{shift\_down}\K\\{big\_op\_spacing4}-\\{height}(\|z);{}$\6 +\&{if} ${}(\\{shift\_down}<\\{big\_op\_spacing2}){}$\1\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 +\4${}\}{}$\2\par +\U750.\fi + +\M{752}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}\E\T{0}$). + +No boundary characters enter into these ligatures. + +\Y\B\4\X734:Declare math construction procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{make\_ord}(\&{pointer} \|q)\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|a;\C{address of lig/kern instruction}\6 +\&{pointer} \|p${},{}$ \|r;\C{temporary registers for list manipulation}\7 +\4\\{restart}:\5 +\hbox{}\6 +\&{if} ${}(\\{math\_type}(\\{subscr}(\|q))\E\\{empty}){}$\1\6 +\&{if} ${}(\\{math\_type}(\\{supscr}(\|q))\E\\{empty}){}$\1\6 +\&{if} ${}(\\{math\_type}(\\{nucleus}(\|q))\E\\{math\_char}){}$\5 +${}\{{}$\5 +\1${}\|p\K\\{link}(\|q);{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\1\6 +\&{if} ${}((\\{type}(\|p)\G\\{ord\_noad})\W(\\{type}(\|p)\Z\\{punct\_noad})){}$\1\6 +\&{if} ${}(\\{math\_type}(\\{nucleus}(\|p))\E\\{math\_char}){}$\1\6 +\&{if} ${}(\\{fam}(\\{nucleus}(\|p))\E\\{fam}(\\{nucleus}(\|q))){}$\5 +${}\{{}$\5 +\1${}\\{math\_type}(\\{nucleus}(\|q))\K\\{math\_text\_char};{}$\5 +\\{fetch}(\\{nucleus}(\|q));\6 +\&{if} ${}(\\{char\_tag}(\\{cur\_i})\E\\{lig\_tag}){}$\5 +${}\{{}$\5 +\1${}\|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}){}$\5 +${}\{{}$\5 +\1${}\|a\K\\{lig\_kern\_restart}(\\{cur\_f})(\\{cur\_i});{}$\5 +${}\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq};{}$\6 +\4${}\}{}$\2\6 +\&{loop}\5 +${}\{{}$\5 +\1\X753: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\5 +\&{return};\2\6 +${}\|a\K\|a+\\{qo}(\\{skip\_byte}(\\{cur\_i}))+\T{1};{}$\5 +${}\\{cur\_i}\K\\{font\_info}[\|a].\\{qqqq};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\2\2\2\6 +\4${}\}{}$\2\2\2\6 +\4${}\}{}$\2\par +\fi + +\M{753}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\B\4\X753: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${}% +\E{}$\6 +\&{if} ${}(\\{next\_char}(\\{cur\_i})\E\\{cur\_c}){}$\1\6 +\&{if} ${}(\\{skip\_byte}(\\{cur\_i})\Z\\{stop\_flag}){}$\1\6 +\&{if} ${}(\\{op\_byte}(\\{cur\_i})\G\\{kern\_flag}){}$\5 +${}\{{}$\5 +\1${}\|p\K\\{new\_kern}(\\{char\_kern}(\\{cur\_f})(\\{cur\_i}));{}$\5 +${}\\{link}(\|p)\K\\{link}(\|q);{}$\5 +${}\\{link}(\|q)\K\|p;{}$\5 +\&{return};\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{check\_interrupt};\C{allow a way out of infinite ligature loop}\6 +\&{switch} (\\{op\_byte}(\\{cur\_i}))\5 +${}\{{}$\1\6 +\4\\{qi}(\&{case} \T{1}):\5 +\\{qi}(\&{case} \T{5}):\5 +${}\\{character}(\\{nucleus}(\|q))\K\\{rem\_byte}(\\{cur\_i}){}$;\5 +\&{break};\C{\.{=:\?}, \.{=:\?>}}\6 +\4\\{qi}(\&{case} \T{2}):\5 +\\{qi}(\&{case} \T{6}):\5 +${}\\{character}(\\{nucleus}(\|p))\K\\{rem\_byte}(\\{cur\_i}){}$;\5 +\&{break};\C{\.{\?=:}, \.{\?=:>}}\6 +\4\\{qi}(\&{case} \T{3}):\5 +\\{qi}(\&{case} \T{7}):\5 +\\{qi}(\&{case} \T{11}):\6 +${}\{{}$\5 +\1${}\|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}(\T{11})){}$\1\5 +${}\\{math\_type}(\\{nucleus}(\|r))\K\\{math\_char};{}$\2\6 +\&{else}\1\5 +${}\\{math\_type}(\\{nucleus}(\|r))\K\\{math\_text\_char}{}$;\C{prevent combination}\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\6 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{op\_byte}(\\{cur\_i})>\\{qi}(\T{3})){}$\1\5 +\&{return};\2\6 +${}\\{math\_type}(\\{nucleus}(\|q))\K\\{math\_char};{}$\5 +\&{goto} \\{restart};\6 +\4${}\}{}$\2\2\2\par +\U752.\fi + +\M{754}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\B\4\X754:Convert \(n)\\{nucleus}(\|q) to an hlist and attach the sub/superscripts\X${}\E{}$\6 +\&{switch} (\\{math\_type}(\\{nucleus}(\|q)))\5 +${}\{{}$\1\6 +\4\&{case} \\{math\_char}:\5 +\&{case} \\{math\_text\_char}:\5 +\X755: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\5 +\&{break};\6 +\4\&{case} \\{empty}:\5 +${}\|p\K\\{null}{}$;\5 +\&{break};\6 +\4\&{case} \\{sub\_box}:\5 +${}\|p\K\\{info}(\\{nucleus}(\|q)){}$;\5 +\&{break};\6 +\4\&{case} \\{sub\_mlist}:\6 +${}\{{}$\5 +\1${}\\{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 +\X703: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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1665:\.{"mlist2"}\X);\6 +\4${}\}{}$\2\6 +${}\\{new\_hlist}(\|q)\K\|p;{}$\6 +\&{if} ${}((\\{math\_type}(\\{subscr}(\|q))\E\\{empty})\W(\\{math\_type}(\\{supscr}(\|q))\E\\{empty})){}$\1\5 +\&{goto} \\{check\_dimensions};\2\6 +$\\{make\_scripts}(\|q,\39\\{delta}{}$)\par +\U728.\fi + +\M{755}\B\X755: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${}\E{}$\6 +${}\{{}$\5 +\1\\{fetch}(\\{nucleus}(\|q));\6 +\&{if} (\\{char\_exists}(\\{cur\_i}))\5 +${}\{{}$\5 +\1${}\\{delta}\K\\{char\_italic}(\\{cur\_f})(\\{cur\_i});{}$\5 +${}\|p\K\\{new\_character}(\\{cur\_f},\39\\{qo}(\\{cur\_c}));{}$\6 +\&{if} ${}((\\{math\_type}(\\{nucleus}(\|q))\E\\{math\_text\_char})\W(\\{space}(\\{cur\_f})\I\T{0})){}$\1\5 +${}\\{delta}\K\T{0}{}$;\C{no italic correction in mid-word of text font}\2\6 +\&{if} ${}((\\{math\_type}(\\{subscr}(\|q))\E\\{empty})\W(\\{delta}\I\T{0})){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|p)\K\\{new\_kern}(\\{delta});{}$\5 +${}\\{delta}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\|p\K\\{null};{}$\2\6 +\4${}\}{}$\2\par +\U754.\fi + +\M{756}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 the 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\B\4\X734:Declare math construction procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{make\_scripts}(\&{pointer} \|q${},\39{}$\&{scaled} \\{delta})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|x${},{}$ \|y${},{}$ \|z;\C{temporary registers for box construction}\6 +\&{scaled} \\{shift\_up}${},{}$ \\{shift\_down}${},{}$ \\{clr};\C{dimensions in the calculation}\6 +\&{small\_number} \|t;\C{subsidiary size code}\7 +${}\|p\K\\{new\_hlist}(\|q);{}$\6 +\&{if} (\\{is\_char\_node}(\|p))\5 +${}\{{}$\5 +\1${}\\{shift\_up}\K\T{0};{}$\5 +${}\\{shift\_down}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|z\K\\{hpack}(\|p,\39\\{natural});{}$\6 +\&{if} ${}(\\{cur\_style}<\\{script\_style}){}$\1\5 +${}\|t\K\\{script\_size}{}$;\5 +\2\&{else}\1\5 +${}\|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 +${}\\{free\_node}(\|z,\39\\{box\_node\_size});{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{math\_type}(\\{supscr}(\|q))\E\\{empty}){}$\1\5 +\X757:Construct a subscript box \|x when there is no superscript\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\X758:Construct a superscript box \|x\X;\6 +\&{if} ${}(\\{math\_type}(\\{subscr}(\|q))\E\\{empty}){}$\1\5 +${}\\{shift\_amount}(\|x)\K{-}\\{shift\_up};{}$\2\6 +\&{else}\1\5 +\X759:Construct a sub/superscript combination box \|x, with the superscript offset by \\{delta}\X;\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{new\_hlist}(\|q)\E\\{null}){}$\1\5 +${}\\{new\_hlist}(\|q)\K\|x;{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|p\K\\{new\_hlist}(\|q);{}$\6 +\&{while} ${}(\\{link}(\|p)\I\\{null}){}$\1\5 +${}\|p\K\\{link}(\|p);{}$\2\6 +${}\\{link}(\|p)\K\|x;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{757}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\B\4\X757:Construct a subscript box \|x when there is no superscript\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|x\K\\{clean\_box}(\\{subscr}(\|q),\39\\{sub\_style}(\\{cur\_style}));{}$\5 +${}\\{width}(\|x)\K\\{width}(\|x)+\\{script\_space};{}$\6 +\&{if} ${}(\\{shift\_down}<\\{sub1}(\\{cur\_size})){}$\1\5 +${}\\{shift\_down}\K\\{sub1}(\\{cur\_size});{}$\2\6 +${}\\{clr}\K\\{height}(\|x)-(\\{abs}(\\{math\_x\_height}(\\{cur\_size})*\T{4})/\T{5});{}$\6 +\&{if} ${}(\\{shift\_down}<\\{clr}){}$\1\5 +${}\\{shift\_down}\K\\{clr};{}$\2\6 +${}\\{shift\_amount}(\|x)\K\\{shift\_down};{}$\6 +\4${}\}{}$\2\par +\U756.\fi + +\M{758}The bottom of a superscript should never descend below the baseline plus +one-fourth of the x-height. + +\Y\B\4\X758:Construct a superscript box \|x\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|x\K\\{clean\_box}(\\{supscr}(\|q),\39\\{sup\_style}(\\{cur\_style}));{}$\5 +${}\\{width}(\|x)\K\\{width}(\|x)+\\{script\_space};{}$\6 +\&{if} (\\{odd}(\\{cur\_style}))\1\5 +${}\\{clr}\K\\{sup3}(\\{cur\_size});{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_style}<\\{text\_style}){}$\1\5 +${}\\{clr}\K\\{sup1}(\\{cur\_size});{}$\2\6 +\&{else}\1\5 +${}\\{clr}\K\\{sup2}(\\{cur\_size});{}$\2\6 +\&{if} ${}(\\{shift\_up}<\\{clr}){}$\1\5 +${}\\{shift\_up}\K\\{clr};{}$\2\6 +${}\\{clr}\K\\{depth}(\|x)+(\\{abs}(\\{math\_x\_height}(\\{cur\_size}))/\T{4});{}$\6 +\&{if} ${}(\\{shift\_up}<\\{clr}){}$\1\5 +${}\\{shift\_up}\K\\{clr};{}$\2\6 +\4${}\}{}$\2\par +\U756.\fi + +\M{759}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\B\4\X759:Construct a sub/superscript combination box \|x, with the superscript offset by \\{delta}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|y\K\\{clean\_box}(\\{subscr}(\|q),\39\\{sub\_style}(\\{cur\_style}));{}$\5 +${}\\{width}(\|y)\K\\{width}(\|y)+\\{script\_space};{}$\6 +\&{if} ${}(\\{shift\_down}<\\{sub2}(\\{cur\_size})){}$\1\5 +${}\\{shift\_down}\K\\{sub2}(\\{cur\_size});{}$\2\6 +${}\\{clr}\K\T{4}*\\{default\_rule\_thickness}-((\\{shift\_up}-\\{depth}(\|x))-(\\{height}(\|y)-\\{shift\_down}));{}$\6 +\&{if} ${}(\\{clr}>\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{shift\_down}\K\\{shift\_down}+\\{clr};{}$\5 +${}\\{clr}\K(\\{abs}(\\{math\_x\_height}(\\{cur\_size})*\T{4})/\T{5})-(\\{shift\_up}-\\{depth}(\|x));{}$\6 +\&{if} ${}(\\{clr}>\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{shift\_up}\K\\{shift\_up}+\\{clr};{}$\5 +${}\\{shift\_down}\K\\{shift\_down}-\\{clr};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\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 +\4${}\}{}$\2\par +\U756.\fi + +\M{760}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\B\4\X760:Make a second pass over the mlist, removing all noads and inserting the proper spacing and penalties\X${}\E{}$\6 +$\|p\K\\{temp\_head};{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\5 +${}\|q\K\\{mlist};{}$\5 +${}\\{r\_type}\K\T{0};{}$\5 +${}\\{cur\_style}\K\\{style};{}$\5 +\X703:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur\_style}\X;\6 +\&{while} ${}(\|q\I\\{null}){}$\5 +${}\{{}$\5 +\1\X761: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}\MRL{{.}{.}}\\{inner\_noad}$), and set \\{pen} to the associated penalty\X;\6 +\X766:Append inter-element spacing based on \\{r\_type} and \|t\X;\6 +\X767:Append any \\{new\_hlist} entries for \|q, and any appropriate penalties\X;\6 +${}\\{r\_type}\K\|t;{}$\6 +\4\\{delete\_q}:\5 +${}\|r\K\|q;{}$\5 +${}\|q\K\\{link}(\|q);{}$\5 +${}\\{free\_node}(\|r,\39\|s);{}$\6 +\4\\{done}:\5 +;\6 +\4${}\}{}$\2\par +\U726.\fi + +\M{761}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\B\4\X761: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}\MRL{{.}{.}}\\{inner\_noad}$), and set \\{pen} to the associated penalty\X${}\E{}$\6 +$\|t\K\\{ord\_noad};{}$\5 +${}\|s\K\\{noad\_size};{}$\5 +${}\\{pen}\K\\{inf\_penalty};{}$\6 +\&{switch} (\\{type}(\|q))\5 +${}\{{}$\1\6 +\4\&{case} \\{op\_noad}:\5 +\&{case} \\{open\_noad}:\5 +\&{case} \\{close\_noad}:\5 +\&{case} \\{punct\_noad}:\5 +\&{case} \\{inner\_noad}:\5 +${}\|t\K\\{type}(\|q){}$;\5 +\&{break};\6 +\4\&{case} \\{bin\_noad}:\6 +${}\{{}$\5 +\1${}\|t\K\\{bin\_noad};{}$\5 +${}\\{pen}\K\\{bin\_op\_penalty};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{rel\_noad}:\6 +${}\{{}$\5 +\1${}\|t\K\\{rel\_noad};{}$\5 +${}\\{pen}\K\\{rel\_penalty};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{ord\_noad}:\5 +\&{case} \\{vcenter\_noad}:\5 +\&{case} \\{over\_noad}:\5 +\&{case} \\{under\_noad}:\5 +\\{do\_nothing};\5 +\&{break};\6 +\4\&{case} \\{radical\_noad}:\5 +${}\|s\K\\{radical\_noad\_size}{}$;\5 +\&{break};\6 +\4\&{case} \\{accent\_noad}:\5 +${}\|s\K\\{accent\_noad\_size}{}$;\5 +\&{break};\6 +\4\&{case} \\{fraction\_noad}:\6 +${}\{{}$\5 +\1${}\|t\K\\{inner\_noad};{}$\5 +${}\|s\K\\{fraction\_noad\_size};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{left\_noad}:\5 +\&{case} \\{right\_noad}:\5 +${}\|t\K\\{make\_left\_right}(\|q,\39\\{style},\39\\{max\_d},\39\\{max\_h}){}$;\5 +\&{break};\6 +\4\&{case} \\{style\_node}:\5 +\X763:Change the current style and \&{goto} \\{delete\_q}\X\6 +\4\&{case} \\{whatsit\_node}:\5 +\&{case} \\{penalty\_node}:\5 +\&{case} \\{rule\_node}:\5 +\&{case} \\{disc\_node}:\5 +\&{case} \\{adjust\_node}:\5 +\&{case} \\{ins\_node}:\5 +\&{case} \\{mark\_node}:\5 +\&{case} \\{glue\_node}:\5 +\&{case} \\{kern\_node}:\5 +\hbox{}\6 +${}\{{}$\5 +\1${}\\{link}(\|p)\K\|q;{}$\5 +${}\|p\K\|q;{}$\5 +${}\|q\K\\{link}(\|q);{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\4\&{default}:\5 +\\{confusion}(\X1666:\.{"mlist3"}\X);\6 +\4${}\}{}$\2\par +\U760.\fi + +\M{762}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}\E\\{close\_noad}-\\{open\_noad}$. + +\Y\B\4\X734:Declare math construction procedures\X${}\mathrel+\E{}$\6 +\&{small\_number} \\{make\_left\_right}(\&{pointer} \|q${},\39{}$\&{small\_number} \\{style}${},\39{}$\&{scaled} \\{max\_d}${},\39{}$\&{scaled} \\{max\_h})\1\1\2\2\6 +${}\{{}$\5 +\1\&{scaled} \\{delta}${},{}$ \\{delta1}${},{}$ \\{delta2};\C{dimensions used in the calculation}\7 +\&{if} ${}(\\{style}<\\{script\_style}){}$\1\5 +${}\\{cur\_size}\K\\{text\_size};{}$\2\6 +\&{else}\1\5 +${}\\{cur\_size}\K\T{16}*((\\{style}-\\{text\_style})/\T{2});{}$\2\6 +${}\\{delta2}\K\\{max\_d}+\\{axis\_height}(\\{cur\_size});{}$\5 +${}\\{delta1}\K\\{max\_h}+\\{max\_d}-\\{delta2};{}$\6 +\&{if} ${}(\\{delta2}>\\{delta1}){}$\1\5 +${}\\{delta1}\K\\{delta2}{}$;\C{\\{delta1} is max distance from axis}\2\6 +${}\\{delta}\K(\\{delta1}/\T{500})*\\{delimiter\_factor};{}$\5 +${}\\{delta2}\K\\{delta1}+\\{delta1}-\\{delimiter\_shortfall};{}$\6 +\&{if} ${}(\\{delta}<\\{delta2}){}$\1\5 +${}\\{delta}\K\\{delta2};{}$\2\6 +${}\\{new\_hlist}(\|q)\K\\{var\_delimiter}(\\{delimiter}(\|q),\39\\{cur\_size},\39\\{delta});{}$\5 +\&{return} \\{type}(\|q)${}-(\\{left\_noad}-\\{open\_noad}){}$;\C{\\{open\_noad} or \\{close\_noad}}\6 +\4${}\}{}$\2\par +\fi + +\M{763}\B\X763:Change the current style and \&{goto} \\{delete\_q}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{cur\_style}\K\\{subtype}(\|q);{}$\5 +${}\|s\K\\{style\_node\_size};{}$\5 +\X703:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur\_style}\X;\6 +\&{goto} \\{delete\_q};\6 +\4${}\}{}$\2\par +\U761.\fi + +\M{764}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}\dotdot\\{inner\_noad}$, then $\\{str\_pool}[\|a*\T{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. + +\Y\B\4\D$\\{math\_spacing\_str}$ \6 +\hbox{\hskip-35pt}\.{"math\_spacing"}\hbox{$ \hskip-35pt$}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{magic\_offset};\C{used to find inter-element spacing}\par +\fi + +\M{765}\B\X765:Compute the magic offset\X${}\E{}$\6 +$\\{magic\_offset}\K\\{str\_start}[\\{math\_spacing}]-\T{9}*{}$\\{ord\_noad}\par +\U1337.\fi + +\M{766}\B\X766:Append inter-element spacing based on \\{r\_type} and \|t\X${}\E{}$\6 +\&{if} ${}(\\{r\_type}>\T{0}{}$)\C{not the first noad}\6 +${}\{{}$\5 +\1\&{switch} ${}(\\{so}(\\{str\_pool}[\\{r\_type}*\T{8}+\|t+\\{magic\_offset}])){}$\5 +${}\{{}$\1\6 +\4\&{case} \.{'0'}:\5 +${}\|x\K\T{0}{}$;\5 +\&{break};\6 +\4\&{case} \.{'1'}:\6 +\&{if} ${}(\\{cur\_style}<\\{script\_style}){}$\1\5 +${}\|x\K\\{thin\_mu\_skip\_code}{}$;\5 +\2\&{else}\1\5 +${}\|x\K\T{0}{}$;\5 +\2\&{break};\6 +\4\&{case} \.{'2'}:\5 +${}\|x\K\\{thin\_mu\_skip\_code}{}$;\5 +\&{break};\6 +\4\&{case} \.{'3'}:\6 +\&{if} ${}(\\{cur\_style}<\\{script\_style}){}$\1\5 +${}\|x\K\\{med\_mu\_skip\_code}{}$;\5 +\2\&{else}\1\5 +${}\|x\K\T{0}{}$;\5 +\2\&{break};\6 +\4\&{case} \.{'4'}:\6 +\&{if} ${}(\\{cur\_style}<\\{script\_style}){}$\1\5 +${}\|x\K\\{thick\_mu\_skip\_code}{}$;\5 +\2\&{else}\1\5 +${}\|x\K\T{0}{}$;\5 +\2\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1668:\.{"mlist4"}\X);\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|x\I\T{0}){}$\5 +${}\{{}$\5 +\1${}\|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+\T{1}{}$;\C{store a symbolic subtype}\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U760.\fi + +\M{767}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\B\4\X767:Append any \\{new\_hlist} entries for \|q, and any appropriate penalties\X${}\E{}$\6 +\&{if} ${}(\\{new\_hlist}(\|q)\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|p)\K\\{new\_hlist}(\|q){}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{link}(\|p)\E\\{null}));{}$\6 +\4${}\}{}$\2\6 +\&{if} (\\{penalties})\1\6 +\&{if} ${}(\\{link}(\|q)\I\\{null}){}$\1\6 +\&{if} ${}(\\{pen}<\\{inf\_penalty}){}$\5 +${}\{{}$\5 +\1${}\\{r\_type}\K\\{type}(\\{link}(\|q));{}$\6 +\&{if} ${}(\\{r\_type}\I\\{penalty\_node}){}$\1\6 +\&{if} ${}(\\{r\_type}\I\\{rel\_noad}){}$\5 +${}\{{}$\5 +\1${}\|z\K\\{new\_penalty}(\\{pen});{}$\5 +${}\\{link}(\|p)\K\|z;{}$\5 +${}\|p\K\|z;{}$\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\2\2\par +\U760.\fi + +\N{1}{768}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 + +\M{769}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\B\4\D$\\{u\_part}(\|X)$ \5 +$\\{mem}[\|X+\\{height\_offset}].{}$\|i\C{pointer to \<u_j> token list}\par +\B\4\D$\\{v\_part}(\|X)$ \5 +$\\{mem}[\|X+\\{depth\_offset}].{}$\|i\C{pointer to \<v_j> token list}\par +\B\4\D$\\{extra\_info}(\|X)$ \5 +$\\{info}(\|X+\\{list\_offset}{}$)\C{info to remember during template}\par +\fi + +\M{770}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\B\4\D$\\{preamble}$ \5 +\\{link}(\\{align\_head})\C{the current preamble list}\par +\B\4\D$\\{align\_stack\_node\_size}$ \5 +\T{5}\C{number of \\{mem} words to save alignment states}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{cur\_align};\C{current position in preamble list}\6 +\&{pointer} \\{cur\_span};\C{start of currently spanned columns in preamble list}\6 +\&{pointer} \\{cur\_loop};\C{place to copy when extending a periodic preamble}\6 +\&{pointer} \\{align\_ptr};\C{most recently pushed-down alignment stack node}\6 +\&{pointer} \\{cur\_head}${},{}$ \\{cur\_tail};\C{adjustment list pointers}\par +\fi + +\M{771}The \\{align\_state} and \\{preamble} variables are initialized elsewhere. + +\Y\B\4\X21:Set initial values of key variables\X${}\mathrel+\E{}$\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 + +\M{772}Alignment stack maintenance is handled by a pair of trivial routines +called \\{push\_alignment} and \\{pop\_alignment}. + +\Y\B\&{void} \\{push\_alignment}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new alignment stack node}\7 +${}\|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+\T{2}].\|i\K\\{cur\_loop};{}$\5 +${}\\{mem}[\|p+\T{3}].\|i\K\\{align\_state};{}$\5 +${}\\{info}(\|p+\T{4})\K\\{cur\_head};{}$\5 +${}\\{link}(\|p+\T{4})\K\\{cur\_tail};{}$\5 +${}\\{align\_ptr}\K\|p;{}$\5 +${}\\{cur\_head}\K\\{get\_avail}(\,);{}$\6 +\4${}\}{}$\2\7 +\&{void} \\{pop\_alignment}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the top alignment stack node}\7 +\\{free\_avail}(\\{cur\_head});\5 +${}\|p\K\\{align\_ptr};{}$\5 +${}\\{cur\_tail}\K\\{link}(\|p+\T{4});{}$\5 +${}\\{cur\_head}\K\\{info}(\|p+\T{4});{}$\5 +${}\\{align\_state}\K\\{mem}[\|p+\T{3}].\|i;{}$\5 +${}\\{cur\_loop}\K\\{mem}[\|p+\T{2}].\|i;{}$\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 +\4${}\}{}$\2\par +\fi + +\M{773}\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 + +\M{774}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\B\hbox{\4}\X782:Declare the procedure called \\{get\_preamble\_token}\X\hbox{}\1\1\6 +\&{void} \\{align\_peek}(\&{void});\6 +\&{void} \\{normal\_paragraph}(\&{void});\6 +\&{void} \\{init\_align}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \\{save\_cs\_ptr};\C{\\{warning\_index} value for error messages}\6 +\&{pointer} \|p;\C{for short-term temporary use}\7 +${}\\{save\_cs\_ptr}\K\\{cur\_cs}{}$;\C{\.{\\halign} or \.{\\valign}, usually}\6 +\\{push\_alignment}(\,);\5 +${}\\{align\_state}\K{-}\T{1000000}{}$;\C{enter a new alignment level}\6 +\X776:Check for improper alignment in displayed math\X;\6 +\\{push\_nest}(\,);\C{enter a new semantic level}\6 +\X775:Change current mode to ${-}\\{vmode}$ for \.{\\halign}, ${-}\\{hmode}$ for \.{\\valign}\X;\6 +${}\\{scan\_spec}(\\{align\_group},\39\\{false}){}$;\6 +\X777:Scan the preamble and record it in the \\{preamble} list\X;\6 +\\{new\_save\_level}(\\{align\_group});\6 +\&{if} ${}(\\{every\_cr}\I\\{null}){}$\1\5 +${}\\{begin\_token\_list}(\\{every\_cr},\39\\{every\_cr\_text});{}$\2\6 +\\{align\_peek}(\,);\C{look for \.{\\noalign} or \.{\\omit}}\6 +\4${}\}{}$\2\par +\fi + +\M{775}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\B\4\X775:Change current mode to ${-}\\{vmode}$ for \.{\\halign}, ${-}\\{hmode}$ for \.{\\valign}\X${}\E{}$\6 +\&{if} ${}(\\{mode}\E\\{mmode}){}$\5 +${}\{{}$\5 +\1${}\\{mode}\K{-}\\{vmode};{}$\5 +${}\\{prev\_depth}\K\\{nest}[\\{nest\_ptr}-\T{2}].\\{aux\_field}.\\{sc};{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{mode}>\T{0})$ \\{negate}(\\{mode})\par +\U774.\fi + +\M{776}When \.{\\halign} is used as a displayed formula, there should be +no other pieces of mlists present. + +\Y\B\4\X776:Check for improper alignment in displayed math\X${}\E{}$\6 +\&{if} ${}((\\{mode}\E\\{mmode})\W((\\{tail}\I\\{head})\V(\\{incompleat\_noad}\I\\{null}))){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Improper\ "});\5 +\\{print\_esc}(\X1542:\.{"halign"}\X);\5 +\\{print\_str}(\.{"\ inside\ \$\$'s"});\5 +\\{help3}(\.{"Displays\ can\ use\ sp}\)\.{ecial\ alignments\ (li}\)\.{ke\ \\\\eqalignno)"})\6 +(\.{"only\ if\ nothing\ but}\)\.{\ the\ alignment\ itsel}\)\.{f\ is\ between\ \$\$'s."})\6 +(\.{"So\ I've\ deleted\ the}\)\.{\ formulas\ that\ prece}\)\.{ded\ this\ alignment."});\6 +\&{error} (\,)\1\5 +;\2\6 +\\{flush\_math}(\,);\6 +\4${}\}{}$\2\par +\U774.\fi + +\M{777}\B\X777:Scan the preamble and record it in the \\{preamble} list\X${}\E{}$\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{-}\T{1000000}{}$;\C{at this point, $\\{cur\_cmd}\E\\{left\_brace}$}\6 +\&{loop}\5 +${}\{{}$\5 +\1\X778:Append the current tabskip glue to the preamble list\X;\6 +\&{if} ${}(\\{cur\_cmd}\E\\{car\_ret}){}$\1\5 +\&{goto} \\{done};\C{\.{\\cr} ends the preamble}\2\6 +\X779: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 +\4${}\}{}$\2\6 +\\{done}: $\\{scanner\_status}\K{}$\\{normal}\par +\U774.\fi + +\M{778}\B\X778:Append the current tabskip glue to the preamble list\X${}\E{}$\6 +$\\{link}(\\{cur\_align})\K\\{new\_param\_glue}(\\{tab\_skip\_code});$ $\\{cur\_align}\K\\{link}{}$(\\{cur\_align})\par +\U777.\fi + +\M{779}\B\X779: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${}\E{}$\6 +\X783: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 +\X784:Scan the template \<v_j>, putting the resulting token list in \\{hold\_head}\X;\6 +$\\{v\_part}(\\{cur\_align})\K\\{link}{}$(\\{hold\_head})\par +\U777.\fi + +\M{780}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\B\4\D$\\{span\_code}$ \5 +\T{256}\C{distinct from any character}\par +\B\4\D$\\{cr\_code}$ \5 +\T{257}\C{distinct from \\{span\_code} and from any character}\par +\B\4\D$\\{cr\_cr\_code}$ \5 +$(\\{cr\_code}+\T{1}{}$)\C{this distinguishes \.{\\crcr} from \.{\\cr}}\par +\B\4\D$\\{end\_template\_token}$ \5 +$\\{cs\_token\_flag}+{}$\\{frozen\_end\_template}\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1669:\.{"span"}\X,\39\\{tab\_mark},\39\\{span\_code}){}$;\6 +${}\\{primitive}(\X1670:\.{"cr"}\X,\39\\{car\_ret},\39\\{cr\_code});{}$\5 +${}\\{text}(\\{frozen\_cr})\K\X1670:\.{"cr"}\X;{}$\5 +${}\\{eqtb}[\\{frozen\_cr}]\K\\{eqtb}[\\{cur\_val}]{}$;\6 +${}\\{primitive}(\X1671:\.{"crcr"}\X,\39\\{car\_ret},\39\\{cr\_cr\_code});{}$\5 +${}\\{text}(\\{frozen\_end\_template})\K\X1672:\.{"endtemplate"}\X;{}$\5 +${}\\{text}(\\{frozen\_endv})\K\X1672:\.{"endtemplate"}\X;{}$\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 + +\M{781}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{tab\_mark}:\6 +\&{if} ${}(\\{chr\_code}\E\\{span\_code}){}$\1\5 +\\{print\_esc}(\X1669:\.{"span"}\X);\2\6 +\&{else}\1\5 +\\{chr\_cmd}(\.{"alignment\ tab\ chara}\)\.{cter\ "})\5 +\2\&{break};\6 +\4\&{case} \\{car\_ret}:\6 +\&{if} ${}(\\{chr\_code}\E\\{cr\_code}){}$\1\5 +\\{print\_esc}(\X1670:\.{"cr"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1671:\.{"crcr"}\X);\5 +\2\&{break};\par +\fi + +\M{782}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\B\4\X782:Declare the procedure called \\{get\_preamble\_token}\X${}\E{}$\6 +\&{void} \\{get\_preamble\_token}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{restart}:\5 +\\{get\_token}(\,);\6 +\&{while} ${}((\\{cur\_chr}\E\\{span\_code})\W(\\{cur\_cmd}\E\\{tab\_mark})){}$\5 +${}\{{}$\5 +\1\\{get\_token}(\,);\C{this token will be expanded once}\6 +\&{if} ${}(\\{cur\_cmd}>\\{max\_command}){}$\5 +${}\{{}$\5 +\1\\{expand}(\,);\5 +\\{get\_token}(\,);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{endv}){}$\1\5 +\\{fatal\_error}(\.{"(interwoven\ alignme}\)\.{nt\ preambles\ are\ not}\)\.{\ allowed)"});\2\6 +\&{if} ${}((\\{cur\_cmd}\E\\{assign\_glue})\W(\\{cur\_chr}\E\\{glue\_base}+\\{tab\_skip\_code})){}$\5 +${}\{{}$\5 +\1\\{scan\_optional\_equals}(\,);\5 +\\{scan\_glue}(\\{glue\_val});\6 +\&{if} ${}(\\{global\_defs}>\T{0}){}$\1\5 +${}\\{geq\_define}(\\{glue\_base}+\\{tab\_skip\_code},\39\\{glue\_ref},\39\\{cur\_val});{}$\2\6 +\&{else}\1\5 +${}\\{eq\_define}(\\{glue\_base}+\\{tab\_skip\_code},\39\\{glue\_ref},\39\\{cur\_val});{}$\2\6 +\&{goto} \\{restart};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U774.\fi + +\M{783}Spaces are eliminated from the beginning of a template. + +\Y\B\4\X783:Scan the template \<u_j>, putting the resulting token list in \\{hold\_head}\X${}\E{}$\6 +$\|p\K\\{hold\_head};{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{get\_preamble\_token}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\E\\{mac\_param}){}$\1\5 +\&{goto} \\{done1};\2\6 +\&{if} ${}((\\{cur\_cmd}\Z\\{car\_ret})\W(\\{cur\_cmd}\G\\{tab\_mark})\W(\\{align\_state}\E{-}\T{1000000})){}$\1\6 +\&{if} ${}((\|p\E\\{hold\_head})\W(\\{cur\_loop}\E\\{null})\W(\\{cur\_cmd}\E\\{tab\_mark})){}$\1\5 +${}\\{cur\_loop}\K\\{cur\_align};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ \#\ inserted\ }\)\.{in\ alignment\ preambl}\)\.{e"});\5 +\\{help3}(\.{"There\ should\ be\ exa}\)\.{ctly\ one\ \#\ between\ \&}\)\.{'s,\ when\ an"})\6 +(\.{"\\\\halign\ or\ \\\\valig}\)\.{n\ is\ being\ set\ up.\ I}\)\.{n\ this\ case\ you\ had"})\6 +(\.{"none,\ so\ I've\ put\ o}\)\.{ne\ in;\ maybe\ that\ wi}\)\.{ll\ work."});\5 +\\{back\_error}(\,);\5 +\&{goto} \\{done1};\6 +\4${}\}{}$\2\2\6 +\&{else} \&{if} ${}((\\{cur\_cmd}\I\\{spacer})\V(\|p\I\\{hold\_head})){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|p)\K\\{get\_avail}(\,);{}$\5 +${}\|p\K\\{link}(\|p);{}$\5 +${}\\{info}(\|p)\K\\{cur\_tok};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\\{done1}:\par +\U779.\fi + +\M{784}\B\X784:Scan the template \<v_j>, putting the resulting token list in \\{hold\_head}\X${}\E{}$\6 +$\|p\K\\{hold\_head};{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{resume}:\5 +\\{get\_preamble\_token}(\,);\6 +\&{if} ${}((\\{cur\_cmd}\Z\\{car\_ret})\W(\\{cur\_cmd}\G\\{tab\_mark})\W(\\{align\_state}\E{-}\T{1000000})){}$\1\5 +\&{goto} \\{done2};\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{mac\_param}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Only\ one\ \#\ is\ allow}\)\.{ed\ per\ tab"});\5 +\\{help3}(\.{"There\ should\ be\ exa}\)\.{ctly\ one\ \#\ between\ \&}\)\.{'s,\ when\ an"})\6 +(\.{"\\\\halign\ or\ \\\\valig}\)\.{n\ is\ being\ set\ up.\ I}\)\.{n\ this\ case\ you\ had"})\6 +(\.{"more\ than\ one,\ so\ I}\)\.{'m\ ignoring\ all\ but\ }\)\.{the\ first."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\6 +${}\\{link}(\|p)\K\\{get\_avail}(\,);{}$\5 +${}\|p\K\\{link}(\|p);{}$\5 +${}\\{info}(\|p)\K\\{cur\_tok};{}$\6 +\4${}\}{}$\2\6 +\4\\{done2}:\5 +${}\\{link}(\|p)\K\\{get\_avail}(\,);{}$\5 +${}\|p\K\\{link}(\|p);$ $\\{info}(\|p)\K{}$\\{end\_template\_token}\C{put \.{\\endtemplate} at the end}\par +\U779.\fi + +\M{785}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\B\4\X785:Declare the procedure called \\{align\_peek}\X${}\E{}$\6 +\&{void} \\{align\_peek}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{restart}:\5 +${}\\{align\_state}\K\T{1000000};{}$\5 +\X406:Get the next non-blank non-call token\X;\6 +\&{if} ${}(\\{cur\_cmd}\E\\{no\_align}){}$\5 +${}\{{}$\5 +\1\\{scan\_left\_brace}(\,);\5 +\\{new\_save\_level}(\\{no\_align\_group});\6 +\&{if} ${}(\\{mode}\E{-}\\{vmode}){}$\1\5 +\\{normal\_paragraph}(\,);\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}\E\\{right\_brace}){}$\1\5 +\\{fin\_align}(\,);\2\6 +\&{else} \&{if} ${}((\\{cur\_cmd}\E\\{car\_ret})\W(\\{cur\_chr}\E\\{cr\_cr\_code})){}$\1\5 +\&{goto} \\{restart};\C{ignore \.{\\crcr}}\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{init\_row}(\,);\C{start a new row}\6 +\\{init\_col}(\,);\C{start a new column and replace what we peeked at}\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U800.\fi + +\M{786}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\B\hbox{\4}\X787:Declare the procedure called \\{init\_span}\X\hbox{}\1\1\6 +\&{void} \\{init\_row}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{push\_nest}(\,);\5 +${}\\{mode}\K({-}\\{hmode}-\\{vmode})-\\{mode};{}$\6 +\&{if} ${}(\\{mode}\E{-}\\{hmode}){}$\1\5 +${}\\{space\_factor}\K\T{0}{}$;\5 +\2\&{else}\1\5 +${}\\{prev\_depth}\K\T{0};{}$\2\6 +\\{tail\_append}(\\{new\_glue}(\\{glue\_ptr}(\\{preamble})));\5 +${}\\{subtype}(\\{tail})\K\\{tab\_skip\_code}+\T{1}{}$;\6 +${}\\{cur\_align}\K\\{link}(\\{preamble});{}$\5 +${}\\{cur\_tail}\K\\{cur\_head};{}$\5 +\\{init\_span}(\\{cur\_align});\6 +\4${}\}{}$\2\par +\fi + +\M{787}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\B\4\X787:Declare the procedure called \\{init\_span}\X${}\E{}$\6 +\&{void} \\{init\_span}(\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\\{push\_nest}(\,);\6 +\&{if} ${}(\\{mode}\E{-}\\{hmode}){}$\1\5 +${}\\{space\_factor}\K\T{1000};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{prev\_depth}\K\\{ignore\_depth};{}$\5 +\\{normal\_paragraph}(\,);\6 +\4${}\}{}$\2\6 +${}\\{cur\_span}\K\|p;{}$\6 +\4${}\}{}$\2\par +\U786.\fi + +\M{788}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\B\&{void} \\{init\_col}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{extra\_info}(\\{cur\_align})\K\\{cur\_cmd};{}$\6 +\&{if} ${}(\\{cur\_cmd}\E\\{omit}){}$\1\5 +${}\\{align\_state}\K\T{0};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +${}\\{begin\_token\_list}(\\{u\_part}(\\{cur\_align}),\39\\{u\_template});{}$\6 +\4${}\}{}$\C{now $\\{align\_state}\E\T{1000000}$}\2\6 +\4${}\}{}$\2\par +\fi + +\M{789}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}\E\T{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\B\4\X789:Insert the \(v)\<v_j> template and \&{goto} \\{restart}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}((\\{scanner\_status}\E\\{aligning})\V(\\{cur\_align}\E\\{null})){}$\1\5 +\\{fatal\_error}(\.{"(interwoven\ alignme}\)\.{nt\ 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}\E\\{omit}){}$\1\5 +${}\\{begin\_token\_list}(\\{omit\_template},\39\\{v\_template});{}$\2\6 +\&{else}\1\5 +${}\\{begin\_token\_list}(\\{v\_part}(\\{cur\_align}),\39\\{v\_template});{}$\2\6 +${}\\{align\_state}\K\T{1000000};{}$\5 +\&{goto} \\{restart};\6 +\4${}\}{}$\2\par +\U342.\fi + +\M{790}The token list \\{omit\_template} just referred to is a constant token +list that contains the special control sequence \.{\\endtemplate} only. + +\Y\B\4\X790:Initialize the special list heads and constant nodes\X${}\E{}$\6 +$\\{info}(\\{omit\_template})\K\\{end\_template\_token}{}$;\C{$\\{link}(\\{omit\_template})\E\\{null}$}\par +\As797, 820, 981\ETs988. +\U164.\fi + +\M{791}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\B\&{bool} \\{fin\_col}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the alignrecord after the current one}\6 +\&{pointer} \|q${},{}$ \|r;\C{temporary pointers for list manipulation}\6 +\&{pointer} \|s;\C{a new span node}\6 +\&{pointer} \|u;\C{a new unset box}\6 +\&{scaled} \|w;\C{natural width}\6 +\&{glue\_ord} \|o;\C{order of infinity}\6 +\&{halfword} \|n;\C{span counter}\7 +\&{if} ${}(\\{cur\_align}\E\\{null}){}$\1\5 +\\{confusion}(\X1673:\.{"endv"}\X);\2\6 +${}\|q\K\\{link}(\\{cur\_align}){}$;\5 +\&{if} ${}(\|q\E\\{null}){}$\1\5 +\\{confusion}(\X1673:\.{"endv"}\X);\2\6 +\&{if} ${}(\\{align\_state}<\T{500000}){}$\1\5 +\\{fatal\_error}(\.{"(interwoven\ alignme}\)\.{nt\ preambles\ are\ not}\)\.{\ allowed)"});\2\6 +${}\|p\K\\{link}(\|q);{}$\5 +\X792:If the preamble list has been traversed, check that the row has ended\X;\6 +\&{if} ${}(\\{extra\_info}(\\{cur\_align})\I\\{span\_code}){}$\5 +${}\{{}$\5 +\1\\{unsave}(\,);\5 +\\{new\_save\_level}(\\{align\_group});\6 +\X796:Package an unset box for the current column and record its width\X;\6 +\X795:Copy the tabskip glue between columns\X;\6 +\&{if} ${}(\\{extra\_info}(\\{cur\_align})\G\\{cr\_code}){}$\5 +${}\{{}$\5 +\1\&{return} \\{true};\6 +\4${}\}{}$\2\6 +\\{init\_span}(\|p);\6 +\4${}\}{}$\2\6 +${}\\{align\_state}\K\T{1000000};{}$\5 +\X406:Get the next non-blank non-call token\X;\6 +${}\\{cur\_align}\K\|p;{}$\5 +\\{init\_col}(\,);\5 +\&{return} \\{false};\6 +\4${}\}{}$\2\par +\fi + +\M{792}\B\X792:If the preamble list has been traversed, check that the row has ended\X${}\E{}$\6 +\&{if} ${}((\|p\E\\{null})\W(\\{extra\_info}(\\{cur\_align})<\\{cr\_code})){}$\1\6 +\&{if} ${}(\\{cur\_loop}\I\\{null}){}$\1\5 +\X793:Lengthen the preamble periodically\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Extra\ alignment\ tab}\)\.{\ has\ been\ changed\ to}\)\.{\ "});\5 +\\{print\_esc}(\X1670:\.{"cr"}\X);\5 +\\{help3}(\.{"You\ have\ given\ more}\)\.{\ \\\\span\ or\ \&\ marks\ t}\)\.{han\ there\ were"})\6 +(\.{"in\ the\ preamble\ to\ }\)\.{the\ \\\\halign\ or\ \\\\va}\)\.{lign\ now\ in\ progress}\)\.{."})\6 +(\.{"So\ I'll\ assume\ that}\)\.{\ you\ meant\ to\ type\ \\}\)\.{\\cr\ instead."});\5 +${}\\{extra\_info}(\\{cur\_align})\K\\{cr\_code};{}$\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\2\par +\U791.\fi + +\M{793}\B\X793:Lengthen the preamble periodically\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{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 +\X794: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 +\4${}\}{}$\2\par +\U792.\fi + +\M{794}\B\X794:Copy the templates from node \\{cur\_loop} into node \|p\X${}\E{}$\6 +$\|q\K\\{hold\_head};{}$\5 +${}\|r\K\\{u\_part}(\\{cur\_loop});{}$\6 +\&{while} ${}(\|r\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|q)\K\\{get\_avail}(\,);{}$\5 +${}\|q\K\\{link}(\|q);{}$\5 +${}\\{info}(\|q)\K\\{info}(\|r);{}$\5 +${}\|r\K\\{link}(\|r);{}$\6 +\4${}\}{}$\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}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|q)\K\\{get\_avail}(\,);{}$\5 +${}\|q\K\\{link}(\|q);{}$\5 +${}\\{info}(\|q)\K\\{info}(\|r);{}$\5 +${}\|r\K\\{link}(\|r);{}$\6 +\4${}\}{}$\2\6 +${}\\{link}(\|q)\K\\{null};$ $\\{v\_part}(\|p)\K\\{link}{}$(\\{hold\_head})\par +\U793.\fi + +\M{795}\B\X795:Copy the tabskip glue between columns\X${}\E{}$\6 +\\{tail\_append}(\\{new\_glue}(\\{glue\_ptr}(\\{link}(\\{cur\_align})))); $\\{subtype}(\\{tail})\K\\{tab\_skip\_code}+{}$\T{1}\par +\U791.\fi + +\M{796}\B\X796:Package an unset box for the current column and record its width\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{mode}\E{-}\\{hmode}){}$\5 +${}\{{}$\5 +\1${}\\{adjust\_tail}\K\\{cur\_tail};{}$\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 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|u\K\\{vpackage}(\\{link}(\\{head}),\39\\{natural},\39\T{0});{}$\5 +${}\|w\K\\{height}(\|u);{}$\6 +\4${}\}{}$\2\6 +${}\|n\K\\{min\_quarterword}{}$;\C{this represents a span count of 1}\6 +\&{if} ${}(\\{cur\_span}\I\\{cur\_align}){}$\1\5 +\X798:Update width entry for spanned columns\X\2\6 +\&{else} \&{if} ${}(\|w>\\{width}(\\{cur\_align})){}$\1\5 +${}\\{width}(\\{cur\_align})\K\|w;{}$\2\6 +${}\\{type}(\|u)\K\\{unset\_node};{}$\5 +${}\\{span\_count}(\|u)\K\|n{}$;\6 +\X659:Determine the stretch order\X;\6 +${}\\{glue\_order}(\|u)\K\|o;{}$\5 +${}\\{glue\_stretch}(\|u)\K\\{total\_stretch}[\|o]{}$;\6 +\X665: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 +\4${}\}{}$\2\par +\U791.\fi + +\M{797}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\B\4\D$\\{span\_node\_size}$ \5 +\T{2}\C{number of \\{mem} words for a span node}\par +\Y\B\4\X790:Initialize the special list heads and constant nodes\X${}\mathrel+\E{}$\6 +$\\{link}(\\{end\_span})\K\\{max\_quarterword}+\T{1};{}$\5 +${}\\{info}(\\{end\_span})\K\\{null}{}$;\par +\fi + +\M{798}\B\X798:Update width entry for spanned columns\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|q\K\\{cur\_span}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\\{incr}(\|n);\5 +${}\|q\K\\{link}(\\{link}(\|q));{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|q\E\\{cur\_align}));{}$\6 +\&{if} ${}(\|n>\\{max\_quarterword}){}$\1\5 +\\{confusion}(\X1674:\.{"256\ spans"}\X);\C{this can happen, but won't}\2\6 +${}\|q\K\\{cur\_span};{}$\6 +\&{while} ${}(\\{link}(\\{info}(\|q))<\|n){}$\1\5 +${}\|q\K\\{info}(\|q);{}$\2\6 +\&{if} ${}(\\{link}(\\{info}(\|q))>\|n){}$\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{width}(\\{info}(\|q))<\|w){}$\1\5 +${}\\{width}(\\{info}(\|q))\K\|w;{}$\2\6 +\4${}\}{}$\2\par +\U796.\fi + +\M{799}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\B\&{void} \\{fin\_row}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new unset box}\7 +\&{if} ${}(\\{mode}\E{-}\\{hmode}){}$\5 +${}\{{}$\5 +\1${}\|p\K\\{hpack}(\\{link}(\\{head}),\39\\{natural});{}$\5 +\\{pop\_nest}(\,);\5 +\\{append\_to\_vlist}(\|p);\6 +\&{if} ${}(\\{cur\_head}\I\\{cur\_tail}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\\{tail})\K\\{link}(\\{cur\_head});{}$\5 +${}\\{tail}\K\\{cur\_tail};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|p\K\\{vpack}(\\{link}(\\{head}),\39\\{natural});{}$\5 +\\{pop\_nest}(\,);\5 +${}\\{link}(\\{tail})\K\|p;{}$\5 +${}\\{tail}\K\|p;{}$\5 +${}\\{space\_factor}\K\T{1000};{}$\6 +\4${}\}{}$\2\6 +${}\\{type}(\|p)\K\\{unset\_node};{}$\5 +${}\\{glue\_stretch}(\|p)\K\T{0};{}$\6 +\&{if} ${}(\\{every\_cr}\I\\{null}){}$\1\5 +${}\\{begin\_token\_list}(\\{every\_cr},\39\\{every\_cr\_text});{}$\2\6 +\\{align\_peek}(\,);\6 +\4${}\}{}$\C{note that $\\{glue\_shrink}(\|p)\E\T{0}$ since $\\{glue\_shrink}\MRL{{\E}{\E}}\\{shift\_amount}$}\2\par +\fi + +\M{800}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\B\&{void} \\{do\_assignments}(\&{void});\6 +\&{void} \\{resume\_after\_display}(\&{void});\6 +\&{void} \\{build\_page}(\&{void});\7 +\&{void} \\{fin\_align}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|q${},{}$ \|r${},{}$ \|s${},{}$ \|u${},{}$ \|v;\C{registers for the list operations}\6 +\&{scaled} \|t${},{}$ \|w;\C{width of column}\6 +\&{scaled} \|o;\C{shift offset for unset boxes}\6 +\&{halfword} \|n;\C{matching span amount}\6 +\&{scaled} \\{rule\_save};\C{temporary storage for \\{overfull\_rule}}\6 +\&{memory\_word} \\{aux\_save};\C{temporary storage for \\{aux}}\7 +\&{if} ${}(\\{cur\_group}\I\\{align\_group}){}$\1\5 +\\{confusion}(\X1675:\.{"align1"}\X);\2\6 +\\{unsave}(\,);\C{that \\{align\_group} was for individual entries}\6 +\&{if} ${}(\\{cur\_group}\I\\{align\_group}){}$\1\5 +\\{confusion}(\X1676:\.{"align0"}\X);\2\6 +\\{unsave}(\,);\C{that \\{align\_group} was for the whole alignment}\6 +\&{if} ${}(\\{nest}[\\{nest\_ptr}-\T{1}].\\{mode\_field}\E\\{mmode}){}$\1\5 +${}\|o\K\\{display\_indent};{}$\2\6 +\&{else}\1\5 +${}\|o\K\T{0};{}$\2\6 +\X801:Go through the preamble list, determining the column widths and changing the alignrecords to dummy unset boxes\X;\6 +\X804:Package the preamble list, to determine the actual tabskip glue amounts, and let \|p point to this prototype box\X;\6 +\X805:Set the glue in all the unset boxes of the current list\X;\6 +\\{flush\_node\_list}(\|p);\5 +\\{pop\_alignment}(\,);\5 +\X812:Insert the \(c)current list into its environment\X;\6 +\4${}\}{}$\2\7 +\hbox{\4}\X785:Declare the procedure called \\{align\_peek}\X\par +\fi + +\M{801}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 +$\T{1}\Z\|i\Z\|j$ (i.e., if every entry that involved column~\|j also involved +column~$\|j+\T{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\B\4\X801:Go through the preamble list, determining the column widths and changing the alignrecords to dummy unset boxes\X${}\E{}$\6 +$\|q\K\\{link}(\\{preamble}){}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\\{flush\_list}(\\{u\_part}(\|q));\5 +\\{flush\_list}(\\{v\_part}(\|q));\5 +${}\|p\K\\{link}(\\{link}(\|q));{}$\6 +\&{if} ${}(\\{width}(\|q)\E\\{null\_flag}){}$\1\5 +\X802:Nullify \\{width}(\|q) and the tabskip glue following this column\X;\2\6 +\&{if} ${}(\\{info}(\|q)\I\\{end\_span}){}$\1\5 +\X803: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)\K\T{0};{}$\5 +${}\\{depth}(\|q)\K\T{0};{}$\5 +${}\\{glue\_order}(\|q)\K\\{normal};{}$\5 +${}\\{glue\_sign}(\|q)\K\\{normal};{}$\5 +${}\\{glue\_stretch}(\|q)\K\T{0};{}$\5 +${}\\{glue\_shrink}(\|q)\K\T{0};{}$\5 +${}\|q\K\|p;{}$\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R(\|q\E\\{null}){}$)\par +\U800.\fi + +\M{802}\B\X802:Nullify \\{width}(\|q) and the tabskip glue following this column\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{width}(\|q)\K\T{0};{}$\5 +${}\|r\K\\{link}(\|q);{}$\5 +${}\|s\K\\{glue\_ptr}(\|r);{}$\6 +\&{if} ${}(\|s\I\\{zero\_glue}){}$\5 +${}\{{}$\5 +\1\\{add\_glue\_ref}(\\{zero\_glue});\5 +\\{delete\_glue\_ref}(\|s);\5 +${}\\{glue\_ptr}(\|r)\K\\{zero\_glue};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U801.\fi + +\M{803}Merging of two span-node lists is a typical exercise in the manipulation of +linearly linked data structures. The essential invariant in the following + \&{do} $\{$ 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)\E\|n$ or $\\{link}(\|r)>\|n$ or $\\{link}(\|r)<\|n$. + +\Y\B\4\X803:Merge the widths in the span nodes of \|q with those of \|p, destroying the span nodes of \|q\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|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}+\T{1}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\\{width}(\|r)\K\\{width}(\|r)-\|t;{}$\5 +${}\|u\K\\{info}(\|r);{}$\6 +\&{while} ${}(\\{link}(\|r)>\|n){}$\5 +${}\{{}$\5 +\1${}\|s\K\\{info}(\|s);{}$\5 +${}\|n\K\\{link}(\\{info}(\|s))+\T{1};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{link}(\|r)<\|n){}$\5 +${}\{{}$\5 +\1${}\\{info}(\|r)\K\\{info}(\|s);{}$\5 +${}\\{info}(\|s)\K\|r;{}$\5 +\\{decr}(\\{link}(\|r));\5 +${}\|s\K\|r;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{width}(\|r)>\\{width}(\\{info}(\|s))){}$\1\5 +${}\\{width}(\\{info}(\|s))\K\\{width}(\|r);{}$\2\6 +${}\\{free\_node}(\|r,\39\\{span\_node\_size});{}$\6 +\4${}\}{}$\2\6 +${}\|r\K\|u;{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|r\E\\{end\_span}));{}$\6 +\4${}\}{}$\2\par +\U801.\fi + +\M{804}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\B\4\X804:Package the preamble list, to determine the actual tabskip glue amounts, and let \|p point to this prototype box\X${}\E{}$\6 +$\\{save\_ptr}\K\\{save\_ptr}-\T{2};{}$\5 +${}\\{pack\_begin\_line}\K{-}\\{mode\_line};{}$\6 +\&{if} ${}(\\{mode}\E{-}\\{vmode}){}$\5 +${}\{{}$\5 +\1${}\\{rule\_save}\K\\{overfull\_rule};{}$\5 +${}\\{overfull\_rule}\K\T{0}{}$;\C{prevent rule from being packaged}\6 +${}\|p\K\\{hpack}(\\{preamble},\39\\{saved}(\T{1}),\39\\{saved}(\T{0}));{}$\5 +${}\\{overfull\_rule}\K\\{rule\_save};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{link}(\\{preamble}){}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\\{height}(\|q)\K\\{width}(\|q);{}$\5 +${}\\{width}(\|q)\K\T{0};{}$\5 +${}\|q\K\\{link}(\\{link}(\|q));{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|q\E\\{null}));{}$\5 +${}\|p\K\\{vpack}(\\{preamble},\39\\{saved}(\T{1}),\39\\{saved}(\T{0}));{}$\5 +${}\|q\K\\{link}(\\{preamble}){}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\\{width}(\|q)\K\\{height}(\|q);{}$\5 +${}\\{height}(\|q)\K\T{0};{}$\5 +${}\|q\K\\{link}(\\{link}(\|q));{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|q\E\\{null}));{}$\6 +\4${}\}{}$\2\6 +$\\{pack\_begin\_line}\K{}$\T{0}\par +\U800.\fi + +\M{805}\B\X805:Set the glue in all the unset boxes of the current list\X${}\E{}$\6 +$\|q\K\\{link}(\\{head});{}$\5 +${}\|s\K\\{head};{}$\6 +\&{while} ${}(\|q\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\R\\{is\_char\_node}(\|q)){}$\1\6 +\&{if} ${}(\\{type}(\|q)\E\\{unset\_node}){}$\1\5 +\X807:Set the unset box \|q and the unset boxes in it\X\2\6 +\&{else} \&{if} ${}(\\{type}(\|q)\E\\{rule\_node}){}$\1\5 +\X806:Make the running dimensions in rule \|q extend to the boundaries of the alignment\X;\2\2\6 +${}\|s\K\|q;{}$\5 +${}\|q\K\\{link}(\|q);{}$\6 +\4${}\}{}$\2\par +\U800.\fi + +\M{806}\B\X806:Make the running dimensions in rule \|q extend to the boundaries of the alignment\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} (\\{is\_running}(\\{width}(\|q)))\1\5 +${}\\{width}(\|q)\K\\{width}(\|p);{}$\2\6 +\&{if} (\\{is\_running}(\\{height}(\|q)))\1\5 +${}\\{height}(\|q)\K\\{height}(\|p);{}$\2\6 +\&{if} (\\{is\_running}(\\{depth}(\|q)))\1\5 +${}\\{depth}(\|q)\K\\{depth}(\|p);{}$\2\6 +\&{if} ${}(\|o\I\T{0}){}$\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U805.\fi + +\M{807}The unset box \|q represents a row that contains one or more unset boxes, +depending on how soon \.{\\cr} occurred in that row. + +\Y\B\4\X807:Set the unset box \|q and the unset boxes in it\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{mode}\E{-}\\{vmode}){}$\5 +${}\{{}$\5 +\1${}\\{type}(\|q)\K\\{hlist\_node};{}$\5 +${}\\{width}(\|q)\K\\{width}(\|p);{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{type}(\|q)\K\\{vlist\_node};{}$\5 +${}\\{height}(\|q)\K\\{height}(\|p);{}$\6 +\4${}\}{}$\2\6 +${}\\{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 +\&{do}\5 +${}\{{}$\1\6 +\X808: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${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|r\E\\{null}));{}$\6 +\4${}\}{}$\2\par +\U805.\fi + +\M{808}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\B\4\X808:Set the glue in node \|r and change it from an unset node\X${}\E{}$\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}){}$\5 +${}\{{}$\5 +\1\\{decr}(\|n);\5 +\X809:Append tabskip glue and an empty box to list \|u, and update \|s and \|t as the prototype nodes are passed\X;\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{mode}\E{-}\\{vmode}){}$\1\5 +\X810:Make the unset node \|r into an \\{hlist\_node} of width \|w, setting the glue as if the width were \|t\X\2\6 +\&{else}\1\5 +\X811: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)\K\T{0};{}$\6 +\&{if} ${}(\|u\I\\{hold\_head}{}$)\C{append blank boxes to account for spanned nodes}\6 +${}\{{}$\5 +\1${}\\{link}(\|u)\K\\{link}(\|r);{}$\5 +${}\\{link}(\|r)\K\\{link}(\\{hold\_head});{}$\5 +${}\|r\K\|u;{}$\6 +\4${}\}{}$\2\par +\U807.\fi + +\M{809}\B\X809:Append tabskip glue and an empty box to list \|u, and update \|s and \|t as the prototype nodes are passed\X${}\E{}$\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}+\T{1};{}$\5 +${}\|t\K\|t+\\{width}(\|v);{}$\6 +\&{if} ${}(\\{glue\_sign}(\|p)\E\\{stretching}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{stretch\_order}(\|v)\E\\{glue\_order}(\|p)){}$\1\5 +${}\|t\K\|t+\\{round}(\&{float}(\\{glue\_set}(\|p))*\\{stretch}(\|v));{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{glue\_sign}(\|p)\E\\{shrinking}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{shrink\_order}(\|v)\E\\{glue\_order}(\|p)){}$\1\5 +${}\|t\K\|t-\\{round}(\&{float}(\\{glue\_set}(\|p))*\\{shrink}(\|v));{}$\2\6 +\4${}\}{}$\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}\E{-}\\{vmode}){}$\1\5 +${}\\{width}(\|u)\K\\{width}(\|s){}$;\5 +\2\&{else}\5 +${}\{{}$\5 +\1${}\\{type}(\|u)\K\\{vlist\_node};{}$\5 +${}\\{height}(\|u)\K\\{width}(\|s);{}$\6 +\4${}\}{}$\2\par +\U808.\fi + +\M{810}\B\X810:Make the unset node \|r into an \\{hlist\_node} of width \|w, setting the glue as if the width were \|t\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{height}(\|r)\K\\{height}(\|q);{}$\5 +${}\\{depth}(\|r)\K\\{depth}(\|q);{}$\6 +\&{if} ${}(\|t\E\\{width}(\|r)){}$\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{normal};{}$\5 +${}\\{glue\_order}(\|r)\K\\{normal};{}$\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|t>\\{width}(\|r)){}$\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{stretching};{}$\6 +\&{if} ${}(\\{glue\_stretch}(\|r)\E\T{0}){}$\1\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\2\6 +\&{else}\1\5 +${}\\{glue\_set}(\|r)\K\\{unfloat}((\|t-\\{width}(\|r))/{}$(\&{double}) \\{glue\_stretch}(\|r));\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{glue\_order}(\|r)\K\\{glue\_sign}(\|r);{}$\5 +${}\\{glue\_sign}(\|r)\K\\{shrinking};{}$\6 +\&{if} ${}(\\{glue\_shrink}(\|r)\E\T{0}){}$\1\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\2\6 +\&{else} \&{if} ${}((\\{glue\_order}(\|r)\E\\{normal})\W(\\{width}(\|r)-\|t>\\{glue\_shrink}(\|r))){}$\1\5 +\\{set\_glue\_ratio\_one}(\\{glue\_set}(\|r));\2\6 +\&{else}\1\5 +${}\\{glue\_set}(\|r)\K\\{unfloat}((\\{width}(\|r)-\|t)/{}$(\&{double}) \\{glue\_shrink}(\|r));\2\6 +\4${}\}{}$\2\6 +${}\\{width}(\|r)\K\|w;{}$\5 +${}\\{type}(\|r)\K\\{hlist\_node};{}$\6 +\4${}\}{}$\2\par +\U808.\fi + +\M{811}\B\X811:Make the unset node \|r into a \\{vlist\_node} of height \|w, setting the glue as if the height were \|t\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{width}(\|r)\K\\{width}(\|q);{}$\6 +\&{if} ${}(\|t\E\\{height}(\|r)){}$\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{normal};{}$\5 +${}\\{glue\_order}(\|r)\K\\{normal};{}$\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|t>\\{height}(\|r)){}$\5 +${}\{{}$\5 +\1${}\\{glue\_sign}(\|r)\K\\{stretching};{}$\6 +\&{if} ${}(\\{glue\_stretch}(\|r)\E\T{0}){}$\1\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\2\6 +\&{else}\1\5 +${}\\{glue\_set}(\|r)\K\\{unfloat}((\|t-\\{height}(\|r))/{}$(\&{double}) \\{glue\_stretch}(\|r));\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{glue\_order}(\|r)\K\\{glue\_sign}(\|r);{}$\5 +${}\\{glue\_sign}(\|r)\K\\{shrinking};{}$\6 +\&{if} ${}(\\{glue\_shrink}(\|r)\E\T{0}){}$\1\5 +\\{set\_glue\_ratio\_zero}(\\{glue\_set}(\|r));\2\6 +\&{else} \&{if} ${}((\\{glue\_order}(\|r)\E\\{normal})\W(\\{height}(\|r)-\|t>\\{glue\_shrink}(\|r))){}$\1\5 +\\{set\_glue\_ratio\_one}(\\{glue\_set}(\|r));\2\6 +\&{else}\1\5 +${}\\{glue\_set}(\|r)\K\\{unfloat}((\\{height}(\|r)-\|t)/{}$(\&{double}) \\{glue\_shrink}(\|r));\2\6 +\4${}\}{}$\2\6 +${}\\{height}(\|r)\K\|w;{}$\5 +${}\\{type}(\|r)\K\\{vlist\_node};{}$\6 +\4${}\}{}$\2\par +\U808.\fi + +\M{812}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\B\4\X812:Insert the \(c)current list into its environment\X${}\E{}$\6 +$\\{aux\_save}\K\\{aux};{}$\5 +${}\|p\K\\{link}(\\{head});{}$\5 +${}\|q\K\\{tail};{}$\5 +\\{pop\_nest}(\,);\6 +\&{if} ${}(\\{mode}\E\\{mmode}){}$\1\5 +\X1206:Finish an alignment in a display\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{aux}\K\\{aux\_save};{}$\5 +${}\\{link}(\\{tail})\K\|p;{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\1\5 +${}\\{tail}\K\|q;{}$\2\6 +\&{if} ${}(\\{mode}\E\\{vmode}){}$\1\5 +\\{build\_page}(\,);\2\6 +\4${}\}{}$\2\par +\U800.\fi + +\N{1}{813}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 + +\M{814}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} +is 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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{just\_box};\C{the \\{hlist\_node} for the last line of the new paragraph}\par +\fi + +\M{815}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\B\hbox{\4}\X826:Declare subprocedures for \\{line\_break}\X\7 +\&{void} \\{line\_break}(\&{int} \\{final\_widow\_penalty})\1\1\2\2\6 +${}\{{}$\5 +\1\X862:Local variables for line breaking\X\6 +${}\\{pack\_begin\_line}\K\\{mode\_line}{}$;\C{this is for over/underfull box messages}\6 +\X816:Get ready to start line breaking\X;\6 +\X863:Find optimal breakpoints\X;\6 +\X876: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 +\X865:Clean up the memory by removing the break nodes\X;\6 +${}\\{pack\_begin\_line}\K\T{0};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{816}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\B\4\X816:Get ready to start line breaking\X${}\E{}$\6 +$\\{link}(\\{temp\_head})\K\\{link}(\\{head});{}$\6 +\&{if} (\\{is\_char\_node}(\\{tail}))\1\5 +\\{tail\_append}(\\{new\_penalty}(\\{inf\_penalty}))\2\6 +\&{else} \&{if} ${}(\\{type}(\\{tail})\I\\{glue\_node}){}$\1\5 +\\{tail\_append}(\\{new\_penalty}(\\{inf\_penalty}))\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\6 +${}\\{link}(\\{tail})\K\\{new\_param\_glue}(\\{par\_fill\_skip\_code});{}$\5 +${}\\{init\_cur\_lang}\K\\{prev\_graf}\MOD\T{\~200000};{}$\5 +${}\\{init\_l\_hyf}\K\\{prev\_graf}/\T{\~20000000};{}$\5 +${}\\{init\_r\_hyf}\K(\\{prev\_graf}/\T{\~200000})\MOD\T{\~100};{}$\5 +\\{pop\_nest}(\,);\par +\As827, 834\ETs848. +\U815.\fi + +\M{817}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\B\4\D$\\{tight\_fit}$ \5 +\T{3}\C{fitness classification for lines shrinking 0.5 to 1.0 of their shrinkability}\par +\B\4\D$\\{loose\_fit}$ \5 +\T{1}\C{fitness classification for lines stretching 0.5 to 1.0 of their stretchability}\par +\B\4\D$\\{very\_loose\_fit}$ \5 +\T{0}\C{fitness classification for lines stretching more than their stretchability}\par +\B\4\D$\\{decent\_fit}$ \5 +\T{2}\C{fitness classification for all other lines}\par +\fi + +\M{818}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 + +\M{819}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}\E\\{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\B\4\D$\\{active\_node\_size}$ \5 +\T{3}\C{number of words in active nodes}\par +\B\4\D$\\{fitness}$ \5 +\\{subtype}\C{$\\{very\_loose\_fit}\dotdot\\{tight\_fit}$ on final line for this break}\par +\B\4\D$\\{break\_node}$ \5 +\\{rlink}\C{pointer to the corresponding passive node}\par +\B\4\D$\\{line\_number}$ \5 +\\{llink}\C{line that begins at this breakpoint}\par +\B\4\D$\\{total\_demerits}(\|X)$ \5 +$\\{mem}[\|X+\T{2}].{}$\|i\C{the quantity that \TeX\ minimizes}\par +\B\4\D$\\{unhyphenated}$ \5 +\T{0}\C{the \\{type} of a normal active break node}\par +\B\4\D$\\{hyphenated}$ \5 +\T{1}\C{the \\{type} of an active node that breaks at a \\{disc\_node}}\par +\B\4\D$\\{last\_active}$ \5 +\\{active}\C{the active list ends where it begins}\par +\fi + +\M{820}\B\X790:Initialize the special list heads and constant nodes\X${}\mathrel+\E{}$\6 +$\\{type}(\\{last\_active})\K\\{hyphenated};{}$\5 +${}\\{line\_number}(\\{last\_active})\K\\{max\_halfword};{}$\5 +${}\\{subtype}(\\{last\_active})\K\T{0}{}$;\C{the \\{subtype} is never examined by the algorithm}\par +\fi + +\M{821}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\B\4\D$\\{passive\_node\_size}$ \5 +\T{2}\C{number of words in passive nodes}\par +\B\4\D$\\{cur\_break}$ \5 +\\{rlink}\C{in passive node, points to position of this breakpoint}\par +\B\4\D$\\{prev\_break}$ \5 +\\{llink}\C{points to passive node that should precede this one}\par +\B\4\D$\\{serial}$ \5 +\\{info}\C{serial number for symbolic identification}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{passive};\C{most recent node on passive list}\6 +\&{pointer} \\{printed\_node};\C{most recent node that has been printed}\6 +\&{halfword} \\{pass\_number};\C{the number of passive nodes allocated on this pass}\par +\fi + +\M{822}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}\E\\{delta\_node}$. If \|p and \|r are active nodes +and if \|q is a delta node between them, so that $\\{link}(\|p)\E\|q$ and $\\{link}(\|q)\E\|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+\T{1}].\\{sc}$; the stretch differences in units of +pt, fil, fill, and filll appear in $\\{mem}[\|q+\T{2}\dotdot\|q+\T{5}].\\{sc}$; and the shrink difference +appears in $\\{mem}[\|q+\T{6}].\\{sc}$. The \\{subtype} field of a delta node is not used. + +\Y\B\4\D$\\{delta\_node\_size}$ \5 +\T{7}\C{number of words in a delta node}\par +\B\4\D$\\{delta\_node}$ \5 +\T{2}\C{\\{type} field in a delta node}\par +\fi + +\M{823}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 $\K$ \T{1} \&{to} \T{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\B\4\D$\\{do\_all\_six}(\|X)$ \5 +\|X(\T{1});\5 +\|X(\T{2});\5 +\|X(\T{3});\5 +\|X(\T{4});\5 +\|X(\T{5}); \|X(\T{6})\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{scaled} \\{active\_width0}[\T{6}]${},{}$ ${}{*\&{const}\ }\\{active\_width}\K\\{active\_width0}-\T{1}{}$;\C{distance from first active node to~\\{cur\_p}}\6 +\&{scaled} \\{cur\_active\_width0}[\T{6}]${},{}$ ${}{*\&{const}\ }\\{cur\_active\_width}\K\\{cur\_active\_width0}-\T{1}{}$;\C{distance from current active node}\6 +\&{scaled} \\{background0}[\T{6}]${},{}$ ${}{*\&{const}\ }\\{background}\K\\{background0}-\T{1}{}$;\C{length of an ``empty'' line}\6 +\&{scaled} \\{break\_width0}[\T{6}]${},{}$ ${}{*\&{const}\ }\\{break\_width}\K\\{break\_width0}-\T{1}{}$;\C{length being computed after current break}\par +\fi + +\M{824}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 + +\M{825}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\B\4\D$\\{check\_shrinkage}(\|X)$ \6 +\&{if} ${}((\\{shrink\_order}(\|X)\I\\{normal})\W(\\{shrink}(\|X)\I\T{0})){}$\5 +${}\{{}$\5 +\1${}\|X\K\\{finite\_shrink}(\|X);{}$\6 +\4${}\}{}$\2\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{bool} \\{no\_shrink\_error\_yet};\C{have we complained about infinite shrinkage?}\par +\fi + +\M{826}\B\X826:Declare subprocedures for \\{line\_break}\X${}\E{}$\6 +\&{pointer} \\{finite\_shrink}(\&{pointer} \|p)\C{recovers from infinite shrinkage}\6 +${}\{{}$\5 +\1\&{pointer} \|q;\C{new glue specification}\7 +\&{if} (\\{no\_shrink\_error\_yet})\5 +${}\{{}$\5 +\1${}\\{no\_shrink\_error\_yet}\K\\{false};{}$\5 +\\{print\_err}(\.{"Infinite\ glue\ shrin}\)\.{kage\ found\ in\ a\ para}\)\.{graph"});\5 +\\{help5}(\.{"The\ paragraph\ just\ }\)\.{ended\ includes\ some\ }\)\.{glue\ that\ has"})\6 +(\.{"infinite\ shrinkabil}\)\.{ity,\ e.g.,\ `\\\\hskip\ }\)\.{0pt\ minus\ 1fil'."})\6 +(\.{"Such\ glue\ doesn't\ b}\)\.{elong\ there---it\ all}\)\.{ows\ a\ paragraph"})\6 +(\.{"of\ any\ length\ to\ fi}\)\.{t\ on\ one\ line.\ But\ i}\)\.{t's\ safe\ to\ proceed,}\)\.{"})\6 +(\.{"since\ the\ offensive}\)\.{\ shrinkability\ has\ b}\)\.{een\ made\ finite."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +${}\|q\K\\{new\_spec}(\|p);{}$\5 +${}\\{shrink\_order}(\|q)\K\\{normal};{}$\5 +\\{delete\_glue\_ref}(\|p);\5 +\&{return} \|q;\6 +\4${}\}{}$\2\par +\As829, 877, 895\ETs942. +\U815.\fi + +\M{827}\B\X816:Get ready to start line breaking\X${}\mathrel+\E{}$\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}[\T{1}]\K\\{width}(\|q)+\\{width}(\|r){}$;\6 +${}\\{background}[\T{2}]\K\T{0};{}$\5 +${}\\{background}[\T{3}]\K\T{0};{}$\5 +${}\\{background}[\T{4}]\K\T{0};{}$\5 +${}\\{background}[\T{5}]\K\T{0}{}$;\6 +${}\\{background}[\T{2}+\\{stretch\_order}(\|q)]\K\\{stretch}(\|q){}$;\6 +${}\\{background}[\T{2}+\\{stretch\_order}(\|r)]\K\30\\{background}[\T{2}+\\{stretch\_order}(\|r)]+\\{stretch}(\|r){}$;\6 +${}\\{background}[\T{6}]\K\\{shrink}(\|q)+\\{shrink}(\|r){}$;\par +\fi + +\M{828}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}\E\\{pretolerance}$ and $\\{second\_pass}\E\\{final\_pass}\E\\{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}\E\\{true}$. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{cur\_p};\C{the current breakpoint under consideration}\6 +\&{bool} \\{second\_pass};\C{is this our second attempt to break this paragraph?}\6 +\&{bool} \\{final\_pass};\C{is this our final attempt to break this paragraph?}\6 +\&{int} \\{threshold};\C{maximum badness on feasible lines}\par +\fi + +\M{829}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}\E\\{eject\_penalty}$ if the break is forced, +and $\\{pi}\E\\{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}\E\\{null}$. + +\Y\B\4\D$\\{copy\_to\_cur\_active}(\|X)$ \5 +$\\{cur\_active\_width}[\|X]\K\\{active\_width}{}$[\|X]\par +\Y\B\4\X826:Declare subprocedures for \\{line\_break}\X${}\mathrel+\E{}$\6 +\&{void} \\{try\_break}(\&{int} \\{pi}${},\39{}$\&{small\_number} \\{break\_type})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|r;\C{runs through the active list}\6 +\&{pointer} \\{prev\_r};\C{stays a step behind \|r}\6 +\&{halfword} \\{old\_l};\C{maximum line number in current equivalence class of lines}\6 +\&{bool} \\{no\_break\_yet};\C{have we found a feasible break at \\{cur\_p}?}\7 +\X830:Other local variables for \\{try\_break}\X\6 +\X831:Make sure that \\{pi} is in the proper range\X;\6 +${}\\{no\_break\_yet}\K\\{true};{}$\5 +${}\\{prev\_r}\K\\{active};{}$\5 +${}\\{old\_l}\K\T{0};{}$\5 +\\{do\_all\_six}(\\{copy\_to\_cur\_active});\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{resume}:\5 +${}\|r\K\\{link}(\\{prev\_r});{}$\5 +\X832:If node \|r is of type \\{delta\_node}, update \\{cur\_active\_width}, set \\{prev\_r} and \\{prev\_prev\_r}, then \&{goto} \&{continue}\X;\6 +\X835:If a line number class has ended, create new active nodes for the best feasible breaks in that class; then \&{return} if $\|r\K\\{last\_active}$, otherwise compute the new \\{line\_width}\X;\6 +\X851: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 +\4${}\}{}$\2\6 +\4\\{end}:\5 +;\6 +\8\#\&{ifdef} \.{STAT}\6 +\X858:Update the value of \\{printed\_node} for symbolic displays\X;\6 +\8\#\&{endif}\6 +\4${}\}{}$\2\par +\fi + +\M{830}\B\X830:Other local variables for \\{try\_break}\X${}\E{}$\6 +\&{pointer} \\{prev\_prev\_r};\C{a step behind \\{prev\_r}, if $\\{type}(\\{prev\_r})\E\\{delta\_node}$}\6 +\&{pointer} \|s;\C{runs through nodes ahead of \\{cur\_p}}\6 +\&{pointer} \|q;\C{points to a new node being created}\6 +\&{pointer} \|v;\C{points to a glue specification or a node ahead of \\{cur\_p}}\6 +\&{int} \|t;\C{node count, if \\{cur\_p} is a discretionary node}\6 +\&{internal\_font\_number} \|f;\C{used in character width calculation}\6 +\&{halfword} \|l;\C{line number of current active node}\6 +\&{bool} \\{node\_r\_stays\_active};\C{should node \|r remain in the active list?}\6 +\&{scaled} \\{line\_width};\C{the current line will be justified to this width}\6 +\&{uint8\_t} \\{fit\_class};\C{possible fitness class of test line}\6 +\&{halfword} \|b;\C{badness of test line}\6 +\&{int} \|d;\C{demerits of test line}\6 +\&{bool} \\{artificial\_demerits};\C{has \|d been forced to zero?}\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{pointer} \\{save\_link};\C{temporarily holds value of \\{link}(\\{cur\_p})}\6 +\8\#\&{endif}\6 +\&{scaled} \\{shortfall};\C{used in badness calculations}\par +\U829.\fi + +\M{831}\B\X831:Make sure that \\{pi} is in the proper range\X${}\E{}$\6 +\&{if} ${}(\\{abs}(\\{pi})\G\\{inf\_penalty})$ \6 +\&{if} ${}(\\{pi}>\T{0}){}$\1\5 +\&{goto} \\{end};\C{this breakpoint is inhibited by infinite penalty}\2\6 +\&{else} $\\{pi}\K{}$\\{eject\_penalty}\C{this breakpoint will be forced}\par +\U829.\fi + +\M{832}The following code uses the fact that $\\{type}(\\{last\_active})\I\\{delta\_node}$. + +\Y\B\4\D$\\{update\_width}(\|X)$ \5 +$\\{cur\_active\_width}[\|X]\K\\{cur\_active\_width}[\|X]+\\{mem}[\|r+\|X].{}$\\{sc}\par +\Y\B\4\X832:If node \|r is of type \\{delta\_node}, update \\{cur\_active\_width}, set \\{prev\_r} and \\{prev\_prev\_r}, then \&{goto} \&{continue}\X${}\E{}$\6 +\&{if} ${}(\\{type}(\|r)\E\\{delta\_node}){}$\5 +${}\{{}$\5 +\1\\{do\_all\_six}(\\{update\_width});\5 +${}\\{prev\_prev\_r}\K\\{prev\_r};{}$\5 +${}\\{prev\_r}\K\|r;{}$\5 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\par +\U829.\fi + +\M{833}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\B\4\D$\\{awful\_bad}$ \5 +\T{\~7777777777}\C{more than a billion demerits}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} ${}\\{minimal\_demerits0}[\\{tight\_fit}-\\{very\_loose\_fit}+\T{1}],{}$ ${}{*\&{const}\ }\\{minimal\_demerits}\K\\{minimal\_demerits0}-\\{very\_loose\_fit}{}$;\C{best total demerits known for current line class and position, given the fitness}% +\6 +\&{int} \\{minimum\_demerits};\C{best total demerits known for current line class and position}\6 +\&{pointer} ${}\\{best\_place0}[\\{tight\_fit}-\\{very\_loose\_fit}+\T{1}],{}$ ${}{*\&{const}\ }\\{best\_place}\K\\{best\_place0}-\\{very\_loose\_fit}{}$;\C{how to achieve \\{minimal\_demerits}}\6 +\&{halfword} ${}\\{best\_pl\_line0}[\\{tight\_fit}-\\{very\_loose\_fit}+\T{1}],{}$ ${}{*\&{const}\ }\\{best\_pl\_line}\K\\{best\_pl\_line0}-\\{very\_loose\_fit}{}$;\C{corresponding line number}\par +\fi + +\M{834}\B\X816:Get ready to start line breaking\X${}\mathrel+\E{}$\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 + +\M{835}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\E\\{last\_active}$ and +$\\{line\_number}(\\{last\_active})>\\{old\_l}$. + +\Y\B\4\X835:If a line number class has ended, create new active nodes for the best feasible breaks in that class; then \&{return} if $\|r\K\\{last\_active}$, otherwise compute the new \\{line\_width}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|l\K\\{line\_number}(\|r);{}$\6 +\&{if} ${}(\|l>\\{old\_l}){}$\5 +${}\{{}$\5 +\C{now we are no longer in the inner loop}\1\6 +\&{if} ${}((\\{minimum\_demerits}<\\{awful\_bad})\W\30((\\{old\_l}\I\\{easy\_line})\V(\|r\E\\{last\_active}))){}$\1\5 +\X836:Create new active nodes for the best feasible breaks just found\X;\2\6 +\&{if} ${}(\|r\E\\{last\_active}){}$\1\5 +\&{goto} \\{end};\2\6 +\X850:Compute the new line width\X;\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U829.\fi + +\M{836}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\B\4\X836:Create new active nodes for the best feasible breaks just found\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} (\\{no\_break\_yet})\1\5 +\X837:Compute the values of \\{break\_width}\X;\2\6 +\X843:Insert a delta node to prepare for breaks at \\{cur\_p}\X;\6 +\&{if} ${}(\\{abs}(\\{adj\_demerits})\G\\{awful\_bad}-\\{minimum\_demerits}){}$\1\5 +${}\\{minimum\_demerits}\K\\{awful\_bad}-\T{1};{}$\2\6 +\&{else}\1\5 +${}\\{minimum\_demerits}\K\\{minimum\_demerits}+\\{abs}(\\{adj\_demerits});{}$\2\6 +\&{for} ${}(\\{fit\_class}\K\\{very\_loose\_fit};{}$ ${}\\{fit\_class}\Z\\{tight\_fit};{}$ ${}\\{fit\_class}\PP){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{minimal\_demerits}[\\{fit\_class}]\Z\\{minimum\_demerits}){}$\1\5 +\X845:Insert a new active node from \\{best\_place}[\\{fit\_class}] to \\{cur\_p}\X;\2\6 +${}\\{minimal\_demerits}[\\{fit\_class}]\K\\{awful\_bad};{}$\6 +\4${}\}{}$\2\6 +${}\\{minimum\_demerits}\K\\{awful\_bad};{}$\5 +\X844:Insert a delta node to prepare for the next active node\X;\6 +\4${}\}{}$\2\par +\U835.\fi + +\M{837}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\B\4\D$\\{set\_break\_width\_to\_background}(\|X)$ \5 +$\\{break\_width}[\|X]\K\\{background}{}$[\|X]\par +\Y\B\4\X837:Compute the values of \\{break\_width}\X${}\E{}$\6 +$\{{}$\5 +$\\{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\6 +\&{if} ${}(\\{cur\_p}\I\\{null}){}$\1\5 +\X840:Compute the discretionary \\{break\_width} values\X;\2\2\6 +\&{while} ${}(\|s\I\\{null})$ $\{{}$\5 +\&{if} (\\{is\_char\_node}(\|s))\1\5 +\&{goto} \\{done};\2\6 +\&{switch} (\\{type}(\|s)) $\{$ \6 +\4\&{case} \\{glue\_node}:\5 +\X838:Subtract glue from \\{break\_width}\X\5 +\&{break};\6 +\4\&{case} \\{penalty\_node}:\5 +\\{do\_nothing};\5 +\&{break};\6 +\4\&{case} \\{math\_node}:\5 +${}\\{break\_width}[\T{1}]\K\\{break\_width}[\T{1}]-\\{width}(\|s){}$;\5 +\&{break}; \&{case} \\{kern\_node}: \&{if} ( \\{subtype}(\|s) $\I$ \&{explicit} ) \&{goto} \\{done};\6 +\&{else}\1\5 +${}\\{break\_width}[\T{1}]\K\\{break\_width}[\T{1}]-\\{width}(\|s){}$;\5 +\2\&{break};\6 +\4\&{default}:\5 +\&{goto} \\{done}; $\}{}$\6 +$\|s\K\\{link}(\|s);$ $\}$ \6 +\4\\{done}:\5 +; $\}{}$\par +\U836.\fi + +\M{838}\B\X838:Subtract glue from \\{break\_width}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|v\K\\{glue\_ptr}(\|s);{}$\5 +${}\\{break\_width}[\T{1}]\K\\{break\_width}[\T{1}]-\\{width}(\|v);{}$\5 +${}\\{break\_width}[\T{2}+\\{stretch\_order}(\|v)]\K\\{break\_width}[\T{2}+\\{stretch\_order}(\|v)]-\\{stretch}(\|v);{}$\5 +${}\\{break\_width}[\T{6}]\K\\{break\_width}[\T{6}]-\\{shrink}(\|v);{}$\6 +\4${}\}{}$\2\par +\U837.\fi + +\M{839}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{scaled} \\{disc\_width};\C{the length of discretionary material preceding a break}\par +\fi + +\M{840}\B\X840:Compute the discretionary \\{break\_width} values\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|t\K\\{replace\_count}(\\{cur\_p});{}$\5 +${}\|v\K\\{cur\_p};{}$\5 +${}\|s\K\\{post\_break}(\\{cur\_p});{}$\6 +\&{while} ${}(\|t>\T{0}){}$\5 +${}\{{}$\5 +\1\\{decr}(\|t);\5 +${}\|v\K\\{link}(\|v);{}$\5 +\X841:Subtract the width of node \|v from \\{break\_width}\X;\6 +\4${}\}{}$\2\6 +\&{while} ${}(\|s\I\\{null}){}$\5 +${}\{{}$\5 +\1\X842:Add the width of node \|s to \\{break\_width}\X;\6 +${}\|s\K\\{link}(\|s);{}$\6 +\4${}\}{}$\2\6 +${}\\{break\_width}[\T{1}]\K\\{break\_width}[\T{1}]+\\{disc\_width};{}$\6 +\&{if} ${}(\\{post\_break}(\\{cur\_p})\E\\{null}){}$\1\5 +${}\|s\K\\{link}(\|v){}$;\C{nodes may be discardable after the break}\2\6 +\4${}\}{}$\2\par +\U837.\fi + +\M{841}Replacement texts and discretionary texts are supposed to contain +only character nodes, kern nodes, ligature nodes, and box or rule nodes. + +\Y\B\4\X841:Subtract the width of node \|v from \\{break\_width}\X${}\E{}$\6 +\&{if} (\\{is\_char\_node}(\|v))\5 +${}\{{}$\5 +\1${}\|f\K\\{font}(\|v);{}$\5 +${}\\{break\_width}[\T{1}]\K\\{break\_width}[\T{1}]-\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\|v)));{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\6 +\&{switch} (\\{type}(\|v))\5 +${}\{{}$\1\6 +\4\&{case} \\{ligature\_node}:\6 +${}\{{}$\5 +\1${}\|f\K\\{font}(\\{lig\_char}(\|v)){}$;\6 +${}\\{break\_width}[\T{1}]\K\30\\{break\_width}[\T{1}]-\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\\{lig\_char}(\|v))));{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\5 +\&{case} \\{kern\_node}:\5 +${}\\{break\_width}[\T{1}]\K\\{break\_width}[\T{1}]-\\{width}(\|v){}$;\5 +\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1677:\.{"disc1"}\X);\6 +\4${}\}{}$\2\2\par +\U840.\fi + +\M{842}\B\X842:Add the width of node \|s to \\{break\_width}\X${}\E{}$\6 +\&{if} (\\{is\_char\_node}(\|s))\5 +${}\{{}$\5 +\1${}\|f\K\\{font}(\|s);{}$\5 +${}\\{break\_width}[\T{1}]\K\30\\{break\_width}[\T{1}]+\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\|s)));{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\6 +\&{switch} (\\{type}(\|s))\5 +${}\{{}$\1\6 +\4\&{case} \\{ligature\_node}:\6 +${}\{{}$\5 +\1${}\|f\K\\{font}(\\{lig\_char}(\|s));{}$\5 +${}\\{break\_width}[\T{1}]\K\\{break\_width}[\T{1}]+\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\\{lig\_char}(\|s))));{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\5 +\&{case} \\{kern\_node}:\5 +${}\\{break\_width}[\T{1}]\K\\{break\_width}[\T{1}]+\\{width}(\|s){}$;\5 +\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1678:\.{"disc2"}\X);\6 +\4${}\}{}$\2\2\par +\U840.\fi + +\M{843}We use the fact that $\\{type}(\\{active})\I\\{delta\_node}$. + +\Y\B\4\D$\\{convert\_to\_break\_width}(\|X)$ \5 +$\\{mem}[\\{prev\_r}+\|X].\\{sc}\K\30\hbox{\hskip10pt}\\{mem}[\\{prev\_r}+\|X].\\{sc}-\\{cur\_active\_width}[\|X]+\\{break\_width}{}$[\|X]\par +\B\4\D$\\{store\_break\_width}(\|X)$ \5 +$\\{active\_width}[\|X]\K\\{break\_width}{}$[\|X]\par +\B\4\D$\\{new\_delta\_to\_break\_width}(\|X)$ \5 +$\\{mem}[\|q+\|X].\\{sc}\K\\{break\_width}[\|X]-\\{cur\_active\_width}{}$[\|X]\par +\Y\B\4\X843:Insert a delta node to prepare for breaks at \\{cur\_p}\X${}\E{}$\6 +\&{if} ${}(\\{type}(\\{prev\_r})\E\\{delta\_node}{}$)\C{modify an existing delta node}\6 +${}\{{}$\5 +\1\\{do\_all\_six}(\\{convert\_to\_break\_width});\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{prev\_r}\E\\{active}{}$)\C{no delta node needed at the beginning}\6 +${}\{{}$\5 +\1\\{do\_all\_six}(\\{store\_break\_width});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{get\_node}(\\{delta\_node\_size});{}$\5 +${}\\{link}(\|q)\K\|r;{}$\5 +${}\\{type}(\|q)\K\\{delta\_node}{}$;\6 +${}\\{subtype}(\|q)\K\T{0}{}$;\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 +\4${}\}{}$\2\par +\U836.\fi + +\M{844}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\B\4\D$\\{new\_delta\_from\_break\_width}(\|X)$ \5 +$\\{mem}[\|q+\|X].\\{sc}\K\\{cur\_active\_width}[\|X]-\\{break\_width}{}$[\|X]\par +\Y\B\4\X844:Insert a delta node to prepare for the next active node\X${}\E{}$\6 +\&{if} ${}(\|r\I\\{last\_active}){}$\5 +${}\{{}$\5 +\1${}\|q\K\\{get\_node}(\\{delta\_node\_size});{}$\5 +${}\\{link}(\|q)\K\|r;{}$\5 +${}\\{type}(\|q)\K\\{delta\_node}{}$;\6 +${}\\{subtype}(\|q)\K\T{0}{}$;\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 +\4${}\}{}$\2\par +\U836.\fi + +\M{845}When we create an active node, we also create the corresponding +passive node. + +\Y\B\4\X845:Insert a new active node from \\{best\_place}[\\{fit\_class}] to \\{cur\_p}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|q\K\\{get\_node}(\\{passive\_node\_size});{}$\5 +${}\\{link}(\|q)\K\\{passive};{}$\5 +${}\\{passive}\K\|q;{}$\5 +${}\\{cur\_break}(\|q)\K\\{cur\_p};{}$\6 +\8\#\&{ifdef} \.{STAT}\6 +\\{incr}(\\{pass\_number});\5 +${}\\{serial}(\|q)\K\\{pass\_number};{}$\6 +\8\#\&{endif}\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}]+\T{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 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_paragraphs}>\T{0}){}$\1\5 +\X846:Print a symbolic description of the new break node\X;\2\6 +\8\#\&{endif}\6 +\4${}\}{}$\2\par +\U836.\fi + +\M{846}\B\X846:Print a symbolic description of the new break node\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_nl}(\.{"@@"});\5 +\\{print\_int}(\\{serial}(\\{passive}));\5 +\\{print\_str}(\.{":\ line\ "});\5 +${}\\{print\_int}(\\{line\_number}(\|q)-\T{1});{}$\5 +\\{print\_char}(\.{'.'});\5 +\\{print\_int}(\\{fit\_class});\6 +\&{if} ${}(\\{break\_type}\E\\{hyphenated}){}$\1\5 +\\{print\_char}(\.{'-'});\2\6 +\\{print\_str}(\.{"\ t="});\5 +\\{print\_int}(\\{total\_demerits}(\|q));\5 +\\{print\_str}(\.{"\ ->\ @@"});\6 +\&{if} ${}(\\{prev\_break}(\\{passive})\E\\{null}){}$\1\5 +\\{print\_char}(\.{'0'});\2\6 +\&{else}\1\5 +\\{print\_int}(\\{serial}(\\{prev\_break}(\\{passive})));\2\6 +\4${}\}{}$\2\par +\U845.\fi + +\M{847}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}\E\\{null}$, the shape of the paragraph depends on the value of +$\|n\E\\{hang\_after}$; if $\|n\G\T{0}$, hanging indentation takes place on lines $\|n+\T{1}$, +$\|n+\T{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}\G\T{0}$, else it is 0; the line length is +$\\{hsize}-\vert\\{hang\_indent}\vert$. The normal setting is +$\\{par\_shape\_ptr}\E\\{null}$, $\\{hang\_after}\E\T{1}$, and $\\{hang\_indent}\E\T{0}$. +Note that if $\\{hang\_indent}\E\T{0}$, the value of \\{hang\_after} is irrelevant. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{halfword} \\{easy\_line};\C{line numbers $>$ \\{easy\_line} are equivalent in break nodes}\6 +\&{halfword} \\{last\_special\_line};\C{line numbers $>$ \\{last\_special\_line} all have the same width}\6 +\&{scaled} \\{first\_width};\C{the width of all lines $\Z$ \\{last\_special\_line}, if no \.{\\parshape} has been specified}\6 +\&{scaled} \\{second\_width};\C{the width of all lines $>$ \\{last\_special\_line}}\6 +\&{scaled} \\{first\_indent};\C{left margin to go with \\{first\_width}}\6 +\&{scaled} \\{second\_indent};\C{left margin to go with \\{second\_width}}\par +\fi + +\M{848}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\B\4\X816:Get ready to start line breaking\X${}\mathrel+\E{}$\6 +\&{if} ${}(\\{par\_shape\_ptr}\E\\{null}){}$\1\6 +\&{if} ${}(\\{hang\_indent}\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{last\_special\_line}\K\T{0};{}$\5 +${}\\{second\_width}\K\\{hsize};{}$\5 +${}\\{second\_indent}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\X849:Set line length parameters in preparation for hanging indentation\X\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{last\_special\_line}\K\\{info}(\\{par\_shape\_ptr})-\T{1};{}$\5 +${}\\{second\_width}\K\\{mem}[\\{par\_shape\_ptr}+\T{2}*(\\{last\_special\_line}+\T{1})].\\{sc};{}$\5 +${}\\{second\_indent}\K\\{mem}[\\{par\_shape\_ptr}+\T{2}*\\{last\_special\_line}+\T{1}].\\{sc};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{looseness}\E\T{0}){}$\1\5 +${}\\{easy\_line}\K\\{last\_special\_line};{}$\2\6 +\&{else} $\\{easy\_line}\K{}$\\{max\_halfword}\par +\fi + +\M{849}\B\X849:Set line length parameters in preparation for hanging indentation\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{last\_special\_line}\K\\{abs}(\\{hang\_after});{}$\6 +\&{if} ${}(\\{hang\_after}<\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{first\_width}\K\\{hsize}-\\{abs}(\\{hang\_indent});{}$\6 +\&{if} ${}(\\{hang\_indent}\G\T{0}){}$\1\5 +${}\\{first\_indent}\K\\{hang\_indent};{}$\2\6 +\&{else}\1\5 +${}\\{first\_indent}\K\T{0};{}$\2\6 +${}\\{second\_width}\K\\{hsize};{}$\5 +${}\\{second\_indent}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{first\_width}\K\\{hsize};{}$\5 +${}\\{first\_indent}\K\T{0};{}$\5 +${}\\{second\_width}\K\\{hsize}-\\{abs}(\\{hang\_indent});{}$\6 +\&{if} ${}(\\{hang\_indent}\G\T{0}){}$\1\5 +${}\\{second\_indent}\K\\{hang\_indent};{}$\2\6 +\&{else}\1\5 +${}\\{second\_indent}\K\T{0};{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U848.\fi + +\M{850}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\B\4\X850:Compute the new line width\X${}\E{}$\6 +\&{if} ${}(\|l>\\{easy\_line}){}$\5 +${}\{{}$\5 +\1${}\\{line\_width}\K\\{second\_width};{}$\5 +${}\\{old\_l}\K\\{max\_halfword}-\T{1};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{old\_l}\K\|l;{}$\6 +\&{if} ${}(\|l>\\{last\_special\_line}){}$\1\5 +${}\\{line\_width}\K\\{second\_width};{}$\2\6 +\&{else} \&{if} ${}(\\{par\_shape\_ptr}\E\\{null}){}$\1\5 +${}\\{line\_width}\K\\{first\_width};{}$\2\6 +\&{else}\1\5 +${}\\{line\_width}\K\\{mem}[\\{par\_shape\_ptr}+\T{2}*\|l\,].\\{sc};{}$\2\6 +\4${}\}{}$\2\par +\U835.\fi + +\M{851}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}+\T{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\B\4\X851: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${}\E{}$\6 +${}\{{}$\5 +\1${}\\{artificial\_demerits}\K\\{false}{}$;\6 +${}\\{shortfall}\K\\{line\_width}-\\{cur\_active\_width}[\T{1}]{}$;\C{we're this much too short}\6 +\&{if} ${}(\\{shortfall}>\T{0}){}$\1\5 +\X852:Set the value of \|b to the badness for stretching the line, and compute the corresponding \\{fit\_class}\X\2\6 +\&{else}\1\5 +\X853: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}\E\\{eject\_penalty})){}$\1\5 +\X854:Prepare to deactivate node~\|r, and \&{goto} \\{deactivate} unless there is a reason to consider lines of text from \|r to \\{cur\_p}\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{prev\_r}\K\|r;{}$\6 +\&{if} ${}(\|b>\\{threshold}){}$\1\5 +\&{goto} \\{resume};\2\6 +${}\\{node\_r\_stays\_active}\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\X855:Record a new feasible break\X;\6 +\&{if} (\\{node\_r\_stays\_active})\1\5 +\&{goto} \\{resume};\C{\\{prev\_r} has been set to \|r}\2\6 +\4\\{deactivate}:\5 +\X860:Deactivate node \|r\X;\6 +\4${}\}{}$\2\par +\U829.\fi + +\M{852}When a line must stretch, the available stretchability can be found in the +subarray $\\{cur\_active\_width}[\T{2}\dotdot\T{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. + +\Y\B\4\X852:Set the value of \|b to the badness for stretching the line, and compute the corresponding \\{fit\_class}\X${}\E{}$\6 +\&{if} ${}((\\{cur\_active\_width}[\T{3}]\I\T{0})\V(\\{cur\_active\_width}[\T{4}]\I\T{0})\V\30(\\{cur\_active\_width}[\T{5}]\I\T{0})){}$\5 +${}\{{}$\5 +\1${}\|b\K\T{0};{}$\5 +${}\\{fit\_class}\K\\{decent\_fit}{}$;\C{infinite stretch}\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{shortfall}>\T{7230584}){}$\1\6 +\&{if} ${}(\\{cur\_active\_width}[\T{2}]<\T{1663497}){}$\5 +${}\{{}$\5 +\1${}\|b\K\\{inf\_bad};{}$\5 +${}\\{fit\_class}\K\\{very\_loose\_fit};{}$\5 +\&{goto} \\{done1};\6 +\4${}\}{}$\2\2\6 +${}\|b\K\\{badness}(\\{shortfall},\39\\{cur\_active\_width}[\T{2}]);{}$\6 +\&{if} ${}(\|b>\T{12}){}$\1\6 +\&{if} ${}(\|b>\T{99}){}$\1\5 +${}\\{fit\_class}\K\\{very\_loose\_fit};{}$\2\6 +\&{else}\1\5 +${}\\{fit\_class}\K\\{loose\_fit};{}$\2\2\6 +\&{else}\1\5 +${}\\{fit\_class}\K\\{decent\_fit};{}$\2\6 +\4\\{done1}:\5 +;\6 +\4${}\}{}$\2\par +\U851.\fi + +\M{853}Shrinkability is never infinite in a paragraph; +we can shrink the line from \|r to \\{cur\_p} by at most \\{cur\_active\_width}[\T{6}]. + +\Y\B\4\X853:Set the value of \|b to the badness for shrinking the line, and compute the corresponding \\{fit\_class}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}({-}\\{shortfall}>\\{cur\_active\_width}[\T{6}]){}$\1\5 +${}\|b\K\\{inf\_bad}+\T{1};{}$\2\6 +\&{else}\1\5 +${}\|b\K\\{badness}({-}\\{shortfall},\39\\{cur\_active\_width}[\T{6}]);{}$\2\6 +\&{if} ${}(\|b>\T{12}){}$\1\5 +${}\\{fit\_class}\K\\{tight\_fit}{}$;\5 +\2\&{else}\1\5 +${}\\{fit\_class}\K\\{decent\_fit};{}$\2\6 +\4${}\}{}$\2\par +\U851.\fi + +\M{854}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\B\4\X854:Prepare to deactivate node~\|r, and \&{goto} \\{deactivate} unless there is a reason to consider lines of text from \|r to \\{cur\_p}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{final\_pass}\W(\\{minimum\_demerits}\E\\{awful\_bad})\W\30(\\{link}(\|r)\E\\{last\_active})\W(\\{prev\_r}\E\\{active})){}$\1\5 +${}\\{artificial\_demerits}\K\\{true}{}$;\C{set demerits zero, this break is forced}\2\6 +\&{else} \&{if} ${}(\|b>\\{threshold}){}$\1\5 +\&{goto} \\{deactivate};\2\6 +${}\\{node\_r\_stays\_active}\K\\{false};{}$\6 +\4${}\}{}$\2\par +\U851.\fi + +\M{855}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\B\4\X855:Record a new feasible break\X${}\E{}$\6 +\&{if} (\\{artificial\_demerits})\1\5 +${}\|d\K\T{0};{}$\2\6 +\&{else}\1\5 +\X859:Compute the demerits, \|d, from \|r to \\{cur\_p}\X;\2\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_paragraphs}>\T{0}){}$\1\5 +\X856:Print a symbolic description of this feasible break\X;\2\6 +\8\#\&{endif}\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\Z\\{minimal\_demerits}[\\{fit\_class}]){}$\5 +${}\{{}$\5 +\1${}\\{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\5 +${}\\{minimum\_demerits}\K\|d;{}$\2\6 +\4${}\}{}$\2\par +\U851.\fi + +\M{856}\B\X856:Print a symbolic description of this feasible break\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{printed\_node}\I\\{cur\_p}){}$\1\5 +\X857: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}\E\\{null}){}$\1\5 +\\{print\_esc}(\X1569:\.{"par"}\X);\2\6 +\&{else} \&{if} ${}(\\{type}(\\{cur\_p})\I\\{glue\_node}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{type}(\\{cur\_p})\E\\{penalty\_node}){}$\1\5 +\\{print\_esc}(\X1553:\.{"penalty"}\X);\2\6 +\&{else} \&{if} ${}(\\{type}(\\{cur\_p})\E\\{disc\_node}){}$\1\5 +\\{print\_esc}(\X1400:\.{"discretionary"}\X);\2\6 +\&{else} \&{if} ${}(\\{type}(\\{cur\_p})\E\\{kern\_node}){}$\1\5 +\\{print\_esc}(\X1396:\.{"kern"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1398:\.{"math"}\X);\2\6 +\4${}\}{}$\2\6 +\\{print\_str}(\.{"\ via\ @@"});\6 +\&{if} ${}(\\{break\_node}(\|r)\E\\{null}){}$\1\5 +\\{print\_char}(\.{'0'});\2\6 +\&{else}\1\5 +\\{print\_int}(\\{serial}(\\{break\_node}(\|r)));\2\6 +\\{print\_str}(\.{"\ b="});\6 +\&{if} ${}(\|b>\\{inf\_bad}){}$\1\5 +\\{print\_char}(\.{'*'});\5 +\2\&{else}\1\5 +\\{print\_int}(\|b);\2\6 +\\{print\_str}(\.{"\ p="});\5 +\\{print\_int}(\\{pi});\5 +\\{print\_str}(\.{"\ d="});\6 +\&{if} (\\{artificial\_demerits})\1\5 +\\{print\_char}(\.{'*'});\5 +\2\&{else}\1\5 +\\{print\_int}(\|d);\2\6 +\4${}\}{}$\2\par +\U855.\fi + +\M{857}\B\X857:Print the list between \\{printed\_node} and \\{cur\_p}, then set \\{printed\_node}: $\K$ \\{cur\_p}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_nl}(\.{""});\6 +\&{if} ${}(\\{cur\_p}\E\\{null}){}$\1\5 +\\{short\_display}(\\{link}(\\{printed\_node}));\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\6 +${}\\{printed\_node}\K\\{cur\_p};{}$\6 +\4${}\}{}$\2\par +\U856.\fi + +\M{858}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\B\4\X858:Update the value of \\{printed\_node} for symbolic displays\X${}\E{}$\6 +\&{if} ${}(\\{cur\_p}\E\\{printed\_node}){}$\1\6 +\&{if} ${}(\\{cur\_p}\I\\{null}){}$\1\6 +\&{if} ${}(\\{type}(\\{cur\_p})\E\\{disc\_node}){}$\5 +${}\{{}$\5 +\1${}\|t\K\\{replace\_count}(\\{cur\_p});{}$\6 +\&{while} ${}(\|t>\T{0}){}$\5 +${}\{{}$\5 +\1\\{decr}(\|t);\5 +${}\\{printed\_node}\K\\{link}(\\{printed\_node});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\2\2\par +\U829.\fi + +\M{859}\B\X859:Compute the demerits, \|d, from \|r to \\{cur\_p}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|d\K\\{line\_penalty}+\|b;{}$\6 +\&{if} ${}(\\{abs}(\|d)\G\T{10000}){}$\1\5 +${}\|d\K\T{100000000}{}$;\5 +\2\&{else}\1\5 +${}\|d\K\|d*\|d;{}$\2\6 +\&{if} ${}(\\{pi}\I\T{0}){}$\1\6 +\&{if} ${}(\\{pi}>\T{0}){}$\1\5 +${}\|d\K\|d+\\{pi}*\\{pi};{}$\2\6 +\&{else} \&{if} ${}(\\{pi}>\\{eject\_penalty}){}$\1\5 +${}\|d\K\|d-\\{pi}*\\{pi};{}$\2\2\6 +\&{if} ${}((\\{break\_type}\E\\{hyphenated})\W(\\{type}(\|r)\E\\{hyphenated})){}$\1\6 +\&{if} ${}(\\{cur\_p}\I\\{null}){}$\1\5 +${}\|d\K\|d+\\{double\_hyphen\_demerits};{}$\2\6 +\&{else}\1\5 +${}\|d\K\|d+\\{final\_hyphen\_demerits};{}$\2\2\6 +\&{if} ${}(\\{abs}(\\{fit\_class}-\\{fitness}(\|r))>\T{1}){}$\1\5 +${}\|d\K\|d+\\{adj\_demerits};{}$\2\6 +\4${}\}{}$\2\par +\U855.\fi + +\M{860}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\B\4\D$\\{combine\_two\_deltas}(\|X)$ \5 +$\\{mem}[\\{prev\_r}+\|X].\\{sc}\K\\{mem}[\\{prev\_r}+\|X].\\{sc}+\\{mem}[\|r+\|X].{}$\\{sc}\par +\B\4\D$\\{downdate\_width}(\|X)$ \5 +$\\{cur\_active\_width}[\|X]\K\\{cur\_active\_width}[\|X]-\\{mem}[\\{prev\_r}+\|X].{}$\\{sc}\par +\Y\B\4\X860:Deactivate node \|r\X${}\E{}$\6 +$\\{link}(\\{prev\_r})\K\\{link}(\|r);{}$\5 +${}\\{free\_node}(\|r,\39\\{active\_node\_size});{}$\6 +\&{if} ${}(\\{prev\_r}\E\\{active}){}$\1\5 +\X861:Update the active widths, since the first active node has been deleted\X\2\6 +\&{else} \&{if} ${}(\\{type}(\\{prev\_r})\E\\{delta\_node}){}$\5 +${}\{{}$\5 +\1${}\|r\K\\{link}(\\{prev\_r});{}$\6 +\&{if} ${}(\|r\E\\{last\_active}){}$\5 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{type}(\|r)\E\\{delta\_node}){}$\5 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U851.\fi + +\M{861}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\B\4\D$\\{update\_active}(\|X)$ \5 +$\\{active\_width}[\|X]\K\\{active\_width}[\|X]+\\{mem}[\|r+\|X].{}$\\{sc}\par +\Y\B\4\X861:Update the active widths, since the first active node has been deleted\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|r\K\\{link}(\\{active});{}$\6 +\&{if} ${}(\\{type}(\|r)\E\\{delta\_node}){}$\5 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U860.\fi + +\N{1}{862}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})\E\\{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\B\4\X862:Local variables for line breaking\X${}\E{}$\6 +\&{bool} \\{auto\_breaking};\C{is node \\{cur\_p} outside a formula?}\6 +\&{pointer} \\{prev\_p};\C{helps to determine when glue nodes are breakpoints}\6 +\&{pointer} \|q${},{}$ \|r${},{}$ \|s${},{}$ \\{prev\_s};\C{miscellaneous nodes of temporary interest}\6 +\&{internal\_font\_number} \|f;\C{used when calculating character widths}\par +\A893. +\U815.\fi + +\M{863}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\B\4\X863:Find optimal breakpoints\X${}\E{}$\6 +$\\{threshold}\K\\{pretolerance};{}$\6 +\&{if} ${}(\\{threshold}\G\T{0}){}$\5 +${}\{{}$\6 +\8\#\&{ifdef} \.{STAT}\1\6 +\&{if} ${}(\\{tracing\_paragraphs}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{"@firstpass"});\5 +${}\}{}$\2\6 +\8\#\&{endif}\6 +${}\\{second\_pass}\K\\{false};{}$\5 +${}\\{final\_pass}\K\\{false};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{threshold}\K\\{tolerance};{}$\5 +${}\\{second\_pass}\K\\{true};{}$\5 +${}\\{final\_pass}\K(\\{emergency\_stretch}\Z\T{0});{}$\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_paragraphs}>\T{0}){}$\1\5 +\\{begin\_diagnostic}(\,);\2\6 +\8\#\&{endif}\6 +\4${}\}{}$\2\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{threshold}>\\{inf\_bad}){}$\1\5 +${}\\{threshold}\K\\{inf\_bad};{}$\2\6 +\&{if} (\\{second\_pass})\1\5 +\X891:Initialize for hyphenating a paragraph\X;\2\6 +\X864: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\5 +\X866: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}\E\\{null}){}$\1\5 +\X873:Try the final line break at the end of the paragraph, and \&{goto} \\{done} if the desired breakpoints have been found\X;\2\6 +\X865:Clean up the memory by removing the break nodes\X;\6 +\&{if} ${}(\R\\{second\_pass}){}$\5 +${}\{{}$\6 +\8\#\&{ifdef} \.{STAT}\1\6 +\&{if} ${}(\\{tracing\_paragraphs}>\T{0}){}$\1\5 +\\{print\_nl}(\.{"@secondpass"});\2\6 +\8\#\&{endif}\6 +${}\\{threshold}\K\\{tolerance};{}$\5 +${}\\{second\_pass}\K\\{true};{}$\5 +${}\\{final\_pass}\K(\\{emergency\_stretch}\Z\T{0});{}$\6 +\4${}\}{}$\C{if at first you don't succeed, \dots}\2\6 +\&{else}\5 +${}\{{}$\6 +\8\#\&{ifdef} \.{STAT}\1\6 +\&{if} ${}(\\{tracing\_paragraphs}>\T{0}){}$\1\5 +\\{print\_nl}(\.{"@emergencypass"});\2\6 +\8\#\&{endif}\6 +${}\\{background}[\T{2}]\K\\{background}[\T{2}]+\\{emergency\_stretch};{}$\5 +${}\\{final\_pass}\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4\\{done}:\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_paragraphs}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{end\_diagnostic}(\\{true});\5 +\\{normalize\_selector}(\,);\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\U815.\fi + +\M{864}The active node that represents the starting point does not need a +corresponding passive node. + +\Y\B\4\D$\\{store\_background}(\|X)$ \5 +$\\{active\_width}[\|X]\K\\{background}{}$[\|X]\par +\Y\B\4\X864:Create an active breakpoint representing the beginning of the paragraph\X${}\E{}$\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}+\T{1};{}$\5 +${}\\{total\_demerits}(\|q)\K\T{0};{}$\5 +${}\\{link}(\\{active})\K\|q;{}$\5 +\\{do\_all\_six}(\\{store\_background});\6 +${}\\{passive}\K\\{null};{}$\5 +${}\\{printed\_node}\K\\{temp\_head};{}$\5 +${}\\{pass\_number}\K\T{0};$ $\\{font\_in\_short\_display}\K{}$\\{null\_font}\par +\U863.\fi + +\M{865}\B\X865:Clean up the memory by removing the break nodes\X${}\E{}$\6 +$\|q\K\\{link}(\\{active});{}$\6 +\&{while} ${}(\|q\I\\{last\_active}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_p}\K\\{link}(\|q);{}$\6 +\&{if} ${}(\\{type}(\|q)\E\\{delta\_node}){}$\1\5 +${}\\{free\_node}(\|q,\39\\{delta\_node\_size});{}$\2\6 +\&{else}\1\5 +${}\\{free\_node}(\|q,\39\\{active\_node\_size});{}$\2\6 +${}\|q\K\\{cur\_p};{}$\6 +\4${}\}{}$\2\6 +${}\|q\K\\{passive};{}$\6 +\&{while} ${}(\|q\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_p}\K\\{link}(\|q);{}$\5 +${}\\{free\_node}(\|q,\39\\{passive\_node\_size});{}$\5 +${}\|q\K\\{cur\_p};{}$\6 +\4${}\}{}$\2\par +\Us815\ET863.\fi + +\M{866}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\B\4\D$\\{act\_width}$ \5 +\\{active\_width}[\T{1}]\C{length from first active node to current node}\par +\B\4\D$\\{kern\_break}$ \6 +${}\{{}$\5 +\1\&{if} ${}(\R\\{is\_char\_node}(\\{link}(\\{cur\_p}))\W\\{auto\_breaking}){}$\1\6 +\&{if} ${}(\\{type}(\\{link}(\\{cur\_p}))\E\\{glue\_node}){}$\1\5 +${}\\{try\_break}(\T{0},\39\\{unhyphenated});{}$\2\2\6 +${}\\{act\_width}\K\\{act\_width}+\\{width}(\\{cur\_p});{}$\6 +\4${}\}{}$\2\par +\Y\B\4\X866: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${}\E{}$\6 +$\{{}$\5 +\&{if} (\\{is\_char\_node}(\\{cur\_p}))\1\5 +\X867:Advance \(c)\\{cur\_p} to the node following the present string of characters\X;\2\6 +\&{switch} (\\{type}(\\{cur\_p})) $\{$ \6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\5 +${}\\{act\_width}\K\\{act\_width}+\\{width}(\\{cur\_p}){}$;\5 +\&{break};\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1362:Advance \(p)past a whatsit node in the \(l)\\{line\_break} loop\X\5 +\&{break};\6 +\4\&{case} \\{glue\_node}:\6 +${}\{{}$\5 +\1\X868: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\5 +\X894:Try to hyphenate the following word\X;\2\6 +\4${}\}{}$\5 +\2\&{break}; \&{case} \\{kern\_node}: \&{if} ( \\{subtype}(\\{cur\_p}) $\E$ \&{explicit} ) \\{kern\_break}\6 +\&{else}\1\5 +${}\\{act\_width}\K\\{act\_width}+\\{width}(\\{cur\_p}){}$;\5 +\2\&{break};\6 +\4\&{case} \\{ligature\_node}:\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{disc\_node}:\5 +\X869:Try to break after a discretionary fragment, then \&{goto} \\{done5}\X\6 +\4\&{case} \\{math\_node}:\6 +${}\{{}$\5 +\1${}\\{auto\_breaking}\K(\\{subtype}(\\{cur\_p})\E\\{after});{}$\5 +\\{kern\_break};\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{penalty\_node}:\5 +${}\\{try\_break}(\\{penalty}(\\{cur\_p}),\39\\{unhyphenated}){}$;\5 +\&{break};\6 +\4\&{case} \\{mark\_node}:\5 +\&{case} \\{ins\_node}:\5 +\&{case} \\{adjust\_node}:\5 +\\{do\_nothing};\5 +\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1679:\.{"paragraph"}\X); $\}{}$\6 +$\\{prev\_p}\K\\{cur\_p};{}$\5 +${}\\{cur\_p}\K\\{link}(\\{cur\_p});{}$\6 +\4\\{done5}:\5 +; $\}{}$\par +\U863.\fi + +\M{867}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})\E\\{null}$ when \\{cur\_p} is a +character node. + +\Y\B\4\X867:Advance \(c)\\{cur\_p} to the node following the present string of characters\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{prev\_p}\K\\{cur\_p}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|f\K\\{font}(\\{cur\_p});{}$\5 +${}\\{act\_width}\K\\{act\_width}+\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\\{cur\_p})));{}$\5 +${}\\{cur\_p}\K\\{link}(\\{cur\_p});{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\R\\{is\_char\_node}(\\{cur\_p})));{}$\6 +\4${}\}{}$\2\par +\U866.\fi + +\M{868}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\B\4\X868: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${}\E{}$\6 +\&{if} (\\{auto\_breaking}) $\{{}$\5 +\&{if} (\\{is\_char\_node}(\\{prev\_p}))\1\5 +${}\\{try\_break}(\T{0},\39\\{unhyphenated});{}$\2\6 +\&{else} \&{if} (\\{precedes\_break}(\\{prev\_p}))\1\5 +${}\\{try\_break}(\T{0},\39\\{unhyphenated});{}$\2\6 +\&{else} \&{if} ( $(\\{type}(\\{prev\_p})\E\\{kern\_node})$ $\W$ ( \\{subtype}(\\{prev\_p}) $\I$ \&{explicit} ) ) $\\{try\_break}(\T{0},\39\\{unhyphenated});$ $\}$ \\{check\_shrinkage}(\\{glue\_ptr}(\\{cur\_p}));\5 +${}\|q\K\\{glue\_ptr}(\\{cur\_p});{}$\5 +${}\\{act\_width}\K\\{act\_width}+\\{width}(\|q);\30{}$\5 +${}\\{active\_width}[\T{2}+\\{stretch\_order}(\|q)]\K\30\\{active\_width}[\T{2}+\\{stretch\_order}(\|q)]+\\{stretch}(\|q){}$;\6 +$\\{active\_width}[\T{6}]\K\\{active\_width}[\T{6}]+\\{shrink}{}$(\|q)\par +\U866.\fi + +\M{869}The following code knows that discretionary texts contain +only character nodes, kern nodes, box nodes, rule nodes, and ligature nodes. + +\Y\B\4\X869:Try to break after a discretionary fragment, then \&{goto} \\{done5}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|s\K\\{pre\_break}(\\{cur\_p});{}$\5 +${}\\{disc\_width}\K\T{0};{}$\6 +\&{if} ${}(\|s\E\\{null}){}$\1\5 +${}\\{try\_break}(\\{ex\_hyphen\_penalty},\39\\{hyphenated});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{do}\5 +${}\{{}$\1\6 +\X870:Add the width of node \|s to \\{disc\_width}\X;\6 +${}\|s\K\\{link}(\|s);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|s\E\\{null}));{}$\5 +${}\\{act\_width}\K\\{act\_width}+\\{disc\_width};{}$\5 +${}\\{try\_break}(\\{hyphen\_penalty},\39\\{hyphenated});{}$\5 +${}\\{act\_width}\K\\{act\_width}-\\{disc\_width};{}$\6 +\4${}\}{}$\2\6 +${}\|r\K\\{replace\_count}(\\{cur\_p});{}$\5 +${}\|s\K\\{link}(\\{cur\_p});{}$\6 +\&{while} ${}(\|r>\T{0}){}$\5 +${}\{{}$\5 +\1\X871:Add the width of node \|s to \\{act\_width}\X;\6 +\\{decr}(\|r);\5 +${}\|s\K\\{link}(\|s);{}$\6 +\4${}\}{}$\2\6 +${}\\{prev\_p}\K\\{cur\_p};{}$\5 +${}\\{cur\_p}\K\|s;{}$\5 +\&{goto} \\{done5};\6 +\4${}\}{}$\2\par +\U866.\fi + +\M{870}\B\X870:Add the width of node \|s to \\{disc\_width}\X${}\E{}$\6 +\&{if} (\\{is\_char\_node}(\|s))\5 +${}\{{}$\5 +\1${}\|f\K\\{font}(\|s);{}$\5 +${}\\{disc\_width}\K\\{disc\_width}+\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\|s)));{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\6 +\&{switch} (\\{type}(\|s))\5 +${}\{{}$\1\6 +\4\&{case} \\{ligature\_node}:\6 +${}\{{}$\5 +\1${}\|f\K\\{font}(\\{lig\_char}(\|s));{}$\5 +${}\\{disc\_width}\K\\{disc\_width}+\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\\{lig\_char}(\|s))));{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\5 +\&{case} \\{kern\_node}:\5 +${}\\{disc\_width}\K\\{disc\_width}+\\{width}(\|s){}$;\5 +\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1680:\.{"disc3"}\X);\6 +\4${}\}{}$\2\2\par +\U869.\fi + +\M{871}\B\X871:Add the width of node \|s to \\{act\_width}\X${}\E{}$\6 +\&{if} (\\{is\_char\_node}(\|s))\5 +${}\{{}$\5 +\1${}\|f\K\\{font}(\|s);{}$\5 +${}\\{act\_width}\K\\{act\_width}+\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\|s)));{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\6 +\&{switch} (\\{type}(\|s))\5 +${}\{{}$\1\6 +\4\&{case} \\{ligature\_node}:\6 +${}\{{}$\5 +\1${}\|f\K\\{font}(\\{lig\_char}(\|s));{}$\5 +${}\\{act\_width}\K\\{act\_width}+\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\\{lig\_char}(\|s))));{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\5 +\&{case} \\{kern\_node}:\5 +${}\\{act\_width}\K\\{act\_width}+\\{width}(\|s){}$;\5 +\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1681:\.{"disc4"}\X);\6 +\4${}\}{}$\2\2\par +\U869.\fi + +\M{872}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}\E\\{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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{best\_bet};\C{use this passive node and its predecessors}\6 +\&{int} \\{fewest\_demerits};\C{the demerits associated with \\{best\_bet}}\6 +\&{halfword} \\{best\_line};\C{line number following the last line of the new paragraph}\6 +\&{int} \\{actual\_looseness};\C{the difference between \\{line\_number}(\\{best\_bet}) and the optimum \\{best\_line}}\6 +\&{int} \\{line\_diff};\C{the difference between the current line number and the optimum \\{best\_line}}\par +\fi + +\M{873}\B\X873:Try the final line break at the end of the paragraph, and \&{goto} \\{done} if the desired breakpoints have been found\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{try\_break}(\\{eject\_penalty},\39\\{hyphenated});{}$\6 +\&{if} ${}(\\{link}(\\{active})\I\\{last\_active}){}$\5 +${}\{{}$\5 +\1\X874:Find an active node with fewest demerits\X;\6 +\&{if} ${}(\\{looseness}\E\T{0}){}$\1\5 +\&{goto} \\{done};\2\6 +\X875:Find the best active node for the desired looseness\X;\6 +\&{if} ${}((\\{actual\_looseness}\E\\{looseness})\V\\{final\_pass}){}$\1\5 +\&{goto} \\{done};\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U863.\fi + +\M{874}\B\X874:Find an active node with fewest demerits\X${}\E{}$\6 +$\|r\K\\{link}(\\{active});{}$\5 +${}\\{fewest\_demerits}\K\\{awful\_bad}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\&{if} ${}(\\{type}(\|r)\I\\{delta\_node}){}$\1\6 +\&{if} ${}(\\{total\_demerits}(\|r)<\\{fewest\_demerits}){}$\5 +${}\{{}$\5 +\1${}\\{fewest\_demerits}\K\\{total\_demerits}(\|r);{}$\5 +${}\\{best\_bet}\K\|r;{}$\6 +\4${}\}{}$\2\2\6 +${}\|r\K\\{link}(\|r);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|r\E\\{last\_active}));$ $\\{best\_line}\K\\{line\_number}{}$(\\{best\_bet})\par +\U873.\fi + +\M{875}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\B\4\X875:Find the best active node for the desired looseness\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|r\K\\{link}(\\{active});{}$\5 +${}\\{actual\_looseness}\K\T{0}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\&{if} ${}(\\{type}(\|r)\I\\{delta\_node}){}$\5 +${}\{{}$\5 +\1${}\\{line\_diff}\K\\{line\_number}(\|r)-\\{best\_line};{}$\6 +\&{if} ${}(((\\{line\_diff}<\\{actual\_looseness})\W(\\{looseness}\Z\\{line\_diff}))\V\30((\\{line\_diff}>\\{actual\_looseness})\W(\\{looseness}\G\\{line\_diff}))){}$\5 +${}\{{}$\5 +\1${}\\{best\_bet}\K\|r;{}$\5 +${}\\{actual\_looseness}\K\\{line\_diff};{}$\5 +${}\\{fewest\_demerits}\K\\{total\_demerits}(\|r);{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}((\\{line\_diff}\E\\{actual\_looseness})\W\30(\\{total\_demerits}(\|r)<\\{fewest\_demerits})){}$\5 +${}\{{}$\5 +\1${}\\{best\_bet}\K\|r;{}$\5 +${}\\{fewest\_demerits}\K\\{total\_demerits}(\|r);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +${}\|r\K\\{link}(\|r);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|r\E\\{last\_active}));{}$\5 +${}\\{best\_line}\K\\{line\_number}(\\{best\_bet});{}$\6 +\4${}\}{}$\2\par +\U873.\fi + +\M{876}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\B\4\X876:Break the paragraph at the chosen breakpoints, justify the resulting lines to the correct widths, and append them to the current vertical list\X${}\E{}$\6 +\\{post\_line\_break}(\\{final\_widow\_penalty})\par +\U815.\fi + +\M{877}The total number of lines that will be set by \\{post\_line\_break} +is $\\{best\_line}-\\{prev\_graf}-\T{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\B\4\D$\\{next\_break}$ \5 +\\{prev\_break}\C{new name for \\{prev\_break} after links are reversed}\par +\Y\B\4\X826:Declare subprocedures for \\{line\_break}\X${}\mathrel+\E{}$\6 +\&{void} \\{post\_line\_break}(\&{int} \\{final\_widow\_penalty})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|q${},{}$ \|r${},{}$ \|s;\C{temporary registers for list manipulation}\6 +\&{bool} \\{disc\_break};\C{was the current break at a discretionary node?}\6 +\&{bool} \\{post\_disc\_break};\C{and did it have a nonempty post-break part?}\6 +\&{scaled} \\{cur\_width};\C{width of line number \\{cur\_line}}\6 +\&{scaled} \\{cur\_indent};\C{left margin of line number \\{cur\_line}}\6 +\&{quarterword} \|t;\C{used for replacement counts in discretionary nodes}\6 +\&{int} \\{pen};\C{use when calculating penalties between lines}\6 +\&{halfword} \\{cur\_line};\C{the current line number being justified}\7 +\X878:Reverse the links of the relevant passive nodes, setting \\{cur\_p} to the first breakpoint\X;\6 +${}\\{cur\_line}\K\\{prev\_graf}+\T{1}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\X880: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\6 +\&{if} ${}(\R\\{post\_disc\_break}){}$\1\5 +\X879:Prune unwanted nodes at the beginning of the next line\X;\2\2\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{cur\_p}\E\\{null}));{}$\6 +\&{if} ${}((\\{cur\_line}\I\\{best\_line})\V(\\{link}(\\{temp\_head})\I\\{null})){}$\1\5 +\\{confusion}(\X1682:\.{"line\ breaking"}\X);\2\6 +${}\\{prev\_graf}\K\\{best\_line}-\T{1};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{878}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\B\4\X878:Reverse the links of the relevant passive nodes, setting \\{cur\_p} to the first breakpoint\X${}\E{}$\6 +$\|q\K\\{break\_node}(\\{best\_bet});{}$\5 +${}\\{cur\_p}\K\\{null}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|r\K\|q;{}$\5 +${}\|q\K\\{prev\_break}(\|q);{}$\5 +${}\\{next\_break}(\|r)\K\\{cur\_p};{}$\5 +${}\\{cur\_p}\K\|r;{}$\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R(\|q\E\\{null}){}$)\par +\U877.\fi + +\M{879}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\B\4\X879:Prune unwanted nodes at the beginning of the next line\X${}\E{}$\6 +$\{{}$\5 +$\|r\K\\{temp\_head};$ \&{loop}\5 +$\{{}$\5 +$\|q\K\\{link}(\|r);{}$\6 +\&{if} ${}(\|q\E\\{cur\_break}(\\{cur\_p})){}$\1\5 +\&{goto} \\{done1};\C{\\{cur\_break}(\\{cur\_p}) is the next breakpoint}\C{now \|q cannot be \\{null}}\2\6 +\&{if} (\\{is\_char\_node}(\|q))\1\5 +\&{goto} \\{done1};\2\6 +\&{if} (\\{non\_discardable}(\|q))\1\5 +\&{goto} \\{done1};\2\6 +\&{if} ${}(\\{type}(\|q)\E\\{kern\_node})$ \&{if} ( \\{subtype}(\|q) $\I$ \&{explicit} ) \&{goto} \\{done1};\5 +${}\|r\K\|q{}$;\C{now $\\{type}(\|q)\E\\{glue\_node}$, \\{kern\_node}, \\{math\_node} or \\{penalty\_node}}\6 +$\}$ \6 +\4\\{done1}:\6 +\&{if} ${}(\|r\I\\{temp\_head}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|r)\K\\{null};{}$\5 +\\{flush\_node\_list}(\\{link}(\\{temp\_head}));\5 +${}\\{link}(\\{temp\_head})\K\|q;{}$\6 +\4${}\}{}$\2\6 +$\}{}$\par +\U877.\fi + +\M{880}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\B\4\X880:Justify the line ending at breakpoint \\{cur\_p}, and append it to the current vertical list, together with associated penalties and other insertions\X${}\E{}$\6 +\X881: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 +\X887:Put the \(l)\.{\\leftskip} glue at the left and detach this line\X;\6 +\X889:Call the packaging subroutine, setting \\{just\_box} to the justified box\X;\6 +\X888: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 +\X890:Append a penalty node, if a nonzero penalty is appropriate\X\par +\U877.\fi + +\M{881}At the end of the following code, \|q will point to the final node on the +list about to be justified. + +\Y\B\4\X881: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${}\E{}$\6 +$\|q\K\\{cur\_break}(\\{cur\_p});{}$\5 +${}\\{disc\_break}\K\\{false};{}$\5 +${}\\{post\_disc\_break}\K\\{false};{}$\6 +\&{if} ${}(\|q\I\\{null}{}$)\C{\|q cannot be a \\{char\_node}}\1\6 +\&{if} ${}(\\{type}(\|q)\E\\{glue\_node}){}$\5 +${}\{{}$\5 +\1\\{delete\_glue\_ref}(\\{glue\_ptr}(\|q));\5 +${}\\{glue\_ptr}(\|q)\K\\{right\_skip};{}$\5 +${}\\{subtype}(\|q)\K\\{right\_skip\_code}+\T{1};{}$\5 +\\{add\_glue\_ref}(\\{right\_skip});\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{type}(\|q)\E\\{disc\_node}){}$\1\5 +\X882:Change discretionary to compulsory and set \\{disc\_break}: $\K$ \\{true}\X\2\6 +\&{else} \&{if} ${}((\\{type}(\|q)\E\\{math\_node})\V(\\{type}(\|q)\E\\{kern\_node})){}$\1\5 +${}\\{width}(\|q)\K\T{0};{}$\2\6 +\4${}\}{}$\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{temp\_head};{}$\6 +\&{while} ${}(\\{link}(\|q)\I\\{null}){}$\1\5 +${}\|q\K\\{link}(\|q);{}$\2\6 +\4${}\}{}$\2\6 +\X886:Put the \(r)\.{\\rightskip} glue after node \|q\X;\6 +\\{done}:\par +\U880.\fi + +\M{882}\B\X882:Change discretionary to compulsory and set \\{disc\_break}: $\K$ \\{true}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|t\K\\{replace\_count}(\|q);{}$\5 +\X883:Destroy the \|t nodes following \|q, and make \|r point to the following node\X;\6 +\&{if} ${}(\\{post\_break}(\|q)\I\\{null}){}$\1\5 +\X884:Transplant the post-break list\X;\2\6 +\&{if} ${}(\\{pre\_break}(\|q)\I\\{null}){}$\1\5 +\X885:Transplant the pre-break list\X;\2\6 +${}\\{link}(\|q)\K\|r;{}$\5 +${}\\{disc\_break}\K\\{true};{}$\6 +\4${}\}{}$\2\par +\U881.\fi + +\M{883}\B\X883:Destroy the \|t nodes following \|q, and make \|r point to the following node\X${}\E{}$\6 +\&{if} ${}(\|t\E\T{0}){}$\1\5 +${}\|r\K\\{link}(\|q);{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|r\K\|q;{}$\6 +\&{while} ${}(\|t>\T{1}){}$\5 +${}\{{}$\5 +\1${}\|r\K\\{link}(\|r);{}$\5 +\\{decr}(\|t);\6 +\4${}\}{}$\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)\K\T{0};{}$\6 +\4${}\}{}$\2\par +\U882.\fi + +\M{884}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\B\4\X884:Transplant the post-break list\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|s\K\\{post\_break}(\|q);{}$\6 +\&{while} ${}(\\{link}(\|s)\I\\{null}){}$\1\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 +\4${}\}{}$\2\par +\U882.\fi + +\M{885}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\B\4\X885:Transplant the pre-break list\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|s\K\\{pre\_break}(\|q);{}$\5 +${}\\{link}(\|q)\K\|s;{}$\6 +\&{while} ${}(\\{link}(\|s)\I\\{null}){}$\1\5 +${}\|s\K\\{link}(\|s);{}$\2\6 +${}\\{pre\_break}(\|q)\K\\{null};{}$\5 +${}\|q\K\|s;{}$\6 +\4${}\}{}$\2\par +\U882.\fi + +\M{886}\B\X886:Put the \(r)\.{\\rightskip} glue after node \|q\X${}\E{}$\6 +$\|r\K\\{new\_param\_glue}(\\{right\_skip\_code});{}$\5 +${}\\{link}(\|r)\K\\{link}(\|q);{}$\5 +${}\\{link}(\|q)\K\|r;$ $\|q\K{}$\|r\par +\U881.\fi + +\M{887}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\B\4\X887:Put the \(l)\.{\\leftskip} glue at the left and detach this line\X${}\E{}$\6 +$\|r\K\\{link}(\|q);{}$\5 +${}\\{link}(\|q)\K\\{null};{}$\5 +${}\|q\K\\{link}(\\{temp\_head});{}$\5 +${}\\{link}(\\{temp\_head})\K\|r;{}$\6 +\&{if} ${}(\\{left\_skip}\I\\{zero\_glue}){}$\5 +${}\{{}$\5 +\1${}\|r\K\\{new\_param\_glue}(\\{left\_skip\_code});{}$\5 +${}\\{link}(\|r)\K\|q;{}$\5 +${}\|q\K\|r;{}$\6 +\4${}\}{}$\2\par +\U880.\fi + +\M{888}\B\X888: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${}\E{}$\6 +\\{append\_to\_vlist}(\\{just\_box});\6 +\&{if} ${}(\\{adjust\_head}\I\\{adjust\_tail}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\\{tail})\K\\{link}(\\{adjust\_head});{}$\5 +${}\\{tail}\K\\{adjust\_tail};{}$\6 +\4${}\}{}$\2\6 +$\\{adjust\_tail}\K{}$\\{null}\par +\U880.\fi + +\M{889}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\B\4\X889:Call the packaging subroutine, setting \\{just\_box} to the justified box\X${}\E{}$\6 +\&{if} ${}(\\{cur\_line}>\\{last\_special\_line}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_width}\K\\{second\_width};{}$\5 +${}\\{cur\_indent}\K\\{second\_indent};{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{par\_shape\_ptr}\E\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_width}\K\\{first\_width};{}$\5 +${}\\{cur\_indent}\K\\{first\_indent};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_width}\K\\{mem}[\\{par\_shape\_ptr}+\T{2}*\\{cur\_line}].\\{sc};{}$\5 +${}\\{cur\_indent}\K\\{mem}[\\{par\_shape\_ptr}+\T{2}*\\{cur\_line}-\T{1}].\\{sc};{}$\6 +\4${}\}{}$\2\6 +${}\\{adjust\_tail}\K\\{adjust\_head};{}$\5 +${}\\{just\_box}\K\\{hpack}(\|q,\39\\{cur\_width},\39\\{exactly});$ $\\{shift\_amount}(\\{just\_box})\K{}$\\{cur\_indent}\par +\U880.\fi + +\M{890}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\B\4\X890:Append a penalty node, if a nonzero penalty is appropriate\X${}\E{}$\6 +\&{if} ${}(\\{cur\_line}+\T{1}\I\\{best\_line}){}$\5 +${}\{{}$\5 +\1${}\\{pen}\K\\{inter\_line\_penalty};{}$\6 +\&{if} ${}(\\{cur\_line}\E\\{prev\_graf}+\T{1}){}$\1\5 +${}\\{pen}\K\\{pen}+\\{club\_penalty};{}$\2\6 +\&{if} ${}(\\{cur\_line}+\T{2}\E\\{best\_line}){}$\1\5 +${}\\{pen}\K\\{pen}+\\{final\_widow\_penalty};{}$\2\6 +\&{if} (\\{disc\_break})\1\5 +${}\\{pen}\K\\{pen}+\\{broken\_penalty};{}$\2\6 +\&{if} ${}(\\{pen}\I\T{0}){}$\5 +${}\{{}$\5 +\1${}\|r\K\\{new\_penalty}(\\{pen});{}$\5 +${}\\{link}(\\{tail})\K\|r;{}$\5 +${}\\{tail}\K\|r;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U880.\fi + +\N{1}{891}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)\E\T{0}$), a lowercase letter (if +$\\{lc\_code}(\|c)\E\|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 +$\T{1}\Z\|a\Z\|b+\T{1}\Z\|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\B\4\X891:Initialize for hyphenating a paragraph\X${}\E{}$\6 +${}\{{}$\6 +\8\#\&{ifdef} \.{INIT}\1\6 +\&{if} (\\{trie\_not\_ready})\1\5 +\\{init\_trie}(\,);\2\6 +\8\#\&{endif}\6 +${}\\{cur\_lang}\K\\{init\_cur\_lang};{}$\5 +${}\\{l\_hyf}\K\\{init\_l\_hyf};{}$\5 +${}\\{r\_hyf}\K\\{init\_r\_hyf};{}$\6 +\4${}\}{}$\2\par +\U863.\fi + +\M{892}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{uint16\_t} \\{hc}[\T{66}];\C{word to be hyphenated}\6 +\&{small\_number} \\{hn};\C{the number of positions occupied in \\{hc}}\6 +\&{pointer} \\{ha}${},{}$ \\{hb};\C{nodes $\\{ha}\dotdot\\{hb}$ should be replaced by the hyphenated result}\6 +\&{internal\_font\_number} \\{hf};\C{font number of the letters in \\{hc}}\6 +\&{uint16\_t} \\{hu}[\T{64}];\C{like \\{hc}, before conversion to lowercase}\6 +\&{int} \\{hyf\_char};\C{hyphen character of the relevant font}\6 +\&{ASCII\_code} \\{cur\_lang}${},{}$ \\{init\_cur\_lang};\C{current hyphenation table of interest}\6 +\&{int} \\{l\_hyf}${},{}$ \\{r\_hyf}${},{}$ \\{init\_l\_hyf}${},{}$ \\{init\_r\_hyf};\C{limits on fragment sizes}\6 +\&{halfword} \\{hyf\_bchar};\C{boundary character after $c_n$}\par +\fi + +\M{893}Hyphenation routines need a few more local variables. + +\Y\B\4\X862:Local variables for line breaking\X${}\mathrel+\E{}$\6 +\&{small\_number} \|j;\C{an index into \\{hc} or \\{hu}}\6 +\&{uint8\_t} \|c;\C{character being considered for hyphenation}\par +\fi + +\M{894}When the following code is activated, the \\{line\_break} procedure is in its +second pass, and \\{cur\_p} points to a glue node. + +\Y\B\4\X894:Try to hyphenate the following word\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{prev\_s}\K\\{cur\_p};{}$\5 +${}\|s\K\\{link}(\\{prev\_s});{}$\6 +\&{if} ${}(\|s\I\\{null}){}$\5 +${}\{{}$\5 +\1\X896:Skip to node \\{ha}, or \&{goto} \\{done1} if no hyphenation should be attempted\X;\6 +\&{if} ${}(\\{l\_hyf}+\\{r\_hyf}>\T{63}){}$\1\5 +\&{goto} \\{done1};\2\6 +\X897:Skip to node \\{hb}, putting letters into \\{hu} and \\{hc}\X;\6 +\X899: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 +\4${}\}{}$\2\6 +\4\\{done1}:\5 +;\6 +\4${}\}{}$\2\par +\U866.\fi + +\M{895}\B\X826:Declare subprocedures for \\{line\_break}\X${}\mathrel+\E{}$\6 +\hbox{\4}\X906:Declare the function called \\{reconstitute}\X\7 +\&{void} \\{hyphenate}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\X901:Local variables for hyphenation\X\6 +\X923:Find hyphen locations for the word in \\{hc}, or \&{return}\X;\6 +\X902:If no hyphens were found, \&{return}\X;\6 +\X903:Replace nodes $\\{ha}\MRL{{.}{.}}\\{hb}$ by a sequence of nodes that includes the discretionary hyphens\X;\6 +\4${}\}{}$\2\par +\fi + +\M{896}The first thing we need to do is find the node \\{ha} just before the +first letter. + +\Y\B\4\X896:Skip to node \\{ha}, or \&{goto} \\{done1} if no hyphenation should be attempted\X${}\E{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} (\\{is\_char\_node}(\|s))\5 +${}\{{}$\5 +\1${}\|c\K\\{qo}(\\{character}(\|s));{}$\5 +${}\\{hf}\K\\{font}(\|s);{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{type}(\|s)\E\\{ligature\_node}){}$\1\6 +\&{if} ${}(\\{lig\_ptr}(\|s)\E\\{null}){}$\1\5 +\&{goto} \\{resume};\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{lig\_ptr}(\|s);{}$\5 +${}\|c\K\\{qo}(\\{character}(\|q));{}$\5 +${}\\{hf}\K\\{font}(\|q);{}$\6 +\4${}\}{}$\2\2\6 +\&{else} \&{if} ${}((\\{type}(\|s)\E\\{kern\_node})\W(\\{subtype}(\|s)\E\\{normal})){}$\1\5 +\&{goto} \\{resume};\2\6 +\&{else} \&{if} ${}(\\{type}(\|s)\E\\{whatsit\_node}){}$\5 +${}\{{}$\5 +\1\X1363:Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop\X;\6 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\&{goto} \\{done1};\2\6 +\&{if} ${}(\\{lc\_code}(\|c)\I\T{0}){}$\1\6 +\&{if} ${}((\\{lc\_code}(\|c)\E\|c)\V(\\{uc\_hyph}>\T{0})){}$\1\5 +\&{goto} \\{done2};\2\6 +\&{else}\1\5 +\&{goto} \\{done1};\2\2\6 +\4\\{resume}:\5 +${}\\{prev\_s}\K\|s;{}$\5 +${}\|s\K\\{link}(\\{prev\_s});{}$\6 +\4${}\}{}$\2\6 +\4\\{done2}:\5 +${}\\{hyf\_char}\K\\{hyphen\_char}[\\{hf}];{}$\6 +\&{if} ${}(\\{hyf\_char}<\T{0}){}$\1\5 +\&{goto} \\{done1};\2\6 +\&{if} ${}(\\{hyf\_char}>\T{255}){}$\1\5 +\&{goto} \\{done1};\2\6 +$\\{ha}\K{}$\\{prev\_s}\par +\U894.\fi + +\M{897}The word to be hyphenated is now moved to the \\{hu} and \\{hc} arrays. + +\Y\B\4\X897:Skip to node \\{hb}, putting letters into \\{hu} and \\{hc}\X${}\E{}$\6 +$\\{hn}\K\T{0};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} (\\{is\_char\_node}(\|s))\5 +${}\{{}$\5 +\1\&{if} ${}(\\{font}(\|s)\I\\{hf}){}$\1\5 +\&{goto} \\{done3};\2\6 +${}\\{hyf\_bchar}\K\\{character}(\|s);{}$\5 +${}\|c\K\\{qo}(\\{hyf\_bchar});{}$\6 +\&{if} ${}(\\{lc\_code}(\|c)\E\T{0}){}$\1\5 +\&{goto} \\{done3};\2\6 +\&{if} ${}(\\{hn}\E\T{63}){}$\1\5 +\&{goto} \\{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 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{type}(\|s)\E\\{ligature\_node}){}$\1\5 +\X898:Move the characters of a ligature node to \\{hu} and \\{hc}; but \&{goto} \\{done3} if they are not all letters\X\2\6 +\&{else} \&{if} ${}((\\{type}(\|s)\E\\{kern\_node})\W(\\{subtype}(\|s)\E\\{normal})){}$\5 +${}\{{}$\5 +\1${}\\{hb}\K\|s;{}$\5 +${}\\{hyf\_bchar}\K\\{font\_bchar}[\\{hf}];{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\&{goto} \\{done3};\2\6 +${}\|s\K\\{link}(\|s);{}$\6 +\4${}\}{}$\2\6 +\\{done3}:\par +\U894.\fi + +\M{898}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}\E\T{0}$ and \\{hb} not set to any value. + +\Y\B\4\X898:Move the characters of a ligature node to \\{hu} and \\{hc}; but \&{goto} \\{done3} if they are not all letters\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{font}(\\{lig\_char}(\|s))\I\\{hf}){}$\1\5 +\&{goto} \\{done3};\2\6 +${}\|j\K\\{hn};{}$\5 +${}\|q\K\\{lig\_ptr}(\|s){}$;\5 +\&{if} ${}(\|q>\\{null}){}$\1\5 +${}\\{hyf\_bchar}\K\\{character}(\|q);{}$\2\6 +\&{while} ${}(\|q>\\{null}){}$\5 +${}\{{}$\5 +\1${}\|c\K\\{qo}(\\{character}(\|q));{}$\6 +\&{if} ${}(\\{lc\_code}(\|c)\E\T{0}){}$\1\5 +\&{goto} \\{done3};\2\6 +\&{if} ${}(\|j\E\T{63}){}$\1\5 +\&{goto} \\{done3};\2\6 +\\{incr}(\|j);\5 +${}\\{hu}[\|j]\K\|c;{}$\5 +${}\\{hc}[\|j]\K\\{lc\_code}(\|c){}$;\6 +${}\|q\K\\{link}(\|q);{}$\6 +\4${}\}{}$\2\6 +${}\\{hb}\K\|s;{}$\5 +${}\\{hn}\K\|j;{}$\6 +\&{if} (\\{odd}(\\{subtype}(\|s)))\1\5 +${}\\{hyf\_bchar}\K\\{font\_bchar}[\\{hf}]{}$;\5 +\2\&{else}\1\5 +${}\\{hyf\_bchar}\K\\{non\_char};{}$\2\6 +\4${}\}{}$\2\par +\U897.\fi + +\M{899}\B\X899:Check that the nodes following \\{hb} permit hyphenation and that at least $\\{l\_hyf}+\\{r\_hyf}$ letters have been found, otherwise \&{goto} \\{done1}\X${}\E{}$\6 +\&{if} ${}(\\{hn}<\\{l\_hyf}+\\{r\_hyf}){}$\1\5 +\&{goto} \\{done1};\C{\\{l\_hyf} and \\{r\_hyf} are $\G$ \T{1}}\2\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\R(\\{is\_char\_node}(\|s))){}$\1\6 +\&{switch} (\\{type}(\|s))\5 +${}\{{}$\1\6 +\4\&{case} \\{ligature\_node}:\5 +\\{do\_nothing};\5 +\&{break};\6 +\4\&{case} \\{kern\_node}:\6 +\&{if} ${}(\\{subtype}(\|s)\I\\{normal}){}$\1\5 +\&{goto} \\{done4};\5 +\2\&{break};\6 +\4\&{case} \\{whatsit\_node}:\5 +\&{case} \\{glue\_node}:\5 +\&{case} \\{penalty\_node}:\5 +\&{case} \\{ins\_node}:\5 +\&{case} \\{adjust\_node}:\5 +\&{case} \\{mark\_node}:\5 +\&{goto} \\{done4};\6 +\4\&{default}:\5 +\&{goto} \\{done1};\6 +\4${}\}{}$\2\2\6 +${}\|s\K\\{link}(\|s);{}$\6 +\4${}\}{}$\2\6 +\\{done4}:\par +\U894.\fi + +\N{1}{900}Post-hyphenation. +If a hyphen may be inserted between \\{hc}[\|j] and $\\{hc}[\|j+\T{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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{uint8\_t} \\{hyf}[\T{65}];\C{odd values indicate discretionary hyphens}\6 +\&{pointer} \\{init\_list};\C{list of punctuation characters preceding the word}\6 +\&{bool} \\{init\_lig};\C{does \\{init\_list} represent a ligature?}\6 +\&{bool} \\{init\_lft};\C{if so, did the ligature involve a left boundary?}\par +\fi + +\M{901}\B\X901:Local variables for hyphenation\X${}\E{}$\6 +\&{int} \|i${},{}$ \|j${},{}$ \|l;\C{indices into \\{hc} or \\{hu}}\6 +\&{pointer} \|q${},{}$ \|r${},{}$ \|s;\C{temporary registers for list manipulation}\6 +\&{halfword} \\{bchar};\C{right boundary character of hyphenated word, or \\{non\_char}}\par +\As912, 922\ETs929. +\U895.\fi + +\M{902}\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\B\4\X902:If no hyphens were found, \&{return}\X${}\E{}$\6 +\&{for} ${}(\|j\K\\{l\_hyf};{}$ ${}\|j\Z\\{hn}-\\{r\_hyf};{}$ ${}\|j\PP){}$\1\6 +\&{if} (\\{odd}(\\{hyf}[\|j]))\1\5 +\&{goto} \\{found1};\2\2\6 +\&{return}; \\{found1}:\par +\U895.\fi + +\M{903}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}[\T{0}] and by storing a possible right boundary +in \\{bchar}. We set $\|j\K\T{0}$ if \\{hu}[\T{0}] is to be part of the reconstruction; +otherwise $\|j\K\T{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. + +\Y\B\4\X903:Replace nodes $\\{ha}\MRL{{.}{.}}\\{hb}$ by a sequence of nodes that includes the discretionary hyphens\X${}\E{}$\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\6 +\&{if} ${}(\\{font}(\\{ha})\I\\{hf}){}$\1\5 +\&{goto} \\{found2};\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{init\_list}\K\\{ha};{}$\5 +${}\\{init\_lig}\K\\{false};{}$\5 +${}\\{hu}[\T{0}]\K\\{qo}(\\{character}(\\{ha}));{}$\6 +\4${}\}{}$\2\2\6 +\&{else} \&{if} ${}(\\{type}(\\{ha})\E\\{ligature\_node}){}$\1\6 +\&{if} ${}(\\{font}(\\{lig\_char}(\\{ha}))\I\\{hf}){}$\1\5 +\&{goto} \\{found2};\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{init\_list}\K\\{lig\_ptr}(\\{ha});{}$\5 +${}\\{init\_lig}\K\\{true};{}$\5 +${}\\{init\_lft}\K(\\{subtype}(\\{ha})>\T{1});{}$\5 +${}\\{hu}[\T{0}]\K\\{qo}(\\{character}(\\{lig\_char}(\\{ha})));{}$\6 +\&{if} ${}(\\{init\_list}\E\\{null}){}$\1\6 +\&{if} (\\{init\_lft})\5 +${}\{{}$\5 +\1${}\\{hu}[\T{0}]\K\T{256};{}$\5 +${}\\{init\_lig}\K\\{false};{}$\6 +\4${}\}{}$\C{in this case a ligature will be reconstructed from scratch}\2\2\6 +${}\\{free\_node}(\\{ha},\39\\{small\_node\_size});{}$\6 +\4${}\}{}$\2\2\6 +\&{else}\5 +${}\{{}$\5 +\C{no punctuation found; look for left boundary}\1\6 +\&{if} ${}(\R\\{is\_char\_node}(\|r)){}$\1\6 +\&{if} ${}(\\{type}(\|r)\E\\{ligature\_node}){}$\1\6 +\&{if} ${}(\\{subtype}(\|r)>\T{1}){}$\1\5 +\&{goto} \\{found2};\2\2\2\6 +${}\|j\K\T{1};{}$\5 +${}\|s\K\\{ha};{}$\5 +${}\\{init\_list}\K\\{null};{}$\5 +\&{goto} \\{common\_ending};\6 +\4${}\}{}$\2\6 +${}\|s\K\\{cur\_p}{}$;\C{we have $\\{cur\_p}\I\\{ha}$ because $\\{type}(\\{cur\_p})\E\\{glue\_node}$}\6 +\&{while} ${}(\\{link}(\|s)\I\\{ha}){}$\1\5 +${}\|s\K\\{link}(\|s);{}$\2\6 +${}\|j\K\T{0};{}$\5 +\&{goto} \\{common\_ending};\6 +\4\\{found2}:\5 +${}\|s\K\\{ha};{}$\5 +${}\|j\K\T{0};{}$\5 +${}\\{hu}[\T{0}]\K\T{256};{}$\5 +${}\\{init\_lig}\K\\{false};{}$\5 +${}\\{init\_list}\K\\{null};{}$\6 +\4\\{common\_ending}:\5 +\\{flush\_node\_list}(\|r);\5 +\X913:Reconstitute nodes for the hyphenated word, inserting discretionary hyphens\X;\6 +\\{flush\_list}(\\{init\_list})\par +\U895.\fi + +\M{904}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 + +\M{905}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+\T{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\E\T{0}$: Then we assume that the +translation of \\{hu}[\T{0}] appears in a special list of charnodes starting at +\\{init\_list}; moreover, if \\{init\_lig} is \\{true}, then \\{hu}[\T{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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{small\_number} \\{hyphen\_passed};\C{first hyphen in a ligature, if any}\par +\fi + +\M{906}\B\X906:Declare the function called \\{reconstitute}\X${}\E{}$\6 +\&{small\_number} \\{reconstitute}(\&{small\_number} \|j${},\39{}$\&{small\_number} \|n${},\39{}$\&{halfword} \\{bchar}${},\39{}$\&{halfword} \\{hchar})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{temporary register for list manipulation}\6 +\&{pointer} \|t;\C{a node being appended to}\6 +\&{four\_quarters} \|q;\C{character information or a lig/kern instruction}\6 +\&{halfword} \\{cur\_rh};\C{hyphen character for ligature testing}\6 +\&{halfword} \\{test\_char};\C{hyphen or other character for ligature testing}\6 +\&{scaled} \|w;\C{amount of kerning}\6 +\&{font\_index} \|k;\C{position of current lig/kern instruction}\7 +${}\\{hyphen\_passed}\K\T{0};{}$\5 +${}\|t\K\\{hold\_head};{}$\5 +${}\|w\K\T{0};{}$\5 +${}\\{link}(\\{hold\_head})\K\\{null}{}$;\C{at this point $\\{ligature\_present}\E\\{lft\_hit}\E\\{rt\_hit}\E\\{false}$}\6 +\X908:Set up data structures with the cursor following position \|j\X;\6 +\4\\{resume}:\5 +\X909: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 +\X910:Append a ligature and/or kern to the translation; \&{goto} \&{continue} if the stack of inserted ligatures is nonempty\X;\6 +\&{return} \|j;\6 +\4${}\}{}$\2\par +\U895.\fi + +\M{907}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+\T{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 +\hbox{$\\{qi}(\\{hu}[\|j+\T{1}])$},&if $\\{lig\_stack}\E\\{null}$ and $\|j<\|n$;\cr +bchar,&if $\\{lig\_stack}\E\\{null}$ and $\|j\E\|n$.\cr}$$ + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{halfword} \\{cur\_l}${},{}$ \\{cur\_r};\C{characters before and after the cursor}\6 +\&{pointer} \\{cur\_q};\C{where a ligature should be detached}\6 +\&{pointer} \\{lig\_stack};\C{unfinished business to the right of the cursor}\6 +\&{bool} \\{ligature\_present};\C{should a ligature node be made for \\{cur\_l}?}\6 +\&{bool} \\{lft\_hit}${},{}$ \\{rt\_hit};\C{did we hit a ligature with a boundary character?}\par +\fi + +\M{908}\B\D$\\{append\_charnode\_to\_t}(\|X)$ \6 +${}\{{}$\5 +\1${}\\{link}(\|t)\K\\{get\_avail}(\,);{}$\5 +${}\|t\K\\{link}(\|t);{}$\5 +${}\\{font}(\|t)\K\\{hf};{}$\5 +${}\\{character}(\|t)\K\|X;{}$\6 +\4${}\}{}$\2\par +\B\4\D$\\{set\_cur\_r}$ \6 +${}\{{}$\5 +\1\&{if} ${}(\|j<\|n){}$\1\5 +${}\\{cur\_r}\K\\{qi}(\\{hu}[\|j+\T{1}]){}$;\5 +\2\&{else}\1\5 +${}\\{cur\_r}\K\\{bchar};{}$\2\6 +\&{if} (\\{odd}(\\{hyf}[\|j]))\1\5 +${}\\{cur\_rh}\K\\{hchar}{}$;\5 +\2\&{else}\1\5 +${}\\{cur\_rh}\K\\{non\_char};{}$\2\6 +\4${}\}{}$\2\par +\Y\B\4\X908:Set up data structures with the cursor following position \|j\X${}\E{}$\6 +$\\{cur\_l}\K\\{qi}(\\{hu}[\|j]);{}$\5 +${}\\{cur\_q}\K\|t;{}$\6 +\&{if} ${}(\|j\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{ligature\_present}\K\\{init\_lig};{}$\5 +${}\|p\K\\{init\_list};{}$\6 +\&{if} (\\{ligature\_present})\1\5 +${}\\{lft\_hit}\K\\{init\_lft};{}$\2\6 +\&{while} ${}(\|p>\\{null}){}$\5 +${}\{{}$\5 +\1\\{append\_charnode\_to\_t}(\\{character}(\|p));\5 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_l}<\\{non\_char}){}$\1\5 +\\{append\_charnode\_to\_t}(\\{cur\_l});\2\6 +${}\\{lig\_stack}\K\\{null};$ \\{set\_cur\_r}\par +\U906.\fi + +\M{909}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\B\4\X909:If there's a ligature or kern at the cursor position, update the data structures, possibly advancing~\|j; continue until the cursor moves\X${}\E{}$\6 +\&{if} ${}(\\{cur\_l}\E\\{non\_char}){}$\5 +${}\{{}$\5 +\1${}\|k\K\\{bchar\_label}[\\{hf}];{}$\6 +\&{if} ${}(\|k\E\\{non\_address}){}$\1\5 +\&{goto} \\{done};\5 +\2\&{else}\1\5 +${}\|q\K\\{font\_info}[\|k].\\{qqqq};{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{char\_info}(\\{hf})(\\{cur\_l});{}$\6 +\&{if} ${}(\\{char\_tag}(\|q)\I\\{lig\_tag}){}$\1\5 +\&{goto} \\{done};\2\6 +${}\|k\K\\{lig\_kern\_start}(\\{hf})(\|q);{}$\5 +${}\|q\K\\{font\_info}[\|k].\\{qqqq};{}$\6 +\&{if} ${}(\\{skip\_byte}(\|q)>\\{stop\_flag}){}$\5 +${}\{{}$\5 +\1${}\|k\K\\{lig\_kern\_restart}(\\{hf})(\|q);{}$\5 +${}\|q\K\\{font\_info}[\|k].\\{qqqq};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\C{now \|k is the starting address of the lig/kern program}\2\6 +\&{if} ${}(\\{cur\_rh}<\\{non\_char}){}$\1\5 +${}\\{test\_char}\K\\{cur\_rh}{}$;\5 +\2\&{else}\1\5 +${}\\{test\_char}\K\\{cur\_r};{}$\2\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{next\_char}(\|q)\E\\{test\_char}){}$\1\6 +\&{if} ${}(\\{skip\_byte}(\|q)\Z\\{stop\_flag}){}$\1\6 +\&{if} ${}(\\{cur\_rh}<\\{non\_char}){}$\5 +${}\{{}$\5 +\1${}\\{hyphen\_passed}\K\|j;{}$\5 +${}\\{hchar}\K\\{non\_char};{}$\5 +${}\\{cur\_rh}\K\\{non\_char};{}$\5 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{hchar}<\\{non\_char}){}$\1\6 +\&{if} (\\{odd}(\\{hyf}[\|j]))\5 +${}\{{}$\5 +\1${}\\{hyphen\_passed}\K\|j;{}$\5 +${}\\{hchar}\K\\{non\_char};{}$\6 +\4${}\}{}$\2\2\6 +\&{if} ${}(\\{op\_byte}(\|q)<\\{kern\_flag}){}$\1\5 +\X911: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} \\{done};\C{this kern will be inserted below}\6 +\4${}\}{}$\2\2\2\6 +\&{if} ${}(\\{skip\_byte}(\|q)\G\\{stop\_flag}){}$\1\6 +\&{if} ${}(\\{cur\_rh}\E\\{non\_char}){}$\1\5 +\&{goto} \\{done};\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_rh}\K\\{non\_char};{}$\5 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\2\6 +${}\|k\K\|k+\\{qo}(\\{skip\_byte}(\|q))+\T{1};{}$\5 +${}\|q\K\\{font\_info}[\|k].\\{qqqq};{}$\6 +\4${}\}{}$\2\6 +\\{done}:\par +\U906.\fi + +\M{910}\B\D$\\{wrap\_lig}(\|X)$ \6 +\&{if} (\\{ligature\_present})\5 +${}\{{}$\5 +\1${}\|p\K\\{new\_ligature}(\\{hf},\39\\{cur\_l},\39\\{link}(\\{cur\_q}));{}$\6 +\&{if} (\\{lft\_hit})\5 +${}\{{}$\5 +\1${}\\{subtype}(\|p)\K\T{2};{}$\5 +${}\\{lft\_hit}\K\\{false};{}$\6 +\4${}\}{}$\2\6 +\&{if} (\|X)\1\6 +\&{if} ${}(\\{lig\_stack}\E\\{null}){}$\5 +${}\{{}$\5 +\1\\{incr}(\\{subtype}(\|p));\5 +${}\\{rt\_hit}\K\\{false};{}$\6 +\4${}\}{}$\2\2\6 +${}\\{link}(\\{cur\_q})\K\|p;{}$\5 +${}\|t\K\|p;{}$\5 +${}\\{ligature\_present}\K\\{false};{}$\6 +\4${}\}{}$\2\par +\B\4\D$\\{pop\_lig\_stack}$ \6 +${}\{{}$\5 +\1\&{if} ${}(\\{lig\_ptr}(\\{lig\_stack})>\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|t)\K\\{lig\_ptr}(\\{lig\_stack}){}$;\C{this is a charnode for $\\{hu}[\|j+\T{1}]$}\6 +${}\|t\K\\{link}(\|t);{}$\5 +\\{incr}(\|j);\6 +\4${}\}{}$\2\6 +${}\|p\K\\{lig\_stack};{}$\5 +${}\\{lig\_stack}\K\\{link}(\|p);{}$\5 +${}\\{free\_node}(\|p,\39\\{small\_node\_size});{}$\6 +\&{if} ${}(\\{lig\_stack}\E\\{null}){}$\1\5 +\\{set\_cur\_r}\5 +\2\&{else}\1\5 +${}\\{cur\_r}\K\\{character}(\\{lig\_stack});{}$\2\6 +\4${}\}{}$\C{if \\{lig\_stack} isn't \\{null} we have $\\{cur\_rh}\E\\{non\_char}$}\2\par +\Y\B\4\X910:Append a ligature and/or kern to the translation; \&{goto} \&{continue} if the stack of inserted ligatures is nonempty\X${}\E{}$\6 +\\{wrap\_lig}(\\{rt\_hit});\6 +\&{if} ${}(\|w\I\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|t)\K\\{new\_kern}(\|w);{}$\5 +${}\|t\K\\{link}(\|t);{}$\5 +${}\|w\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{lig\_stack}>\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_q}\K\|t;{}$\5 +${}\\{cur\_l}\K\\{character}(\\{lig\_stack});{}$\5 +${}\\{ligature\_present}\K\\{true};{}$\5 +\\{pop\_lig\_stack};\5 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\par +\U906.\fi + +\M{911}\B\X911: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${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_l}\E\\{non\_char}){}$\1\5 +${}\\{lft\_hit}\K\\{true};{}$\2\6 +\&{if} ${}(\|j\E\|n){}$\1\6 +\&{if} ${}(\\{lig\_stack}\E\\{null}){}$\1\5 +${}\\{rt\_hit}\K\\{true};{}$\2\2\6 +\\{check\_interrupt};\C{allow a way out in case there's an infinite ligature loop}\6 +\&{switch} (\\{op\_byte}(\|q))\5 +${}\{{}$\1\6 +\4\\{qi}(\&{case} \T{1}):\5 +\\{qi}(\&{case} \T{5}):\6 +${}\{{}$\5 +\1${}\\{cur\_l}\K\\{rem\_byte}(\|q){}$;\C{\.{=:\?}, \.{=:\?>}}\6 +${}\\{ligature\_present}\K\\{true};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\\{qi}(\&{case} \T{2}):\5 +\\{qi}(\&{case} \T{6}):\6 +${}\{{}$\5 +\1${}\\{cur\_r}\K\\{rem\_byte}(\|q){}$;\C{\.{\?=:}, \.{\?=:>}}\6 +\&{if} ${}(\\{lig\_stack}>\\{null}){}$\1\5 +${}\\{character}(\\{lig\_stack})\K\\{cur\_r};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{lig\_stack}\K\\{new\_lig\_item}(\\{cur\_r});{}$\6 +\&{if} ${}(\|j\E\|n){}$\1\5 +${}\\{bchar}\K\\{non\_char};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|p\K\\{get\_avail}(\,);{}$\5 +${}\\{lig\_ptr}(\\{lig\_stack})\K\|p;{}$\5 +${}\\{character}(\|p)\K\\{qi}(\\{hu}[\|j+\T{1}]);{}$\5 +${}\\{font}(\|p)\K\\{hf};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\\{qi}(\&{case} \T{3}):\6 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\\{qi}(\&{case} \T{7}):\5 +\\{qi}(\&{case} \T{11}):\6 +${}\{{}$\5 +\1\\{wrap\_lig}(\\{false});\C{\.{\?=:\?>}, \.{\?=:\?>>}}\6 +${}\\{cur\_q}\K\|t;{}$\5 +${}\\{cur\_l}\K\\{rem\_byte}(\|q);{}$\5 +${}\\{ligature\_present}\K\\{true};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\6 +${}\{{}$\5 +\1${}\\{cur\_l}\K\\{rem\_byte}(\|q);{}$\5 +${}\\{ligature\_present}\K\\{true}{}$;\C{\.{=:}}\6 +\&{if} ${}(\\{lig\_stack}>\\{null}){}$\1\5 +\\{pop\_lig\_stack}\2\6 +\&{else} \&{if} ${}(\|j\E\|n){}$\1\5 +\&{goto} \\{done};\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{append\_charnode\_to\_t}(\\{cur\_r});\5 +\\{incr}(\|j);\5 +\\{set\_cur\_r};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{op\_byte}(\|q)>\\{qi}(\T{4})){}$\1\6 +\&{if} ${}(\\{op\_byte}(\|q)\I\\{qi}(\T{7})){}$\1\5 +\&{goto} \\{done};\2\2\6 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\par +\U909.\fi + +\M{912}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}[\T{1}\dotdot\\{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\B\4\X901:Local variables for hyphenation\X${}\mathrel+\E{}$\6 +\&{pointer} \\{major\_tail}${},{}$ \\{minor\_tail};\C{the end of lists in the main and discretionary branches being reconstructed}\6 +\&{ASCII\_code} \|c;\C{character temporarily replaced by a hyphen}\6 +\&{uint8\_t} \\{c\_loc};\C{where that character came from}\6 +\&{int} \\{r\_count};\C{replacement count for discretionary}\6 +\&{pointer} \\{hyf\_node};\C{the hyphen, if it exists}\par +\fi + +\M{913}When the following code is performed, \\{hyf}[\T{0}] and \\{hyf}[\\{hn}] will be zero. + +\Y\B\4\X913:Reconstitute nodes for the hyphenated word, inserting discretionary hyphens\X${}\E{}$\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|l\K\|j;{}$\5 +${}\|j\K\\{reconstitute}(\|j,\39\\{hn},\39\\{bchar},\39\\{qi}(\\{hyf\_char}))+\T{1};{}$\6 +\&{if} ${}(\\{hyphen\_passed}\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|s)\K\\{link}(\\{hold\_head});{}$\6 +\&{while} ${}(\\{link}(\|s)>\\{null}){}$\1\5 +${}\|s\K\\{link}(\|s);{}$\2\6 +\&{if} ${}(\\{odd}(\\{hyf}[\|j-\T{1}])){}$\5 +${}\{{}$\5 +\1${}\|l\K\|j;{}$\5 +${}\\{hyphen\_passed}\K\|j-\T{1};{}$\5 +${}\\{link}(\\{hold\_head})\K\\{null};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{hyphen\_passed}>\T{0}){}$\1\5 +\X914: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${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|j>\\{hn}));$ $\\{link}(\|s)\K{}$\|q\par +\U903.\fi + +\M{914}In this repeat loop we will insert another discretionary if $\\{hyf}[\|j-\T{1}]$ is +odd, when both branches of the previous discretionary end at position $\|j-\T{1}$. +Strictly speaking, we aren't justified in doing this, because we don't know +that a hyphen after $\|j-\T{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\B\4\D$\\{advance\_major\_tail}$ \6 +${}\{{}$\5 +\1${}\\{major\_tail}\K\\{link}(\\{major\_tail});{}$\5 +\\{incr}(\\{r\_count});\6 +\4${}\}{}$\2\par +\Y\B\4\X914:Create and append a discretionary node as an alternative to the unhyphenated word, and continue to develop both branches until they become equivalent\X${}\E{}$\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|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}\K\T{0};{}$\6 +\&{while} ${}(\\{link}(\\{major\_tail})>\\{null}){}$\1\5 +\\{advance\_major\_tail};\2\6 +${}\|i\K\\{hyphen\_passed};{}$\5 +${}\\{hyf}[\|i]\K\T{0};{}$\5 +\X915:Put the \(c)characters $\\{hu}[\|l\MRL{{.}{.}}\|i]$ and a hyphen into \\{pre\_break}(\|r)\X;\6 +\X916:Put the \(c)characters $\\{hu}[\|i+\T{1..}]$ into \\{post\_break}(\|r), appending to this list and to \\{major\_tail} until synchronization has been achieved\X;\6 +\X918:Move pointer \|s to the end of the current list, and set \\{replace\_count}(\|r) appropriately\X;\6 +${}\\{hyphen\_passed}\K\|j-\T{1};{}$\5 +${}\\{link}(\\{hold\_head})\K\\{null};{}$\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R(\R\\{odd}(\\{hyf}[\|j-\T{1}])){}$)\par +\U913.\fi + +\M{915}The new hyphen might combine with the previous character via ligature +or kern. At this point we have $\|l-\T{1}\Z\|i<\|j$ and $\|i<\\{hn}$. + +\Y\B\4\X915:Put the \(c)characters $\\{hu}[\|l\MRL{{.}{.}}\|i]$ and a hyphen into \\{pre\_break}(\|r)\X${}\E{}$\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}){}$\5 +${}\{{}$\5 +\1\\{incr}(\|i);\5 +${}\|c\K\\{hu}[\|i];{}$\5 +${}\\{hu}[\|i]\K\\{hyf\_char};{}$\5 +\\{free\_avail}(\\{hyf\_node});\6 +\4${}\}{}$\2\6 +\&{while} ${}(\|l\Z\|i){}$\5 +${}\{{}$\5 +\1${}\|l\K\\{reconstitute}(\|l,\39\|i,\39\\{font\_bchar}[\\{hf}],\39\\{non\_char})+\T{1};{}$\6 +\&{if} ${}(\\{link}(\\{hold\_head})>\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{minor\_tail}\E\\{null}){}$\1\5 +${}\\{pre\_break}(\|r)\K\\{link}(\\{hold\_head});{}$\2\6 +\&{else}\1\5 +${}\\{link}(\\{minor\_tail})\K\\{link}(\\{hold\_head});{}$\2\6 +${}\\{minor\_tail}\K\\{link}(\\{hold\_head});{}$\6 +\&{while} ${}(\\{link}(\\{minor\_tail})>\\{null}){}$\1\5 +${}\\{minor\_tail}\K\\{link}(\\{minor\_tail});{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{hyf\_node}\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{hu}[\|i]\K\|c{}$;\C{restore the character in the hyphen position}\6 +${}\|l\K\|i;{}$\5 +\\{decr}(\|i);\6 +\4${}\}{}$\2\par +\U914.\fi + +\M{916}The synchronization algorithm begins with $\|l\E\|i+\T{1}\Z\|j$. + +\Y\B\4\X916:Put the \(c)characters $\\{hu}[\|i+\T{1..}]$ into \\{post\_break}(\|r), appending to this list and to \\{major\_tail} until synchronization has been achieved\X${}\E{}$\6 +$\\{minor\_tail}\K\\{null};{}$\5 +${}\\{post\_break}(\|r)\K\\{null};{}$\5 +${}\\{c\_loc}\K\T{0};{}$\6 +\&{if} ${}(\\{bchar\_label}[\\{hf}]\I\\{non\_address}{}$)\C{put left boundary at beginning of new line}\6 +${}\{{}$\5 +\1\\{decr}(\|l);\5 +${}\|c\K\\{hu}[\|l];{}$\5 +${}\\{c\_loc}\K\|l;{}$\5 +${}\\{hu}[\|l]\K\T{256};{}$\6 +\4${}\}{}$\2\6 +\&{while} ${}(\|l<\|j){}$\5 +${}\{{}$\5 +\1\&{do}\5 +${}\{{}$\1\6 +${}\|l\K\\{reconstitute}(\|l,\39\\{hn},\39\\{bchar},\39\\{non\_char})+\T{1};{}$\6 +\&{if} ${}(\\{c\_loc}>\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{hu}[\\{c\_loc}]\K\|c;{}$\5 +${}\\{c\_loc}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{link}(\\{hold\_head})>\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{minor\_tail}\E\\{null}){}$\1\5 +${}\\{post\_break}(\|r)\K\\{link}(\\{hold\_head});{}$\2\6 +\&{else}\1\5 +${}\\{link}(\\{minor\_tail})\K\\{link}(\\{hold\_head});{}$\2\6 +${}\\{minor\_tail}\K\\{link}(\\{hold\_head});{}$\6 +\&{while} ${}(\\{link}(\\{minor\_tail})>\\{null}){}$\1\5 +${}\\{minor\_tail}\K\\{link}(\\{minor\_tail});{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|l\G\|j));{}$\6 +\&{while} ${}(\|l>\|j){}$\1\5 +\X917:Append characters of \\{hu} [ \|j $\MRL{{.}{.}}$ ] to \\{major\_tail}, advancing~\|j\X;\2\6 +\4${}\}{}$\2\par +\U914.\fi + +\M{917}\B\X917:Append characters of \\{hu} [ \|j $\MRL{{.}{.}}$ ] to \\{major\_tail}, advancing~\|j\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|j\K\\{reconstitute}(\|j,\39\\{hn},\39\\{bchar},\39\\{non\_char})+\T{1};{}$\5 +${}\\{link}(\\{major\_tail})\K\\{link}(\\{hold\_head});{}$\6 +\&{while} ${}(\\{link}(\\{major\_tail})>\\{null}){}$\1\5 +\\{advance\_major\_tail};\2\6 +\4${}\}{}$\2\par +\U916.\fi + +\M{918}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\B\4\X918:Move pointer \|s to the end of the current list, and set \\{replace\_count}(\|r) appropriately\X${}\E{}$\6 +\&{if} ${}(\\{r\_count}>\T{127}{}$)\C{we have to forget the discretionary hyphen}\6 +${}\{{}$\5 +\1${}\\{link}(\|s)\K\\{link}(\|r);{}$\5 +${}\\{link}(\|r)\K\\{null};{}$\5 +\\{flush\_node\_list}(\|r);\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{link}(\|s)\K\|r;{}$\5 +${}\\{replace\_count}(\|r)\K\\{r\_count};{}$\6 +\4${}\}{}$\2\6 +$\|s\K{}$\\{major\_tail}\par +\U914.\fi + +\N{1}{919}Hyphenation. +When a word $\\{hc}[\T{1}\dotdot\\{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}[\T{0}] +and $\\{hc}[\\{hn}+\T{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}[\T{0}\dotdot(\\{hn}+\T{1})]$. Each pattern $p_1\ldots p_k$ of length \|k has an associated +sequence of $\|k+\T{1}$ numbers $n_0\ldots n_k$; and if the pattern occurs in +$\\{hc}[(\|j+\T{1})\dotdot(\|j+\|k)]$, \TeX\ will set $\\{hyf}[\|j+\|i]\K\hbox{max}(\\{hyf}[\|j+\|i],\,\hbox{$n_i$})$ for +$\T{0}\Z\|i\Z\|k$. After this has been done for each pattern that occurs, a +discretionary hyphen will be inserted between \\{hc}[\|j] and $\\{hc}[\|j+\T{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 + +\M{920}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 $\T{1}\Z\|i\Z\|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$. + +Comparatively few different number sequences $n_0\ldots n_k$ actually occur, +since most of the \|n's are generally zero. Therefore the number sequences +are encoded in such a way that \\{trie\_op}$(z_k)$ is only one byte long. +If $\\{trie\_op}(\,\hbox{$z_k$})\I\\{min\_quarterword}$, when $p_1\ldots p_k$ has matched +the letters in $\\{hc}[(\|l-\|k+\T{1})\dotdot\|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\E\\{min\_quarterword}$. + +\Y\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{uint16\_t} \&{trie\_pointer};\C{an index into \\{trie}}\par +\fi + +\M{921}\B\D$\\{trie\_link}(\|X)$ \5 +$\\{trie}[\|X].{}$\\{rh}\C{``downward'' link in a trie}\par +\B\4\D$\\{trie\_char}(\|X)$ \5 +$\\{trie}[\|X].{}$\\{b1}\C{character matched at this trie location}\par +\B\4\D$\\{trie\_op}(\|X)$ \5 +$\\{trie}[\|X].{}$\\{b0}\C{program for hyphenation at this trie location}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{two\_halves} ${}\\{trie}[\\{trie\_size}+\T{1}]{}$;\C{\\{trie\_link}, \\{trie\_char}, \\{trie\_op}}\6 +\&{small\_number} \\{hyf\_distance0}[\\{trie\_op\_size}]${},{}$ ${}{*\&{const}\ }\\{hyf\_distance}\K\\{hyf\_distance0}-\T{1}{}$;\C{position $\|k-\|j$ of $n_j$}\6 +\&{small\_number} \\{hyf\_num0}[\\{trie\_op\_size}]${},{}$ ${}{*\&{const}\ }\\{hyf\_num}\K\\{hyf\_num0}-\T{1}{}$;\C{value of $n_j$}\6 +\&{quarterword} \\{hyf\_next0}[\\{trie\_op\_size}]${},{}$ ${}{*\&{const}\ }\\{hyf\_next}\K\\{hyf\_next0}-\T{1}{}$;\C{continuation code}\6 +\&{uint16\_t} \\{op\_start}[\T{256}];\C{offset for current language}\par +\fi + +\M{922}\B\X901:Local variables for hyphenation\X${}\mathrel+\E{}$\6 +\&{trie\_pointer} \|z;\C{an index into \\{trie}}\6 +\&{int} \|v;\C{an index into \\{hyf\_distance}, etc.}\par +\fi + +\M{923}Assuming that these auxiliary tables have been set up properly, the +hyphenation algorithm is quite short. In the following code we set $\\{hc}[\\{hn}+\T{2}]$ +to the impossible value 256, in order to guarantee that $\\{hc}[\\{hn}+\T{3}]$ will +never be fetched. + +\Y\B\4\X923:Find hyphen locations for the word in \\{hc}, or \&{return}\X${}\E{}$\6 +\&{for} ${}(\|j\K\T{0};{}$ ${}\|j\Z\\{hn};{}$ ${}\|j\PP){}$\1\5 +${}\\{hyf}[\|j]\K\T{0};{}$\2\6 +\X930:Look for the word \\{hc}[\T{1..}\\{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}+\T{1})\I\\{qi}(\\{cur\_lang})){}$\1\5 +\&{return};\C{no patterns for \\{cur\_lang}}\2\6 +${}\\{hc}[\T{0}]\K\T{0};{}$\5 +${}\\{hc}[\\{hn}+\T{1}]\K\T{0};{}$\5 +${}\\{hc}[\\{hn}+\T{2}]\K\T{256}{}$;\C{insert delimiters}\6 +\&{for} ${}(\|j\K\T{0};{}$ ${}\|j\Z\\{hn}-\\{r\_hyf}+\T{1};{}$ ${}\|j\PP){}$\5 +${}\{{}$\5 +\1${}\|z\K\\{trie\_link}(\\{cur\_lang}+\T{1})+\\{hc}[\|j];{}$\5 +${}\|l\K\|j;{}$\6 +\&{while} ${}(\\{hc}[\|l]\E\\{qo}(\\{trie\_char}(\|z))){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{trie\_op}(\|z)\I\\{min\_quarterword}){}$\1\5 +\X924:Store \(m)maximum values in the \\{hyf} table\X;\2\6 +\\{incr}(\|l);\5 +${}\|z\K\\{trie\_link}(\|z)+\\{hc}[\|l];{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4\\{found}:\6 +\&{for} ${}(\|j\K\T{0};{}$ ${}\|j\Z\\{l\_hyf}-\T{1};{}$ ${}\|j\PP){}$\1\5 +${}\\{hyf}[\|j]\K\T{0};{}$\2\6 +\&{for} ${}(\|j\K\T{0};{}$ ${}\|j\Z\\{r\_hyf}-\T{1};{}$ ${}\|j\PP)$ $\\{hyf}[\\{hn}-\|j]\K{}$\T{0}\par +\U895.\fi + +\M{924}\B\X924:Store \(m)maximum values in the \\{hyf} table\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|v\K\\{trie\_op}(\|z){}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|v\K\|v+\\{op\_start}[\\{cur\_lang}];{}$\5 +${}\|i\K\|l-\\{hyf\_distance}[\|v];{}$\6 +\&{if} ${}(\\{hyf\_num}[\|v]>\\{hyf}[\|i]){}$\1\5 +${}\\{hyf}[\|i]\K\\{hyf\_num}[\|v];{}$\2\6 +${}\|v\K\\{hyf\_next}[\|v];{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|v\E\\{min\_quarterword}));{}$\6 +\4${}\}{}$\2\par +\U923.\fi + +\M{925}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-\T{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. + +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\B\4\X18:Types in the outer block\X${}\mathrel+\E{}$\6 +\&{typedef} \&{uint16\_t} \&{hyph\_pointer};\C{an index into the ordered hash table}\par +\fi + +\M{926}\B\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{str\_number} ${}\\{hyph\_word}[\\{hyph\_size}+\T{1}]{}$;\C{exception words}\6 +\&{pointer} ${}\\{hyph\_list}[\\{hyph\_size}+\T{1}]{}$;\C{lists of hyphen positions}\6 +\&{hyph\_pointer} \\{hyph\_count};\C{the number of words in the exception dictionary}\par +\fi + +\M{927}\B\X19:Local variables for initialization\X${}\mathrel+\E{}$\6 +\&{hyph\_pointer} \|z;\C{runs through the exception dictionary}\par +\fi + +\M{928}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|z\K\T{0};{}$ ${}\|z\Z\\{hyph\_size};{}$ ${}\|z\PP){}$\5 +${}\{{}$\5 +\1${}\\{hyph\_word}[\|z]\K\T{0};{}$\5 +${}\\{hyph\_list}[\|z]\K\\{null};{}$\6 +\4${}\}{}$\2\6 +${}\\{hyph\_count}\K\T{0}{}$;\par +\fi + +\M{929}The algorithm for exception lookup is quite simple, as soon as we have +a few more local variables to work with. + +\Y\B\4\X901:Local variables for hyphenation\X${}\mathrel+\E{}$\6 +\&{hyph\_pointer} \|h;\C{an index into \\{hyph\_word} and \\{hyph\_list}}\6 +\&{str\_number} \|k;\C{an index into \\{str\_start}}\6 +\&{pool\_pointer} \|u;\C{an index into \\{str\_pool}}\par +\fi + +\M{930}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\B\4\X930:Look for the word \\{hc}[\T{1..}\\{hn}] in the exception table, and \&{goto} \\{found} (with \\{hyf} containing the hyphens) if an entry is found\X${}\E{}$\6 +$\|h\K\\{hc}[\T{1}];{}$\5 +\\{incr}(\\{hn});\5 +${}\\{hc}[\\{hn}]\K\\{cur\_lang};{}$\6 +\&{for} ${}(\|j\K\T{2};{}$ ${}\|j\Z\\{hn};{}$ ${}\|j\PP){}$\1\5 +${}\|h\K(\|h+\|h+\\{hc}[\|j])\MOD\\{hyph\_size};{}$\2\6 +\&{loop}\5 +${}\{{}$\5 +\1\X931:If the string \\{hyph\_word}[\|h] is less than \(hc)\\{hc}[\T{1..}\\{hn}], \&{goto} \\{not\_found}; but if the two strings are equal, set \\{hyf} to the hyphen positions and \&{goto} \\{found}\X;\6 +\&{if} ${}(\|h>\T{0}){}$\1\5 +\\{decr}(\|h);\5 +\2\&{else}\1\5 +${}\|h\K\\{hyph\_size};{}$\2\6 +\4${}\}{}$\2\6 +\\{not\_found}: \\{decr}(\\{hn})\par +\U923.\fi + +\M{931}\B\X931:If the string \\{hyph\_word}[\|h] is less than \(hc)\\{hc}[\T{1..}\\{hn}], \&{goto} \\{not\_found}; but if the two strings are equal, set \\{hyf} to the hyphen positions and \&{goto} \\{found}\X${}\E{}$\6 +$\|k\K\\{hyph\_word}[\|h];{}$\6 +\&{if} ${}(\|k\E\T{0}){}$\1\5 +\&{goto} \\{not\_found};\2\6 +\&{if} ${}(\\{length}(\|k)<\\{hn}){}$\1\5 +\&{goto} \\{not\_found};\2\6 +\&{if} ${}(\\{length}(\|k)\E\\{hn}){}$\5 +${}\{{}$\5 +\1${}\|j\K\T{1};{}$\5 +${}\|u\K\\{str\_start}[\|k]{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\&{if} ${}(\\{so}(\\{str\_pool}[\|u])<\\{hc}[\|j]){}$\1\5 +\&{goto} \\{not\_found};\2\6 +\&{if} ${}(\\{so}(\\{str\_pool}[\|u])>\\{hc}[\|j]){}$\1\5 +\&{goto} \\{done};\2\6 +\\{incr}(\|j);\5 +\\{incr}(\|u);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|j>\\{hn}));{}$\5 +\X932:Insert hyphens as specified in \\{hyph\_list}[\|h]\X;\6 +\\{decr}(\\{hn});\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\\{done}:\par +\U930.\fi + +\M{932}\B\X932:Insert hyphens as specified in \\{hyph\_list}[\|h]\X${}\E{}$\6 +$\|s\K\\{hyph\_list}[\|h];{}$\6 +\&{while} ${}(\|s\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{hyf}[\\{info}(\|s)]\K\T{1};{}$\5 +${}\|s\K\\{link}(\|s);{}$\6 +\4${}\}{}$\2\par +\U931.\fi + +\M{933}\B\X933:Search \\{hyph\_list} for pointers to \|p\X${}\E{}$\6 +\&{for} ${}(\|q\K\T{0};{}$ ${}\|q\Z\\{hyph\_size};{}$ ${}\|q\PP){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{hyph\_list}[\|q]\E\|p){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"HYPH("});\5 +\\{print\_int}(\|q);\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U172.\fi + +\M{934}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\B\4\D$\\{set\_cur\_lang}$ \6 +\&{if} ${}(\\{language}\Z\T{0}){}$\1\5 +${}\\{cur\_lang}\K\T{0};{}$\2\6 +\&{else} \&{if} ${}(\\{language}>\T{255}){}$\1\5 +${}\\{cur\_lang}\K\T{0};{}$\2\6 +\&{else} $\\{cur\_lang}\K{}$\\{language}\par +\Y\B\&{void} \\{new\_hyph\_exceptions}(\&{void})\C{enters new exceptions}\6 +${}\{{}$\5 +\1\&{uint8\_t} \|n;\C{length of current word; not always a \&{small\_number}}\6 +\&{int} \|j;\C{an index into \\{hc}}\6 +\&{hyph\_pointer} \|h;\C{an index into \\{hyph\_word} and \\{hyph\_list}}\6 +\&{str\_number} \|k;\C{an index into \\{str\_start}}\6 +\&{pointer} \|p;\C{head of a list of hyphen positions}\6 +\&{pointer} \|q;\C{used when creating a new node for list \|p}\6 +\&{str\_number} \|s${},{}$ \|t;\C{strings being compared or stored}\6 +\&{pool\_pointer} \|u${},{}$ \|v;\C{indices into \\{str\_pool}}\7 +\\{scan\_left\_brace}(\,);\C{a left brace must follow \.{\\hyphenation}}\6 +\\{set\_cur\_lang};\5 +\X935:Enter as many hyphenation exceptions as are listed, until coming to a right brace; then \&{return}\X;\6 +\4${}\}{}$\2\par +\fi + +\M{935}\B\X935:Enter as many hyphenation exceptions as are listed, until coming to a right brace; then \&{return}\X${}\E{}$\6 +$\|n\K\T{0};{}$\5 +${}\|p\K\\{null};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{get\_x\_token}(\,);\6 +\4\\{reswitch}:\6 +\&{switch} (\\{cur\_cmd})\5 +${}\{{}$\1\6 +\4\&{case} \\{letter}:\5 +\&{case} \\{other\_char}:\5 +\&{case} \\{char\_given}:\5 +\X937:Append a new letter or hyphen\X\5 +\&{break};\6 +\4\&{case} \\{char\_num}:\6 +${}\{{}$\5 +\1\\{scan\_char\_num}(\,);\5 +${}\\{cur\_chr}\K\\{cur\_val};{}$\5 +${}\\{cur\_cmd}\K\\{char\_given};{}$\5 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{spacer}:\5 +\&{case} \\{right\_brace}:\6 +${}\{{}$\5 +\1\&{if} ${}(\|n>\T{1}){}$\1\5 +\X939:Enter a hyphenation exception\X;\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{right\_brace}){}$\1\5 +\&{return};\2\6 +${}\|n\K\T{0};{}$\5 +${}\|p\K\\{null};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\5 +\X936:Give improper \.{\\hyphenation} error\X\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U934.\fi + +\M{936}\B\X936:Give improper \.{\\hyphenation} error\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Improper\ "});\5 +\\{print\_esc}(\X1683:\.{"hyphenation"}\X);\5 +\\{print\_str}(\.{"\ will\ be\ flushed"});\5 +\\{help2}(\.{"Hyphenation\ excepti}\)\.{ons\ must\ contain\ onl}\)\.{y\ letters"})\6 +(\.{"and\ hyphens.\ But\ co}\)\.{ntinue;\ I'll\ forgive}\)\.{\ and\ forget."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U935.\fi + +\M{937}\B\X937:Append a new letter or hyphen\X${}\E{}$\6 +\&{if} ${}(\\{cur\_chr}\E\.{'-'}){}$\1\5 +\X938:Append the value \|n to list \|p\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{lc\_code}(\\{cur\_chr})\E\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Not\ a\ letter"});\5 +\\{help2}(\.{"Letters\ in\ \\\\hyphen}\)\.{ation\ words\ must\ hav}\)\.{e\ \\\\lccode>0."})\6 +(\.{"Proceed;\ I'll\ ignor}\)\.{e\ the\ character\ I\ ju}\)\.{st\ read."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|n<\T{63}){}$\5 +${}\{{}$\5 +\1\\{incr}(\|n);\5 +${}\\{hc}[\|n]\K\\{lc\_code}(\\{cur\_chr});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U935.\fi + +\M{938}\B\X938:Append the value \|n to list \|p\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\|n<\T{63}){}$\5 +${}\{{}$\5 +\1${}\|q\K\\{get\_avail}(\,);{}$\5 +${}\\{link}(\|q)\K\|p;{}$\5 +${}\\{info}(\|q)\K\|n;{}$\5 +${}\|p\K\|q;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U937.\fi + +\M{939}\B\X939:Enter a hyphenation exception\X${}\E{}$\6 +${}\{{}$\5 +\1\\{incr}(\|n);\5 +${}\\{hc}[\|n]\K\\{cur\_lang};{}$\5 +\\{str\_room}(\|n);\5 +${}\|h\K\T{0};{}$\6 +\&{for} ${}(\|j\K\T{1};{}$ ${}\|j\Z\|n;{}$ ${}\|j\PP){}$\5 +${}\{{}$\5 +\1${}\|h\K(\|h+\|h+\\{hc}[\|j])\MOD\\{hyph\_size};{}$\5 +\\{append\_char}(\\{hc}[\|j]);\6 +\4${}\}{}$\2\6 +${}\|s\K\\{make\_string}(\,);{}$\5 +\X940:Insert the \(p)pair $(\|s,\|p)$ into the exception table\X;\6 +\4${}\}{}$\2\par +\U935.\fi + +\M{940}\B\X940:Insert the \(p)pair $(\|s,\|p)$ into the exception table\X${}\E{}$\6 +\&{if} ${}(\\{hyph\_count}\E\\{hyph\_size}){}$\1\5 +${}\\{overflow}(\.{"exception\ dictionar}\)\.{y"},\39\\{hyph\_size});{}$\2\6 +\\{incr}(\\{hyph\_count});\6 +\&{while} ${}(\\{hyph\_word}[\|h]\I\T{0}){}$\5 +${}\{{}$\5 +\1\X941: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} ${}(\|h>\T{0}){}$\1\5 +\\{decr}(\|h);\5 +\2\&{else}\1\5 +${}\|h\K\\{hyph\_size};{}$\2\6 +\4${}\}{}$\2\6 +${}\\{hyph\_word}[\|h]\K\|s;$ $\\{hyph\_list}[\|h]\K{}$\|p\par +\U939.\fi + +\M{941}\B\X941: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${}\E{}$\6 +$\|k\K\\{hyph\_word}[\|h];{}$\6 +\&{if} ${}(\\{length}(\|k)<\\{length}(\|s)){}$\1\5 +\&{goto} \\{found};\2\6 +\&{if} ${}(\\{length}(\|k)>\\{length}(\|s)){}$\1\5 +\&{goto} \\{not\_found};\2\6 +${}\|u\K\\{str\_start}[\|k];{}$\5 +${}\|v\K\\{str\_start}[\|s]{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\&{if} ${}(\\{str\_pool}[\|u]<\\{str\_pool}[\|v]){}$\1\5 +\&{goto} \\{found};\2\6 +\&{if} ${}(\\{str\_pool}[\|u]>\\{str\_pool}[\|v]){}$\1\5 +\&{goto} \\{not\_found};\2\6 +\\{incr}(\|u);\5 +\\{incr}(\|v);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|u\E\\{str\_start}[\|k+\T{1}]));{}$\6 +\4\\{found}:\5 +${}\|q\K\\{hyph\_list}[\|h];{}$\5 +${}\\{hyph\_list}[\|h]\K\|p;{}$\5 +${}\|p\K\|q{}$;\6 +${}\|t\K\\{hyph\_word}[\|h];{}$\5 +${}\\{hyph\_word}[\|h]\K\|s;{}$\5 +${}\|s\K\|t;$ \\{not\_found}:\par +\U940.\fi + +\N{1}{942}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\B\4\X826:Declare subprocedures for \\{line\_break}\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{INIT}\6 +\X944:Declare procedures for preprocessing hyphenation patterns\X\6 +\8\#\&{endif}\par +\fi + +\M{943}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]\E\T{3}$, $\\{hyf\_num}[\|v]\E\T{2}$, and \\{hyf\_next}[\|v] $\E\hbox{$v^\prime$}$, +where the auxiliary \\{trie\_op} code $v^\prime$ has +$\\{hyf\_distance}[\,\hbox{$v^\prime$}]\E\T{0}$, $\\{hyf\_num}[\,\hbox{$v^\prime$}]\E\T{1}$, and +$\\{hyf\_next}[\,\hbox{$v^\prime$}]\E\\{min\_quarterword}$. + +\TeX\ computes an appropriate value \|v with the \\{new\_trie\_op} subroutine +below, by setting +$$\hbox{$\hbox{$v^\prime$}\K$ $\\{new\_trie\_op}(\T{0},\T{1},\\{min\_quarterword})$,\qquad +$\|v\K\\{new\_trie\_op}(\T{3},\T{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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{INIT}\6 +\&{uint16\_t} ${}\\{trie\_op\_hash0}[\\{trie\_op\_size}+\\{trie\_op\_size}+\T{1}],{}$ ${}{*\&{const}\ }\\{trie\_op\_hash}\K\\{trie\_op\_hash0}+\\{trie\_op\_size}{}$;\C{trie op codes for quadruples}\6 +\&{quarterword} \\{trie\_used}[\T{256}];\C{largest opcode used so far for this language}\6 +\&{ASCII\_code} \\{trie\_op\_lang0}[\\{trie\_op\_size}]${},{}$ ${}{*\&{const}\ }\\{trie\_op\_lang}\K\\{trie\_op\_lang0}-\T{1}{}$;\C{language part of a hashed quadruple}\6 +\&{quarterword} \\{trie\_op\_val0}[\\{trie\_op\_size}]${},{}$ ${}{*\&{const}\ }\\{trie\_op\_val}\K\\{trie\_op\_val0}-\T{1}{}$;\C{opcode corresponding to a hashed quadruple}\6 +\&{uint16\_t} \\{trie\_op\_ptr};\C{number of stored ops so far}\6 +\8\#\&{endif}\par +\fi + +\M{944}It's tempting to remove the \\{overflow} stops in the following procedure; +\\{new\_trie\_op} could return \\{min\_quarterword} (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\B\4\X944:Declare procedures for preprocessing hyphenation patterns\X${}\E{}$\6 +\&{quarterword} \\{new\_trie\_op}(\&{small\_number} \|d${},\39{}$\&{small\_number} \|n${},\39{}$\&{quarterword} \|v)\1\1\2\2\6 +${}\{{}$\5 +\1\\{int16\_t}\|h;\C{trial hash location}\7 +\&{quarterword} \|u;\C{trial op code}\6 +\&{uint16\_t} \|l;\C{pointer to stored data}\7 +${}\|h\K\\{abs}(\|n+\T{313}*\|d+\T{361}*\|v+\T{1009}*\\{cur\_lang})\MOD(\\{trie\_op\_size}+\\{trie\_op\_size})-\\{trie\_op\_size};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1${}\|l\K\\{trie\_op\_hash}[\|h];{}$\6 +\&{if} ${}(\|l\E\T{0}{}$)\C{empty position found for a new op}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{trie\_op\_ptr}\E\\{trie\_op\_size}){}$\1\5 +${}\\{overflow}(\.{"pattern\ memory\ ops"},\39\\{trie\_op\_size});{}$\2\6 +${}\|u\K\\{trie\_used}[\\{cur\_lang}];{}$\6 +\&{if} ${}(\|u\E\\{max\_quarterword}){}$\1\5 +${}\\{overflow}(\.{"pattern\ memory\ ops\ }\)\.{per\ language"},\39\\{max\_quarterword}-\\{min\_quarterword});{}$\2\6 +\\{incr}(\\{trie\_op\_ptr});\5 +\\{incr}(\|u);\5 +${}\\{trie\_used}[\\{cur\_lang}]\K\|u;{}$\5 +${}\\{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 +\&{return} \|u;\6 +\4${}\}{}$\2\6 +\&{if} ${}((\\{hyf\_distance}[\|l]\E\|d)\W(\\{hyf\_num}[\|l]\E\|n)\W(\\{hyf\_next}[\|l]\E\|v)\W(\\{trie\_op\_lang}[\|l]\E\\{cur\_lang})){}$\5 +${}\{{}$\5 +\1\&{return} \\{trie\_op\_val}[\|l];\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|h>{-}\\{trie\_op\_size}){}$\1\5 +\\{decr}(\|h);\5 +\2\&{else}\1\5 +${}\|h\K\\{trie\_op\_size};{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\As948, 949, 953, 957, 959, 960\ETs966. +\U942.\fi + +\M{945}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\B\4\X945:Sort \(t)the hyphenation op tables into proper order\X${}\E{}$\6 +$\\{op\_start}[\T{0}]\K{-}\\{min\_quarterword};{}$\6 +\&{for} ${}(\|j\K\T{1};{}$ ${}\|j\Z\T{255};{}$ ${}\|j\PP){}$\1\5 +${}\\{op\_start}[\|j]\K\\{op\_start}[\|j-\T{1}]+\\{qo}(\\{trie\_used}[\|j-\T{1}]);{}$\2\6 +\&{for} ${}(\|j\K\T{1};{}$ ${}\|j\Z\\{trie\_op\_ptr};{}$ ${}\|j\PP){}$\1\5 +${}\\{trie\_op\_hash}[\|j]\K\\{op\_start}[\\{trie\_op\_lang}[\|j]]+\\{trie\_op\_val}[\|j]{}$;\C{destination}\2\6 +\&{for} ${}(\|j\K\T{1};{}$ ${}\|j\Z\\{trie\_op\_ptr};{}$ ${}\|j\PP){}$\1\6 +\&{while} ${}(\\{trie\_op\_hash}[\|j]>\|j){}$\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\2\par +\U952.\fi + +\M{946}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\B\4\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|k\K{-}\\{trie\_op\_size};{}$ ${}\|k\Z\\{trie\_op\_size};{}$ ${}\|k\PP){}$\1\5 +${}\\{trie\_op\_hash}[\|k]\K\T{0};{}$\2\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{255};{}$ ${}\|k\PP){}$\1\5 +${}\\{trie\_used}[\|k]\K\\{min\_quarterword};{}$\2\6 +${}\\{trie\_op\_ptr}\K\T{0}{}$;\par +\fi + +\M{947}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}[\T{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}[\T{0}] and \\{trie\_ptr} to zero. We also set \\{trie\_c}[\T{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\I\T{0}$ and $\\{trie\_r}[\|z]\I\T{0}$};$$ in other words, sibling nodes are +ordered by their \|c fields. + +\Y\B\4\D$\\{trie\_root}$ \5 +\\{trie\_l}[\T{0}]\C{root of the linked trie}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{INIT}\6 +\&{packed\_ASCII\_code} ${}\\{trie\_c}[\\{trie\_size}+\T{1}]{}$;\C{characters to match}\6 +\hbox{\hskip10pt}\&{quarterword} ${}\\{trie\_o}[\\{trie\_size}+\T{1}]{}$;\C{operations to perform}\6 +\hbox{\hskip10pt}\&{trie\_pointer} ${}\\{trie\_l}[\\{trie\_size}+\T{1}]{}$;\C{left subtrie links}\6 +\hbox{\hskip10pt}\&{trie\_pointer} ${}\\{trie\_r}[\\{trie\_size}+\T{1}]{}$;\C{right subtrie links}\6 +\hbox{\hskip10pt}\&{trie\_pointer} \\{trie\_ptr};\C{the number of nodes in the trie}\6 +\hbox{\hskip10pt}\&{trie\_pointer} ${}\\{trie\_hash}[\\{trie\_size}+\T{1}]{}$;\C{used to identify equivalent subtries}\6 +\8\#\&{endif}\par +\fi + +\M{948}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\B\4\X944:Declare procedures for preprocessing hyphenation patterns\X${}\mathrel+\E{}$\6 +\&{trie\_pointer} \\{trie\_node}(\&{trie\_pointer} \|p)\C{converts to a canonical form}\6 +${}\{{}$\5 +\1\&{trie\_pointer} \|h;\C{trial hash location}\6 +\&{trie\_pointer} \|q;\C{trial trie node}\7 +${}\|h\K\\{abs}(\\{trie\_c}[\|p]+\T{1009}*\\{trie\_o}[\|p]+\30\T{2718}*\\{trie\_l}[\|p]+\T{3142}*\\{trie\_r}[\|p])\MOD\\{trie\_size};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1${}\|q\K\\{trie\_hash}[\|h];{}$\6 +\&{if} ${}(\|q\E\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{trie\_hash}[\|h]\K\|p;{}$\5 +\&{return} \|p;\6 +\4${}\}{}$\2\6 +\&{if} ${}((\\{trie\_c}[\|q]\E\\{trie\_c}[\|p])\W(\\{trie\_o}[\|q]\E\\{trie\_o}[\|p])\W\30(\\{trie\_l}[\|q]\E\\{trie\_l}[\|p])\W(\\{trie\_r}[\|q]\E\\{trie\_r}[\|p])){}$\5 +${}\{{}$\5 +\1\&{return} \|q;\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|h>\T{0}){}$\1\5 +\\{decr}(\|h);\5 +\2\&{else}\1\5 +${}\|h\K\\{trie\_size};{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{949}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\B\4\X944:Declare procedures for preprocessing hyphenation patterns\X${}\mathrel+\E{}$\6 +\&{trie\_pointer} \\{compress\_trie}(\&{trie\_pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\|p\E\T{0}){}$\1\5 +\&{return} \T{0};\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{trie\_l}[\|p]\K\\{compress\_trie}(\\{trie\_l}[\|p]);{}$\5 +${}\\{trie\_r}[\|p]\K\\{compress\_trie}(\\{trie\_r}[\|p]);{}$\5 +\&{return} \\{trie\_node}(\|p);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{950}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}\E\T{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\B\4\D$\\{trie\_ref}$ \5 +\\{trie\_hash}\C{where linked trie families go into \\{trie}}\par +\B\4\D$\\{trie\_back}(\|X)$ \5 +$\\{trie}[\|X].{}$\\{lh}\C{backward links in \\{trie} holes}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{INIT}\6 +\&{bool} \\{trie\_taken0}[\\{trie\_size}]${},{}$ ${}{*\&{const}\ }\\{trie\_taken}\K\\{trie\_taken0}-\T{1}{}$;\C{does a family start here?}\6 +\hbox{\hskip10pt}\&{trie\_pointer} \\{trie\_min}[\T{256}];\C{the first possible slot for each character}\6 +\hbox{\hskip10pt}\&{trie\_pointer} \\{trie\_max};\C{largest location used in \\{trie}}\6 +\hbox{\hskip10pt}\&{bool} \\{trie\_not\_ready};\C{is the trie still in linked form?}\6 +\8\#\&{endif}\par +\fi + +\M{951}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\B\4\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\6 +$\\{trie\_not\_ready}\K\\{true};{}$\5 +${}\\{trie\_root}\K\T{0};{}$\5 +${}\\{trie\_c}[\T{0}]\K\\{si}(\T{0});{}$\5 +${}\\{trie\_ptr}\K\T{0}{}$;\par +\fi + +\M{952}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\B\4\X952:Get ready to compress the trie\X${}\E{}$\6 +\X945:Sort \(t)the hyphenation op tables into proper order\X;\6 +\&{for} ${}(\|p\K\T{0};{}$ ${}\|p\Z\\{trie\_size};{}$ ${}\|p\PP){}$\1\5 +${}\\{trie\_hash}[\|p]\K\T{0};{}$\2\6 +${}\\{trie\_root}\K\\{compress\_trie}(\\{trie\_root}){}$;\C{identify equivalent subtries}\6 +\&{for} ${}(\|p\K\T{0};{}$ ${}\|p\Z\\{trie\_ptr};{}$ ${}\|p\PP){}$\1\5 +${}\\{trie\_ref}[\|p]\K\T{0};{}$\2\6 +\&{for} ${}(\|p\K\T{0};{}$ ${}\|p\Z\T{255};{}$ ${}\|p\PP){}$\1\5 +${}\\{trie\_min}[\|p]\K\|p+\T{1};{}$\2\6 +${}\\{trie\_link}(\T{0})\K\T{1};$ $\\{trie\_max}\K{}$\T{0}\par +\U966.\fi + +\M{953}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\E\\{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\B\4\X944:Declare procedures for preprocessing hyphenation patterns\X${}\mathrel+\E{}$\6 +\&{void} \\{first\_fit}(\&{trie\_pointer} \|p)\C{packs a family into \\{trie}}\6 +${}\{{}$\5 +\1\&{trie\_pointer} \|h;\C{candidate for \\{trie\_ref}[\|p]}\6 +\&{trie\_pointer} \|z;\C{runs through holes}\6 +\&{trie\_pointer} \|q;\C{runs through the family starting at \|p}\6 +\&{ASCII\_code} \|c;\C{smallest character in the family}\6 +\&{trie\_pointer} \|l${},{}$ \|r;\C{left and right neighbors}\6 +\&{uint16\_t} \\{ll};\C{upper limit of \\{trie\_min} updating}\7 +${}\|c\K\\{so}(\\{trie\_c}[\|p]);{}$\5 +${}\|z\K\\{trie\_min}[\|c]{}$;\C{get the first conceivably good hole}\6 +\&{loop}\5 +${}\{{}$\5 +\1${}\|h\K\|z-\|c{}$;\6 +\X954:Ensure that $\\{trie\_max}\G\|h+\T{256}$\X;\6 +\&{if} (\\{trie\_taken}[\|h])\1\5 +\&{goto} \\{not\_found};\2\6 +\X955:If all characters of the family fit relative to \|h, then \&{goto} \\{found},\30\ otherwise \&{goto} \\{not\_found}\X;\6 +\4\\{not\_found}:\5 +${}\|z\K\\{trie\_link}(\|z){}$;\C{move to the next hole}\6 +\4${}\}{}$\2\6 +\4\\{found}:\5 +\X956:Pack the family into \\{trie} relative to \|h\X;\6 +\4${}\}{}$\2\par +\fi + +\M{954}By making sure that \\{trie\_max} is at least $\|h+\T{256}$, we can be sure that +$\\{trie\_max}>\|z$, since $\|h\E\|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\B\4\X954:Ensure that $\\{trie\_max}\G\|h+\T{256}$\X${}\E{}$\6 +\&{if} ${}(\\{trie\_max}<\|h+\T{256}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{trie\_size}\Z\|h+\T{256}){}$\1\5 +${}\\{overflow}(\.{"pattern\ memory"},\39\\{trie\_size}){}$;\2\6 +\&{do}\5 +${}\{{}$\1\6 +\\{incr}(\\{trie\_max});\5 +${}\\{trie\_taken}[\\{trie\_max}]\K\\{false};{}$\5 +${}\\{trie\_link}(\\{trie\_max})\K\\{trie\_max}+\T{1};{}$\5 +${}\\{trie\_back}(\\{trie\_max})\K\\{trie\_max}-\T{1};{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{trie\_max}\E\|h+\T{256}));{}$\6 +\4${}\}{}$\2\par +\U953.\fi + +\M{955}\B\X955:If all characters of the family fit relative to \|h, then \&{goto} \\{found},\30\ otherwise \&{goto} \\{not\_found}\X${}\E{}$\6 +$\|q\K\\{trie\_r}[\|p];{}$\6 +\&{while} ${}(\|q>\T{0}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{trie\_link}(\|h+\\{so}(\\{trie\_c}[\|q]))\E\T{0}){}$\1\5 +\&{goto} \\{not\_found};\2\6 +${}\|q\K\\{trie\_r}[\|q];{}$\6 +\4${}\}{}$\2\6 +\&{goto} \\{found}\par +\U953.\fi + +\M{956}\B\X956:Pack the family into \\{trie} relative to \|h\X${}\E{}$\6 +$\\{trie\_taken}[\|h]\K\\{true};{}$\5 +${}\\{trie\_ref}[\|p]\K\|h;{}$\5 +${}\|q\K\|p{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|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)\K\T{0};{}$\6 +\&{if} ${}(\|l<\T{256}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|z<\T{256}){}$\1\5 +${}\\{ll}\K\|z{}$;\5 +\2\&{else}\1\5 +${}\\{ll}\K\T{256}{}$;\2\6 +\&{do}\5 +${}\{{}$\1\6 +${}\\{trie\_min}[\|l]\K\|r;{}$\5 +\\{incr}(\|l);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|l\E\\{ll}));{}$\6 +\4${}\}{}$\2\6 +${}\|q\K\\{trie\_r}[\|q];{}$\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R(\|q\E\T{0}){}$)\par +\U953.\fi + +\M{957}To pack the entire linked trie, we use the following recursive procedure. + +\Y\B\4\X944:Declare procedures for preprocessing hyphenation patterns\X${}\mathrel+\E{}$\6 +\&{void} \\{trie\_pack}(\&{trie\_pointer} \|p)\C{pack subtries of a family}\6 +${}\{{}$\5 +\1\&{trie\_pointer} \|q;\C{a local variable that need not be saved on recursive calls}\7 +\&{do}\5 +${}\{{}$\1\6 +${}\|q\K\\{trie\_l}[\|p];{}$\6 +\&{if} ${}((\|q>\T{0})\W(\\{trie\_ref}[\|q]\E\T{0})){}$\5 +${}\{{}$\5 +\1\\{first\_fit}(\|q);\5 +\\{trie\_pack}(\|q);\6 +\4${}\}{}$\2\6 +${}\|p\K\\{trie\_r}[\|p];{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|p\E\T{0}));{}$\6 +\4${}\}{}$\2\par +\fi + +\M{958}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\B\4\X958:Move the data into \\{trie}\X${}\E{}$\6 +$\|h.\\{rh}\K\T{0};{}$\5 +${}\|h.\\{b0}\K\\{min\_quarterword};{}$\5 +${}\|h.\\{b1}\K\\{min\_quarterword}{}$;\C{$\\{trie\_link}\K\T{0}$, $\\{trie\_op}\K\\{min\_quarterword}$, $\\{trie\_char}\K\\{qi}(\T{0})$}\6 +\&{if} ${}(\\{trie\_root}\E\T{0}{}$)\C{no patterns were given}\6 +${}\{{}$\5 +\1\&{for} ${}(\|r\K\T{0};{}$ ${}\|r\Z\T{256};{}$ ${}\|r\PP){}$\1\5 +${}\\{trie}[\|r]\K\|h;{}$\2\6 +${}\\{trie\_max}\K\T{256};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{trie\_fix}(\\{trie\_root});\C{this fixes the non-holes in \\{trie}}\6 +${}\|r\K\T{0}{}$;\C{now we will zero out all the holes}\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|s\K\\{trie\_link}(\|r);{}$\5 +${}\\{trie}[\|r]\K\|h;{}$\5 +${}\|r\K\|s;{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|r>\\{trie\_max}));{}$\6 +\4${}\}{}$\2\6 +${}\\{trie\_char}(\T{0})\K\\{qi}(\.{'?'}){}$;\C{make $\\{trie\_char}(\|c)\I\|c$ for all \|c}\par +\U966.\fi + +\M{959}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\B\4\X944:Declare procedures for preprocessing hyphenation patterns\X${}\mathrel+\E{}$\6 +\&{void} \\{trie\_fix}(\&{trie\_pointer} \|p)\C{moves \|p and its siblings into \\{trie}}\6 +${}\{{}$\5 +\1\&{trie\_pointer} \|q;\C{a local variable that need not be saved on recursive calls}\6 +\&{ASCII\_code} \|c;\C{another one that need not be saved}\6 +\&{trie\_pointer} \|z;\C{\\{trie} reference; this local variable must be saved}\7 +${}\|z\K\\{trie\_ref}[\|p]{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|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>\T{0}){}$\1\5 +\\{trie\_fix}(\|q);\2\6 +${}\|p\K\\{trie\_r}[\|p];{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|p\E\T{0}));{}$\6 +\4${}\}{}$\2\par +\fi + +\M{960}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\B\4\X944:Declare procedures for preprocessing hyphenation patterns\X${}\mathrel+\E{}$\6 +\&{void} \\{new\_patterns}(\&{void})\C{initializes the hyphenation pattern data}\6 +${}\{{}$\5 +\1\&{uint8\_t} \|k${},{}$ \|l;\C{indices into \\{hc} and \\{hyf}; not always in \&{small\_number} range}\6 +\&{bool} \\{digit\_sensed};\C{should the next digit be treated as a letter?}\6 +\&{quarterword} \|v;\C{trie op code}\6 +\&{trie\_pointer} \|p${},{}$ \|q;\C{nodes of trie traversed during insertion}\6 +\&{bool} \\{first\_child};\C{is $\|p\E\\{trie\_l}[\|q]$?}\6 +\&{ASCII\_code} \|c;\C{character being inserted}\7 +\&{if} (\\{trie\_not\_ready})\5 +${}\{{}$\5 +\1\\{set\_cur\_lang};\5 +\\{scan\_left\_brace}(\,);\C{a left brace must follow \.{\\patterns}}\6 +\X961:Enter all of the patterns into a linked trie, until coming to a right brace\X;\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Too\ late\ for\ "});\5 +\\{print\_esc}(\X1684:\.{"patterns"}\X);\5 +\\{help1}(\.{"All\ patterns\ must\ b}\)\.{e\ given\ before\ types}\)\.{etting\ begins."});\6 +\&{error} (\,)\1\5 +;\2\6 +${}\\{link}(\\{garbage})\K\\{scan\_toks}(\\{false},\39\\{false});{}$\5 +\\{flush\_list}(\\{def\_ref});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{961}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\B\4\X961:Enter all of the patterns into a linked trie, until coming to a right brace\X${}\E{}$\6 +$\|k\K\T{0};{}$\5 +${}\\{hyf}[\T{0}]\K\T{0};{}$\5 +${}\\{digit\_sensed}\K\\{false};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\\{get\_x\_token}(\,);\6 +\&{switch} (\\{cur\_cmd})\5 +${}\{{}$\1\6 +\4\&{case} \\{letter}:\5 +\&{case} \\{other\_char}:\5 +\X962:Append a new letter or a hyphen level\X\5 +\&{break};\6 +\4\&{case} \\{spacer}:\5 +\&{case} \\{right\_brace}:\6 +${}\{{}$\5 +\1\&{if} ${}(\|k>\T{0}){}$\1\5 +\X963:Insert a new pattern into the linked trie\X;\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{right\_brace}){}$\1\5 +\&{goto} \\{done};\2\6 +${}\|k\K\T{0};{}$\5 +${}\\{hyf}[\T{0}]\K\T{0};{}$\5 +${}\\{digit\_sensed}\K\\{false};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Bad\ "});\5 +\\{print\_esc}(\X1684:\.{"patterns"}\X);\5 +\\{help1}(\.{"(See\ Appendix\ H.)"});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\\{done}:\par +\U960.\fi + +\M{962}\B\X962:Append a new letter or a hyphen level\X${}\E{}$\6 +\&{if} ${}(\\{digit\_sensed}\V(\\{cur\_chr}<\.{'0'})\V(\\{cur\_chr}>\.{'9'})){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_chr}\E\.{'.'}){}$\1\5 +${}\\{cur\_chr}\K\T{0}{}$;\C{edge-of-word delimiter}\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_chr}\K\\{lc\_code}(\\{cur\_chr});{}$\6 +\&{if} ${}(\\{cur\_chr}\E\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Nonletter"});\5 +\\{help1}(\.{"(See\ Appendix\ H.)"});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|k<\T{63}){}$\5 +${}\{{}$\5 +\1\\{incr}(\|k);\5 +${}\\{hc}[\|k]\K\\{cur\_chr};{}$\5 +${}\\{hyf}[\|k]\K\T{0};{}$\5 +${}\\{digit\_sensed}\K\\{false};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\|k<\T{63}){}$\5 +${}\{{}$\5 +\1${}\\{hyf}[\|k]\K\\{cur\_chr}-\.{'0'};{}$\5 +${}\\{digit\_sensed}\K\\{true};{}$\6 +\4${}\}{}$\2\par +\U961.\fi + +\M{963}When the following code comes into play, the pattern $p_1\ldots p_k$ +appears in $\\{hc}[\T{1}\dotdot\|k]$, and the corresponding sequence of numbers $n_0\ldots +n_k$ appears in $\\{hyf}[\T{0}\dotdot\|k]$. + +\Y\B\4\X963:Insert a new pattern into the linked trie\X${}\E{}$\6 +${}\{{}$\5 +\1\X965:Compute the trie op code, \|v, and set \|l: $\K$ \T{0}\X;\6 +${}\|q\K\T{0};{}$\5 +${}\\{hc}[\T{0}]\K\\{cur\_lang};{}$\6 +\&{while} ${}(\|l\Z\|k){}$\5 +${}\{{}$\5 +\1${}\|c\K\\{hc}[\|l];{}$\5 +\\{incr}(\|l);\5 +${}\|p\K\\{trie\_l}[\|q];{}$\5 +${}\\{first\_child}\K\\{true};{}$\6 +\&{while} ${}((\|p>\T{0})\W(\|c>\\{so}(\\{trie\_c}[\|p]))){}$\5 +${}\{{}$\5 +\1${}\|q\K\|p;{}$\5 +${}\|p\K\\{trie\_r}[\|q];{}$\5 +${}\\{first\_child}\K\\{false};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}((\|p\E\T{0})\V(\|c<\\{so}(\\{trie\_c}[\|p]))){}$\1\5 +\X964: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 +\4${}\}{}$\2\6 +\&{if} ${}(\\{trie\_o}[\|q]\I\\{min\_quarterword}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Duplicate\ pattern"});\5 +\\{help1}(\.{"(See\ Appendix\ H.)"});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +${}\\{trie\_o}[\|q]\K\|v;{}$\6 +\4${}\}{}$\2\par +\U961.\fi + +\M{964}\B\X964:Insert a new trie node between \|q and \|p, and make \|p point to it\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{trie\_ptr}\E\\{trie\_size}){}$\1\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]\K\T{0};{}$\6 +\&{if} (\\{first\_child})\1\5 +${}\\{trie\_l}[\|q]\K\|p{}$;\5 +\2\&{else}\1\5 +${}\\{trie\_r}[\|q]\K\|p;{}$\2\6 +${}\\{trie\_c}[\|p]\K\\{si}(\|c);{}$\5 +${}\\{trie\_o}[\|p]\K\\{min\_quarterword};{}$\6 +\4${}\}{}$\2\par +\U963.\fi + +\M{965}\B\X965:Compute the trie op code, \|v, and set \|l: $\K$ \T{0}\X${}\E{}$\6 +\&{if} ${}(\\{hc}[\T{1}]\E\T{0}){}$\1\5 +${}\\{hyf}[\T{0}]\K\T{0};{}$\2\6 +\&{if} ${}(\\{hc}[\|k]\E\T{0}){}$\1\5 +${}\\{hyf}[\|k]\K\T{0};{}$\2\6 +${}\|l\K\|k;{}$\5 +${}\|v\K\\{min\_quarterword};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{hyf}[\|l]\I\T{0}){}$\1\5 +${}\|v\K\\{new\_trie\_op}(\|k-\|l,\39\\{hyf}[\|l],\39\|v);{}$\2\6 +\&{if} ${}(\|l>\T{0}){}$\1\5 +\\{decr}(\|l);\5 +\2\&{else}\1\5 +\&{goto} \\{done1};\2\6 +\4${}\}{}$\2\6 +\\{done1}:\par +\U963.\fi + +\M{966}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\B\4\X944:Declare procedures for preprocessing hyphenation patterns\X${}\mathrel+\E{}$\6 +\&{void} \\{init\_trie}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{trie\_pointer} \|p;\C{pointer for initialization}\6 +\&{int} \|j${},{}$ \|k${},{}$ \|t;\C{all-purpose registers for initialization}\6 +\&{trie\_pointer} \|r${},{}$ \|s;\C{used to clean up the packed \\{trie}}\6 +\&{two\_halves} \|h;\C{template used to zero out \\{trie}'s holes}\7 +\X952:Get ready to compress the trie\X;\6 +\&{if} ${}(\\{trie\_root}\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{first\_fit}(\\{trie\_root});\5 +\\{trie\_pack}(\\{trie\_root});\6 +\4${}\}{}$\2\6 +\X958:Move the data into \\{trie}\X;\6 +${}\\{trie\_not\_ready}\K\\{false};{}$\6 +\4${}\}{}$\2\par +\fi + +\N{1}{967}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 + +\M{968}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\B\&{pointer} \\{prune\_page\_top}(\&{pointer} \|p)\C{adjust top after page break}\6 +${}\{{}$\5 +\1\&{pointer} \\{prev\_p};\C{lags one step behind \|p}\6 +\&{pointer} \|q;\C{temporary variable for list manipulation}\7 +${}\\{prev\_p}\K\\{temp\_head};{}$\5 +${}\\{link}(\\{temp\_head})\K\|p;{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\1\6 +\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\5 +\X969:Insert glue for \\{split\_top\_skip} and set~\|p: $\K$ \\{null}\X\5 +\&{break};\6 +\4\&{case} \\{whatsit\_node}:\5 +\&{case} \\{mark\_node}:\5 +\&{case} \\{ins\_node}:\6 +${}\{{}$\5 +\1${}\\{prev\_p}\K\|p;{}$\5 +${}\|p\K\\{link}(\\{prev\_p});{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{glue\_node}:\5 +\&{case} \\{kern\_node}:\5 +\&{case} \\{penalty\_node}:\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1685:\.{"pruning"}\X);\6 +\4${}\}{}$\2\2\6 +\&{return} \\{link}(\\{temp\_head});\6 +\4${}\}{}$\2\par +\fi + +\M{969}\B\X969:Insert glue for \\{split\_top\_skip} and set~\|p: $\K$ \\{null}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|q\K\\{new\_skip\_param}(\\{split\_top\_skip\_code});{}$\5 +${}\\{link}(\\{prev\_p})\K\|q;{}$\5 +${}\\{link}(\|q)\K\|p{}$;\C{now $\\{temp\_ptr}\E\\{glue\_ptr}(\|q)$}\6 +\&{if} ${}(\\{width}(\\{temp\_ptr})>\\{height}(\|p)){}$\1\5 +${}\\{width}(\\{temp\_ptr})\K\\{width}(\\{temp\_ptr})-\\{height}(\|p);{}$\2\6 +\&{else}\1\5 +${}\\{width}(\\{temp\_ptr})\K\T{0};{}$\2\6 +${}\|p\K\\{null};{}$\6 +\4${}\}{}$\2\par +\U968.\fi + +\M{970}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\B\4\D$\\{active\_height}$ \5 +\\{active\_width}\C{new name for the six distance variables}\par +\B\4\D$\\{cur\_height}$ \5 +\\{active\_height}[\T{1}]\C{the natural height}\par +\B\4\D$\\{set\_height\_zero}(\|X)$ \5 +$\\{active\_height}[\|X]\K{}$\T{0}\C{initialize the height to zero}\Y\par +\Y\B\&{pointer} \\{vert\_break}(\&{pointer} \|p${},\39{}$\&{scaled} \|h${},\39{}$\&{scaled} \|d)\C{finds optimum page break}\6 +${}\{{}$\5 +\1\&{pointer} \\{prev\_p};\C{if \|p is a glue node, \\{type}(\\{prev\_p}) determines whether \|p is a legal breakpoint}\6 +\&{pointer} \|q${},{}$ \|r;\C{glue specifications}\6 +\&{int} \\{pi};\C{penalty value}\6 +\&{int} \|b;\C{badness at a trial breakpoint}\6 +\&{int} \\{least\_cost};\C{the smallest badness plus penalties found so far}\6 +\&{pointer} \\{best\_place};\C{the most recent break that leads to \\{least\_cost}}\6 +\&{scaled} \\{prev\_dp};\C{depth of previous box in the list}\6 +\&{small\_number} \|t;\C{\\{type} of the node following a kern}\7 +${}\\{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}\K\T{0};{}$\6 +\&{loop}\5 +${}\{{}$\5 +\1\X972: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 +\4${}\}{}$\2\6 +\4\\{done}:\5 +\&{return} \\{best\_place};\6 +\4${}\}{}$\2\par +\fi + +\M{971}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{scaled} \\{best\_height\_plus\_depth};\C{height of the best box, without stretching or shrinking}\par +\fi + +\M{972}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\B\4\X972: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${}\E{}$\6 +\&{if} ${}(\|p\E\\{null}){}$\1\5 +${}\\{pi}\K\\{eject\_penalty};{}$\2\6 +\&{else}\1\5 +\X973: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 +\X974: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\5 +\&{goto} \\{not\_found};\2\6 +\4\\{update\_heights}:\5 +\X976:Update the current height and depth measurements with respect to a glue or kern node~\|p\X;\6 +\4\\{not\_found}:\6 +\&{if} ${}(\\{prev\_dp}>\|d){}$\5 +${}\{{}$\5 +\1${}\\{cur\_height}\K\\{cur\_height}+\\{prev\_dp}-\|d;{}$\5 +${}\\{prev\_dp}\K\|d;{}$\6 +\4${}\}{}$\2\par +\U970.\fi + +\M{973}\B\X973: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${}\E{}$\6 +\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\6 +${}\{{}$\5 +\1\hbox{}\6 +${}\\{cur\_height}\K\\{cur\_height}+\\{prev\_dp}+\\{height}(\|p);{}$\5 +${}\\{prev\_dp}\K\\{depth}(\|p);{}$\5 +\&{goto} \\{not\_found};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1365:Process whatsit \|p in \\{vert\_break} loop, \&{goto} \\{not\_found}\X;\6 +\4\&{case} \\{glue\_node}:\6 +\&{if} (\\{precedes\_break}(\\{prev\_p}))\1\5 +${}\\{pi}\K\T{0};{}$\2\6 +\&{else}\1\5 +\&{goto} \\{update\_heights};\5 +\2\&{break};\6 +\4\&{case} \\{kern\_node}:\6 +${}\{{}$\5 +\1\&{if} ${}(\\{link}(\|p)\E\\{null}){}$\1\5 +${}\|t\K\\{penalty\_node};{}$\2\6 +\&{else}\1\5 +${}\|t\K\\{type}(\\{link}(\|p));{}$\2\6 +\&{if} ${}(\|t\E\\{glue\_node}){}$\1\5 +${}\\{pi}\K\T{0}{}$;\5 +\2\&{else}\1\5 +\&{goto} \\{update\_heights};\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{penalty\_node}:\5 +${}\\{pi}\K\\{penalty}(\|p){}$;\5 +\&{break};\6 +\4\&{case} \\{mark\_node}:\5 +\&{case} \\{ins\_node}:\5 +\&{goto} \\{not\_found};\6 +\4\&{default}:\5 +\\{confusion}(\X1686:\.{"vertbreak"}\X);\6 +\4${}\}{}$\2\par +\U972.\fi + +\M{974}\B\D$\\{deplorable}$ \5 +\T{100000}\C{more than \\{inf\_bad}, but less than \\{awful\_bad}}\par +\Y\B\4\X974: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${}\E{}$\6 +\&{if} ${}(\\{pi}<\\{inf\_penalty}){}$\5 +${}\{{}$\5 +\1\X975:Compute the badness, \|b, using \\{awful\_bad} if the box is too full\X;\6 +\&{if} ${}(\|b<\\{awful\_bad}){}$\1\6 +\&{if} ${}(\\{pi}\Z\\{eject\_penalty}){}$\1\5 +${}\|b\K\\{pi};{}$\2\6 +\&{else} \&{if} ${}(\|b<\\{inf\_bad}){}$\1\5 +${}\|b\K\|b+\\{pi};{}$\2\6 +\&{else}\1\5 +${}\|b\K\\{deplorable};{}$\2\2\6 +\&{if} ${}(\|b\Z\\{least\_cost}){}$\5 +${}\{{}$\5 +\1${}\\{best\_place}\K\|p;{}$\5 +${}\\{least\_cost}\K\|b;{}$\5 +${}\\{best\_height\_plus\_depth}\K\\{cur\_height}+\\{prev\_dp};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}((\|b\E\\{awful\_bad})\V(\\{pi}\Z\\{eject\_penalty})){}$\1\5 +\&{goto} \\{done};\2\6 +\4${}\}{}$\2\par +\U972.\fi + +\M{975}\B\X975:Compute the badness, \|b, using \\{awful\_bad} if the box is too full\X${}\E{}$\6 +\&{if} ${}(\\{cur\_height}<\|h){}$\1\6 +\&{if} ${}((\\{active\_height}[\T{3}]\I\T{0})\V(\\{active\_height}[\T{4}]\I\T{0})\V(\\{active\_height}[\T{5}]\I\T{0})){}$\1\5 +${}\|b\K\T{0};{}$\2\6 +\&{else}\1\5 +${}\|b\K\\{badness}(\|h-\\{cur\_height},\39\\{active\_height}[\T{2}]);{}$\2\2\6 +\&{else} \&{if} ${}(\\{cur\_height}-\|h>\\{active\_height}[\T{6}]){}$\1\5 +${}\|b\K\\{awful\_bad};{}$\2\6 +\&{else} $\|b\K\\{badness}(\\{cur\_height}-\|h,\39\\{active\_height}[\T{6}]{}$)\par +\U974.\fi + +\M{976}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\B\4\X976:Update the current height and depth measurements with respect to a glue or kern node~\|p\X${}\E{}$\6 +\&{if} ${}(\\{type}(\|p)\E\\{kern\_node}){}$\1\5 +${}\|q\K\|p;{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{glue\_ptr}(\|p);{}$\5 +${}\\{active\_height}[\T{2}+\\{stretch\_order}(\|q)]\K\30\\{active\_height}[\T{2}+\\{stretch\_order}(\|q)]+\\{stretch}(\|q){}$;\6 +${}\\{active\_height}[\T{6}]\K\\{active\_height}[\T{6}]+\\{shrink}(\|q);{}$\6 +\&{if} ${}((\\{shrink\_order}(\|q)\I\\{normal})\W(\\{shrink}(\|q)\I\T{0})){}$\5 +${}\{{}$\5 +\1\hbox{}\6 +\\{print\_err}(\.{"Infinite\ glue\ shrin}\)\.{kage\ found\ in\ box\ be}\)\.{ing\ split"});\6 +\\{help4}(\.{"The\ box\ you\ are\ \\\\v}\)\.{splitting\ contains\ s}\)\.{ome\ infinitely"})\6 +(\.{"shrinkable\ glue,\ e.}\)\.{g.,\ `\\\\vss'\ or\ `\\\\vs}\)\.{kip\ 0pt\ minus\ 1fil'.}\)\.{"})\6 +(\.{"Such\ glue\ doesn't\ b}\)\.{elong\ there;\ but\ you}\)\.{\ can\ safely\ proceed,}\)\.{"})\6 +(\.{"since\ the\ offensive}\)\.{\ shrinkability\ has\ b}\)\.{een\ made\ finite."});\6 +\&{error} (\,)\1\5 +;\2\6 +${}\|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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +${}\\{cur\_height}\K\\{cur\_height}+\\{prev\_dp}+\\{width}(\|q);$ $\\{prev\_dp}\K{}$\T{0}\par +\U972.\fi + +\M{977}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}\E\\{null}$ if and only if $\\{split\_bot\_mark}\E\\{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\B\&{pointer} \\{vsplit}(\&{eight\_bits} \|n${},\39{}$\&{scaled} \|h)\C{extracts a page of height \|h from box \|n}\6 +${}\{{}$\5 +\1\&{pointer} \|v;\C{the box to be split}\6 +\&{pointer} \|p;\C{runs through the vlist}\6 +\&{pointer} \|q;\C{points to where the break occurs}\7 +${}\|v\K\\{box}(\|n);{}$\6 +\&{if} ${}(\\{split\_first\_mark}\I\\{null}){}$\5 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\6 +\X978: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 +\X979: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);{}$\5 +${}\\{free\_node}(\|v,\39\\{box\_node\_size});{}$\6 +\&{if} ${}(\|q\E\\{null}){}$\1\5 +${}\\{box}(\|n)\K\\{null}{}$;\C{the \\{eq\_level} of the box stays the same}\2\6 +\&{else}\1\5 +${}\\{box}(\|n)\K\\{vpack}(\|q,\39\\{natural});{}$\2\6 +\&{return} \\{vpackage}${}(\|p,\39\|h,\39\\{exactly},\39\\{split\_max\_depth});{}$\6 +\4${}\}{}$\2\par +\fi + +\M{978}\B\X978:Dispense with trivial cases of void or bad boxes\X${}\E{}$\6 +\&{if} ${}(\|v\E\\{null}){}$\5 +${}\{{}$\5 +\1\&{return} \\{null};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{type}(\|v)\I\\{vlist\_node}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{""});\5 +\\{print\_esc}(\X1687:\.{"vsplit"}\X);\5 +\\{print\_str}(\.{"\ needs\ a\ "});\5 +\\{print\_esc}(\X1688:\.{"vbox"}\X);\5 +\\{help2}(\.{"The\ box\ you\ are\ try}\)\.{ing\ to\ split\ is\ an\ \\}\)\.{\\hbox."})\6 +(\.{"I\ can't\ split\ such\ }\)\.{a\ box,\ so\ I'll\ leave}\)\.{\ it\ alone."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{return} \\{null};\6 +\4${}\}{}$\2\par +\U977.\fi + +\M{979}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\B\4\X979:Look at all the marks in nodes before the break, and set the final link to \\{null} at the break\X${}\E{}$\6 +$\|p\K\\{list\_ptr}(\|v);{}$\6 +\&{if} ${}(\|p\E\|q){}$\1\5 +${}\\{list\_ptr}(\|v)\K\\{null};{}$\2\6 +\&{else}\1\6 +\&{loop}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{type}(\|p)\E\\{mark\_node}){}$\1\6 +\&{if} ${}(\\{split\_first\_mark}\E\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{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})+\T{2};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{delete\_token\_ref}(\\{split\_bot\_mark});\5 +${}\\{split\_bot\_mark}\K\\{mark\_ptr}(\|p);{}$\5 +\\{add\_token\_ref}(\\{split\_bot\_mark});\6 +\4${}\}{}$\2\2\6 +\&{if} ${}(\\{link}(\|p)\E\|q){}$\5 +${}\{{}$\5 +\1${}\\{link}(\|p)\K\\{null};{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\2\6 +\\{done}:\par +\U977.\fi + +\N{1}{980}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}\E\\{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\B\4\D$\\{inserts\_only}$ \5 +\T{1}\C{\\{page\_contents} when an insert node has been contributed, but no boxes}\par +\B\4\D$\\{box\_there}$ \5 +\T{2}\C{\\{page\_contents} when a box or rule has been contributed}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{page\_tail};\C{the final node on the current page}\6 +\&{uint8\_t} \\{page\_contents};\C{what is on the current page so far?}\6 +\&{scaled} \\{page\_max\_depth};\C{maximum box depth on page being built}\6 +\&{pointer} \\{best\_page\_break};\C{break here to get the best page known so far}\6 +\&{int} \\{least\_page\_cost};\C{the score for this currently best page}\6 +\&{scaled} \\{best\_size};\C{its \\{page\_goal}}\par +\fi + +\M{981}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$}\E\\{link}(\\{page\_ins\_head})$; +node $r_j$ is followed by $\|r\hbox{$_{j+1}$}\E\\{link}(\|r\hbox{$_j$})$; and if there are +\|n items we have $\|r\hbox{$_{n+1}$}\E\\{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}(\T{250}) +(the same as the \\{subtype} field of the relevant \\{ins\_node}). These \\{subtype} +fields are in increasing order, and $\\{subtype}(\\{page\_ins\_head})\E\\{qi}(\T{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)\E\\{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)\E\\{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)\E\\{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\B\4\D$\\{page\_ins\_node\_size}$ \5 +\T{4}\C{number of words for a page insertion node}\par +\B\4\D$\\{inserting}$ \5 +\T{0}\C{an insertion class that has not yet overflowed}\par +\B\4\D$\\{split\_up}$ \5 +\T{1}\C{an overflowed insertion class}\par +\B\4\D$\\{broken\_ptr}(\|X)$ \5 +$\\{link}(\|X+\T{1}{}$)\C{an insertion for this class will break here if anywhere}\par +\B\4\D$\\{broken\_ins}(\|X)$ \5 +$\\{info}(\|X+\T{1}{}$)\C{this insertion might break at \\{broken\_ptr}}\par +\B\4\D$\\{last\_ins\_ptr}(\|X)$ \5 +$\\{link}(\|X+\T{2}{}$)\C{the most recent insertion for this \\{subtype}}\par +\B\4\D$\\{best\_ins\_ptr}(\|X)$ \5 +$\\{info}(\|X+\T{2}{}$)\C{the optimum most recent insertion}\par +\Y\B\4\X790:Initialize the special list heads and constant nodes\X${}\mathrel+\E{}$\6 +$\\{subtype}(\\{page\_ins\_head})\K\\{qi}(\T{255});{}$\5 +${}\\{type}(\\{page\_ins\_head})\K\\{split\_up};{}$\5 +${}\\{link}(\\{page\_ins\_head})\K\\{page\_ins\_head}{}$;\par +\fi + +\M{982}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}[\T{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}\E\\{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\B\4\D$\\{page\_goal}$ \5 +\\{page\_so\_far}[\T{0}]\C{desired height of information on page being built}\par +\B\4\D$\\{page\_total}$ \5 +\\{page\_so\_far}[\T{1}]\C{height of the current page}\par +\B\4\D$\\{page\_shrink}$ \5 +\\{page\_so\_far}[\T{6}]\C{shrinkability of the current page}\par +\B\4\D$\\{page\_depth}$ \5 +\\{page\_so\_far}[\T{7}]\C{depth of the current page}\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{scaled} \\{page\_so\_far}[\T{8}];\C{height and glue of the current page}\6 +\&{pointer} \\{last\_glue};\C{used to implement \.{\\lastskip}}\6 +\&{int} \\{last\_penalty};\C{used to implement \.{\\lastpenalty}}\6 +\&{scaled} \\{last\_kern};\C{used to implement \.{\\lastkern}}\6 +\&{int} \\{insert\_penalties};\C{sum of the penalties for held-over insertions}\par +\fi + +\M{983}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1689:\.{"pagegoal"}\X,\39\\{set\_page\_dimen},\39\T{0});{}$\5 +${}\\{primitive}(\X1690:\.{"pagetotal"}\X,\39\\{set\_page\_dimen},\39\T{1});{}$\5 +${}\\{primitive}(\X1691:\.{"pagestretch"}\X,\39\\{set\_page\_dimen},\39\T{2});{}$\5 +${}\\{primitive}(\X1692:\.{"pagefilstretch"}\X,\39\\{set\_page\_dimen},\39\T{3});{}$\5 +${}\\{primitive}(\X1693:\.{"pagefillstretch"}\X,\39\\{set\_page\_dimen},\39\T{4});{}$\5 +${}\\{primitive}(\X1694:\.{"pagefilllstretch"}\X,\39\\{set\_page\_dimen},\39\T{5});{}$\5 +${}\\{primitive}(\X1695:\.{"pageshrink"}\X,\39\\{set\_page\_dimen},\39\T{6});{}$\5 +${}\\{primitive}(\X1696:\.{"pagedepth"}\X,\39\\{set\_page\_dimen},\39\T{7}){}$;\par +\fi + +\M{984}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{set\_page\_dimen}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \T{0}:\5 +\\{print\_esc}(\X1689:\.{"pagegoal"}\X);\5 +\&{break};\6 +\4\&{case} \T{1}:\5 +\\{print\_esc}(\X1690:\.{"pagetotal"}\X);\5 +\&{break};\6 +\4\&{case} \T{2}:\5 +\\{print\_esc}(\X1691:\.{"pagestretch"}\X);\5 +\&{break};\6 +\4\&{case} \T{3}:\5 +\\{print\_esc}(\X1692:\.{"pagefilstretch"}\X);\5 +\&{break};\6 +\4\&{case} \T{4}:\5 +\\{print\_esc}(\X1693:\.{"pagefillstretch"}\X);\5 +\&{break};\6 +\4\&{case} \T{5}:\5 +\\{print\_esc}(\X1694:\.{"pagefilllstretch"}\X);\5 +\&{break};\6 +\4\&{case} \T{6}:\5 +\\{print\_esc}(\X1695:\.{"pageshrink"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1696:\.{"pagedepth"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{985}\B\D$\\{print\_plus\_end}(\|X)$ \5 +\\{print\_str}(\|X);\5 +$\}{}$\par +\B\4\D$\\{print\_plus}(\|X)$ \5 +\&{if} ${}(\\{page\_so\_far}[\|X]\I\T{0})$ $\{{}$\5 +\\{print\_str}(\.{"\ plus\ "});\5 +\\{print\_scaled}(\\{page\_so\_far}[\|X]); \\{print\_plus\_end}\par +\Y\B\&{void} \\{print\_totals}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_scaled}(\\{page\_total});\5 +\\{print\_plus}(\T{2})(\.{""});\5 +\\{print\_plus}(\T{3})(\.{"fil"});\5 +\\{print\_plus}(\T{4})(\.{"fill"});\5 +\\{print\_plus}(\T{5})(\.{"filll"});\6 +\&{if} ${}(\\{page\_shrink}\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ minus\ "});\5 +\\{print\_scaled}(\\{page\_shrink});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{986}\B\X986:Show the status of the current page\X${}\E{}$\6 +\&{if} ${}(\\{page\_head}\I\\{page\_tail}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"\#\#\#\ current\ page:"});\6 +\&{if} (\\{output\_active})\1\5 +\\{print\_str}(\.{"\ (held\ over\ for\ nex}\)\.{t\ output)"});\2\6 +\\{show\_box}(\\{link}(\\{page\_head}));\6 +\&{if} ${}(\\{page\_contents}>\\{empty}){}$\5 +${}\{{}$\5 +\1\\{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}){}$\5 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +\\{print\_esc}(\X1390:\.{"insert"}\X);\5 +${}\|t\K\\{qo}(\\{subtype}(\|r));{}$\5 +\\{print\_int}(\|t);\5 +\\{print\_str}(\.{"\ adds\ "});\6 +\&{if} ${}(\\{count}(\|t)\E\T{1000}){}$\1\5 +${}\|t\K\\{height}(\|r);{}$\2\6 +\&{else}\1\5 +${}\|t\K\\{x\_over\_n}(\\{height}(\|r),\39\T{1000})*\\{count}(\|t);{}$\2\6 +\\{print\_scaled}(\|t);\6 +\&{if} ${}(\\{type}(\|r)\E\\{split\_up}){}$\5 +${}\{{}$\5 +\1${}\|q\K\\{page\_head};{}$\5 +${}\|t\K\T{0}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|q\K\\{link}(\|q);{}$\6 +\&{if} ${}((\\{type}(\|q)\E\\{ins\_node})\W(\\{subtype}(\|q)\E\\{subtype}(\|r))){}$\1\5 +\\{incr}(\|t);\2\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|q\E\\{broken\_ins}(\|r)));{}$\5 +\\{print\_str}(\.{",\ \#"});\5 +\\{print\_int}(\|t);\5 +\\{print\_str}(\.{"\ might\ split"});\6 +\4${}\}{}$\2\6 +${}\|r\K\\{link}(\|r);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U218.\fi + +\M{987}Here is a procedure that is called when the \\{page\_contents} is changing +from \\{empty} to \\{inserts\_only} or \\{box\_there}. + +\Y\B\4\D$\\{set\_page\_so\_far\_zero}(\|X)$ \5 +$\\{page\_so\_far}[\|X]\K{}$\T{0}\par +\Y\B\&{void} \\{freeze\_page\_specs}(\&{small\_number} \|s)\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{page\_contents}\K\|s;{}$\5 +${}\\{page\_goal}\K\\{vsize};{}$\5 +${}\\{page\_max\_depth}\K\\{max\_depth};{}$\5 +${}\\{page\_depth}\K\T{0};{}$\5 +\\{do\_all\_six}(\\{set\_page\_so\_far\_zero});\5 +${}\\{least\_page\_cost}\K\\{awful\_bad};{}$\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_pages}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{"\%\%\ goal\ height="});\5 +\\{print\_scaled}(\\{page\_goal});\5 +\\{print\_str}(\.{",\ max\ depth="});\5 +\\{print\_scaled}(\\{page\_max\_depth});\5 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\6 +\4${}\}{}$\2\par +\fi + +\M{988}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})\E\\{glue\_node}$, so that an initial glue node on +the current page will not be considered a valid breakpoint. + +\Y\B\4\X790:Initialize the special list heads and constant nodes\X${}\mathrel+\E{}$\6 +$\\{type}(\\{page\_head})\K\\{glue\_node};{}$\5 +${}\\{subtype}(\\{page\_head})\K\\{normal}{}$;\par +\fi + +\M{989}The global variable \\{output\_active} is true during the time the +user's output routine is driving \TeX. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{bool} \\{output\_active};\C{are we in the midst of an output routine?}\par +\fi + +\M{990}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{output\_active}\K\\{false};{}$\5 +${}\\{insert\_penalties}\K\T{0}{}$;\par +\fi + +\M{991}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\B\4\X991:Start a new current page\X${}\E{}$\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}\K\T{0};{}$\5 +${}\\{last\_kern}\K\T{0};{}$\5 +${}\\{page\_depth}\K\T{0};$ $\\{page\_max\_depth}\K{}$\T{0}\par +\Us215\ET1017.\fi + +\M{992}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\B\&{void} \\{box\_error}(\&{eight\_bits} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\&{error} (\,)\1\5 +;\2\6 +\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{"The\ following\ box\ h}\)\.{as\ been\ deleted:"});\5 +\\{show\_box}(\\{box}(\|n));\5 +\\{end\_diagnostic}(\\{true});\5 +\\{flush\_node\_list}(\\{box}(\|n));\5 +${}\\{box}(\|n)\K\\{null};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{993}The following procedure guarantees that a given box register +does not contain an \.{\\hbox}. + +\Y\B\&{void} \\{ensure\_vbox}(\&{eight\_bits} \|n)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the box register contents}\7 +${}\|p\K\\{box}(\|n);{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\1\6 +\&{if} ${}(\\{type}(\|p)\E\\{hlist\_node}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Insertions\ can\ only}\)\.{\ be\ added\ to\ a\ vbox"});\5 +\\{help3}(\.{"Tut\ tut:\ You're\ try}\)\.{ing\ to\ \\\\insert\ into}\)\.{\ a"})\6 +(\.{"\\\\box\ register\ that}\)\.{\ now\ contains\ an\ \\\\h}\)\.{box."})\6 +(\.{"Proceed,\ and\ I'll\ d}\)\.{iscard\ its\ present\ c}\)\.{ontents."});\5 +\\{box\_error}(\|n);\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\par +\fi + +\M{994}\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\B\hbox{\4}\X1012:Declare the procedure called \\{fire\_up}\X\7 +\&{void} \\{build\_page}(\&{void})\C{append contributions to the current page}\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the node being appended}\6 +\&{pointer} \|q${},{}$ \|r;\C{nodes being examined}\6 +\&{int} \|b${},{}$ \|c;\C{badness and cost of current page}\6 +\&{int} \\{pi};\C{penalty to be added to the badness}\6 +\&{uint8\_t} \|n;\C{insertion box number}\6 +\&{scaled} \\{delta}${},{}$ \|h${},{}$ \|w;\C{sizes used for insertion calculations}\7 +\&{if} ${}((\\{link}(\\{contrib\_head})\E\\{null})\V\\{output\_active}){}$\1\5 +\&{return};\2\6 +\&{do}\5 +${}\{{}$\1\6 +\4\\{resume}:\5 +${}\|p\K\\{link}(\\{contrib\_head}){}$;\6 +\X996:Update the values of \\{last\_glue}, \\{last\_penalty}, and \\{last\_kern}\X;\6 +\X997: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${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{link}(\\{contrib\_head})\E\\{null}));{}$\5 +\X995:Make the contribution list empty by setting its tail to \\{contrib\_head}\X;\6 +\4${}\}{}$\2\par +\fi + +\M{995}\B\D$\\{contrib\_tail}$ \5 +$\\{nest}[\T{0}].{}$\\{tail\_field}\C{tail of the contribution list}\par +\Y\B\4\X995:Make the contribution list empty by setting its tail to \\{contrib\_head}\X${}\E{}$\6 +\&{if} ${}(\\{nest\_ptr}\E\T{0}){}$\1\5 +${}\\{tail}\K\\{contrib\_head}{}$;\C{vertical mode}\2\6 +\&{else} $\\{contrib\_tail}\K{}$\\{contrib\_head}\C{other modes}\par +\U994.\fi + +\M{996}\B\X996:Update the values of \\{last\_glue}, \\{last\_penalty}, and \\{last\_kern}\X${}\E{}$\6 +\&{if} ${}(\\{last\_glue}\I\\{max\_halfword}){}$\1\5 +\\{delete\_glue\_ref}(\\{last\_glue});\2\6 +${}\\{last\_penalty}\K\T{0};{}$\5 +${}\\{last\_kern}\K\T{0};{}$\6 +\&{if} ${}(\\{type}(\|p)\E\\{glue\_node}){}$\5 +${}\{{}$\5 +\1${}\\{last\_glue}\K\\{glue\_ptr}(\|p);{}$\5 +\\{add\_glue\_ref}(\\{last\_glue});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{last\_glue}\K\\{max\_halfword};{}$\6 +\&{if} ${}(\\{type}(\|p)\E\\{penalty\_node}){}$\1\5 +${}\\{last\_penalty}\K\\{penalty}(\|p);{}$\2\6 +\&{else} \&{if} ${}(\\{type}(\|p)\E\\{kern\_node}){}$\1\5 +${}\\{last\_kern}\K\\{width}(\|p);{}$\2\6 +\4${}\}{}$\2\par +\U994.\fi + +\M{997}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\B\4\X997: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${}\E{}$\6 +\X1000: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 +\X1005: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\5 +\&{goto} \\{contribute};\2\6 +\4\\{update\_heights}:\5 +\X1004:Update the current page measurements with respect to the glue or kern specified by node~\|p\X;\6 +\4\\{contribute}:\5 +\X1003:Make sure that \\{page\_max\_depth} is not exceeded\X;\6 +\X998:Link node \|p into the current page and \&{goto} \\{done}\X;\6 +\4\\{done1}:\5 +\X999:Recycle node \|p\X;\6 +\\{done}:\par +\U994.\fi + +\M{998}\B\X998:Link node \|p into the current page and \&{goto} \\{done}\X${}\E{}$\6 +$\\{link}(\\{page\_tail})\K\|p;{}$\5 +${}\\{page\_tail}\K\|p;{}$\5 +${}\\{link}(\\{contrib\_head})\K\\{link}(\|p);{}$\5 +${}\\{link}(\|p)\K\\{null};$ \&{goto} \\{done}\par +\U997.\fi + +\M{999}\B\X999:Recycle node \|p\X${}\E{}$\6 +$\\{link}(\\{contrib\_head})\K\\{link}(\|p);{}$\5 +${}\\{link}(\|p)\K\\{null};$ \\{flush\_node\_list}(\|p)\par +\U997.\fi + +\M{1000}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\B\4\X1000: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${}\E{}$\6 +\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\6 +\&{if} ${}(\\{page\_contents}<\\{box\_there}){}$\1\5 +\X1001:Initialize the current page, insert the \.{\\topskip} glue ahead of \|p, and \&{goto} \&{continue}\X\2\6 +\&{else}\1\5 +\X1002:Prepare to move a box or rule node to the current page, then \&{goto} \\{contribute}\X\5 +\2\&{break};\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1364:Prepare to move whatsit \|p to the current page, then \&{goto} \\{contribute}\X;\6 +\4\&{case} \\{glue\_node}:\6 +\&{if} ${}(\\{page\_contents}<\\{box\_there}){}$\1\5 +\&{goto} \\{done1};\2\6 +\&{else} \&{if} (\\{precedes\_break}(\\{page\_tail}))\1\5 +${}\\{pi}\K\T{0};{}$\2\6 +\&{else}\1\5 +\&{goto} \\{update\_heights};\5 +\2\&{break};\6 +\4\&{case} \\{kern\_node}:\6 +\&{if} ${}(\\{page\_contents}<\\{box\_there}){}$\1\5 +\&{goto} \\{done1};\2\6 +\&{else} \&{if} ${}(\\{link}(\|p)\E\\{null}){}$\1\5 +\&{return};\2\6 +\&{else} \&{if} ${}(\\{type}(\\{link}(\|p))\E\\{glue\_node}){}$\1\5 +${}\\{pi}\K\T{0};{}$\2\6 +\&{else}\1\5 +\&{goto} \\{update\_heights};\5 +\2\&{break};\6 +\4\&{case} \\{penalty\_node}:\6 +\&{if} ${}(\\{page\_contents}<\\{box\_there}){}$\1\5 +\&{goto} \\{done1};\5 +\2\&{else}\1\5 +${}\\{pi}\K\\{penalty}(\|p){}$;\5 +\2\&{break};\6 +\4\&{case} \\{mark\_node}:\5 +\&{goto} \\{contribute};\6 +\4\&{case} \\{ins\_node}:\5 +\X1008:Append an insertion to the current page and \&{goto} \\{contribute}\X\6 +\4\&{default}:\5 +\\{confusion}(\X1697:\.{"page"}\X);\6 +\4${}\}{}$\2\par +\U997.\fi + +\M{1001}\B\X1001:Initialize the current page, insert the \.{\\topskip} glue ahead of \|p, and \&{goto} \&{continue}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{page\_contents}\E\\{empty}){}$\1\5 +\\{freeze\_page\_specs}(\\{box\_there});\2\6 +\&{else}\1\5 +${}\\{page\_contents}\K\\{box\_there};{}$\2\6 +${}\|q\K\\{new\_skip\_param}(\\{top\_skip\_code}){}$;\C{now $\\{temp\_ptr}\E\\{glue\_ptr}(\|q)$}\6 +\&{if} ${}(\\{width}(\\{temp\_ptr})>\\{height}(\|p)){}$\1\5 +${}\\{width}(\\{temp\_ptr})\K\\{width}(\\{temp\_ptr})-\\{height}(\|p);{}$\2\6 +\&{else}\1\5 +${}\\{width}(\\{temp\_ptr})\K\T{0};{}$\2\6 +${}\\{link}(\|q)\K\|p;{}$\5 +${}\\{link}(\\{contrib\_head})\K\|q;{}$\5 +\&{goto} \\{resume};\6 +\4${}\}{}$\2\par +\U1000.\fi + +\M{1002}\B\X1002:Prepare to move a box or rule node to the current page, then \&{goto} \\{contribute}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{page\_total}\K\\{page\_total}+\\{page\_depth}+\\{height}(\|p);{}$\5 +${}\\{page\_depth}\K\\{depth}(\|p);{}$\5 +\&{goto} \\{contribute};\6 +\4${}\}{}$\2\par +\U1000.\fi + +\M{1003}\B\X1003:Make sure that \\{page\_max\_depth} is not exceeded\X${}\E{}$\6 +\&{if} ${}(\\{page\_depth}>\\{page\_max\_depth}){}$\5 +${}\{{}$\5 +\1${}\\{page\_total}\K\30\\{page\_total}+\\{page\_depth}-\\{page\_max\_depth}{}$;\6 +${}\\{page\_depth}\K\\{page\_max\_depth};{}$\6 +\4${}\}{}$\2\par +\U997.\fi + +\M{1004}\B\X1004:Update the current page measurements with respect to the glue or kern specified by node~\|p\X${}\E{}$\6 +\&{if} ${}(\\{type}(\|p)\E\\{kern\_node}){}$\1\5 +${}\|q\K\|p;{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{glue\_ptr}(\|p);{}$\5 +${}\\{page\_so\_far}[\T{2}+\\{stretch\_order}(\|q)]\K\30\\{page\_so\_far}[\T{2}+\\{stretch\_order}(\|q)]+\\{stretch}(\|q){}$;\6 +${}\\{page\_shrink}\K\\{page\_shrink}+\\{shrink}(\|q);{}$\6 +\&{if} ${}((\\{shrink\_order}(\|q)\I\\{normal})\W(\\{shrink}(\|q)\I\T{0})){}$\5 +${}\{{}$\5 +\1\hbox{}\6 +\\{print\_err}(\.{"Infinite\ glue\ shrin}\)\.{kage\ found\ on\ curren}\)\.{t\ page"});\6 +\\{help4}(\.{"The\ page\ about\ to\ b}\)\.{e\ output\ contains\ so}\)\.{me\ infinitely"})\6 +(\.{"shrinkable\ glue,\ e.}\)\.{g.,\ `\\\\vss'\ or\ `\\\\vs}\)\.{kip\ 0pt\ minus\ 1fil'.}\)\.{"})\6 +(\.{"Such\ glue\ doesn't\ b}\)\.{elong\ there;\ but\ you}\)\.{\ can\ safely\ proceed,}\)\.{"})\6 +(\.{"since\ the\ offensive}\)\.{\ shrinkability\ has\ b}\)\.{een\ made\ finite."});\6 +\&{error} (\,)\1\5 +;\2\6 +${}\|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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +${}\\{page\_total}\K\\{page\_total}+\\{page\_depth}+\\{width}(\|q);$ $\\{page\_depth}\K{}$\T{0}\par +\U997.\fi + +\M{1005}\B\X1005: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${}\E{}$\6 +\&{if} ${}(\\{pi}<\\{inf\_penalty}){}$\5 +${}\{{}$\5 +\1\X1007:Compute the badness, \|b, of the current page, using \\{awful\_bad} if the box is too full\X;\6 +\&{if} ${}(\|b<\\{awful\_bad}){}$\1\6 +\&{if} ${}(\\{pi}\Z\\{eject\_penalty}){}$\1\5 +${}\|c\K\\{pi};{}$\2\6 +\&{else} \&{if} ${}(\|b<\\{inf\_bad}){}$\1\5 +${}\|c\K\|b+\\{pi}+\\{insert\_penalties};{}$\2\6 +\&{else}\1\5 +${}\|c\K\\{deplorable};{}$\2\2\6 +\&{else}\1\5 +${}\|c\K\|b;{}$\2\6 +\&{if} ${}(\\{insert\_penalties}\G\T{10000}){}$\1\5 +${}\|c\K\\{awful\_bad};{}$\2\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_pages}>\T{0}){}$\1\5 +\X1006:Display the page break cost\X;\2\6 +\8\#\&{endif}\6 +\&{if} ${}(\|c\Z\\{least\_page\_cost}){}$\5 +${}\{{}$\5 +\1${}\\{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}){}$\5 +${}\{{}$\5 +\1${}\\{best\_ins\_ptr}(\|r)\K\\{last\_ins\_ptr}(\|r);{}$\5 +${}\|r\K\\{link}(\|r);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}((\|c\E\\{awful\_bad})\V(\\{pi}\Z\\{eject\_penalty})){}$\5 +${}\{{}$\5 +\1\\{fire\_up}(\|p);\C{output the current page at the best place}\6 +\&{if} (\\{output\_active})\1\5 +\&{return};\C{user's output routine will act}\2\6 +\&{goto} \\{done};\C{the page has been shipped out by default output routine}\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U997.\fi + +\M{1006}\B\X1006:Display the page break cost\X${}\E{}$\6 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{"\%"});\5 +\\{print\_str}(\.{"\ t="});\5 +\\{print\_totals}(\,);\6 +\\{print\_str}(\.{"\ g="});\5 +\\{print\_scaled}(\\{page\_goal});\6 +\\{print\_str}(\.{"\ b="});\6 +\&{if} ${}(\|b\E\\{awful\_bad}){}$\1\5 +\\{print\_char}(\.{'*'});\5 +\2\&{else}\1\5 +\\{print\_int}(\|b);\2\6 +\\{print\_str}(\.{"\ p="});\5 +\\{print\_int}(\\{pi});\5 +\\{print\_str}(\.{"\ c="});\6 +\&{if} ${}(\|c\E\\{awful\_bad}){}$\1\5 +\\{print\_char}(\.{'*'});\5 +\2\&{else}\1\5 +\\{print\_int}(\|c);\2\6 +\&{if} ${}(\|c\Z\\{least\_page\_cost}){}$\1\5 +\\{print\_char}(\.{'\#'});\2\6 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\par +\U1005.\fi + +\M{1007}\B\X1007:Compute the badness, \|b, of the current page, using \\{awful\_bad} if the box is too full\X${}\E{}$\6 +\&{if} ${}(\\{page\_total}<\\{page\_goal}){}$\1\6 +\&{if} ${}((\\{page\_so\_far}[\T{3}]\I\T{0})\V(\\{page\_so\_far}[\T{4}]\I\T{0})\V\30(\\{page\_so\_far}[\T{5}]\I\T{0})){}$\1\5 +${}\|b\K\T{0};{}$\2\6 +\&{else}\1\5 +${}\|b\K\\{badness}(\\{page\_goal}-\\{page\_total},\39\\{page\_so\_far}[\T{2}]);{}$\2\2\6 +\&{else} \&{if} ${}(\\{page\_total}-\\{page\_goal}>\\{page\_shrink}){}$\1\5 +${}\|b\K\\{awful\_bad};{}$\2\6 +\&{else} $\|b\K\\{badness}(\\{page\_total}-\\{page\_goal},\39\\{page\_shrink}{}$)\par +\U1005.\fi + +\M{1008}\B\X1008:Append an insertion to the current page and \&{goto} \\{contribute}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{page\_contents}\E\\{empty}){}$\1\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\5 +${}\|r\K\\{link}(\|r);{}$\2\6 +${}\|n\K\\{qo}(\|n);{}$\6 +\&{if} ${}(\\{subtype}(\|r)\I\\{qi}(\|n)){}$\1\5 +\X1009:Create a page insertion node with $\\{subtype}(\|r)\K\\{qi}(\|n)$, and include the glue correction for box \|n in the current page state\X;\2\6 +\&{if} ${}(\\{type}(\|r)\E\\{split\_up}){}$\1\5 +${}\\{insert\_penalties}\K\\{insert\_penalties}+\\{float\_cost}(\|p);{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{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)\E\T{1000}){}$\1\5 +${}\|h\K\\{height}(\|p);{}$\2\6 +\&{else}\1\5 +${}\|h\K\\{x\_over\_n}(\\{height}(\|p),\39\T{1000})*\\{count}(\|n){}$;\C{this much room is needed}\2\6 +\&{if} ${}(((\|h\Z\T{0})\V(\|h\Z\\{delta}))\W(\\{height}(\|p)+\\{height}(\|r)\Z\\{dimen}(\|n))){}$\5 +${}\{{}$\5 +\1${}\\{page\_goal}\K\\{page\_goal}-\|h;{}$\5 +${}\\{height}(\|r)\K\\{height}(\|r)+\\{height}(\|p);{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\X1010:Find the best way to split the insertion, and change \\{type}(\|r) to \\{split\_up}\X;\2\6 +\4${}\}{}$\2\6 +\&{goto} \\{contribute};\6 +\4${}\}{}$\2\par +\U1000.\fi + +\M{1009}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\B\4\X1009:Create a page insertion node with $\\{subtype}(\|r)\K\\{qi}(\|n)$, and include the glue correction for box \|n in the current page state\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|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)\E\\{null}){}$\1\5 +${}\\{height}(\|r)\K\T{0};{}$\2\6 +\&{else}\1\5 +${}\\{height}(\|r)\K\\{height}(\\{box}(\|n))+\\{depth}(\\{box}(\|n));{}$\2\6 +${}\\{best\_ins\_ptr}(\|r)\K\\{null}{}$;\6 +${}\|q\K\\{skip}(\|n);{}$\6 +\&{if} ${}(\\{count}(\|n)\E\T{1000}){}$\1\5 +${}\|h\K\\{height}(\|r);{}$\2\6 +\&{else}\1\5 +${}\|h\K\\{x\_over\_n}(\\{height}(\|r),\39\T{1000})*\\{count}(\|n);{}$\2\6 +${}\\{page\_goal}\K\\{page\_goal}-\|h-\\{width}(\|q){}$;\6 +${}\\{page\_so\_far}[\T{2}+\\{stretch\_order}(\|q)]\K\30\\{page\_so\_far}[\T{2}+\\{stretch\_order}(\|q)]+\\{stretch}(\|q){}$;\6 +${}\\{page\_shrink}\K\\{page\_shrink}+\\{shrink}(\|q);{}$\6 +\&{if} ${}((\\{shrink\_order}(\|q)\I\\{normal})\W(\\{shrink}(\|q)\I\T{0})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Infinite\ glue\ shrin}\)\.{kage\ inserted\ from\ "});\5 +\\{print\_esc}(\X1423:\.{"skip"}\X);\5 +\\{print\_int}(\|n);\5 +\\{help3}(\.{"The\ correction\ glue}\)\.{\ for\ page\ breaking\ w}\)\.{ith\ insertions"})\6 +(\.{"must\ have\ finite\ sh}\)\.{rinkability.\ But\ you}\)\.{\ may\ proceed,"})\6 +(\.{"since\ the\ offensive}\)\.{\ shrinkability\ has\ b}\)\.{een\ made\ finite."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1008.\fi + +\M{1010}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\B\4\X1010:Find the best way to split the insertion, and change \\{type}(\|r) to \\{split\_up}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{count}(\|n)\Z\T{0}){}$\1\5 +${}\|w\K\\{max\_dimen};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|w\K\\{page\_goal}-\\{page\_total}-\\{page\_depth};{}$\6 +\&{if} ${}(\\{count}(\|n)\I\T{1000}){}$\1\5 +${}\|w\K\\{x\_over\_n}(\|w,\39\\{count}(\|n))*\T{1000};{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|w>\\{dimen}(\|n)-\\{height}(\|r)){}$\1\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 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_pages}>\T{0}){}$\1\5 +\X1011:Display the insertion split cost\X;\2\6 +\8\#\&{endif}\6 +\&{if} ${}(\\{count}(\|n)\I\T{1000}){}$\1\5 +${}\\{best\_height\_plus\_depth}\K\\{x\_over\_n}(\\{best\_height\_plus\_depth},\39\T{1000})*\\{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\E\\{null}){}$\1\5 +${}\\{insert\_penalties}\K\\{insert\_penalties}+\\{eject\_penalty};{}$\2\6 +\&{else} \&{if} ${}(\\{type}(\|q)\E\\{penalty\_node}){}$\1\5 +${}\\{insert\_penalties}\K\\{insert\_penalties}+\\{penalty}(\|q);{}$\2\6 +\4${}\}{}$\2\par +\U1008.\fi + +\M{1011}\B\X1011:Display the insertion split cost\X${}\E{}$\6 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{"\%\ split"});\5 +\\{print\_int}(\|n);\5 +\\{print\_str}(\.{"\ to\ "});\5 +\\{print\_scaled}(\|w);\5 +\\{print\_char}(\.{','});\5 +\\{print\_scaled}(\\{best\_height\_plus\_depth});\6 +\\{print\_str}(\.{"\ p="});\6 +\&{if} ${}(\|q\E\\{null}){}$\1\5 +\\{print\_int}(\\{eject\_penalty});\2\6 +\&{else} \&{if} ${}(\\{type}(\|q)\E\\{penalty\_node}){}$\1\5 +\\{print\_int}(\\{penalty}(\|q));\2\6 +\&{else}\1\5 +\\{print\_char}(\.{'0'});\2\6 +\\{end\_diagnostic}(\\{false});\6 +\4${}\}{}$\2\par +\U1010.\fi + +\M{1012}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}\E\\{null}$ implies $\\{top\_mark}\E\\{first\_mark}\E\\{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\B\4\X1012:Declare the procedure called \\{fire\_up}\X${}\E{}$\6 +\&{void} \\{fire\_up}(\&{pointer} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|q${},{}$ \|r${},{}$ \|s;\C{nodes being examined and/or changed}\6 +\&{pointer} \\{prev\_p};\C{predecessor of \|p}\6 +\&{uint8\_t} \|n;\C{insertion box number}\6 +\&{bool} \\{wait};\C{should the present insertion be held over?}\6 +\&{int} \\{save\_vbadness};\C{saved value of \\{vbadness}}\6 +\&{scaled} \\{save\_vfuzz};\C{saved value of \\{vfuzz}}\6 +\&{pointer} \\{save\_split\_top\_skip};\C{saved value of \\{split\_top\_skip}}\7 +\X1013:Set the value of \\{output\_penalty}\X;\6 +\&{if} ${}(\\{bot\_mark}\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{top\_mark}\I\\{null}){}$\1\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 +\4${}\}{}$\2\6 +\X1014: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}\E\\{null})){}$\5 +${}\{{}$\5 +\1${}\\{first\_mark}\K\\{top\_mark};{}$\5 +\\{add\_token\_ref}(\\{top\_mark});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{output\_routine}\I\\{null}){}$\1\6 +\&{if} ${}(\\{dead\_cycles}\G\\{max\_dead\_cycles}){}$\1\5 +\X1024:Explain that too many dead cycles have occurred in a row\X\2\6 +\&{else}\1\5 +\X1025:Fire up the user's output routine and \&{return}\X;\2\2\6 +\X1023:Perform the default output routine\X;\6 +\4${}\}{}$\2\par +\U994.\fi + +\M{1013}\B\X1013:Set the value of \\{output\_penalty}\X${}\E{}$\6 +\&{if} ${}(\\{type}(\\{best\_page\_break})\E\\{penalty\_node}){}$\5 +${}\{{}$\5 +\1${}\\{geq\_word\_define}(\\{int\_base}+\\{output\_penalty\_code},\39\\{penalty}(\\{best\_page\_break}));{}$\5 +${}\\{penalty}(\\{best\_page\_break})\K\\{inf\_penalty};{}$\6 +\4${}\}{}$\2\6 +\&{else} $\\{geq\_word\_define}(\\{int\_base}+\\{output\_penalty\_code},\39\\{inf\_penalty}{}$)\par +\U1012.\fi + +\M{1014}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\B\4\X1014: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${}\E{}$\6 +\&{if} ${}(\|c\E\\{best\_page\_break}){}$\1\5 +${}\\{best\_page\_break}\K\\{null}{}$;\C{\|c not yet linked in}\2\6 +\X1015:Ensure that box 255 is empty before output\X;\6 +${}\\{insert\_penalties}\K\T{0}{}$;\C{this will count the number of insertions held over}\6 +${}\\{save\_split\_top\_skip}\K\\{split\_top\_skip};{}$\6 +\&{if} ${}(\\{holding\_inserts}\Z\T{0}){}$\1\5 +\X1018: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}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{type}(\|p)\E\\{ins\_node}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{holding\_inserts}\Z\T{0}){}$\1\5 +\X1020: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 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{type}(\|p)\E\\{mark\_node}){}$\1\5 +\X1016:Update the values of \\{first\_mark} and \\{bot\_mark}\X;\2\6 +${}\\{prev\_p}\K\|p;{}$\5 +${}\|p\K\\{link}(\\{prev\_p});{}$\6 +\4${}\}{}$\2\6 +${}\\{split\_top\_skip}\K\\{save\_split\_top\_skip};{}$\5 +\X1017:Break the current page at node \|p, put it in box~255, and put the remaining nodes on the contribution list\X;\6 +\X1019:Delete \(t)the page-insertion nodes\X\par +\U1012.\fi + +\M{1015}\B\X1015:Ensure that box 255 is empty before output\X${}\E{}$\6 +\&{if} ${}(\\{box}(\T{255})\I\\{null}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{""});\5 +\\{print\_esc}(\X1437:\.{"box"}\X);\5 +\\{print\_str}(\.{"255\ is\ not\ void"});\5 +\\{help2}(\.{"You\ shouldn't\ use\ \\}\)\.{\\box255\ except\ in\ \\\\}\)\.{output\ routines."})\6 +(\.{"Proceed,\ and\ I'll\ d}\)\.{iscard\ its\ present\ c}\)\.{ontents."});\5 +\\{box\_error}(\T{255});\6 +\4${}\}{}$\2\par +\U1014.\fi + +\M{1016}\B\X1016:Update the values of \\{first\_mark} and \\{bot\_mark}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{first\_mark}\E\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{first\_mark}\K\\{mark\_ptr}(\|p);{}$\5 +\\{add\_token\_ref}(\\{first\_mark});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{bot\_mark}\I\\{null}){}$\1\5 +\\{delete\_token\_ref}(\\{bot\_mark});\2\6 +${}\\{bot\_mark}\K\\{mark\_ptr}(\|p);{}$\5 +\\{add\_token\_ref}(\\{bot\_mark});\6 +\4${}\}{}$\2\par +\U1014.\fi + +\M{1017}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\E\\{hold\_head}$; and $\|p\E\\{null}$ if +and only if $\\{prev\_p}\E\\{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\B\4\X1017:Break the current page at node \|p, put it in box~255, and put the remaining nodes on the contribution list\X${}\E{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{link}(\\{contrib\_head})\E\\{null}){}$\1\6 +\&{if} ${}(\\{nest\_ptr}\E\T{0}){}$\1\5 +${}\\{tail}\K\\{page\_tail};{}$\2\6 +\&{else}\1\5 +${}\\{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 +\4${}\}{}$\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}(\T{255})\K\\{vpackage}(\\{link}(\\{page\_head}),\39\\{best\_size},\39\\{exactly},\39\\{page\_max\_depth});{}$\5 +${}\\{vbadness}\K\\{save\_vbadness};{}$\5 +${}\\{vfuzz}\K\\{save\_vfuzz};{}$\6 +\&{if} ${}(\\{last\_glue}\I\\{max\_halfword}){}$\1\5 +\\{delete\_glue\_ref}(\\{last\_glue});\2\6 +\X991:Start a new current page\X;\C{this sets $\\{last\_glue}\K\\{max\_halfword}$}\6 +\&{if} ${}(\|q\I\\{hold\_head}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\\{page\_head})\K\\{link}(\\{hold\_head});{}$\5 +${}\\{page\_tail}\K\|q;{}$\6 +\4${}\}{}$\2\par +\U1014.\fi + +\M{1018}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\B\4\X1018:Prepare all the boxes involved in insertions to act as queues\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|r\K\\{link}(\\{page\_ins\_head});{}$\6 +\&{while} ${}(\|r\I\\{page\_ins\_head}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{best\_ins\_ptr}(\|r)\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\|n\K\\{qo}(\\{subtype}(\|r));{}$\5 +\\{ensure\_vbox}(\|n);\6 +\&{if} ${}(\\{box}(\|n)\E\\{null}){}$\1\5 +${}\\{box}(\|n)\K\\{new\_null\_box}(\,);{}$\2\6 +${}\|p\K\\{box}(\|n)+\\{list\_offset};{}$\6 +\&{while} ${}(\\{link}(\|p)\I\\{null}){}$\1\5 +${}\|p\K\\{link}(\|p);{}$\2\6 +${}\\{last\_ins\_ptr}(\|r)\K\|p;{}$\6 +\4${}\}{}$\2\6 +${}\|r\K\\{link}(\|r);{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1014.\fi + +\M{1019}\B\X1019:Delete \(t)the page-insertion nodes\X${}\E{}$\6 +$\|r\K\\{link}(\\{page\_ins\_head});{}$\6 +\&{while} ${}(\|r\I\\{page\_ins\_head}){}$\5 +${}\{{}$\5 +\1${}\|q\K\\{link}(\|r);{}$\5 +${}\\{free\_node}(\|r,\39\\{page\_ins\_node\_size});{}$\5 +${}\|r\K\|q;{}$\6 +\4${}\}{}$\2\6 +$\\{link}(\\{page\_ins\_head})\K{}$\\{page\_ins\_head}\par +\U1014.\fi + +\M{1020}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\B\4\X1020: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${}\E{}$\6 +${}\{{}$\5 +\1${}\|r\K\\{link}(\\{page\_ins\_head});{}$\6 +\&{while} ${}(\\{subtype}(\|r)\I\\{subtype}(\|p)){}$\1\5 +${}\|r\K\\{link}(\|r);{}$\2\6 +\&{if} ${}(\\{best\_ins\_ptr}(\|r)\E\\{null}){}$\1\5 +${}\\{wait}\K\\{true};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{wait}\K\\{false};{}$\5 +${}\|s\K\\{last\_ins\_ptr}(\|r);{}$\5 +${}\\{link}(\|s)\K\\{ins\_ptr}(\|p);{}$\6 +\&{if} ${}(\\{best\_ins\_ptr}(\|r)\E\|p){}$\1\5 +\X1021: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\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{while} ${}(\\{link}(\|s)\I\\{null}){}$\1\5 +${}\|s\K\\{link}(\|s);{}$\2\6 +${}\\{last\_ins\_ptr}(\|r)\K\|s;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\X1022:Either append the insertion node \|p after node \|q, and remove it from the current page, or delete \\{node}(\|p)\X;\6 +\4${}\}{}$\2\par +\U1014.\fi + +\M{1021}\B\X1021: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${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{type}(\|r)\E\\{split\_up}){}$\1\6 +\&{if} ${}((\\{broken\_ins}(\|r)\E\|p)\W(\\{broken\_ptr}(\|r)\I\\{null})){}$\5 +${}\{{}$\5 +\1\&{while} ${}(\\{link}(\|s)\I\\{broken\_ptr}(\|r)){}$\1\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}){}$\5 +${}\{{}$\5 +\1${}\\{temp\_ptr}\K\\{vpack}(\\{ins\_ptr}(\|p),\39\\{natural});{}$\5 +${}\\{height}(\|p)\K\\{height}(\\{temp\_ptr})+\\{depth}(\\{temp\_ptr});{}$\5 +${}\\{free\_node}(\\{temp\_ptr},\39\\{box\_node\_size});{}$\5 +${}\\{wait}\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\2\6 +${}\\{best\_ins\_ptr}(\|r)\K\\{null};{}$\5 +${}\|n\K\\{qo}(\\{subtype}(\|r));{}$\5 +${}\\{temp\_ptr}\K\\{list\_ptr}(\\{box}(\|n));{}$\5 +${}\\{free\_node}(\\{box}(\|n),\39\\{box\_node\_size});{}$\5 +${}\\{box}(\|n)\K\\{vpack}(\\{temp\_ptr},\39\\{natural});{}$\6 +\4${}\}{}$\2\par +\U1020.\fi + +\M{1022}\B\X1022:Either append the insertion node \|p after node \|q, and remove it from the current page, or delete \\{node}(\|p)\X${}\E{}$\6 +$\\{link}(\\{prev\_p})\K\\{link}(\|p);{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\6 +\&{if} (\\{wait})\5 +${}\{{}$\5 +\1${}\\{link}(\|q)\K\|p;{}$\5 +${}\|q\K\|p;{}$\5 +\\{incr}(\\{insert\_penalties});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{delete\_glue\_ref}(\\{split\_top\_ptr}(\|p));\5 +${}\\{free\_node}(\|p,\39\\{ins\_node\_size});{}$\6 +\4${}\}{}$\2\6 +$\|p\K{}$\\{prev\_p}\par +\U1020.\fi + +\M{1023}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\B\4\X1023:Perform the default output routine\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{link}(\\{page\_head})\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{link}(\\{contrib\_head})\E\\{null}){}$\1\6 +\&{if} ${}(\\{nest\_ptr}\E\T{0}){}$\1\5 +${}\\{tail}\K\\{page\_tail}{}$;\5 +\2\&{else}\1\5 +${}\\{contrib\_tail}\K\\{page\_tail};{}$\2\2\6 +\&{else}\1\5 +${}\\{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 +\4${}\}{}$\2\6 +\\{ship\_out}(\\{box}(\T{255}));\5 +${}\\{box}(\T{255})\K\\{null};{}$\6 +\4${}\}{}$\2\par +\U1012.\fi + +\M{1024}\B\X1024:Explain that too many dead cycles have occurred in a row\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Output\ loop---"});\5 +\\{print\_int}(\\{dead\_cycles});\5 +\\{print\_str}(\.{"\ consecutive\ dead\ c}\)\.{ycles"});\5 +\\{help3}(\.{"I've\ concluded\ that}\)\.{\ your\ \\\\output\ is\ aw}\)\.{ry;\ it\ never\ does\ a"})\6 +(\.{"\\\\shipout,\ so\ I'm\ s}\)\.{hipping\ \\\\box255\ out}\)\.{\ myself.\ Next\ time"})\6 +(\.{"increase\ \\\\maxdeadc}\)\.{ycles\ if\ you\ want\ me}\)\.{\ to\ be\ more\ patient!}\)\.{"});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U1012.\fi + +\M{1025}\B\X1025:Fire up the user's output routine and \&{return}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\par +\U1012.\fi + +\M{1026}When the user's output routine finishes, it has constructed a vlist +in internal vertical mode, and \TeX\ will do the following: + +\Y\B\4\X1026:Resume the page builder after an output routine has come to an end\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}((\\{loc}\I\\{null})\V((\\{token\_type}\I\\{output\_text})\W(\\{token\_type}\I\\{backed\_up}))){}$\1\5 +\X1027: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}\K\T{0}{}$;\6 +\X1028:Ensure that box 255 is empty after output\X;\6 +\&{if} ${}(\\{tail}\I\\{head}{}$)\C{current list goes after heldover insertions}\6 +${}\{{}$\5 +\1${}\\{link}(\\{page\_tail})\K\\{link}(\\{head});{}$\5 +${}\\{page\_tail}\K\\{tail};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{link}(\\{page\_head})\I\\{null}{}$)\C{and both go before heldover contributions}\6 +${}\{{}$\5 +\1\&{if} ${}(\\{link}(\\{contrib\_head})\E\\{null}){}$\1\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 +\4${}\}{}$\2\6 +\\{pop\_nest}(\,);\5 +\\{build\_page}(\,);\6 +\4${}\}{}$\2\par +\U1100.\fi + +\M{1027}\B\X1027:Recover from an unbalanced output routine\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Unbalanced\ output\ r}\)\.{outine"});\5 +\\{help2}(\.{"Your\ sneaky\ output\ }\)\.{routine\ has\ problema}\)\.{tic\ \{'s\ and/or\ \}'s."})\6 +(\.{"I\ can't\ handle\ that}\)\.{\ very\ well;\ good\ luc}\)\.{k."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{do}\5 +${}\{{}$\1\6 +\\{get\_token}(\,);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{loc}\E\\{null}));{}$\6 +\4${}\}{}$\C{loops forever if reading from a file, since $\\{null}\E\\{min\_halfword}\Z\T{0}$}\2\par +\U1026.\fi + +\M{1028}\B\X1028:Ensure that box 255 is empty after output\X${}\E{}$\6 +\&{if} ${}(\\{box}(\T{255})\I\\{null}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Output\ routine\ didn}\)\.{'t\ use\ all\ of\ "});\5 +\\{print\_esc}(\X1437:\.{"box"}\X);\5 +\\{print\_int}(\T{255});\5 +\\{help3}(\.{"Your\ \\\\output\ comma}\)\.{nds\ should\ empty\ \\\\b}\)\.{ox255,"})\6 +(\.{"e.g.,\ by\ saying\ `\\\\}\)\.{shipout\\\\box255'."})\6 +(\.{"Proceed;\ I'll\ disca}\)\.{rd\ its\ present\ conte}\)\.{nts."});\5 +\\{box\_error}(\T{255});\6 +\4${}\}{}$\2\par +\U1026.\fi + +\N{1}{1029}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 + +\M{1030}We shall concentrate first on the inner loop of \\{main\_control}, deferring +consideration of the other cases until later. + +\Y\B\hbox{\4}\X1043:Declare action procedures for use by \\{main\_control}\X\6 +\hbox{\4}\X1068:Declare the procedure called \\{handle\_right\_brace}\X\7 +\&{void} \\{main\_control}(\&{void})\C{governs \TeX's activities}\6 +${}\{{}$\5 +\1\&{int} \|t;\C{general-purpose temporary variable}\7 +\&{if} ${}(\\{every\_job}\I\\{null}){}$\1\5 +${}\\{begin\_token\_list}(\\{every\_job},\39\\{every\_job\_text});{}$\2\6 +\4\\{big\_switch}:\5 +\\{get\_x\_token}(\,);\6 +\4\\{reswitch}:\5 +\X1031:Give diagnostic information, if requested\X;\6 +\&{switch} ${}(\\{abs}(\\{mode})+\\{cur\_cmd}){}$\5 +${}\{{}$\1\6 +\4\&{case} \\{hmode}${}+\\{letter}{}$:\5 +\&{case} \\{hmode}${}+\\{other\_char}{}$:\5 +\&{case} \\{hmode}${}+\\{char\_given}{}$:\5 +\&{goto} \\{main\_loop};\6 +\4\&{case} \\{hmode}${}+\\{char\_num}{}$:\6 +${}\{{}$\5 +\1\\{scan\_char\_num}(\,);\5 +${}\\{cur\_chr}\K\\{cur\_val};{}$\5 +\&{goto} \\{main\_loop};\5 +${}\}{}$\2\6 +\4\&{case} \\{hmode}${}+\\{no\_boundary}{}$:\6 +${}\{{}$\5 +\1\\{get\_x\_token}(\,);\6 +\&{if} ${}((\\{cur\_cmd}\E\\{letter})\V(\\{cur\_cmd}\E\\{other\_char})\V(\\{cur\_cmd}\E\\{char\_given})\V(\\{cur\_cmd}\E\\{char\_num})){}$\1\5 +${}\\{cancel\_boundary}\K\\{true};{}$\2\6 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{hmode}${}+\\{spacer}{}$:\6 +\&{if} ${}(\\{space\_factor}\E\T{1000}){}$\1\5 +\&{goto} \\{append\_normal\_space};\2\6 +\&{else}\1\5 +\\{app\_space}(\,);\5 +\2\&{break};\6 +\4\&{case} \\{hmode}${}+\\{ex\_space}{}$:\5 +\&{case} \\{mmode}${}+\\{ex\_space}{}$:\5 +\&{goto} \\{append\_normal\_space};\5 +\hbox{\4}\X1045:Cases of \\{main\_control} that are not part of the inner loop\X\6 +\4${}\}{}$\C{of the big \&{case} statement}\2\6 +\&{goto} \\{big\_switch};\6 +\4\\{main\_loop}:\5 +\X1034: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}:\5 +\X1041:Append a normal inter-word space to the current list, then \&{goto} \\{big\_switch}\X;\6 +\4${}\}{}$\2\par +\fi + +\M{1031}When a new token has just been fetched at \\{big\_switch}, we have an +ideal place to monitor \TeX's activity. + +\Y\B\4\X1031:Give diagnostic information, if requested\X${}\E{}$\6 +\&{if} ${}(\\{interrupt}\I\T{0}){}$\1\6 +\&{if} (\\{OK\_to\_interrupt})\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +\\{check\_interrupt};\5 +\&{goto} \\{big\_switch};\6 +\4${}\}{}$\2\2\6 +\8\#\&{ifdef} \.{DEBUG}\6 +\&{if} (\\{panicking})\1\5 +\\{check\_mem}(\\{false});\2\6 +\8\#\&{endif}\6 +\&{if} ${}(\\{tracing\_commands}>\T{0})$ \\{show\_cur\_cmd\_chr}(\,)\par +\U1030.\fi + +\M{1032}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})\E\\{font\_false\_bchar}[\\{cur\_font}]$. +Several additional global variables are needed. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{internal\_font\_number} \\{main\_f};\C{the current font}\6 +\&{four\_quarters} \\{main\_i};\C{character information bytes for \\{cur\_l}}\6 +\&{four\_quarters} \\{main\_j};\C{ligature/kern command}\6 +\&{font\_index} \\{main\_k};\C{index into \\{font\_info}}\6 +\&{pointer} \\{main\_p};\C{temporary register for list manipulation}\6 +\&{int} \\{main\_s};\C{space factor value}\6 +\&{halfword} \\{bchar};\C{right boundary character of current font, or \\{non\_char}}\6 +\&{halfword} \\{false\_bchar};\C{nonexistent character matching \\{bchar}, or \\{non\_char}}\6 +\&{bool} \\{cancel\_boundary};\C{should the left boundary be ignored?}\6 +\&{bool} \\{ins\_disc};\C{should we insert a discretionary node?}\par +\fi + +\M{1033}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\B\4\X21:Set initial values of key variables\X${}\mathrel+\E{}$\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 + +\M{1034}We leave the \\{space\_factor} unchanged if $\\{sf\_code}(\\{cur\_chr})\E\T{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})\E\T{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\B\4\D$\\{adjust\_space\_factor}$ \5 +\hbox{}\6 +${}\\{main\_s}\K\\{sf\_code}(\\{cur\_chr});$ \6 +\&{if} ${}(\\{main\_s}\E\T{1000}){}$\1\5 +${}\\{space\_factor}\K\T{1000};{}$\2\6 +\&{else} \&{if} ${}(\\{main\_s}<\T{1000}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{main\_s}>\T{0}){}$\1\5 +${}\\{space\_factor}\K\\{main\_s};{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{space\_factor}<\T{1000}){}$\1\5 +${}\\{space\_factor}\K\T{1000};{}$\2\6 +\&{else} $\\{space\_factor}\K{}$\\{main\_s}\par +\Y\B\4\X1034: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${}\E{}$\6 +\\{adjust\_space\_factor};\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}>\T{0}){}$\1\6 +\&{if} ${}(\\{language}\I\\{clang}){}$\1\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})\5 +${}\{{}$\5 +\1${}\\{cancel\_boundary}\K\\{false};{}$\5 +${}\\{main\_k}\K\\{non\_address};{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{main\_k}\K\\{bchar\_label}[\\{main\_f}];{}$\2\6 +\&{if} ${}(\\{main\_k}\E\\{non\_address}){}$\1\5 +\&{goto} \\{main\_loop\_move2};\C{no left boundary processing}\2\6 +${}\\{cur\_r}\K\\{cur\_l};{}$\5 +${}\\{cur\_l}\K\\{non\_char};{}$\5 +\&{goto} \\{main\_lig\_loop1};\C{begin with cursor after left boundary}\7 +\4\\{main\_loop\_wrapup}:\5 +\X1035:Make a ligature node, if \\{ligature\_present}; insert a null discretionary, if appropriate\X;\6 +\4\\{main\_loop\_move}:\5 +\X1036: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}:\5 +\X1038:Look ahead for another character, or leave \\{lig\_stack} empty if there's none there\X;\6 +\4\\{main\_lig\_loop}:\5 +\X1039: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}:\5 +\X1037:Move the cursor past a pseudo-ligature, then \&{goto} \\{main\_loop\_lookahead} or \\{main\_lig\_loop}\X\par +\U1030.\fi + +\M{1035}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\B\4\D$\\{pack\_lig}(\|X)$ \C{the parameter is either \\{rt\_hit} or \\{false}}\6 +${}\{{}$\5 +\1${}\\{main\_p}\K\\{new\_ligature}(\\{main\_f},\39\\{cur\_l},\39\\{link}(\\{cur\_q}));{}$\6 +\&{if} (\\{lft\_hit})\5 +${}\{{}$\5 +\1${}\\{subtype}(\\{main\_p})\K\T{2};{}$\5 +${}\\{lft\_hit}\K\\{false};{}$\6 +\4${}\}{}$\2\6 +\&{if} (\|X)\1\6 +\&{if} ${}(\\{lig\_stack}\E\\{null}){}$\5 +${}\{{}$\5 +\1\\{incr}(\\{subtype}(\\{main\_p}));\5 +${}\\{rt\_hit}\K\\{false};{}$\6 +\4${}\}{}$\2\2\6 +${}\\{link}(\\{cur\_q})\K\\{main\_p};{}$\5 +${}\\{tail}\K\\{main\_p};{}$\5 +${}\\{ligature\_present}\K\\{false};{}$\6 +\4${}\}{}$\2\par +\B\4\D$\\{wrapup}(\|X)$ \6 +\&{if} ${}(\\{cur\_l}<\\{non\_char}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{link}(\\{cur\_q})>\\{null}){}$\1\6 +\&{if} ${}(\\{character}(\\{tail})\E\\{qi}(\\{hyphen\_char}[\\{main\_f}])){}$\1\5 +${}\\{ins\_disc}\K\\{true};{}$\2\2\6 +\&{if} (\\{ligature\_present})\1\5 +\\{pack\_lig}(\|X);\2\6 +\&{if} (\\{ins\_disc})\5 +${}\{{}$\5 +\1${}\\{ins\_disc}\K\\{false};{}$\6 +\&{if} ${}(\\{mode}>\T{0}){}$\1\5 +\\{tail\_append}(\\{new\_disc}(\,));\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\Y\B\4\X1035:Make a ligature node, if \\{ligature\_present}; insert a null discretionary, if appropriate\X${}\E{}$\6 +\\{wrapup}(\\{rt\_hit})\par +\U1034.\fi + +\M{1036}\B\X1036: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${}% +\E{}$\6 +\&{if} ${}(\\{lig\_stack}\E\\{null}){}$\1\5 +\&{goto} \\{reswitch};\2\6 +${}\\{cur\_q}\K\\{tail};{}$\5 +${}\\{cur\_l}\K\\{character}(\\{lig\_stack});{}$\6 +\4\\{main\_loop\_move1}:\6 +\&{if} ${}(\R\\{is\_char\_node}(\\{lig\_stack})){}$\1\5 +\&{goto} \\{main\_loop\_move\_lig};\2\6 +\4\\{main\_loop\_move2}:\6 +\&{if} ${}((\\{cur\_chr}<\\{font\_bc}[\\{main\_f}])\V(\\{cur\_chr}>\\{font\_ec}[\\{main\_f}])){}$\5 +${}\{{}$\5 +\1${}\\{char\_warning}(\\{main\_f},\39\\{cur\_chr});{}$\5 +\\{free\_avail}(\\{lig\_stack});\5 +\&{goto} \\{big\_switch};\6 +\4${}\}{}$\2\6 +${}\\{main\_i}\K\\{char\_info}(\\{main\_f})(\\{cur\_l});{}$\6 +\&{if} ${}(\R\\{char\_exists}(\\{main\_i})){}$\5 +${}\{{}$\5 +\1${}\\{char\_warning}(\\{main\_f},\39\\{cur\_chr});{}$\5 +\\{free\_avail}(\\{lig\_stack});\5 +\&{goto} \\{big\_switch};\6 +\4${}\}{}$\2\6 +${}\\{link}(\\{tail})\K\\{lig\_stack};$ $\\{tail}\K{}$\\{lig\_stack}\C{\\{main\_loop\_lookahead} is next}\par +\U1034.\fi + +\M{1037}Here we are at \\{main\_loop\_move\_lig}. +When we begin this code we have $\\{cur\_q}\E\\{tail}$ and $\\{cur\_l}\E\\{character}(\\{lig\_stack})$. + +\Y\B\4\X1037:Move the cursor past a pseudo-ligature, then \&{goto} \\{main\_loop\_lookahead} or \\{main\_lig\_loop}\X${}\E{}$\6 +$\\{main\_p}\K\\{lig\_ptr}(\\{lig\_stack});{}$\6 +\&{if} ${}(\\{main\_p}>\\{null}){}$\1\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}\E\\{null}){}$\1\6 +\&{if} ${}(\\{main\_p}>\\{null}){}$\1\5 +\&{goto} \\{main\_loop\_lookahead};\2\6 +\&{else}\1\5 +${}\\{cur\_r}\K\\{bchar};{}$\2\2\6 +\&{else}\1\5 +${}\\{cur\_r}\K\\{character}(\\{lig\_stack});{}$\2\6 +\&{goto} \\{main\_lig\_loop}\par +\U1034.\fi + +\M{1038}The result of \.{\\char} can participate in a ligature or kern, so we must +look ahead for it. + +\Y\B\4\X1038:Look ahead for another character, or leave \\{lig\_stack} empty if there's none there\X${}\E{}$\6 +\\{get\_next}(\,);\C{set only \\{cur\_cmd} and \\{cur\_chr}, for speed}\6 +\&{if} ${}(\\{cur\_cmd}\E\\{letter}){}$\1\5 +\&{goto} \\{main\_loop\_lookahead1};\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{other\_char}){}$\1\5 +\&{goto} \\{main\_loop\_lookahead1};\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{char\_given}){}$\1\5 +\&{goto} \\{main\_loop\_lookahead1};\2\6 +\\{x\_token}(\,);\C{now expand and set \\{cur\_cmd}, \\{cur\_chr}, \\{cur\_tok}}\6 +\&{if} ${}(\\{cur\_cmd}\E\\{letter}){}$\1\5 +\&{goto} \\{main\_loop\_lookahead1};\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{other\_char}){}$\1\5 +\&{goto} \\{main\_loop\_lookahead1};\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{char\_given}){}$\1\5 +\&{goto} \\{main\_loop\_lookahead1};\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{char\_num}){}$\5 +${}\{{}$\5 +\1\\{scan\_char\_num}(\,);\5 +${}\\{cur\_chr}\K\\{cur\_val};{}$\5 +\&{goto} \\{main\_loop\_lookahead1};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{no\_boundary}){}$\1\5 +${}\\{bchar}\K\\{non\_char};{}$\2\6 +${}\\{cur\_r}\K\\{bchar};{}$\5 +${}\\{lig\_stack}\K\\{null};{}$\5 +\&{goto} \\{main\_lig\_loop};\6 +\4\\{main\_loop\_lookahead1}:\5 +\\{adjust\_space\_factor};\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};$ \&{if} ${}(\\{cur\_r}\E\\{false\_bchar})$ $\\{cur\_r}\K{}$\\{non\_char}\C{this prevents spurious ligatures}\par +\U1034.\fi + +\M{1039}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}\E\\{char\_info}(\\{main\_f})(\\{cur\_l})$. + +\Y\B\4\X1039:If there's a ligature/kern command relevant to \\{cur\_l} and \\{cur\_r}, adjust the text appropriately; exit to \\{main\_loop\_wrapup}\X${}\E{}$\6 +\&{if} ${}(\\{char\_tag}(\\{main\_i})\I\\{lig\_tag}){}$\1\5 +\&{goto} \\{main\_loop\_wrapup};\2\6 +\&{if} ${}(\\{cur\_r}\E\\{non\_char}){}$\1\5 +\&{goto} \\{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})\Z\\{stop\_flag}){}$\1\5 +\&{goto} \\{main\_lig\_loop2};\2\6 +${}\\{main\_k}\K\\{lig\_kern\_restart}(\\{main\_f})(\\{main\_j});{}$\6 +\4\\{main\_lig\_loop1}:\5 +${}\\{main\_j}\K\\{font\_info}[\\{main\_k}].\\{qqqq};{}$\6 +\4\\{main\_lig\_loop2}:\6 +\&{if} ${}(\\{next\_char}(\\{main\_j})\E\\{cur\_r}){}$\1\6 +\&{if} ${}(\\{skip\_byte}(\\{main\_j})\Z\\{stop\_flag}){}$\1\5 +\X1040: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})\E\\{qi}(\T{0})){}$\1\5 +\\{incr}(\\{main\_k});\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{skip\_byte}(\\{main\_j})\G\\{stop\_flag}){}$\1\5 +\&{goto} \\{main\_loop\_wrapup};\2\6 +${}\\{main\_k}\K\\{main\_k}+\\{qo}(\\{skip\_byte}(\\{main\_j}))+\T{1};{}$\6 +\4${}\}{}$\2\6 +\&{goto} \\{main\_lig\_loop1}\par +\U1034.\fi + +\M{1040}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\B\4\X1040:Do ligature or kern command, returning to \\{main\_lig\_loop} or \\{main\_loop\_wrapup} or \\{main\_loop\_move}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{op\_byte}(\\{main\_j})\G\\{kern\_flag}){}$\5 +${}\{{}$\5 +\1\\{wrapup}(\\{rt\_hit});\5 +\\{tail\_append}(\\{new\_kern}(\\{char\_kern}(\\{main\_f})(\\{main\_j})));\5 +\&{goto} \\{main\_loop\_move};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_l}\E\\{non\_char}){}$\1\5 +${}\\{lft\_hit}\K\\{true};{}$\2\6 +\&{else} \&{if} ${}(\\{lig\_stack}\E\\{null}){}$\1\5 +${}\\{rt\_hit}\K\\{true};{}$\2\6 +\\{check\_interrupt};\C{allow a way out in case there's an infinite ligature loop}\6 +\&{switch} (\\{op\_byte}(\\{main\_j}))\5 +${}\{{}$\1\6 +\4\\{qi}(\&{case} \T{1}):\5 +\\{qi}(\&{case} \T{5}):\6 +${}\{{}$\5 +\1${}\\{cur\_l}\K\\{rem\_byte}(\\{main\_j}){}$;\C{\.{=:\?}, \.{=:\?>}}\6 +${}\\{main\_i}\K\\{char\_info}(\\{main\_f})(\\{cur\_l});{}$\5 +${}\\{ligature\_present}\K\\{true};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\\{qi}(\&{case} \T{2}):\5 +\\{qi}(\&{case} \T{6}):\6 +${}\{{}$\5 +\1${}\\{cur\_r}\K\\{rem\_byte}(\\{main\_j}){}$;\C{\.{\?=:}, \.{\?=:>}}\6 +\&{if} ${}(\\{lig\_stack}\E\\{null}{}$)\C{right boundary character is being consumed}\6 +${}\{{}$\5 +\1${}\\{lig\_stack}\K\\{new\_lig\_item}(\\{cur\_r});{}$\5 +${}\\{bchar}\K\\{non\_char};{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} (\\{is\_char\_node}(\\{lig\_stack}))\C{$\\{link}(\\{lig\_stack})\E\\{null}$}\6 +${}\{{}$\5 +\1${}\\{main\_p}\K\\{lig\_stack};{}$\5 +${}\\{lig\_stack}\K\\{new\_lig\_item}(\\{cur\_r});{}$\5 +${}\\{lig\_ptr}(\\{lig\_stack})\K\\{main\_p};{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{character}(\\{lig\_stack})\K\\{cur\_r};{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\\{qi}(\&{case} \T{3}):\6 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\\{qi}(\&{case} \T{7}):\5 +\\{qi}(\&{case} \T{11}):\6 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\6 +${}\{{}$\5 +\1${}\\{cur\_l}\K\\{rem\_byte}(\\{main\_j});{}$\5 +${}\\{ligature\_present}\K\\{true}{}$;\C{\.{=:}}\6 +\&{if} ${}(\\{lig\_stack}\E\\{null}){}$\1\5 +\&{goto} \\{main\_loop\_wrapup};\2\6 +\&{else}\1\5 +\&{goto} \\{main\_loop\_move1};\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{op\_byte}(\\{main\_j})>\\{qi}(\T{4})){}$\1\6 +\&{if} ${}(\\{op\_byte}(\\{main\_j})\I\\{qi}(\T{7})){}$\1\5 +\&{goto} \\{main\_loop\_wrapup};\2\2\6 +\&{if} ${}(\\{cur\_l}<\\{non\_char}){}$\1\5 +\&{goto} \\{main\_lig\_loop};\2\6 +${}\\{main\_k}\K\\{bchar\_label}[\\{main\_f}];{}$\5 +\&{goto} \\{main\_lig\_loop1};\6 +\4${}\}{}$\2\par +\U1039.\fi + +\M{1041}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\B\4\X1041:Append a normal inter-word space to the current list, then \&{goto} \\{big\_switch}\X${}\E{}$\6 +\&{if} ${}(\\{space\_skip}\E\\{zero\_glue}){}$\5 +${}\{{}$\5 +\1\X1042:Find the glue specification, \\{main\_p}, for text spaces in the current font\X;\6 +${}\\{temp\_ptr}\K\\{new\_glue}(\\{main\_p});{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{temp\_ptr}\K\\{new\_param\_glue}(\\{space\_skip\_code});{}$\2\6 +${}\\{link}(\\{tail})\K\\{temp\_ptr};{}$\5 +${}\\{tail}\K\\{temp\_ptr};$ \&{goto} \\{big\_switch}\par +\U1030.\fi + +\M{1042}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\B\4\X1042:Find the glue specification, \\{main\_p}, for text spaces in the current font\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{main\_p}\K\\{font\_glue}[\\{cur\_font}];{}$\6 +\&{if} ${}(\\{main\_p}\E\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{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}+\T{1}].\\{sc}{}$;\C{and \\{space\_stretch}(\\{cur\_font})}\6 +${}\\{shrink}(\\{main\_p})\K\\{font\_info}[\\{main\_k}+\T{2}].\\{sc}{}$;\C{and \\{space\_shrink}(\\{cur\_font})}\6 +${}\\{font\_glue}[\\{cur\_font}]\K\\{main\_p};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\Us1041\ET1043.\fi + +\M{1043}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\E{}$\6 +\&{void} \\{app\_space}(\&{void})\C{handle spaces when $\\{space\_factor}\I\T{1000}$}\6 +${}\{{}$\5 +\1\&{pointer} \|q;\C{glue node}\7 +\&{if} ${}((\\{space\_factor}\G\T{2000})\W(\\{xspace\_skip}\I\\{zero\_glue})){}$\1\5 +${}\|q\K\\{new\_param\_glue}(\\{xspace\_skip\_code});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{space\_skip}\I\\{zero\_glue}){}$\1\5 +${}\\{main\_p}\K\\{space\_skip};{}$\2\6 +\&{else}\1\5 +\X1042:Find the glue specification, \\{main\_p}, for text spaces in the current font\X;\2\6 +${}\\{main\_p}\K\\{new\_spec}(\\{main\_p});{}$\5 +\X1044: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 +\4${}\}{}$\2\6 +${}\\{link}(\\{tail})\K\|q;{}$\5 +${}\\{tail}\K\|q;{}$\6 +\4${}\}{}$\2\par +\As1047, 1049, 1050, 1051, 1054, 1060, 1061, 1064, 1069, 1070, 1075, 1079, 1084, 1086, 1091, 1093, 1095, 1096, 1099, 1101, 1103, 1105, 1110, 1113, 1117, 1119, 1123, 1127, 1129, 1131, 1135, 1136, 1138, 1142, 1151, 1155, 1159, 1160, 1163, 1165, 1172, 1174, +1176, 1181, 1191, 1194, 1200, 1211, 1270, 1275, 1279, 1288, 1293, 1302, 1348\ETs1376. +\U1030.\fi + +\M{1044}\B\X1044:Modify the glue specification in \\{main\_p} according to the space factor\X${}\E{}$\6 +\&{if} ${}(\\{space\_factor}\G\T{2000}){}$\1\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},\39\T{1000});$ $\\{shrink}(\\{main\_p})\K\\{xn\_over\_d}(\\{shrink}(\\{main\_p}),\39\T{1000},\39\\{space\_factor}{}$)\par +\U1043.\fi + +\M{1045}Whew---that covers the main loop. We can now proceed at a leisurely +pace through the other combinations of possibilities. + +\Y\B\4\D$\\{any\_mode}(\|X)$ \5 +\&{case} \\{vmode}${}+\|X{}$:\5 +\&{case} \\{hmode}${}+\|X{}$: \&{case} \\{mmode}${}+{}$\|X\C{for mode-independent commands}\par +\Y\B\4\X1045:Cases of \\{main\_control} that are not part of the inner loop\X${}\E{}$\6 +\4\\{any\_mode}(\\{relax}):\5 +\&{case} \\{vmode}${}+\\{spacer}{}$:\5 +\&{case} \\{mmode}${}+\\{spacer}{}$:\5 +\&{case} \\{mmode}${}+\\{no\_boundary}{}$:\5 +\\{do\_nothing};\6 +\4\\{any\_mode}(\\{ignore\_spaces}):\6 +${}\{{}$\5 +\1\X406:Get the next non-blank non-call token\X;\6 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{vmode}${}+\\{stop}{}$:\6 +\&{if} (\\{its\_all\_over}(\,))\1\5 +\&{return};\5 +\2\&{break};\C{this is the only way out}\6 +\4\hbox{\4}\X1048:Forbidden cases detected in \\{main\_control}\X\5 +\,\\{any\_mode}(\\{mac\_param}):\5 +\\{report\_illegal\_case}(\,);\5 +\&{break};\6 +\4\X1046:Math-only cases in non-math modes, or vice versa\X:\5 +\\{insert\_dollar\_sign}(\,);\5 +\&{break};\5 +\hbox{\4}\X1056:Cases of \\{main\_control} that build boxes and lists\X\6 +\hbox{\4}\X1210:Cases of \\{main\_control} that don't depend on \\{mode}\X\6 +\hbox{\4}\X1347:Cases of \\{main\_control} that are for extensions to \TeX\X\par +\U1030.\fi + +\M{1046}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\B\4\D$\\{non\_math}(\|X)$ \5 +\&{case} \\{vmode}${}+\|X{}$: \&{case} \\{hmode}${}+{}$\|X\par +\Y\B\4\X1046:Math-only cases in non-math modes, or vice versa\X${}\E{}$\6 +\\{non\_math}(\\{sup\_mark}):\5 +\\{non\_math}(\\{sub\_mark}):\5 +\\{non\_math}(\\{math\_char\_num}):\5 +\\{non\_math}(\\{math\_given}):\5 +\\{non\_math}(\\{math\_comp}):\5 +\\{non\_math}(\\{delim\_num}):\5 +\\{non\_math}(\\{left\_right}):\5 +\\{non\_math}(\\{above}):\5 +\\{non\_math}(\\{radical}):\5 +\\{non\_math}(\\{math\_style}):\5 +\\{non\_math}(\\{math\_choice}):\5 +\\{non\_math}(\\{vcenter}):\5 +\\{non\_math}(\\{non\_script}):\5 +\\{non\_math}(\\{mkern}):\5 +\\{non\_math}(\\{limit\_switch}):\5 +\\{non\_math}(\\{mskip}):\5 +\\{non\_math}(\\{math\_accent}):\5 +\&{case} \\{mmode}${}+\\{endv}{}$:\5 +\&{case} \\{mmode}${}+\\{par\_end}{}$:\5 +\&{case} \\{mmode}${}+\\{stop}{}$:\5 +\&{case} \\{mmode}${}+\\{vskip}{}$:\5 +\&{case} \\{mmode}${}+\\{un\_vbox}{}$:\5 +\&{case} \\{mmode}${}+\\{valign}{}$: \&{case} \\{mmode}${}+{}$\\{hrule}\par +\U1045.\fi + +\M{1047}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{insert\_dollar\_sign}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +${}\\{cur\_tok}\K\\{math\_shift\_token}+\.{'\$'};{}$\5 +\\{print\_err}(\.{"Missing\ \$\ inserted"});\5 +\\{help2}(\.{"I've\ inserted\ a\ beg}\)\.{in-math/end-math\ sym}\)\.{bol\ since\ I\ think"})\6 +(\.{"you\ left\ one\ out.\ P}\)\.{roceed,\ with\ fingers}\)\.{\ crossed."});\5 +\\{ins\_error}(\,);\6 +\4${}\}{}$\2\par +\fi + +\M{1048}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\B\4\X1048:Forbidden cases detected in \\{main\_control}\X${}\E{}$\6 +\&{case} \\{vmode}${}+\\{vmove}{}$:\5 +\&{case} \\{hmode}${}+\\{hmove}{}$:\5 +\&{case} \\{mmode}${}+\\{hmove}{}$:\5 +\\{any\_mode}(\\{last\_item}):\par +\As1098, 1111\ETs1144. +\U1045.\fi + +\M{1049}The `\\{you\_cant}' procedure prints a line saying that the current command +is illegal in the current mode; it identifies these things symbolically. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{you\_cant}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"You\ can't\ use\ `"});\5 +${}\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr});{}$\5 +\\{print\_str}(\.{"'\ in\ "});\5 +\\{print\_mode}(\\{mode});\6 +\4${}\}{}$\2\par +\fi + +\M{1050}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{report\_illegal\_case}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{you\_cant}(\,);\5 +\\{help4}(\.{"Sorry,\ but\ I'm\ not\ }\)\.{programmed\ to\ handle}\)\.{\ this\ case;"})\6 +(\.{"I'll\ just\ pretend\ t}\)\.{hat\ you\ didn't\ ask\ f}\)\.{or\ it."})\6 +(\.{"If\ you're\ in\ the\ wr}\)\.{ong\ mode,\ you\ might\ }\)\.{be\ able\ to"})\6 +(\.{"return\ to\ the\ right}\)\.{\ one\ by\ typing\ `I\}'\ }\)\.{or\ `I\$'\ or\ `I\\\\par'.}\)\.{"});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\fi + +\M{1051}Some operations are allowed only in privileged modes, i.e., in cases +that $\\{mode}>\T{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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{bool} \\{privileged}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{mode}>\T{0}){}$\1\5 +\&{return} \\{true};\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{report\_illegal\_case}(\,);\5 +\&{return} \\{false};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1052}Either \.{\\dump} or \.{\\end} will cause \\{main\_control} to enter the +endgame, since both of them have `\\{stop}' as their command code. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1698:\.{"end"}\X,\39\\{stop},\39\T{0}){}$;\6 +${}\\{primitive}(\X1699:\.{"dump"}\X,\39\\{stop},\39\T{1}){}$;\par +\fi + +\M{1053}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{stop}:\6 +\&{if} ${}(\\{chr\_code}\E\T{1}){}$\1\5 +\\{print\_esc}(\X1699:\.{"dump"}\X);\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1698:\.{"end"}\X);\5 +\2\&{break};\par +\fi + +\M{1054}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{bool} \\{its\_all\_over}(\&{void})\C{do this when \.{\\end} or \.{\\dump} occurs}\6 +${}\{{}$\5 +\1\&{if} (\\{privileged}(\,))\5 +${}\{{}$\5 +\1\&{if} ${}((\\{page\_head}\E\\{page\_tail})\W(\\{head}\E\\{tail})\W(\\{dead\_cycles}\E\T{0})){}$\5 +${}\{{}$\5 +\1\&{return} \\{true};\6 +\4${}\}{}$\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}({-}\T{\~10000000000})){}$;\6 +\\{build\_page}(\,);\C{append \.{\\hbox to \\hsize\{\}\\vfill\\penalty-'10000000000}}\6 +\4${}\}{}$\2\6 +\&{return} \\{false};\6 +\4${}\}{}$\2\par +\fi + +\N{1}{1055}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 + +\M{1056}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\E{}$\6 +\4\&{case} \\{vmode}${}+\\{hrule}{}$:\5 +\&{case} \\{hmode}${}+\\{vrule}{}$:\5 +\&{case} \\{mmode}${}+\\{vrule}{}$:\6 +${}\{{}$\5 +\1\\{tail\_append}(\\{scan\_rule\_spec}(\,));\6 +\&{if} ${}(\\{abs}(\\{mode})\E\\{vmode}){}$\1\5 +${}\\{prev\_depth}\K\\{ignore\_depth};{}$\2\6 +\&{else} \&{if} ${}(\\{abs}(\\{mode})\E\\{hmode}){}$\1\5 +${}\\{space\_factor}\K\T{1000};{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\par +\As1057, 1063, 1067, 1073, 1090, 1092, 1094, 1097, 1102, 1104, 1109, 1112, 1116, 1122, 1126, 1130, 1134, 1137, 1140, 1150, 1154, 1158, 1162, 1164, 1167, 1171, 1175, 1180, 1190\ETs1193. +\U1045.\fi + +\M{1057}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{vmode}${}+\\{vskip}{}$:\5 +\&{case} \\{hmode}${}+\\{hskip}{}$:\5 +\&{case} \\{mmode}${}+\\{hskip}{}$:\5 +\&{case} \\{mmode}${}+\\{mskip}{}$:\5 +\\{append\_glue}(\,);\5 +\&{break};\6 +\4\\{any\_mode}(\\{kern}):\5 +\&{case} \\{mmode}${}+\\{mkern}{}$:\5 +\\{append\_kern}(\,);\5 +\&{break};\par +\fi + +\M{1058}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\B\4\D$\\{fil\_code}$ \5 +\T{0}\C{identifies \.{\\hfil} and \.{\\vfil}}\par +\B\4\D$\\{fill\_code}$ \5 +\T{1}\C{identifies \.{\\hfill} and \.{\\vfill}}\par +\B\4\D$\\{ss\_code}$ \5 +\T{2}\C{identifies \.{\\hss} and \.{\\vss}}\par +\B\4\D$\\{fil\_neg\_code}$ \5 +\T{3}\C{identifies \.{\\hfilneg} and \.{\\vfilneg}}\par +\B\4\D$\\{skip\_code}$ \5 +\T{4}\C{identifies \.{\\hskip} and \.{\\vskip}}\par +\B\4\D$\\{mskip\_code}$ \5 +\T{5}\C{identifies \.{\\mskip}}\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1700:\.{"hskip"}\X,\39\\{hskip},\39\\{skip\_code}){}$;\6 +${}\\{primitive}(\X1701:\.{"hfil"}\X,\39\\{hskip},\39\\{fil\_code});{}$\5 +${}\\{primitive}(\X1702:\.{"hfill"}\X,\39\\{hskip},\39\\{fill\_code}){}$;\6 +${}\\{primitive}(\X1703:\.{"hss"}\X,\39\\{hskip},\39\\{ss\_code});{}$\5 +${}\\{primitive}(\X1704:\.{"hfilneg"}\X,\39\\{hskip},\39\\{fil\_neg\_code}){}$;\6 +${}\\{primitive}(\X1705:\.{"vskip"}\X,\39\\{vskip},\39\\{skip\_code}){}$;\6 +${}\\{primitive}(\X1706:\.{"vfil"}\X,\39\\{vskip},\39\\{fil\_code});{}$\5 +${}\\{primitive}(\X1707:\.{"vfill"}\X,\39\\{vskip},\39\\{fill\_code}){}$;\6 +${}\\{primitive}(\X1708:\.{"vss"}\X,\39\\{vskip},\39\\{ss\_code});{}$\5 +${}\\{primitive}(\X1709:\.{"vfilneg"}\X,\39\\{vskip},\39\\{fil\_neg\_code}){}$;\6 +${}\\{primitive}(\X1393:\.{"mskip"}\X,\39\\{mskip},\39\\{mskip\_code}){}$;\6 +${}\\{primitive}(\X1396:\.{"kern"}\X,\39\\{kern},\39\&{explicit});{}$\5 +${}\\{primitive}(\X1397:\.{"mkern"}\X,\39\\{mkern},\39\\{mu\_glue}){}$;\par +\fi + +\M{1059}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{hskip}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{skip\_code}:\5 +\\{print\_esc}(\X1700:\.{"hskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{fil\_code}:\5 +\\{print\_esc}(\X1701:\.{"hfil"}\X);\5 +\&{break};\6 +\4\&{case} \\{fill\_code}:\5 +\\{print\_esc}(\X1702:\.{"hfill"}\X);\5 +\&{break};\6 +\4\&{case} \\{ss\_code}:\5 +\\{print\_esc}(\X1703:\.{"hss"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1704:\.{"hfilneg"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{vskip}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{skip\_code}:\5 +\\{print\_esc}(\X1705:\.{"vskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{fil\_code}:\5 +\\{print\_esc}(\X1706:\.{"vfil"}\X);\5 +\&{break};\6 +\4\&{case} \\{fill\_code}:\5 +\\{print\_esc}(\X1707:\.{"vfill"}\X);\5 +\&{break};\6 +\4\&{case} \\{ss\_code}:\5 +\\{print\_esc}(\X1708:\.{"vss"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1709:\.{"vfilneg"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{mskip}:\5 +\\{print\_esc}(\X1393:\.{"mskip"}\X);\5 +\&{break};\6 +\4\&{case} \\{kern}:\5 +\\{print\_esc}(\X1396:\.{"kern"}\X);\5 +\&{break};\6 +\4\&{case} \\{mkern}:\5 +\\{print\_esc}(\X1397:\.{"mkern"}\X);\5 +\&{break};\par +\fi + +\M{1060}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{append\_glue}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{small\_number} \|s;\C{modifier of skip command}\7 +${}\|s\K\\{cur\_chr};{}$\6 +\&{switch} (\|s)\5 +${}\{{}$\1\6 +\4\&{case} \\{fil\_code}:\5 +${}\\{cur\_val}\K\\{fil\_glue}{}$;\5 +\&{break};\6 +\4\&{case} \\{fill\_code}:\5 +${}\\{cur\_val}\K\\{fill\_glue}{}$;\5 +\&{break};\6 +\4\&{case} \\{ss\_code}:\5 +${}\\{cur\_val}\K\\{ss\_glue}{}$;\5 +\&{break};\6 +\4\&{case} \\{fil\_neg\_code}:\5 +${}\\{cur\_val}\K\\{fil\_neg\_glue}{}$;\5 +\&{break};\6 +\4\&{case} \\{skip\_code}:\5 +\\{scan\_glue}(\\{glue\_val});\5 +\&{break};\6 +\4\&{case} \\{mskip\_code}:\5 +\\{scan\_glue}(\\{mu\_val});\6 +\4${}\}{}$\C{now \\{cur\_val} points to the glue specification}\2\6 +\\{tail\_append}(\\{new\_glue}(\\{cur\_val}));\6 +\&{if} ${}(\|s\G\\{skip\_code}){}$\5 +${}\{{}$\5 +\1\\{decr}(\\{glue\_ref\_count}(\\{cur\_val}));\6 +\&{if} ${}(\|s>\\{skip\_code}){}$\1\5 +${}\\{subtype}(\\{tail})\K\\{mu\_glue};{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1061}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{append\_kern}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{quarterword} \|s;\C{\\{subtype} of the kern node}\7 +${}\|s\K\\{cur\_chr};{}$\5 +${}\\{scan\_dimen}(\|s\E\\{mu\_glue},\39\\{false},\39\\{false});{}$\5 +\\{tail\_append}(\\{new\_kern}(\\{cur\_val}));\5 +${}\\{subtype}(\\{tail})\K\|s;{}$\6 +\4${}\}{}$\2\par +\fi + +\M{1062}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 + +\M{1063}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\\{non\_math}(\\{left\_brace}):\5 +\\{new\_save\_level}(\\{simple\_group});\5 +\&{break};\6 +\4\\{any\_mode}(\\{begin\_group}):\5 +\\{new\_save\_level}(\\{semi\_simple\_group});\5 +\&{break};\6 +\4\\{any\_mode}(\\{end\_group}):\6 +\&{if} ${}(\\{cur\_group}\E\\{semi\_simple\_group}){}$\1\5 +\\{unsave}(\,);\2\6 +\&{else}\1\5 +\\{off\_save}(\,);\5 +\2\&{break};\par +\fi + +\M{1064}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{off\_save}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{inserted token}\7 +\&{if} ${}(\\{cur\_group}\E\\{bottom\_level}){}$\1\5 +\X1066:Drop current token and complain that it was unmatched\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +${}\|p\K\\{get\_avail}(\,);{}$\5 +${}\\{link}(\\{temp\_head})\K\|p;{}$\5 +\\{print\_err}(\.{"Missing\ "});\5 +\X1065:Prepare to insert a token that matches \\{cur\_group}, and print what it is\X;\6 +\\{print\_str}(\.{"\ inserted"});\5 +\\{ins\_list}(\\{link}(\\{temp\_head}));\5 +\\{help5}(\.{"I've\ inserted\ somet}\)\.{hing\ that\ you\ may\ ha}\)\.{ve\ forgotten."})\6 +(\.{"(See\ the\ <inserted\ }\)\.{text>\ above.)"})\6 +(\.{"With\ luck,\ this\ wil}\)\.{l\ get\ me\ unwedged.\ B}\)\.{ut\ if\ you"})\6 +(\.{"really\ didn't\ forge}\)\.{t\ anything,\ try\ typi}\)\.{ng\ `2'\ now;\ then"})\6 +(\.{"my\ insertion\ and\ my}\)\.{\ current\ dilemma\ wil}\)\.{l\ both\ disappear."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1065}At this point, $\\{link}(\\{temp\_head})\E\|p$, a pointer to an empty one-word node. + +\Y\B\4\X1065:Prepare to insert a token that matches \\{cur\_group}, and print what it is\X${}\E{}$\6 +\&{switch} (\\{cur\_group})\5 +${}\{{}$\1\6 +\4\&{case} \\{semi\_simple\_group}:\6 +${}\{{}$\5 +\1${}\\{info}(\|p)\K\\{cs\_token\_flag}+\\{frozen\_end\_group};{}$\5 +\\{print\_esc}(\X1538:\.{"endgroup"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{math\_shift\_group}:\6 +${}\{{}$\5 +\1${}\\{info}(\|p)\K\\{math\_shift\_token}+\.{'\$'};{}$\5 +\\{print\_char}(\.{'\$'});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{math\_left\_group}:\6 +${}\{{}$\5 +\1${}\\{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}(\X1710:\.{"right."}\X);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\6 +${}\{{}$\5 +\1${}\\{info}(\|p)\K\\{right\_brace\_token}+\.{'\}'};{}$\5 +\\{print\_char}(\.{'\}'});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1064.\fi + +\M{1066}\B\X1066:Drop current token and complain that it was unmatched\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Extra\ "});\5 +${}\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr});{}$\5 +\\{help1}(\.{"Things\ are\ pretty\ m}\)\.{ixed\ up,\ but\ I\ think}\)\.{\ the\ worst\ is\ over."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U1064.\fi + +\M{1067}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{right\_brace}):\5 +\\{handle\_right\_brace}(\,);\5 +\&{break};\par +\fi + +\M{1068}\B\X1068:Declare the procedure called \\{handle\_right\_brace}\X${}\E{}$\6 +\&{void} \\{handle\_right\_brace}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|q;\C{for short-term use}\6 +\&{scaled} \|d;\C{holds \\{split\_max\_depth} in \\{insert\_group}}\6 +\&{int} \|f;\C{holds \\{floating\_penalty} in \\{insert\_group}}\7 +\&{switch} (\\{cur\_group})\5 +${}\{{}$\1\6 +\4\&{case} \\{simple\_group}:\5 +\\{unsave}(\,);\5 +\&{break};\6 +\4\&{case} \\{bottom\_level}:\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Too\ many\ \}'s"});\5 +\\{help2}(\.{"You've\ closed\ more\ }\)\.{groups\ than\ you\ open}\)\.{ed."})\6 +(\.{"Such\ booboos\ are\ ge}\)\.{nerally\ harmless,\ so}\)\.{\ keep\ going."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{semi\_simple\_group}:\5 +\&{case} \\{math\_shift\_group}:\5 +\&{case} \\{math\_left\_group}:\5 +\\{extra\_right\_brace}(\,);\5 +\&{break};\5 +\hbox{\4}\X1085:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X\6 +\4\&{default}:\5 +\\{confusion}(\X1711:\.{"rightbrace"}\X);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1030.\fi + +\M{1069}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{extra\_right\_brace}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Extra\ \},\ or\ forgott}\)\.{en\ "});\6 +\&{switch} (\\{cur\_group})\5 +${}\{{}$\1\6 +\4\&{case} \\{semi\_simple\_group}:\5 +\\{print\_esc}(\X1538:\.{"endgroup"}\X);\5 +\&{break};\6 +\4\&{case} \\{math\_shift\_group}:\5 +\\{print\_char}(\.{'\$'});\5 +\&{break};\6 +\4\&{case} \\{math\_left\_group}:\5 +\\{print\_esc}(\X1660:\.{"right"}\X);\6 +\4${}\}{}$\2\6 +\\{help5}(\.{"I've\ deleted\ a\ grou}\)\.{p-closing\ symbol\ bec}\)\.{ause\ it\ seems\ to\ be"})\6 +(\.{"spurious,\ as\ in\ `\$x}\)\.{\}\$'.\ But\ perhaps\ the}\)\.{\ \}\ is\ legitimate\ and}\)\.{"})\6 +(\.{"you\ forgot\ somethin}\)\.{g\ else,\ as\ in\ `\\\\hbo}\)\.{x\{\$x\}'.\ In\ such\ case}\)\.{s"})\6 +(\.{"the\ way\ to\ recover\ }\)\.{is\ to\ insert\ both\ th}\)\.{e\ forgotten\ and\ the"})\6 +(\.{"deleted\ material,\ e}\)\.{.g.,\ by\ typing\ `I\$\}'}\)\.{."});\6 +\&{error} (\,)\1\5 +;\2\6 +\\{incr}(\\{align\_state});\6 +\4${}\}{}$\2\par +\fi + +\M{1070}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{normal\_paragraph}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{looseness}\I\T{0}){}$\1\5 +${}\\{eq\_word\_define}(\\{int\_base}+\\{looseness\_code},\39\T{0});{}$\2\6 +\&{if} ${}(\\{hang\_indent}\I\T{0}){}$\1\5 +${}\\{eq\_word\_define}(\\{dimen\_base}+\\{hang\_indent\_code},\39\T{0});{}$\2\6 +\&{if} ${}(\\{hang\_after}\I\T{1}){}$\1\5 +${}\\{eq\_word\_define}(\\{int\_base}+\\{hang\_after\_code},\39\T{1});{}$\2\6 +\&{if} ${}(\\{par\_shape\_ptr}\I\\{null}){}$\1\5 +${}\\{eq\_define}(\\{par\_shape\_loc},\39\\{shape\_ref},\39\\{null});{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1071}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} $\E\hbox{$2^{30}$}$. Codes \\{box\_flag} through +$\\{box\_flag}+\T{255}$ represent `\.{\\setbox0}' through `\.{\\setbox255}'; +codes $\\{box\_flag}+\T{256}$ through $\\{box\_flag}+\T{511}$ represent `\.{\\global\\setbox0}' +through `\.{\\global\\setbox255}'; +code $\\{box\_flag}+\T{512}$ represents `\.{\\shipout}'; and codes $\\{box\_flag}+\T{513}$ +through $\\{box\_flag}+\T{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 to denote \.{\\vbox} and \.{\\hbox}, respectively. + +\Y\B\4\D$\\{box\_flag}$ \5 +\T{\~10000000000}\C{context code for `\.{\\setbox0}'}\par +\B\4\D$\\{ship\_out\_flag}$ \5 +$\\{box\_flag}+{}$\T{512}\C{context code for `\.{\\shipout}'}\par +\B\4\D$\\{leader\_flag}$ \5 +$\\{box\_flag}+{}$\T{513}\C{context code for `\.{\\leaders}'}\par +\B\4\D$\\{box\_code}$ \5 +\T{0}\C{\\{chr\_code} for `\.{\\box}'}\par +\B\4\D$\\{copy\_code}$ \5 +\T{1}\C{\\{chr\_code} for `\.{\\copy}'}\par +\B\4\D$\\{last\_box\_code}$ \5 +\T{2}\C{\\{chr\_code} for `\.{\\lastbox}'}\par +\B\4\D$\\{vsplit\_code}$ \5 +\T{3}\C{\\{chr\_code} for `\.{\\vsplit}'}\par +\B\4\D$\\{vtop\_code}$ \5 +\T{4}\C{\\{chr\_code} for `\.{\\vtop}'}\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1712:\.{"moveleft"}\X,\39\\{hmove},\39\T{1});{}$\5 +${}\\{primitive}(\X1713:\.{"moveright"}\X,\39\\{hmove},\39\T{0}){}$;\6 +${}\\{primitive}(\X1714:\.{"raise"}\X,\39\\{vmove},\39\T{1});{}$\5 +${}\\{primitive}(\X1715:\.{"lower"}\X,\39\\{vmove},\39\T{0}){}$;\7 +${}\\{primitive}(\X1437:\.{"box"}\X,\39\\{make\_box},\39\\{box\_code});{}$\5 +${}\\{primitive}(\X1716:\.{"copy"}\X,\39\\{make\_box},\39\\{copy\_code});{}$\5 +${}\\{primitive}(\X1717:\.{"lastbox"}\X,\39\\{make\_box},\39\\{last\_box\_code});{}$\5 +${}\\{primitive}(\X1687:\.{"vsplit"}\X,\39\\{make\_box},\39\\{vsplit\_code});{}$\5 +${}\\{primitive}(\X1718:\.{"vtop"}\X,\39\\{make\_box},\39\\{vtop\_code}){}$;\6 +${}\\{primitive}(\X1688:\.{"vbox"}\X,\39\\{make\_box},\39\\{vtop\_code}+\\{vmode});{}$\5 +${}\\{primitive}(\X1719:\.{"hbox"}\X,\39\\{make\_box},\39\\{vtop\_code}+\\{hmode}){}$;\6 +${}\\{primitive}(\X1720:\.{"shipout"}\X,\39\\{leader\_ship},\39\\{a\_leaders}-\T{1}){}$;\C{$\\{ship\_out\_flag}\E\\{leader\_flag}-\T{1}$}\6 +${}\\{primitive}(\X1721:\.{"leaders"}\X,\39\\{leader\_ship},\39\\{a\_leaders});{}$\5 +${}\\{primitive}(\X1722:\.{"cleaders"}\X,\39\\{leader\_ship},\39\\{c\_leaders});{}$\5 +${}\\{primitive}(\X1723:\.{"xleaders"}\X,\39\\{leader\_ship},\39\\{x\_leaders}){}$;\par +\fi + +\M{1072}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{hmove}:\6 +\&{if} ${}(\\{chr\_code}\E\T{1}){}$\1\5 +\\{print\_esc}(\X1712:\.{"moveleft"}\X);\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1713:\.{"moveright"}\X);\5 +\2\&{break};\6 +\4\&{case} \\{vmove}:\6 +\&{if} ${}(\\{chr\_code}\E\T{1}){}$\1\5 +\\{print\_esc}(\X1714:\.{"raise"}\X);\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1715:\.{"lower"}\X);\5 +\2\&{break};\6 +\4\&{case} \\{make\_box}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{box\_code}:\5 +\\{print\_esc}(\X1437:\.{"box"}\X);\5 +\&{break};\6 +\4\&{case} \\{copy\_code}:\5 +\\{print\_esc}(\X1716:\.{"copy"}\X);\5 +\&{break};\6 +\4\&{case} \\{last\_box\_code}:\5 +\\{print\_esc}(\X1717:\.{"lastbox"}\X);\5 +\&{break};\6 +\4\&{case} \\{vsplit\_code}:\5 +\\{print\_esc}(\X1687:\.{"vsplit"}\X);\5 +\&{break};\6 +\4\&{case} \\{vtop\_code}:\5 +\\{print\_esc}(\X1718:\.{"vtop"}\X);\5 +\&{break};\6 +\4\&{case} \\{vtop\_code}${}+\\{vmode}{}$:\5 +\\{print\_esc}(\X1688:\.{"vbox"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1719:\.{"hbox"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{leader\_ship}:\6 +\&{if} ${}(\\{chr\_code}\E\\{a\_leaders}){}$\1\5 +\\{print\_esc}(\X1721:\.{"leaders"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{c\_leaders}){}$\1\5 +\\{print\_esc}(\X1722:\.{"cleaders"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{x\_leaders}){}$\1\5 +\\{print\_esc}(\X1723:\.{"xleaders"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1720:\.{"shipout"}\X);\5 +\2\&{break};\par +\fi + +\M{1073}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{vmode}${}+\\{hmove}{}$:\5 +\&{case} \\{hmode}${}+\\{vmove}{}$:\5 +\&{case} \\{mmode}${}+\\{vmove}{}$:\6 +${}\{{}$\5 +\1${}\|t\K\\{cur\_chr};{}$\5 +\\{scan\_normal\_dimen};\6 +\&{if} ${}(\|t\E\T{0}){}$\1\5 +\\{scan\_box}(\\{cur\_val});\5 +\2\&{else}\1\5 +${}\\{scan\_box}({-}\\{cur\_val});{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\\{any\_mode}(\\{leader\_ship}):\5 +${}\\{scan\_box}(\\{leader\_flag}-\\{a\_leaders}+\\{cur\_chr}){}$;\5 +\&{break};\6 +\4\\{any\_mode}(\\{make\_box}):\5 +\\{begin\_box}(\T{0});\5 +\&{break};\par +\fi + +\M{1074}The global variable \\{cur\_box} will point to a newly made box. If the box +is void, we will have $\\{cur\_box}\E\\{null}$. Otherwise we will have +$\\{type}(\\{cur\_box})\E\\{hlist\_node}$ or \\{vlist\_node} or \\{rule\_node}; the \\{rule\_node} +case can occur only with leaders. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{cur\_box};\C{box to be placed into its context}\par +\fi + +\M{1075}The \\{box\_end} procedure does the right thing with \\{cur\_box}, if +\\{box\_context} represents the context as explained above. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{box\_end}(\&{int} \\{box\_context})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{\\{ord\_noad} for new box in math mode}\7 +\&{if} ${}(\\{box\_context}<\\{box\_flag}){}$\1\5 +\X1076:Append box \\{cur\_box} to the current list, shifted by \\{box\_context}\X\2\6 +\&{else} \&{if} ${}(\\{box\_context}<\\{ship\_out\_flag}){}$\1\5 +\X1077:Store \(c)\\{cur\_box} in a box register\X;\2\6 +\&{else} \&{if} ${}(\\{cur\_box}\I\\{null}){}$\1\6 +\&{if} ${}(\\{box\_context}>\\{ship\_out\_flag}){}$\1\5 +\X1078:Append a new leader node that uses \\{cur\_box}\X\2\6 +\&{else}\1\5 +\\{ship\_out}(\\{cur\_box});\2\2\6 +\4${}\}{}$\2\par +\fi + +\M{1076}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\B\4\X1076:Append box \\{cur\_box} to the current list, shifted by \\{box\_context}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_box}\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\\{shift\_amount}(\\{cur\_box})\K\\{box\_context};{}$\6 +\&{if} ${}(\\{abs}(\\{mode})\E\\{vmode}){}$\5 +${}\{{}$\5 +\1\\{append\_to\_vlist}(\\{cur\_box});\6 +\&{if} ${}(\\{adjust\_tail}\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{adjust\_head}\I\\{adjust\_tail}){}$\5 +${}\{{}$\5 +\1${}\\{link}(\\{tail})\K\\{link}(\\{adjust\_head});{}$\5 +${}\\{tail}\K\\{adjust\_tail};{}$\6 +\4${}\}{}$\2\6 +${}\\{adjust\_tail}\K\\{null};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{mode}>\T{0}){}$\1\5 +\\{build\_page}(\,);\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{abs}(\\{mode})\E\\{hmode}){}$\1\5 +${}\\{space\_factor}\K\T{1000};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +${}\\{link}(\\{tail})\K\\{cur\_box};{}$\5 +${}\\{tail}\K\\{cur\_box};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1075.\fi + +\M{1077}\B\X1077:Store \(c)\\{cur\_box} in a box register\X${}\E{}$\6 +\&{if} ${}(\\{box\_context}<\\{box\_flag}+\T{256}){}$\1\5 +${}\\{eq\_define}(\\{box\_base}-\\{box\_flag}+\\{box\_context},\39\\{box\_ref},\39\\{cur\_box});{}$\2\6 +\&{else} $\\{geq\_define}(\\{box\_base}-\\{box\_flag}-\T{256}+\\{box\_context},\39\\{box\_ref},\39\\{cur\_box}{}$)\par +\U1075.\fi + +\M{1078}\B\X1078:Append a new leader node that uses \\{cur\_box}\X${}\E{}$\6 +${}\{{}$\5 +\1\X404:Get the next non-blank non-relax non-call token\X;\6 +\&{if} ${}(((\\{cur\_cmd}\E\\{hskip})\W(\\{abs}(\\{mode})\I\\{vmode}))\V\30((\\{cur\_cmd}\E\\{vskip})\W(\\{abs}(\\{mode})\E\\{vmode}))){}$\5 +${}\{{}$\5 +\1\\{append\_glue}(\,);\5 +${}\\{subtype}(\\{tail})\K\\{box\_context}-(\\{leader\_flag}-\\{a\_leaders});{}$\5 +${}\\{leader\_ptr}(\\{tail})\K\\{cur\_box};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Leaders\ not\ followe}\)\.{d\ by\ proper\ glue"});\5 +\\{help3}(\.{"You\ should\ say\ `\\\\l}\)\.{eaders\ <box\ or\ rule>}\)\.{<hskip\ or\ vskip>'."})\6 +(\.{"I\ found\ the\ <box\ or}\)\.{\ rule>,\ but\ there's\ }\)\.{no\ suitable"})\6 +(\.{"<hskip\ or\ vskip>,\ s}\)\.{o\ I'm\ ignoring\ these}\)\.{\ leaders."});\5 +\\{back\_error}(\,);\5 +\\{flush\_node\_list}(\\{cur\_box});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1075.\fi + +\M{1079}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}\E\\{make\_box}$. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{begin\_box}(\&{int} \\{box\_context})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|q;\C{run through the current list}\6 +\&{int} \|m;\C{the length of a replacement list}\6 +\&{halfword} \|k;\C{0 or \\{vmode} or \\{hmode}}\6 +\&{eight\_bits} \|n;\C{a box number}\7 +\&{switch} (\\{cur\_chr})\5 +${}\{{}$\1\6 +\4\&{case} \\{box\_code}:\6 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{copy\_code}:\6 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\5 +${}\\{cur\_box}\K\\{copy\_node\_list}(\\{box}(\\{cur\_val}));{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{last\_box\_code}:\5 +\X1080: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\5 +\&{break};\6 +\4\&{case} \\{vsplit\_code}:\5 +\X1082:Split off part of a vertical box, make \\{cur\_box} point to it\X\5 +\&{break};\6 +\4\&{default}:\5 +\X1083:Initiate the construction of an hbox or vbox, then \&{return}\X\6 +\4${}\}{}$\2\6 +\\{box\_end}(\\{box\_context});\C{in simple cases, we use the box immediately}\6 +\4${}\}{}$\2\par +\fi + +\M{1080}Note that the condition $\R\\{is\_char\_node}(\\{tail})$ implies that $\\{head}\I\\{tail}$, +since \\{head} is a one-word node. + +\Y\B\4\X1080: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${}\E{}$\6 +${}\{{}$\5 +\1${}\\{cur\_box}\K\\{null};{}$\6 +\&{if} ${}(\\{abs}(\\{mode})\E\\{mmode}){}$\5 +${}\{{}$\5 +\1\\{you\_cant}(\,);\5 +\\{help1}(\.{"Sorry;\ this\ \\\\lastb}\)\.{ox\ will\ be\ void."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}((\\{mode}\E\\{vmode})\W(\\{head}\E\\{tail})){}$\5 +${}\{{}$\5 +\1\\{you\_cant}(\,);\5 +\\{help2}(\.{"Sorry...I\ usually\ c}\)\.{an't\ take\ things\ fro}\)\.{m\ the\ current\ page."})\6 +(\.{"This\ \\\\lastbox\ will}\)\.{\ therefore\ be\ void."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\R\\{is\_char\_node}(\\{tail})){}$\1\6 +\&{if} ${}((\\{type}(\\{tail})\E\\{hlist\_node})\V(\\{type}(\\{tail})\E\\{vlist\_node})){}$\1\5 +\X1081:Remove the last box, unless it's part of a discretionary\X;\2\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1079.\fi + +\M{1081}\B\X1081:Remove the last box, unless it's part of a discretionary\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|q\K\\{head}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|p\K\|q;{}$\6 +\&{if} ${}(\R\\{is\_char\_node}(\|q)){}$\1\6 +\&{if} ${}(\\{type}(\|q)\E\\{disc\_node}){}$\5 +${}\{{}$\5 +\1\&{for} ${}(\|m\K\T{1};{}$ ${}\|m\Z\\{replace\_count}(\|q);{}$ ${}\|m\PP){}$\1\5 +${}\|p\K\\{link}(\|p);{}$\2\6 +\&{if} ${}(\|p\E\\{tail}){}$\1\5 +\&{goto} \\{done};\2\6 +\4${}\}{}$\2\2\6 +${}\|q\K\\{link}(\|p);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|q\E\\{tail}));{}$\5 +${}\\{cur\_box}\K\\{tail};{}$\5 +${}\\{shift\_amount}(\\{cur\_box})\K\T{0};{}$\5 +${}\\{tail}\K\|p;{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\6 +\4\\{done}:\5 +;\6 +\4${}\}{}$\2\par +\U1080.\fi + +\M{1082}Here we deal with things like `\.{\\vsplit 13 to 100pt}'. + +\Y\B\4\X1082:Split off part of a vertical box, make \\{cur\_box} point to it\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\5 +${}\|n\K\\{cur\_val};{}$\6 +\&{if} ${}(\R\\{scan\_keyword}(\X1642:\.{"to"}\X)){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ `to'\ insert}\)\.{ed"});\5 +\\{help2}(\.{"I'm\ working\ on\ `\\\\v}\)\.{split<box\ number>\ to}\)\.{\ <dimen>';"})\6 +(\.{"will\ look\ for\ the\ <}\)\.{dimen>\ next."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\\{scan\_normal\_dimen};\5 +${}\\{cur\_box}\K\\{vsplit}(\|n,\39\\{cur\_val});{}$\6 +\4${}\}{}$\2\par +\U1079.\fi + +\M{1083}Here is where we enter restricted horizontal mode or internal vertical +mode, in order to make a box. + +\Y\B\4\X1083:Initiate the construction of an hbox or vbox, then \&{return}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|k\K\\{cur\_chr}-\\{vtop\_code};{}$\5 +${}\\{saved}(\T{0})\K\\{box\_context};{}$\6 +\&{if} ${}(\|k\E\\{hmode}){}$\1\6 +\&{if} ${}((\\{box\_context}<\\{box\_flag})\W(\\{abs}(\\{mode})\E\\{vmode})){}$\1\5 +${}\\{scan\_spec}(\\{adjusted\_hbox\_group},\39\\{true});{}$\2\6 +\&{else}\1\5 +${}\\{scan\_spec}(\\{hbox\_group},\39\\{true});{}$\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\|k\E\\{vmode}){}$\1\5 +${}\\{scan\_spec}(\\{vbox\_group},\39\\{true});{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{scan\_spec}(\\{vtop\_group},\39\\{true});{}$\5 +${}\|k\K\\{vmode};{}$\6 +\4${}\}{}$\2\6 +\\{normal\_paragraph}(\,);\6 +\4${}\}{}$\2\6 +\\{push\_nest}(\,);\5 +${}\\{mode}\K{-}\|k;{}$\6 +\&{if} ${}(\|k\E\\{vmode}){}$\5 +${}\{{}$\5 +\1${}\\{prev\_depth}\K\\{ignore\_depth};{}$\6 +\&{if} ${}(\\{every\_vbox}\I\\{null}){}$\1\5 +${}\\{begin\_token\_list}(\\{every\_vbox},\39\\{every\_vbox\_text});{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{space\_factor}\K\T{1000};{}$\6 +\&{if} ${}(\\{every\_hbox}\I\\{null}){}$\1\5 +${}\\{begin\_token\_list}(\\{every\_hbox},\39\\{every\_hbox\_text});{}$\2\6 +\4${}\}{}$\2\6 +\&{return};\6 +\4${}\}{}$\2\par +\U1079.\fi + +\M{1084}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{scan\_box}(\&{int} \\{box\_context})\C{the next input should specify a box or perhaps a rule}\6 +${}\{{}$\5 +\1\X404:Get the next non-blank non-relax non-call token\X;\6 +\&{if} ${}(\\{cur\_cmd}\E\\{make\_box}){}$\1\5 +\\{begin\_box}(\\{box\_context});\2\6 +\&{else} \&{if} ${}((\\{box\_context}\G\\{leader\_flag})\W((\\{cur\_cmd}\E\\{hrule})\V(\\{cur\_cmd}\E\\{vrule}))){}$\5 +${}\{{}$\5 +\1${}\\{cur\_box}\K\\{scan\_rule\_spec}(\,);{}$\5 +\\{box\_end}(\\{box\_context});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\hbox{}\6 +\\{print\_err}(\.{"A\ <box>\ was\ suppose}\)\.{d\ 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\ ke}\)\.{ep\ trying;\ you\ can\ f}\)\.{ix\ this\ later."});\5 +\\{back\_error}(\,);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1085}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\B\4\X1085:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X${}\E{}$\6 +\4\&{case} \\{hbox\_group}:\5 +\\{package}(\T{0});\5 +\&{break};\6 +\4\&{case} \\{adjusted\_hbox\_group}:\6 +${}\{{}$\5 +\1${}\\{adjust\_tail}\K\\{adjust\_head};{}$\5 +\\{package}(\T{0});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{vbox\_group}:\6 +${}\{{}$\5 +\1\\{end\_graf}(\,);\5 +\\{package}(\T{0});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{vtop\_group}:\6 +${}\{{}$\5 +\1\\{end\_graf}(\,);\5 +\\{package}(\\{vtop\_code});\6 +\4${}\}{}$\5 +\2\&{break};\par +\As1100, 1118, 1132, 1133, 1168, 1173\ETs1186. +\U1068.\fi + +\M{1086}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{package}(\&{small\_number} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{scaled} \|h;\C{height of box}\6 +\&{pointer} \|p;\C{first node in a box}\6 +\&{scaled} \|d;\C{max depth}\7 +${}\|d\K\\{box\_max\_depth};{}$\5 +\\{unsave}(\,);\5 +${}\\{save\_ptr}\K\\{save\_ptr}-\T{3};{}$\6 +\&{if} ${}(\\{mode}\E{-}\\{hmode}){}$\1\5 +${}\\{cur\_box}\K\\{hpack}(\\{link}(\\{head}),\39\\{saved}(\T{2}),\39\\{saved}(\T{1}));{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{cur\_box}\K\\{vpackage}(\\{link}(\\{head}),\39\\{saved}(\T{2}),\39\\{saved}(\T{1}),\39\|d);{}$\6 +\&{if} ${}(\|c\E\\{vtop\_code}){}$\1\5 +\X1087:Readjust the height and depth of \\{cur\_box}, for \.{\\vtop}\X;\2\6 +\4${}\}{}$\2\6 +\\{pop\_nest}(\,);\5 +\\{box\_end}(\\{saved}(\T{0}));\6 +\4${}\}{}$\2\par +\fi + +\M{1087}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\B\4\X1087:Readjust the height and depth of \\{cur\_box}, for \.{\\vtop}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|h\K\T{0};{}$\5 +${}\|p\K\\{list\_ptr}(\\{cur\_box});{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\1\6 +\&{if} ${}(\\{type}(\|p)\Z\\{rule\_node}){}$\1\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 +\4${}\}{}$\2\par +\U1086.\fi + +\M{1088}A paragraph begins when horizontal-mode material occurs in vertical mode, +or when the paragraph is explicitly started by `\.{\\indent}' or +`\.{\\noindent}'. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1724:\.{"indent"}\X,\39\\{start\_par},\39\T{1});{}$\5 +${}\\{primitive}(\X1725:\.{"noindent"}\X,\39\\{start\_par},\39\T{0}){}$;\par +\fi + +\M{1089}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{start\_par}:\6 +\&{if} ${}(\\{chr\_code}\E\T{0}){}$\1\5 +\\{print\_esc}(\X1725:\.{"noindent"}\X);\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1724:\.{"indent"}\X);\5 +\2\&{break};\par +\fi + +\M{1090}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{vmode}${}+\\{start\_par}{}$:\5 +${}\\{new\_graf}(\\{cur\_chr}>\T{0}){}$;\5 +\&{break};\6 +\4\&{case} \\{vmode}${}+\\{letter}{}$:\5 +\&{case} \\{vmode}${}+\\{other\_char}{}$:\5 +\&{case} \\{vmode}${}+\\{char\_num}{}$:\5 +\&{case} \\{vmode}${}+\\{char\_given}{}$:\5 +\&{case} \\{vmode}${}+\\{math\_shift}{}$:\5 +\&{case} \\{vmode}${}+\\{un\_hbox}{}$:\5 +\&{case} \\{vmode}${}+\\{vrule}{}$:\5 +\&{case} \\{vmode}${}+\\{accent}{}$:\5 +\&{case} \\{vmode}${}+\\{discretionary}{}$:\5 +\&{case} \\{vmode}${}+\\{hskip}{}$:\5 +\&{case} \\{vmode}${}+\\{valign}{}$:\5 +\&{case} \\{vmode}${}+\\{ex\_space}{}$:\5 +\&{case} \\{vmode}${}+\\{no\_boundary}{}$:\5 +\hbox{}\6 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +\\{new\_graf}(\\{true});\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1091}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{small\_number} \\{norm\_min}(\&{int} \|h)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\|h\Z\T{0}){}$\1\5 +\&{return} \T{1};\5 +\2\&{else} \&{if} ${}(\|h\G\T{63}){}$\1\5 +\&{return} \T{63};\5 +\2\&{else}\1\5 +\&{return} \|h;\2\6 +\4${}\}{}$\2\7 +\&{void} \\{new\_graf}(\&{bool} \\{indented})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{prev\_graf}\K\T{0};{}$\6 +\&{if} ${}((\\{mode}\E\\{vmode})\V(\\{head}\I\\{tail})){}$\1\5 +\\{tail\_append}(\\{new\_param\_glue}(\\{par\_skip\_code}));\2\6 +\\{push\_nest}(\,);\5 +${}\\{mode}\K\\{hmode};{}$\5 +${}\\{space\_factor}\K\T{1000};{}$\5 +\\{set\_cur\_lang};\5 +${}\\{clang}\K\\{cur\_lang};{}$\5 +${}\\{prev\_graf}\K(\\{norm\_min}(\\{left\_hyphen\_min})*\T{\~100}+\\{norm\_min}(\\{right\_hyphen\_min}))*\T{\~200000}+\\{cur\_lang};{}$\6 +\&{if} (\\{indented})\5 +${}\{{}$\5 +\1${}\\{tail}\K\\{new\_null\_box}(\,);{}$\5 +${}\\{link}(\\{head})\K\\{tail};{}$\5 +${}\\{width}(\\{tail})\K\\{par\_indent}{}$;\5 +${}\}{}$\2\6 +\&{if} ${}(\\{every\_par}\I\\{null}){}$\1\5 +${}\\{begin\_token\_list}(\\{every\_par},\39\\{every\_par\_text});{}$\2\6 +\&{if} ${}(\\{nest\_ptr}\E\T{1}){}$\1\5 +\\{build\_page}(\,);\C{put \\{par\_skip} glue on current page}\2\6 +\4${}\}{}$\2\par +\fi + +\M{1092}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{hmode}${}+\\{start\_par}{}$:\5 +\&{case} \\{mmode}${}+\\{start\_par}{}$:\5 +\\{indent\_in\_hmode}(\,);\5 +\&{break};\par +\fi + +\M{1093}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{indent\_in\_hmode}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|q;\7 +\&{if} ${}(\\{cur\_chr}>\T{0}{}$)\C{\.{\\indent}}\6 +${}\{{}$\5 +\1${}\|p\K\\{new\_null\_box}(\,);{}$\5 +${}\\{width}(\|p)\K\\{par\_indent};{}$\6 +\&{if} ${}(\\{abs}(\\{mode})\E\\{hmode}){}$\1\5 +${}\\{space\_factor}\K\T{1000};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{new\_noad}(\,);{}$\5 +${}\\{math\_type}(\\{nucleus}(\|q))\K\\{sub\_box};{}$\5 +${}\\{info}(\\{nucleus}(\|q))\K\|p;{}$\5 +${}\|p\K\|q;{}$\6 +\4${}\}{}$\2\6 +\\{tail\_append}(\|p);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1094}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{vmode}${}+\\{par\_end}{}$:\6 +${}\{{}$\5 +\1\\{normal\_paragraph}(\,);\6 +\&{if} ${}(\\{mode}>\T{0}){}$\1\5 +\\{build\_page}(\,);\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{hmode}${}+\\{par\_end}{}$:\6 +${}\{{}$\5 +\1\&{if} ${}(\\{align\_state}<\T{0}){}$\1\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}>\T{0}$}\6 +\&{if} ${}(\\{mode}\E\\{vmode}){}$\1\5 +\\{build\_page}(\,);\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{hmode}${}+\\{stop}{}$:\5 +\&{case} \\{hmode}${}+\\{vskip}{}$:\5 +\&{case} \\{hmode}${}+\\{hrule}{}$:\5 +\&{case} \\{hmode}${}+\\{un\_vbox}{}$:\5 +\&{case} \\{hmode}${}+\\{halign}{}$:\5 +\\{head\_for\_vmode}(\,);\5 +\&{break};\par +\fi + +\M{1095}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{head\_for\_vmode}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{mode}<\T{0}){}$\1\6 +\&{if} ${}(\\{cur\_cmd}\I\\{hrule}){}$\1\5 +\\{off\_save}(\,);\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"You\ can't\ use\ `"});\5 +\\{print\_esc}(\X1543:\.{"hrule"}\X);\5 +\\{print\_str}(\.{"'\ here\ except\ with\ }\)\.{leaders"});\5 +\\{help2}(\.{"To\ put\ a\ horizontal}\)\.{\ rule\ in\ an\ hbox\ or\ }\)\.{an\ alignment,"})\6 +(\.{"you\ should\ use\ \\\\le}\)\.{aders\ or\ \\\\hrulefill}\)\.{\ (see\ The\ TeXbook)."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +${}\\{cur\_tok}\K\\{par\_token};{}$\5 +\\{back\_input}(\,);\5 +${}\\{token\_type}\K\\{inserted};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1096}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{end\_graf}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{mode}\E\\{hmode}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{head}\E\\{tail}){}$\1\5 +\\{pop\_nest}(\,);\C{null paragraphs are ignored}\2\6 +\&{else}\1\5 +\\{line\_break}(\\{widow\_penalty});\2\6 +\\{normal\_paragraph}(\,);\5 +${}\\{error\_count}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1097}Insertion and adjustment and mark nodes are constructed by the following +pieces of the program. + +\Y\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{insert}):\5 +\&{case} \\{hmode}${}+\\{vadjust}{}$:\5 +\&{case} \\{mmode}${}+\\{vadjust}{}$:\5 +\\{begin\_insert\_or\_adjust}(\,);\5 +\&{break};\6 +\4\\{any\_mode}(\\{mark}):\5 +\\{make\_mark}(\,);\5 +\&{break};\par +\fi + +\M{1098}\B\X1048:Forbidden cases detected in \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{case} \\{vmode}${}+\\{vadjust}{}$:\par +\fi + +\M{1099}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{begin\_insert\_or\_adjust}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_cmd}\E\\{vadjust}){}$\1\5 +${}\\{cur\_val}\K\T{255};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\6 +\&{if} ${}(\\{cur\_val}\E\T{255}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"You\ can't\ "});\5 +\\{print\_esc}(\X1390:\.{"insert"}\X);\5 +\\{print\_int}(\T{255});\5 +\\{help1}(\.{"I'm\ changing\ to\ \\\\i}\)\.{nsert0;\ box\ 255\ is\ s}\)\.{pecial."});\6 +\&{error} (\,)\1\5 +;\2\6 +${}\\{cur\_val}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +${}\\{saved}(\T{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 +${}\\{prev\_depth}\K\\{ignore\_depth};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{1100}\B\X1085:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X${}\mathrel+\E{}$\6 +\4\&{case} \\{insert\_group}:\6 +${}\{{}$\5 +\1\\{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}(\T{0}) is the insertion number, or 255 for \\{vadjust}}\6 +${}\|p\K\\{vpack}(\\{link}(\\{head}),\39\\{natural});{}$\5 +\\{pop\_nest}(\,);\6 +\&{if} ${}(\\{saved}(\T{0})<\T{255}){}$\5 +${}\{{}$\5 +\1\\{tail\_append}(\\{get\_node}(\\{ins\_node\_size}));\5 +${}\\{type}(\\{tail})\K\\{ins\_node};{}$\5 +${}\\{subtype}(\\{tail})\K\\{qi}(\\{saved}(\T{0}));{}$\5 +${}\\{height}(\\{tail})\K\\{height}(\|p)+\\{depth}(\|p);{}$\5 +${}\\{ins\_ptr}(\\{tail})\K\\{list\_ptr}(\|p);{}$\5 +${}\\{split\_top\_ptr}(\\{tail})\K\|q;{}$\5 +${}\\{depth}(\\{tail})\K\|d;{}$\5 +${}\\{float\_cost}(\\{tail})\K\|f;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{tail\_append}(\\{get\_node}(\\{small\_node\_size}));\5 +${}\\{type}(\\{tail})\K\\{adjust\_node}{}$;\6 +${}\\{subtype}(\\{tail})\K\T{0}{}$;\C{the \\{subtype} is not used}\6 +${}\\{adjust\_ptr}(\\{tail})\K\\{list\_ptr}(\|p);{}$\5 +\\{delete\_glue\_ref}(\|q);\6 +\4${}\}{}$\2\6 +${}\\{free\_node}(\|p,\39\\{box\_node\_size});{}$\6 +\&{if} ${}(\\{nest\_ptr}\E\T{0}){}$\1\5 +\\{build\_page}(\,);\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{output\_group}:\5 +\X1026:Resume the page builder after an output routine has come to an end\X\5 +\&{break};\par +\fi + +\M{1101}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{make\_mark}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{new node}\7 +${}\|p\K\\{scan\_toks}(\\{false},\39\\{true});{}$\5 +${}\|p\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{type}(\|p)\K\\{mark\_node};{}$\5 +${}\\{subtype}(\|p)\K\T{0}{}$;\C{the \\{subtype} is not used}\6 +${}\\{mark\_ptr}(\|p)\K\\{def\_ref};{}$\5 +${}\\{link}(\\{tail})\K\|p;{}$\5 +${}\\{tail}\K\|p;{}$\6 +\4${}\}{}$\2\par +\fi + +\M{1102}Penalty nodes get into a list via the \\{break\_penalty} command. + +\Y\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{break\_penalty}):\5 +\\{append\_penalty}(\,);\5 +\&{break};\par +\fi + +\M{1103}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{append\_penalty}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{scan\_int}(\,);\5 +\\{tail\_append}(\\{new\_penalty}(\\{cur\_val}));\6 +\&{if} ${}(\\{mode}\E\\{vmode}){}$\1\5 +\\{build\_page}(\,);\2\6 +\4${}\}{}$\2\par +\fi + +\M{1104}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{remove\_item}):\5 +\\{delete\_last}(\,);\5 +\&{break};\par +\fi + +\M{1105}When \\{delete\_last} is called, \\{cur\_chr} is the \\{type} of node that +will be deleted, if present. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{delete\_last}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|q;\C{run through the current list}\6 +\&{int} \|m;\C{the length of a replacement list}\7 +\&{if} ${}((\\{mode}\E\\{vmode})\W(\\{tail}\E\\{head})){}$\1\5 +\X1106:Apologize for inability to do the operation now, unless \.{\\unskip} follows non-glue\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\R\\{is\_char\_node}(\\{tail})){}$\1\6 +\&{if} ${}(\\{type}(\\{tail})\E\\{cur\_chr}){}$\5 +${}\{{}$\5 +\1${}\|q\K\\{head}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|p\K\|q;{}$\6 +\&{if} ${}(\R\\{is\_char\_node}(\|q)){}$\1\6 +\&{if} ${}(\\{type}(\|q)\E\\{disc\_node}){}$\5 +${}\{{}$\5 +\1\&{for} ${}(\|m\K\T{1};{}$ ${}\|m\Z\\{replace\_count}(\|q);{}$ ${}\|m\PP){}$\1\5 +${}\|p\K\\{link}(\|p);{}$\2\6 +\&{if} ${}(\|p\E\\{tail}){}$\1\5 +\&{return};\2\6 +\4${}\}{}$\2\2\6 +${}\|q\K\\{link}(\|p);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|q\E\\{tail}));{}$\5 +${}\\{link}(\|p)\K\\{null};{}$\5 +\\{flush\_node\_list}(\\{tail});\5 +${}\\{tail}\K\|p;{}$\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1106}\B\X1106:Apologize for inability to do the operation now, unless \.{\\unskip} follows non-glue\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}((\\{cur\_chr}\I\\{glue\_node})\V(\\{last\_glue}\I\\{max\_halfword})){}$\5 +${}\{{}$\5 +\1\\{you\_cant}(\,);\5 +\\{help2}(\.{"Sorry...I\ usually\ c}\)\.{an't\ take\ things\ fro}\)\.{m\ the\ current\ page."})\6 +(\.{"Try\ `I\\\\vskip-\\\\las}\)\.{tskip'\ instead."});\6 +\&{if} ${}(\\{cur\_chr}\E\\{kern\_node}){}$\1\5 +${}\\{help\_line}[\T{0}]\K(\.{"Try\ `I\\\\kern-\\\\last}\)\.{kern'\ instead."});{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_chr}\I\\{glue\_node}){}$\1\5 +${}\\{help\_line}[\T{0}]\K\30(\.{"Perhaps\ you\ can\ mak}\)\.{e\ the\ output\ routine}\)\.{\ do\ it."});{}$\2\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1105.\fi + +\M{1107}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1726:\.{"unpenalty"}\X,\39\\{remove\_item},\39\\{penalty\_node}){}$;\6 +${}\\{primitive}(\X1727:\.{"unkern"}\X,\39\\{remove\_item},\39\\{kern\_node}){}$;\6 +${}\\{primitive}(\X1728:\.{"unskip"}\X,\39\\{remove\_item},\39\\{glue\_node}){}$;\6 +${}\\{primitive}(\X1729:\.{"unhbox"}\X,\39\\{un\_hbox},\39\\{box\_code}){}$;\6 +${}\\{primitive}(\X1730:\.{"unhcopy"}\X,\39\\{un\_hbox},\39\\{copy\_code}){}$;\6 +${}\\{primitive}(\X1731:\.{"unvbox"}\X,\39\\{un\_vbox},\39\\{box\_code}){}$;\6 +${}\\{primitive}(\X1732:\.{"unvcopy"}\X,\39\\{un\_vbox},\39\\{copy\_code}){}$;\par +\fi + +\M{1108}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{remove\_item}:\6 +\&{if} ${}(\\{chr\_code}\E\\{glue\_node}){}$\1\5 +\\{print\_esc}(\X1728:\.{"unskip"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{kern\_node}){}$\1\5 +\\{print\_esc}(\X1727:\.{"unkern"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1726:\.{"unpenalty"}\X);\5 +\2\&{break};\6 +\4\&{case} \\{un\_hbox}:\6 +\&{if} ${}(\\{chr\_code}\E\\{copy\_code}){}$\1\5 +\\{print\_esc}(\X1730:\.{"unhcopy"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1729:\.{"unhbox"}\X);\5 +\2\&{break};\6 +\4\&{case} \\{un\_vbox}:\6 +\&{if} ${}(\\{chr\_code}\E\\{copy\_code}){}$\1\5 +\\{print\_esc}(\X1732:\.{"unvcopy"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1731:\.{"unvbox"}\X);\5 +\2\&{break};\par +\fi + +\M{1109}The \\{un\_hbox} and \\{un\_vbox} commands unwrap one of the 256 current boxes. + +\Y\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{vmode}${}+\\{un\_vbox}{}$:\5 +\&{case} \\{hmode}${}+\\{un\_hbox}{}$:\5 +\&{case} \\{mmode}${}+\\{un\_hbox}{}$:\5 +\\{unpackage}(\,);\5 +\&{break};\par +\fi + +\M{1110}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{unpackage}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the box}\6 +\&{uint8\_t} \|c;\C{should we copy?}\7 +${}\|c\K\\{cur\_chr};{}$\5 +\\{scan\_eight\_bit\_int}(\,);\5 +${}\|p\K\\{box}(\\{cur\_val});{}$\6 +\&{if} ${}(\|p\E\\{null}){}$\1\5 +\&{return};\2\6 +\&{if} ${}((\\{abs}(\\{mode})\E\\{mmode})\V((\\{abs}(\\{mode})\E\\{vmode})\W(\\{type}(\|p)\I\\{vlist\_node}))\V\30((\\{abs}(\\{mode})\E\\{hmode})\W(\\{type}(\|p)\I\\{hlist\_node}))){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Incompatible\ list\ c}\)\.{an't\ be\ unboxed"});\5 +\\{help3}(\.{"Sorry,\ Pandora.\ (Yo}\)\.{u\ sneaky\ devil.)"})\6 +(\.{"I\ refuse\ to\ unbox\ a}\)\.{n\ \\\\hbox\ in\ vertical}\)\.{\ mode\ or\ vice\ versa.}\)\.{"})\6 +(\.{"And\ I\ can't\ open\ an}\)\.{y\ boxes\ in\ math\ mode}\)\.{."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{return};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|c\E\\{copy\_code}){}$\1\5 +${}\\{link}(\\{tail})\K\\{copy\_node\_list}(\\{list\_ptr}(\|p));{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{link}(\\{tail})\K\\{list\_ptr}(\|p);{}$\5 +${}\\{box}(\\{cur\_val})\K\\{null};{}$\5 +${}\\{free\_node}(\|p,\39\\{box\_node\_size});{}$\6 +\4${}\}{}$\2\6 +\&{while} ${}(\\{link}(\\{tail})\I\\{null}){}$\1\5 +${}\\{tail}\K\\{link}(\\{tail});{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1111}\B\X1048:Forbidden cases detected in \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{case} \\{vmode}${}+\\{ital\_corr}{}$:\par +\fi + +\M{1112}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{hmode}${}+\\{ital\_corr}{}$:\5 +\\{append\_italic\_correction}(\,);\5 +\&{break};\6 +\4\&{case} \\{mmode}${}+\\{ital\_corr}{}$:\5 +\\{tail\_append}(\\{new\_kern}(\T{0}))\5 +\&{break};\par +\fi + +\M{1113}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{append\_italic\_correction}(\&{void})\1\1 $\{{}$\5 +\&{pointer} \|p;\C{\\{char\_node} at the tail of the current list}\6 +\&{internal\_font\_number} \|f;\C{the font in the \\{char\_node}}\6 +\&{if} ${}(\\{tail}\I\\{head})$ $\{{}$\5 +\&{if} (\\{is\_char\_node}(\\{tail}))\1\5 +${}\|p\K\\{tail};{}$\2\6 +\&{else} \&{if} ${}(\\{type}(\\{tail})\E\\{ligature\_node}){}$\1\5 +${}\|p\K\\{lig\_char}(\\{tail});{}$\2\6 +\&{else}\1\5 +\&{return};\2\6 +${}\|f\K\\{font}(\|p);{}$\5 +\\{tail\_append}(\\{new\_kern}(\\{char\_italic}(\|f)(\\{char\_info}(\|f)(\\{character}(\|p))))); \\{subtype}(\\{tail}) $\K$ \&{explicit}; $\}$ $\}{}$\par +\fi + +\M{1114}Discretionary nodes are easy in the common case `\.{\\-}', but in the +general case we must process three braces full of items. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\.{'-'},\39\\{discretionary},\39\T{1});{}$\5 +${}\\{primitive}(\X1400:\.{"discretionary"}\X,\39\\{discretionary},\39\T{0}){}$;\par +\fi + +\M{1115}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{discretionary}:\6 +\&{if} ${}(\\{chr\_code}\E\T{1}){}$\1\5 +\\{print\_esc}(\.{'-'});\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1400:\.{"discretionary"}\X);\5 +\2\&{break};\par +\fi + +\M{1116}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{hmode}${}+\\{discretionary}{}$:\5 +\&{case} \\{mmode}${}+\\{discretionary}{}$:\5 +\\{append\_discretionary}(\,);\5 +\&{break};\par +\fi + +\M{1117}The space factor does not change when we append a discretionary node, +but it starts out as 1000 in the subsidiary lists. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{append\_discretionary}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|c;\C{hyphen character}\7 +\\{tail\_append}(\\{new\_disc}(\,));\6 +\&{if} ${}(\\{cur\_chr}\E\T{1}){}$\5 +${}\{{}$\5 +\1${}\|c\K\\{hyphen\_char}[\\{cur\_font}];{}$\6 +\&{if} ${}(\|c\G\T{0}){}$\1\6 +\&{if} ${}(\|c<\T{256}){}$\1\5 +${}\\{pre\_break}(\\{tail})\K\\{new\_character}(\\{cur\_font},\39\|c);{}$\2\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{incr}(\\{save\_ptr});\5 +${}\\{saved}({-}\T{1})\K\T{0};{}$\5 +\\{new\_save\_level}(\\{disc\_group});\5 +\\{scan\_left\_brace}(\,);\5 +\\{push\_nest}(\,);\5 +${}\\{mode}\K{-}\\{hmode};{}$\5 +${}\\{space\_factor}\K\T{1000};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1118}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\B\4\X1085:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X${}\mathrel+\E{}$\6 +\4\&{case} \\{disc\_group}:\5 +\\{build\_discretionary}(\,);\5 +\&{break};\par +\fi + +\M{1119}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{build\_discretionary}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p${},{}$ \|q;\C{for link manipulation}\6 +\&{int} \|n;\C{length of discretionary list}\7 +\\{unsave}(\,);\5 +\X1121: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 +\&{switch} ${}(\\{saved}({-}\T{1})){}$\5 +${}\{{}$\1\6 +\4\&{case} \T{0}:\5 +${}\\{pre\_break}(\\{tail})\K\|p{}$;\5 +\&{break};\6 +\4\&{case} \T{1}:\5 +${}\\{post\_break}(\\{tail})\K\|p{}$;\5 +\&{break};\6 +\4\&{case} \T{2}:\5 +\X1120:Attach list \|p to the current list, and record its length; then finish up and \&{return}\X;\6 +\4${}\}{}$\C{there are no other cases}\2\6 +${}\\{incr}(\\{saved}({-}\T{1}));{}$\5 +\\{new\_save\_level}(\\{disc\_group});\5 +\\{scan\_left\_brace}(\,);\5 +\\{push\_nest}(\,);\5 +${}\\{mode}\K{-}\\{hmode};{}$\5 +${}\\{space\_factor}\K\T{1000};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{1120}\B\X1120:Attach list \|p to the current list, and record its length; then finish up and \&{return}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}((\|n>\T{0})\W(\\{abs}(\\{mode})\E\\{mmode})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Illegal\ math\ "});\5 +\\{print\_esc}(\X1400:\.{"discretionary"}\X);\5 +\\{help2}(\.{"Sorry:\ The\ third\ pa}\)\.{rt\ of\ a\ discretionar}\)\.{y\ break\ must\ be"})\6 +(\.{"empty,\ in\ math\ form}\)\.{ulas.\ I\ had\ to\ delet}\)\.{e\ your\ third\ part."});\5 +\\{flush\_node\_list}(\|p);\5 +${}\|n\K\T{0};{}$\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{link}(\\{tail})\K\|p;{}$\2\6 +\&{if} ${}(\|n\Z\\{max\_quarterword}){}$\1\5 +${}\\{replace\_count}(\\{tail})\K\|n;{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Discretionary\ list\ }\)\.{is\ too\ long"});\5 +\\{help2}(\.{"Wow---I\ never\ thoug}\)\.{ht\ anybody\ would\ twe}\)\.{ak\ me\ here."})\6 +(\.{"You\ can't\ seriously}\)\.{\ need\ such\ a\ huge\ di}\)\.{scretionary\ list?"});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|n>\T{0}){}$\1\5 +${}\\{tail}\K\|q;{}$\2\6 +\\{decr}(\\{save\_ptr});\5 +\&{return};\6 +\4${}\}{}$\2\par +\U1119.\fi + +\M{1121}During this loop, $\|p\E\\{link}(\|q)$ and there are \|n items preceding \|p. + +\Y\B\4\X1121: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${}\E{}$\6 +$\|q\K\\{head};{}$\5 +${}\|p\K\\{link}(\|q);{}$\5 +${}\|n\K\T{0};{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\R\\{is\_char\_node}(\|p)){}$\1\6 +\&{if} ${}(\\{type}(\|p)>\\{rule\_node}){}$\1\6 +\&{if} ${}(\\{type}(\|p)\I\\{kern\_node}){}$\1\6 +\&{if} ${}(\\{type}(\|p)\I\\{ligature\_node}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Improper\ discretion}\)\.{ary\ list"});\5 +\\{help1}(\.{"Discretionary\ lists}\)\.{\ must\ contain\ only\ b}\)\.{oxes\ and\ kerns."});\6 +\&{error} (\,)\1\5 +;\2\6 +\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{"The\ following\ discr}\)\.{etionary\ sublist\ has}\)\.{\ been\ deleted:"});\5 +\\{show\_box}(\|p);\5 +\\{end\_diagnostic}(\\{true});\5 +\\{flush\_node\_list}(\|p);\5 +${}\\{link}(\|q)\K\\{null};{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\2\2\2\6 +${}\|q\K\|p;{}$\5 +${}\|p\K\\{link}(\|q);{}$\5 +\\{incr}(\|n);\6 +\4${}\}{}$\2\6 +\\{done}:\par +\U1119.\fi + +\M{1122}We need only one more thing to complete the horizontal mode routines, namely +the \.{\\accent} primitive. + +\Y\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{hmode}${}+\\{accent}{}$:\5 +\\{make\_accent}(\,);\5 +\&{break};\par +\fi + +\M{1123}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{make\_accent}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{double} \|s${},{}$ \|t;\C{amount of slant}\6 +\&{pointer} \|p${},{}$ \|q${},{}$ \|r;\C{character, box, and kern nodes}\6 +\&{internal\_font\_number} \|f;\C{relevant font}\6 +\&{scaled} \|a${},{}$ \|h${},{}$ \|x${},{}$ \|w${},{}$ \\{delta};\C{heights and widths, as explained above}\6 +\&{four\_quarters} \|i;\C{character information}\7 +\\{scan\_char\_num}(\,);\5 +${}\|f\K\\{cur\_font};{}$\5 +${}\|p\K\\{new\_character}(\|f,\39\\{cur\_val});{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1${}\|x\K\\{x\_height}(\|f);{}$\5 +${}\|s\K\\{slant}(\|f)/\\{float\_constant}(\T{65536});{}$\5 +${}\|a\K\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\|p))){}$;\6 +\\{do\_assignments}(\,);\6 +\X1124:Create a character node \|q for the next character, but set \|q: $\K$ \\{null} if problems arise\X;\6 +\&{if} ${}(\|q\I\\{null}){}$\1\5 +\X1125:Append the accent with appropriate kerns, then set \|p: $\K$ \|q\X;\2\6 +${}\\{link}(\\{tail})\K\|p;{}$\5 +${}\\{tail}\K\|p;{}$\5 +${}\\{space\_factor}\K\T{1000};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1124}\B\X1124:Create a character node \|q for the next character, but set \|q: $\K$ \\{null} if problems arise\X${}\E{}$\6 +$\|q\K\\{null};{}$\5 +${}\|f\K\\{cur\_font};$ \6 +\&{if} ${}((\\{cur\_cmd}\E\\{letter})\V(\\{cur\_cmd}\E\\{other\_char})\V(\\{cur\_cmd}\E\\{char\_given})){}$\1\5 +${}\|q\K\\{new\_character}(\|f,\39\\{cur\_chr});{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_cmd}\E\\{char\_num}){}$\5 +${}\{{}$\5 +\1\\{scan\_char\_num}(\,);\5 +${}\|q\K\\{new\_character}(\|f,\39\\{cur\_val});{}$\6 +\4${}\}{}$\2\6 +\&{else} \\{back\_input}(\,)\par +\U1123.\fi + +\M{1125}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) \&{double} 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\B\4\X1125:Append the accent with appropriate kerns, then set \|p: $\K$ \|q\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|t\K\\{slant}(\|f)/\\{float\_constant}(\T{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{}$)\C{the accent must be shifted up or down}\6 +${}\{{}$\5 +\1${}\|p\K\\{hpack}(\|p,\39\\{natural});{}$\5 +${}\\{shift\_amount}(\|p)\K\|x-\|h;{}$\6 +\4${}\}{}$\2\6 +${}\\{delta}\K\\{round}((\|w-\|a)/\\{float\_constant}(\T{2})+\|h*\|t-\|x*\|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};{}$\5 +${}\\{link}(\|p)\K\\{tail};{}$\5 +${}\|p\K\|q;{}$\6 +\4${}\}{}$\2\par +\U1123.\fi + +\M{1126}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}\E\T{0}$. The following +program attempts to make an appropriate recovery. + +\Y\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{car\_ret}):\5 +\\{any\_mode}(\\{tab\_mark}):\5 +\\{align\_error}(\,);\5 +\&{break};\6 +\4\\{any\_mode}(\\{no\_align}):\5 +\\{no\_align\_error}(\,);\5 +\&{break};\6 +\4\\{any\_mode}(\\{omit}):\5 +\\{omit\_error}(\,);\5 +\&{break};\par +\fi + +\M{1127}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{align\_error}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{abs}(\\{align\_state})>\T{2}){}$\1\5 +\X1128:Express consternation over the fact that no alignment is in progress\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\6 +\&{if} ${}(\\{align\_state}<\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ \{\ inserted"});\5 +\\{incr}(\\{align\_state});\5 +${}\\{cur\_tok}\K\\{left\_brace\_token}+\.{'\{'};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ \}\ inserted"});\5 +\\{decr}(\\{align\_state});\5 +${}\\{cur\_tok}\K\\{right\_brace\_token}+\.{'\}'};{}$\6 +\4${}\}{}$\2\6 +\\{help3}(\.{"I've\ put\ in\ what\ se}\)\.{ems\ to\ be\ necessary\ }\)\.{to\ fix"})\6 +(\.{"the\ current\ column\ }\)\.{of\ the\ current\ align}\)\.{ment."})\6 +(\.{"Try\ to\ go\ on,\ since}\)\.{\ this\ might\ almost\ w}\)\.{ork."});\5 +\\{ins\_error}(\,);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1128}\B\X1128:Express consternation over the fact that no alignment is in progress\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Misplaced\ "});\5 +${}\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr});{}$\6 +\&{if} ${}(\\{cur\_tok}\E\\{tab\_token}+\.{'\&'}){}$\5 +${}\{{}$\5 +\1\\{help6}(\.{"I\ can't\ figure\ out\ }\)\.{why\ you\ would\ want\ t}\)\.{o\ use\ a\ tab\ mark"})\6 +(\.{"here.\ If\ you\ just\ w}\)\.{ant\ an\ ampersand,\ th}\)\.{e\ remedy\ is"})\6 +(\.{"simple:\ Just\ type\ `}\)\.{I\\\\\&'\ now.\ But\ if\ so}\)\.{me\ right\ brace"})\6 +(\.{"up\ above\ has\ ended\ }\)\.{a\ previous\ alignment}\)\.{\ prematurely,"})\6 +(\.{"you're\ probably\ due}\)\.{\ for\ more\ error\ mess}\)\.{ages,\ and\ you"})\6 +(\.{"might\ try\ typing\ `S}\)\.{'\ now\ just\ to\ see\ wh}\)\.{at\ is\ salvageable."});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{help5}(\.{"I\ can't\ figure\ out\ }\)\.{why\ you\ would\ want\ t}\)\.{o\ use\ a\ tab\ mark"})\6 +(\.{"or\ \\\\cr\ or\ \\\\span\ j}\)\.{ust\ now.\ If\ somethin}\)\.{g\ like\ a\ right\ brace}\)\.{"})\6 +(\.{"up\ above\ has\ ended\ }\)\.{a\ previous\ alignment}\)\.{\ prematurely,"})\6 +(\.{"you're\ probably\ due}\)\.{\ for\ more\ error\ mess}\)\.{ages,\ and\ you"})\6 +(\.{"might\ try\ typing\ `S}\)\.{'\ now\ just\ to\ see\ wh}\)\.{at\ is\ salvageable."});\6 +\4${}\}{}$\2\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U1127.\fi + +\M{1129}The help messages here contain a little white lie, since \.{\\noalign} +and \.{\\omit} are allowed also after `\.{\\noalign\{...\}}'. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{no\_align\_error}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Misplaced\ "});\5 +\\{print\_esc}(\X1549:\.{"noalign"}\X);\5 +\\{help2}(\.{"I\ expect\ to\ see\ \\\\n}\)\.{oalign\ only\ after\ th}\)\.{e\ \\\\cr\ of"})\6 +(\.{"an\ alignment.\ Proce}\)\.{ed,\ and\ I'll\ ignore\ }\)\.{this\ case."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\7 +\&{void} \\{omit\_error}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Misplaced\ "});\5 +\\{print\_esc}(\X1552:\.{"omit"}\X);\5 +\\{help2}(\.{"I\ expect\ to\ see\ \\\\o}\)\.{mit\ only\ after\ tab\ m}\)\.{arks\ or\ the\ \\\\cr\ of"})\6 +(\.{"an\ alignment.\ Proce}\)\.{ed,\ and\ I'll\ ignore\ }\)\.{this\ case."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\fi + +\M{1130}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{vmode}${}+\\{halign}{}$:\5 +\&{case} \\{hmode}${}+\\{valign}{}$:\5 +\\{init\_align}(\,);\5 +\&{break};\6 +\4\&{case} \\{mmode}${}+\\{halign}{}$:\6 +\&{if} (\\{privileged}(\,))\1\6 +\&{if} ${}(\\{cur\_group}\E\\{math\_shift\_group}){}$\1\5 +\\{init\_align}(\,);\2\6 +\&{else}\1\5 +\\{off\_save}(\,);\5 +\2\2\&{break};\6 +\4\&{case} \\{vmode}${}+\\{endv}{}$:\5 +\&{case} \\{hmode}${}+\\{endv}{}$:\5 +\\{do\_endv}(\,);\5 +\&{break};\par +\fi + +\M{1131}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{do\_endv}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{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}\E\\{null})\W(\\{input\_stack}[\\{base\_ptr}].\\{state\_field}\E\\{token\_list})){}$\1\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\5 +\\{fatal\_error}(\.{"(interwoven\ alignme}\)\.{nt\ preambles\ are\ not}\)\.{\ allowed)"});\2\6 +\&{if} ${}(\\{cur\_group}\E\\{align\_group}){}$\5 +${}\{{}$\5 +\1\\{end\_graf}(\,);\6 +\&{if} (\\{fin\_col}(\,))\1\5 +\\{fin\_row}(\,);\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{off\_save}(\,);\2\6 +\4${}\}{}$\2\par +\fi + +\M{1132}\B\X1085:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X${}\mathrel+\E{}$\6 +\4\&{case} \\{align\_group}:\6 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +${}\\{cur\_tok}\K\\{cs\_token\_flag}+\\{frozen\_cr};{}$\5 +\\{print\_err}(\.{"Missing\ "});\5 +\\{print\_esc}(\X1670:\.{"cr"}\X);\5 +\\{print\_str}(\.{"\ inserted"});\5 +\\{help1}(\.{"I'm\ guessing\ that\ y}\)\.{ou\ meant\ to\ end\ an\ a}\)\.{lignment\ here."});\5 +\\{ins\_error}(\,);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1133}\B\X1085:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X${}\mathrel+\E{}$\6 +\4\&{case} \\{no\_align\_group}:\6 +${}\{{}$\5 +\1\\{end\_graf}(\,);\5 +\\{unsave}(\,);\5 +\\{align\_peek}(\,);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1134}Finally, \.{\\endcsname} is not supposed to get through to \\{main\_control}. + +\Y\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{end\_cs\_name}):\5 +\\{cs\_error}(\,);\5 +\&{break};\par +\fi + +\M{1135}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{cs\_error}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Extra\ "});\5 +\\{print\_esc}(\X1527:\.{"endcsname"}\X);\5 +\\{help1}(\.{"I'm\ ignoring\ this,\ }\)\.{since\ I\ wasn't\ doing}\)\.{\ a\ \\\\csname."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\fi + +\N{1}{1136}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{push\_math}(\&{group\_code} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\\{push\_nest}(\,);\5 +${}\\{mode}\K{-}\\{mmode};{}$\5 +${}\\{incompleat\_noad}\K\\{null};{}$\5 +\\{new\_save\_level}(\|c);\6 +\4${}\}{}$\2\par +\fi + +\M{1137}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{hmode}${}+\\{math\_shift}{}$:\5 +\\{init\_math}(\,);\5 +\&{break};\par +\fi + +\M{1138}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{init\_math}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{scaled} \|w;\C{new or partial \\{pre\_display\_size}}\6 +\&{scaled} \|l;\C{new \\{display\_width}}\6 +\&{scaled} \|s;\C{new \\{display\_indent}}\6 +\&{pointer} \|p;\C{current node when calculating \\{pre\_display\_size}}\6 +\&{pointer} \|q;\C{glue specification when calculating \\{pre\_display\_size}}\6 +\&{internal\_font\_number} \|f;\C{font in current \\{char\_node}}\6 +\&{int} \|n;\C{scope of paragraph shape specification}\6 +\&{scaled} \|v;\C{\|w plus possible glue amount}\6 +\&{scaled} \|d;\C{increment to \|v}\7 +\\{get\_token}(\,);\C{\\{get\_x\_token} would fail on \.{\\ifmmode}\thinspace!}\6 +\&{if} ${}((\\{cur\_cmd}\E\\{math\_shift})\W(\\{mode}>\T{0})){}$\1\5 +\X1145:Go into display math mode\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +\X1139:Go into ordinary math mode\X;\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1139}\B\X1139:Go into ordinary math mode\X${}\E{}$\6 +${}\{{}$\5 +\1\\{push\_math}(\\{math\_shift\_group});\5 +${}\\{eq\_word\_define}(\\{int\_base}+\\{cur\_fam\_code},\39{-}\T{1});{}$\6 +\&{if} ${}(\\{every\_math}\I\\{null}){}$\1\5 +${}\\{begin\_token\_list}(\\{every\_math},\39\\{every\_math\_text});{}$\2\6 +\4${}\}{}$\2\par +\Us1138\ET1142.\fi + +\M{1140}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{eq\_no}{}$:\6 +\&{if} (\\{privileged}(\,))\1\6 +\&{if} ${}(\\{cur\_group}\E\\{math\_shift\_group}){}$\1\5 +\\{start\_eq\_no}(\,);\2\6 +\&{else}\1\5 +\\{off\_save}(\,);\5 +\2\2\&{break};\par +\fi + +\M{1141}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1733:\.{"eqno"}\X,\39\\{eq\_no},\39\T{0});{}$\5 +${}\\{primitive}(\X1734:\.{"leqno"}\X,\39\\{eq\_no},\39\T{1}){}$;\par +\fi + +\M{1142}When \TeX\ is in display math mode, $\\{cur\_group}\E\\{math\_shift\_group}$, +so it is not necessary for the \\{start\_eq\_no} procedure to test for +this condition. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{start\_eq\_no}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{saved}(\T{0})\K\\{cur\_chr};{}$\5 +\\{incr}(\\{save\_ptr});\5 +\X1139:Go into ordinary math mode\X;\6 +\4${}\}{}$\2\par +\fi + +\M{1143}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{eq\_no}:\6 +\&{if} ${}(\\{chr\_code}\E\T{1}){}$\1\5 +\\{print\_esc}(\X1734:\.{"leqno"}\X);\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1733:\.{"eqno"}\X);\5 +\2\&{break};\par +\fi + +\M{1144}\B\X1048:Forbidden cases detected in \\{main\_control}\X${}\mathrel+\E{}$\6 +\\{non\_math}(\\{eq\_no}):\par +\fi + +\M{1145}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\B\4\X1145:Go into display math mode\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{head}\E\\{tail}{}$)\C{`\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}'}\6 +${}\{{}$\5 +\1\\{pop\_nest}(\,);\5 +${}\|w\K{-}\\{max\_dimen};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{line\_break}(\\{display\_widow\_penalty});\6 +\X1146: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 +\4${}\}{}$\C{now we are in vertical mode, working on the list that will contain the display}\2\6 +\X1149: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{-}\T{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\5 +${}\\{begin\_token\_list}(\\{every\_display},\39\\{every\_display\_text});{}$\2\6 +\&{if} ${}(\\{nest\_ptr}\E\T{1}){}$\1\5 +\\{build\_page}(\,);\2\6 +\4${}\}{}$\2\par +\U1138.\fi + +\M{1146}\B\X1146: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${}\E{}$\6 +$\|v\K\\{shift\_amount}(\\{just\_box})+\T{2}*\\{quad}(\\{cur\_font});{}$\5 +${}\|w\K{-}\\{max\_dimen};{}$\5 +${}\|p\K\\{list\_ptr}(\\{just\_box});{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1\X1147: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\5 +${}\|v\K\|v+\|d;{}$\2\6 +\&{goto} \\{not\_found};\6 +\4\\{found}:\6 +\&{if} ${}(\|v<\\{max\_dimen}){}$\5 +${}\{{}$\5 +\1${}\|v\K\|v+\|d;{}$\5 +${}\|w\K\|v;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|w\K\\{max\_dimen};{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\4\\{not\_found}:\5 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\\{done}:\par +\U1145.\fi + +\M{1147}\B\X1147: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${}\E{}$\6 +\4\\{reswitch}:\6 +\&{if} (\\{is\_char\_node}(\|p))\5 +${}\{{}$\5 +\1${}\|f\K\\{font}(\|p);{}$\5 +${}\|d\K\\{char\_width}(\|f)(\\{char\_info}(\|f)(\\{character}(\|p)));{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\&{switch} (\\{type}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{hlist\_node}:\5 +\&{case} \\{vlist\_node}:\5 +\&{case} \\{rule\_node}:\6 +${}\{{}$\5 +\1${}\|d\K\\{width}(\|p);{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{ligature\_node}:\5 +\X652:Make node \|p look like a \\{char\_node} and \&{goto} \\{reswitch}\X\6 +\4\&{case} \\{kern\_node}:\5 +\&{case} \\{math\_node}:\5 +${}\|d\K\\{width}(\|p){}$;\5 +\&{break};\6 +\4\&{case} \\{glue\_node}:\5 +\X1148: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\5 +\&{break};\6 +\4\&{case} \\{whatsit\_node}:\5 +\X1361:Let \|d be the width of the whatsit \|p\X;\5 +\&{break};\6 +\4\&{default}:\5 +${}\|d\K\T{0};{}$\6 +\4${}\}{}$\2\par +\U1146.\fi + +\M{1148}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\B\4\X1148: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${}\E{}$\6 +${}\{{}$\5 +\1${}\|q\K\\{glue\_ptr}(\|p);{}$\5 +${}\|d\K\\{width}(\|q);{}$\6 +\&{if} ${}(\\{glue\_sign}(\\{just\_box})\E\\{stretching}){}$\5 +${}\{{}$\5 +\1\&{if} ${}((\\{glue\_order}(\\{just\_box})\E\\{stretch\_order}(\|q))\W\30(\\{stretch}(\|q)\I\T{0})){}$\1\5 +${}\|v\K\\{max\_dimen};{}$\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{glue\_sign}(\\{just\_box})\E\\{shrinking}){}$\5 +${}\{{}$\5 +\1\&{if} ${}((\\{glue\_order}(\\{just\_box})\E\\{shrink\_order}(\|q))\W\30(\\{shrink}(\|q)\I\T{0})){}$\1\5 +${}\|v\K\\{max\_dimen};{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{subtype}(\|p)\G\\{a\_leaders}){}$\1\5 +\&{goto} \\{found};\2\6 +\4${}\}{}$\2\par +\U1147.\fi + +\M{1149}A displayed equation is considered to be three lines long, so we +calculate the length and offset of line number $\\{prev\_graf}+\T{2}$. + +\Y\B\4\X1149:Calculate the length, \|l, and the shift amount, \|s, of the display lines\X${}\E{}$\6 +\&{if} ${}(\\{par\_shape\_ptr}\E\\{null}){}$\1\6 +\&{if} ${}((\\{hang\_indent}\I\T{0})\W\30(((\\{hang\_after}\G\T{0})\W(\\{prev\_graf}+\T{2}>\\{hang\_after}))\V\30(\\{prev\_graf}+\T{1}<{-}\\{hang\_after}))){}$\5 +${}\{{}$\5 +\1${}\|l\K\\{hsize}-\\{abs}(\\{hang\_indent});{}$\6 +\&{if} ${}(\\{hang\_indent}>\T{0}){}$\1\5 +${}\|s\K\\{hang\_indent}{}$;\5 +\2\&{else}\1\5 +${}\|s\K\T{0};{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|l\K\\{hsize};{}$\5 +${}\|s\K\T{0};{}$\6 +\4${}\}{}$\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|n\K\\{info}(\\{par\_shape\_ptr});{}$\6 +\&{if} ${}(\\{prev\_graf}+\T{2}\G\|n){}$\1\5 +${}\|p\K\\{par\_shape\_ptr}+\T{2}*\|n;{}$\2\6 +\&{else}\1\5 +${}\|p\K\\{par\_shape\_ptr}+\T{2}*(\\{prev\_graf}+\T{2});{}$\2\6 +${}\|s\K\\{mem}[\|p-\T{1}].\\{sc};{}$\5 +${}\|l\K\\{mem}[\|p].\\{sc};{}$\6 +\4${}\}{}$\2\par +\U1145.\fi + +\M{1150}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{left\_brace}{}$:\6 +${}\{{}$\5 +\1\\{tail\_append}(\\{new\_noad}(\,));\5 +\\{back\_input}(\,);\5 +\\{scan\_math}(\\{nucleus}(\\{tail}));\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1151}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\B\4\D$\\{fam\_in\_range}$ \5 +$((\\{cur\_fam}\G\T{0})\W(\\{cur\_fam}<\T{16}){}$)\par +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{scan\_math}(\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|c;\C{math character code}\7 +\4\\{restart}:\5 +\X404:Get the next non-blank non-relax non-call token\X;\6 +\4\\{reswitch}:\6 +\&{switch} (\\{cur\_cmd})\5 +${}\{{}$\1\6 +\4\&{case} \\{letter}:\5 +\&{case} \\{other\_char}:\5 +\&{case} \\{char\_given}:\6 +${}\{{}$\5 +\1${}\|c\K\\{ho}(\\{math\_code}(\\{cur\_chr}));{}$\6 +\&{if} ${}(\|c\E\T{\~100000}){}$\5 +${}\{{}$\5 +\1\X1152:Treat \\{cur\_chr} as an active character\X;\6 +\&{goto} \\{restart};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{char\_num}:\6 +${}\{{}$\5 +\1\\{scan\_char\_num}(\,);\5 +${}\\{cur\_chr}\K\\{cur\_val};{}$\5 +${}\\{cur\_cmd}\K\\{char\_given};{}$\5 +\&{goto} \\{reswitch};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{math\_char\_num}:\6 +${}\{{}$\5 +\1\\{scan\_fifteen\_bit\_int}(\,);\5 +${}\|c\K\\{cur\_val};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{math\_given}:\5 +${}\|c\K\\{cur\_chr}{}$;\5 +\&{break};\6 +\4\&{case} \\{delim\_num}:\6 +${}\{{}$\5 +\1\\{scan\_twenty\_seven\_bit\_int}(\,);\5 +${}\|c\K\\{cur\_val}/\T{\~10000};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\5 +\X1153:Scan a subformula enclosed in braces and \&{return}\X\6 +\4${}\}{}$\2\6 +${}\\{math\_type}(\|p)\K\\{math\_char};{}$\5 +${}\\{character}(\|p)\K\\{qi}(\|c\MOD\T{256});{}$\6 +\&{if} ${}((\|c\G\\{var\_code})\W\\{fam\_in\_range}){}$\1\5 +${}\\{fam}(\|p)\K\\{cur\_fam};{}$\2\6 +\&{else}\1\5 +${}\\{fam}(\|p)\K(\|c/\T{256})\MOD\T{16};{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1152}An active character that is an \\{outer\_call} is allowed here. + +\Y\B\4\X1152:Treat \\{cur\_chr} as an active character\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\par +\Us1151\ET1155.\fi + +\M{1153}The pointer \|p is placed on \\{save\_stack} while a complex subformula +is being scanned. + +\Y\B\4\X1153:Scan a subformula enclosed in braces and \&{return}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{back\_input}(\,);\5 +\\{scan\_left\_brace}(\,);\6 +${}\\{saved}(\T{0})\K\|p;{}$\5 +\\{incr}(\\{save\_ptr});\5 +\\{push\_math}(\\{math\_group});\5 +\&{return};\6 +\4${}\}{}$\2\par +\U1151.\fi + +\M{1154}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\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{letter}{}$:\5 +\&{case} \\{mmode}${}+\\{other\_char}{}$:\5 +\&{case} \\{mmode}${}+\\{char\_given}{}$:\5 +\\{set\_math\_char}(\\{ho}(\\{math\_code}(\\{cur\_chr})));\5 +\&{break};\6 +\4\&{case} \\{mmode}${}+\\{char\_num}{}$:\6 +${}\{{}$\5 +\1\\{scan\_char\_num}(\,);\5 +${}\\{cur\_chr}\K\\{cur\_val};{}$\5 +\\{set\_math\_char}(\\{ho}(\\{math\_code}(\\{cur\_chr})));\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{mmode}${}+\\{math\_char\_num}{}$:\6 +${}\{{}$\5 +\1\\{scan\_fifteen\_bit\_int}(\,);\5 +\\{set\_math\_char}(\\{cur\_val});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{mmode}${}+\\{math\_given}{}$:\5 +\\{set\_math\_char}(\\{cur\_chr});\5 +\&{break};\6 +\4\&{case} \\{mmode}${}+\\{delim\_num}{}$:\6 +${}\{{}$\5 +\1\\{scan\_twenty\_seven\_bit\_int}(\,);\5 +${}\\{set\_math\_char}(\\{cur\_val}/\T{\~10000});{}$\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1155}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{set\_math\_char}(\&{int} \|c)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new noad}\7 +\&{if} ${}(\|c\G\T{\~100000}){}$\1\5 +\X1152:Treat \\{cur\_chr} as an active character\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|p\K\\{new\_noad}(\,);{}$\5 +${}\\{math\_type}(\\{nucleus}(\|p))\K\\{math\_char};{}$\5 +${}\\{character}(\\{nucleus}(\|p))\K\\{qi}(\|c\MOD\T{256});{}$\5 +${}\\{fam}(\\{nucleus}(\|p))\K(\|c/\T{256})\MOD\T{16};{}$\6 +\&{if} ${}(\|c\G\\{var\_code}){}$\5 +${}\{{}$\5 +\1\&{if} (\\{fam\_in\_range})\1\5 +${}\\{fam}(\\{nucleus}(\|p))\K\\{cur\_fam};{}$\2\6 +${}\\{type}(\|p)\K\\{ord\_noad};{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{type}(\|p)\K\\{ord\_noad}+(\|c/\T{\~10000});{}$\2\6 +${}\\{link}(\\{tail})\K\|p;{}$\5 +${}\\{tail}\K\|p;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1156}Primitive math operators like \.{\\mathop} and \.{\\underline} are given +the command code \\{math\_comp}, supplemented by the noad type that they +generate. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1649:\.{"mathord"}\X,\39\\{math\_comp},\39\\{ord\_noad});{}$\5 +${}\\{primitive}(\X1650:\.{"mathop"}\X,\39\\{math\_comp},\39\\{op\_noad});{}$\5 +${}\\{primitive}(\X1651:\.{"mathbin"}\X,\39\\{math\_comp},\39\\{bin\_noad});{}$\5 +${}\\{primitive}(\X1652:\.{"mathrel"}\X,\39\\{math\_comp},\39\\{rel\_noad});{}$\5 +${}\\{primitive}(\X1653:\.{"mathopen"}\X,\39\\{math\_comp},\39\\{open\_noad});{}$\5 +${}\\{primitive}(\X1654:\.{"mathclose"}\X,\39\\{math\_comp},\39\\{close\_noad});{}$\5 +${}\\{primitive}(\X1655:\.{"mathpunct"}\X,\39\\{math\_comp},\39\\{punct\_noad});{}$\5 +${}\\{primitive}(\X1656:\.{"mathinner"}\X,\39\\{math\_comp},\39\\{inner\_noad});{}$\5 +${}\\{primitive}(\X1658:\.{"underline"}\X,\39\\{math\_comp},\39\\{under\_noad});{}$\5 +${}\\{primitive}(\X1657:\.{"overline"}\X,\39\\{math\_comp},\39\\{over\_noad}){}$;\6 +${}\\{primitive}(\X1735:\.{"displaylimits"}\X,\39\\{limit\_switch},\39\\{normal});{}$\5 +${}\\{primitive}(\X1661:\.{"limits"}\X,\39\\{limit\_switch},\39\\{limits});{}$\5 +${}\\{primitive}(\X1662:\.{"nolimits"}\X,\39\\{limit\_switch},\39\\{no\_limits}){}$;\par +\fi + +\M{1157}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{math\_comp}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{ord\_noad}:\5 +\\{print\_esc}(\X1649:\.{"mathord"}\X);\5 +\&{break};\6 +\4\&{case} \\{op\_noad}:\5 +\\{print\_esc}(\X1650:\.{"mathop"}\X);\5 +\&{break};\6 +\4\&{case} \\{bin\_noad}:\5 +\\{print\_esc}(\X1651:\.{"mathbin"}\X);\5 +\&{break};\6 +\4\&{case} \\{rel\_noad}:\5 +\\{print\_esc}(\X1652:\.{"mathrel"}\X);\5 +\&{break};\6 +\4\&{case} \\{open\_noad}:\5 +\\{print\_esc}(\X1653:\.{"mathopen"}\X);\5 +\&{break};\6 +\4\&{case} \\{close\_noad}:\5 +\\{print\_esc}(\X1654:\.{"mathclose"}\X);\5 +\&{break};\6 +\4\&{case} \\{punct\_noad}:\5 +\\{print\_esc}(\X1655:\.{"mathpunct"}\X);\5 +\&{break};\6 +\4\&{case} \\{inner\_noad}:\5 +\\{print\_esc}(\X1656:\.{"mathinner"}\X);\5 +\&{break};\6 +\4\&{case} \\{under\_noad}:\5 +\\{print\_esc}(\X1658:\.{"underline"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1657:\.{"overline"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{limit\_switch}:\6 +\&{if} ${}(\\{chr\_code}\E\\{limits}){}$\1\5 +\\{print\_esc}(\X1661:\.{"limits"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{no\_limits}){}$\1\5 +\\{print\_esc}(\X1662:\.{"nolimits"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1735:\.{"displaylimits"}\X);\5 +\2\&{break};\par +\fi + +\M{1158}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{math\_comp}{}$:\6 +${}\{{}$\5 +\1\\{tail\_append}(\\{new\_noad}(\,));\5 +${}\\{type}(\\{tail})\K\\{cur\_chr};{}$\5 +\\{scan\_math}(\\{nucleus}(\\{tail}));\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{mmode}${}+\\{limit\_switch}{}$:\5 +\\{math\_limit\_switch}(\,);\5 +\&{break};\par +\fi + +\M{1159}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{math\_limit\_switch}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{head}\I\\{tail}){}$\1\6 +\&{if} ${}(\\{type}(\\{tail})\E\\{op\_noad}){}$\5 +${}\{{}$\5 +\1${}\\{subtype}(\\{tail})\K\\{cur\_chr};{}$\5 +\&{return};\6 +\4${}\}{}$\2\2\6 +\\{print\_err}(\.{"Limit\ controls\ must}\)\.{\ follow\ a\ math\ opera}\)\.{tor"});\5 +\\{help1}(\.{"I'm\ ignoring\ this\ m}\)\.{isplaced\ \\\\limits\ or}\)\.{\ \\\\nolimits\ command.}\)\.{"});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\fi + +\M{1160}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{scan\_delimiter}(\&{pointer} \|p${},\39{}$\&{bool} \|r)\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} (\|r)\1\5 +\\{scan\_twenty\_seven\_bit\_int}(\,);\2\6 +\&{else}\5 +${}\{{}$\5 +\1\X404:Get the next non-blank non-relax non-call token\X;\6 +\&{switch} (\\{cur\_cmd})\5 +${}\{{}$\1\6 +\4\&{case} \\{letter}:\5 +\&{case} \\{other\_char}:\5 +${}\\{cur\_val}\K\\{del\_code}(\\{cur\_chr}){}$;\5 +\&{break};\6 +\4\&{case} \\{delim\_num}:\5 +\\{scan\_twenty\_seven\_bit\_int}(\,);\5 +\&{break};\6 +\4\&{default}:\5 +${}\\{cur\_val}\K{-}\T{1};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_val}<\T{0}){}$\1\5 +\X1161:Report that an invalid delimiter code is being changed to null; set~\\{cur\_val}: $\K$ \T{0}\X;\2\6 +${}\\{small\_fam}(\|p)\K(\\{cur\_val}/\T{\~4000000})\MOD\T{16};{}$\5 +${}\\{small\_char}(\|p)\K\\{qi}((\\{cur\_val}/\T{\~10000})\MOD\T{256});{}$\5 +${}\\{large\_fam}(\|p)\K(\\{cur\_val}/\T{256})\MOD\T{16};{}$\5 +${}\\{large\_char}(\|p)\K\\{qi}(\\{cur\_val}\MOD\T{256});{}$\6 +\4${}\}{}$\2\par +\fi + +\M{1161}\B\X1161:Report that an invalid delimiter code is being changed to null; set~\\{cur\_val}: $\K$ \T{0}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ delimiter\ (}\)\.{.\ inserted)"});\5 +\\{help6}(\.{"I\ was\ expecting\ to\ }\)\.{see\ something\ like\ `}\)\.{('\ or\ `\\\\\{'\ or"})\6 +(\.{"`\\\\\}'\ here.\ If\ you\ }\)\.{typed,\ e.g.,\ `\{'\ ins}\)\.{tead\ of\ `\\\\\{',\ you"})\6 +(\.{"should\ probably\ del}\)\.{ete\ the\ `\{'\ by\ typin}\)\.{g\ `1'\ now,\ so\ that"})\6 +(\.{"braces\ don't\ get\ un}\)\.{balanced.\ Otherwise\ }\)\.{just\ proceed."})\6 +(\.{"Acceptable\ delimite}\)\.{rs\ are\ characters\ wh}\)\.{ose\ \\\\delcode\ is"})\6 +(\.{"nonnegative,\ or\ you}\)\.{\ can\ use\ `\\\\delimite}\)\.{r\ <delimiter\ code>'.}\)\.{"});\5 +\\{back\_error}(\,);\5 +${}\\{cur\_val}\K\T{0};{}$\6 +\4${}\}{}$\2\par +\U1160.\fi + +\M{1162}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{radical}{}$:\5 +\\{math\_radical}(\,);\5 +\&{break};\par +\fi + +\M{1163}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{math\_radical}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{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}));\6 +\4${}\}{}$\2\par +\fi + +\M{1164}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{accent}{}$:\5 +\&{case} \\{mmode}${}+\\{math\_accent}{}$:\5 +\\{math\_ac}(\,);\5 +\&{break};\par +\fi + +\M{1165}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{math\_ac}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_cmd}\E\\{accent}){}$\1\5 +\X1166: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}\MOD\T{256});{}$\6 +\&{if} ${}((\\{cur\_val}\G\\{var\_code})\W\\{fam\_in\_range}){}$\1\5 +${}\\{fam}(\\{accent\_chr}(\\{tail}))\K\\{cur\_fam};{}$\2\6 +\&{else}\1\5 +${}\\{fam}(\\{accent\_chr}(\\{tail}))\K(\\{cur\_val}/\T{256})\MOD\T{16};{}$\2\6 +\\{scan\_math}(\\{nucleus}(\\{tail}));\6 +\4${}\}{}$\2\par +\fi + +\M{1166}\B\X1166:Complain that the user should have said \.{\\mathaccent}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Please\ use\ "});\5 +\\{print\_esc}(\X1545:\.{"mathaccent"}\X);\5 +\\{print\_str}(\.{"\ for\ accents\ in\ mat}\)\.{h\ mode"});\5 +\\{help2}(\.{"I'm\ changing\ \\\\acce}\)\.{nt\ to\ \\\\mathaccent\ h}\)\.{ere;\ wish\ me\ luck."})\6 +(\.{"(Accents\ are\ not\ th}\)\.{e\ same\ in\ formulas\ a}\)\.{s\ they\ are\ in\ text.)}\)\.{"});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U1165.\fi + +\M{1167}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{vcenter}{}$:\6 +${}\{{}$\5 +\1${}\\{scan\_spec}(\\{vcenter\_group},\39\\{false});{}$\5 +\\{normal\_paragraph}(\,);\5 +\\{push\_nest}(\,);\5 +${}\\{mode}\K{-}\\{vmode};{}$\5 +${}\\{prev\_depth}\K\\{ignore\_depth};{}$\6 +\&{if} ${}(\\{every\_vbox}\I\\{null}){}$\1\5 +${}\\{begin\_token\_list}(\\{every\_vbox},\39\\{every\_vbox\_text});{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1168}\B\X1085:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X${}\mathrel+\E{}$\6 +\4\&{case} \\{vcenter\_group}:\6 +${}\{{}$\5 +\1\\{end\_graf}(\,);\5 +\\{unsave}(\,);\5 +${}\\{save\_ptr}\K\\{save\_ptr}-\T{2};{}$\5 +${}\|p\K\\{vpack}(\\{link}(\\{head}),\39\\{saved}(\T{1}),\39\\{saved}(\T{0}));{}$\5 +\\{pop\_nest}(\,);\5 +\\{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 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1169}The routine that inserts a \\{style\_node} holds no surprises. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1645:\.{"displaystyle"}\X,\39\\{math\_style},\39\\{display\_style});{}$\5 +${}\\{primitive}(\X1646:\.{"textstyle"}\X,\39\\{math\_style},\39\\{text\_style});{}$\5 +${}\\{primitive}(\X1647:\.{"scriptstyle"}\X,\39\\{math\_style},\39\\{script\_style});{}$\5 +${}\\{primitive}(\X1648:\.{"scriptscriptstyle"}\X,\39\\{math\_style},\39\\{script\_script\_style}){}$;\par +\fi + +\M{1170}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{math\_style}:\5 +\\{print\_style}(\\{chr\_code});\5 +\&{break};\par +\fi + +\M{1171}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{math\_style}{}$:\5 +\\{tail\_append}(\\{new\_style}(\\{cur\_chr}))\5 +\&{break};\6 +\4\&{case} \\{mmode}${}+\\{non\_script}{}$:\6 +${}\{{}$\5 +\1\\{tail\_append}(\\{new\_glue}(\\{zero\_glue}));\5 +${}\\{subtype}(\\{tail})\K\\{cond\_math\_glue};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{mmode}${}+\\{math\_choice}{}$:\5 +\\{append\_choices}(\,);\5 +\&{break};\par +\fi + +\M{1172}The routine that scans the four mlists of a \.{\\mathchoice} is very +much like the routine that builds discretionary nodes. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{append\_choices}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{tail\_append}(\\{new\_choice}(\,));\5 +\\{incr}(\\{save\_ptr});\5 +${}\\{saved}({-}\T{1})\K\T{0};{}$\5 +\\{push\_math}(\\{math\_choice\_group});\5 +\\{scan\_left\_brace}(\,);\6 +\4${}\}{}$\2\par +\fi + +\M{1173}\B\X1085:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X${}\mathrel+\E{}$\6 +\4\&{case} \\{math\_choice\_group}:\5 +\\{build\_choices}(\,);\5 +\&{break};\par +\fi + +\M{1174}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\hbox{\4}\X1184:Declare the function called \\{fin\_mlist}\X\hbox{}\7 +\&{void} \\{build\_choices}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the current mlist}\7 +\\{unsave}(\,);\5 +${}\|p\K\\{fin\_mlist}(\\{null});{}$\6 +\&{switch} ${}(\\{saved}({-}\T{1})){}$\5 +${}\{{}$\1\6 +\4\&{case} \T{0}:\5 +${}\\{display\_mlist}(\\{tail})\K\|p{}$;\5 +\&{break};\6 +\4\&{case} \T{1}:\5 +${}\\{text\_mlist}(\\{tail})\K\|p{}$;\5 +\&{break};\6 +\4\&{case} \T{2}:\5 +${}\\{script\_mlist}(\\{tail})\K\|p{}$;\5 +\&{break};\6 +\4\&{case} \T{3}:\6 +${}\{{}$\5 +\1${}\\{script\_script\_mlist}(\\{tail})\K\|p;{}$\5 +\\{decr}(\\{save\_ptr});\5 +\&{return};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\C{there are no other cases}\2\6 +${}\\{incr}(\\{saved}({-}\T{1}));{}$\5 +\\{push\_math}(\\{math\_choice\_group});\5 +\\{scan\_left\_brace}(\,);\6 +\4${}\}{}$\2\par +\fi + +\M{1175}Subscripts and superscripts are attached to the previous nucleus by the +action procedure called \\{sub\_sup}. We use the facts that $\\{sub\_mark}\E\\{sup\_mark}+\T{1}$ +and $\\{subscr}(\|p)\E\\{supscr}(\|p)+\T{1}$. + +\Y\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{sub\_mark}{}$:\5 +\&{case} \\{mmode}${}+\\{sup\_mark}{}$:\5 +\\{sub\_sup}(\,);\5 +\&{break};\par +\fi + +\M{1176}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{sub\_sup}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{small\_number} \|t;\C{type of previous sub/superscript}\6 +\&{pointer} \|p;\C{field to be filled by \\{scan\_math}}\7 +${}\|t\K\\{empty};{}$\5 +${}\|p\K\\{null};{}$\6 +\&{if} ${}(\\{tail}\I\\{head}){}$\1\6 +\&{if} (\\{scripts\_allowed}(\\{tail}))\5 +${}\{{}$\5 +\1${}\|p\K\\{supscr}(\\{tail})+\\{cur\_cmd}-\\{sup\_mark}{}$;\C{\\{supscr} or \\{subscr}}\6 +${}\|t\K\\{math\_type}(\|p);{}$\6 +\4${}\}{}$\2\2\6 +\&{if} ${}((\|p\E\\{null})\V(\|t\I\\{empty})){}$\1\5 +\X1177:Insert a dummy noad to be sub/superscripted\X;\2\6 +\\{scan\_math}(\|p);\6 +\4${}\}{}$\2\par +\fi + +\M{1177}\B\X1177:Insert a dummy noad to be sub/superscripted\X${}\E{}$\6 +${}\{{}$\5 +\1\\{tail\_append}(\\{new\_noad}(\,));\5 +${}\|p\K\\{supscr}(\\{tail})+\\{cur\_cmd}-\\{sup\_mark}{}$;\C{\\{supscr} or \\{subscr}}\6 +\&{if} ${}(\|t\I\\{empty}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_cmd}\E\\{sup\_mark}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Double\ superscript"});\5 +\\{help1}(\.{"I\ treat\ `x\^1\^2'\ ess}\)\.{entially\ like\ `x\^1\{\}}\)\.{\^2'."});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Double\ subscript"});\5 +\\{help1}(\.{"I\ treat\ `x\_1\_2'\ ess}\)\.{entially\ like\ `x\_1\{\}}\)\.{\_2'."});\6 +\4${}\}{}$\2\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1176.\fi + +\M{1178}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\B\4\D$\\{above\_code}$ \5 +\T{0}\C{ `\.{\\above}' }\par +\B\4\D$\\{over\_code}$ \5 +\T{1}\C{ `\.{\\over}' }\par +\B\4\D$\\{atop\_code}$ \5 +\T{2}\C{ `\.{\\atop}' }\par +\B\4\D$\\{delimited\_code}$ \5 +\T{3}\C{ `\.{\\abovewithdelims}', etc.}\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1736:\.{"above"}\X,\39\\{above},\39\\{above\_code}){}$;\6 +${}\\{primitive}(\X1737:\.{"over"}\X,\39\\{above},\39\\{over\_code}){}$;\6 +${}\\{primitive}(\X1738:\.{"atop"}\X,\39\\{above},\39\\{atop\_code}){}$;\6 +${}\\{primitive}(\X1739:\.{"abovewithdelims"}\X,\39\\{above},\39\\{delimited\_code}+\\{above\_code}){}$;\6 +${}\\{primitive}(\X1740:\.{"overwithdelims"}\X,\39\\{above},\39\\{delimited\_code}+\\{over\_code}){}$;\6 +${}\\{primitive}(\X1741:\.{"atopwithdelims"}\X,\39\\{above},\39\\{delimited\_code}+\\{atop\_code}){}$;\par +\fi + +\M{1179}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{above}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{over\_code}:\5 +\\{print\_esc}(\X1737:\.{"over"}\X);\5 +\&{break};\6 +\4\&{case} \\{atop\_code}:\5 +\\{print\_esc}(\X1738:\.{"atop"}\X);\5 +\&{break};\6 +\4\&{case} \\{delimited\_code}${}+\\{above\_code}{}$:\5 +\\{print\_esc}(\X1739:\.{"abovewithdelims"}\X);\5 +\&{break};\6 +\4\&{case} \\{delimited\_code}${}+\\{over\_code}{}$:\5 +\\{print\_esc}(\X1740:\.{"overwithdelims"}\X);\5 +\&{break};\6 +\4\&{case} \\{delimited\_code}${}+\\{atop\_code}{}$:\5 +\\{print\_esc}(\X1741:\.{"atopwithdelims"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1736:\.{"above"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1180}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{above}{}$:\5 +\\{math\_fraction}(\,);\5 +\&{break};\par +\fi + +\M{1181}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{math\_fraction}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{small\_number} \|c;\C{the type of generalized fraction we are scanning}\7 +${}\|c\K\\{cur\_chr};{}$\6 +\&{if} ${}(\\{incompleat\_noad}\I\\{null}){}$\1\5 +\X1183:Ignore the fraction operation and complain about this ambiguous case\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{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 +\X1182:Use code \|c to distinguish between generalized fractions\X;\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1182}\B\X1182:Use code \|c to distinguish between generalized fractions\X${}\E{}$\6 +\&{if} ${}(\|c\G\\{delimited\_code}){}$\5 +${}\{{}$\5 +\1${}\\{scan\_delimiter}(\\{left\_delimiter}(\\{incompleat\_noad}),\39\\{false});{}$\5 +${}\\{scan\_delimiter}(\\{right\_delimiter}(\\{incompleat\_noad}),\39\\{false});{}$\6 +\4${}\}{}$\2\6 +\&{switch} ${}(\|c\MOD\\{delimited\_code}){}$\5 +${}\{{}$\1\6 +\4\&{case} \\{above\_code}:\6 +${}\{{}$\5 +\1\\{scan\_normal\_dimen};\5 +${}\\{thickness}(\\{incompleat\_noad})\K\\{cur\_val};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{over\_code}:\5 +${}\\{thickness}(\\{incompleat\_noad})\K\\{default\_code}{}$;\5 +\&{break};\6 +\4\&{case} \\{atop\_code}:\5 +${}\\{thickness}(\\{incompleat\_noad})\K\T{0};{}$\6 +\4${}\}{}$\C{there are no other cases}\2\par +\U1181.\fi + +\M{1183}\B\X1183:Ignore the fraction operation and complain about this ambiguous case\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\|c\G\\{delimited\_code}){}$\5 +${}\{{}$\5 +\1${}\\{scan\_delimiter}(\\{garbage},\39\\{false});{}$\5 +${}\\{scan\_delimiter}(\\{garbage},\39\\{false});{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|c\MOD\\{delimited\_code}\E\\{above\_code}){}$\1\5 +\\{scan\_normal\_dimen};\2\6 +\\{print\_err}(\.{"Ambiguous;\ you\ need}\)\.{\ another\ \{\ and\ \}"});\5 +\\{help3}(\.{"I'm\ ignoring\ this\ f}\)\.{raction\ specificatio}\)\.{n,\ since\ I\ don't"})\6 +(\.{"know\ whether\ a\ cons}\)\.{truction\ like\ `x\ \\\\o}\)\.{ver\ y\ \\\\over\ z'"})\6 +(\.{"means\ `\{x\ \\\\over\ y\}}\)\.{\ \\\\over\ z'\ or\ `x\ \\\\o}\)\.{ver\ \{y\ \\\\over\ z\}'."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U1181.\fi + +\M{1184}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\B\4\X1184:Declare the function called \\{fin\_mlist}\X${}\E{}$\6 +\&{pointer} \\{fin\_mlist}(\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|q;\C{the mlist to return}\7 +\&{if} ${}(\\{incompleat\_noad}\I\\{null}){}$\1\5 +\X1185:Compleat the incompleat noad\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{link}(\\{tail})\K\|p;{}$\5 +${}\|q\K\\{link}(\\{head});{}$\6 +\4${}\}{}$\2\6 +\\{pop\_nest}(\,);\5 +\&{return} \|q;\6 +\4${}\}{}$\2\par +\U1174.\fi + +\M{1185}\B\X1185:Compleat the incompleat noad\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{math\_type}(\\{denominator}(\\{incompleat\_noad}))\K\\{sub\_mlist};{}$\5 +${}\\{info}(\\{denominator}(\\{incompleat\_noad}))\K\\{link}(\\{head});{}$\6 +\&{if} ${}(\|p\E\\{null}){}$\1\5 +${}\|q\K\\{incompleat\_noad};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|q\K\\{info}(\\{numerator}(\\{incompleat\_noad}));{}$\6 +\&{if} ${}(\\{type}(\|q)\I\\{left\_noad}){}$\1\5 +\\{confusion}(\X1660:\.{"right"}\X);\2\6 +${}\\{info}(\\{numerator}(\\{incompleat\_noad}))\K\\{link}(\|q);{}$\5 +${}\\{link}(\|q)\K\\{incompleat\_noad};{}$\5 +${}\\{link}(\\{incompleat\_noad})\K\|p;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1184.\fi + +\M{1186}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\B\4\X1085:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X${}\mathrel+\E{}$\6 +\4\&{case} \\{math\_group}:\6 +${}\{{}$\5 +\1\\{unsave}(\,);\5 +\\{decr}(\\{save\_ptr});\6 +${}\\{math\_type}(\\{saved}(\T{0}))\K\\{sub\_mlist};{}$\5 +${}\|p\K\\{fin\_mlist}(\\{null});{}$\5 +${}\\{info}(\\{saved}(\T{0}))\K\|p;{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\1\6 +\&{if} ${}(\\{link}(\|p)\E\\{null}){}$\1\6 +\&{if} ${}(\\{type}(\|p)\E\\{ord\_noad}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{math\_type}(\\{subscr}(\|p))\E\\{empty}){}$\1\6 +\&{if} ${}(\\{math\_type}(\\{supscr}(\|p))\E\\{empty}){}$\5 +${}\{{}$\5 +\1${}\\{mem}[\\{saved}(\T{0})].\\{hh}\K\\{mem}[\\{nucleus}(\|p)].\\{hh};{}$\5 +${}\\{free\_node}(\|p,\39\\{noad\_size});{}$\6 +\4${}\}{}$\2\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{type}(\|p)\E\\{accent\_noad}){}$\1\6 +\&{if} ${}(\\{saved}(\T{0})\E\\{nucleus}(\\{tail})){}$\1\6 +\&{if} ${}(\\{type}(\\{tail})\E\\{ord\_noad}){}$\1\5 +\X1187:Replace the tail of the list by \|p\X;\2\2\2\2\2\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1187}\B\X1187:Replace the tail of the list by \|p\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|q\K\\{head};{}$\6 +\&{while} ${}(\\{link}(\|q)\I\\{tail}){}$\1\5 +${}\|q\K\\{link}(\|q);{}$\2\6 +${}\\{link}(\|q)\K\|p;{}$\5 +${}\\{free\_node}(\\{tail},\39\\{noad\_size});{}$\5 +${}\\{tail}\K\|p;{}$\6 +\4${}\}{}$\2\par +\U1186.\fi + +\M{1188}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\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1659:\.{"left"}\X,\39\\{left\_right},\39\\{left\_noad});{}$\5 +${}\\{primitive}(\X1660:\.{"right"}\X,\39\\{left\_right},\39\\{right\_noad});{}$\5 +${}\\{text}(\\{frozen\_right})\K\X1660:\.{"right"}\X;{}$\5 +${}\\{eqtb}[\\{frozen\_right}]\K\\{eqtb}[\\{cur\_val}]{}$;\par +\fi + +\M{1189}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{left\_right}:\6 +\&{if} ${}(\\{chr\_code}\E\\{left\_noad}){}$\1\5 +\\{print\_esc}(\X1659:\.{"left"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1660:\.{"right"}\X);\5 +\2\&{break};\par +\fi + +\M{1190}\B\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{left\_right}{}$:\5 +\\{math\_left\_right}(\,);\5 +\&{break};\par +\fi + +\M{1191}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{math\_left\_right}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{small\_number} \|t;\C{\\{left\_noad} or \\{right\_noad}}\6 +\&{pointer} \|p;\C{new noad}\7 +${}\|t\K\\{cur\_chr};{}$\6 +\&{if} ${}((\|t\E\\{right\_noad})\W(\\{cur\_group}\I\\{math\_left\_group})){}$\1\5 +\X1192:Try to recover from mismatched \.{\\right}\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|p\K\\{new\_noad}(\,);{}$\5 +${}\\{type}(\|p)\K\|t;{}$\5 +${}\\{scan\_delimiter}(\\{delimiter}(\|p),\39\\{false});{}$\6 +\&{if} ${}(\|t\E\\{left\_noad}){}$\5 +${}\{{}$\5 +\1\\{push\_math}(\\{math\_left\_group});\5 +${}\\{link}(\\{head})\K\|p;{}$\5 +${}\\{tail}\K\|p;{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1192}\B\X1192:Try to recover from mismatched \.{\\right}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_group}\E\\{math\_shift\_group}){}$\5 +${}\{{}$\5 +\1${}\\{scan\_delimiter}(\\{garbage},\39\\{false});{}$\5 +\\{print\_err}(\.{"Extra\ "});\5 +\\{print\_esc}(\X1660:\.{"right"}\X);\5 +\\{help1}(\.{"I'm\ ignoring\ a\ \\\\ri}\)\.{ght\ that\ had\ no\ matc}\)\.{hing\ \\\\left."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{off\_save}(\,);\2\6 +\4${}\}{}$\2\par +\U1191.\fi + +\M{1193}Here is the only way out of math mode. + +\Y\B\4\X1056:Cases of \\{main\_control} that build boxes and lists\X${}\mathrel+\E{}$\6 +\4\&{case} \\{mmode}${}+\\{math\_shift}{}$:\6 +\&{if} ${}(\\{cur\_group}\E\\{math\_shift\_group}){}$\1\5 +\\{after\_math}(\,);\2\6 +\&{else}\1\5 +\\{off\_save}(\,);\5 +\2\&{break};\par +\fi + +\M{1194}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{after\_math}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{bool} \|l;\C{`\.{\\leqno}' instead of `\.{\\eqno}'}\6 +\&{bool} \\{danger};\C{not enough symbol fonts are present}\6 +\&{int} \|m;\C{\\{mmode} or ${-}\\{mmode}$}\6 +\&{pointer} \|p;\C{the formula}\6 +\&{pointer} \|a;\C{box containing equation number}\7 +\X1198:Local variables for finishing a displayed formula\X\6 +${}\\{danger}\K\\{false};{}$\5 +\X1195: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 +${}\|l\K\\{false};{}$\5 +${}\|p\K\\{fin\_mlist}(\\{null}){}$;\C{this pops the nest}\6 +\&{if} ${}(\\{mode}\E{-}\|m{}$)\C{end of equation number}\6 +${}\{{}$\5 +\1\X1197: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}\E\\{math\_shift\_group}$}\6 +\&{if} ${}(\\{saved}(\T{0})\E\T{1}){}$\1\5 +${}\|l\K\\{true};{}$\2\6 +${}\\{danger}\K\\{false};{}$\5 +\X1195: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 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\|a\K\\{null};{}$\2\6 +\&{if} ${}(\|m<\T{0}){}$\1\5 +\X1196:Finish math in text\X\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\|a\E\\{null}){}$\1\5 +\X1197:Check that another \.\$ follows\X;\2\6 +\X1199:Finish displayed math\X;\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1195}\B\X1195:Check that the necessary fonts for math symbols are present; if not, flush the current math lists and set \\{danger}: $\K$ \\{true}\X${}\E{}$\6 +\&{if} ${}((\\{font\_params}[\\{fam\_fnt}(\T{2}+\\{text\_size})]<\\{total\_mathsy\_params})\V\30(\\{font\_params}[\\{fam\_fnt}(\T{2}+\\{script\_size})]<\\{total\_mathsy\_params})\V\30(\\{font\_params}[\\{fam\_fnt}(\T{2}+\\{script\_script\_size})]<% +\\{total\_mathsy\_params})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Math\ formula\ delete}\)\.{d:\ Insufficient\ symb}\)\.{ol\ fonts"});\6 +\\{help3}(\.{"Sorry,\ but\ I\ can't\ }\)\.{typeset\ math\ unless\ }\)\.{\\\\textfont\ 2"})\6 +(\.{"and\ \\\\scriptfont\ 2\ }\)\.{and\ \\\\scriptscriptfo}\)\.{nt\ 2\ have\ all"})\6 +(\.{"the\ \\\\fontdimen\ val}\)\.{ues\ needed\ in\ math\ s}\)\.{ymbol\ fonts."});\6 +\&{error} (\,)\1\5 +;\2\6 +\\{flush\_math}(\,);\5 +${}\\{danger}\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}((\\{font\_params}[\\{fam\_fnt}(\T{3}+\\{text\_size})]<\\{total\_mathex\_params})\V\30(\\{font\_params}[\\{fam\_fnt}(\T{3}+\\{script\_size})]<\\{total\_mathex\_params})\V\30(\\{font\_params}[\\{fam\_fnt}(\T{3}+\\{script\_script% +\_size})]<\\{total\_mathex\_params})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Math\ formula\ delete}\)\.{d:\ Insufficient\ exte}\)\.{nsion\ fonts"});\6 +\\{help3}(\.{"Sorry,\ but\ I\ can't\ }\)\.{typeset\ math\ unless\ }\)\.{\\\\textfont\ 3"})\6 +(\.{"and\ \\\\scriptfont\ 3\ }\)\.{and\ \\\\scriptscriptfo}\)\.{nt\ 3\ have\ all"})\6 +(\.{"the\ \\\\fontdimen\ val}\)\.{ues\ needed\ in\ math\ e}\)\.{xtension\ fonts."});\6 +\&{error} (\,)\1\5 +;\2\6 +\\{flush\_math}(\,);\5 +${}\\{danger}\K\\{true};{}$\6 +\4${}\}{}$\2\par +\U1194.\fi + +\M{1196}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\B\4\X1196:Finish math in text\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{tail\_append}(\\{new\_math}(\\{math\_surround},\39\\{before}));{}$\5 +${}\\{cur\_mlist}\K\|p;{}$\5 +${}\\{cur\_style}\K\\{text\_style};{}$\5 +${}\\{mlist\_penalties}\K(\\{mode}>\T{0});{}$\5 +\\{mlist\_to\_hlist}(\,);\5 +${}\\{link}(\\{tail})\K\\{link}(\\{temp\_head});{}$\6 +\&{while} ${}(\\{link}(\\{tail})\I\\{null}){}$\1\5 +${}\\{tail}\K\\{link}(\\{tail});{}$\2\6 +${}\\{tail\_append}(\\{new\_math}(\\{math\_surround},\39\\{after}));{}$\5 +${}\\{space\_factor}\K\T{1000};{}$\5 +\\{unsave}(\,);\6 +\4${}\}{}$\2\par +\U1194.\fi + +\M{1197}\TeX\ gets to the following part of the program when the first `\.\$' ending +a display has been scanned. + +\Y\B\4\X1197:Check that another \.\$ follows\X${}\E{}$\6 +${}\{{}$\5 +\1\\{get\_x\_token}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\I\\{math\_shift}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Display\ math\ should}\)\.{\ end\ with\ \$\$"});\5 +\\{help2}(\.{"The\ `\$'\ that\ I\ just}\)\.{\ saw\ supposedly\ matc}\)\.{hes\ a\ previous\ `\$\$'.}\)\.{"})\6 +(\.{"So\ I\ shall\ assume\ t}\)\.{hat\ you\ typed\ `\$\$'\ b}\)\.{oth\ times."});\5 +\\{back\_error}(\,);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\Us1194\ET1206.\fi + +\M{1198}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\B\4\X1198:Local variables for finishing a displayed formula\X${}\E{}$\6 +\&{pointer} \|b;\C{box containing the equation}\6 +\&{scaled} \|w;\C{width of the equation}\6 +\&{scaled} \|z;\C{width of the line}\6 +\&{scaled} \|e;\C{width of equation number}\6 +\&{scaled} \|q;\C{width of equation number plus space to separate from equation}\6 +\&{scaled} \|d;\C{displacement of equation in the line}\6 +\&{scaled} \|s;\C{move the line right this much}\6 +\&{small\_number} \\{g1}${},{}$ \\{g2};\C{glue parameter codes for before and after}\6 +\&{pointer} \|r;\C{kern node used to position the display}\6 +\&{pointer} \|t;\C{tail of adjustment list}\par +\U1194.\fi + +\M{1199}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\B\4\X1199:Finish displayed math\X${}\E{}$\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\E\\{null})\V\\{danger}){}$\5 +${}\{{}$\5 +\1${}\|e\K\T{0};{}$\5 +${}\|q\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|e\K\\{width}(\|a);{}$\5 +${}\|q\K\|e+\\{math\_quad}(\\{text\_size});{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|w+\|q>\|z){}$\1\5 +\X1201:Squeeze the equation as much as possible; if there is an equation number that should go on a separate line by itself, set~\|e: $\K$ \T{0}\X;\2\6 +\X1202:Determine the displacement, \|d, of the left edge of the equation, with respect to the line size \|z, assuming that $\|l\K\\{false}$\X;\6 +\X1203:Append the glue or equation number preceding the display\X;\6 +\X1204:Append the display and perhaps also the equation number\X;\6 +\X1205:Append the glue or equation number following the display\X;\6 +\\{resume\_after\_display}(\,)\par +\U1194.\fi + +\M{1200}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{resume\_after\_display}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_group}\I\\{math\_shift\_group}){}$\1\5 +\\{confusion}(\X1742:\.{"display"}\X);\2\6 +\\{unsave}(\,);\5 +${}\\{prev\_graf}\K\\{prev\_graf}+\T{3};{}$\5 +\\{push\_nest}(\,);\5 +${}\\{mode}\K\\{hmode};{}$\5 +${}\\{space\_factor}\K\T{1000};{}$\5 +\\{set\_cur\_lang};\5 +${}\\{clang}\K\\{cur\_lang};{}$\5 +${}\\{prev\_graf}\K(\\{norm\_min}(\\{left\_hyphen\_min})*\T{\~100}+\\{norm\_min}(\\{right\_hyphen\_min}))*\T{\~200000}+\\{cur\_lang};{}$\5 +\X443:Scan an optional space\X;\6 +\&{if} ${}(\\{nest\_ptr}\E\T{1}){}$\1\5 +\\{build\_page}(\,);\2\6 +\4${}\}{}$\2\par +\fi + +\M{1201}The user can force the equation number to go on a separate line +by causing its width to be zero. + +\Y\B\4\X1201:Squeeze the equation as much as possible; if there is an equation number that should go on a separate line by itself, set~\|e: $\K$ \T{0}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}((\|e\I\T{0})\W((\|w-\\{total\_shrink}[\\{normal}]+\|q\Z\|z)\V\30(\\{total\_shrink}[\\{fil}]\I\T{0})\V(\\{total\_shrink}[\\{fill}]\I\T{0})\V(\\{total\_shrink}[\\{filll}]\I\T{0}))){}$\5 +${}\{{}$\5 +\1${}\\{free\_node}(\|b,\39\\{box\_node\_size});{}$\5 +${}\|b\K\\{hpack}(\|p,\39\|z-\|q,\39\\{exactly});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|e\K\T{0};{}$\6 +\&{if} ${}(\|w>\|z){}$\5 +${}\{{}$\5 +\1${}\\{free\_node}(\|b,\39\\{box\_node\_size});{}$\5 +${}\|b\K\\{hpack}(\|p,\39\|z,\39\\{exactly});{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +${}\|w\K\\{width}(\|b);{}$\6 +\4${}\}{}$\2\par +\U1199.\fi + +\M{1202}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\B\4\X1202:Determine the displacement, \|d, of the left edge of the equation, with respect to the line size \|z, assuming that $\|l\K\\{false}$\X${}\E{}$\6 +$\|d\K\\{half}(\|z-\|w);{}$\6 +\&{if} ${}((\|e>\T{0})\W(\|d<\T{2}*\|e){}$)\C{too close}\6 +${}\{{}$\5 +\1${}\|d\K\\{half}(\|z-\|w-\|e);{}$\6 +\&{if} ${}(\|p\I\\{null}){}$\1\6 +\&{if} ${}(\R\\{is\_char\_node}(\|p)){}$\1\6 +\&{if} ${}(\\{type}(\|p)\E\\{glue\_node}){}$\1\5 +${}\|d\K\T{0};{}$\2\2\2\6 +\4${}\}{}$\2\par +\U1199.\fi + +\M{1203}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\B\4\X1203:Append the glue or equation number preceding the display\X${}\E{}$\6 +\\{tail\_append}(\\{new\_penalty}(\\{pre\_display\_penalty}));\6 +\&{if} ${}((\|d+\|s\Z\\{pre\_display\_size})\V\|l{}$)\C{not enough clearance}\6 +${}\{{}$\5 +\1${}\\{g1}\K\\{above\_display\_skip\_code};{}$\5 +${}\\{g2}\K\\{below\_display\_skip\_code};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{g1}\K\\{above\_display\_short\_skip\_code};{}$\5 +${}\\{g2}\K\\{below\_display\_short\_skip\_code};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|l\W(\|e\E\T{0}){}$)\C{it follows that $\\{type}(\|a)\E\\{hlist\_node}$}\6 +${}\{{}$\5 +\1${}\\{shift\_amount}(\|a)\K\|s;{}$\5 +\\{append\_to\_vlist}(\|a);\5 +\\{tail\_append}(\\{new\_penalty}(\\{inf\_penalty}));\6 +\4${}\}{}$\2\6 +\&{else} \\{tail\_append}(\\{new\_param\_glue}(\\{g1}))\par +\U1199.\fi + +\M{1204}\B\X1204:Append the display and perhaps also the equation number\X${}\E{}$\6 +\&{if} ${}(\|e\I\T{0}){}$\5 +${}\{{}$\5 +\1${}\|r\K\\{new\_kern}(\|z-\|w-\|e-\|d);{}$\6 +\&{if} (\|l)\5 +${}\{{}$\5 +\1${}\\{link}(\|a)\K\|r;{}$\5 +${}\\{link}(\|r)\K\|b;{}$\5 +${}\|b\K\|a;{}$\5 +${}\|d\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{link}(\|b)\K\|r;{}$\5 +${}\\{link}(\|r)\K\|a;{}$\6 +\4${}\}{}$\2\6 +${}\|b\K\\{hpack}(\|b,\39\\{natural});{}$\6 +\4${}\}{}$\2\6 +${}\\{shift\_amount}(\|b)\K\|s+\|d;$ \\{append\_to\_vlist}(\|b)\par +\U1199.\fi + +\M{1205}\B\X1205:Append the glue or equation number following the display\X${}\E{}$\6 +\&{if} ${}((\|a\I\\{null})\W(\|e\E\T{0})\W\R\|l){}$\5 +${}\{{}$\5 +\1\\{tail\_append}(\\{new\_penalty}(\\{inf\_penalty}));\5 +${}\\{shift\_amount}(\|a)\K\|s+\|z-\\{width}(\|a);{}$\5 +\\{append\_to\_vlist}(\|a);\5 +${}\\{g2}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|t\I\\{adjust\_head}{}$)\C{migrating material comes after equation number}\6 +${}\{{}$\5 +\1${}\\{link}(\\{tail})\K\\{link}(\\{adjust\_head});{}$\5 +${}\\{tail}\K\|t;{}$\6 +\4${}\}{}$\2\6 +\\{tail\_append}(\\{new\_penalty}(\\{post\_display\_penalty})); \&{if} ${}(\\{g2}>\T{0})$ \\{tail\_append}(\\{new\_param\_glue}(\\{g2}))\par +\U1199.\fi + +\M{1206}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\B\4\X1206:Finish an alignment in a display\X${}\E{}$\6 +${}\{{}$\5 +\1\\{do\_assignments}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\I\\{math\_shift}){}$\1\5 +\X1207:Pontificate about improper alignment in display\X\2\6 +\&{else}\1\5 +\X1197: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\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 +\4${}\}{}$\2\par +\U812.\fi + +\M{1207}\B\X1207:Pontificate about improper alignment in display\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ \$\$\ inserted}\)\.{"});\5 +\\{help2}(\.{"Displays\ can\ use\ sp}\)\.{ecial\ alignments\ (li}\)\.{ke\ \\\\eqalignno)"})\6 +(\.{"only\ if\ nothing\ but}\)\.{\ the\ alignment\ itsel}\)\.{f\ is\ between\ \$\$'s."});\5 +\\{back\_error}(\,);\6 +\4${}\}{}$\2\par +\U1206.\fi + +\N{1}{1208}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\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1743:\.{"long"}\X,\39\\{prefix},\39\T{1});{}$\5 +${}\\{primitive}(\X1744:\.{"outer"}\X,\39\\{prefix},\39\T{2});{}$\5 +${}\\{primitive}(\X1745:\.{"global"}\X,\39\\{prefix},\39\T{4});{}$\5 +${}\\{primitive}(\X1746:\.{"def"}\X,\39\\{def},\39\T{0});{}$\5 +${}\\{primitive}(\X1747:\.{"gdef"}\X,\39\\{def},\39\T{1});{}$\5 +${}\\{primitive}(\X1748:\.{"edef"}\X,\39\\{def},\39\T{2});{}$\5 +${}\\{primitive}(\X1749:\.{"xdef"}\X,\39\\{def},\39\T{3}){}$;\par +\fi + +\M{1209}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{prefix}:\6 +\&{if} ${}(\\{chr\_code}\E\T{1}){}$\1\5 +\\{print\_esc}(\X1743:\.{"long"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\T{2}){}$\1\5 +\\{print\_esc}(\X1744:\.{"outer"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1745:\.{"global"}\X);\5 +\2\&{break};\6 +\4\&{case} \\{def}:\6 +\&{if} ${}(\\{chr\_code}\E\T{0}){}$\1\5 +\\{print\_esc}(\X1746:\.{"def"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\T{1}){}$\1\5 +\\{print\_esc}(\X1747:\.{"gdef"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\T{2}){}$\1\5 +\\{print\_esc}(\X1748:\.{"edef"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1749:\.{"xdef"}\X);\5 +\2\&{break};\par +\fi + +\M{1210}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\B\4\X1210:Cases of \\{main\_control} that don't depend on \\{mode}\X${}\E{}$\6 +\\{any\_mode}(\\{toks\_register}):\5 +\\{any\_mode}(\\{assign\_toks}):\5 +\\{any\_mode}(\\{assign\_int}):\5 +\\{any\_mode}(\\{assign\_dimen}):\5 +\\{any\_mode}(\\{assign\_glue}):\5 +\\{any\_mode}(\\{assign\_mu\_glue}):\5 +\\{any\_mode}(\\{assign\_font\_dimen}):\5 +\\{any\_mode}(\\{assign\_font\_int}):\5 +\\{any\_mode}(\\{set\_aux}):\5 +\\{any\_mode}(\\{set\_prev\_graf}):\5 +\\{any\_mode}(\\{set\_page\_dimen}):\5 +\\{any\_mode}(\\{set\_page\_int}):\5 +\\{any\_mode}(\\{set\_box\_dimen}):\5 +\\{any\_mode}(\\{set\_shape}):\5 +\\{any\_mode}(\\{def\_code}):\5 +\\{any\_mode}(\\{def\_family}):\5 +\\{any\_mode}(\\{set\_font}):\5 +\\{any\_mode}(\\{def\_font}): \\{any\_mode}(\&{register}) : \6 +\4\\{any\_mode}(\\{advance}):\5 +\\{any\_mode}(\\{multiply}):\5 +\\{any\_mode}(\\{divide}):\5 +\\{any\_mode}(\\{prefix}):\5 +\\{any\_mode}(\\{let}):\5 +\\{any\_mode}(\\{shorthand\_def}):\5 +\\{any\_mode}(\\{read\_to\_cs}):\5 +\\{any\_mode}(\\{def}):\5 +\\{any\_mode}(\\{set\_box}):\5 +\\{any\_mode}(\\{hyph\_data}):\5 +\\{any\_mode}(\\{set\_interaction}):\5 +\\{prefixed\_command}(\,);\5 +\&{break};\par +\As1268, 1271, 1274, 1276, 1285\ETs1290. +\U1045.\fi + +\M{1211}If the user says, e.g., `\.{\\global\\global}', the redundancy is +silently accepted. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\hbox{\4}\X1215:Declare subprocedures for \\{prefixed\_command}\X\hbox{}\7 +\&{void} \\{prefixed\_command}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{small\_number} \|a;\C{accumulated prefix codes so far}\6 +\&{internal\_font\_number} \|f;\C{identifies a font}\6 +\&{int} \|j;\C{index into a \.{\\parshape} specification}\6 +\&{font\_index} \|k;\C{index into \\{font\_info}}\6 +\&{pointer} \|p${},{}$ \|q;\C{for temporary short-term use}\6 +\&{int} \|n;\C{ditto}\6 +\&{bool} \|e;\C{should a definition be expanded? or was \.{\\let} not done?}\7 +${}\|a\K\T{0};{}$\6 +\&{while} ${}(\\{cur\_cmd}\E\\{prefix}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\R\\{odd}(\|a/\\{cur\_chr})){}$\1\5 +${}\|a\K\|a+\\{cur\_chr};{}$\2\6 +\X404:Get the next non-blank non-relax non-call token\X;\6 +\&{if} ${}(\\{cur\_cmd}\Z\\{max\_non\_prefixed\_command}){}$\1\5 +\X1212:Discard erroneous prefixes and \&{return}\X;\2\6 +\4${}\}{}$\2\6 +\X1213:Discard the prefixes \.{\\long} and \.{\\outer} if they are irrelevant\X;\6 +\X1214:Adjust \(f)for the setting of \.{\\globaldefs}\X;\6 +\&{switch} (\\{cur\_cmd})\5 +${}\{{}$\1\6 +\hbox{\4}\X1217:Assignments\X\6 +\4\&{default}:\5 +\\{confusion}(\X1750:\.{"prefix"}\X);\6 +\4${}\}{}$\2\6 +\4\\{done}:\5 +\X1269:Insert a token saved by \.{\\afterassignment}, if any\X;\6 +\4${}\}{}$\2\par +\fi + +\M{1212}\B\X1212:Discard erroneous prefixes and \&{return}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"You\ can't\ use\ a\ pre}\)\.{fix\ with\ `"});\5 +${}\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr});{}$\5 +\\{print\_char}(\.{'\\''});\5 +\\{help1}(\.{"I'll\ pretend\ you\ di}\)\.{dn't\ say\ \\\\long\ or\ \\}\)\.{\\outer\ or\ \\\\global."});\5 +\\{back\_error}(\,);\5 +\&{return};\6 +\4${}\}{}$\2\par +\U1211.\fi + +\M{1213}\B\X1213:Discard the prefixes \.{\\long} and \.{\\outer} if they are irrelevant\X${}\E{}$\6 +\&{if} ${}((\\{cur\_cmd}\I\\{def})\W(\|a\MOD\T{4}\I\T{0})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"You\ can't\ use\ `"});\5 +\\{print\_esc}(\X1743:\.{"long"}\X);\5 +\\{print\_str}(\.{"'\ or\ `"});\5 +\\{print\_esc}(\X1744:\.{"outer"}\X);\5 +\\{print\_str}(\.{"'\ with\ `"});\5 +${}\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr});{}$\5 +\\{print\_char}(\.{'\\''});\5 +\\{help1}(\.{"I'll\ pretend\ you\ di}\)\.{dn't\ say\ \\\\long\ or\ \\}\)\.{\\outer\ here."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\U1211.\fi + +\M{1214}The previous routine does not have to adjust \|a so that $\|a\MOD\T{4}\E\T{0}$, +since the following routines test for the \.{\\global} prefix as follows. + +\Y\B\4\D$\\{global}$ \5 +$(\|a\G\T{4}{}$)\par +\B\4\D$\&{define}(\|X,\|Y,\|Z)$ \6 +\&{if} (\\{global})\1\5 +${}\\{geq\_define}(\|X,\39\|Y,\39\|Z){}$;\5 +\2\&{else} $\\{eq\_define}(\|X,\39\|Y,\39\|Z{}$)\par +\B\4\D$\\{word\_define}(\|X,\|Y)$ \6 +\&{if} (\\{global})\1\5 +${}\\{geq\_word\_define}(\|X,\39\|Y){}$;\5 +\2\&{else} $\\{eq\_word\_define}(\|X,\39\|Y{}$)\par +\Y\B\4\X1214:Adjust \(f)for the setting of \.{\\globaldefs}\X${}\E{}$\6 +\&{if} ${}(\\{global\_defs}\I\T{0}){}$\1\6 +\&{if} ${}(\\{global\_defs}<\T{0}){}$\5 +${}\{{}$\5 +\1\&{if} (\\{global})\1\5 +${}\|a\K\|a-\T{4};{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\R\\{global}){}$\1\5 +${}\|a\K\|a+\T{4};{}$\2\6 +\4${}\}{}$\2\2\par +\U1211.\fi + +\M{1215}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\B\4\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\E{}$\6 +\&{void} \\{get\_r\_token}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{restart}:\6 +\&{do}\5 +${}\{{}$\1\6 +\\{get\_token}(\,);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{cur\_tok}\I\\{space\_token}));{}$\6 +\&{if} ${}((\\{cur\_cs}\E\T{0})\V(\\{cur\_cs}>\\{frozen\_control\_sequence})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ control\ seq}\)\.{uence\ inserted"});\5 +\\{help5}(\.{"Please\ don't\ say\ `\\}\)\.{\\def\ cs\{...\}',\ say\ `}\)\.{\\\\def\\\\cs\{...\}'."})\6 +(\.{"I've\ inserted\ an\ in}\)\.{accessible\ control\ s}\)\.{equence\ so\ that\ your}\)\.{"})\6 +(\.{"definition\ will\ be\ }\)\.{completed\ without\ mi}\)\.{xing\ me\ up\ too\ badly}\)\.{."})\6 +(\.{"You\ can\ recover\ gra}\)\.{ciously\ from\ this\ er}\)\.{ror,\ if\ you're"})\6 +(\.{"careful;\ see\ exerci}\)\.{se\ 27.2\ in\ The\ TeXbo}\)\.{ok."});\6 +\&{if} ${}(\\{cur\_cs}\E\T{0}){}$\1\5 +\\{back\_input}(\,);\2\6 +${}\\{cur\_tok}\K\\{cs\_token\_flag}+\\{frozen\_protection};{}$\5 +\\{ins\_error}(\,);\5 +\&{goto} \\{restart};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\As1229, 1236, 1243, 1244, 1245, 1246, 1247, 1257\ETs1265. +\U1211.\fi + +\M{1216}\B\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\6 +$\\{text}(\\{frozen\_protection})\K\X1751:\.{"inaccessible"}\X{}$;\par +\fi + +\M{1217}Here's an example of the way many of the following routines operate. +(Unfortunately, they aren't all as simple as this.) + +\Y\B\4\X1217:Assignments\X${}\E{}$\6 +\&{case} \\{set\_font}: \&{define} $(\\{cur\_font\_loc},\39\\{data},\39\\{cur\_chr}){}$;\5 +\&{break};\par +\As1218, 1221, 1224, 1225, 1226, 1228, 1232, 1234, 1235, 1241, 1242, 1248, 1252, 1253, 1256\ETs1264. +\U1211.\fi + +\M{1218}When a \\{def} command has been scanned, +\\{cur\_chr} is odd if the definition is supposed to be global, and +$\\{cur\_chr}\G\T{2}$ if the definition is supposed to be expanded. + +\Y\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\&{case} \\{def}: $\{{}$\5 +\&{if} ${}(\\{odd}(\\{cur\_chr})\W\R\\{global}\W(\\{global\_defs}\G\T{0})){}$\1\5 +${}\|a\K\|a+\T{4};{}$\2\6 +${}\|e\K(\\{cur\_chr}\G\T{2});{}$\5 +\\{get\_r\_token}(\,);\5 +${}\|p\K\\{cur\_cs};{}$\5 +${}\|q\K\\{scan\_toks}(\\{true},\39\|e);$ \&{define} $(\|p,\39\\{call}+(\|a\MOD\T{4}),\39\\{def\_ref});$ $\}{}$\5 +\&{break};\par +\fi + +\M{1219}Both \.{\\let} and \.{\\futurelet} share the command code \\{let}. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1752:\.{"let"}\X,\39\\{let},\39\\{normal}){}$;\6 +${}\\{primitive}(\X1753:\.{"futurelet"}\X,\39\\{let},\39\\{normal}+\T{1}){}$;\par +\fi + +\M{1220}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{let}:\6 +\&{if} ${}(\\{chr\_code}\I\\{normal}){}$\1\5 +\\{print\_esc}(\X1753:\.{"futurelet"}\X);\5 +\2\&{else}\1\5 +\\{print\_esc}(\X1752:\.{"let"}\X);\5 +\2\&{break};\par +\fi + +\M{1221}\B\X1217:Assignments\X${}\mathrel+\E{}$\6 +\&{case} \\{let}: $\{{}$\5 +$\|n\K\\{cur\_chr};{}$\5 +\\{get\_r\_token}(\,);\5 +${}\|p\K\\{cur\_cs};{}$\6 +\&{if} ${}(\|n\E\\{normal}){}$\5 +${}\{{}$\5 +\1\&{do}\5 +${}\{{}$\1\6 +\\{get\_token}(\,);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{cur\_cmd}\I\\{spacer}));{}$\6 +\&{if} ${}(\\{cur\_tok}\E\\{other\_token}+\.{'='}){}$\5 +${}\{{}$\5 +\1\\{get\_token}(\,);\6 +\&{if} ${}(\\{cur\_cmd}\E\\{spacer}){}$\1\5 +\\{get\_token}(\,);\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\C{note that \\{back\_input} doesn't affect \\{cur\_cmd}, \\{cur\_chr}}\2\6 +\&{if} ${}(\\{cur\_cmd}\G\\{call}){}$\1\5 +\\{add\_token\_ref}(\\{cur\_chr});\2\6 +\&{define} $(\|p,\39\\{cur\_cmd},\39\\{cur\_chr});$ $\}{}$\5 +\&{break};\par +\fi + +\M{1222}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\B\4\D$\\{char\_def\_code}$ \5 +\T{0}\C{\\{shorthand\_def} for \.{\\chardef}}\par +\B\4\D$\\{math\_char\_def\_code}$ \5 +\T{1}\C{\\{shorthand\_def} for \.{\\mathchardef}}\par +\B\4\D$\\{count\_def\_code}$ \5 +\T{2}\C{\\{shorthand\_def} for \.{\\countdef}}\par +\B\4\D$\\{dimen\_def\_code}$ \5 +\T{3}\C{\\{shorthand\_def} for \.{\\dimendef}}\par +\B\4\D$\\{skip\_def\_code}$ \5 +\T{4}\C{\\{shorthand\_def} for \.{\\skipdef}}\par +\B\4\D$\\{mu\_skip\_def\_code}$ \5 +\T{5}\C{\\{shorthand\_def} for \.{\\muskipdef}}\par +\B\4\D$\\{toks\_def\_code}$ \5 +\T{6}\C{\\{shorthand\_def} for \.{\\toksdef}}\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1754:\.{"chardef"}\X,\39\\{shorthand\_def},\39\\{char\_def\_code}){}$;\6 +${}\\{primitive}(\X1755:\.{"mathchardef"}\X,\39\\{shorthand\_def},\39\\{math\_char\_def\_code}){}$;\6 +${}\\{primitive}(\X1756:\.{"countdef"}\X,\39\\{shorthand\_def},\39\\{count\_def\_code}){}$;\6 +${}\\{primitive}(\X1757:\.{"dimendef"}\X,\39\\{shorthand\_def},\39\\{dimen\_def\_code}){}$;\6 +${}\\{primitive}(\X1758:\.{"skipdef"}\X,\39\\{shorthand\_def},\39\\{skip\_def\_code}){}$;\6 +${}\\{primitive}(\X1759:\.{"muskipdef"}\X,\39\\{shorthand\_def},\39\\{mu\_skip\_def\_code}){}$;\6 +${}\\{primitive}(\X1760:\.{"toksdef"}\X,\39\\{shorthand\_def},\39\\{toks\_def\_code}){}$;\par +\fi + +\M{1223}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{shorthand\_def}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{char\_def\_code}:\5 +\\{print\_esc}(\X1754:\.{"chardef"}\X);\5 +\&{break};\6 +\4\&{case} \\{math\_char\_def\_code}:\5 +\\{print\_esc}(\X1755:\.{"mathchardef"}\X);\5 +\&{break};\6 +\4\&{case} \\{count\_def\_code}:\5 +\\{print\_esc}(\X1756:\.{"countdef"}\X);\5 +\&{break};\6 +\4\&{case} \\{dimen\_def\_code}:\5 +\\{print\_esc}(\X1757:\.{"dimendef"}\X);\5 +\&{break};\6 +\4\&{case} \\{skip\_def\_code}:\5 +\\{print\_esc}(\X1758:\.{"skipdef"}\X);\5 +\&{break};\6 +\4\&{case} \\{mu\_skip\_def\_code}:\5 +\\{print\_esc}(\X1759:\.{"muskipdef"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1760:\.{"toksdef"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{char\_given}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1535:\.{"char"}\X);\5 +\\{print\_hex}(\\{chr\_code});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{math\_given}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1546:\.{"mathchar"}\X);\5 +\\{print\_hex}(\\{chr\_code});\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1224}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\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\&{case} \\{shorthand\_def}: $\{{}$\5 +$\|n\K\\{cur\_chr};{}$\5 +\\{get\_r\_token}(\,);\5 +${}\|p\K\\{cur\_cs};$ \&{define} $(\|p,\39\\{relax},\39\T{256});{}$\5 +\\{scan\_optional\_equals}(\,); \&{switch} (\|n) $\{$ \&{case} \\{char\_def\_code}: $\{{}$\5 +\\{scan\_char\_num}(\,); \&{define} $(\|p,\39\\{char\_given},\39\\{cur\_val});$ $\}{}$\5 +\&{break}; \&{case} \\{math\_char\_def\_code}: $\{{}$\5 +\\{scan\_fifteen\_bit\_int}(\,); \&{define} $(\|p,\39\\{math\_given},\39\\{cur\_val});$ $\}{}$\5 +\&{break}; \&{default}: $\{{}$\5 +\\{scan\_eight\_bit\_int}(\,); \&{switch} (\|n) $\{$ \&{case} \\{count\_def\_code}: \&{define} $(\|p,\39\\{assign\_int},\39\\{count\_base}+\\{cur\_val}){}$;\5 +\&{break}; \&{case} \\{dimen\_def\_code}: \&{define} $(\|p,\39\\{assign\_dimen},\39\\{scaled\_base}+\\{cur\_val}){}$;\5 +\&{break}; \&{case} \\{skip\_def\_code}: \&{define} $(\|p,\39\\{assign\_glue},\39\\{skip\_base}+\\{cur\_val}){}$;\5 +\&{break}; \&{case} \\{mu\_skip\_def\_code}: \&{define} $(\|p,\39\\{assign\_mu\_glue},\39\\{mu\_skip\_base}+\\{cur\_val}){}$;\5 +\&{break}; \&{case} \\{toks\_def\_code}: \&{define} $(\|p,\39\\{assign\_toks},\39\\{toks\_base}+\\{cur\_val});$ $\}{}$\C{there are no other cases}\6 +$\}$ $\}$ $\}{}$\5 +\&{break};\par +\fi + +\M{1225}\B\X1217:Assignments\X${}\mathrel+\E{}$\6 +\&{case} \\{read\_to\_cs}: $\{{}$\5 +\\{scan\_int}(\,);\5 +${}\|n\K\\{cur\_val};{}$\6 +\&{if} ${}(\R\\{scan\_keyword}(\X1642:\.{"to"}\X)){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Missing\ `to'\ insert}\)\.{ed"});\5 +\\{help2}(\.{"You\ should\ have\ sai}\)\.{d\ `\\\\read<number>\ to}\)\.{\ \\\\cs'."})\6 +(\.{"I'm\ going\ to\ look\ f}\)\.{or\ the\ \\\\cs\ now."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\\{get\_r\_token}(\,);\5 +${}\|p\K\\{cur\_cs};{}$\5 +${}\\{read\_toks}(\|n,\39\|p);$ \&{define} $(\|p,\39\\{call},\39\\{cur\_val});$ $\}{}$\5 +\&{break};\par +\fi + +\M{1226}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\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\&{case} \\{toks\_register}:\5 +\&{case} \\{assign\_toks}: $\{{}$\5 +$\|q\K\\{cur\_cs};{}$\6 +\&{if} ${}(\\{cur\_cmd}\E\\{toks\_register}){}$\5 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\5 +${}\|p\K\\{toks\_base}+\\{cur\_val};{}$\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\|p\K\\{cur\_chr}{}$;\C{$\|p\E\\{every\_par\_loc}$ or \\{output\_routine\_loc} or \dots}\2\6 +\\{scan\_optional\_equals}(\,);\5 +\X404:Get the next non-blank non-relax non-call token\X;\6 +\&{if} ${}(\\{cur\_cmd}\I\\{left\_brace}){}$\1\5 +\X1227: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});$ \&{if} ${}(\\{link}(\\{def\_ref})\E\\{null}{}$)\C{empty list: revert to the default}\6 +$\{{}$\5 +\&{define} $(\|p,\39\\{undefined\_cs},\39\\{null});{}$\5 +\\{free\_avail}(\\{def\_ref}); $\}$ \&{else} $\{{}$\5 +\&{if} ${}(\|p\E\\{output\_routine\_loc}{}$)\C{enclose in curlies}\6 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\6 +\&{define} $(\|p,\39\\{call},\39\\{def\_ref});$ $\}$ $\}{}$\5 +\&{break};\par +\fi + +\M{1227}\B\X1227:If the right-hand side is a token parameter or token register, finish the assignment and \&{goto} \\{done}\X${}\E{}$\6 +$\{{}$\5 +\&{if} ${}(\\{cur\_cmd}\E\\{toks\_register}){}$\5 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\5 +${}\\{cur\_cmd}\K\\{assign\_toks};{}$\5 +${}\\{cur\_chr}\K\\{toks\_base}+\\{cur\_val};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_cmd}\E\\{assign\_toks})$ $\{{}$\5 +$\|q\K\\{equiv}(\\{cur\_chr});$ \&{if} ${}(\|q\E\\{null})$ \&{define} $(\|p,\39\\{undefined\_cs},\39\\{null});$ \&{else} $\{{}$\5 +\\{add\_token\_ref}(\|q); \&{define} $(\|p,\39\\{call},\39\|q);$ $\}$ \&{goto} \\{done}; $\}$ $\}{}$\par +\U1226.\fi + +\M{1228}Similar routines are used to assign values to the numeric parameters. + +\Y\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\4\&{case} \\{assign\_int}:\6 +${}\{{}$\5 +\1${}\|p\K\\{cur\_chr};{}$\5 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_int}(\,);\5 +${}\\{word\_define}(\|p,\39\\{cur\_val});{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{assign\_dimen}:\6 +${}\{{}$\5 +\1${}\|p\K\\{cur\_chr};{}$\5 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_normal\_dimen};\5 +${}\\{word\_define}(\|p,\39\\{cur\_val});{}$\6 +\4${}\}{}$\5 +\2\&{break}; \&{case} \\{assign\_glue}:\5 +\&{case} \\{assign\_mu\_glue}: $\{{}$\5 +$\|p\K\\{cur\_chr};{}$\5 +${}\|n\K\\{cur\_cmd};{}$\5 +\\{scan\_optional\_equals}(\,);\6 +\&{if} ${}(\|n\E\\{assign\_mu\_glue}){}$\1\5 +\\{scan\_glue}(\\{mu\_val});\5 +\2\&{else}\1\5 +\\{scan\_glue}(\\{glue\_val});\2\6 +\\{trap\_zero\_glue}(\,); \&{define} $(\|p,\39\\{glue\_ref},\39\\{cur\_val});$ $\}{}$\5 +\&{break};\par +\fi + +\M{1229}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\B\4\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\mathrel+\E{}$\6 +\&{void} \\{trap\_zero\_glue}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{if} ${}((\\{width}(\\{cur\_val})\E\T{0})\W(\\{stretch}(\\{cur\_val})\E\T{0})\W(\\{shrink}(\\{cur\_val})\E\T{0})){}$\5 +${}\{{}$\5 +\1\\{add\_glue\_ref}(\\{zero\_glue});\5 +\\{delete\_glue\_ref}(\\{cur\_val});\5 +${}\\{cur\_val}\K\\{zero\_glue};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1230}The various character code tables are changed by the \\{def\_code} commands, +and the font families are declared by \\{def\_family}. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1441:\.{"catcode"}\X,\39\\{def\_code},\39\\{cat\_code\_base});{}$\5 +${}\\{primitive}(\X1445:\.{"mathcode"}\X,\39\\{def\_code},\39\\{math\_code\_base});{}$\5 +${}\\{primitive}(\X1442:\.{"lccode"}\X,\39\\{def\_code},\39\\{lc\_code\_base});{}$\5 +${}\\{primitive}(\X1443:\.{"uccode"}\X,\39\\{def\_code},\39\\{uc\_code\_base});{}$\5 +${}\\{primitive}(\X1444:\.{"sfcode"}\X,\39\\{def\_code},\39\\{sf\_code\_base});{}$\5 +${}\\{primitive}(\X1502:\.{"delcode"}\X,\39\\{def\_code},\39\\{del\_code\_base});{}$\5 +${}\\{primitive}(\X1438:\.{"textfont"}\X,\39\\{def\_family},\39\\{math\_font\_base});{}$\5 +${}\\{primitive}(\X1439:\.{"scriptfont"}\X,\39\\{def\_family},\39\\{math\_font\_base}+\\{script\_size});{}$\5 +${}\\{primitive}(\X1440:\.{"scriptscriptfont"}\X,\39\\{def\_family},\39\\{math\_font\_base}+\\{script\_script\_size}){}$;\par +\fi + +\M{1231}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{def\_code}:\6 +\&{if} ${}(\\{chr\_code}\E\\{cat\_code\_base}){}$\1\5 +\\{print\_esc}(\X1441:\.{"catcode"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{math\_code\_base}){}$\1\5 +\\{print\_esc}(\X1445:\.{"mathcode"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{lc\_code\_base}){}$\1\5 +\\{print\_esc}(\X1442:\.{"lccode"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{uc\_code\_base}){}$\1\5 +\\{print\_esc}(\X1443:\.{"uccode"}\X);\2\6 +\&{else} \&{if} ${}(\\{chr\_code}\E\\{sf\_code\_base}){}$\1\5 +\\{print\_esc}(\X1444:\.{"sfcode"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1502:\.{"delcode"}\X);\5 +\2\&{break};\6 +\4\&{case} \\{def\_family}:\5 +${}\\{print\_size}(\\{chr\_code}-\\{math\_font\_base}){}$;\5 +\&{break};\par +\fi + +\M{1232}The different types of code values have different legal ranges; the +following program is careful to check each case properly. + +\Y\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\&{case} \\{def\_code}: $\{{}$\5 +\X1233:Let \|n be the largest legal code value, based on \\{cur\_chr}\X;\6 +${}\|p\K\\{cur\_chr};{}$\5 +\\{scan\_char\_num}(\,);\5 +${}\|p\K\|p+\\{cur\_val};{}$\5 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_int}(\,);\6 +\&{if} ${}(((\\{cur\_val}<\T{0})\W(\|p<\\{del\_code\_base}))\V(\\{cur\_val}>\|n)){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Invalid\ code\ ("});\5 +\\{print\_int}(\\{cur\_val});\6 +\&{if} ${}(\|p<\\{del\_code\_base}){}$\1\5 +\\{print\_str}(\.{"),\ should\ be\ in\ the}\)\.{\ range\ 0.."});\2\6 +\&{else}\1\5 +\\{print\_str}(\.{"),\ should\ be\ at\ mos}\)\.{t\ "});\2\6 +\\{print\_int}(\|n);\5 +\\{help1}(\.{"I'm\ going\ to\ use\ 0\ }\)\.{instead\ of\ that\ ille}\)\.{gal\ code\ value."});\6 +\&{error} (\,)\1\5 +;\2\6 +${}\\{cur\_val}\K\T{0};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|p<\\{math\_code\_base})$ \&{define} $(\|p,\39\\{data},\39\\{cur\_val});$ \&{else} \&{if} ${}(\|p<\\{del\_code\_base})$ \&{define} $(\|p,\39\\{data},\39\\{hi}(\\{cur\_val}));{}$\6 +\&{else}\1\5 +${}\\{word\_define}(\|p,\39\\{cur\_val});{}$\2\6 +$\}{}$\5 +\&{break};\par +\fi + +\M{1233}\B\X1233:Let \|n be the largest legal code value, based on \\{cur\_chr}\X${}\E{}$\6 +\&{if} ${}(\\{cur\_chr}\E\\{cat\_code\_base}){}$\1\5 +${}\|n\K\\{max\_char\_code};{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_chr}\E\\{math\_code\_base}){}$\1\5 +${}\|n\K\T{\~100000};{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_chr}\E\\{sf\_code\_base}){}$\1\5 +${}\|n\K\T{\~77777};{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_chr}\E\\{del\_code\_base}){}$\1\5 +${}\|n\K\T{\~77777777};{}$\2\6 +\&{else} $\|n\K{}$\T{255}\par +\U1232.\fi + +\M{1234}\B\X1217:Assignments\X${}\mathrel+\E{}$\6 +\&{case} \\{def\_family}: $\{{}$\5 +$\|p\K\\{cur\_chr};{}$\5 +\\{scan\_four\_bit\_int}(\,);\5 +${}\|p\K\|p+\\{cur\_val};{}$\5 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_font\_ident}(\,); \&{define} $(\|p,\39\\{data},\39\\{cur\_val});$ $\}{}$\5 +\&{break};\par +\fi + +\M{1235}Next we consider changes to \TeX's numeric registers. + +\Y\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\&{case} \&{register} : \6 +\4\&{case} \\{advance}:\5 +\&{case} \\{multiply}:\5 +\&{case} \\{divide}:\5 +\\{do\_register\_command}(\|a);\5 +\&{break};\par +\fi + +\M{1236}We use the fact that \&{register} $<$ $\\{advance}<\\{multiply}<\\{divide}$. + +\Y\B\4\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\mathrel+\E{}$\6 +\&{void} \\{do\_register\_command}(\&{small\_number} \|a)\1\1 $\{{}$\5 +\&{pointer} \|l${},{}$ \|q${},{}$ \|r${},{}$ \|s;\C{for list manipulation}\6 +\&{uint8\_t} \|p;\C{type of register involved}\7 +${}\|q\K\\{cur\_cmd};{}$\5 +\X1237:Compute the register location \|l and its type \|p; but \&{return} if invalid\X;\6 +\&{if} ( \|q $\E$ \&{register} ) \\{scan\_optional\_equals}(\,);\6 +\&{else}\1\6 +\&{if} (\\{scan\_keyword}(\X1761:\.{"by"}\X))\1\5 +\\{do\_nothing};\C{optional `\.{by}'}\2\2\6 +${}\\{arith\_error}\K\\{false};{}$\6 +\&{if} ${}(\|q<\\{multiply}){}$\1\5 +\X1238:Compute result of \&{register} or \\{advance}, put it in \\{cur\_val}\X\2\6 +\&{else}\1\5 +\X1240:Compute result of \\{multiply} or \\{divide}, put it in \\{cur\_val}\X;\2\6 +\&{if} (\\{arith\_error})\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Arithmetic\ overflow}\)\.{"});\5 +\\{help2}(\.{"I\ can't\ carry\ out\ t}\)\.{hat\ multiplication\ o}\)\.{r\ division,"})\6 +(\.{"since\ the\ result\ is}\)\.{\ out\ of\ range."});\6 +\&{if} ${}(\|p\G\\{glue\_val}){}$\1\5 +\\{delete\_glue\_ref}(\\{cur\_val});\2\6 +\&{error} (\,)\1\5 +;\2\6 +\&{return};\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|p<\\{glue\_val}){}$\1\5 +${}\\{word\_define}(\|l,\39\\{cur\_val});{}$\2\6 +\&{else} $\{{}$\5 +\\{trap\_zero\_glue}(\,); \&{define} $(\|l,\39\\{glue\_ref},\39\\{cur\_val});$ $\}$ $\}{}$\par +\fi + +\M{1237}Here we use the fact that the consecutive codes $\\{int\_val}\dotdot\\{mu\_val}$ and +$\\{assign\_int}\dotdot\\{assign\_mu\_glue}$ correspond to each other nicely. + +\Y\B\4\X1237:Compute the register location \|l and its type \|p; but \&{return} if invalid\X${}\E{}$\6 +$\{{}$\5 +\&{if} ( \|q $\I$ \&{register} ) $\{{}$\5 +\\{get\_x\_token}(\,);\6 +\&{if} ${}((\\{cur\_cmd}\G\\{assign\_int})\W(\\{cur\_cmd}\Z\\{assign\_mu\_glue})){}$\5 +${}\{{}$\5 +\1${}\|l\K\\{cur\_chr};{}$\5 +${}\|p\K\\{cur\_cmd}-\\{assign\_int};{}$\5 +\&{goto} \\{found};\6 +\4${}\}{}$\2\6 +\&{if} ( \\{cur\_cmd} $\I$ \&{register} ) \6 +${}\{{}$\5 +\1\\{print\_err}(\.{"You\ can't\ use\ `"});\5 +${}\\{print\_cmd\_chr}(\\{cur\_cmd},\39\\{cur\_chr});{}$\5 +\\{print\_str}(\.{"'\ after\ "});\5 +${}\\{print\_cmd\_chr}(\|q,\39\T{0});{}$\5 +\\{help1}(\.{"I'm\ forgetting\ what}\)\.{\ you\ said\ and\ not\ ch}\)\.{anging\ anything."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{return};\6 +\4${}\}{}$\2\6 +$\}$ $\|p\K\\{cur\_chr};{}$\5 +\\{scan\_eight\_bit\_int}(\,);\6 +\&{switch} (\|p)\5 +${}\{{}$\1\6 +\4\&{case} \\{int\_val}:\5 +${}\|l\K\\{cur\_val}+\\{count\_base}{}$;\5 +\&{break};\6 +\4\&{case} \\{dimen\_val}:\5 +${}\|l\K\\{cur\_val}+\\{scaled\_base}{}$;\5 +\&{break};\6 +\4\&{case} \\{glue\_val}:\5 +${}\|l\K\\{cur\_val}+\\{skip\_base}{}$;\5 +\&{break};\6 +\4\&{case} \\{mu\_val}:\5 +${}\|l\K\\{cur\_val}+\\{mu\_skip\_base};{}$\6 +\4${}\}{}$\C{there are no other cases}\2\6 +$\}$ \\{found}:\par +\U1236.\fi + +\M{1238}\B\X1238:Compute result of \&{register} or \\{advance}, put it in \\{cur\_val}\X${}\E{}$\6 +\&{if} ${}(\|p<\\{glue\_val}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|p\E\\{int\_val}){}$\1\5 +\\{scan\_int}(\,);\5 +\2\&{else}\1\5 +\\{scan\_normal\_dimen};\2\6 +\&{if} ${}(\|q\E\\{advance}){}$\1\5 +${}\\{cur\_val}\K\\{cur\_val}+\\{eqtb}[\|l].\|i;{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{scan\_glue}(\|p);\6 +\&{if} ${}(\|q\E\\{advance}){}$\1\5 +\X1239:Compute the sum of two glue specs\X;\2\6 +\4${}\}{}$\2\par +\U1236.\fi + +\M{1239}\B\X1239:Compute the sum of two glue specs\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|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)\E\T{0}){}$\1\5 +${}\\{stretch\_order}(\|q)\K\\{normal};{}$\2\6 +\&{if} ${}(\\{stretch\_order}(\|q)\E\\{stretch\_order}(\|r)){}$\1\5 +${}\\{stretch}(\|q)\K\\{stretch}(\|q)+\\{stretch}(\|r);{}$\2\6 +\&{else} \&{if} ${}((\\{stretch\_order}(\|q)<\\{stretch\_order}(\|r))\W(\\{stretch}(\|r)\I\T{0})){}$\5 +${}\{{}$\5 +\1${}\\{stretch}(\|q)\K\\{stretch}(\|r);{}$\5 +${}\\{stretch\_order}(\|q)\K\\{stretch\_order}(\|r);{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{shrink}(\|q)\E\T{0}){}$\1\5 +${}\\{shrink\_order}(\|q)\K\\{normal};{}$\2\6 +\&{if} ${}(\\{shrink\_order}(\|q)\E\\{shrink\_order}(\|r)){}$\1\5 +${}\\{shrink}(\|q)\K\\{shrink}(\|q)+\\{shrink}(\|r);{}$\2\6 +\&{else} \&{if} ${}((\\{shrink\_order}(\|q)<\\{shrink\_order}(\|r))\W(\\{shrink}(\|r)\I\T{0})){}$\5 +${}\{{}$\5 +\1${}\\{shrink}(\|q)\K\\{shrink}(\|r);{}$\5 +${}\\{shrink\_order}(\|q)\K\\{shrink\_order}(\|r);{}$\6 +\4${}\}{}$\2\6 +${}\\{cur\_val}\K\|q;{}$\6 +\4${}\}{}$\2\par +\U1238.\fi + +\M{1240}\B\X1240:Compute result of \\{multiply} or \\{divide}, put it in \\{cur\_val}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_int}(\,);\6 +\&{if} ${}(\|p<\\{glue\_val}){}$\1\6 +\&{if} ${}(\|q\E\\{multiply}){}$\1\6 +\&{if} ${}(\|p\E\\{int\_val}){}$\1\5 +${}\\{cur\_val}\K\\{mult\_integers}(\\{eqtb}[\|l].\|i,\39\\{cur\_val});{}$\2\6 +\&{else}\1\5 +${}\\{cur\_val}\K\\{nx\_plus\_y}(\\{eqtb}[\|l].\|i,\39\\{cur\_val},\39\T{0});{}$\2\2\6 +\&{else}\1\5 +${}\\{cur\_val}\K\\{x\_over\_n}(\\{eqtb}[\|l].\|i,\39\\{cur\_val});{}$\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|s\K\\{equiv}(\|l);{}$\5 +${}\|r\K\\{new\_spec}(\|s);{}$\6 +\&{if} ${}(\|q\E\\{multiply}){}$\5 +${}\{{}$\5 +\1${}\\{width}(\|r)\K\\{nx\_plus\_y}(\\{width}(\|s),\39\\{cur\_val},\39\T{0});{}$\5 +${}\\{stretch}(\|r)\K\\{nx\_plus\_y}(\\{stretch}(\|s),\39\\{cur\_val},\39\T{0});{}$\5 +${}\\{shrink}(\|r)\K\\{nx\_plus\_y}(\\{shrink}(\|s),\39\\{cur\_val},\39\T{0});{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\6 +${}\\{cur\_val}\K\|r;{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1236.\fi + +\M{1241}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\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\4\&{case} \\{set\_box}:\6 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\6 +\&{if} (\\{global})\1\5 +${}\|n\K\T{256}+\\{cur\_val}{}$;\5 +\2\&{else}\1\5 +${}\|n\K\\{cur\_val};{}$\2\6 +\\{scan\_optional\_equals}(\,);\6 +\&{if} (\\{set\_box\_allowed})\1\5 +${}\\{scan\_box}(\\{box\_flag}+\|n);{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Improper\ "});\5 +\\{print\_esc}(\X1558:\.{"setbox"}\X);\5 +\\{help2}(\.{"Sorry,\ \\\\setbox\ is\ }\)\.{not\ allowed\ after\ \\\\}\)\.{halign\ in\ a\ display,}\)\.{"})\6 +(\.{"or\ between\ \\\\accent}\)\.{\ and\ an\ accented\ cha}\)\.{racter."});\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1242}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\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\4\&{case} \\{set\_aux}:\5 +\\{alter\_aux}(\,);\5 +\&{break};\6 +\4\&{case} \\{set\_prev\_graf}:\5 +\\{alter\_prev\_graf}(\,);\5 +\&{break};\6 +\4\&{case} \\{set\_page\_dimen}:\5 +\\{alter\_page\_so\_far}(\,);\5 +\&{break};\6 +\4\&{case} \\{set\_page\_int}:\5 +\\{alter\_integer}(\,);\5 +\&{break};\6 +\4\&{case} \\{set\_box\_dimen}:\5 +\\{alter\_box\_dimen}(\,);\5 +\&{break};\par +\fi + +\M{1243}\B\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\mathrel+\E{}$\6 +\&{void} \\{alter\_aux}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{halfword} \|c;\C{\\{hmode} or \\{vmode}}\7 +\&{if} ${}(\\{cur\_chr}\I\\{abs}(\\{mode})){}$\1\5 +\\{report\_illegal\_case}(\,);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|c\K\\{cur\_chr};{}$\5 +\\{scan\_optional\_equals}(\,);\6 +\&{if} ${}(\|c\E\\{vmode}){}$\5 +${}\{{}$\5 +\1\\{scan\_normal\_dimen};\5 +${}\\{prev\_depth}\K\\{cur\_val};{}$\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{scan\_int}(\,);\6 +\&{if} ${}((\\{cur\_val}\Z\T{0})\V(\\{cur\_val}>\T{32767})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Bad\ space\ factor"});\5 +\\{help1}(\.{"I\ allow\ only\ values}\)\.{\ in\ the\ range\ 1..327}\)\.{67\ here."});\5 +\\{int\_error}(\\{cur\_val});\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\\{space\_factor}\K\\{cur\_val};{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1244}\B\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\mathrel+\E{}$\6 +\&{void} \\{alter\_prev\_graf}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \|p;\C{index into \\{nest}}\7 +${}\\{nest}[\\{nest\_ptr}]\K\\{cur\_list};{}$\5 +${}\|p\K\\{nest\_ptr};{}$\6 +\&{while} ${}(\\{abs}(\\{nest}[\|p].\\{mode\_field})\I\\{vmode}){}$\1\5 +\\{decr}(\|p);\2\6 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_int}(\,);\6 +\&{if} ${}(\\{cur\_val}<\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Bad\ "});\5 +\\{print\_esc}(\X1554:\.{"prevgraf"}\X);\5 +\\{help1}(\.{"I\ allow\ only\ nonneg}\)\.{ative\ values\ here."});\5 +\\{int\_error}(\\{cur\_val});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{nest}[\|p].\\{pg\_field}\K\\{cur\_val};{}$\5 +${}\\{cur\_list}\K\\{nest}[\\{nest\_ptr}];{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1245}\B\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\mathrel+\E{}$\6 +\&{void} \\{alter\_page\_so\_far}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \|c;\C{index into \\{page\_so\_far}}\7 +${}\|c\K\\{cur\_chr};{}$\5 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_normal\_dimen};\5 +${}\\{page\_so\_far}[\|c]\K\\{cur\_val};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{1246}\B\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\mathrel+\E{}$\6 +\&{void} \\{alter\_integer}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \|c;\C{0 for \.{\\deadcycles}, 1 for \.{\\insertpenalties}}\7 +${}\|c\K\\{cur\_chr};{}$\5 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_int}(\,);\6 +\&{if} ${}(\|c\E\T{0}){}$\1\5 +${}\\{dead\_cycles}\K\\{cur\_val};{}$\2\6 +\&{else}\1\5 +${}\\{insert\_penalties}\K\\{cur\_val};{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1247}\B\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\mathrel+\E{}$\6 +\&{void} \\{alter\_box\_dimen}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{small\_number} \|c;\C{\\{width\_offset} or \\{height\_offset} or \\{depth\_offset}}\6 +\&{eight\_bits} \|b;\C{box number}\7 +${}\|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\5 +${}\\{mem}[\\{box}(\|b)+\|c].\\{sc}\K\\{cur\_val};{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1248}Paragraph shapes are set up in the obvious way. + +\Y\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\&{case} \\{set\_shape}: $\{{}$\5 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_int}(\,);\5 +${}\|n\K\\{cur\_val};{}$\6 +\&{if} ${}(\|n\Z\T{0}){}$\1\5 +${}\|p\K\\{null};{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\|p\K\\{get\_node}(\T{2}*\|n+\T{1});{}$\5 +${}\\{info}(\|p)\K\|n;{}$\6 +\&{for} ${}(\|j\K\T{1};{}$ ${}\|j\Z\|n;{}$ ${}\|j\PP){}$\5 +${}\{{}$\5 +\1\\{scan\_normal\_dimen};\5 +${}\\{mem}[\|p+\T{2}*\|j-\T{1}].\\{sc}\K\\{cur\_val}{}$;\C{indentation}\6 +\\{scan\_normal\_dimen};\5 +${}\\{mem}[\|p+\T{2}*\|j].\\{sc}\K\\{cur\_val}{}$;\C{width}\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{define} $(\\{par\_shape\_loc},\39\\{shape\_ref},\39\|p);$ $\}{}$\5 +\&{break};\par +\fi + +\M{1249}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}(\T{2}*\|n+\T{1})$ +doesn't overflow the memory capacity. + +\Y\B\4\X14:Check the ``constant'' values for consistency\X${}\mathrel+\E{}$\6 +\&{if} ${}(\T{2}*\\{max\_halfword}<\\{mem\_top}-\\{mem\_min}){}$\1\5 +${}\\{bad}\K\T{41}{}$;\2\par +\fi + +\M{1250}New hyphenation data is loaded by the \\{hyph\_data} command. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1683:\.{"hyphenation"}\X,\39\\{hyph\_data},\39\T{0});{}$\5 +${}\\{primitive}(\X1684:\.{"patterns"}\X,\39\\{hyph\_data},\39\T{1}){}$;\par +\fi + +\M{1251}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{hyph\_data}:\6 +\&{if} ${}(\\{chr\_code}\E\T{1}){}$\1\5 +\\{print\_esc}(\X1684:\.{"patterns"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1683:\.{"hyphenation"}\X);\5 +\2\&{break};\par +\fi + +\M{1252}\B\X1217:Assignments\X${}\mathrel+\E{}$\6 +\4\&{case} \\{hyph\_data}:\6 +\&{if} ${}(\\{cur\_chr}\E\T{1}){}$\5 +${}\{{}$\6 +\8\#\&{ifdef} \.{INIT}\1\6 +\\{new\_patterns}(\,);\5 +\&{goto} \\{done};\6 +\8\#\&{endif}\6 +\\{print\_err}(\.{"Patterns\ can\ be\ loa}\)\.{ded\ only\ by\ INITEX"});\5 +\\{help0};\6 +\&{error} (\,)\1\5 +;\2\6 +\&{do}\5 +${}\{{}$\1\6 +\\{get\_token}(\,);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{cur\_cmd}\E\\{right\_brace})){}$;\C{flush the patterns}\6 +\&{return};\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{new\_hyph\_exceptions}(\,);\5 +\&{goto} \\{done};\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1253}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\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\4\&{case} \\{assign\_font\_dimen}:\6 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{assign\_font\_int}:\6 +${}\{{}$\5 +\1${}\|n\K\\{cur\_chr};{}$\5 +\\{scan\_font\_ident}(\,);\5 +${}\|f\K\\{cur\_val};{}$\5 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_int}(\,);\6 +\&{if} ${}(\|n\E\T{0}){}$\1\5 +${}\\{hyphen\_char}[\|f]\K\\{cur\_val}{}$;\5 +\2\&{else}\1\5 +${}\\{skew\_char}[\|f]\K\\{cur\_val};{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1254}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1762:\.{"hyphenchar"}\X,\39\\{assign\_font\_int},\39\T{0});{}$\5 +${}\\{primitive}(\X1763:\.{"skewchar"}\X,\39\\{assign\_font\_int},\39\T{1}){}$;\par +\fi + +\M{1255}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{assign\_font\_int}:\6 +\&{if} ${}(\\{chr\_code}\E\T{0}){}$\1\5 +\\{print\_esc}(\X1762:\.{"hyphenchar"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1763:\.{"skewchar"}\X);\5 +\2\&{break};\par +\fi + +\M{1256}Here is where the information for a new font gets loaded. + +\Y\B\4\X1217:Assignments\X${}\mathrel+\E{}$\6 +\4\&{case} \\{def\_font}:\5 +\\{new\_font}(\|a);\5 +\&{break};\par +\fi + +\M{1257}\B\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\mathrel+\E{}$\6 +\&{void} \\{new\_font}(\&{small\_number} \|a)\1\1 $\{{}$\5 +\&{pointer} \|u;\C{user's font identifier}\6 +\&{scaled} \|s;\C{stated ``at'' size, or negative of scaled magnification}\6 +\&{int} \|f;\C{runs through existing fonts}\6 +\&{str\_number} \|t;\C{name for the frozen font identifier}\6 +\&{uint8\_t} \\{old\_setting};\C{holds \\{selector} setting}\6 +\&{str\_number} \\{flushable\_string};\C{string not yet referenced}\7 +\&{if} ${}(\\{job\_name}\E\T{0}){}$\1\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\5 +${}\|t\K\\{text}(\|u);{}$\2\6 +\&{else} \&{if} ${}(\|u\G\\{single\_base}){}$\1\6 +\&{if} ${}(\|u\E\\{null\_cs}){}$\1\5 +${}\|t\K\X1764:\.{"FONT"}\X{}$;\5 +\2\&{else}\1\5 +${}\|t\K\|u-\\{single\_base};{}$\2\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{old\_setting}\K\\{selector};{}$\5 +${}\\{selector}\K\\{new\_string};{}$\5 +\\{print\_str}(\.{"FONT"});\5 +${}\\{print}(\|u-\\{active\_base});{}$\5 +${}\\{selector}\K\\{old\_setting};{}$\5 +\\{str\_room}(\T{1});\5 +${}\|t\K\\{make\_string}(\,);{}$\6 +\4${}\}{}$\2\6 +\&{define} $(\|u,\39\\{set\_font},\39\\{null\_font});{}$\5 +\\{scan\_optional\_equals}(\,);\5 +\\{scan\_file\_name}(\,);\5 +\X1258:Scan the font size specification\X;\6 +\X1260: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}:\5 +${}\\{equiv}(\|u)\K\|f;{}$\5 +${}\\{eqtb}[\\{font\_id\_base}+\|f]\K\\{eqtb}[\|u];{}$\5 +${}\\{font\_id\_text}(\|f)\K\|t;$ $\}{}$\par +\fi + +\M{1258}\B\X1258:Scan the font size specification\X${}\E{}$\6 +$\\{name\_in\_progress}\K\\{true}{}$;\C{this keeps \\{cur\_name} from being changed}\6 +\&{if} (\\{scan\_keyword}(\X1765:\.{"at"}\X))\1\5 +\X1259:Put the \(p)(positive) `at' size into \|s\X\2\6 +\&{else} \&{if} (\\{scan\_keyword}(\X1766:\.{"scaled"}\X))\5 +${}\{{}$\5 +\1\\{scan\_int}(\,);\5 +${}\|s\K{-}\\{cur\_val};{}$\6 +\&{if} ${}((\\{cur\_val}\Z\T{0})\V(\\{cur\_val}>\T{32768})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Illegal\ magnificati}\)\.{on\ has\ been\ changed\ }\)\.{to\ 1000"});\6 +\\{help1}(\.{"The\ magnification\ r}\)\.{atio\ must\ be\ between}\)\.{\ 1\ and\ 32768."});\5 +\\{int\_error}(\\{cur\_val});\5 +${}\|s\K{-}\T{1000};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\&{else}\1\5 +${}\|s\K{-}\T{1000};{}$\2\6 +$\\{name\_in\_progress}\K{}$\\{false}\par +\U1257.\fi + +\M{1259}\B\X1259:Put the \(p)(positive) `at' size into \|s\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_normal\_dimen};\5 +${}\|s\K\\{cur\_val};{}$\6 +\&{if} ${}((\|s\Z\T{0})\V(\|s\G\T{\~1000000000})){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"Improper\ `at'\ size\ }\)\.{("});\5 +\\{print\_scaled}(\|s);\5 +\\{print\_str}(\.{"pt),\ replaced\ by\ 10}\)\.{pt"});\5 +\\{help2}(\.{"I\ can\ only\ handle\ f}\)\.{onts\ at\ positive\ siz}\)\.{es\ that\ are"})\6 +(\.{"less\ than\ 2048pt,\ s}\)\.{o\ I've\ changed\ what\ }\)\.{you\ said\ to\ 10pt."});\6 +\&{error} (\,)\1\5 +;\2\6 +${}\|s\K\T{10}*\\{unity};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1258.\fi + +\M{1260}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\B\4\X1260:If this font has already been loaded, set \|f to the internal font number and \&{goto} \\{common\_ending}\X${}\E{}$\6 +$\\{flushable\_string}\K\\{str\_ptr}-\T{1};{}$\6 +\&{for} ${}(\|f\K\\{font\_base}+\T{1};{}$ ${}\|f\Z\\{font\_ptr};{}$ ${}\|f\PP){}$\1\6 +\&{if} ${}(\\{str\_eq\_str}(\\{font\_name}[\|f],\39\\{cur\_name})\W\\{str\_eq\_str}(\\{font\_area}[\|f],\39\\{cur\_area})){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{cur\_name}\E\\{flushable\_string}){}$\5 +${}\{{}$\5 +\1\\{flush\_string};\5 +${}\\{cur\_name}\K\\{font\_name}[\|f];{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|s>\T{0}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\|s\E\\{font\_size}[\|f]){}$\1\5 +\&{goto} \\{common\_ending};\2\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{font\_size}[\|f]\E\\{xn\_over\_d}(\\{font\_dsize}[\|f],\39{-}\|s,\39\T{1000})){}$\1\5 +\&{goto} \\{common\_ending};\2\6 +\4${}\}{}$\2\2\par +\U1257.\fi + +\M{1261}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{set\_font}:\6 +${}\{{}$\5 +\1\\{print\_str}(\.{"select\ font\ "});\5 +\\{slow\_print}(\\{font\_name}[\\{chr\_code}]);\6 +\&{if} ${}(\\{font\_size}[\\{chr\_code}]\I\\{font\_dsize}[\\{chr\_code}]){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ at\ "});\5 +\\{print\_scaled}(\\{font\_size}[\\{chr\_code}]);\5 +\\{print\_str}(\.{"pt"});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1262}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1383:\.{"batchmode"}\X,\39\\{set\_interaction},\39\\{batch\_mode});{}$\5 +${}\\{primitive}(\X1384:\.{"nonstopmode"}\X,\39\\{set\_interaction},\39\\{nonstop\_mode});{}$\5 +${}\\{primitive}(\X1385:\.{"scrollmode"}\X,\39\\{set\_interaction},\39\\{scroll\_mode});{}$\5 +${}\\{primitive}(\X1767:\.{"errorstopmode"}\X,\39\\{set\_interaction},\39\\{error\_stop\_mode}){}$;\par +\fi + +\M{1263}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{set\_interaction}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{batch\_mode}:\5 +\\{print\_esc}(\X1383:\.{"batchmode"}\X);\5 +\&{break};\6 +\4\&{case} \\{nonstop\_mode}:\5 +\\{print\_esc}(\X1384:\.{"nonstopmode"}\X);\5 +\&{break};\6 +\4\&{case} \\{scroll\_mode}:\5 +\\{print\_esc}(\X1385:\.{"scrollmode"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1767:\.{"errorstopmode"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1264}\B\X1217:Assignments\X${}\mathrel+\E{}$\6 +\4\&{case} \\{set\_interaction}:\5 +\\{new\_interaction}(\,);\5 +\&{break};\par +\fi + +\M{1265}\B\X1215:Declare subprocedures for \\{prefixed\_command}\X${}\mathrel+\E{}$\6 +\&{void} \\{new\_interaction}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_ln}(\,);\5 +${}\\{interaction}\K\\{cur\_chr};{}$\5 +\X75:Initialize the print \\{selector} based on \\{interaction}\X;\6 +\&{if} (\\{log\_opened})\1\5 +${}\\{selector}\K\\{selector}+\T{2};{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1266}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{halfword} \\{after\_token};\C{zero, or a saved token}\par +\fi + +\M{1267}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{after\_token}\K\T{0}{}$;\par +\fi + +\M{1268}\B\X1210:Cases of \\{main\_control} that don't depend on \\{mode}\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{after\_assignment}):\6 +${}\{{}$\5 +\1\\{get\_token}(\,);\5 +${}\\{after\_token}\K\\{cur\_tok};{}$\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1269}\B\X1269:Insert a token saved by \.{\\afterassignment}, if any\X${}\E{}$\6 +\&{if} ${}(\\{after\_token}\I\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_tok}\K\\{after\_token};{}$\5 +\\{back\_input}(\,);\5 +${}\\{after\_token}\K\T{0};{}$\6 +\4${}\}{}$\2\par +\U1211.\fi + +\M{1270}Here is a procedure that might be called `Get the next non-blank non-relax +non-call non-assignment token'. + +\Y\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{do\_assignments}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{loop}\5 +${}\{{}$\5 +\1\X404:Get the next non-blank non-relax non-call token\X;\6 +\&{if} ${}(\\{cur\_cmd}\Z\\{max\_non\_prefixed\_command}){}$\1\5 +\&{return};\2\6 +${}\\{set\_box\_allowed}\K\\{false};{}$\5 +\\{prefixed\_command}(\,);\5 +${}\\{set\_box\_allowed}\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1271}\B\X1210:Cases of \\{main\_control} that don't depend on \\{mode}\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{after\_group}):\6 +${}\{{}$\5 +\1\\{get\_token}(\,);\5 +\\{save\_for\_after}(\\{cur\_tok});\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1272}Files for \.{\\read} are opened and closed by the \\{in\_stream} command. + +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1768:\.{"openin"}\X,\39\\{in\_stream},\39\T{1});{}$\5 +${}\\{primitive}(\X1769:\.{"closein"}\X,\39\\{in\_stream},\39\T{0}){}$;\par +\fi + +\M{1273}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{in\_stream}:\6 +\&{if} ${}(\\{chr\_code}\E\T{0}){}$\1\5 +\\{print\_esc}(\X1769:\.{"closein"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1768:\.{"openin"}\X);\5 +\2\&{break};\par +\fi + +\M{1274}\B\X1210:Cases of \\{main\_control} that don't depend on \\{mode}\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{in\_stream}):\5 +\\{open\_or\_close\_in}(\,);\5 +\&{break};\par +\fi + +\M{1275}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{open\_or\_close\_in}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \|c;\C{1 for \.{\\openin}, 0 for \.{\\closein}}\6 +\&{uint8\_t} \|n;\C{stream number}\7 +${}\|c\K\\{cur\_chr};{}$\5 +\\{scan\_four\_bit\_int}(\,);\5 +${}\|n\K\\{cur\_val};{}$\6 +\&{if} ${}(\\{read\_open}[\|n]\I\\{closed}){}$\5 +${}\{{}$\5 +\1${}\\{a\_close}({\AND}\\{read\_file}[\|n]);{}$\5 +${}\\{read\_open}[\|n]\K\\{closed};{}$\6 +\4${}\}{}$\2\6 +\&{if} ${}(\|c\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{scan\_optional\_equals}(\,);\5 +\\{scan\_file\_name}(\,);\6 +\&{if} ${}(\\{cur\_ext}\E\\{empty\_string}){}$\1\5 +${}\\{cur\_ext}\K\X1637:\.{".tex"}\X;{}$\2\6 +\\{pack\_cur\_name};\6 +\&{if} ${}(\\{a\_open\_in}({\AND}\\{read\_file}[\|n])){}$\1\5 +${}\\{read\_open}[\|n]\K\\{just\_open};{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1276}The user can issue messages to the terminal, regardless of the +current mode. + +\Y\B\4\X1210:Cases of \\{main\_control} that don't depend on \\{mode}\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{message}):\5 +\\{issue\_message}(\,);\5 +\&{break};\par +\fi + +\M{1277}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1770:\.{"message"}\X,\39\\{message},\39\T{0});{}$\5 +${}\\{primitive}(\X1771:\.{"errmessage"}\X,\39\\{message},\39\T{1}){}$;\par +\fi + +\M{1278}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{message}:\6 +\&{if} ${}(\\{chr\_code}\E\T{0}){}$\1\5 +\\{print\_esc}(\X1770:\.{"message"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1771:\.{"errmessage"}\X);\5 +\2\&{break};\par +\fi + +\M{1279}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{issue\_message}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \\{old\_setting};\C{holds \\{selector} setting}\6 +\&{uint8\_t} \|c;\C{identifies \.{\\message} and \.{\\errmessage}}\6 +\&{str\_number} \|s;\C{the message}\7 +${}\|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}(\T{1});\5 +${}\|s\K\\{make\_string}(\,);{}$\6 +\&{if} ${}(\|c\E\T{0}){}$\1\5 +\X1280:Print string \|s on the terminal\X\2\6 +\&{else}\1\5 +\X1283:Print string \|s as an error message\X;\2\6 +\\{flush\_string};\6 +\4${}\}{}$\2\par +\fi + +\M{1280}\B\X1280:Print string \|s on the terminal\X${}\E{}$\6 +${}\{{}$\5 +\1\&{if} ${}(\\{term\_offset}+\\{length}(\|s)>\\{max\_print\_line}-\T{2}){}$\1\5 +\\{print\_ln}(\,);\2\6 +\&{else} \&{if} ${}((\\{term\_offset}>\T{0})\V(\\{file\_offset}>\T{0})){}$\1\5 +\\{print\_char}(\.{'\ '});\2\6 +\\{slow\_print}(\|s);\5 +\\{update\_terminal};\6 +\4${}\}{}$\2\par +\U1279.\fi + +\M{1281}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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{bool} \\{long\_help\_seen};\C{has the long \.{\\errmessage} help been used?}\par +\fi + +\M{1282}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{long\_help\_seen}\K\\{false}{}$;\par +\fi + +\M{1283}\B\X1283:Print string \|s as an error message\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{""});\5 +\\{slow\_print}(\|s);\6 +\&{if} ${}(\\{err\_help}\I\\{null}){}$\1\5 +${}\\{use\_err\_help}\K\\{true};{}$\2\6 +\&{else} \&{if} (\\{long\_help\_seen})\1\5 +\\{help1}(\.{"(That\ was\ another\ \\}\)\.{\\errmessage.)"})\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} ${}(\\{interaction}<\\{error\_stop\_mode}){}$\1\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\ h}\)\.{elp."})\6 +(\.{"Pretend\ that\ you're}\)\.{\ Hercule\ Poirot:\ Exa}\)\.{mine\ all\ clues,"})\6 +(\.{"and\ deduce\ the\ trut}\)\.{h\ by\ order\ and\ metho}\)\.{d."});\6 +\4${}\}{}$\2\6 +\&{error} (\,)\1\5 +;\2\6 +${}\\{use\_err\_help}\K\\{false};{}$\6 +\4${}\}{}$\2\par +\U1279.\fi + +\M{1284}The \&{error} routine calls on \\{give\_err\_help} if help is requested from +the \\{err\_help} parameter. + +\Y\B\&{void} \\{give\_err\_help}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\\{token\_show}(\\{err\_help});\6 +\4${}\}{}$\2\par +\fi + +\M{1285}The \.{\\uppercase} and \.{\\lowercase} commands are implemented by +building a token list and then changing the cases of the letters in it. + +\Y\B\4\X1210:Cases of \\{main\_control} that don't depend on \\{mode}\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{case\_shift}):\5 +\\{shift\_case}(\,);\5 +\&{break};\par +\fi + +\M{1286}\B\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1772:\.{"lowercase"}\X,\39\\{case\_shift},\39\\{lc\_code\_base});{}$\5 +${}\\{primitive}(\X1773:\.{"uppercase"}\X,\39\\{case\_shift},\39\\{uc\_code\_base}){}$;\par +\fi + +\M{1287}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{case\_shift}:\6 +\&{if} ${}(\\{chr\_code}\E\\{lc\_code\_base}){}$\1\5 +\\{print\_esc}(\X1772:\.{"lowercase"}\X);\2\6 +\&{else}\1\5 +\\{print\_esc}(\X1773:\.{"uppercase"}\X);\5 +\2\&{break};\par +\fi + +\M{1288}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{shift\_case}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|b;\C{\\{lc\_code\_base} or \\{uc\_code\_base}}\6 +\&{pointer} \|p;\C{runs through the token list}\6 +\&{halfword} \|t;\C{token}\6 +\&{eight\_bits} \|c;\C{character code}\7 +${}\|b\K\\{cur\_chr};{}$\5 +${}\|p\K\\{scan\_toks}(\\{false},\39\\{false});{}$\5 +${}\|p\K\\{link}(\\{def\_ref});{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1\X1289:Change the case of the token in \|p, if a change is appropriate\X;\6 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\\{back\_list}(\\{link}(\\{def\_ref}));\5 +\\{free\_avail}(\\{def\_ref});\C{omit reference count}\6 +\4${}\}{}$\2\par +\fi + +\M{1289}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\B\4\X1289:Change the case of the token in \|p, if a change is appropriate\X${}\E{}$\6 +$\|t\K\\{info}(\|p);{}$\6 +\&{if} ${}(\|t<\\{cs\_token\_flag}+\\{single\_base}){}$\5 +${}\{{}$\5 +\1${}\|c\K\|t\MOD\T{256};{}$\6 +\&{if} ${}(\\{equiv}(\|b+\|c)\I\T{0}){}$\1\5 +${}\\{info}(\|p)\K\|t-\|c+\\{equiv}(\|b+\|c);{}$\2\6 +\4${}\}{}$\2\par +\U1288.\fi + +\M{1290}We come finally to the last pieces missing from \\{main\_control}, namely the +`\.{\\show}' commands that are useful when debugging. + +\Y\B\4\X1210:Cases of \\{main\_control} that don't depend on \\{mode}\X${}\mathrel+\E{}$\6 +\4\\{any\_mode}(\\{xray}):\5 +\\{show\_whatever}(\,);\5 +\&{break};\par +\fi + +\M{1291}\B\D$\\{show\_code}$ \5 +\T{0}\C{ \.{\\show} }\par +\B\4\D$\\{show\_box\_code}$ \5 +\T{1}\C{ \.{\\showbox} }\par +\B\4\D$\\{show\_the\_code}$ \5 +\T{2}\C{ \.{\\showthe} }\par +\B\4\D$\\{show\_lists}$ \5 +\T{3}\C{ \.{\\showlists} }\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1774:\.{"show"}\X,\39\\{xray},\39\\{show\_code});{}$\5 +${}\\{primitive}(\X1775:\.{"showbox"}\X,\39\\{xray},\39\\{show\_box\_code});{}$\5 +${}\\{primitive}(\X1776:\.{"showthe"}\X,\39\\{xray},\39\\{show\_the\_code});{}$\5 +${}\\{primitive}(\X1777:\.{"showlists"}\X,\39\\{xray},\39\\{show\_lists}){}$;\par +\fi + +\M{1292}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{xray}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{show\_box\_code}:\5 +\\{print\_esc}(\X1775:\.{"showbox"}\X);\5 +\&{break};\6 +\4\&{case} \\{show\_the\_code}:\5 +\\{print\_esc}(\X1776:\.{"showthe"}\X);\5 +\&{break};\6 +\4\&{case} \\{show\_lists}:\5 +\\{print\_esc}(\X1777:\.{"showlists"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_esc}(\X1774:\.{"show"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1293}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{show\_whatever}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{tail of a token list to show}\7 +\&{switch} (\\{cur\_chr})\5 +${}\{{}$\1\6 +\4\&{case} \\{show\_lists}:\6 +${}\{{}$\5 +\1\\{begin\_diagnostic}(\,);\5 +\\{show\_activities}(\,);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{show\_box\_code}:\5 +\X1296:Show the current contents of a box\X\5 +\&{break};\6 +\4\&{case} \\{show\_code}:\5 +\X1294:Show the current meaning of a token, then \&{goto} \\{common\_ending}\X\6 +\4\&{default}:\5 +\X1297:Show the current value of some parameter or register, then \&{goto} \\{common\_ending}\X\6 +\4${}\}{}$\2\6 +\X1298:Complete a potentially long \.{\\show} command\X;\6 +\4\\{common\_ending}:\6 +\&{if} ${}(\\{interaction}<\\{error\_stop\_mode}){}$\5 +${}\{{}$\5 +\1\\{help0};\5 +\\{decr}(\\{error\_count});\6 +\4${}\}{}$\2\6 +\&{else} \&{if} ${}(\\{tracing\_online}>\T{0}){}$\5 +${}\{{}$\5 +\1\hbox{}\6 +\\{help3}(\.{"This\ isn't\ an\ error}\)\.{\ message;\ I'm\ just\ \\}\)\.{\\showing\ something."})\6 +(\.{"Type\ `I\\\\show...'\ t}\)\.{o\ show\ more\ (e.g.,\ \\}\)\.{\\show\\\\cs,"})\6 +(\.{"\\\\showthe\\\\count10,}\)\.{\ \\\\showbox255,\ \\\\sho}\)\.{wlists)."});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\hbox{}\6 +\\{help5}(\.{"This\ isn't\ an\ error}\)\.{\ message;\ I'm\ just\ \\}\)\.{\\showing\ something."})\6 +(\.{"Type\ `I\\\\show...'\ t}\)\.{o\ show\ more\ (e.g.,\ \\}\)\.{\\show\\\\cs,"})\6 +(\.{"\\\\showthe\\\\count10,}\)\.{\ \\\\showbox255,\ \\\\sho}\)\.{wlists)."})\6 +(\.{"And\ type\ `I\\\\tracin}\)\.{gonline=1\\\\show...'\ }\)\.{to\ show\ boxes\ and"})\6 +(\.{"lists\ on\ your\ termi}\)\.{nal\ as\ well\ as\ in\ th}\)\.{e\ transcript\ file."});\6 +\4${}\}{}$\2\6 +\&{error} (\,)\1\5 +;\2\6 +\4${}\}{}$\2\par +\fi + +\M{1294}\B\X1294:Show the current meaning of a token, then \&{goto} \\{common\_ending}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{get\_token}(\,);\6 +\&{if} ${}(\\{interaction}\E\\{error\_stop\_mode}){}$\1\5 +\\{wake\_up\_terminal};\2\6 +\\{print\_nl}(\.{">\ "});\6 +\&{if} ${}(\\{cur\_cs}\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{sprint\_cs}(\\{cur\_cs});\5 +\\{print\_char}(\.{'='});\6 +\4${}\}{}$\2\6 +\\{print\_meaning}(\,);\5 +\&{goto} \\{common\_ending};\6 +\4${}\}{}$\2\par +\U1293.\fi + +\M{1295}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{undefined\_cs}:\5 +\\{print\_str}(\.{"undefined"});\5 +\&{break};\6 +\4\&{case} \\{call}:\5 +\\{print\_str}(\.{"macro"});\5 +\&{break};\6 +\4\&{case} \\{long\_call}:\5 +\\{print\_esc}(\X1778:\.{"long\ macro"}\X);\5 +\&{break};\6 +\4\&{case} \\{outer\_call}:\5 +\\{print\_esc}(\X1779:\.{"outer\ macro"}\X);\5 +\&{break};\6 +\4\&{case} \\{long\_outer\_call}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1743:\.{"long"}\X);\5 +\\{print\_esc}(\X1779:\.{"outer\ macro"}\X);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{end\_template}:\5 +\\{print\_esc}(\X1780:\.{"outer\ endtemplate"}\X);\5 +\&{break};\par +\fi + +\M{1296}\B\X1296:Show the current contents of a box\X${}\E{}$\6 +${}\{{}$\5 +\1\\{scan\_eight\_bit\_int}(\,);\5 +\\{begin\_diagnostic}(\,);\5 +\\{print\_nl}(\.{">\ \\\\box"});\5 +\\{print\_int}(\\{cur\_val});\5 +\\{print\_char}(\.{'='});\6 +\&{if} ${}(\\{box}(\\{cur\_val})\E\\{null}){}$\1\5 +\\{print\_str}(\.{"void"});\2\6 +\&{else}\1\5 +\\{show\_box}(\\{box}(\\{cur\_val}));\2\6 +\4${}\}{}$\2\par +\U1293.\fi + +\M{1297}\B\X1297:Show the current value of some parameter or register, then \&{goto} \\{common\_ending}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|p\K\\{the\_toks}(\,);{}$\6 +\&{if} ${}(\\{interaction}\E\\{error\_stop\_mode}){}$\1\5 +\\{wake\_up\_terminal};\2\6 +\\{print\_nl}(\.{">\ "});\5 +\\{token\_show}(\\{temp\_head});\5 +\\{flush\_list}(\\{link}(\\{temp\_head}));\5 +\&{goto} \\{common\_ending};\6 +\4${}\}{}$\2\par +\U1293.\fi + +\M{1298}\B\X1298:Complete a potentially long \.{\\show} command\X${}\E{}$\6 +\\{end\_diagnostic}(\\{true});\5 +\\{print\_err}(\.{"OK"});\6 +\&{if} ${}(\\{selector}\E\\{term\_and\_log}){}$\1\6 +\&{if} ${}(\\{tracing\_online}\Z\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{selector}\K\\{term\_only};{}$\5 +\\{print\_str}(\.{"\ (see\ the\ transcrip}\)\.{t\ file)"});\5 +${}\\{selector}\K\\{term\_and\_log};{}$\6 +\4${}\}{}$\2\2\par +\U1293.\fi + +\N{1}{1299}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}\E\T{0}$ +before \TeX's tables are loaded. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{str\_number} \\{format\_ident};\par +\fi + +\M{1300}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +$\\{format\_ident}\K\T{0}{}$;\par +\fi + +\M{1301}\B\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\6 +$\\{format\_ident}\K\X1781:\.{"\ (INITEX)"}\X{}$;\par +\fi + +\M{1302}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{INIT}\6 +\&{void} \\{store\_fmt\_file}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|j${},{}$ \|k${},{}$ \|l;\C{all-purpose indices}\6 +\&{pointer} \|p${},{}$ \|q;\C{all-purpose pointers}\6 +\&{int} \|x;\C{something to dump}\6 +\&{four\_quarters} \|w;\C{four ASCII codes}\7 +\X1304:If dumping is not allowed, abort\X;\6 +\X1328:Create the \\{format\_ident}, open the format file, and inform the user that dumping has begun\X;\6 +\X1307:Dump constants for consistency check\X;\6 +\X1309:Dump the string pool\X;\6 +\X1311:Dump the dynamic memory\X;\6 +\X1313:Dump the table of equivalents\X;\6 +\X1320:Dump the font information\X;\6 +\X1324:Dump the hyphenation tables\X;\6 +\X1326:Dump a couple more things and the closing check word\X;\6 +\X1329:Close the format file\X;\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\M{1303}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\B\4\D$\\{too\_small}(\|X)$ \6 +${}\{{}$\5 +\1\\{wake\_up\_terminal};\5 +${}\\{wterm\_ln}(\.{"---!\ Must\ increase\ }\)\.{the\ \%s"},\39\|X);{}$\5 +\&{goto} \\{bad\_fmt};\6 +\4${}\}{}$\2\par +\Y\B\hbox{\4}\X523:Declare the function called \\{open\_fmt\_file}\X\7 +\&{bool} \\{load\_fmt\_file}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|j${},{}$ \|k;\C{all-purpose indices}\6 +\&{pointer} \|p${},{}$ \|q;\C{all-purpose pointers}\6 +\&{int} \|x;\C{something undumped}\6 +\&{four\_quarters} \|w;\C{four ASCII codes}\7 +\X1308:Undump constants for consistency check\X;\6 +\X1310:Undump the string pool\X;\6 +\X1312:Undump the dynamic memory\X;\6 +\X1314:Undump the table of equivalents\X;\6 +\X1321:Undump the font information\X;\6 +\X1325:Undump the hyphenation tables\X;\6 +\X1327:Undump a couple more things and the closing check word\X;\6 +\&{return} \\{true};\C{it worked!}\6 +\4\\{bad\_fmt}:\5 +\\{wake\_up\_terminal};\5 +\\{wterm\_ln}(\.{"(Fatal\ format\ file\ }\)\.{error;\ I'm\ stymied)"});\5 +\&{return} \\{false};\6 +\4${}\}{}$\2\par +\fi + +\M{1304}The user is not allowed to dump a format file unless $\\{save\_ptr}\E\T{0}$. +This condition implies that $\\{cur\_level}\E\\{level\_one}$, hence +the \\{xeq\_level} array is constant and it need not be dumped. + +\Y\B\4\X1304:If dumping is not allowed, abort\X${}\E{}$\6 +\&{if} ${}(\\{save\_ptr}\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_err}(\.{"You\ can't\ dump\ insi}\)\.{de\ a\ group"});\5 +\\{help1}(\.{"`\{...\\\\dump\}'\ is\ a\ }\)\.{no-no."});\5 +\\{succumb};\6 +\4${}\}{}$\2\par +\U1302.\fi + +\M{1305}Format files consist of \&{memory\_word} items, and we use the following +macros to dump words of different types: + +\Y\B\4\D$\\{dump\_wd}(\|X)$ \6 +${}\{{}$\5 +\1${}\\{fmt\_file}.\|d\K\|X;{}$\5 +\\{put}(\\{fmt\_file});\5 +${}\}{}$\2\par +\B\4\D$\\{dump\_int}(\|X)$ \6 +${}\{{}$\5 +\1${}\\{fmt\_file}.\|d.\|i\K\|X;{}$\5 +\\{put}(\\{fmt\_file});\5 +${}\}{}$\2\par +\B\4\D$\\{dump\_hh}(\|X)$ \6 +${}\{{}$\5 +\1${}\\{fmt\_file}.\|d.\\{hh}\K\|X;{}$\5 +\\{put}(\\{fmt\_file});\5 +${}\}{}$\2\par +\B\4\D$\\{dump\_qqqq}(\|X)$ \6 +${}\{{}$\5 +\1${}\\{fmt\_file}.\|d.\\{qqqq}\K\|X;{}$\5 +\\{put}(\\{fmt\_file});\5 +${}\}{}$\2\par +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{word\_file} \\{fmt\_file};\C{for input or output of format information}\par +\fi + +\M{1306}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\Z\|x\Z\|b$. + +\Y\B\4\D$\\{undump\_wd}(\|X)$ \6 +${}\{{}$\5 +\1\\{get}(\\{fmt\_file});\5 +${}\|X\K\\{fmt\_file}.\|d{}$;\5 +${}\}{}$\2\par +\B\4\D$\\{undump\_int}(\|X)$ \6 +${}\{{}$\5 +\1\\{get}(\\{fmt\_file});\5 +${}\|X\K\\{fmt\_file}.\|d.\|i{}$;\5 +${}\}{}$\2\par +\B\4\D$\\{undump\_hh}(\|X)$ \6 +${}\{{}$\5 +\1\\{get}(\\{fmt\_file});\5 +${}\|X\K\\{fmt\_file}.\|d.\\{hh}{}$;\5 +${}\}{}$\2\par +\B\4\D$\\{undump\_qqqq}(\|X)$ \6 +${}\{{}$\5 +\1\\{get}(\\{fmt\_file});\5 +${}\|X\K\\{fmt\_file}.\|d.\\{qqqq}{}$;\5 +${}\}{}$\2\par +\B\4\D$\\{undump\_end\_end}(\|X)$ \5 +$\|X\K\|x{}$;\5 +$\}{}$\par +\B\4\D$\\{undump\_end}(\|X)$ \5 +$(\|x>\|X)$ ) \&{goto} \\{bad\_fmt};\5 +\&{else} \\{undump\_end\_end}\par +\B\4\D$\\{undump}(\|X)$ \5 +$\{{}$\5 +\\{undump\_int}(\|x); \&{if} ( $(\|x<\|X)\V{}$\\{undump\_end}\par +\B\4\D$\\{undump\_size\_end\_end}(\|X)$ \5 +\\{too\_small}(\|X)\5 +\&{else} \\{undump\_end\_end}\par +\B\4\D$\\{undump\_size\_end}(\|X)$ \5 +\&{if} ${}(\|x>\|X)$ \\{undump\_size\_end\_end}\par +\B\4\D$\\{undump\_size}(\|X)$ \5 +$\{{}$\5 +\\{undump\_int}(\|x);\6 +\&{if} ${}(\|x<\|X){}$\1\5 +\&{goto} \\{bad\_fmt};\2\6 +\\{undump\_size\_end}\par +\fi + +\M{1307}The next few sections of the program should make it clear how we use the +dump/undump macros. + +\Y\B\4\X1307:Dump constants for consistency check\X${}\E{}$\6 +\\{dump\_int}(\T{0});\6 +\\{dump\_int}(\\{mem\_bot});\6 +\\{dump\_int}(\\{mem\_top});\6 +\\{dump\_int}(\\{eqtb\_size});\6 +\\{dump\_int}(\\{hash\_prime});\6 +\\{dump\_int}(\\{hyph\_size})\par +\U1302.\fi + +\M{1308}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\B\4\X1308:Undump constants for consistency check\X${}\E{}$\6 +$\|x\K\\{fmt\_file}.\|d.\|i;{}$\6 +\&{if} ${}(\|x\I\T{0}){}$\1\5 +\&{goto} \\{bad\_fmt};\C{check that strings are the same}\2\6 +\\{undump\_int}(\|x);\6 +\&{if} ${}(\|x\I\\{mem\_bot}){}$\1\5 +\&{goto} \\{bad\_fmt};\2\6 +\\{undump\_int}(\|x);\6 +\&{if} ${}(\|x\I\\{mem\_top}){}$\1\5 +\&{goto} \\{bad\_fmt};\2\6 +\\{undump\_int}(\|x);\6 +\&{if} ${}(\|x\I\\{eqtb\_size}){}$\1\5 +\&{goto} \\{bad\_fmt};\2\6 +\\{undump\_int}(\|x);\6 +\&{if} ${}(\|x\I\\{hash\_prime}){}$\1\5 +\&{goto} \\{bad\_fmt};\2\6 +\\{undump\_int}(\|x); \&{if} ${}(\|x\I\\{hyph\_size})$ \&{goto} \\{bad\_fmt}\par +\U1303.\fi + +\M{1309}\B\D$\\{dump\_four\_ASCII}$ \5 +$\|w.\\{b0}\K\\{qi}(\\{so}(\\{str\_pool}[\|k]));{}$\5 +${}\|w.\\{b1}\K\\{qi}(\\{so}(\\{str\_pool}[\|k+\T{1}]));{}$\5 +${}\|w.\\{b2}\K\\{qi}(\\{so}(\\{str\_pool}[\|k+\T{2}]));{}$\5 +${}\|w.\\{b3}\K\\{qi}(\\{so}(\\{str\_pool}[\|k+\T{3}]));$ \\{dump\_qqqq}(\|w)\par +\Y\B\4\X1309:Dump the string pool\X${}\E{}$\6 +\\{dump\_int}(\\{pool\_ptr});\5 +\\{dump\_int}(\\{str\_ptr});\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\\{str\_ptr};{}$ ${}\|k\PP){}$\1\5 +\\{dump\_int}(\\{str\_start}[\|k]);\2\6 +${}\|k\K\T{0};{}$\6 +\&{while} ${}(\|k+\T{4}<\\{pool\_ptr}){}$\5 +${}\{{}$\5 +\1\\{dump\_four\_ASCII};\5 +${}\|k\K\|k+\T{4};{}$\6 +\4${}\}{}$\2\6 +${}\|k\K\\{pool\_ptr}-\T{4};{}$\5 +\\{dump\_four\_ASCII};\5 +\\{print\_ln}(\,);\5 +\\{print\_int}(\\{str\_ptr});\5 +\\{print\_str}(\.{"\ strings\ of\ total\ l}\)\.{ength\ "}); \\{print\_int}(\\{pool\_ptr})\par +\U1302.\fi + +\M{1310}\B\D$\\{undump\_four\_ASCII}$ \5 +\\{undump\_qqqq}(\|w);\5 +${}\\{str\_pool}[\|k]\K\\{si}(\\{qo}(\|w.\\{b0}));{}$\5 +${}\\{str\_pool}[\|k+\T{1}]\K\\{si}(\\{qo}(\|w.\\{b1}));{}$\5 +${}\\{str\_pool}[\|k+\T{2}]\K\\{si}(\\{qo}(\|w.\\{b2}));$ $\\{str\_pool}[\|k+\T{3}]\K\\{si}(\\{qo}(\|w.\\{b3}){}$)\par +\Y\B\4\X1310:Undump the string pool\X${}\E{}$\6 +\\{undump\_size}(\T{0})(\\{pool\_size})(\.{"string\ pool\ size"})(\\{pool\_ptr});\5 +\\{undump\_size}(\T{0})(\\{max\_strings})(\.{"max\ strings"})(\\{str\_ptr});\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\\{str\_ptr};{}$ ${}\|k\PP){}$\1\5 +\\{undump}(\T{0})(\\{pool\_ptr})(\\{str\_start}[\|k]);\2\6 +${}\|k\K\T{0};{}$\6 +\&{while} ${}(\|k+\T{4}<\\{pool\_ptr}){}$\5 +${}\{{}$\5 +\1\\{undump\_four\_ASCII};\5 +${}\|k\K\|k+\T{4};{}$\6 +\4${}\}{}$\2\6 +${}\|k\K\\{pool\_ptr}-\T{4};{}$\5 +\\{undump\_four\_ASCII};\5 +${}\\{init\_str\_ptr}\K\\{str\_ptr};$ $\\{init\_pool\_ptr}\K{}$\\{pool\_ptr}\par +\U1303.\fi + +\M{1311}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\B\4\X1311:Dump the dynamic memory\X${}\E{}$\6 +\\{sort\_avail}(\,);\5 +${}\\{var\_used}\K\T{0};{}$\5 +\\{dump\_int}(\\{lo\_mem\_max});\5 +\\{dump\_int}(\\{rover});\5 +${}\|p\K\\{mem\_bot};{}$\5 +${}\|q\K\\{rover};{}$\5 +${}\|x\K\T{0}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\&{for} ${}(\|k\K\|p;{}$ ${}\|k\Z\|q+\T{1};{}$ ${}\|k\PP){}$\1\5 +\\{dump\_wd}(\\{mem}[\|k]);\2\6 +${}\|x\K\|x+\|q+\T{2}-\|p;{}$\5 +${}\\{var\_used}\K\\{var\_used}+\|q-\|p;{}$\5 +${}\|p\K\|q+\\{node\_size}(\|q);{}$\5 +${}\|q\K\\{rlink}(\|q);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|q\E\\{rover}));{}$\5 +${}\\{var\_used}\K\\{var\_used}+\\{lo\_mem\_max}-\|p;{}$\5 +${}\\{dyn\_used}\K\\{mem\_end}+\T{1}-\\{hi\_mem\_min}{}$;\6 +\&{for} ${}(\|k\K\|p;{}$ ${}\|k\Z\\{lo\_mem\_max};{}$ ${}\|k\PP){}$\1\5 +\\{dump\_wd}(\\{mem}[\|k]);\2\6 +${}\|x\K\|x+\\{lo\_mem\_max}+\T{1}-\|p;{}$\5 +\\{dump\_int}(\\{hi\_mem\_min});\5 +\\{dump\_int}(\\{avail});\6 +\&{for} ${}(\|k\K\\{hi\_mem\_min};{}$ ${}\|k\Z\\{mem\_end};{}$ ${}\|k\PP){}$\1\5 +\\{dump\_wd}(\\{mem}[\|k]);\2\6 +${}\|x\K\|x+\\{mem\_end}+\T{1}-\\{hi\_mem\_min};{}$\5 +${}\|p\K\\{avail};{}$\6 +\&{while} ${}(\|p\I\\{null}){}$\5 +${}\{{}$\5 +\1\\{decr}(\\{dyn\_used});\5 +${}\|p\K\\{link}(\|p);{}$\6 +\4${}\}{}$\2\6 +\\{dump\_int}(\\{var\_used});\5 +\\{dump\_int}(\\{dyn\_used});\5 +\\{print\_ln}(\,);\5 +\\{print\_int}(\|x);\5 +\\{print\_str}(\.{"\ memory\ locations\ d}\)\.{umped;\ current\ usage}\)\.{\ is\ "});\5 +\\{print\_int}(\\{var\_used});\5 +\\{print\_char}(\.{'\&'}); \\{print\_int}(\\{dyn\_used})\par +\U1302.\fi + +\M{1312}\B\X1312:Undump the dynamic memory\X${}\E{}$\6 +$\\{undump}(\\{lo\_mem\_stat\_max}+\T{1000})(\\{hi\_mem\_stat\_min}-\T{1})(\\{lo\_mem\_max});{}$\5 +${}\\{undump}(\\{lo\_mem\_stat\_max}+\T{1})(\\{lo\_mem\_max})(\\{rover});{}$\5 +${}\|p\K\\{mem\_bot};{}$\5 +${}\|q\K\\{rover}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\&{for} ${}(\|k\K\|p;{}$ ${}\|k\Z\|q+\T{1};{}$ ${}\|k\PP){}$\1\5 +\\{undump\_wd}(\\{mem}[\|k]);\2\6 +${}\|p\K\|q+\\{node\_size}(\|q);{}$\6 +\&{if} ${}((\|p>\\{lo\_mem\_max})\V((\|q\G\\{rlink}(\|q))\W(\\{rlink}(\|q)\I\\{rover}))){}$\1\5 +\&{goto} \\{bad\_fmt};\2\6 +${}\|q\K\\{rlink}(\|q);{}$\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|q\E\\{rover}));{}$\6 +\&{for} ${}(\|k\K\|p;{}$ ${}\|k\Z\\{lo\_mem\_max};{}$ ${}\|k\PP){}$\1\5 +\\{undump\_wd}(\\{mem}[\|k]);\2\6 +\&{if} ${}(\\{mem\_min}<\\{mem\_bot}-\T{2}{}$)\C{make more low memory available}\6 +${}\{{}$\5 +\1${}\|p\K\\{llink}(\\{rover});{}$\5 +${}\|q\K\\{mem\_min}+\T{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 +\4${}\}{}$\2\6 +${}\\{undump}(\\{lo\_mem\_max}+\T{1})(\\{hi\_mem\_stat\_min})(\\{hi\_mem\_min});{}$\5 +\\{undump}(\\{null})(\\{mem\_top})(\\{avail});\5 +${}\\{mem\_end}\K\\{mem\_top};{}$\6 +\&{for} ${}(\|k\K\\{hi\_mem\_min};{}$ ${}\|k\Z\\{mem\_end};{}$ ${}\|k\PP){}$\1\5 +\\{undump\_wd}(\\{mem}[\|k]);\2\6 +\\{undump\_int}(\\{var\_used}); \\{undump\_int}(\\{dyn\_used})\par +\U1303.\fi + +\M{1313}\B\X1313:Dump the table of equivalents\X${}\E{}$\6 +\X1315:Dump regions 1 to 4 of \\{eqtb}\X;\6 +\X1316:Dump regions 5 and 6 of \\{eqtb}\X;\6 +\\{dump\_int}(\\{par\_loc});\5 +\\{dump\_int}(\\{write\_loc});\6 +\X1318:Dump the hash table\X\par +\U1302.\fi + +\M{1314}\B\X1314:Undump the table of equivalents\X${}\E{}$\6 +\X1317:Undump regions 1 to 6 of \\{eqtb}\X;\6 +\\{undump}(\\{hash\_base})(\\{frozen\_control\_sequence})(\\{par\_loc});\5 +${}\\{par\_token}\K\\{cs\_token\_flag}+\\{par\_loc}{}$;\6 +\\{undump}(\\{hash\_base})(\\{frozen\_control\_sequence})(\\{write\_loc});\6 +\X1319:Undump the hash table\X\par +\U1303.\fi + +\M{1315}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\B\4\X1315:Dump regions 1 to 4 of \\{eqtb}\X${}\E{}$\6 +$\|k\K\\{active\_base}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|j\K\|k;{}$\6 +\&{while} ${}(\|j<\\{int\_base}-\T{1}){}$\5 +${}\{{}$\5 +\1\&{if} ${}((\\{equiv}(\|j)\E\\{equiv}(\|j+\T{1}))\W(\\{eq\_type}(\|j)\E\\{eq\_type}(\|j+\T{1}))\W\30(\\{eq\_level}(\|j)\E\\{eq\_level}(\|j+\T{1}))){}$\1\5 +\&{goto} \\{found1};\2\6 +\\{incr}(\|j);\6 +\4${}\}{}$\2\6 +${}\|l\K\\{int\_base};{}$\5 +\&{goto} \\{done1};\C{$\|j\E\\{int\_base}-\T{1}$}\6 +\4\\{found1}:\5 +\\{incr}(\|j);\5 +${}\|l\K\|j;{}$\6 +\&{while} ${}(\|j<\\{int\_base}-\T{1}){}$\5 +${}\{{}$\5 +\1\&{if} ${}((\\{equiv}(\|j)\I\\{equiv}(\|j+\T{1}))\V(\\{eq\_type}(\|j)\I\\{eq\_type}(\|j+\T{1}))\V\30(\\{eq\_level}(\|j)\I\\{eq\_level}(\|j+\T{1}))){}$\1\5 +\&{goto} \\{done1};\2\6 +\\{incr}(\|j);\6 +\4${}\}{}$\2\6 +\4\\{done1}:\5 +${}\\{dump\_int}(\|l-\|k);{}$\6 +\&{while} ${}(\|k<\|l){}$\5 +${}\{{}$\5 +\1\\{dump\_wd}(\\{eqtb}[\|k]);\5 +\\{incr}(\|k);\6 +\4${}\}{}$\2\6 +${}\|k\K\|j+\T{1};{}$\5 +${}\\{dump\_int}(\|k-\|l);{}$\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R(\|k\E\\{int\_base}){}$)\par +\U1313.\fi + +\M{1316}\B\X1316:Dump regions 5 and 6 of \\{eqtb}\X${}\E{}$\6 +\&{do}\5 +${}\{{}$\1\6 +${}\|j\K\|k;{}$\6 +\&{while} ${}(\|j<\\{eqtb\_size}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{eqtb}[\|j].\|i\E\\{eqtb}[\|j+\T{1}].\|i){}$\1\5 +\&{goto} \\{found2};\2\6 +\\{incr}(\|j);\6 +\4${}\}{}$\2\6 +${}\|l\K\\{eqtb\_size}+\T{1};{}$\5 +\&{goto} \\{done2};\C{$\|j\E\\{eqtb\_size}$}\6 +\4\\{found2}:\5 +\\{incr}(\|j);\5 +${}\|l\K\|j;{}$\6 +\&{while} ${}(\|j<\\{eqtb\_size}){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{eqtb}[\|j].\|i\I\\{eqtb}[\|j+\T{1}].\|i){}$\1\5 +\&{goto} \\{done2};\2\6 +\\{incr}(\|j);\6 +\4${}\}{}$\2\6 +\4\\{done2}:\5 +${}\\{dump\_int}(\|l-\|k);{}$\6 +\&{while} ${}(\|k<\|l){}$\5 +${}\{{}$\5 +\1\\{dump\_wd}(\\{eqtb}[\|k]);\5 +\\{incr}(\|k);\6 +\4${}\}{}$\2\6 +${}\|k\K\|j+\T{1};{}$\5 +${}\\{dump\_int}(\|k-\|l);{}$\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R(\|k>\\{eqtb\_size}){}$)\par +\U1313.\fi + +\M{1317}\B\X1317:Undump regions 1 to 6 of \\{eqtb}\X${}\E{}$\6 +$\|k\K\\{active\_base}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +\\{undump\_int}(\|x);\6 +\&{if} ${}((\|x<\T{1})\V(\|k+\|x>\\{eqtb\_size}+\T{1})){}$\1\5 +\&{goto} \\{bad\_fmt};\2\6 +\&{for} ${}(\|j\K\|k;{}$ ${}\|j\Z\|k+\|x-\T{1};{}$ ${}\|j\PP){}$\1\5 +\\{undump\_wd}(\\{eqtb}[\|j]);\2\6 +${}\|k\K\|k+\|x;{}$\5 +\\{undump\_int}(\|x);\6 +\&{if} ${}((\|x<\T{0})\V(\|k+\|x>\\{eqtb\_size}+\T{1})){}$\1\5 +\&{goto} \\{bad\_fmt};\2\6 +\&{for} ${}(\|j\K\|k;{}$ ${}\|j\Z\|k+\|x-\T{1};{}$ ${}\|j\PP){}$\1\5 +${}\\{eqtb}[\|j]\K\\{eqtb}[\|k-\T{1}];{}$\2\6 +${}\|k\K\|k+\|x;{}$\6 +\4${}\}{}$\5 +\2\&{while} ${}(\R(\|k>\\{eqtb\_size}){}$)\par +\U1314.\fi + +\M{1318}A different scheme is used to compress the hash table, since its lower +region is usually sparse. When $\\{text}(\|p)\I\T{0}$ for $\|p\Z\\{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\B\4\X1318:Dump the hash table\X${}\E{}$\6 +\\{dump\_int}(\\{hash\_used});\5 +${}\\{cs\_count}\K\\{frozen\_control\_sequence}-\T{1}-\\{hash\_used};{}$\6 +\&{for} ${}(\|p\K\\{hash\_base};{}$ ${}\|p\Z\\{hash\_used};{}$ ${}\|p\PP){}$\1\6 +\&{if} ${}(\\{text}(\|p)\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{dump\_int}(\|p);\5 +\\{dump\_hh}(\\{hash}[\|p]);\5 +\\{incr}(\\{cs\_count});\6 +\4${}\}{}$\2\2\6 +\&{for} ${}(\|p\K\\{hash\_used}+\T{1};{}$ ${}\|p\Z\\{undefined\_control\_sequence}-\T{1};{}$ ${}\|p\PP){}$\1\5 +\\{dump\_hh}(\\{hash}[\|p]);\2\6 +\\{dump\_int}(\\{cs\_count});\6 +\\{print\_ln}(\,);\5 +\\{print\_int}(\\{cs\_count}); \\{print\_str}(\.{"\ multiletter\ contro}\)\.{l\ sequences"})\par +\U1313.\fi + +\M{1319}\B\X1319:Undump the hash table\X${}\E{}$\6 +\\{undump}(\\{hash\_base})(\\{frozen\_control\_sequence})(\\{hash\_used});\5 +${}\|p\K\\{hash\_base}-\T{1}{}$;\6 +\&{do}\5 +${}\{{}$\1\6 +${}\\{undump}(\|p+\T{1})(\\{hash\_used})(\|p);{}$\5 +\\{undump\_hh}(\\{hash}[\|p]);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\|p\E\\{hash\_used}));{}$\6 +\&{for} ${}(\|p\K\\{hash\_used}+\T{1};{}$ ${}\|p\Z\\{undefined\_control\_sequence}-\T{1};{}$ ${}\|p\PP){}$\1\5 +\\{undump\_hh}(\\{hash}[\|p]);\2\6 +\\{undump\_int}(\\{cs\_count})\par +\U1314.\fi + +\M{1320}\B\X1320:Dump the font information\X${}\E{}$\6 +\\{dump\_int}(\\{fmem\_ptr});\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\\{fmem\_ptr}-\T{1};{}$ ${}\|k\PP){}$\1\5 +\\{dump\_wd}(\\{font\_info}[\|k]);\2\6 +\\{dump\_int}(\\{font\_ptr});\6 +\&{for} ${}(\|k\K\\{null\_font};{}$ ${}\|k\Z\\{font\_ptr};{}$ ${}\|k\PP){}$\1\5 +\X1322:Dump the array info for internal font number \|k\X;\2\6 +\\{print\_ln}(\,);\5 +${}\\{print\_int}(\\{fmem\_ptr}-\T{7});{}$\5 +\\{print\_str}(\.{"\ words\ of\ font\ info}\)\.{\ for\ "});\5 +${}\\{print\_int}(\\{font\_ptr}-\\{font\_base});{}$\5 +\\{print\_str}(\.{"\ preloaded\ font"}); \&{if} ${}(\\{font\_ptr}\I\\{font\_base}+\T{1})$ \\{print\_char}(\.{'s'})\par +\U1302.\fi + +\M{1321}\B\X1321:Undump the font information\X${}\E{}$\6 +\\{undump\_size}(\T{7})(\\{font\_mem\_size})(\.{"font\ mem\ size"})(\\{fmem\_ptr});\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\\{fmem\_ptr}-\T{1};{}$ ${}\|k\PP){}$\1\5 +\\{undump\_wd}(\\{font\_info}[\|k]);\2\6 +\\{undump\_size}(\\{font\_base})(\\{font\_max})(\.{"font\ max"})(\\{font\_ptr});\6 +\&{for} ${}(\|k\K\\{null\_font};{}$ ${}\|k\Z\\{font\_ptr};{}$ ${}\|k\PP){}$\1\5 +\X1323:Undump the array info for internal font number \|k\X\2\par +\U1303.\fi + +\M{1322}\B\X1322:Dump the array info for internal font number \|k\X${}\E{}$\6 +${}\{{}$\5 +\1\\{dump\_qqqq}(\\{font\_check}[\|k]);\5 +\\{dump\_int}(\\{font\_size}[\|k]);\5 +\\{dump\_int}(\\{font\_dsize}[\|k]);\5 +\\{dump\_int}(\\{font\_params}[\|k]);\6 +\\{dump\_int}(\\{hyphen\_char}[\|k]);\5 +\\{dump\_int}(\\{skew\_char}[\|k]);\6 +\\{dump\_int}(\\{font\_name}[\|k]);\5 +\\{dump\_int}(\\{font\_area}[\|k]);\6 +\\{dump\_int}(\\{font\_bc}[\|k]);\5 +\\{dump\_int}(\\{font\_ec}[\|k]);\6 +\\{dump\_int}(\\{char\_base}[\|k]);\5 +\\{dump\_int}(\\{width\_base}[\|k]);\5 +\\{dump\_int}(\\{height\_base}[\|k]);\6 +\\{dump\_int}(\\{depth\_base}[\|k]);\5 +\\{dump\_int}(\\{italic\_base}[\|k]);\5 +\\{dump\_int}(\\{lig\_kern\_base}[\|k]);\6 +\\{dump\_int}(\\{kern\_base}[\|k]);\5 +\\{dump\_int}(\\{exten\_base}[\|k]);\5 +\\{dump\_int}(\\{param\_base}[\|k]);\6 +\\{dump\_int}(\\{font\_glue}[\|k]);\6 +\\{dump\_int}(\\{bchar\_label}[\|k]);\5 +\\{dump\_int}(\\{font\_bchar}[\|k]);\5 +\\{dump\_int}(\\{font\_false\_bchar}[\|k]);\6 +\\{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\\{empty\_string});{}$\6 +\&{if} ${}(\\{font\_size}[\|k]\I\\{font\_dsize}[\|k]){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ at\ "});\5 +\\{print\_scaled}(\\{font\_size}[\|k]);\5 +\\{print\_str}(\.{"pt"});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1320.\fi + +\M{1323}\B\X1323:Undump the array info for internal font number \|k\X${}\E{}$\6 +${}\{{}$\5 +\1\\{undump\_qqqq}(\\{font\_check}[\|k]);\6 +\\{undump\_int}(\\{font\_size}[\|k]);\5 +\\{undump\_int}(\\{font\_dsize}[\|k]);\5 +\\{undump}(\\{min\_halfword})(\\{max\_halfword})(\\{font\_params}[\|k]);\6 +\\{undump\_int}(\\{hyphen\_char}[\|k]);\5 +\\{undump\_int}(\\{skew\_char}[\|k]);\6 +\\{undump}(\T{0})(\\{str\_ptr})(\\{font\_name}[\|k]);\5 +\\{undump}(\T{0})(\\{str\_ptr})(\\{font\_area}[\|k]);\6 +\\{undump}(\T{0})(\T{255})(\\{font\_bc}[\|k]);\5 +\\{undump}(\T{0})(\T{255})(\\{font\_ec}[\|k]);\6 +\\{undump\_int}(\\{char\_base}[\|k]);\5 +\\{undump\_int}(\\{width\_base}[\|k]);\5 +\\{undump\_int}(\\{height\_base}[\|k]);\6 +\\{undump\_int}(\\{depth\_base}[\|k]);\5 +\\{undump\_int}(\\{italic\_base}[\|k]);\5 +\\{undump\_int}(\\{lig\_kern\_base}[\|k]);\6 +\\{undump\_int}(\\{kern\_base}[\|k]);\5 +\\{undump\_int}(\\{exten\_base}[\|k]);\5 +\\{undump\_int}(\\{param\_base}[\|k]);\6 +\\{undump}(\\{min\_halfword})(\\{lo\_mem\_max})(\\{font\_glue}[\|k]);\6 +${}\\{undump}(\T{0})(\\{fmem\_ptr}-\T{1})(\\{bchar\_label}[\|k]);{}$\5 +\\{undump}(\\{min\_quarterword})(\\{non\_char})(\\{font\_bchar}[\|k]);\5 +\\{undump}(\\{min\_quarterword})(\\{non\_char})(\\{font\_false\_bchar}[\|k]);\6 +\4${}\}{}$\2\par +\U1321.\fi + +\M{1324}\B\X1324:Dump the hyphenation tables\X${}\E{}$\6 +\\{dump\_int}(\\{hyph\_count});\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\\{hyph\_size};{}$ ${}\|k\PP){}$\1\6 +\&{if} ${}(\\{hyph\_word}[\|k]\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{dump\_int}(\|k);\5 +\\{dump\_int}(\\{hyph\_word}[\|k]);\5 +\\{dump\_int}(\\{hyph\_list}[\|k]);\6 +\4${}\}{}$\2\2\6 +\\{print\_ln}(\,);\5 +\\{print\_int}(\\{hyph\_count});\5 +\\{print\_str}(\.{"\ hyphenation\ except}\)\.{ion"});\6 +\&{if} ${}(\\{hyph\_count}\I\T{1}){}$\1\5 +\\{print\_char}(\.{'s'});\2\6 +\&{if} (\\{trie\_not\_ready})\1\5 +\\{init\_trie}(\,);\2\6 +\\{dump\_int}(\\{trie\_max});\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\\{trie\_max};{}$ ${}\|k\PP){}$\1\5 +\\{dump\_hh}(\\{trie}[\|k]);\2\6 +\\{dump\_int}(\\{trie\_op\_ptr});\6 +\&{for} ${}(\|k\K\T{1};{}$ ${}\|k\Z\\{trie\_op\_ptr};{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1\\{dump\_int}(\\{hyf\_distance}[\|k]);\5 +\\{dump\_int}(\\{hyf\_num}[\|k]);\5 +\\{dump\_int}(\\{hyf\_next}[\|k]);\6 +\4${}\}{}$\2\6 +\\{print\_nl}(\.{"Hyphenation\ trie\ of}\)\.{\ length\ "});\5 +\\{print\_int}(\\{trie\_max});\5 +\\{print\_str}(\.{"\ has\ "});\5 +\\{print\_int}(\\{trie\_op\_ptr});\5 +\\{print\_str}(\.{"\ op"});\6 +\&{if} ${}(\\{trie\_op\_ptr}\I\T{1}){}$\1\5 +\\{print\_char}(\.{'s'});\2\6 +\\{print\_str}(\.{"\ out\ of\ "});\5 +\\{print\_int}(\\{trie\_op\_size});\6 +\&{for} ${}(\|k\K\T{255};{}$ ${}\|k\G\T{0};{}$ ${}\|k\MM){}$\1\6 +\&{if} ${}(\\{trie\_used}[\|k]>\\{min\_quarterword}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"\ \ "});\5 +\\{print\_int}(\\{qo}(\\{trie\_used}[\|k]));\5 +\\{print\_str}(\.{"\ for\ language\ "});\5 +\\{print\_int}(\|k);\5 +\\{dump\_int}(\|k);\5 +\\{dump\_int}(\\{qo}(\\{trie\_used}[\|k]));\6 +\4${}\}{}$\2\2\par +\U1302.\fi + +\M{1325}Only ``nonempty'' parts of \\{op\_start} need to be restored. + +\Y\B\4\X1325:Undump the hyphenation tables\X${}\E{}$\6 +\\{undump}(\T{0})(\\{hyph\_size})(\\{hyph\_count});\6 +\&{for} ${}(\|k\K\T{1};{}$ ${}\|k\Z\\{hyph\_count};{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1\\{undump}(\T{0})(\\{hyph\_size})(\|j);\5 +\\{undump}(\T{0})(\\{str\_ptr})(\\{hyph\_word}[\|j]);\5 +\\{undump}(\\{min\_halfword})(\\{max\_halfword})(\\{hyph\_list}[\|j]);\6 +\4${}\}{}$\2\6 +\\{undump\_size}(\T{0})(\\{trie\_size})(\.{"trie\ size"})(\|j);\6 +\8\#\&{ifdef} \.{INIT}\6 +${}\\{trie\_max}\K\|j;{}$\6 +\8\#\&{endif}\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\|j;{}$ ${}\|k\PP){}$\1\5 +\\{undump\_hh}(\\{trie}[\|k]);\2\6 +\\{undump\_size}(\T{0})(\\{trie\_op\_size})(\.{"trie\ op\ size"})(\|j);\6 +\8\#\&{ifdef} \.{INIT}\6 +${}\\{trie\_op\_ptr}\K\|j;{}$\6 +\8\#\&{endif}\6 +\&{for} ${}(\|k\K\T{1};{}$ ${}\|k\Z\|j;{}$ ${}\|k\PP){}$\5 +${}\{{}$\5 +\1\\{undump}(\T{0})(\T{63})(\\{hyf\_distance}[\|k]);\C{a \&{small\_number}}\6 +\\{undump}(\T{0})(\T{63})(\\{hyf\_num}[\|k]);\5 +\\{undump}(\\{min\_quarterword})(\\{max\_quarterword})(\\{hyf\_next}[\|k]);\6 +\4${}\}{}$\2\6 +\8\#\&{ifdef} \.{INIT}\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{255};{}$ ${}\|k\PP){}$\1\5 +${}\\{trie\_used}[\|k]\K\\{min\_quarterword};{}$\2\6 +\8\#\&{endif}\6 +${}\|k\K\T{256};{}$\6 +\&{while} ${}(\|j>\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{undump}(\T{0})(\|k-\T{1})(\|k);{}$\5 +\\{undump}(\T{1})(\|j)(\|x);\6 +\8\#\&{ifdef} \.{INIT}\6 +${}\\{trie\_used}[\|k]\K\\{qi}(\|x);{}$\6 +\8\#\&{endif}\6 +${}\|j\K\|j-\|x;{}$\5 +${}\\{op\_start}[\|k]\K\\{qo}(\|j);{}$\6 +\4${}\}{}$\2\6 +\8\#\&{ifdef} \.{INIT}\6 +$\\{trie\_not\_ready}\K\\{false}{}$\6 +\8\#\&{endif}\par +\U1303.\fi + +\M{1326}We have already printed a lot of statistics, so we set $\\{tracing\_stats}\K\T{0}$ +to prevent them from appearing again. + +\Y\B\4\X1326:Dump a couple more things and the closing check word\X${}\E{}$\6 +\\{dump\_int}(\\{interaction});\5 +\\{dump\_int}(\\{format\_ident});\5 +\\{dump\_int}(\T{69069}); $\\{tracing\_stats}\K{}$\T{0}\par +\U1302.\fi + +\M{1327}\B\X1327:Undump a couple more things and the closing check word\X${}\E{}$\6 +\\{undump}(\\{batch\_mode})(\\{error\_stop\_mode})(\\{interaction});\5 +\\{undump}(\T{0})(\\{str\_ptr})(\\{format\_ident});\5 +\\{undump\_int}(\|x); \&{if} ${}((\|x\I\T{69069})\V\\{eof}(\\{fmt\_file}))$ \&{goto} \\{bad\_fmt}\par +\U1303.\fi + +\M{1328}\B\X1328:Create the \\{format\_ident}, open the format file, and inform the user that dumping has begun\X${}\E{}$\6 +$\\{selector}\K\\{new\_string};{}$\5 +\\{print\_str}(\.{"\ (preloaded\ 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}\E\\{batch\_mode}){}$\1\5 +${}\\{selector}\K\\{log\_only};{}$\2\6 +\&{else}\1\5 +${}\\{selector}\K\\{term\_and\_log};{}$\2\6 +\\{str\_room}(\T{1});\5 +${}\\{format\_ident}\K\\{make\_string}(\,);{}$\5 +\\{pack\_job\_name}(\\{format\_extension});\6 +\&{while} ${}(\R\\{w\_open\_out}({\AND}\\{fmt\_file})){}$\1\5 +${}\\{prompt\_file\_name}(\.{"format\ file\ name"},\39\\{format\_extension});{}$\2\6 +\\{print\_nl}(\.{"Beginning\ to\ dump\ o}\)\.{n\ file\ "});\5 +${}\\{slow\_print}(\\{w\_make\_name\_string}({\AND}\\{fmt\_file}));{}$\5 +\\{flush\_string};\5 +\\{print\_nl}(\.{""}); \\{slow\_print}(\\{format\_ident})\par +\U1302.\fi + +\M{1329}\B\X1329:Close the format file\X${}\E{}$\6 +$\\{w\_close}({\AND}\\{fmt\_file}{}$)\par +\U1302.\fi + +\N{1}{1330}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\B\X1333:Last-minute procedures\X\par +\fi + +\M{1331}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}\K\T{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}\E\T{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}\E\T{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\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{int} \\{ready\_already};\C{a sacrifice of purity for economy}\par +\fi + +\M{1332}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\B\&{int} \\{main}(\&{void})\1\1\2\2\6 +${}\{{}$\C{\\{start\_here}}\1\6 +${}\\{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}\E\T{314159}){}$\1\5 +\&{goto} \\{start\_of\_TEX};\2\6 +\X14:Check the ``constant'' values for consistency\X\6 +\&{if} ${}(\\{bad}>\T{0}){}$\5 +${}\{{}$\5 +\1${}\\{wterm\_ln}(\.{"Ouch---my\ internal\ }\)\.{constants\ have\ been\ }\)\.{clobbered!"}\.{"---case\ \%d"},\39\\{bad});{}$\5 +\\{exit}(\T{0});\6 +\4${}\}{}$\2\6 +\\{initialize}(\,);\C{set global variables to their starting values}\6 +\8\#\&{ifdef} \.{INIT}\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 +\8\#\&{endif}\6 +${}\\{ready\_already}\K\T{314159};{}$\6 +\4\\{start\_of\_TEX}:\5 +\X55:Initialize the output routines\X;\6 +\X1337: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}(\,);\5 +${}\\{ready\_already}\K\T{0};{}$\5 +\&{return} \T{0};\6 +\4${}\}{}$\2\par +\fi + +\M{1333}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\B\4\X1333:Last-minute procedures\X${}\E{}$\6 +\&{void} \\{close\_files\_and\_terminate}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|k;\C{all-purpose index}\7 +\X1378:Finish the extensions\X;\6 +\8\#\&{ifdef} \.{STAT}\6 +\&{if} ${}(\\{tracing\_stats}>\T{0}){}$\1\5 +\X1334:Output statistics about this job\X;\2\6 +\8\#\&{endif}\6 +\\{wake\_up\_terminal};\5 +\X642:Finish the \.{DVI} file\X;\6 +\&{if} (\\{log\_opened})\5 +${}\{{}$\5 +\1\\{wlog\_cr};\5 +${}\\{a\_close}({\AND}\\{log\_file});{}$\5 +${}\\{selector}\K\\{selector}-\T{2};{}$\6 +\&{if} ${}(\\{selector}\E\\{term\_only}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"Transcript\ written\ }\)\.{on\ "});\5 +\\{slow\_print}(\\{log\_name});\5 +\\{print\_char}(\.{'.'});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\As1335, 1336\ETs1338. +\U1330.\fi + +\M{1334}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\B\4\X1334:Output statistics about this job\X${}\E{}$\6 +\&{if} (\\{log\_opened})\5 +${}\{{}$\5 +\1\\{wlog\_ln}(\.{"\ "});\5 +\\{wlog\_ln}(\.{"Here\ is\ how\ much\ of}\)\.{\ TeX's\ memory\ you\ us}\)\.{ed:"});\5 +${}\\{wlog}(\.{"\ \%d\ string"},\39\\{str\_ptr}-\\{init\_str\_ptr});{}$\6 +\&{if} ${}(\\{str\_ptr}\I\\{init\_str\_ptr}+\T{1}){}$\1\5 +\\{wlog}(\.{"s"});\2\6 +${}\\{wlog\_ln}(\.{"\ out\ of\ \%d"},\39\\{max\_strings}-\\{init\_str\_ptr}){}$;\6 +${}\\{wlog\_ln}(\.{"\ \%d\ string\ characte}\)\.{rs\ out\ of\ \%d"},\39\\{pool\_ptr}-\\{init\_pool\_ptr},\39\\{pool\_size}-\\{init\_pool\_ptr}){}$;\6 +${}\\{wlog\_ln}(\.{"\ \%d\ words\ of\ memory}\)\.{\ out\ of\ \%d"},\39\\{lo\_mem\_max}-\\{mem\_min}+\\{mem\_end}-\\{hi\_mem\_min}+\T{2},\30\39\\{mem\_end}+\T{1}-\\{mem\_min}){}$;\6 +${}\\{wlog\_ln}(\.{"\ \%d\ multiletter\ con}\)\.{trol\ sequences\ out\ o}\)\.{f\ \%d"},\39\\{cs\_count},\39\\{hash\_size}){}$;\6 +${}\\{wlog}(\.{"\ \%d\ words\ of\ font\ i}\)\.{nfo\ for\ \%d\ font"},\39\\{fmem\_ptr},\39\\{font\_ptr}-\\{font\_base});{}$\6 +\&{if} ${}(\\{font\_ptr}\I\\{font\_base}+\T{1}){}$\1\5 +\\{wlog}(\.{"s"});\2\6 +${}\\{wlog\_ln}(\.{",\ out\ of\ \%d\ for\ \%d"},\39\\{font\_mem\_size},\39\\{font\_max}-\\{font\_base}){}$;\6 +${}\\{wlog}(\.{"\ \%d\ hyphenation\ exc}\)\.{eption"},\39\\{hyph\_count});{}$\6 +\&{if} ${}(\\{hyph\_count}\I\T{1}){}$\1\5 +\\{wlog}(\.{"s"});\2\6 +${}\\{wlog\_ln}(\.{"\ out\ of\ \%d"},\39\\{hyph\_size}){}$;\6 +${}\\{wlog\_ln}(\.{"\ \%di,\%dn,\%dp,\%db,\%d}\)\.{s\ stack\ positions\ ou}\)\.{t\ of\ \%di,\%dn,\%dp,\%db}\)\.{,\%ds"},\39\\{max\_in\_stack},\39\\{max\_nest\_stack},\30\39\\{max\_param\_stack},\30\39\\{max\_buf\_stack}+\T{1},\30\39\\{max\_save\_stack}+% +\T{6},\30\39\\{stack\_size},\39\\{nest\_size},\39\\{param\_size},\39\\{buf\_size},\39\\{save\_size});{}$\6 +\4${}\}{}$\2\par +\U1333.\fi + +\M{1335}We get to the \\{final\_cleanup} routine when \.{\\end} or \.{\\dump} has +been scanned and \\{its\_all\_over}\kern-2pt. + +\Y\B\4\X1333:Last-minute procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{final\_cleanup}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{small\_number} \|c;\C{0 for \.{\\end}, 1 for \.{\\dump}}\7 +${}\|c\K\\{cur\_chr};{}$\6 +\&{if} ${}(\\{job\_name}\E\T{0}){}$\1\5 +\\{open\_log\_file}(\,);\2\6 +\&{while} ${}(\\{input\_ptr}>\T{0}){}$\1\6 +\&{if} ${}(\\{state}\E\\{token\_list}){}$\1\5 +\\{end\_token\_list}(\,);\5 +\2\&{else}\1\5 +\\{end\_file\_reading}(\,);\2\2\6 +\&{while} ${}(\\{open\_parens}>\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ )"});\5 +\\{decr}(\\{open\_parens});\6 +\4${}\}{}$\2\6 +\&{if} ${}(\\{cur\_level}>\\{level\_one}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"("});\5 +\\{print\_esc}(\X1782:\.{"end\ occurred\ "}\X);\5 +\\{print\_str}(\.{"inside\ a\ group\ at\ l}\)\.{evel\ "});\5 +${}\\{print\_int}(\\{cur\_level}-\\{level\_one});{}$\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\2\6 +\&{while} ${}(\\{cond\_ptr}\I\\{null}){}$\5 +${}\{{}$\5 +\1\\{print\_nl}(\.{"("});\5 +\\{print\_esc}(\X1782:\.{"end\ occurred\ "}\X);\5 +\\{print\_str}(\.{"when\ "});\5 +${}\\{print\_cmd\_chr}(\\{if\_test},\39\\{cur\_if});{}$\6 +\&{if} ${}(\\{if\_line}\I\T{0}){}$\5 +${}\{{}$\5 +\1\\{print\_str}(\.{"\ on\ line\ "});\5 +\\{print\_int}(\\{if\_line});\6 +\4${}\}{}$\2\6 +\\{print\_str}(\.{"\ 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 +\4${}\}{}$\2\6 +\&{if} ${}(\\{history}\I\\{spotless}){}$\1\6 +\&{if} ${}(((\\{history}\E\\{warning\_issued})\V(\\{interaction}<\\{error\_stop\_mode}))){}$\1\6 +\&{if} ${}(\\{selector}\E\\{term\_and\_log}){}$\5 +${}\{{}$\5 +\1${}\\{selector}\K\\{term\_only};{}$\5 +\\{print\_nl}(\.{"(see\ the\ transcript}\)\.{\ file\ for\ additional}\)\.{\ information)"});\5 +${}\\{selector}\K\\{term\_and\_log};{}$\6 +\4${}\}{}$\2\2\2\6 +\&{if} ${}(\|c\E\T{1}){}$\5 +${}\{{}$\6 +\8\#\&{ifdef} \.{INIT}\1\6 +\&{for} ${}(\|c\K\\{top\_mark\_code};{}$ ${}\|c\Z\\{split\_bot\_mark\_code};{}$ ${}\|c\PP){}$\1\6 +\&{if} ${}(\\{cur\_mark}[\|c]\I\\{null}){}$\1\5 +\\{delete\_token\_ref}(\\{cur\_mark}[\|c]);\2\2\6 +\&{if} ${}(\\{last\_glue}\I\\{max\_halfword}){}$\1\5 +\\{delete\_glue\_ref}(\\{last\_glue});\2\6 +\\{store\_fmt\_file}(\,);\5 +\&{return};\6 +\8\#\&{endif}\6 +\\{print\_nl}(\.{"(\\\\dump\ is\ performe}\)\.{d\ only\ by\ INITEX)"});\5 +\&{return};\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1336}\B\X1333:Last-minute procedures\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{INIT}\6 +\&{void} \\{init\_prim}(\&{void})\C{initialize all the primitives}\6 +${}\{{}$\5 +\1${}\\{no\_new\_control\_sequence}\K\\{false};{}$\5 +\X226:Put each of \TeX's primitives into the hash table\X;\6 +${}\\{no\_new\_control\_sequence}\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\M{1337}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\B\4\X1337:Get the first line of input and prepare to start\X${}\E{}$\6 +${}\{{}$\5 +\1\X331:Initialize the input routines\X;\6 +\&{if} ${}((\\{format\_ident}\E\T{0})\V(\\{buffer}[\\{loc}]\E\.{'\&'})){}$\5 +${}\{{}$\5 +\1\&{if} ${}(\\{format\_ident}\I\T{0}){}$\1\5 +\\{initialize}(\,);\C{erase preloaded format}\2\6 +\&{if} ${}(\R\\{open\_fmt\_file}(\,)){}$\1\5 +\\{exit}(\T{0});\2\6 +\&{if} ${}(\R\\{load\_fmt\_file}(\,)){}$\5 +${}\{{}$\5 +\1${}\\{w\_close}({\AND}\\{fmt\_file});{}$\5 +\\{exit}(\T{0});\6 +\4${}\}{}$\2\6 +${}\\{w\_close}({\AND}\\{fmt\_file});{}$\6 +\&{while} ${}((\\{loc}<\\{limit})\W(\\{buffer}[\\{loc}]\E\.{'\ '})){}$\1\5 +\\{incr}(\\{loc});\2\6 +\4${}\}{}$\2\6 +\&{if} (\\{end\_line\_char\_inactive})\1\5 +\\{decr}(\\{limit});\2\6 +\&{else}\1\5 +${}\\{buffer}[\\{limit}]\K\\{end\_line\_char};{}$\2\6 +\\{fix\_date\_and\_time}(\,);\6 +\X765:Compute the magic offset\X;\6 +\X75:Initialize the print \\{selector} based on \\{interaction}\X;\6 +\&{if} ${}((\\{loc}<\\{limit})\W(\\{cat\_code}(\\{buffer}[\\{loc}])\I\\{escape})){}$\1\5 +\\{start\_input}(\,);\C{\.{\\input} assumed}\2\6 +\4${}\}{}$\2\par +\U1332.\fi + +\N{1}{1338}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\E\T{13}$, there is an additional argument, \|l.) + +\Y\B\4\X1333:Last-minute procedures\X${}\mathrel+\E{}$\6 +\8\#\&{ifdef} \.{DEBUG}\6 +\&{void} \\{debug\_help}(\&{void})\C{routine to display various things}\6 +${}\{{}$\5 +\1\&{int} \|k${},{}$ \|l${},{}$ \|m${},{}$ \|n;\7 +\&{loop}\5 +${}\{{}$\5 +\1\\{wake\_up\_terminal};\5 +\\{print\_nl}(\.{"debug\ \#\ (-1\ to\ exit}\)\.{):"});\5 +\\{update\_terminal};\6 +\&{if} ${}(\\{fscanf}(\\{term\_in}.\|f,\39\.{"\ \%d"},\39{\AND}\|m)<\T{1}\V\|m<\T{0}){}$\1\5 +\&{return};\2\6 +\&{else} \&{if} ${}(\|m\E\T{0}){}$\5 +${}\{{}$\5 +\1\&{goto} \\{breakpoint};\C{go to every label at least once}\6 +\4\\{breakpoint}:\5 +${}\|m\K\T{0}{}$;\C{'BREAKPOINT'}\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{fscanf}(\\{term\_in}.\|f,\39\.{"\ \%d"},\39{\AND}\|n);{}$\6 +\&{switch} (\|m)\5 +${}\{{}$\1\6 +\hbox{\4}\X1339:Numbered cases for \\{debug\_help}\X\6 +\4\&{default}:\5 +\\{print\_str}(\.{"?"});\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\8\#\&{endif}\par +\fi + +\M{1339}\B\X1339:Numbered cases for \\{debug\_help}\X${}\E{}$\6 +\4\&{case} \T{1}:\5 +\\{print\_word}(\\{mem}[\|n]);\5 +\&{break};\C{display \\{mem}[\|n] in all forms}\6 +\4\&{case} \T{2}:\5 +\\{print\_int}(\\{info}(\|n));\5 +\&{break};\6 +\4\&{case} \T{3}:\5 +\\{print\_int}(\\{link}(\|n));\5 +\&{break};\6 +\4\&{case} \T{4}:\5 +\\{print\_word}(\\{eqtb}[\|n]);\5 +\&{break};\6 +\4\&{case} \T{5}:\5 +\\{print\_word}(\\{font\_info}[\|n]);\5 +\&{break};\6 +\4\&{case} \T{6}:\5 +\\{print\_word}(\\{save\_stack}[\|n]);\5 +\&{break};\6 +\4\&{case} \T{7}:\5 +\\{show\_box}(\|n);\5 +\&{break};\C{show a box, abbreviated by \\{show\_box\_depth} and \\{show\_box\_breadth}}\6 +\4\&{case} \T{8}:\6 +${}\{{}$\5 +\1${}\\{breadth\_max}\K\T{10000};{}$\5 +${}\\{depth\_threshold}\K\\{pool\_size}-\\{pool\_ptr}-\T{10};{}$\5 +\\{show\_node\_list}(\|n);\C{show a box in its entirety}\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \T{9}:\5 +${}\\{show\_token\_list}(\|n,\39\\{null},\39\T{1000}){}$;\5 +\&{break};\6 +\4\&{case} \T{10}:\5 +\\{slow\_print}(\|n);\5 +\&{break};\6 +\4\&{case} \T{11}:\5 +${}\\{check\_mem}(\|n>\T{0}){}$;\5 +\&{break};\C{check wellformedness; print new busy locations if $\|n>\T{0}$}\6 +\4\&{case} \T{12}:\5 +\\{search\_mem}(\|n);\5 +\&{break};\C{look for pointers to \|n}\6 +\4\&{case} \T{13}:\6 +${}\{{}$\5 +\1${}\\{fscanf}(\\{term\_in}.\|f,\39\.{"\ \%d"},\39{\AND}\|l);{}$\5 +${}\\{print\_cmd\_chr}(\|n,\39\|l);{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \T{14}:\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\|n;{}$ ${}\|k\PP){}$\1\5 +\\{print}(\\{buffer}[\|k]);\5 +\2\&{break};\6 +\4\&{case} \T{15}:\6 +${}\{{}$\5 +\1${}\\{font\_in\_short\_display}\K\\{null\_font};{}$\5 +\\{short\_display}(\|n);\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \T{16}:\5 +${}\\{panicking}\K\R\\{panicking}{}$;\5 +\&{break};\par +\U1338.\fi + +\N{1}{1340}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 + +\M{1341}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}\E\\{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\B\4\D$\\{write\_node\_size}$ \5 +\T{2}\C{number of words in a write/whatsit node}\par +\B\4\D$\\{open\_node\_size}$ \5 +\T{3}\C{number of words in an open/whatsit node}\par +\B\4\D$\\{open\_node}$ \5 +\T{0}\C{\\{subtype} in whatsits that represent files to \.{\\openout}}\par +\B\4\D$\\{write\_node}$ \5 +\T{1}\C{\\{subtype} in whatsits that represent things to \.{\\write}}\par +\B\4\D$\\{close\_node}$ \5 +\T{2}\C{\\{subtype} in whatsits that represent streams to \.{\\closeout}}\par +\B\4\D$\\{special\_node}$ \5 +\T{3}\C{\\{subtype} in whatsits that represent \.{\\special} things}\par +\B\4\D$\\{language\_node}$ \5 +\T{4}\C{\\{subtype} in whatsits that change the current language}\par +\B\4\D$\\{what\_lang}(\|X)$ \5 +$\\{link}(\|X+\T{1}{}$)\C{language number, in the range $\T{0}\dotdot\T{255}$}\par +\B\4\D$\\{what\_lhm}(\|X)$ \5 +$\\{type}(\|X+\T{1}{}$)\C{minimum left fragment, in the range $\T{1}\dotdot\T{63}$}\par +\B\4\D$\\{what\_rhm}(\|X)$ \5 +$\\{subtype}(\|X+\T{1}{}$)\C{minimum right fragment, in the range $\T{1}\dotdot\T{63}$}\par +\B\4\D$\\{write\_tokens}(\|X)$ \5 +$\\{link}(\|X+\T{1}{}$)\C{reference count of token list to write}\par +\B\4\D$\\{write\_stream}(\|X)$ \5 +$\\{info}(\|X+\T{1}{}$)\C{stream number (0 to 17)}\par +\B\4\D$\\{open\_name}(\|X)$ \5 +$\\{link}(\|X+\T{1}{}$)\C{string number of file name to open}\par +\B\4\D$\\{open\_area}(\|X)$ \5 +$\\{info}(\|X+\T{2}{}$)\C{string number of file area for \\{open\_name}}\par +\B\4\D$\\{open\_ext}(\|X)$ \5 +$\\{link}(\|X+\T{2}{}$)\C{string number of file extension for \\{open\_name}}\par +\fi + +\M{1342}The sixteen possible \.{\\write} streams are represented by the \\{write\_file} +array. The \|jth file is open if and only if $\\{write\_open}[\|j]\E\\{true}$. The last +two streams are special; \\{write\_open}[\T{16}] represents a stream number +greater than 15, while \\{write\_open}[\T{17}] represents a negative stream number, +and both of these variables are always \\{false}. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{alpha\_file} \\{write\_file}[\T{16}];\6 +\&{bool} \\{write\_open}[\T{18}];\par +\fi + +\M{1343}\B\X21:Set initial values of key variables\X${}\mathrel+\E{}$\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{17};{}$ ${}\|k\PP){}$\1\5 +${}\\{write\_open}[\|k]\K\\{false}{}$;\2\par +\fi + +\M{1344}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\B\4\D$\\{immediate\_code}$ \5 +\T{4}\C{command modifier for \.{\\immediate}}\par +\B\4\D$\\{set\_language\_code}$ \5 +\T{5}\C{command modifier for \.{\\setlanguage}}\par +\Y\B\4\X226:Put each of \TeX's primitives into the hash table\X${}\mathrel+\E{}$\6 +$\\{primitive}(\X1783:\.{"openout"}\X,\39\\{extension},\39\\{open\_node}){}$;\6 +${}\\{primitive}(\X1568:\.{"write"}\X,\39\\{extension},\39\\{write\_node});{}$\5 +${}\\{write\_loc}\K\\{cur\_val}{}$;\6 +${}\\{primitive}(\X1784:\.{"closeout"}\X,\39\\{extension},\39\\{close\_node}){}$;\6 +${}\\{primitive}(\X1785:\.{"special"}\X,\39\\{extension},\39\\{special\_node}){}$;\6 +${}\\{primitive}(\X1786:\.{"immediate"}\X,\39\\{extension},\39\\{immediate\_code}){}$;\6 +${}\\{primitive}(\X1787:\.{"setlanguage"}\X,\39\\{extension},\39\\{set\_language\_code}){}$;\par +\fi + +\M{1345}The variable \\{write\_loc} just introduced is used to provide an +appropriate error message in case of ``runaway'' write texts. + +\Y\B\4\X13:Global variables\X${}\mathrel+\E{}$\6 +\&{pointer} \\{write\_loc};\C{\\{eqtb} address of \.{\\write}}\par +\fi + +\M{1346}\B\X227:Cases of \\{print\_cmd\_chr} for symbolic printing of primitives\X${}\mathrel+\E{}$\6 +\4\&{case} \\{extension}:\6 +\&{switch} (\\{chr\_code})\5 +${}\{{}$\1\6 +\4\&{case} \\{open\_node}:\5 +\\{print\_esc}(\X1783:\.{"openout"}\X);\5 +\&{break};\6 +\4\&{case} \\{write\_node}:\5 +\\{print\_esc}(\X1568:\.{"write"}\X);\5 +\&{break};\6 +\4\&{case} \\{close\_node}:\5 +\\{print\_esc}(\X1784:\.{"closeout"}\X);\5 +\&{break};\6 +\4\&{case} \\{special\_node}:\5 +\\{print\_esc}(\X1785:\.{"special"}\X);\5 +\&{break};\6 +\4\&{case} \\{immediate\_code}:\5 +\\{print\_esc}(\X1786:\.{"immediate"}\X);\5 +\&{break};\6 +\4\&{case} \\{set\_language\_code}:\5 +\\{print\_esc}(\X1787:\.{"setlanguage"}\X);\5 +\&{break};\6 +\4\&{default}:\5 +\\{print\_str}(\.{"[unknown\ extension!}\)\.{]"});\6 +\4${}\}{}$\5 +\2\&{break};\par +\fi + +\M{1347}When an \\{extension} command occurs in \\{main\_control}, in any mode, +the \\{do\_extension} routine is called. + +\Y\B\4\X1347:Cases of \\{main\_control} that are for extensions to \TeX\X${}\E{}$\6 +\4\\{any\_mode}(\\{extension}):\5 +\\{do\_extension}(\,);\par +\U1045.\fi + +\M{1348}\B\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\hbox{\4}\X1349:Declare procedures needed in \\{do\_extension}\X\7 +\&{void} \\{do\_extension}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{int} \|k;\C{all-purpose integer}\6 +\&{pointer} \|p;\C{all-purpose pointer}\7 +\&{switch} (\\{cur\_chr})\5 +${}\{{}$\1\6 +\4\&{case} \\{open\_node}:\5 +\X1351:Implement \.{\\openout}\X\5 +\&{break};\6 +\4\&{case} \\{write\_node}:\5 +\X1352:Implement \.{\\write}\X\5 +\&{break};\6 +\4\&{case} \\{close\_node}:\5 +\X1353:Implement \.{\\closeout}\X\5 +\&{break};\6 +\4\&{case} \\{special\_node}:\5 +\X1354:Implement \.{\\special}\X\5 +\&{break};\6 +\4\&{case} \\{immediate\_code}:\5 +\X1375:Implement \.{\\immediate}\X\5 +\&{break};\6 +\4\&{case} \\{set\_language\_code}:\5 +\X1377:Implement \.{\\setlanguage}\X\5 +\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1788:\.{"ext1"}\X);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1349}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\B\4\X1349:Declare procedures needed in \\{do\_extension}\X${}\E{}$\6 +\&{void} \\{new\_whatsit}(\&{small\_number} \|s${},\39{}$\&{small\_number} \|w)\1\1\2\2\6 +${}\{{}$\5 +\1\&{pointer} \|p;\C{the new node}\7 +${}\|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 +\4${}\}{}$\2\par +\A1350. +\U1348.\fi + +\M{1350}The next subroutine uses \\{cur\_chr} to decide what sort of whatsit is +involved, and also inserts a \\{write\_stream} number. + +\Y\B\4\X1349:Declare procedures needed in \\{do\_extension}\X${}\mathrel+\E{}$\6 +\&{void} \\{new\_write\_whatsit}(\&{small\_number} \|w)\1\1\2\2\6 +${}\{{}$\5 +\1${}\\{new\_whatsit}(\\{cur\_chr},\39\|w);{}$\6 +\&{if} ${}(\|w\I\\{write\_node\_size}){}$\1\5 +\\{scan\_four\_bit\_int}(\,);\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{scan\_int}(\,);\6 +\&{if} ${}(\\{cur\_val}<\T{0}){}$\1\5 +${}\\{cur\_val}\K\T{17};{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_val}>\T{15}){}$\1\5 +${}\\{cur\_val}\K\T{16};{}$\2\6 +\4${}\}{}$\2\6 +${}\\{write\_stream}(\\{tail})\K\\{cur\_val};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{1351}\B\X1351:Implement \.{\\openout}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{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 +\4${}\}{}$\2\par +\U1348.\fi + +\M{1352}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\B\4\X1352:Implement \.{\\write}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\par +\U1348.\fi + +\M{1353}\B\X1353:Implement \.{\\closeout}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{new\_write\_whatsit}(\\{write\_node\_size});\5 +${}\\{write\_tokens}(\\{tail})\K\\{null};{}$\6 +\4${}\}{}$\2\par +\U1348.\fi + +\M{1354}When `\.{\\special\{...\}}' appears, we expand the macros in the token +list as in \.{\\xdef} and \.{\\mark}. + +\Y\B\4\X1354:Implement \.{\\special}\X${}\E{}$\6 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\par +\U1348.\fi + +\M{1355}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\B\4\X57:Basic printing procedures\X${}\mathrel+\E{}$\6 +\&{void} \\{print\_write\_whatsit}(\&{str\_number} \|s${},\39{}$\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\\{print\_esc}(\|s);\6 +\&{if} ${}(\\{write\_stream}(\|p)<\T{16}){}$\1\5 +\\{print\_int}(\\{write\_stream}(\|p));\2\6 +\&{else} \&{if} ${}(\\{write\_stream}(\|p)\E\T{16}){}$\1\5 +\\{print\_char}(\.{'*'});\2\6 +\&{else}\1\5 +\\{print\_char}(\.{'-'});\2\6 +\4${}\}{}$\2\par +\fi + +\M{1356}\B\X1356:Display the whatsit node \|p\X${}\E{}$\6 +\&{switch} (\\{subtype}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{open\_node}:\6 +${}\{{}$\5 +\1${}\\{print\_write\_whatsit}(\X1783:\.{"openout"}\X,\39\|p);{}$\5 +\\{print\_char}(\.{'='});\5 +${}\\{print\_file\_name}(\\{open\_name}(\|p),\39\\{open\_area}(\|p),\39\\{open\_ext}(\|p));{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{write\_node}:\6 +${}\{{}$\5 +\1${}\\{print\_write\_whatsit}(\X1568:\.{"write"}\X,\39\|p);{}$\5 +\\{print\_mark}(\\{write\_tokens}(\|p));\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{close\_node}:\5 +${}\\{print\_write\_whatsit}(\X1784:\.{"closeout"}\X,\39\|p){}$;\5 +\&{break};\6 +\4\&{case} \\{special\_node}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1785:\.{"special"}\X);\5 +\\{print\_mark}(\\{write\_tokens}(\|p));\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{language\_node}:\6 +${}\{{}$\5 +\1\\{print\_esc}(\X1787:\.{"setlanguage"}\X);\5 +\\{print\_int}(\\{what\_lang}(\|p));\5 +\\{print\_str}(\.{"\ (hyphenmin\ "});\5 +\\{print\_int}(\\{what\_lhm}(\|p));\5 +\\{print\_char}(\.{','});\5 +\\{print\_int}(\\{what\_rhm}(\|p));\5 +\\{print\_char}(\.{')'});\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\5 +\\{print\_str}(\.{"whatsit?"});\6 +\4${}\}{}$\2\par +\U183.\fi + +\M{1357}\B\X1357: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${}\E{}$\6 +\&{switch} (\\{subtype}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{open\_node}:\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_node}(\\{open\_node\_size});{}$\5 +${}\\{words}\K\\{open\_node\_size};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{write\_node}:\5 +\&{case} \\{special\_node}:\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_node}(\\{write\_node\_size});{}$\5 +\\{add\_token\_ref}(\\{write\_tokens}(\|p));\5 +${}\\{words}\K\\{write\_node\_size};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{case} \\{close\_node}:\5 +\&{case} \\{language\_node}:\6 +${}\{{}$\5 +\1${}\|r\K\\{get\_node}(\\{small\_node\_size});{}$\5 +${}\\{words}\K\\{small\_node\_size};{}$\6 +\4${}\}{}$\5 +\2\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1789:\.{"ext2"}\X);\6 +\4${}\}{}$\2\par +\U206.\fi + +\M{1358}\B\X1358:Wipe out the whatsit node \|p and \&{goto} \\{done}\X${}\E{}$\6 +${}\{{}$\5 +\1\&{switch} (\\{subtype}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{open\_node}:\5 +${}\\{free\_node}(\|p,\39\\{open\_node\_size}){}$;\5 +\&{break};\6 +\4\&{case} \\{write\_node}:\5 +\&{case} \\{special\_node}:\6 +${}\{{}$\5 +\1\\{delete\_token\_ref}(\\{write\_tokens}(\|p));\5 +${}\\{free\_node}(\|p,\39\\{write\_node\_size});{}$\5 +\&{goto} \\{done};\6 +\4${}\}{}$\2\6 +\4\&{case} \\{close\_node}:\5 +\&{case} \\{language\_node}:\5 +${}\\{free\_node}(\|p,\39\\{small\_node\_size}){}$;\5 +\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1790:\.{"ext3"}\X);\6 +\4${}\}{}$\2\6 +\&{goto} \\{done};\6 +\4${}\}{}$\2\par +\U202.\fi + +\M{1359}\B\X1359:Incorporate a whatsit node into a vbox\X${}\E{}$\6 +\\{do\_nothing}\par +\U669.\fi + +\M{1360}\B\X1360:Incorporate a whatsit node into an hbox\X${}\E{}$\6 +\\{do\_nothing}\par +\U651.\fi + +\M{1361}\B\X1361:Let \|d be the width of the whatsit \|p\X${}\E{}$\6 +$\|d\K{}$\T{0}\par +\U1147.\fi + +\M{1362}\B\D$\\{adv\_past}(\|X)$ \5 +\&{if} ${}(\\{subtype}(\|X)\E\\{language\_node}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_lang}\K\\{what\_lang}(\|X);{}$\5 +${}\\{l\_hyf}\K\\{what\_lhm}(\|X);{}$\5 +${}\\{r\_hyf}\K\\{what\_rhm}(\|X){}$;\5 +${}\}{}$\2\par +\Y\B\4\X1362:Advance \(p)past a whatsit node in the \(l)\\{line\_break} loop\X${}\E{}$\5 +\\{adv\_past}(\\{cur\_p})\par +\U866.\fi + +\M{1363}\B\X1363:Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop\X${}\E{}$\5 +\\{adv\_past}(\|s)\par +\U896.\fi + +\M{1364}\B\X1364:Prepare to move whatsit \|p to the current page, then \&{goto} \\{contribute}\X${}\E{}$\6 +\&{goto} \\{contribute}\par +\U1000.\fi + +\M{1365}\B\X1365:Process whatsit \|p in \\{vert\_break} loop, \&{goto} \\{not\_found}\X${}\E{}$\6 +\&{goto} \\{not\_found}\par +\U973.\fi + +\M{1366}\B\X1366:Output the whatsit node \|p in a vlist\X${}\E{}$\6 +\\{out\_what}(\|p)\par +\U631.\fi + +\M{1367}\B\X1367:Output the whatsit node \|p in an hlist\X${}\E{}$\6 +\\{out\_what}(\|p)\par +\U622.\fi + +\M{1368}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\B\4\X1368:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X${}\E{}$\6 +\&{void} \\{special\_out}(\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \\{old\_setting};\C{holds print \\{selector}}\6 +\&{int} \|k;\C{index into \\{str\_pool}}\7 +\\{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}(\T{1});\6 +\&{if} ${}(\\{cur\_length}<\T{256}){}$\5 +${}\{{}$\5 +\1\\{dvi\_out}(\\{xxx1});\5 +\\{dvi\_out}(\\{cur\_length});\6 +\4${}\}{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\1\\{dvi\_out}(\\{xxx4});\5 +\\{dvi\_four}(\\{cur\_length});\6 +\4${}\}{}$\2\6 +\&{for} ${}(\|k\K\\{str\_start}[\\{str\_ptr}];{}$ ${}\|k\Z\\{pool\_ptr}-\T{1};{}$ ${}\|k\PP){}$\1\5 +\\{dvi\_out}(\\{so}(\\{str\_pool}[\|k]));\2\6 +${}\\{pool\_ptr}\K\\{str\_start}[\\{str\_ptr}]{}$;\C{erase the string}\6 +\4${}\}{}$\2\par +\As1370\ET1373. +\U619.\fi + +\M{1369}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\B\4\X164:Initialize table entries (done by \.{INITEX} only)\X${}\mathrel+\E{}$\6 +$\\{text}(\\{end\_write})\K\X1791:\.{"endwrite"}\X;{}$\5 +${}\\{eq\_level}(\\{end\_write})\K\\{level\_one};{}$\5 +${}\\{eq\_type}(\\{end\_write})\K\\{outer\_call};{}$\5 +${}\\{equiv}(\\{end\_write})\K\\{null}{}$;\par +\fi + +\M{1370}\B\X1368:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X${}\mathrel+\E{}$\6 +\&{void} \\{write\_out}(\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\&{uint8\_t} \\{old\_setting};\C{holds print \\{selector}}\6 +\&{int} \\{old\_mode};\C{saved \\{mode}}\6 +\&{small\_number} \|j;\C{write stream number}\6 +\&{pointer} \|q${},{}$ \|r;\C{temporary variables for list manipulation}\7 +\X1371: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} (\\{write\_open}[\|j])\1\5 +${}\\{selector}\K\|j;{}$\2\6 +\&{else}\5 +${}\{{}$\5 +\C{write to the terminal if file isn't open}\1\6 +\&{if} ${}((\|j\E\T{17})\W(\\{selector}\E\\{term\_and\_log})){}$\1\5 +${}\\{selector}\K\\{log\_only};{}$\2\6 +\\{print\_nl}(\.{""});\6 +\4${}\}{}$\2\6 +\\{token\_show}(\\{def\_ref});\5 +\\{print\_ln}(\,);\5 +\\{flush\_list}(\\{def\_ref});\5 +${}\\{selector}\K\\{old\_setting};{}$\6 +\4${}\}{}$\2\par +\fi + +\M{1371}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\B\4\D$\\{end\_write\_token}$ \5 +$\\{cs\_token\_flag}+{}$\\{end\_write}\par +\Y\B\4\X1371:Expand macros in the token list and make \\{link}(\\{def\_ref}) point to the result\X${}\E{}$\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}\K\T{0}{}$;\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}(\,);\5 +\&{if} ${}(\\{cur\_tok}\I\\{end\_write\_token}){}$\1\5 +\X1372:Recover from an unbalanced write command\X;\2\6 +${}\\{mode}\K\\{old\_mode};$ \\{end\_token\_list}(\,)\C{conserve stack space}\par +\U1370.\fi + +\M{1372}\B\X1372:Recover from an unbalanced write command\X${}\E{}$\6 +${}\{{}$\5 +\1\\{print\_err}(\.{"Unbalanced\ write\ co}\)\.{mmand"});\5 +\\{help2}(\.{"On\ this\ page\ there'}\)\.{s\ a\ \\\\write\ with\ few}\)\.{er\ real\ \{'s\ than\ \}'s}\)\.{."})\6 +(\.{"I\ can't\ handle\ that}\)\.{\ very\ well;\ good\ luc}\)\.{k."});\6 +\&{error} (\,)\1\5 +;\2\6 +\&{do}\5 +${}\{{}$\1\6 +\\{get\_token}(\,);\6 +\4${}\}{}$\5 +\2\5 +\&{while} ${}(\R(\\{cur\_tok}\E\\{end\_write\_token}));{}$\6 +\4${}\}{}$\2\par +\U1371.\fi + +\M{1373}The \\{out\_what} procedure takes care of outputting whatsit nodes for +\\{vlist\_out} and \\{hlist\_out}\kern-.3pt. + +\Y\B\4\X1368:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X${}\mathrel+\E{}$\6 +\&{void} \\{out\_what}(\&{pointer} \|p)\1\1\2\2\6 +${}\{{}$\5 +\1\&{small\_number} \|j;\C{write stream number}\7 +\&{switch} (\\{subtype}(\|p))\5 +${}\{{}$\1\6 +\4\&{case} \\{open\_node}:\5 +\&{case} \\{write\_node}:\5 +\&{case} \\{close\_node}:\5 +\X1374:Do some work that has been queued up for \.{\\write}\X\5 +\&{break};\6 +\4\&{case} \\{special\_node}:\5 +\\{special\_out}(\|p);\5 +\&{break};\6 +\4\&{case} \\{language\_node}:\5 +\\{do\_nothing};\5 +\&{break};\6 +\4\&{default}:\5 +\\{confusion}(\X1792:\.{"ext4"}\X);\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1374}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\B\4\X1374:Do some work that has been queued up for \.{\\write}\X${}\E{}$\6 +\&{if} ${}(\R\\{doing\_leaders}){}$\5 +${}\{{}$\5 +\1${}\|j\K\\{write\_stream}(\|p);{}$\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{write\_node}){}$\1\5 +\\{write\_out}(\|p);\2\6 +\&{else}\5 +${}\{{}$\5 +\1\&{if} (\\{write\_open}[\|j])\1\5 +${}\\{a\_close}({\AND}\\{write\_file}[\|j]);{}$\2\6 +\&{if} ${}(\\{subtype}(\|p)\E\\{close\_node}){}$\1\5 +${}\\{write\_open}[\|j]\K\\{false};{}$\2\6 +\&{else} \&{if} ${}(\|j<\T{16}){}$\5 +${}\{{}$\5 +\1${}\\{cur\_name}\K\\{open\_name}(\|p);{}$\5 +${}\\{cur\_area}\K\\{open\_area}(\|p);{}$\5 +${}\\{cur\_ext}\K\\{open\_ext}(\|p);{}$\6 +\&{if} ${}(\\{cur\_ext}\E\\{empty\_string}){}$\1\5 +${}\\{cur\_ext}\K\X1637:\.{".tex"}\X;{}$\2\6 +\\{pack\_cur\_name};\6 +\&{while} ${}(\R\\{a\_open\_out}({\AND}\\{write\_file}[\|j])){}$\1\5 +${}\\{prompt\_file\_name}(\.{"output\ file\ name"},\39\X1637:\.{".tex"}\X);{}$\2\6 +${}\\{write\_open}[\|j]\K\\{true};{}$\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\U1373.\fi + +\M{1375}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\B\4\X1375:Implement \.{\\immediate}\X${}\E{}$\6 +${}\{{}$\5 +\1\\{get\_x\_token}(\,);\6 +\&{if} ${}((\\{cur\_cmd}\E\\{extension})\W(\\{cur\_chr}\Z\\{close\_node})){}$\5 +${}\{{}$\5 +\1${}\|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 +\4${}\}{}$\2\6 +\&{else}\1\5 +\\{back\_input}(\,);\2\6 +\4${}\}{}$\2\par +\U1348.\fi + +\M{1376}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\B\4\X1043:Declare action procedures for use by \\{main\_control}\X${}\mathrel+\E{}$\6 +\&{void} \\{fix\_language}(\&{void})\1\1\2\2\6 +${}\{{}$\5 +\1\&{ASCII\_code} \|l;\C{the new current language}\7 +\&{if} ${}(\\{language}\Z\T{0}){}$\1\5 +${}\|l\K\T{0};{}$\2\6 +\&{else} \&{if} ${}(\\{language}>\T{255}){}$\1\5 +${}\|l\K\T{0};{}$\2\6 +\&{else}\1\5 +${}\|l\K\\{language};{}$\2\6 +\&{if} ${}(\|l\I\\{clang}){}$\5 +${}\{{}$\5 +\1${}\\{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 +\4${}\}{}$\2\6 +\4${}\}{}$\2\par +\fi + +\M{1377}\B\X1377:Implement \.{\\setlanguage}\X${}\E{}$\6 +\&{if} ${}(\\{abs}(\\{mode})\I\\{hmode}){}$\1\5 +\\{report\_illegal\_case}(\,);\2\6 +\&{else}\5 +${}\{{}$\5 +\1${}\\{new\_whatsit}(\\{language\_node},\39\\{small\_node\_size});{}$\5 +\\{scan\_int}(\,);\6 +\&{if} ${}(\\{cur\_val}\Z\T{0}){}$\1\5 +${}\\{clang}\K\T{0};{}$\2\6 +\&{else} \&{if} ${}(\\{cur\_val}>\T{255}){}$\1\5 +${}\\{clang}\K\T{0};{}$\2\6 +\&{else}\1\5 +${}\\{clang}\K\\{cur\_val};{}$\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 +\4${}\}{}$\2\par +\U1348.\fi + +\M{1378}\B\X1378:Finish the extensions\X${}\E{}$\6 +\&{for} ${}(\|k\K\T{0};{}$ ${}\|k\Z\T{15};{}$ ${}\|k\PP)$ \&{if} (\\{write\_open}[\|k]) $\\{a\_close}({\AND}\\{write\_file}[\|k]{}$)\par +\U1333.\fi + +\N{1}{1379}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 + +\M{1380}Appendix: Replacement of the string pool file. +\Y\B\4\D$\\{str\_0\_255}$ \5 +\.{"\^\^@\^\^A\^\^B\^\^C\^\^D\^\^E\^}\)\.{\^F\^\^G\^\^H\^\^I\^\^J\^\^K\^\^L}\)\.{\^\^M\^\^N\^\^O"}\6 +\.{"\^\^P\^\^Q\^\^R\^\^S\^\^T\^\^U\^}\)\.{\^V\^\^W\^\^X\^\^Y\^\^Z\^\^[\^\^\\}\)\.{\\\^\^]\^\^\^\^\^\_"}\6 +\.{"\ !\\"\#\$\%\&'()*+,-./"}\6 +\.{"0123456789:;<=>?"}\6 +\.{"@ABCDEFGHIJKLMNO"}\6 +\.{"PQRSTUVWXYZ[\\\\]\^\_"}\6 +\.{"`abcdefghijklmno"}\6 +\.{"pqrstuvwxyz\{|\}\~\^\^?"}\6 +\.{"\^\^80\^\^81\^\^82\^\^83\^\^8}\)\.{4\^\^85\^\^86\^\^87\^\^88\^\^8}\)\.{9\^\^8a\^\^8b\^\^8c\^\^8d\^\^8}\)\.{e\^\^8f"}\6 +\.{"\^\^90\^\^91\^\^92\^\^93\^\^9}\)\.{4\^\^95\^\^96\^\^97\^\^98\^\^9}\)\.{9\^\^9a\^\^9b\^\^9c\^\^9d\^\^9}\)\.{e\^\^9f"}\6 +\.{"\^\^a0\^\^a1\^\^a2\^\^a3\^\^a}\)\.{4\^\^a5\^\^a6\^\^a7\^\^a8\^\^a}\)\.{9\^\^aa\^\^ab\^\^ac\^\^ad\^\^a}\)\.{e\^\^af"}\6 +\.{"\^\^b0\^\^b1\^\^b2\^\^b3\^\^b}\)\.{4\^\^b5\^\^b6\^\^b7\^\^b8\^\^b}\)\.{9\^\^ba\^\^bb\^\^bc\^\^bd\^\^b}\)\.{e\^\^bf"}\6 +\.{"\^\^c0\^\^c1\^\^c2\^\^c3\^\^c}\)\.{4\^\^c5\^\^c6\^\^c7\^\^c8\^\^c}\)\.{9\^\^ca\^\^cb\^\^cc\^\^cd\^\^c}\)\.{e\^\^cf"}\6 +\.{"\^\^d0\^\^d1\^\^d2\^\^d3\^\^d}\)\.{4\^\^d5\^\^d6\^\^d7\^\^d8\^\^d}\)\.{9\^\^da\^\^db\^\^dc\^\^dd\^\^d}\)\.{e\^\^df"}\6 +\.{"\^\^e0\^\^e1\^\^e2\^\^e3\^\^e}\)\.{4\^\^e5\^\^e6\^\^e7\^\^e8\^\^e}\)\.{9\^\^ea\^\^eb\^\^ec\^\^ed\^\^e}\)\.{e\^\^ef"}\6 +\.{"\^\^f0\^\^f1\^\^f2\^\^f3\^\^f}\)\.{4\^\^f5\^\^f6\^\^f7\^\^f8\^\^f}\)\.{9\^\^fa\^\^fb\^\^fc\^\^fd\^\^f}\)\.{e\^\^ff"}\par +\B\4\D$\\{str\_start\_0\_255}$ \5 +$\T{0},\39\T{3},\39\T{6},\39\T{9},\39\T{12},\39\T{15},\39\T{18},\39\T{21},\39\T{24},\39\T{27},\39\T{30},\39\T{33},\39\T{36},\39\T{39},\39\T{42},\39\T{45},{}$\6 +\T{48}${},\39\T{51},\39\T{54},\39\T{57},\39\T{60},\39\T{63},\39\T{66},\39\T{69},\39\T{72},\39\T{75},\39\T{78},\39\T{81},\39\T{84},\39\T{87},\39\T{90},\39\T{93},{}$\6 +\T{96}${},\39\T{97},\39\T{98},\39\T{99},\39\T{100},\39\T{101},\39\T{102},\39\T{103},\39\T{104},\39\T{105},\39\T{106},\39\T{107},\39\T{108},\39\T{109},\39\T{110},\39\T{111},{}$\6 +\T{112}${},\39\T{113},\39\T{114},\39\T{115},\39\T{116},\39\T{117},\39\T{118},\39\T{119},\39\T{120},\39\T{121},\39\T{122},\39\T{123},\39\T{124},\39\T{125},\39\T{126},\39\T{127},{}$\6 +\T{128}${},\39\T{129},\39\T{130},\39\T{131},\39\T{132},\39\T{133},\39\T{134},\39\T{135},\39\T{136},\39\T{137},\39\T{138},\39\T{139},\39\T{140},\39\T{141},\39\T{142},\39\T{143},{}$\6 +\T{144}${},\39\T{145},\39\T{146},\39\T{147},\39\T{148},\39\T{149},\39\T{150},\39\T{151},\39\T{152},\39\T{153},\39\T{154},\39\T{155},\39\T{156},\39\T{157},\39\T{158},\39\T{159},{}$\6 +\T{160}${},\39\T{161},\39\T{162},\39\T{163},\39\T{164},\39\T{165},\39\T{166},\39\T{167},\39\T{168},\39\T{169},\39\T{170},\39\T{171},\39\T{172},\39\T{173},\39\T{174},\39\T{175},{}$\6 +\T{176}${},\39\T{177},\39\T{178},\39\T{179},\39\T{180},\39\T{181},\39\T{182},\39\T{183},\39\T{184},\39\T{185},\39\T{186},\39\T{187},\39\T{188},\39\T{189},\39\T{190},\39\T{191},{}$\6 +\T{194}${},\39\T{198},\39\T{202},\39\T{206},\39\T{210},\39\T{214},\39\T{218},\39\T{222},\39\T{226},\39\T{230},\39\T{234},\39\T{238},\39\T{242},\39\T{246},\39\T{250},\39\T{254},{}$\6 +\T{258}${},\39\T{262},\39\T{266},\39\T{270},\39\T{274},\39\T{278},\39\T{282},\39\T{286},\39\T{290},\39\T{294},\39\T{298},\39\T{302},\39\T{306},\39\T{310},\39\T{314},\39\T{318},{}$\6 +\T{322}${},\39\T{326},\39\T{330},\39\T{334},\39\T{338},\39\T{342},\39\T{346},\39\T{350},\39\T{354},\39\T{358},\39\T{362},\39\T{366},\39\T{370},\39\T{374},\39\T{378},\39\T{382},{}$\6 +\T{386}${},\39\T{390},\39\T{394},\39\T{398},\39\T{402},\39\T{406},\39\T{410},\39\T{414},\39\T{418},\39\T{422},\39\T{426},\39\T{430},\39\T{434},\39\T{438},\39\T{442},\39\T{446},{}$\6 +\T{450}${},\39\T{454},\39\T{458},\39\T{462},\39\T{466},\39\T{470},\39\T{474},\39\T{478},\39\T{482},\39\T{486},\39\T{490},\39\T{494},\39\T{498},\39\T{502},\39\T{506},\39\T{510},{}$\6 +\T{514}${},\39\T{518},\39\T{522},\39\T{526},\39\T{530},\39\T{534},\39\T{538},\39\T{542},\39\T{546},\39\T{550},\39\T{554},\39\T{558},\39\T{562},\39\T{566},\39\T{570},\39\T{574},{}$\6 +\T{578}${},\39\T{582},\39\T{586},\39\T{590},\39\T{594},\39\T{598},\39\T{602},\39\T{606},\39\T{610},\39\T{614},\39\T{618},\39\T{622},\39\T{626},\39\T{630},\39\T{634},\39\T{638},{}$\6 +\T{642}${},\39\T{646},\39\T{650},\39\T{654},\39\T{658},\39\T{662},\39\T{666},\39\T{670},\39\T{674},\39\T{678},\39\T{682},\39\T{686},\39\T{690},\39\T{694},\39\T{698},\39\T{702}$ $,{}$\par +\fi + +\M{1381} +\Y\B\4\D$\\{str\_256}$ \5 +\.{"???"}\par +\Y\B\4\X1381:\.{"???"}\X${}\E{}$\5 +\T{256}\par +\U59.\fi + +\M{1382} +\Y\B\4\D$\\{str\_257}$ \5 +\.{"m2d5c2l5x2v5i"}\par +\Y\B\4\X1382:\.{"m2d5c2l5x2v5i"}\X${}\E{}$\5 +\T{257}\par +\U69.\fi + +\M{1383} +\Y\B\4\D$\\{str\_258}$ \5 +\.{"batchmode"}\par +\Y\B\4\X1383:\.{"batchmode"}\X${}\E{}$\5 +\T{258}\par +\Us86, 1262\ETs1263.\fi + +\M{1384} +\Y\B\4\D$\\{str\_259}$ \5 +\.{"nonstopmode"}\par +\Y\B\4\X1384:\.{"nonstopmode"}\X${}\E{}$\5 +\T{259}\par +\Us86, 1262\ETs1263.\fi + +\M{1385} +\Y\B\4\D$\\{str\_260}$ \5 +\.{"scrollmode"}\par +\Y\B\4\X1385:\.{"scrollmode"}\X${}\E{}$\5 +\T{260}\par +\Us86, 1262\ETs1263.\fi + +\M{1386} +\Y\B\4\D$\\{str\_261}$ \5 +\.{"CLOBBERED."}\par +\Y\B\4\X1386:\.{"CLOBBERED."}\X${}\E{}$\5 +\T{261}\par +\Us176\ET293.\fi + +\M{1387} +\Y\B\4\D$\\{str\_262}$ \5 +\.{"fil"}\par +\Y\B\4\X1387:\.{"fil"}\X${}\E{}$\5 +\T{262}\par +\U454.\fi + +\M{1388} +\Y\B\4\D$\\{str\_263}$ \5 +\.{"unset"}\par +\Y\B\4\X1388:\.{"unset"}\X${}\E{}$\5 +\T{263}\par +\U184.\fi + +\M{1389} +\Y\B\4\D$\\{str\_264}$ \5 +\.{"rule("}\par +\Y\B\4\X1389:\.{"rule("}\X${}\E{}$\5 +\T{264}\par +\U187.\fi + +\M{1390} +\Y\B\4\D$\\{str\_265}$ \5 +\.{"insert"}\par +\Y\B\4\X1390:\.{"insert"}\X${}\E{}$\5 +\T{265}\par +\Us188, 265, 266, 986\ETs1099.\fi + +\M{1391} +\Y\B\4\D$\\{str\_266}$ \5 +\.{"glue"}\par +\Y\B\4\X1391:\.{"glue"}\X${}\E{}$\5 +\T{266}\par +\U189.\fi + +\M{1392} +\Y\B\4\D$\\{str\_267}$ \5 +\.{"nonscript"}\par +\Y\B\4\X1392:\.{"nonscript"}\X${}\E{}$\5 +\T{267}\par +\Us189, 265\ETs266.\fi + +\M{1393} +\Y\B\4\D$\\{str\_268}$ \5 +\.{"mskip"}\par +\Y\B\4\X1393:\.{"mskip"}\X${}\E{}$\5 +\T{268}\par +\Us189, 1058\ETs1059.\fi + +\M{1394} +\Y\B\4\D$\\{str\_269}$ \5 +\.{"mu"}\par +\Y\B\4\X1394:\.{"mu"}\X${}\E{}$\5 +\T{269}\par +\Us189, 229, 456\ETs465.\fi + +\M{1395} +\Y\B\4\D$\\{str\_270}$ \5 +\.{""}\par +\B\4\D$\\{empty\_string}$ \5 +\T{270}\par +\fi + +\M{1396} +\Y\B\4\D$\\{str\_271}$ \5 +\.{"kern"}\par +\Y\B\4\X1396:\.{"kern"}\X${}\E{}$\5 +\T{271}\par +\Us191, 856, 1058\ETs1059.\fi + +\M{1397} +\Y\B\4\D$\\{str\_272}$ \5 +\.{"mkern"}\par +\Y\B\4\X1397:\.{"mkern"}\X${}\E{}$\5 +\T{272}\par +\Us191, 1058\ETs1059.\fi + +\M{1398} +\Y\B\4\D$\\{str\_273}$ \5 +\.{"math"}\par +\Y\B\4\X1398:\.{"math"}\X${}\E{}$\5 +\T{273}\par +\Us192\ET856.\fi + +\M{1399} +\Y\B\4\D$\\{str\_274}$ \5 +\.{"penalty\ "}\par +\Y\B\4\X1399:\.{"penalty\ "}\X${}\E{}$\5 +\T{274}\par +\U194.\fi + +\M{1400} +\Y\B\4\D$\\{str\_275}$ \5 +\.{"discretionary"}\par +\Y\B\4\X1400:\.{"discretionary"}\X${}\E{}$\5 +\T{275}\par +\Us195, 856, 1114, 1115\ETs1120.\fi + +\M{1401} +\Y\B\4\D$\\{str\_276}$ \5 +\.{"mark"}\par +\Y\B\4\X1401:\.{"mark"}\X${}\E{}$\5 +\T{276}\par +\Us196, 265, 266\ETs323.\fi + +\M{1402} +\Y\B\4\D$\\{str\_277}$ \5 +\.{"vadjust"}\par +\Y\B\4\X1402:\.{"vadjust"}\X${}\E{}$\5 +\T{277}\par +\Us197, 265\ETs266.\fi + +\M{1403} +\Y\B\4\D$\\{str\_278}$ \5 +\.{"flushing"}\par +\Y\B\4\X1403:\.{"flushing"}\X${}\E{}$\5 +\T{278}\par +\U202.\fi + +\M{1404} +\Y\B\4\D$\\{str\_279}$ \5 +\.{"copying"}\par +\Y\B\4\X1404:\.{"copying"}\X${}\E{}$\5 +\T{279}\par +\U206.\fi + +\M{1405} +\Y\B\4\D$\\{str\_280}$ \5 +\.{"lineskip"}\par +\Y\B\4\X1405:\.{"lineskip"}\X${}\E{}$\5 +\T{280}\par +\Us225\ET226.\fi + +\M{1406} +\Y\B\4\D$\\{str\_281}$ \5 +\.{"baselineskip"}\par +\Y\B\4\X1406:\.{"baselineskip"}\X${}\E{}$\5 +\T{281}\par +\Us225\ET226.\fi + +\M{1407} +\Y\B\4\D$\\{str\_282}$ \5 +\.{"parskip"}\par +\Y\B\4\X1407:\.{"parskip"}\X${}\E{}$\5 +\T{282}\par +\Us225\ET226.\fi + +\M{1408} +\Y\B\4\D$\\{str\_283}$ \5 +\.{"abovedisplayskip"}\par +\Y\B\4\X1408:\.{"abovedisplayskip"}\X${}\E{}$\5 +\T{283}\par +\Us225\ET226.\fi + +\M{1409} +\Y\B\4\D$\\{str\_284}$ \5 +\.{"belowdisplayskip"}\par +\Y\B\4\X1409:\.{"belowdisplayskip"}\X${}\E{}$\5 +\T{284}\par +\Us225\ET226.\fi + +\M{1410} +\Y\B\4\D$\\{str\_285}$ \5 +\.{"abovedisplayshortsk}\)\.{ip"}\par +\Y\B\4\X1410:\.{"abovedisplayshortsk}\)\.{ip"}\X${}\E{}$\5 +\T{285}\par +\Us225\ET226.\fi + +\M{1411} +\Y\B\4\D$\\{str\_286}$ \5 +\.{"belowdisplayshortsk}\)\.{ip"}\par +\Y\B\4\X1411:\.{"belowdisplayshortsk}\)\.{ip"}\X${}\E{}$\5 +\T{286}\par +\Us225\ET226.\fi + +\M{1412} +\Y\B\4\D$\\{str\_287}$ \5 +\.{"leftskip"}\par +\Y\B\4\X1412:\.{"leftskip"}\X${}\E{}$\5 +\T{287}\par +\Us225\ET226.\fi + +\M{1413} +\Y\B\4\D$\\{str\_288}$ \5 +\.{"rightskip"}\par +\Y\B\4\X1413:\.{"rightskip"}\X${}\E{}$\5 +\T{288}\par +\Us225\ET226.\fi + +\M{1414} +\Y\B\4\D$\\{str\_289}$ \5 +\.{"topskip"}\par +\Y\B\4\X1414:\.{"topskip"}\X${}\E{}$\5 +\T{289}\par +\Us225\ET226.\fi + +\M{1415} +\Y\B\4\D$\\{str\_290}$ \5 +\.{"splittopskip"}\par +\Y\B\4\X1415:\.{"splittopskip"}\X${}\E{}$\5 +\T{290}\par +\Us225\ET226.\fi + +\M{1416} +\Y\B\4\D$\\{str\_291}$ \5 +\.{"tabskip"}\par +\Y\B\4\X1416:\.{"tabskip"}\X${}\E{}$\5 +\T{291}\par +\Us225\ET226.\fi + +\M{1417} +\Y\B\4\D$\\{str\_292}$ \5 +\.{"spaceskip"}\par +\Y\B\4\X1417:\.{"spaceskip"}\X${}\E{}$\5 +\T{292}\par +\Us225\ET226.\fi + +\M{1418} +\Y\B\4\D$\\{str\_293}$ \5 +\.{"xspaceskip"}\par +\Y\B\4\X1418:\.{"xspaceskip"}\X${}\E{}$\5 +\T{293}\par +\Us225\ET226.\fi + +\M{1419} +\Y\B\4\D$\\{str\_294}$ \5 +\.{"parfillskip"}\par +\Y\B\4\X1419:\.{"parfillskip"}\X${}\E{}$\5 +\T{294}\par +\Us225\ET226.\fi + +\M{1420} +\Y\B\4\D$\\{str\_295}$ \5 +\.{"thinmuskip"}\par +\Y\B\4\X1420:\.{"thinmuskip"}\X${}\E{}$\5 +\T{295}\par +\Us225\ET226.\fi + +\M{1421} +\Y\B\4\D$\\{str\_296}$ \5 +\.{"medmuskip"}\par +\Y\B\4\X1421:\.{"medmuskip"}\X${}\E{}$\5 +\T{296}\par +\Us225\ET226.\fi + +\M{1422} +\Y\B\4\D$\\{str\_297}$ \5 +\.{"thickmuskip"}\par +\Y\B\4\X1422:\.{"thickmuskip"}\X${}\E{}$\5 +\T{297}\par +\Us225\ET226.\fi + +\M{1423} +\Y\B\4\D$\\{str\_298}$ \5 +\.{"skip"}\par +\Y\B\4\X1423:\.{"skip"}\X${}\E{}$\5 +\T{298}\par +\Us227, 229, 411, 412\ETs1009.\fi + +\M{1424} +\Y\B\4\D$\\{str\_299}$ \5 +\.{"muskip"}\par +\Y\B\4\X1424:\.{"muskip"}\X${}\E{}$\5 +\T{299}\par +\Us227, 229, 411\ETs412.\fi + +\M{1425} +\Y\B\4\D$\\{str\_300}$ \5 +\.{"pt"}\par +\Y\B\4\X1425:\.{"pt"}\X${}\E{}$\5 +\T{300}\par +\Us229, 453\ETs465.\fi + +\M{1426} +\Y\B\4\D$\\{str\_301}$ \5 +\.{"output"}\par +\Y\B\4\X1426:\.{"output"}\X${}\E{}$\5 +\T{301}\par +\Us230\ET231.\fi + +\M{1427} +\Y\B\4\D$\\{str\_302}$ \5 +\.{"everypar"}\par +\Y\B\4\X1427:\.{"everypar"}\X${}\E{}$\5 +\T{302}\par +\Us230\ET231.\fi + +\M{1428} +\Y\B\4\D$\\{str\_303}$ \5 +\.{"everymath"}\par +\Y\B\4\X1428:\.{"everymath"}\X${}\E{}$\5 +\T{303}\par +\Us230\ET231.\fi + +\M{1429} +\Y\B\4\D$\\{str\_304}$ \5 +\.{"everydisplay"}\par +\Y\B\4\X1429:\.{"everydisplay"}\X${}\E{}$\5 +\T{304}\par +\Us230\ET231.\fi + +\M{1430} +\Y\B\4\D$\\{str\_305}$ \5 +\.{"everyhbox"}\par +\Y\B\4\X1430:\.{"everyhbox"}\X${}\E{}$\5 +\T{305}\par +\Us230\ET231.\fi + +\M{1431} +\Y\B\4\D$\\{str\_306}$ \5 +\.{"everyvbox"}\par +\Y\B\4\X1431:\.{"everyvbox"}\X${}\E{}$\5 +\T{306}\par +\Us230\ET231.\fi + +\M{1432} +\Y\B\4\D$\\{str\_307}$ \5 +\.{"everyjob"}\par +\Y\B\4\X1432:\.{"everyjob"}\X${}\E{}$\5 +\T{307}\par +\Us230\ET231.\fi + +\M{1433} +\Y\B\4\D$\\{str\_308}$ \5 +\.{"everycr"}\par +\Y\B\4\X1433:\.{"everycr"}\X${}\E{}$\5 +\T{308}\par +\Us230\ET231.\fi + +\M{1434} +\Y\B\4\D$\\{str\_309}$ \5 +\.{"errhelp"}\par +\Y\B\4\X1434:\.{"errhelp"}\X${}\E{}$\5 +\T{309}\par +\Us230\ET231.\fi + +\M{1435} +\Y\B\4\D$\\{str\_310}$ \5 +\.{"toks"}\par +\Y\B\4\X1435:\.{"toks"}\X${}\E{}$\5 +\T{310}\par +\Us231, 233, 265\ETs266.\fi + +\M{1436} +\Y\B\4\D$\\{str\_311}$ \5 +\.{"parshape"}\par +\Y\B\4\X1436:\.{"parshape"}\X${}\E{}$\5 +\T{311}\par +\Us233, 265\ETs266.\fi + +\M{1437} +\Y\B\4\D$\\{str\_312}$ \5 +\.{"box"}\par +\Y\B\4\X1437:\.{"box"}\X${}\E{}$\5 +\T{312}\par +\Us233, 1015, 1028, 1071\ETs1072.\fi + +\M{1438} +\Y\B\4\D$\\{str\_313}$ \5 +\.{"textfont"}\par +\Y\B\4\X1438:\.{"textfont"}\X${}\E{}$\5 +\T{313}\par +\Us234, 699\ETs1230.\fi + +\M{1439} +\Y\B\4\D$\\{str\_314}$ \5 +\.{"scriptfont"}\par +\Y\B\4\X1439:\.{"scriptfont"}\X${}\E{}$\5 +\T{314}\par +\Us234, 699\ETs1230.\fi + +\M{1440} +\Y\B\4\D$\\{str\_315}$ \5 +\.{"scriptscriptfont"}\par +\Y\B\4\X1440:\.{"scriptscriptfont"}\X${}\E{}$\5 +\T{315}\par +\Us234, 699\ETs1230.\fi + +\M{1441} +\Y\B\4\D$\\{str\_316}$ \5 +\.{"catcode"}\par +\Y\B\4\X1441:\.{"catcode"}\X${}\E{}$\5 +\T{316}\par +\Us235, 1230\ETs1231.\fi + +\M{1442} +\Y\B\4\D$\\{str\_317}$ \5 +\.{"lccode"}\par +\Y\B\4\X1442:\.{"lccode"}\X${}\E{}$\5 +\T{317}\par +\Us235, 1230\ETs1231.\fi + +\M{1443} +\Y\B\4\D$\\{str\_318}$ \5 +\.{"uccode"}\par +\Y\B\4\X1443:\.{"uccode"}\X${}\E{}$\5 +\T{318}\par +\Us235, 1230\ETs1231.\fi + +\M{1444} +\Y\B\4\D$\\{str\_319}$ \5 +\.{"sfcode"}\par +\Y\B\4\X1444:\.{"sfcode"}\X${}\E{}$\5 +\T{319}\par +\Us235, 1230\ETs1231.\fi + +\M{1445} +\Y\B\4\D$\\{str\_320}$ \5 +\.{"mathcode"}\par +\Y\B\4\X1445:\.{"mathcode"}\X${}\E{}$\5 +\T{320}\par +\Us235, 1230\ETs1231.\fi + +\M{1446} +\Y\B\4\D$\\{str\_321}$ \5 +\.{"pretolerance"}\par +\Y\B\4\X1446:\.{"pretolerance"}\X${}\E{}$\5 +\T{321}\par +\Us237\ET238.\fi + +\M{1447} +\Y\B\4\D$\\{str\_322}$ \5 +\.{"tolerance"}\par +\Y\B\4\X1447:\.{"tolerance"}\X${}\E{}$\5 +\T{322}\par +\Us237\ET238.\fi + +\M{1448} +\Y\B\4\D$\\{str\_323}$ \5 +\.{"linepenalty"}\par +\Y\B\4\X1448:\.{"linepenalty"}\X${}\E{}$\5 +\T{323}\par +\Us237\ET238.\fi + +\M{1449} +\Y\B\4\D$\\{str\_324}$ \5 +\.{"hyphenpenalty"}\par +\Y\B\4\X1449:\.{"hyphenpenalty"}\X${}\E{}$\5 +\T{324}\par +\Us237\ET238.\fi + +\M{1450} +\Y\B\4\D$\\{str\_325}$ \5 +\.{"exhyphenpenalty"}\par +\Y\B\4\X1450:\.{"exhyphenpenalty"}\X${}\E{}$\5 +\T{325}\par +\Us237\ET238.\fi + +\M{1451} +\Y\B\4\D$\\{str\_326}$ \5 +\.{"clubpenalty"}\par +\Y\B\4\X1451:\.{"clubpenalty"}\X${}\E{}$\5 +\T{326}\par +\Us237\ET238.\fi + +\M{1452} +\Y\B\4\D$\\{str\_327}$ \5 +\.{"widowpenalty"}\par +\Y\B\4\X1452:\.{"widowpenalty"}\X${}\E{}$\5 +\T{327}\par +\Us237\ET238.\fi + +\M{1453} +\Y\B\4\D$\\{str\_328}$ \5 +\.{"displaywidowpenalty}\)\.{"}\par +\Y\B\4\X1453:\.{"displaywidowpenalty}\)\.{"}\X${}\E{}$\5 +\T{328}\par +\Us237\ET238.\fi + +\M{1454} +\Y\B\4\D$\\{str\_329}$ \5 +\.{"brokenpenalty"}\par +\Y\B\4\X1454:\.{"brokenpenalty"}\X${}\E{}$\5 +\T{329}\par +\Us237\ET238.\fi + +\M{1455} +\Y\B\4\D$\\{str\_330}$ \5 +\.{"binoppenalty"}\par +\Y\B\4\X1455:\.{"binoppenalty"}\X${}\E{}$\5 +\T{330}\par +\Us237\ET238.\fi + +\M{1456} +\Y\B\4\D$\\{str\_331}$ \5 +\.{"relpenalty"}\par +\Y\B\4\X1456:\.{"relpenalty"}\X${}\E{}$\5 +\T{331}\par +\Us237\ET238.\fi + +\M{1457} +\Y\B\4\D$\\{str\_332}$ \5 +\.{"predisplaypenalty"}\par +\Y\B\4\X1457:\.{"predisplaypenalty"}\X${}\E{}$\5 +\T{332}\par +\Us237\ET238.\fi + +\M{1458} +\Y\B\4\D$\\{str\_333}$ \5 +\.{"postdisplaypenalty"}\par +\Y\B\4\X1458:\.{"postdisplaypenalty"}\X${}\E{}$\5 +\T{333}\par +\Us237\ET238.\fi + +\M{1459} +\Y\B\4\D$\\{str\_334}$ \5 +\.{"interlinepenalty"}\par +\Y\B\4\X1459:\.{"interlinepenalty"}\X${}\E{}$\5 +\T{334}\par +\Us237\ET238.\fi + +\M{1460} +\Y\B\4\D$\\{str\_335}$ \5 +\.{"doublehyphendemerit}\)\.{s"}\par +\Y\B\4\X1460:\.{"doublehyphendemerit}\)\.{s"}\X${}\E{}$\5 +\T{335}\par +\Us237\ET238.\fi + +\M{1461} +\Y\B\4\D$\\{str\_336}$ \5 +\.{"finalhyphendemerits}\)\.{"}\par +\Y\B\4\X1461:\.{"finalhyphendemerits}\)\.{"}\X${}\E{}$\5 +\T{336}\par +\Us237\ET238.\fi + +\M{1462} +\Y\B\4\D$\\{str\_337}$ \5 +\.{"adjdemerits"}\par +\Y\B\4\X1462:\.{"adjdemerits"}\X${}\E{}$\5 +\T{337}\par +\Us237\ET238.\fi + +\M{1463} +\Y\B\4\D$\\{str\_338}$ \5 +\.{"mag"}\par +\Y\B\4\X1463:\.{"mag"}\X${}\E{}$\5 +\T{338}\par +\Us237\ET238.\fi + +\M{1464} +\Y\B\4\D$\\{str\_339}$ \5 +\.{"delimiterfactor"}\par +\Y\B\4\X1464:\.{"delimiterfactor"}\X${}\E{}$\5 +\T{339}\par +\Us237\ET238.\fi + +\M{1465} +\Y\B\4\D$\\{str\_340}$ \5 +\.{"looseness"}\par +\Y\B\4\X1465:\.{"looseness"}\X${}\E{}$\5 +\T{340}\par +\Us237\ET238.\fi + +\M{1466} +\Y\B\4\D$\\{str\_341}$ \5 +\.{"time"}\par +\Y\B\4\X1466:\.{"time"}\X${}\E{}$\5 +\T{341}\par +\Us237\ET238.\fi + +\M{1467} +\Y\B\4\D$\\{str\_342}$ \5 +\.{"day"}\par +\Y\B\4\X1467:\.{"day"}\X${}\E{}$\5 +\T{342}\par +\Us237\ET238.\fi + +\M{1468} +\Y\B\4\D$\\{str\_343}$ \5 +\.{"month"}\par +\Y\B\4\X1468:\.{"month"}\X${}\E{}$\5 +\T{343}\par +\Us237\ET238.\fi + +\M{1469} +\Y\B\4\D$\\{str\_344}$ \5 +\.{"year"}\par +\Y\B\4\X1469:\.{"year"}\X${}\E{}$\5 +\T{344}\par +\Us237\ET238.\fi + +\M{1470} +\Y\B\4\D$\\{str\_345}$ \5 +\.{"showboxbreadth"}\par +\Y\B\4\X1470:\.{"showboxbreadth"}\X${}\E{}$\5 +\T{345}\par +\Us237\ET238.\fi + +\M{1471} +\Y\B\4\D$\\{str\_346}$ \5 +\.{"showboxdepth"}\par +\Y\B\4\X1471:\.{"showboxdepth"}\X${}\E{}$\5 +\T{346}\par +\Us237\ET238.\fi + +\M{1472} +\Y\B\4\D$\\{str\_347}$ \5 +\.{"hbadness"}\par +\Y\B\4\X1472:\.{"hbadness"}\X${}\E{}$\5 +\T{347}\par +\Us237\ET238.\fi + +\M{1473} +\Y\B\4\D$\\{str\_348}$ \5 +\.{"vbadness"}\par +\Y\B\4\X1473:\.{"vbadness"}\X${}\E{}$\5 +\T{348}\par +\Us237\ET238.\fi + +\M{1474} +\Y\B\4\D$\\{str\_349}$ \5 +\.{"pausing"}\par +\Y\B\4\X1474:\.{"pausing"}\X${}\E{}$\5 +\T{349}\par +\Us237\ET238.\fi + +\M{1475} +\Y\B\4\D$\\{str\_350}$ \5 +\.{"tracingonline"}\par +\Y\B\4\X1475:\.{"tracingonline"}\X${}\E{}$\5 +\T{350}\par +\Us237\ET238.\fi + +\M{1476} +\Y\B\4\D$\\{str\_351}$ \5 +\.{"tracingmacros"}\par +\Y\B\4\X1476:\.{"tracingmacros"}\X${}\E{}$\5 +\T{351}\par +\Us237\ET238.\fi + +\M{1477} +\Y\B\4\D$\\{str\_352}$ \5 +\.{"tracingstats"}\par +\Y\B\4\X1477:\.{"tracingstats"}\X${}\E{}$\5 +\T{352}\par +\Us237\ET238.\fi + +\M{1478} +\Y\B\4\D$\\{str\_353}$ \5 +\.{"tracingparagraphs"}\par +\Y\B\4\X1478:\.{"tracingparagraphs"}\X${}\E{}$\5 +\T{353}\par +\Us237\ET238.\fi + +\M{1479} +\Y\B\4\D$\\{str\_354}$ \5 +\.{"tracingpages"}\par +\Y\B\4\X1479:\.{"tracingpages"}\X${}\E{}$\5 +\T{354}\par +\Us237\ET238.\fi + +\M{1480} +\Y\B\4\D$\\{str\_355}$ \5 +\.{"tracingoutput"}\par +\Y\B\4\X1480:\.{"tracingoutput"}\X${}\E{}$\5 +\T{355}\par +\Us237\ET238.\fi + +\M{1481} +\Y\B\4\D$\\{str\_356}$ \5 +\.{"tracinglostchars"}\par +\Y\B\4\X1481:\.{"tracinglostchars"}\X${}\E{}$\5 +\T{356}\par +\Us237\ET238.\fi + +\M{1482} +\Y\B\4\D$\\{str\_357}$ \5 +\.{"tracingcommands"}\par +\Y\B\4\X1482:\.{"tracingcommands"}\X${}\E{}$\5 +\T{357}\par +\Us237\ET238.\fi + +\M{1483} +\Y\B\4\D$\\{str\_358}$ \5 +\.{"tracingrestores"}\par +\Y\B\4\X1483:\.{"tracingrestores"}\X${}\E{}$\5 +\T{358}\par +\Us237\ET238.\fi + +\M{1484} +\Y\B\4\D$\\{str\_359}$ \5 +\.{"uchyph"}\par +\Y\B\4\X1484:\.{"uchyph"}\X${}\E{}$\5 +\T{359}\par +\Us237\ET238.\fi + +\M{1485} +\Y\B\4\D$\\{str\_360}$ \5 +\.{"outputpenalty"}\par +\Y\B\4\X1485:\.{"outputpenalty"}\X${}\E{}$\5 +\T{360}\par +\Us237\ET238.\fi + +\M{1486} +\Y\B\4\D$\\{str\_361}$ \5 +\.{"maxdeadcycles"}\par +\Y\B\4\X1486:\.{"maxdeadcycles"}\X${}\E{}$\5 +\T{361}\par +\Us237\ET238.\fi + +\M{1487} +\Y\B\4\D$\\{str\_362}$ \5 +\.{"hangafter"}\par +\Y\B\4\X1487:\.{"hangafter"}\X${}\E{}$\5 +\T{362}\par +\Us237\ET238.\fi + +\M{1488} +\Y\B\4\D$\\{str\_363}$ \5 +\.{"floatingpenalty"}\par +\Y\B\4\X1488:\.{"floatingpenalty"}\X${}\E{}$\5 +\T{363}\par +\Us237\ET238.\fi + +\M{1489} +\Y\B\4\D$\\{str\_364}$ \5 +\.{"globaldefs"}\par +\Y\B\4\X1489:\.{"globaldefs"}\X${}\E{}$\5 +\T{364}\par +\Us237\ET238.\fi + +\M{1490} +\Y\B\4\D$\\{str\_365}$ \5 +\.{"fam"}\par +\Y\B\4\X1490:\.{"fam"}\X${}\E{}$\5 +\T{365}\par +\Us237, 238\ETs691.\fi + +\M{1491} +\Y\B\4\D$\\{str\_366}$ \5 +\.{"escapechar"}\par +\Y\B\4\X1491:\.{"escapechar"}\X${}\E{}$\5 +\T{366}\par +\Us237\ET238.\fi + +\M{1492} +\Y\B\4\D$\\{str\_367}$ \5 +\.{"defaulthyphenchar"}\par +\Y\B\4\X1492:\.{"defaulthyphenchar"}\X${}\E{}$\5 +\T{367}\par +\Us237\ET238.\fi + +\M{1493} +\Y\B\4\D$\\{str\_368}$ \5 +\.{"defaultskewchar"}\par +\Y\B\4\X1493:\.{"defaultskewchar"}\X${}\E{}$\5 +\T{368}\par +\Us237\ET238.\fi + +\M{1494} +\Y\B\4\D$\\{str\_369}$ \5 +\.{"endlinechar"}\par +\Y\B\4\X1494:\.{"endlinechar"}\X${}\E{}$\5 +\T{369}\par +\Us237\ET238.\fi + +\M{1495} +\Y\B\4\D$\\{str\_370}$ \5 +\.{"newlinechar"}\par +\Y\B\4\X1495:\.{"newlinechar"}\X${}\E{}$\5 +\T{370}\par +\Us237\ET238.\fi + +\M{1496} +\Y\B\4\D$\\{str\_371}$ \5 +\.{"language"}\par +\Y\B\4\X1496:\.{"language"}\X${}\E{}$\5 +\T{371}\par +\Us237\ET238.\fi + +\M{1497} +\Y\B\4\D$\\{str\_372}$ \5 +\.{"lefthyphenmin"}\par +\Y\B\4\X1497:\.{"lefthyphenmin"}\X${}\E{}$\5 +\T{372}\par +\Us237\ET238.\fi + +\M{1498} +\Y\B\4\D$\\{str\_373}$ \5 +\.{"righthyphenmin"}\par +\Y\B\4\X1498:\.{"righthyphenmin"}\X${}\E{}$\5 +\T{373}\par +\Us237\ET238.\fi + +\M{1499} +\Y\B\4\D$\\{str\_374}$ \5 +\.{"holdinginserts"}\par +\Y\B\4\X1499:\.{"holdinginserts"}\X${}\E{}$\5 +\T{374}\par +\Us237\ET238.\fi + +\M{1500} +\Y\B\4\D$\\{str\_375}$ \5 +\.{"errorcontextlines"}\par +\Y\B\4\X1500:\.{"errorcontextlines"}\X${}\E{}$\5 +\T{375}\par +\Us237\ET238.\fi + +\M{1501} +\Y\B\4\D$\\{str\_376}$ \5 +\.{"count"}\par +\Y\B\4\X1501:\.{"count"}\X${}\E{}$\5 +\T{376}\par +\Us239, 242, 411\ETs412.\fi + +\M{1502} +\Y\B\4\D$\\{str\_377}$ \5 +\.{"delcode"}\par +\Y\B\4\X1502:\.{"delcode"}\X${}\E{}$\5 +\T{377}\par +\Us242, 1230\ETs1231.\fi + +\M{1503} +\Y\B\4\D$\\{str\_378}$ \5 +\.{"parindent"}\par +\Y\B\4\X1503:\.{"parindent"}\X${}\E{}$\5 +\T{378}\par +\Us247\ET248.\fi + +\M{1504} +\Y\B\4\D$\\{str\_379}$ \5 +\.{"mathsurround"}\par +\Y\B\4\X1504:\.{"mathsurround"}\X${}\E{}$\5 +\T{379}\par +\Us247\ET248.\fi + +\M{1505} +\Y\B\4\D$\\{str\_380}$ \5 +\.{"lineskiplimit"}\par +\Y\B\4\X1505:\.{"lineskiplimit"}\X${}\E{}$\5 +\T{380}\par +\Us247\ET248.\fi + +\M{1506} +\Y\B\4\D$\\{str\_381}$ \5 +\.{"hsize"}\par +\Y\B\4\X1506:\.{"hsize"}\X${}\E{}$\5 +\T{381}\par +\Us247\ET248.\fi + +\M{1507} +\Y\B\4\D$\\{str\_382}$ \5 +\.{"vsize"}\par +\Y\B\4\X1507:\.{"vsize"}\X${}\E{}$\5 +\T{382}\par +\Us247\ET248.\fi + +\M{1508} +\Y\B\4\D$\\{str\_383}$ \5 +\.{"maxdepth"}\par +\Y\B\4\X1508:\.{"maxdepth"}\X${}\E{}$\5 +\T{383}\par +\Us247\ET248.\fi + +\M{1509} +\Y\B\4\D$\\{str\_384}$ \5 +\.{"splitmaxdepth"}\par +\Y\B\4\X1509:\.{"splitmaxdepth"}\X${}\E{}$\5 +\T{384}\par +\Us247\ET248.\fi + +\M{1510} +\Y\B\4\D$\\{str\_385}$ \5 +\.{"boxmaxdepth"}\par +\Y\B\4\X1510:\.{"boxmaxdepth"}\X${}\E{}$\5 +\T{385}\par +\Us247\ET248.\fi + +\M{1511} +\Y\B\4\D$\\{str\_386}$ \5 +\.{"hfuzz"}\par +\Y\B\4\X1511:\.{"hfuzz"}\X${}\E{}$\5 +\T{386}\par +\Us247\ET248.\fi + +\M{1512} +\Y\B\4\D$\\{str\_387}$ \5 +\.{"vfuzz"}\par +\Y\B\4\X1512:\.{"vfuzz"}\X${}\E{}$\5 +\T{387}\par +\Us247\ET248.\fi + +\M{1513} +\Y\B\4\D$\\{str\_388}$ \5 +\.{"delimitershortfall"}\par +\Y\B\4\X1513:\.{"delimitershortfall"}\X${}\E{}$\5 +\T{388}\par +\Us247\ET248.\fi + +\M{1514} +\Y\B\4\D$\\{str\_389}$ \5 +\.{"nulldelimiterspace"}\par +\Y\B\4\X1514:\.{"nulldelimiterspace"}\X${}\E{}$\5 +\T{389}\par +\Us247\ET248.\fi + +\M{1515} +\Y\B\4\D$\\{str\_390}$ \5 +\.{"scriptspace"}\par +\Y\B\4\X1515:\.{"scriptspace"}\X${}\E{}$\5 +\T{390}\par +\Us247\ET248.\fi + +\M{1516} +\Y\B\4\D$\\{str\_391}$ \5 +\.{"predisplaysize"}\par +\Y\B\4\X1516:\.{"predisplaysize"}\X${}\E{}$\5 +\T{391}\par +\Us247\ET248.\fi + +\M{1517} +\Y\B\4\D$\\{str\_392}$ \5 +\.{"displaywidth"}\par +\Y\B\4\X1517:\.{"displaywidth"}\X${}\E{}$\5 +\T{392}\par +\Us247\ET248.\fi + +\M{1518} +\Y\B\4\D$\\{str\_393}$ \5 +\.{"displayindent"}\par +\Y\B\4\X1518:\.{"displayindent"}\X${}\E{}$\5 +\T{393}\par +\Us247\ET248.\fi + +\M{1519} +\Y\B\4\D$\\{str\_394}$ \5 +\.{"overfullrule"}\par +\Y\B\4\X1519:\.{"overfullrule"}\X${}\E{}$\5 +\T{394}\par +\Us247\ET248.\fi + +\M{1520} +\Y\B\4\D$\\{str\_395}$ \5 +\.{"hangindent"}\par +\Y\B\4\X1520:\.{"hangindent"}\X${}\E{}$\5 +\T{395}\par +\Us247\ET248.\fi + +\M{1521} +\Y\B\4\D$\\{str\_396}$ \5 +\.{"hoffset"}\par +\Y\B\4\X1521:\.{"hoffset"}\X${}\E{}$\5 +\T{396}\par +\Us247\ET248.\fi + +\M{1522} +\Y\B\4\D$\\{str\_397}$ \5 +\.{"voffset"}\par +\Y\B\4\X1522:\.{"voffset"}\X${}\E{}$\5 +\T{397}\par +\Us247\ET248.\fi + +\M{1523} +\Y\B\4\D$\\{str\_398}$ \5 +\.{"emergencystretch"}\par +\Y\B\4\X1523:\.{"emergencystretch"}\X${}\E{}$\5 +\T{398}\par +\Us247\ET248.\fi + +\M{1524} +\Y\B\4\D$\\{str\_399}$ \5 +\.{"dimen"}\par +\Y\B\4\X1524:\.{"dimen"}\X${}\E{}$\5 +\T{399}\par +\Us249, 251, 411\ETs412.\fi + +\M{1525} +\Y\B\4\D$\\{str\_400}$ \5 +\.{"notexpanded:"}\par +\Y\B\4\X1525:\.{"notexpanded:"}\X${}\E{}$\5 +\T{400}\par +\U258.\fi + +\M{1526} +\Y\B\4\D$\\{str\_401}$ \5 +\.{"csname"}\par +\Y\B\4\X1526:\.{"csname"}\X${}\E{}$\5 +\T{401}\par +\Us262, 263, 265\ETs266.\fi + +\M{1527} +\Y\B\4\D$\\{str\_402}$ \5 +\.{"endcsname"}\par +\Y\B\4\X1527:\.{"endcsname"}\X${}\E{}$\5 +\T{402}\par +\Us262, 263, 265, 266, 373\ETs1135.\fi + +\M{1528} +\Y\B\4\D$\\{str\_403}$ \5 +\.{"IMPOSSIBLE."}\par +\Y\B\4\X1528:\.{"IMPOSSIBLE."}\X${}\E{}$\5 +\T{403}\par +\U262.\fi + +\M{1529} +\Y\B\4\D$\\{str\_404}$ \5 +\.{"NONEXISTENT."}\par +\Y\B\4\X1529:\.{"NONEXISTENT."}\X${}\E{}$\5 +\T{404}\par +\U262.\fi + +\M{1530} +\Y\B\4\D$\\{str\_405}$ \5 +\.{"accent"}\par +\Y\B\4\X1530:\.{"accent"}\X${}\E{}$\5 +\T{405}\par +\Us265, 266\ETs696.\fi + +\M{1531} +\Y\B\4\D$\\{str\_406}$ \5 +\.{"advance"}\par +\Y\B\4\X1531:\.{"advance"}\X${}\E{}$\5 +\T{406}\par +\Us265\ET266.\fi + +\M{1532} +\Y\B\4\D$\\{str\_407}$ \5 +\.{"afterassignment"}\par +\Y\B\4\X1532:\.{"afterassignment"}\X${}\E{}$\5 +\T{407}\par +\Us265\ET266.\fi + +\M{1533} +\Y\B\4\D$\\{str\_408}$ \5 +\.{"aftergroup"}\par +\Y\B\4\X1533:\.{"aftergroup"}\X${}\E{}$\5 +\T{408}\par +\Us265\ET266.\fi + +\M{1534} +\Y\B\4\D$\\{str\_409}$ \5 +\.{"begingroup"}\par +\Y\B\4\X1534:\.{"begingroup"}\X${}\E{}$\5 +\T{409}\par +\Us265\ET266.\fi + +\M{1535} +\Y\B\4\D$\\{str\_410}$ \5 +\.{"char"}\par +\Y\B\4\X1535:\.{"char"}\X${}\E{}$\5 +\T{410}\par +\Us265, 266\ETs1223.\fi + +\M{1536} +\Y\B\4\D$\\{str\_411}$ \5 +\.{"delimiter"}\par +\Y\B\4\X1536:\.{"delimiter"}\X${}\E{}$\5 +\T{411}\par +\Us265\ET266.\fi + +\M{1537} +\Y\B\4\D$\\{str\_412}$ \5 +\.{"divide"}\par +\Y\B\4\X1537:\.{"divide"}\X${}\E{}$\5 +\T{412}\par +\Us265\ET266.\fi + +\M{1538} +\Y\B\4\D$\\{str\_413}$ \5 +\.{"endgroup"}\par +\Y\B\4\X1538:\.{"endgroup"}\X${}\E{}$\5 +\T{413}\par +\Us265, 266, 1065\ETs1069.\fi + +\M{1539} +\Y\B\4\D$\\{str\_414}$ \5 +\.{"expandafter"}\par +\Y\B\4\X1539:\.{"expandafter"}\X${}\E{}$\5 +\T{414}\par +\Us265\ET266.\fi + +\M{1540} +\Y\B\4\D$\\{str\_415}$ \5 +\.{"font"}\par +\Y\B\4\X1540:\.{"font"}\X${}\E{}$\5 +\T{415}\par +\Us265\ET266.\fi + +\M{1541} +\Y\B\4\D$\\{str\_416}$ \5 +\.{"fontdimen"}\par +\Y\B\4\X1541:\.{"fontdimen"}\X${}\E{}$\5 +\T{416}\par +\Us265\ET266.\fi + +\M{1542} +\Y\B\4\D$\\{str\_417}$ \5 +\.{"halign"}\par +\Y\B\4\X1542:\.{"halign"}\X${}\E{}$\5 +\T{417}\par +\Us265, 266\ETs776.\fi + +\M{1543} +\Y\B\4\D$\\{str\_418}$ \5 +\.{"hrule"}\par +\Y\B\4\X1543:\.{"hrule"}\X${}\E{}$\5 +\T{418}\par +\Us265, 266\ETs1095.\fi + +\M{1544} +\Y\B\4\D$\\{str\_419}$ \5 +\.{"ignorespaces"}\par +\Y\B\4\X1544:\.{"ignorespaces"}\X${}\E{}$\5 +\T{419}\par +\Us265\ET266.\fi + +\M{1545} +\Y\B\4\D$\\{str\_420}$ \5 +\.{"mathaccent"}\par +\Y\B\4\X1545:\.{"mathaccent"}\X${}\E{}$\5 +\T{420}\par +\Us265, 266\ETs1166.\fi + +\M{1546} +\Y\B\4\D$\\{str\_421}$ \5 +\.{"mathchar"}\par +\Y\B\4\X1546:\.{"mathchar"}\X${}\E{}$\5 +\T{421}\par +\Us265, 266\ETs1223.\fi + +\M{1547} +\Y\B\4\D$\\{str\_422}$ \5 +\.{"mathchoice"}\par +\Y\B\4\X1547:\.{"mathchoice"}\X${}\E{}$\5 +\T{422}\par +\Us265, 266\ETs695.\fi + +\M{1548} +\Y\B\4\D$\\{str\_423}$ \5 +\.{"multiply"}\par +\Y\B\4\X1548:\.{"multiply"}\X${}\E{}$\5 +\T{423}\par +\Us265\ET266.\fi + +\M{1549} +\Y\B\4\D$\\{str\_424}$ \5 +\.{"noalign"}\par +\Y\B\4\X1549:\.{"noalign"}\X${}\E{}$\5 +\T{424}\par +\Us265, 266\ETs1129.\fi + +\M{1550} +\Y\B\4\D$\\{str\_425}$ \5 +\.{"noboundary"}\par +\Y\B\4\X1550:\.{"noboundary"}\X${}\E{}$\5 +\T{425}\par +\Us265\ET266.\fi + +\M{1551} +\Y\B\4\D$\\{str\_426}$ \5 +\.{"noexpand"}\par +\Y\B\4\X1551:\.{"noexpand"}\X${}\E{}$\5 +\T{426}\par +\Us265\ET266.\fi + +\M{1552} +\Y\B\4\D$\\{str\_427}$ \5 +\.{"omit"}\par +\Y\B\4\X1552:\.{"omit"}\X${}\E{}$\5 +\T{427}\par +\Us265, 266\ETs1129.\fi + +\M{1553} +\Y\B\4\D$\\{str\_428}$ \5 +\.{"penalty"}\par +\Y\B\4\X1553:\.{"penalty"}\X${}\E{}$\5 +\T{428}\par +\Us265, 266\ETs856.\fi + +\M{1554} +\Y\B\4\D$\\{str\_429}$ \5 +\.{"prevgraf"}\par +\Y\B\4\X1554:\.{"prevgraf"}\X${}\E{}$\5 +\T{429}\par +\Us265, 266\ETs1244.\fi + +\M{1555} +\Y\B\4\D$\\{str\_430}$ \5 +\.{"radical"}\par +\Y\B\4\X1555:\.{"radical"}\X${}\E{}$\5 +\T{430}\par +\Q267. +\Us265, 266\ETs696.\fi + +\M{1556} +\Y\B\4\D$\\{str\_431}$ \5 +\.{"read"}\par +\Y\B\4\X1556:\.{"read"}\X${}\E{}$\5 +\T{431}\par +\Us265, 266\ETs486.\fi + +\M{1557} +\Y\B\4\D$\\{str\_432}$ \5 +\.{"relax"}\par +\Y\B\4\X1557:\.{"relax"}\X${}\E{}$\5 +\T{432}\par +\Us265\ET266.\fi + +\M{1558} +\Y\B\4\D$\\{str\_433}$ \5 +\.{"setbox"}\par +\Y\B\4\X1558:\.{"setbox"}\X${}\E{}$\5 +\T{433}\par +\Us265, 266\ETs1241.\fi + +\M{1559} +\Y\B\4\D$\\{str\_434}$ \5 +\.{"the"}\par +\Y\B\4\X1559:\.{"the"}\X${}\E{}$\5 +\T{434}\par +\Us265, 266\ETs428.\fi + +\M{1560} +\Y\B\4\D$\\{str\_435}$ \5 +\.{"valign"}\par +\Y\B\4\X1560:\.{"valign"}\X${}\E{}$\5 +\T{435}\par +\Us265\ET266.\fi + +\M{1561} +\Y\B\4\D$\\{str\_436}$ \5 +\.{"vcenter"}\par +\Y\B\4\X1561:\.{"vcenter"}\X${}\E{}$\5 +\T{436}\par +\Us265, 266, 696\ETs736.\fi + +\M{1562} +\Y\B\4\D$\\{str\_437}$ \5 +\.{"vrule"}\par +\Y\B\4\X1562:\.{"vrule"}\X${}\E{}$\5 +\T{437}\par +\Us265\ET266.\fi + +\M{1563} +\Y\B\4\D$\\{str\_438}$ \5 +\.{"curlevel"}\par +\Y\B\4\X1563:\.{"curlevel"}\X${}\E{}$\5 +\T{438}\par +\U281.\fi + +\M{1564} +\Y\B\4\D$\\{str\_439}$ \5 +\.{"retaining"}\par +\Y\B\4\X1564:\.{"retaining"}\X${}\E{}$\5 +\T{439}\par +\U283.\fi + +\M{1565} +\Y\B\4\D$\\{str\_440}$ \5 +\.{"restoring"}\par +\Y\B\4\X1565:\.{"restoring"}\X${}\E{}$\5 +\T{440}\par +\U283.\fi + +\M{1566} +\Y\B\4\D$\\{str\_441}$ \5 +\.{"ETC."}\par +\Y\B\4\X1566:\.{"ETC."}\X${}\E{}$\5 +\T{441}\par +\U292.\fi + +\M{1567} +\Y\B\4\D$\\{str\_442}$ \5 +\.{"BAD."}\par +\Y\B\4\X1567:\.{"BAD."}\X${}\E{}$\5 +\T{442}\par +\Us293\ET294.\fi + +\M{1568} +\Y\B\4\D$\\{str\_443}$ \5 +\.{"write"}\par +\Y\B\4\X1568:\.{"write"}\X${}\E{}$\5 +\T{443}\par +\Us323, 1344, 1346\ETs1356.\fi + +\M{1569} +\Y\B\4\D$\\{str\_444}$ \5 +\.{"par"}\par +\Y\B\4\X1569:\.{"par"}\X${}\E{}$\5 +\T{444}\par +\Us334, 335\ETs856.\fi + +\M{1570} +\Y\B\4\D$\\{str\_445}$ \5 +\.{"input"}\par +\Y\B\4\X1570:\.{"input"}\X${}\E{}$\5 +\T{445}\par +\Us376\ET377.\fi + +\M{1571} +\Y\B\4\D$\\{str\_446}$ \5 +\.{"endinput"}\par +\Y\B\4\X1571:\.{"endinput"}\X${}\E{}$\5 +\T{446}\par +\Us376\ET377.\fi + +\M{1572} +\Y\B\4\D$\\{str\_447}$ \5 +\.{"topmark"}\par +\Y\B\4\X1572:\.{"topmark"}\X${}\E{}$\5 +\T{447}\par +\Us384\ET385.\fi + +\M{1573} +\Y\B\4\D$\\{str\_448}$ \5 +\.{"firstmark"}\par +\Y\B\4\X1573:\.{"firstmark"}\X${}\E{}$\5 +\T{448}\par +\Us384\ET385.\fi + +\M{1574} +\Y\B\4\D$\\{str\_449}$ \5 +\.{"botmark"}\par +\Y\B\4\X1574:\.{"botmark"}\X${}\E{}$\5 +\T{449}\par +\Us384\ET385.\fi + +\M{1575} +\Y\B\4\D$\\{str\_450}$ \5 +\.{"splitfirstmark"}\par +\Y\B\4\X1575:\.{"splitfirstmark"}\X${}\E{}$\5 +\T{450}\par +\Us384\ET385.\fi + +\M{1576} +\Y\B\4\D$\\{str\_451}$ \5 +\.{"splitbotmark"}\par +\Y\B\4\X1576:\.{"splitbotmark"}\X${}\E{}$\5 +\T{451}\par +\Us384\ET385.\fi + +\M{1577} +\Y\B\4\D$\\{str\_452}$ \5 +\.{"spacefactor"}\par +\Y\B\4\X1577:\.{"spacefactor"}\X${}\E{}$\5 +\T{452}\par +\Us416\ET417.\fi + +\M{1578} +\Y\B\4\D$\\{str\_453}$ \5 +\.{"prevdepth"}\par +\Y\B\4\X1578:\.{"prevdepth"}\X${}\E{}$\5 +\T{453}\par +\Us416\ET417.\fi + +\M{1579} +\Y\B\4\D$\\{str\_454}$ \5 +\.{"deadcycles"}\par +\Y\B\4\X1579:\.{"deadcycles"}\X${}\E{}$\5 +\T{454}\par +\Us416\ET417.\fi + +\M{1580} +\Y\B\4\D$\\{str\_455}$ \5 +\.{"insertpenalties"}\par +\Y\B\4\X1580:\.{"insertpenalties"}\X${}\E{}$\5 +\T{455}\par +\Us416\ET417.\fi + +\M{1581} +\Y\B\4\D$\\{str\_456}$ \5 +\.{"wd"}\par +\Y\B\4\X1581:\.{"wd"}\X${}\E{}$\5 +\T{456}\par +\Us416\ET417.\fi + +\M{1582} +\Y\B\4\D$\\{str\_457}$ \5 +\.{"ht"}\par +\Y\B\4\X1582:\.{"ht"}\X${}\E{}$\5 +\T{457}\par +\Us416\ET417.\fi + +\M{1583} +\Y\B\4\D$\\{str\_458}$ \5 +\.{"dp"}\par +\Y\B\4\X1583:\.{"dp"}\X${}\E{}$\5 +\T{458}\par +\Us416\ET417.\fi + +\M{1584} +\Y\B\4\D$\\{str\_459}$ \5 +\.{"lastpenalty"}\par +\Y\B\4\X1584:\.{"lastpenalty"}\X${}\E{}$\5 +\T{459}\par +\Us416\ET417.\fi + +\M{1585} +\Y\B\4\D$\\{str\_460}$ \5 +\.{"lastkern"}\par +\Y\B\4\X1585:\.{"lastkern"}\X${}\E{}$\5 +\T{460}\par +\Us416\ET417.\fi + +\M{1586} +\Y\B\4\D$\\{str\_461}$ \5 +\.{"lastskip"}\par +\Y\B\4\X1586:\.{"lastskip"}\X${}\E{}$\5 +\T{461}\par +\Us416\ET417.\fi + +\M{1587} +\Y\B\4\D$\\{str\_462}$ \5 +\.{"inputlineno"}\par +\Y\B\4\X1587:\.{"inputlineno"}\X${}\E{}$\5 +\T{462}\par +\Us416\ET417.\fi + +\M{1588} +\Y\B\4\D$\\{str\_463}$ \5 +\.{"badness"}\par +\Y\B\4\X1588:\.{"badness"}\X${}\E{}$\5 +\T{463}\par +\Us416\ET417.\fi + +\M{1589} +\Y\B\4\D$\\{str\_464}$ \5 +\.{"true"}\par +\Y\B\4\X1589:\.{"true"}\X${}\E{}$\5 +\T{464}\par +\U453.\fi + +\M{1590} +\Y\B\4\D$\\{str\_465}$ \5 +\.{"em"}\par +\Y\B\4\X1590:\.{"em"}\X${}\E{}$\5 +\T{465}\par +\U455.\fi + +\M{1591} +\Y\B\4\D$\\{str\_466}$ \5 +\.{"ex"}\par +\Y\B\4\X1591:\.{"ex"}\X${}\E{}$\5 +\T{466}\par +\U455.\fi + +\M{1592} +\Y\B\4\D$\\{str\_467}$ \5 +\.{"in"}\par +\Y\B\4\X1592:\.{"in"}\X${}\E{}$\5 +\T{467}\par +\U458.\fi + +\M{1593} +\Y\B\4\D$\\{str\_468}$ \5 +\.{"pc"}\par +\Y\B\4\X1593:\.{"pc"}\X${}\E{}$\5 +\T{468}\par +\U458.\fi + +\M{1594} +\Y\B\4\D$\\{str\_469}$ \5 +\.{"cm"}\par +\Y\B\4\X1594:\.{"cm"}\X${}\E{}$\5 +\T{469}\par +\U458.\fi + +\M{1595} +\Y\B\4\D$\\{str\_470}$ \5 +\.{"mm"}\par +\Y\B\4\X1595:\.{"mm"}\X${}\E{}$\5 +\T{470}\par +\U458.\fi + +\M{1596} +\Y\B\4\D$\\{str\_471}$ \5 +\.{"bp"}\par +\Y\B\4\X1596:\.{"bp"}\X${}\E{}$\5 +\T{471}\par +\U458.\fi + +\M{1597} +\Y\B\4\D$\\{str\_472}$ \5 +\.{"dd"}\par +\Y\B\4\X1597:\.{"dd"}\X${}\E{}$\5 +\T{472}\par +\U458.\fi + +\M{1598} +\Y\B\4\D$\\{str\_473}$ \5 +\.{"cc"}\par +\Y\B\4\X1598:\.{"cc"}\X${}\E{}$\5 +\T{473}\par +\U458.\fi + +\M{1599} +\Y\B\4\D$\\{str\_474}$ \5 +\.{"sp"}\par +\Y\B\4\X1599:\.{"sp"}\X${}\E{}$\5 +\T{474}\par +\U458.\fi + +\M{1600} +\Y\B\4\D$\\{str\_475}$ \5 +\.{"plus"}\par +\Y\B\4\X1600:\.{"plus"}\X${}\E{}$\5 +\T{475}\par +\U462.\fi + +\M{1601} +\Y\B\4\D$\\{str\_476}$ \5 +\.{"minus"}\par +\Y\B\4\X1601:\.{"minus"}\X${}\E{}$\5 +\T{476}\par +\U462.\fi + +\M{1602} +\Y\B\4\D$\\{str\_477}$ \5 +\.{"width"}\par +\Y\B\4\X1602:\.{"width"}\X${}\E{}$\5 +\T{477}\par +\U463.\fi + +\M{1603} +\Y\B\4\D$\\{str\_478}$ \5 +\.{"height"}\par +\Y\B\4\X1603:\.{"height"}\X${}\E{}$\5 +\T{478}\par +\U463.\fi + +\M{1604} +\Y\B\4\D$\\{str\_479}$ \5 +\.{"depth"}\par +\Y\B\4\X1604:\.{"depth"}\X${}\E{}$\5 +\T{479}\par +\U463.\fi + +\M{1605} +\Y\B\4\D$\\{str\_480}$ \5 +\.{"number"}\par +\Y\B\4\X1605:\.{"number"}\X${}\E{}$\5 +\T{480}\par +\Us468\ET469.\fi + +\M{1606} +\Y\B\4\D$\\{str\_481}$ \5 +\.{"romannumeral"}\par +\Y\B\4\X1606:\.{"romannumeral"}\X${}\E{}$\5 +\T{481}\par +\Us468\ET469.\fi + +\M{1607} +\Y\B\4\D$\\{str\_482}$ \5 +\.{"string"}\par +\Y\B\4\X1607:\.{"string"}\X${}\E{}$\5 +\T{482}\par +\Us468\ET469.\fi + +\M{1608} +\Y\B\4\D$\\{str\_483}$ \5 +\.{"meaning"}\par +\Y\B\4\X1608:\.{"meaning"}\X${}\E{}$\5 +\T{483}\par +\Us468\ET469.\fi + +\M{1609} +\Y\B\4\D$\\{str\_484}$ \5 +\.{"fontname"}\par +\Y\B\4\X1609:\.{"fontname"}\X${}\E{}$\5 +\T{484}\par +\Us468\ET469.\fi + +\M{1610} +\Y\B\4\D$\\{str\_485}$ \5 +\.{"jobname"}\par +\Y\B\4\X1610:\.{"jobname"}\X${}\E{}$\5 +\T{485}\par +\Us468\ET469.\fi + +\M{1611} +\Y\B\4\D$\\{str\_486}$ \5 +\.{"if"}\par +\Y\B\4\X1611:\.{"if"}\X${}\E{}$\5 +\T{486}\par +\Us487, 488\ETs497.\fi + +\M{1612} +\Y\B\4\D$\\{str\_487}$ \5 +\.{"ifcat"}\par +\Y\B\4\X1612:\.{"ifcat"}\X${}\E{}$\5 +\T{487}\par +\Us487\ET488.\fi + +\M{1613} +\Y\B\4\D$\\{str\_488}$ \5 +\.{"ifnum"}\par +\Y\B\4\X1613:\.{"ifnum"}\X${}\E{}$\5 +\T{488}\par +\Us487\ET488.\fi + +\M{1614} +\Y\B\4\D$\\{str\_489}$ \5 +\.{"ifdim"}\par +\Y\B\4\X1614:\.{"ifdim"}\X${}\E{}$\5 +\T{489}\par +\Us487\ET488.\fi + +\M{1615} +\Y\B\4\D$\\{str\_490}$ \5 +\.{"ifodd"}\par +\Y\B\4\X1615:\.{"ifodd"}\X${}\E{}$\5 +\T{490}\par +\Us487\ET488.\fi + +\M{1616} +\Y\B\4\D$\\{str\_491}$ \5 +\.{"ifvmode"}\par +\Y\B\4\X1616:\.{"ifvmode"}\X${}\E{}$\5 +\T{491}\par +\Us487\ET488.\fi + +\M{1617} +\Y\B\4\D$\\{str\_492}$ \5 +\.{"ifhmode"}\par +\Y\B\4\X1617:\.{"ifhmode"}\X${}\E{}$\5 +\T{492}\par +\Us487\ET488.\fi + +\M{1618} +\Y\B\4\D$\\{str\_493}$ \5 +\.{"ifmmode"}\par +\Y\B\4\X1618:\.{"ifmmode"}\X${}\E{}$\5 +\T{493}\par +\Us487\ET488.\fi + +\M{1619} +\Y\B\4\D$\\{str\_494}$ \5 +\.{"ifinner"}\par +\Y\B\4\X1619:\.{"ifinner"}\X${}\E{}$\5 +\T{494}\par +\Us487\ET488.\fi + +\M{1620} +\Y\B\4\D$\\{str\_495}$ \5 +\.{"ifvoid"}\par +\Y\B\4\X1620:\.{"ifvoid"}\X${}\E{}$\5 +\T{495}\par +\Us487\ET488.\fi + +\M{1621} +\Y\B\4\D$\\{str\_496}$ \5 +\.{"ifhbox"}\par +\Y\B\4\X1621:\.{"ifhbox"}\X${}\E{}$\5 +\T{496}\par +\Us487\ET488.\fi + +\M{1622} +\Y\B\4\D$\\{str\_497}$ \5 +\.{"ifvbox"}\par +\Y\B\4\X1622:\.{"ifvbox"}\X${}\E{}$\5 +\T{497}\par +\Us487\ET488.\fi + +\M{1623} +\Y\B\4\D$\\{str\_498}$ \5 +\.{"ifx"}\par +\Y\B\4\X1623:\.{"ifx"}\X${}\E{}$\5 +\T{498}\par +\Us487\ET488.\fi + +\M{1624} +\Y\B\4\D$\\{str\_499}$ \5 +\.{"ifeof"}\par +\Y\B\4\X1624:\.{"ifeof"}\X${}\E{}$\5 +\T{499}\par +\Us487\ET488.\fi + +\M{1625} +\Y\B\4\D$\\{str\_500}$ \5 +\.{"iftrue"}\par +\Y\B\4\X1625:\.{"iftrue"}\X${}\E{}$\5 +\T{500}\par +\Us487\ET488.\fi + +\M{1626} +\Y\B\4\D$\\{str\_501}$ \5 +\.{"iffalse"}\par +\Y\B\4\X1626:\.{"iffalse"}\X${}\E{}$\5 +\T{501}\par +\Us487\ET488.\fi + +\M{1627} +\Y\B\4\D$\\{str\_502}$ \5 +\.{"ifcase"}\par +\Y\B\4\X1627:\.{"ifcase"}\X${}\E{}$\5 +\T{502}\par +\Us487\ET488.\fi + +\M{1628} +\Y\B\4\D$\\{str\_503}$ \5 +\.{"fi"}\par +\Y\B\4\X1628:\.{"fi"}\X${}\E{}$\5 +\T{503}\par +\Us491\ET492.\fi + +\M{1629} +\Y\B\4\D$\\{str\_504}$ \5 +\.{"or"}\par +\Y\B\4\X1629:\.{"or"}\X${}\E{}$\5 +\T{504}\par +\Us491, 492\ETs500.\fi + +\M{1630} +\Y\B\4\D$\\{str\_505}$ \5 +\.{"else"}\par +\Y\B\4\X1630:\.{"else"}\X${}\E{}$\5 +\T{505}\par +\Us491\ET492.\fi + +\M{1631} +\Y\B\4\D$\\{str\_506}$ \5 +\.{"TeXinputs/"}\par +\B\4\D$\\{TEX\_area}$ \5 +\T{506}\par +\fi + +\M{1632} +\Y\B\4\D$\\{str\_507}$ \5 +\.{"TeXfonts/"}\par +\B\4\D$\\{TEX\_font\_area}$ \5 +\T{507}\par +\fi + +\M{1633} +\Y\B\4\D$\\{str\_508}$ \5 +\.{".fmt"}\par +\B\4\D$\\{format\_extension}$ \5 +\T{508}\par +\fi + +\M{1634} +\Y\B\4\D$\\{str\_509}$ \5 +\.{".log"}\par +\Y\B\4\X1634:\.{".log"}\X${}\E{}$\5 +\T{509}\par +\Q528. +\Us534\ET535.\fi + +\M{1635} +\Y\B\4\D$\\{str\_510}$ \5 +\.{".dvi"}\par +\Y\B\4\X1635:\.{".dvi"}\X${}\E{}$\5 +\T{510}\par +\Q528. +\U531.\fi + +\M{1636} +\Y\B\4\D$\\{str\_511}$ \5 +\.{"input\ file\ name"}\par +\Y\B\4\X1636:\.{"input\ file\ name"}\X${}\E{}$\5 +\T{511}\par +\fi + +\M{1637} +\Y\B\4\D$\\{str\_512}$ \5 +\.{".tex"}\par +\Y\B\4\X1637:\.{".tex"}\X${}\E{}$\5 +\T{512}\par +\Us529, 537, 1275\ETs1374.\fi + +\M{1638} +\Y\B\4\D$\\{str\_513}$ \5 +\.{"texput"}\par +\Y\B\4\X1638:\.{"texput"}\X${}\E{}$\5 +\T{513}\par +\U534.\fi + +\M{1639} +\Y\B\4\D$\\{str\_514}$ \5 +\.{"nullfont"}\par +\Y\B\4\X1639:\.{"nullfont"}\X${}\E{}$\5 +\T{514}\par +\Us552\ET553.\fi + +\M{1640} +\Y\B\4\D$\\{str\_515}$ \5 +\.{".tfm"}\par +\Y\B\4\X1640:\.{".tfm"}\X${}\E{}$\5 +\T{515}\par +\U563.\fi + +\M{1641} +\Y\B\4\D$\\{str\_516}$ \5 +\.{"vlistout"}\par +\Y\B\4\X1641:\.{"vlistout"}\X${}\E{}$\5 +\T{516}\par +\U630.\fi + +\M{1642} +\Y\B\4\D$\\{str\_517}$ \5 +\.{"to"}\par +\Y\B\4\X1642:\.{"to"}\X${}\E{}$\5 +\T{517}\par +\Us645, 1082\ETs1225.\fi + +\M{1643} +\Y\B\4\D$\\{str\_518}$ \5 +\.{"spread"}\par +\Y\B\4\X1643:\.{"spread"}\X${}\E{}$\5 +\T{518}\par +\U645.\fi + +\M{1644} +\Y\B\4\D$\\{str\_519}$ \5 +\.{"vpack"}\par +\Y\B\4\X1644:\.{"vpack"}\X${}\E{}$\5 +\T{519}\par +\U669.\fi + +\M{1645} +\Y\B\4\D$\\{str\_520}$ \5 +\.{"displaystyle"}\par +\Y\B\4\X1645:\.{"displaystyle"}\X${}\E{}$\5 +\T{520}\par +\Us694\ET1169.\fi + +\M{1646} +\Y\B\4\D$\\{str\_521}$ \5 +\.{"textstyle"}\par +\Y\B\4\X1646:\.{"textstyle"}\X${}\E{}$\5 +\T{521}\par +\Us694\ET1169.\fi + +\M{1647} +\Y\B\4\D$\\{str\_522}$ \5 +\.{"scriptstyle"}\par +\Y\B\4\X1647:\.{"scriptstyle"}\X${}\E{}$\5 +\T{522}\par +\Us694\ET1169.\fi + +\M{1648} +\Y\B\4\D$\\{str\_523}$ \5 +\.{"scriptscriptstyle"}\par +\Y\B\4\X1648:\.{"scriptscriptstyle"}\X${}\E{}$\5 +\T{523}\par +\Us694\ET1169.\fi + +\M{1649} +\Y\B\4\D$\\{str\_524}$ \5 +\.{"mathord"}\par +\Y\B\4\X1649:\.{"mathord"}\X${}\E{}$\5 +\T{524}\par +\Us696, 1156\ETs1157.\fi + +\M{1650} +\Y\B\4\D$\\{str\_525}$ \5 +\.{"mathop"}\par +\Y\B\4\X1650:\.{"mathop"}\X${}\E{}$\5 +\T{525}\par +\Us696, 1156\ETs1157.\fi + +\M{1651} +\Y\B\4\D$\\{str\_526}$ \5 +\.{"mathbin"}\par +\Y\B\4\X1651:\.{"mathbin"}\X${}\E{}$\5 +\T{526}\par +\Us696, 1156\ETs1157.\fi + +\M{1652} +\Y\B\4\D$\\{str\_527}$ \5 +\.{"mathrel"}\par +\Y\B\4\X1652:\.{"mathrel"}\X${}\E{}$\5 +\T{527}\par +\Us696, 1156\ETs1157.\fi + +\M{1653} +\Y\B\4\D$\\{str\_528}$ \5 +\.{"mathopen"}\par +\Y\B\4\X1653:\.{"mathopen"}\X${}\E{}$\5 +\T{528}\par +\Us696, 1156\ETs1157.\fi + +\M{1654} +\Y\B\4\D$\\{str\_529}$ \5 +\.{"mathclose"}\par +\Y\B\4\X1654:\.{"mathclose"}\X${}\E{}$\5 +\T{529}\par +\Us696, 1156\ETs1157.\fi + +\M{1655} +\Y\B\4\D$\\{str\_530}$ \5 +\.{"mathpunct"}\par +\Y\B\4\X1655:\.{"mathpunct"}\X${}\E{}$\5 +\T{530}\par +\Us696, 1156\ETs1157.\fi + +\M{1656} +\Y\B\4\D$\\{str\_531}$ \5 +\.{"mathinner"}\par +\Y\B\4\X1656:\.{"mathinner"}\X${}\E{}$\5 +\T{531}\par +\Us696, 1156\ETs1157.\fi + +\M{1657} +\Y\B\4\D$\\{str\_532}$ \5 +\.{"overline"}\par +\Y\B\4\X1657:\.{"overline"}\X${}\E{}$\5 +\T{532}\par +\Us696, 1156\ETs1157.\fi + +\M{1658} +\Y\B\4\D$\\{str\_533}$ \5 +\.{"underline"}\par +\Y\B\4\X1658:\.{"underline"}\X${}\E{}$\5 +\T{533}\par +\Us696, 1156\ETs1157.\fi + +\M{1659} +\Y\B\4\D$\\{str\_534}$ \5 +\.{"left"}\par +\Y\B\4\X1659:\.{"left"}\X${}\E{}$\5 +\T{534}\par +\Us696, 1188\ETs1189.\fi + +\M{1660} +\Y\B\4\D$\\{str\_535}$ \5 +\.{"right"}\par +\Y\B\4\X1660:\.{"right"}\X${}\E{}$\5 +\T{535}\par +\Us696, 1069, 1185, 1188, 1189\ETs1192.\fi + +\M{1661} +\Y\B\4\D$\\{str\_536}$ \5 +\.{"limits"}\par +\Y\B\4\X1661:\.{"limits"}\X${}\E{}$\5 +\T{536}\par +\Us696, 1156\ETs1157.\fi + +\M{1662} +\Y\B\4\D$\\{str\_537}$ \5 +\.{"nolimits"}\par +\Y\B\4\X1662:\.{"nolimits"}\X${}\E{}$\5 +\T{537}\par +\Us696, 1156\ETs1157.\fi + +\M{1663} +\Y\B\4\D$\\{str\_538}$ \5 +\.{"fraction,\ thickness}\)\.{\ "}\par +\Y\B\4\X1663:\.{"fraction,\ thickness}\)\.{\ "}\X${}\E{}$\5 +\T{538}\par +\U697.\fi + +\M{1664} +\Y\B\4\D$\\{str\_539}$ \5 +\.{"mlist1"}\par +\Y\B\4\X1664:\.{"mlist1"}\X${}\E{}$\5 +\T{539}\par +\U728.\fi + +\M{1665} +\Y\B\4\D$\\{str\_540}$ \5 +\.{"mlist2"}\par +\Y\B\4\X1665:\.{"mlist2"}\X${}\E{}$\5 +\T{540}\par +\U754.\fi + +\M{1666} +\Y\B\4\D$\\{str\_541}$ \5 +\.{"mlist3"}\par +\Y\B\4\X1666:\.{"mlist3"}\X${}\E{}$\5 +\T{541}\par +\U761.\fi + +\M{1667} +\Y\B\4\D$\\{str\_542}$ \5 +\.{"0234000122*4000133*}\)\.{*3**344*0400400*0000}\)\.{00234000111*11111123}\)\.{41011"}\par +\B\4\D$\\{math\_spacing}$ \5 +\T{542}\par +\fi + +\M{1668} +\Y\B\4\D$\\{str\_543}$ \5 +\.{"mlist4"}\par +\Y\B\4\X1668:\.{"mlist4"}\X${}\E{}$\5 +\T{543}\par +\U766.\fi + +\M{1669} +\Y\B\4\D$\\{str\_544}$ \5 +\.{"span"}\par +\Y\B\4\X1669:\.{"span"}\X${}\E{}$\5 +\T{544}\par +\Us780\ET781.\fi + +\M{1670} +\Y\B\4\D$\\{str\_545}$ \5 +\.{"cr"}\par +\Y\B\4\X1670:\.{"cr"}\X${}\E{}$\5 +\T{545}\par +\Us780, 781, 792\ETs1132.\fi + +\M{1671} +\Y\B\4\D$\\{str\_546}$ \5 +\.{"crcr"}\par +\Y\B\4\X1671:\.{"crcr"}\X${}\E{}$\5 +\T{546}\par +\Us780\ET781.\fi + +\M{1672} +\Y\B\4\D$\\{str\_547}$ \5 +\.{"endtemplate"}\par +\Y\B\4\X1672:\.{"endtemplate"}\X${}\E{}$\5 +\T{547}\par +\U780.\fi + +\M{1673} +\Y\B\4\D$\\{str\_548}$ \5 +\.{"endv"}\par +\Y\B\4\X1673:\.{"endv"}\X${}\E{}$\5 +\T{548}\par +\U791.\fi + +\M{1674} +\Y\B\4\D$\\{str\_549}$ \5 +\.{"256\ spans"}\par +\Y\B\4\X1674:\.{"256\ spans"}\X${}\E{}$\5 +\T{549}\par +\U798.\fi + +\M{1675} +\Y\B\4\D$\\{str\_550}$ \5 +\.{"align1"}\par +\Y\B\4\X1675:\.{"align1"}\X${}\E{}$\5 +\T{550}\par +\U800.\fi + +\M{1676} +\Y\B\4\D$\\{str\_551}$ \5 +\.{"align0"}\par +\Y\B\4\X1676:\.{"align0"}\X${}\E{}$\5 +\T{551}\par +\U800.\fi + +\M{1677} +\Y\B\4\D$\\{str\_552}$ \5 +\.{"disc1"}\par +\Y\B\4\X1677:\.{"disc1"}\X${}\E{}$\5 +\T{552}\par +\U841.\fi + +\M{1678} +\Y\B\4\D$\\{str\_553}$ \5 +\.{"disc2"}\par +\Y\B\4\X1678:\.{"disc2"}\X${}\E{}$\5 +\T{553}\par +\U842.\fi + +\M{1679} +\Y\B\4\D$\\{str\_554}$ \5 +\.{"paragraph"}\par +\Y\B\4\X1679:\.{"paragraph"}\X${}\E{}$\5 +\T{554}\par +\U866.\fi + +\M{1680} +\Y\B\4\D$\\{str\_555}$ \5 +\.{"disc3"}\par +\Y\B\4\X1680:\.{"disc3"}\X${}\E{}$\5 +\T{555}\par +\U870.\fi + +\M{1681} +\Y\B\4\D$\\{str\_556}$ \5 +\.{"disc4"}\par +\Y\B\4\X1681:\.{"disc4"}\X${}\E{}$\5 +\T{556}\par +\U871.\fi + +\M{1682} +\Y\B\4\D$\\{str\_557}$ \5 +\.{"line\ breaking"}\par +\Y\B\4\X1682:\.{"line\ breaking"}\X${}\E{}$\5 +\T{557}\par +\U877.\fi + +\M{1683} +\Y\B\4\D$\\{str\_558}$ \5 +\.{"hyphenation"}\par +\Y\B\4\X1683:\.{"hyphenation"}\X${}\E{}$\5 +\T{558}\par +\Us936, 1250\ETs1251.\fi + +\M{1684} +\Y\B\4\D$\\{str\_559}$ \5 +\.{"patterns"}\par +\Y\B\4\X1684:\.{"patterns"}\X${}\E{}$\5 +\T{559}\par +\Us960, 961, 1250\ETs1251.\fi + +\M{1685} +\Y\B\4\D$\\{str\_560}$ \5 +\.{"pruning"}\par +\Y\B\4\X1685:\.{"pruning"}\X${}\E{}$\5 +\T{560}\par +\U968.\fi + +\M{1686} +\Y\B\4\D$\\{str\_561}$ \5 +\.{"vertbreak"}\par +\Y\B\4\X1686:\.{"vertbreak"}\X${}\E{}$\5 +\T{561}\par +\U973.\fi + +\M{1687} +\Y\B\4\D$\\{str\_562}$ \5 +\.{"vsplit"}\par +\Y\B\4\X1687:\.{"vsplit"}\X${}\E{}$\5 +\T{562}\par +\Us978, 1071\ETs1072.\fi + +\M{1688} +\Y\B\4\D$\\{str\_563}$ \5 +\.{"vbox"}\par +\Y\B\4\X1688:\.{"vbox"}\X${}\E{}$\5 +\T{563}\par +\Us978, 1071\ETs1072.\fi + +\M{1689} +\Y\B\4\D$\\{str\_564}$ \5 +\.{"pagegoal"}\par +\Y\B\4\X1689:\.{"pagegoal"}\X${}\E{}$\5 +\T{564}\par +\Us983\ET984.\fi + +\M{1690} +\Y\B\4\D$\\{str\_565}$ \5 +\.{"pagetotal"}\par +\Y\B\4\X1690:\.{"pagetotal"}\X${}\E{}$\5 +\T{565}\par +\Us983\ET984.\fi + +\M{1691} +\Y\B\4\D$\\{str\_566}$ \5 +\.{"pagestretch"}\par +\Y\B\4\X1691:\.{"pagestretch"}\X${}\E{}$\5 +\T{566}\par +\Us983\ET984.\fi + +\M{1692} +\Y\B\4\D$\\{str\_567}$ \5 +\.{"pagefilstretch"}\par +\Y\B\4\X1692:\.{"pagefilstretch"}\X${}\E{}$\5 +\T{567}\par +\Us983\ET984.\fi + +\M{1693} +\Y\B\4\D$\\{str\_568}$ \5 +\.{"pagefillstretch"}\par +\Y\B\4\X1693:\.{"pagefillstretch"}\X${}\E{}$\5 +\T{568}\par +\Us983\ET984.\fi + +\M{1694} +\Y\B\4\D$\\{str\_569}$ \5 +\.{"pagefilllstretch"}\par +\Y\B\4\X1694:\.{"pagefilllstretch"}\X${}\E{}$\5 +\T{569}\par +\Us983\ET984.\fi + +\M{1695} +\Y\B\4\D$\\{str\_570}$ \5 +\.{"pageshrink"}\par +\Y\B\4\X1695:\.{"pageshrink"}\X${}\E{}$\5 +\T{570}\par +\Us983\ET984.\fi + +\M{1696} +\Y\B\4\D$\\{str\_571}$ \5 +\.{"pagedepth"}\par +\Y\B\4\X1696:\.{"pagedepth"}\X${}\E{}$\5 +\T{571}\par +\Us983\ET984.\fi + +\M{1697} +\Y\B\4\D$\\{str\_572}$ \5 +\.{"page"}\par +\Y\B\4\X1697:\.{"page"}\X${}\E{}$\5 +\T{572}\par +\U1000.\fi + +\M{1698} +\Y\B\4\D$\\{str\_573}$ \5 +\.{"end"}\par +\Y\B\4\X1698:\.{"end"}\X${}\E{}$\5 +\T{573}\par +\Us1052\ET1053.\fi + +\M{1699} +\Y\B\4\D$\\{str\_574}$ \5 +\.{"dump"}\par +\Y\B\4\X1699:\.{"dump"}\X${}\E{}$\5 +\T{574}\par +\Us1052\ET1053.\fi + +\M{1700} +\Y\B\4\D$\\{str\_575}$ \5 +\.{"hskip"}\par +\Y\B\4\X1700:\.{"hskip"}\X${}\E{}$\5 +\T{575}\par +\Us1058\ET1059.\fi + +\M{1701} +\Y\B\4\D$\\{str\_576}$ \5 +\.{"hfil"}\par +\Y\B\4\X1701:\.{"hfil"}\X${}\E{}$\5 +\T{576}\par +\Us1058\ET1059.\fi + +\M{1702} +\Y\B\4\D$\\{str\_577}$ \5 +\.{"hfill"}\par +\Y\B\4\X1702:\.{"hfill"}\X${}\E{}$\5 +\T{577}\par +\Us1058\ET1059.\fi + +\M{1703} +\Y\B\4\D$\\{str\_578}$ \5 +\.{"hss"}\par +\Y\B\4\X1703:\.{"hss"}\X${}\E{}$\5 +\T{578}\par +\Us1058\ET1059.\fi + +\M{1704} +\Y\B\4\D$\\{str\_579}$ \5 +\.{"hfilneg"}\par +\Y\B\4\X1704:\.{"hfilneg"}\X${}\E{}$\5 +\T{579}\par +\Us1058\ET1059.\fi + +\M{1705} +\Y\B\4\D$\\{str\_580}$ \5 +\.{"vskip"}\par +\Y\B\4\X1705:\.{"vskip"}\X${}\E{}$\5 +\T{580}\par +\Us1058\ET1059.\fi + +\M{1706} +\Y\B\4\D$\\{str\_581}$ \5 +\.{"vfil"}\par +\Y\B\4\X1706:\.{"vfil"}\X${}\E{}$\5 +\T{581}\par +\Us1058\ET1059.\fi + +\M{1707} +\Y\B\4\D$\\{str\_582}$ \5 +\.{"vfill"}\par +\Y\B\4\X1707:\.{"vfill"}\X${}\E{}$\5 +\T{582}\par +\Us1058\ET1059.\fi + +\M{1708} +\Y\B\4\D$\\{str\_583}$ \5 +\.{"vss"}\par +\Y\B\4\X1708:\.{"vss"}\X${}\E{}$\5 +\T{583}\par +\Us1058\ET1059.\fi + +\M{1709} +\Y\B\4\D$\\{str\_584}$ \5 +\.{"vfilneg"}\par +\Y\B\4\X1709:\.{"vfilneg"}\X${}\E{}$\5 +\T{584}\par +\Us1058\ET1059.\fi + +\M{1710} +\Y\B\4\D$\\{str\_585}$ \5 +\.{"right."}\par +\Y\B\4\X1710:\.{"right."}\X${}\E{}$\5 +\T{585}\par +\U1065.\fi + +\M{1711} +\Y\B\4\D$\\{str\_586}$ \5 +\.{"rightbrace"}\par +\Y\B\4\X1711:\.{"rightbrace"}\X${}\E{}$\5 +\T{586}\par +\U1068.\fi + +\M{1712} +\Y\B\4\D$\\{str\_587}$ \5 +\.{"moveleft"}\par +\Y\B\4\X1712:\.{"moveleft"}\X${}\E{}$\5 +\T{587}\par +\Us1071\ET1072.\fi + +\M{1713} +\Y\B\4\D$\\{str\_588}$ \5 +\.{"moveright"}\par +\Y\B\4\X1713:\.{"moveright"}\X${}\E{}$\5 +\T{588}\par +\Us1071\ET1072.\fi + +\M{1714} +\Y\B\4\D$\\{str\_589}$ \5 +\.{"raise"}\par +\Y\B\4\X1714:\.{"raise"}\X${}\E{}$\5 +\T{589}\par +\Us1071\ET1072.\fi + +\M{1715} +\Y\B\4\D$\\{str\_590}$ \5 +\.{"lower"}\par +\Y\B\4\X1715:\.{"lower"}\X${}\E{}$\5 +\T{590}\par +\Us1071\ET1072.\fi + +\M{1716} +\Y\B\4\D$\\{str\_591}$ \5 +\.{"copy"}\par +\Y\B\4\X1716:\.{"copy"}\X${}\E{}$\5 +\T{591}\par +\Us1071\ET1072.\fi + +\M{1717} +\Y\B\4\D$\\{str\_592}$ \5 +\.{"lastbox"}\par +\Y\B\4\X1717:\.{"lastbox"}\X${}\E{}$\5 +\T{592}\par +\Us1071\ET1072.\fi + +\M{1718} +\Y\B\4\D$\\{str\_593}$ \5 +\.{"vtop"}\par +\Y\B\4\X1718:\.{"vtop"}\X${}\E{}$\5 +\T{593}\par +\Us1071\ET1072.\fi + +\M{1719} +\Y\B\4\D$\\{str\_594}$ \5 +\.{"hbox"}\par +\Y\B\4\X1719:\.{"hbox"}\X${}\E{}$\5 +\T{594}\par +\Us1071\ET1072.\fi + +\M{1720} +\Y\B\4\D$\\{str\_595}$ \5 +\.{"shipout"}\par +\Y\B\4\X1720:\.{"shipout"}\X${}\E{}$\5 +\T{595}\par +\Us1071\ET1072.\fi + +\M{1721} +\Y\B\4\D$\\{str\_596}$ \5 +\.{"leaders"}\par +\Y\B\4\X1721:\.{"leaders"}\X${}\E{}$\5 +\T{596}\par +\Us1071\ET1072.\fi + +\M{1722} +\Y\B\4\D$\\{str\_597}$ \5 +\.{"cleaders"}\par +\Y\B\4\X1722:\.{"cleaders"}\X${}\E{}$\5 +\T{597}\par +\Us1071\ET1072.\fi + +\M{1723} +\Y\B\4\D$\\{str\_598}$ \5 +\.{"xleaders"}\par +\Y\B\4\X1723:\.{"xleaders"}\X${}\E{}$\5 +\T{598}\par +\Us1071\ET1072.\fi + +\M{1724} +\Y\B\4\D$\\{str\_599}$ \5 +\.{"indent"}\par +\Y\B\4\X1724:\.{"indent"}\X${}\E{}$\5 +\T{599}\par +\Us1088\ET1089.\fi + +\M{1725} +\Y\B\4\D$\\{str\_600}$ \5 +\.{"noindent"}\par +\Y\B\4\X1725:\.{"noindent"}\X${}\E{}$\5 +\T{600}\par +\Us1088\ET1089.\fi + +\M{1726} +\Y\B\4\D$\\{str\_601}$ \5 +\.{"unpenalty"}\par +\Y\B\4\X1726:\.{"unpenalty"}\X${}\E{}$\5 +\T{601}\par +\Us1107\ET1108.\fi + +\M{1727} +\Y\B\4\D$\\{str\_602}$ \5 +\.{"unkern"}\par +\Y\B\4\X1727:\.{"unkern"}\X${}\E{}$\5 +\T{602}\par +\Us1107\ET1108.\fi + +\M{1728} +\Y\B\4\D$\\{str\_603}$ \5 +\.{"unskip"}\par +\Y\B\4\X1728:\.{"unskip"}\X${}\E{}$\5 +\T{603}\par +\Us1107\ET1108.\fi + +\M{1729} +\Y\B\4\D$\\{str\_604}$ \5 +\.{"unhbox"}\par +\Y\B\4\X1729:\.{"unhbox"}\X${}\E{}$\5 +\T{604}\par +\Us1107\ET1108.\fi + +\M{1730} +\Y\B\4\D$\\{str\_605}$ \5 +\.{"unhcopy"}\par +\Y\B\4\X1730:\.{"unhcopy"}\X${}\E{}$\5 +\T{605}\par +\Us1107\ET1108.\fi + +\M{1731} +\Y\B\4\D$\\{str\_606}$ \5 +\.{"unvbox"}\par +\Y\B\4\X1731:\.{"unvbox"}\X${}\E{}$\5 +\T{606}\par +\Us1107\ET1108.\fi + +\M{1732} +\Y\B\4\D$\\{str\_607}$ \5 +\.{"unvcopy"}\par +\Y\B\4\X1732:\.{"unvcopy"}\X${}\E{}$\5 +\T{607}\par +\Us1107\ET1108.\fi + +\M{1733} +\Y\B\4\D$\\{str\_608}$ \5 +\.{"eqno"}\par +\Y\B\4\X1733:\.{"eqno"}\X${}\E{}$\5 +\T{608}\par +\Us1141\ET1143.\fi + +\M{1734} +\Y\B\4\D$\\{str\_609}$ \5 +\.{"leqno"}\par +\Y\B\4\X1734:\.{"leqno"}\X${}\E{}$\5 +\T{609}\par +\Us1141\ET1143.\fi + +\M{1735} +\Y\B\4\D$\\{str\_610}$ \5 +\.{"displaylimits"}\par +\Y\B\4\X1735:\.{"displaylimits"}\X${}\E{}$\5 +\T{610}\par +\Us1156\ET1157.\fi + +\M{1736} +\Y\B\4\D$\\{str\_611}$ \5 +\.{"above"}\par +\Y\B\4\X1736:\.{"above"}\X${}\E{}$\5 +\T{611}\par +\Us1178\ET1179.\fi + +\M{1737} +\Y\B\4\D$\\{str\_612}$ \5 +\.{"over"}\par +\Y\B\4\X1737:\.{"over"}\X${}\E{}$\5 +\T{612}\par +\Us1178\ET1179.\fi + +\M{1738} +\Y\B\4\D$\\{str\_613}$ \5 +\.{"atop"}\par +\Y\B\4\X1738:\.{"atop"}\X${}\E{}$\5 +\T{613}\par +\Us1178\ET1179.\fi + +\M{1739} +\Y\B\4\D$\\{str\_614}$ \5 +\.{"abovewithdelims"}\par +\Y\B\4\X1739:\.{"abovewithdelims"}\X${}\E{}$\5 +\T{614}\par +\Us1178\ET1179.\fi + +\M{1740} +\Y\B\4\D$\\{str\_615}$ \5 +\.{"overwithdelims"}\par +\Y\B\4\X1740:\.{"overwithdelims"}\X${}\E{}$\5 +\T{615}\par +\Us1178\ET1179.\fi + +\M{1741} +\Y\B\4\D$\\{str\_616}$ \5 +\.{"atopwithdelims"}\par +\Y\B\4\X1741:\.{"atopwithdelims"}\X${}\E{}$\5 +\T{616}\par +\Us1178\ET1179.\fi + +\M{1742} +\Y\B\4\D$\\{str\_617}$ \5 +\.{"display"}\par +\Y\B\4\X1742:\.{"display"}\X${}\E{}$\5 +\T{617}\par +\U1200.\fi + +\M{1743} +\Y\B\4\D$\\{str\_618}$ \5 +\.{"long"}\par +\Y\B\4\X1743:\.{"long"}\X${}\E{}$\5 +\T{618}\par +\Us1208, 1209, 1213\ETs1295.\fi + +\M{1744} +\Y\B\4\D$\\{str\_619}$ \5 +\.{"outer"}\par +\Y\B\4\X1744:\.{"outer"}\X${}\E{}$\5 +\T{619}\par +\Us1208, 1209\ETs1213.\fi + +\M{1745} +\Y\B\4\D$\\{str\_620}$ \5 +\.{"global"}\par +\Y\B\4\X1745:\.{"global"}\X${}\E{}$\5 +\T{620}\par +\Us1208\ET1209.\fi + +\M{1746} +\Y\B\4\D$\\{str\_621}$ \5 +\.{"def"}\par +\Y\B\4\X1746:\.{"def"}\X${}\E{}$\5 +\T{621}\par +\Us1208\ET1209.\fi + +\M{1747} +\Y\B\4\D$\\{str\_622}$ \5 +\.{"gdef"}\par +\Y\B\4\X1747:\.{"gdef"}\X${}\E{}$\5 +\T{622}\par +\Us1208\ET1209.\fi + +\M{1748} +\Y\B\4\D$\\{str\_623}$ \5 +\.{"edef"}\par +\Y\B\4\X1748:\.{"edef"}\X${}\E{}$\5 +\T{623}\par +\Us1208\ET1209.\fi + +\M{1749} +\Y\B\4\D$\\{str\_624}$ \5 +\.{"xdef"}\par +\Y\B\4\X1749:\.{"xdef"}\X${}\E{}$\5 +\T{624}\par +\Us1208\ET1209.\fi + +\M{1750} +\Y\B\4\D$\\{str\_625}$ \5 +\.{"prefix"}\par +\Y\B\4\X1750:\.{"prefix"}\X${}\E{}$\5 +\T{625}\par +\U1211.\fi + +\M{1751} +\Y\B\4\D$\\{str\_626}$ \5 +\.{"inaccessible"}\par +\Y\B\4\X1751:\.{"inaccessible"}\X${}\E{}$\5 +\T{626}\par +\U1216.\fi + +\M{1752} +\Y\B\4\D$\\{str\_627}$ \5 +\.{"let"}\par +\Y\B\4\X1752:\.{"let"}\X${}\E{}$\5 +\T{627}\par +\Us1219\ET1220.\fi + +\M{1753} +\Y\B\4\D$\\{str\_628}$ \5 +\.{"futurelet"}\par +\Y\B\4\X1753:\.{"futurelet"}\X${}\E{}$\5 +\T{628}\par +\Us1219\ET1220.\fi + +\M{1754} +\Y\B\4\D$\\{str\_629}$ \5 +\.{"chardef"}\par +\Y\B\4\X1754:\.{"chardef"}\X${}\E{}$\5 +\T{629}\par +\Us1222\ET1223.\fi + +\M{1755} +\Y\B\4\D$\\{str\_630}$ \5 +\.{"mathchardef"}\par +\Y\B\4\X1755:\.{"mathchardef"}\X${}\E{}$\5 +\T{630}\par +\Us1222\ET1223.\fi + +\M{1756} +\Y\B\4\D$\\{str\_631}$ \5 +\.{"countdef"}\par +\Y\B\4\X1756:\.{"countdef"}\X${}\E{}$\5 +\T{631}\par +\Us1222\ET1223.\fi + +\M{1757} +\Y\B\4\D$\\{str\_632}$ \5 +\.{"dimendef"}\par +\Y\B\4\X1757:\.{"dimendef"}\X${}\E{}$\5 +\T{632}\par +\Us1222\ET1223.\fi + +\M{1758} +\Y\B\4\D$\\{str\_633}$ \5 +\.{"skipdef"}\par +\Y\B\4\X1758:\.{"skipdef"}\X${}\E{}$\5 +\T{633}\par +\Us1222\ET1223.\fi + +\M{1759} +\Y\B\4\D$\\{str\_634}$ \5 +\.{"muskipdef"}\par +\Y\B\4\X1759:\.{"muskipdef"}\X${}\E{}$\5 +\T{634}\par +\Us1222\ET1223.\fi + +\M{1760} +\Y\B\4\D$\\{str\_635}$ \5 +\.{"toksdef"}\par +\Y\B\4\X1760:\.{"toksdef"}\X${}\E{}$\5 +\T{635}\par +\Us1222\ET1223.\fi + +\M{1761} +\Y\B\4\D$\\{str\_636}$ \5 +\.{"by"}\par +\Y\B\4\X1761:\.{"by"}\X${}\E{}$\5 +\T{636}\par +\U1236.\fi + +\M{1762} +\Y\B\4\D$\\{str\_637}$ \5 +\.{"hyphenchar"}\par +\Y\B\4\X1762:\.{"hyphenchar"}\X${}\E{}$\5 +\T{637}\par +\Us1254\ET1255.\fi + +\M{1763} +\Y\B\4\D$\\{str\_638}$ \5 +\.{"skewchar"}\par +\Y\B\4\X1763:\.{"skewchar"}\X${}\E{}$\5 +\T{638}\par +\Us1254\ET1255.\fi + +\M{1764} +\Y\B\4\D$\\{str\_639}$ \5 +\.{"FONT"}\par +\Y\B\4\X1764:\.{"FONT"}\X${}\E{}$\5 +\T{639}\par +\U1257.\fi + +\M{1765} +\Y\B\4\D$\\{str\_640}$ \5 +\.{"at"}\par +\Y\B\4\X1765:\.{"at"}\X${}\E{}$\5 +\T{640}\par +\U1258.\fi + +\M{1766} +\Y\B\4\D$\\{str\_641}$ \5 +\.{"scaled"}\par +\Y\B\4\X1766:\.{"scaled"}\X${}\E{}$\5 +\T{641}\par +\U1258.\fi + +\M{1767} +\Y\B\4\D$\\{str\_642}$ \5 +\.{"errorstopmode"}\par +\Y\B\4\X1767:\.{"errorstopmode"}\X${}\E{}$\5 +\T{642}\par +\Us1262\ET1263.\fi + +\M{1768} +\Y\B\4\D$\\{str\_643}$ \5 +\.{"openin"}\par +\Y\B\4\X1768:\.{"openin"}\X${}\E{}$\5 +\T{643}\par +\Us1272\ET1273.\fi + +\M{1769} +\Y\B\4\D$\\{str\_644}$ \5 +\.{"closein"}\par +\Y\B\4\X1769:\.{"closein"}\X${}\E{}$\5 +\T{644}\par +\Us1272\ET1273.\fi + +\M{1770} +\Y\B\4\D$\\{str\_645}$ \5 +\.{"message"}\par +\Y\B\4\X1770:\.{"message"}\X${}\E{}$\5 +\T{645}\par +\Us1277\ET1278.\fi + +\M{1771} +\Y\B\4\D$\\{str\_646}$ \5 +\.{"errmessage"}\par +\Y\B\4\X1771:\.{"errmessage"}\X${}\E{}$\5 +\T{646}\par +\Us1277\ET1278.\fi + +\M{1772} +\Y\B\4\D$\\{str\_647}$ \5 +\.{"lowercase"}\par +\Y\B\4\X1772:\.{"lowercase"}\X${}\E{}$\5 +\T{647}\par +\Us1286\ET1287.\fi + +\M{1773} +\Y\B\4\D$\\{str\_648}$ \5 +\.{"uppercase"}\par +\Y\B\4\X1773:\.{"uppercase"}\X${}\E{}$\5 +\T{648}\par +\Us1286\ET1287.\fi + +\M{1774} +\Y\B\4\D$\\{str\_649}$ \5 +\.{"show"}\par +\Y\B\4\X1774:\.{"show"}\X${}\E{}$\5 +\T{649}\par +\Us1291\ET1292.\fi + +\M{1775} +\Y\B\4\D$\\{str\_650}$ \5 +\.{"showbox"}\par +\Y\B\4\X1775:\.{"showbox"}\X${}\E{}$\5 +\T{650}\par +\Us1291\ET1292.\fi + +\M{1776} +\Y\B\4\D$\\{str\_651}$ \5 +\.{"showthe"}\par +\Y\B\4\X1776:\.{"showthe"}\X${}\E{}$\5 +\T{651}\par +\Us1291\ET1292.\fi + +\M{1777} +\Y\B\4\D$\\{str\_652}$ \5 +\.{"showlists"}\par +\Y\B\4\X1777:\.{"showlists"}\X${}\E{}$\5 +\T{652}\par +\Us1291\ET1292.\fi + +\M{1778} +\Y\B\4\D$\\{str\_653}$ \5 +\.{"long\ macro"}\par +\Y\B\4\X1778:\.{"long\ macro"}\X${}\E{}$\5 +\T{653}\par +\U1295.\fi + +\M{1779} +\Y\B\4\D$\\{str\_654}$ \5 +\.{"outer\ macro"}\par +\Y\B\4\X1779:\.{"outer\ macro"}\X${}\E{}$\5 +\T{654}\par +\U1295.\fi + +\M{1780} +\Y\B\4\D$\\{str\_655}$ \5 +\.{"outer\ endtemplate"}\par +\Y\B\4\X1780:\.{"outer\ endtemplate"}\X${}\E{}$\5 +\T{655}\par +\U1295.\fi + +\M{1781} +\Y\B\4\D$\\{str\_656}$ \5 +\.{"\ (INITEX)"}\par +\Y\B\4\X1781:\.{"\ (INITEX)"}\X${}\E{}$\5 +\T{656}\par +\U1301.\fi + +\M{1782} +\Y\B\4\D$\\{str\_657}$ \5 +\.{"end\ occurred\ "}\par +\Y\B\4\X1782:\.{"end\ occurred\ "}\X${}\E{}$\5 +\T{657}\par +\U1335.\fi + +\M{1783} +\Y\B\4\D$\\{str\_658}$ \5 +\.{"openout"}\par +\Y\B\4\X1783:\.{"openout"}\X${}\E{}$\5 +\T{658}\par +\Us1344, 1346\ETs1356.\fi + +\M{1784} +\Y\B\4\D$\\{str\_659}$ \5 +\.{"closeout"}\par +\Y\B\4\X1784:\.{"closeout"}\X${}\E{}$\5 +\T{659}\par +\Us1344, 1346\ETs1356.\fi + +\M{1785} +\Y\B\4\D$\\{str\_660}$ \5 +\.{"special"}\par +\Y\B\4\X1785:\.{"special"}\X${}\E{}$\5 +\T{660}\par +\Us1344, 1346\ETs1356.\fi + +\M{1786} +\Y\B\4\D$\\{str\_661}$ \5 +\.{"immediate"}\par +\Y\B\4\X1786:\.{"immediate"}\X${}\E{}$\5 +\T{661}\par +\Us1344\ET1346.\fi + +\M{1787} +\Y\B\4\D$\\{str\_662}$ \5 +\.{"setlanguage"}\par +\Y\B\4\X1787:\.{"setlanguage"}\X${}\E{}$\5 +\T{662}\par +\Us1344, 1346\ETs1356.\fi + +\M{1788} +\Y\B\4\D$\\{str\_663}$ \5 +\.{"ext1"}\par +\Y\B\4\X1788:\.{"ext1"}\X${}\E{}$\5 +\T{663}\par +\U1348.\fi + +\M{1789} +\Y\B\4\D$\\{str\_664}$ \5 +\.{"ext2"}\par +\Y\B\4\X1789:\.{"ext2"}\X${}\E{}$\5 +\T{664}\par +\U1357.\fi + +\M{1790} +\Y\B\4\D$\\{str\_665}$ \5 +\.{"ext3"}\par +\Y\B\4\X1790:\.{"ext3"}\X${}\E{}$\5 +\T{665}\par +\U1358.\fi + +\M{1791} +\Y\B\4\D$\\{str\_666}$ \5 +\.{"endwrite"}\par +\Y\B\4\X1791:\.{"endwrite"}\X${}\E{}$\5 +\T{666}\par +\U1369.\fi + +\M{1792} +\Y\B\4\D$\\{str\_667}$ \5 +\.{"ext4"}\par +\Y\B\4\X1792:\.{"ext4"}\X${}\E{}$\5 +\T{667}\par +\U1373.\fi + +\M{1793}All the above strings together make up the string pool. +\Y\B\4\X1793:\\{str\_pool} initialization\X${}\E{}$\6 +\\{str\_0\_255}\\{str\_256}\\{str\_257}\\{str\_258}\\{str\_259}\\{str\_260}\\{str\_261}\\{str\_262}\\{str\_263}\6 +\\{str\_264}\\{str\_265}\\{str\_266}\\{str\_267}\\{str\_268}\\{str\_269}\\{str\_270}\\{str\_271}\6 +\\{str\_272}\\{str\_273}\\{str\_274}\\{str\_275}\\{str\_276}\\{str\_277}\\{str\_278}\\{str\_279}\6 +\\{str\_280}\\{str\_281}\\{str\_282}\\{str\_283}\\{str\_284}\\{str\_285}\\{str\_286}\\{str\_287}\6 +\\{str\_288}\\{str\_289}\\{str\_290}\\{str\_291}\\{str\_292}\\{str\_293}\\{str\_294}\\{str\_295}\6 +\\{str\_296}\\{str\_297}\\{str\_298}\\{str\_299}\\{str\_300}\\{str\_301}\\{str\_302}\\{str\_303}\6 +\\{str\_304}\\{str\_305}\\{str\_306}\\{str\_307}\\{str\_308}\\{str\_309}\\{str\_310}\\{str\_311}\6 +\\{str\_312}\\{str\_313}\\{str\_314}\\{str\_315}\\{str\_316}\\{str\_317}\\{str\_318}\\{str\_319}\6 +\\{str\_320}\\{str\_321}\\{str\_322}\\{str\_323}\\{str\_324}\\{str\_325}\\{str\_326}\\{str\_327}\6 +\\{str\_328}\\{str\_329}\\{str\_330}\\{str\_331}\\{str\_332}\\{str\_333}\\{str\_334}\\{str\_335}\6 +\\{str\_336}\\{str\_337}\\{str\_338}\\{str\_339}\\{str\_340}\\{str\_341}\\{str\_342}\\{str\_343}\6 +\\{str\_344}\\{str\_345}\\{str\_346}\\{str\_347}\\{str\_348}\\{str\_349}\\{str\_350}\\{str\_351}\6 +\\{str\_352}\\{str\_353}\\{str\_354}\\{str\_355}\\{str\_356}\\{str\_357}\\{str\_358}\\{str\_359}\6 +\\{str\_360}\\{str\_361}\\{str\_362}\\{str\_363}\\{str\_364}\\{str\_365}\\{str\_366}\\{str\_367}\6 +\\{str\_368}\\{str\_369}\\{str\_370}\\{str\_371}\\{str\_372}\\{str\_373}\\{str\_374}\\{str\_375}\6 +\\{str\_376}\\{str\_377}\\{str\_378}\\{str\_379}\\{str\_380}\\{str\_381}\\{str\_382}\\{str\_383}\6 +\\{str\_384}\\{str\_385}\\{str\_386}\\{str\_387}\\{str\_388}\\{str\_389}\\{str\_390}\\{str\_391}\6 +\\{str\_392}\\{str\_393}\\{str\_394}\\{str\_395}\\{str\_396}\\{str\_397}\\{str\_398}\\{str\_399}\6 +\\{str\_400}\\{str\_401}\\{str\_402}\\{str\_403}\\{str\_404}\\{str\_405}\\{str\_406}\\{str\_407}\6 +\\{str\_408}\\{str\_409}\\{str\_410}\\{str\_411}\\{str\_412}\\{str\_413}\\{str\_414}\\{str\_415}\6 +\\{str\_416}\\{str\_417}\\{str\_418}\\{str\_419}\\{str\_420}\\{str\_421}\\{str\_422}\\{str\_423}\6 +\\{str\_424}\\{str\_425}\\{str\_426}\\{str\_427}\\{str\_428}\\{str\_429}\\{str\_430}\\{str\_431}\6 +\\{str\_432}\\{str\_433}\\{str\_434}\\{str\_435}\\{str\_436}\\{str\_437}\\{str\_438}\\{str\_439}\6 +\\{str\_440}\\{str\_441}\\{str\_442}\\{str\_443}\\{str\_444}\\{str\_445}\\{str\_446}\\{str\_447}\6 +\\{str\_448}\\{str\_449}\\{str\_450}\\{str\_451}\\{str\_452}\\{str\_453}\\{str\_454}\\{str\_455}\6 +\\{str\_456}\\{str\_457}\\{str\_458}\\{str\_459}\\{str\_460}\\{str\_461}\\{str\_462}\\{str\_463}\6 +\\{str\_464}\\{str\_465}\\{str\_466}\\{str\_467}\\{str\_468}\\{str\_469}\\{str\_470}\\{str\_471}\6 +\\{str\_472}\\{str\_473}\\{str\_474}\\{str\_475}\\{str\_476}\\{str\_477}\\{str\_478}\\{str\_479}\6 +\\{str\_480}\\{str\_481}\\{str\_482}\\{str\_483}\\{str\_484}\\{str\_485}\\{str\_486}\\{str\_487}\6 +\\{str\_488}\\{str\_489}\\{str\_490}\\{str\_491}\\{str\_492}\\{str\_493}\\{str\_494}\\{str\_495}\6 +\\{str\_496}\\{str\_497}\\{str\_498}\\{str\_499}\\{str\_500}\\{str\_501}\\{str\_502}\\{str\_503}\6 +\\{str\_504}\\{str\_505}\\{str\_506}\\{str\_507}\\{str\_508}\\{str\_509}\\{str\_510}\\{str\_511}\6 +\\{str\_512}\\{str\_513}\\{str\_514}\\{str\_515}\\{str\_516}\\{str\_517}\\{str\_518}\\{str\_519}\6 +\\{str\_520}\\{str\_521}\\{str\_522}\\{str\_523}\\{str\_524}\\{str\_525}\\{str\_526}\\{str\_527}\6 +\\{str\_528}\\{str\_529}\\{str\_530}\\{str\_531}\\{str\_532}\\{str\_533}\\{str\_534}\\{str\_535}\6 +\\{str\_536}\\{str\_537}\\{str\_538}\\{str\_539}\\{str\_540}\\{str\_541}\\{str\_542}\\{str\_543}\6 +\\{str\_544}\\{str\_545}\\{str\_546}\\{str\_547}\\{str\_548}\\{str\_549}\\{str\_550}\\{str\_551}\6 +\\{str\_552}\\{str\_553}\\{str\_554}\\{str\_555}\\{str\_556}\\{str\_557}\\{str\_558}\\{str\_559}\6 +\\{str\_560}\\{str\_561}\\{str\_562}\\{str\_563}\\{str\_564}\\{str\_565}\\{str\_566}\\{str\_567}\6 +\\{str\_568}\\{str\_569}\\{str\_570}\\{str\_571}\\{str\_572}\\{str\_573}\\{str\_574}\\{str\_575}\6 +\\{str\_576}\\{str\_577}\\{str\_578}\\{str\_579}\\{str\_580}\\{str\_581}\\{str\_582}\\{str\_583}\6 +\\{str\_584}\\{str\_585}\\{str\_586}\\{str\_587}\\{str\_588}\\{str\_589}\\{str\_590}\\{str\_591}\6 +\\{str\_592}\\{str\_593}\\{str\_594}\\{str\_595}\\{str\_596}\\{str\_597}\\{str\_598}\\{str\_599}\6 +\\{str\_600}\\{str\_601}\\{str\_602}\\{str\_603}\\{str\_604}\\{str\_605}\\{str\_606}\\{str\_607}\6 +\\{str\_608}\\{str\_609}\\{str\_610}\\{str\_611}\\{str\_612}\\{str\_613}\\{str\_614}\\{str\_615}\6 +\\{str\_616}\\{str\_617}\\{str\_618}\\{str\_619}\\{str\_620}\\{str\_621}\\{str\_622}\\{str\_623}\6 +\\{str\_624}\\{str\_625}\\{str\_626}\\{str\_627}\\{str\_628}\\{str\_629}\\{str\_630}\\{str\_631}\6 +\\{str\_632}\\{str\_633}\\{str\_634}\\{str\_635}\\{str\_636}\\{str\_637}\\{str\_638}\\{str\_639}\6 +\\{str\_640}\\{str\_641}\\{str\_642}\\{str\_643}\\{str\_644}\\{str\_645}\\{str\_646}\\{str\_647}\6 +\\{str\_648}\\{str\_649}\\{str\_650}\\{str\_651}\\{str\_652}\\{str\_653}\\{str\_654}\\{str\_655}\6 +\\{str\_656}\\{str\_657}\\{str\_658}\\{str\_659}\\{str\_660}\\{str\_661}\\{str\_662}\\{str\_663}\6 +\\{str\_664}\\{str\_665}\\{str\_666}\\{str\_667}\par +\U39.\fi + +\M{1794}\B\X1794:\\{str\_start} initialization\X${}\E{}$\6 +$\\{str\_start\_0\_255}\\{str\_start\_256},\39\\{str\_start\_257},\39\\{str\_start\_258},\39\\{str\_start\_259},\39\\{str\_start\_260},\39\\{str\_start\_261},\39\\{str\_start\_262},\39\\{str\_start\_263},\39\\{str\_start\_264},\39\\{str\_start\_265},\39% +\\{str\_start\_266},\39\\{str\_start\_267},\39\\{str\_start\_268},\39\\{str\_start\_269},\39\\{str\_start\_270},\39\\{str\_start\_271},\39\\{str\_start\_272},\39\\{str\_start\_273},\39\\{str\_start\_274},\39\\{str\_start\_275},\39\\{str\_start\_276},\39% +\\{str\_start\_277},\39\\{str\_start\_278},\39\\{str\_start\_279},\39\\{str\_start\_280},\39\\{str\_start\_281},\39\\{str\_start\_282},\39\\{str\_start\_283},\39\\{str\_start\_284},\39\\{str\_start\_285},\39\\{str\_start\_286},\39\\{str\_start\_287},\39% +\\{str\_start\_288},\39\\{str\_start\_289},\39\\{str\_start\_290},\39\\{str\_start\_291},\39\\{str\_start\_292},\39\\{str\_start\_293},\39\\{str\_start\_294},\39\\{str\_start\_295},\39\\{str\_start\_296},\39\\{str\_start\_297},\39\\{str\_start\_298},\39% +\\{str\_start\_299},\39\\{str\_start\_300},\39\\{str\_start\_301},\39\\{str\_start\_302},\39\\{str\_start\_303},\39\\{str\_start\_304},\39\\{str\_start\_305},\39\\{str\_start\_306},\39\\{str\_start\_307},\39\\{str\_start\_308},\39\\{str\_start\_309},\39% +\\{str\_start\_310},\39\\{str\_start\_311},\39\\{str\_start\_312},\39\\{str\_start\_313},\39\\{str\_start\_314},\39\\{str\_start\_315},\39\\{str\_start\_316},\39\\{str\_start\_317},\39\\{str\_start\_318},\39\\{str\_start\_319},\39\\{str\_start\_320},\39% +\\{str\_start\_321},\39\\{str\_start\_322},\39\\{str\_start\_323},\39\\{str\_start\_324},\39\\{str\_start\_325},\39\\{str\_start\_326},\39\\{str\_start\_327},\39\\{str\_start\_328},\39\\{str\_start\_329},\39\\{str\_start\_330},\39\\{str\_start\_331},\39% +\\{str\_start\_332},\39\\{str\_start\_333},\39\\{str\_start\_334},\39\\{str\_start\_335},\39\\{str\_start\_336},\39\\{str\_start\_337},\39\\{str\_start\_338},\39\\{str\_start\_339},\39\\{str\_start\_340},\39\\{str\_start\_341},\39\\{str\_start\_342},\39% +\\{str\_start\_343},\39\\{str\_start\_344},\39\\{str\_start\_345},\39\\{str\_start\_346},\39\\{str\_start\_347},\39\\{str\_start\_348},\39\\{str\_start\_349},\39\\{str\_start\_350},\39\\{str\_start\_351},\39\\{str\_start\_352},\39\\{str\_start\_353},\39% +\\{str\_start\_354},\39\\{str\_start\_355},\39\\{str\_start\_356},\39\\{str\_start\_357},\39\\{str\_start\_358},\39\\{str\_start\_359},\39\\{str\_start\_360},\39\\{str\_start\_361},\39\\{str\_start\_362},\39\\{str\_start\_363},\39\\{str\_start\_364},\39% +\\{str\_start\_365},\39\\{str\_start\_366},\39\\{str\_start\_367},\39\\{str\_start\_368},\39\\{str\_start\_369},\39\\{str\_start\_370},\39\\{str\_start\_371},\39\\{str\_start\_372},\39\\{str\_start\_373},\39\\{str\_start\_374},\39\\{str\_start\_375},\39% +\\{str\_start\_376},\39\\{str\_start\_377},\39\\{str\_start\_378},\39\\{str\_start\_379},\39\\{str\_start\_380},\39\\{str\_start\_381},\39\\{str\_start\_382},\39\\{str\_start\_383},\39\\{str\_start\_384},\39\\{str\_start\_385},\39\\{str\_start\_386},\39% +\\{str\_start\_387},\39\\{str\_start\_388},\39\\{str\_start\_389},\39\\{str\_start\_390},\39\\{str\_start\_391},\39\\{str\_start\_392},\39\\{str\_start\_393},\39\\{str\_start\_394},\39\\{str\_start\_395},\39\\{str\_start\_396},\39\\{str\_start\_397},\39% +\\{str\_start\_398},\39\\{str\_start\_399},\39\\{str\_start\_400},\39\\{str\_start\_401},\39\\{str\_start\_402},\39\\{str\_start\_403},\39\\{str\_start\_404},\39\\{str\_start\_405},\39\\{str\_start\_406},\39\\{str\_start\_407},\39\\{str\_start\_408},\39% +\\{str\_start\_409},\39\\{str\_start\_410},\39\\{str\_start\_411},\39\\{str\_start\_412},\39\\{str\_start\_413},\39\\{str\_start\_414},\39\\{str\_start\_415},\39\\{str\_start\_416},\39\\{str\_start\_417},\39\\{str\_start\_418},\39\\{str\_start\_419},\39% +\\{str\_start\_420},\39\\{str\_start\_421},\39\\{str\_start\_422},\39\\{str\_start\_423},\39\\{str\_start\_424},\39\\{str\_start\_425},\39\\{str\_start\_426},\39\\{str\_start\_427},\39\\{str\_start\_428},\39\\{str\_start\_429},\39\\{str\_start\_430},\39% +\\{str\_start\_431},\39\\{str\_start\_432},\39\\{str\_start\_433},\39\\{str\_start\_434},\39\\{str\_start\_435},\39\\{str\_start\_436},\39\\{str\_start\_437},\39\\{str\_start\_438},\39\\{str\_start\_439},\39\\{str\_start\_440},\39\\{str\_start\_441},\39% +\\{str\_start\_442},\39\\{str\_start\_443},\39\\{str\_start\_444},\39\\{str\_start\_445},\39\\{str\_start\_446},\39\\{str\_start\_447},\39\\{str\_start\_448},\39\\{str\_start\_449},\39\\{str\_start\_450},\39\\{str\_start\_451},\39\\{str\_start\_452},\39% +\\{str\_start\_453},\39\\{str\_start\_454},\39\\{str\_start\_455},\39\\{str\_start\_456},\39\\{str\_start\_457},\39\\{str\_start\_458},\39\\{str\_start\_459},\39\\{str\_start\_460},\39\\{str\_start\_461},\39\\{str\_start\_462},\39\\{str\_start\_463},\39% +\\{str\_start\_464},\39\\{str\_start\_465},\39\\{str\_start\_466},\39\\{str\_start\_467},\39\\{str\_start\_468},\39\\{str\_start\_469},\39\\{str\_start\_470},\39\\{str\_start\_471},\39\\{str\_start\_472},\39\\{str\_start\_473},\39\\{str\_start\_474},\39% +\\{str\_start\_475},\39\\{str\_start\_476},\39\\{str\_start\_477},\39\\{str\_start\_478},\39\\{str\_start\_479},\39\\{str\_start\_480},\39\\{str\_start\_481},\39\\{str\_start\_482},\39\\{str\_start\_483},\39\\{str\_start\_484},\39\\{str\_start\_485},\39% +\\{str\_start\_486},\39\\{str\_start\_487},\39\\{str\_start\_488},\39\\{str\_start\_489},\39\\{str\_start\_490},\39\\{str\_start\_491},\39\\{str\_start\_492},\39\\{str\_start\_493},\39\\{str\_start\_494},\39\\{str\_start\_495},\39\\{str\_start\_496},\39% +\\{str\_start\_497},\39\\{str\_start\_498},\39\\{str\_start\_499},\39\\{str\_start\_500},\39\\{str\_start\_501},\39\\{str\_start\_502},\39\\{str\_start\_503},\39\\{str\_start\_504},\39\\{str\_start\_505},\39\\{str\_start\_506},\39\\{str\_start\_507},\39% +\\{str\_start\_508},\39\\{str\_start\_509},\39\\{str\_start\_510},\39\\{str\_start\_511},\39\\{str\_start\_512},\39\\{str\_start\_513},\39\\{str\_start\_514},\39\\{str\_start\_515},\39\\{str\_start\_516},\39\\{str\_start\_517},\39\\{str\_start\_518},\39% +\\{str\_start\_519},\39\\{str\_start\_520},\39\\{str\_start\_521},\39\\{str\_start\_522},\39\\{str\_start\_523},\39\\{str\_start\_524},\39\\{str\_start\_525},\39\\{str\_start\_526},\39\\{str\_start\_527},\39\\{str\_start\_528},\39\\{str\_start\_529},\39% +\\{str\_start\_530},\39\\{str\_start\_531},\39\\{str\_start\_532},\39\\{str\_start\_533},\39\\{str\_start\_534},\39\\{str\_start\_535},\39\\{str\_start\_536},\39\\{str\_start\_537},\39\\{str\_start\_538},\39\\{str\_start\_539},\39\\{str\_start\_540},\39% +\\{str\_start\_541},\39\\{str\_start\_542},\39\\{str\_start\_543},\39\\{str\_start\_544},\39\\{str\_start\_545},\39\\{str\_start\_546},\39\\{str\_start\_547},\39\\{str\_start\_548},\39\\{str\_start\_549},\39\\{str\_start\_550},\39\\{str\_start\_551},\39% +\\{str\_start\_552},\39\\{str\_start\_553},\39\\{str\_start\_554},\39\\{str\_start\_555},\39\\{str\_start\_556},\39\\{str\_start\_557},\39\\{str\_start\_558},\39\\{str\_start\_559},\39\\{str\_start\_560},\39\\{str\_start\_561},\39\\{str\_start\_562},\39% +\\{str\_start\_563},\39\\{str\_start\_564},\39\\{str\_start\_565},\39\\{str\_start\_566},\39\\{str\_start\_567},\39\\{str\_start\_568},\39\\{str\_start\_569},\39\\{str\_start\_570},\39\\{str\_start\_571},\39\\{str\_start\_572},\39\\{str\_start\_573},\39% +\\{str\_start\_574},\39\\{str\_start\_575},\39\\{str\_start\_576},\39\\{str\_start\_577},\39\\{str\_start\_578},\39\\{str\_start\_579},\39\\{str\_start\_580},\39\\{str\_start\_581},\39\\{str\_start\_582},\39\\{str\_start\_583},\39\\{str\_start\_584},\39% +\\{str\_start\_585},\39\\{str\_start\_586},\39\\{str\_start\_587},\39\\{str\_start\_588},\39\\{str\_start\_589},\39\\{str\_start\_590},\39\\{str\_start\_591},\39\\{str\_start\_592},\39\\{str\_start\_593},\39\\{str\_start\_594},\39\\{str\_start\_595},\39% +\\{str\_start\_596},\39\\{str\_start\_597},\39\\{str\_start\_598},\39\\{str\_start\_599},\39\\{str\_start\_600},\39\\{str\_start\_601},\39\\{str\_start\_602},\39\\{str\_start\_603},\39\\{str\_start\_604},\39\\{str\_start\_605},\39\\{str\_start\_606},\39% +\\{str\_start\_607},\39\\{str\_start\_608},\39\\{str\_start\_609},\39\\{str\_start\_610},\39\\{str\_start\_611},\39\\{str\_start\_612},\39\\{str\_start\_613},\39\\{str\_start\_614},\39\\{str\_start\_615},\39\\{str\_start\_616},\39\\{str\_start\_617},\39% +\\{str\_start\_618},\39\\{str\_start\_619},\39\\{str\_start\_620},\39\\{str\_start\_621},\39\\{str\_start\_622},\39\\{str\_start\_623},\39\\{str\_start\_624},\39\\{str\_start\_625},\39\\{str\_start\_626},\39\\{str\_start\_627},\39\\{str\_start\_628},\39% +\\{str\_start\_629},\39\\{str\_start\_630},\39\\{str\_start\_631},\39\\{str\_start\_632},\39\\{str\_start\_633},\39\\{str\_start\_634},\39\\{str\_start\_635},\39\\{str\_start\_636},\39\\{str\_start\_637},\39\\{str\_start\_638},\39\\{str\_start\_639},\39% +\\{str\_start\_640},\39\\{str\_start\_641},\39\\{str\_start\_642},\39\\{str\_start\_643},\39\\{str\_start\_644},\39\\{str\_start\_645},\39\\{str\_start\_646},\39\\{str\_start\_647},\39\\{str\_start\_648},\39\\{str\_start\_649},\39\\{str\_start\_650},\39% +\\{str\_start\_651},\39\\{str\_start\_652},\39\\{str\_start\_653},\39\\{str\_start\_654},\39\\{str\_start\_655},\39\\{str\_start\_656},\39\\{str\_start\_657},\39\\{str\_start\_658},\39\\{str\_start\_659},\39\\{str\_start\_660},\39\\{str\_start\_661},\39% +\\{str\_start\_662},\39\\{str\_start\_663},\39\\{str\_start\_664},\39\\{str\_start\_665},\39\\{str\_start\_666},\39\\{str\_start\_667},\39{}$\\{str\_start\_668}\par +\U39.\fi + +\M{1795}We still need to define the start locations of the strings. +\Y\B\4\X1795:prepare for string pool initialization\X${}\E{}$\6 +\&{typedef} \&{enum} ${}\{{}$\1\6 +${}\\{str\_start\_256}\K{}$\&{sizeof} (\\{str\_0\_255})${}-\T{1},\39\\{str\_start\_257}\K\\{str\_start\_256}+{}$\&{sizeof} (\\{str\_256})${}-\T{1},{}$\6 +\\{str\_start\_258}${}\K\\{str\_start\_257}+{}$\&{sizeof} (\\{str\_257})${}-\T{1},{}$\6 +\\{str\_start\_259}${}\K\\{str\_start\_258}+{}$\&{sizeof} (\\{str\_258})${}-\T{1},{}$\6 +\\{str\_start\_260}${}\K\\{str\_start\_259}+{}$\&{sizeof} (\\{str\_259})${}-\T{1},{}$\6 +\\{str\_start\_261}${}\K\\{str\_start\_260}+{}$\&{sizeof} (\\{str\_260})${}-\T{1},{}$\6 +\\{str\_start\_262}${}\K\\{str\_start\_261}+{}$\&{sizeof} (\\{str\_261})${}-\T{1},{}$\6 +\\{str\_start\_263}${}\K\\{str\_start\_262}+{}$\&{sizeof} (\\{str\_262})${}-\T{1},{}$\6 +\\{str\_start\_264}${}\K\\{str\_start\_263}+{}$\&{sizeof} (\\{str\_263})${}-\T{1},{}$\6 +\\{str\_start\_265}${}\K\\{str\_start\_264}+{}$\&{sizeof} (\\{str\_264})${}-\T{1},{}$\6 +\\{str\_start\_266}${}\K\\{str\_start\_265}+{}$\&{sizeof} (\\{str\_265})${}-\T{1},{}$\6 +\\{str\_start\_267}${}\K\\{str\_start\_266}+{}$\&{sizeof} (\\{str\_266})${}-\T{1},{}$\6 +\\{str\_start\_268}${}\K\\{str\_start\_267}+{}$\&{sizeof} (\\{str\_267})${}-\T{1},{}$\6 +\\{str\_start\_269}${}\K\\{str\_start\_268}+{}$\&{sizeof} (\\{str\_268})${}-\T{1},{}$\6 +\\{str\_start\_270}${}\K\\{str\_start\_269}+{}$\&{sizeof} (\\{str\_269})${}-\T{1},{}$\6 +\\{str\_start\_271}${}\K\\{str\_start\_270}+{}$\&{sizeof} (\\{str\_270})${}-\T{1},{}$\6 +\\{str\_start\_272}${}\K\\{str\_start\_271}+{}$\&{sizeof} (\\{str\_271})${}-\T{1},{}$\6 +\\{str\_start\_273}${}\K\\{str\_start\_272}+{}$\&{sizeof} (\\{str\_272})${}-\T{1},{}$\6 +\\{str\_start\_274}${}\K\\{str\_start\_273}+{}$\&{sizeof} (\\{str\_273})${}-\T{1},{}$\6 +\\{str\_start\_275}${}\K\\{str\_start\_274}+{}$\&{sizeof} (\\{str\_274})${}-\T{1},{}$\6 +\\{str\_start\_276}${}\K\\{str\_start\_275}+{}$\&{sizeof} (\\{str\_275})${}-\T{1},{}$\6 +\\{str\_start\_277}${}\K\\{str\_start\_276}+{}$\&{sizeof} (\\{str\_276})${}-\T{1},{}$\6 +\\{str\_start\_278}${}\K\\{str\_start\_277}+{}$\&{sizeof} (\\{str\_277})${}-\T{1},{}$\6 +\\{str\_start\_279}${}\K\\{str\_start\_278}+{}$\&{sizeof} (\\{str\_278})${}-\T{1},{}$\6 +\\{str\_start\_280}${}\K\\{str\_start\_279}+{}$\&{sizeof} (\\{str\_279})${}-\T{1},{}$\6 +\\{str\_start\_281}${}\K\\{str\_start\_280}+{}$\&{sizeof} (\\{str\_280})${}-\T{1},{}$\6 +\\{str\_start\_282}${}\K\\{str\_start\_281}+{}$\&{sizeof} (\\{str\_281})${}-\T{1},{}$\6 +\\{str\_start\_283}${}\K\\{str\_start\_282}+{}$\&{sizeof} (\\{str\_282})${}-\T{1},{}$\6 +\\{str\_start\_284}${}\K\\{str\_start\_283}+{}$\&{sizeof} (\\{str\_283})${}-\T{1},{}$\6 +\\{str\_start\_285}${}\K\\{str\_start\_284}+{}$\&{sizeof} (\\{str\_284})${}-\T{1},{}$\6 +\\{str\_start\_286}${}\K\\{str\_start\_285}+{}$\&{sizeof} (\\{str\_285})${}-\T{1},{}$\6 +\\{str\_start\_287}${}\K\\{str\_start\_286}+{}$\&{sizeof} (\\{str\_286})${}-\T{1},{}$\6 +\\{str\_start\_288}${}\K\\{str\_start\_287}+{}$\&{sizeof} (\\{str\_287})${}-\T{1},{}$\6 +\\{str\_start\_289}${}\K\\{str\_start\_288}+{}$\&{sizeof} (\\{str\_288})${}-\T{1},{}$\6 +\\{str\_start\_290}${}\K\\{str\_start\_289}+{}$\&{sizeof} (\\{str\_289})${}-\T{1},{}$\6 +\\{str\_start\_291}${}\K\\{str\_start\_290}+{}$\&{sizeof} (\\{str\_290})${}-\T{1},{}$\6 +\\{str\_start\_292}${}\K\\{str\_start\_291}+{}$\&{sizeof} (\\{str\_291})${}-\T{1},{}$\6 +\\{str\_start\_293}${}\K\\{str\_start\_292}+{}$\&{sizeof} (\\{str\_292})${}-\T{1},{}$\6 +\\{str\_start\_294}${}\K\\{str\_start\_293}+{}$\&{sizeof} (\\{str\_293})${}-\T{1},{}$\6 +\\{str\_start\_295}${}\K\\{str\_start\_294}+{}$\&{sizeof} (\\{str\_294})${}-\T{1},{}$\6 +\\{str\_start\_296}${}\K\\{str\_start\_295}+{}$\&{sizeof} (\\{str\_295})${}-\T{1},{}$\6 +\\{str\_start\_297}${}\K\\{str\_start\_296}+{}$\&{sizeof} (\\{str\_296})${}-\T{1},{}$\6 +\\{str\_start\_298}${}\K\\{str\_start\_297}+{}$\&{sizeof} (\\{str\_297})${}-\T{1},{}$\6 +\\{str\_start\_299}${}\K\\{str\_start\_298}+{}$\&{sizeof} (\\{str\_298})${}-\T{1},{}$\6 +\\{str\_start\_300}${}\K\\{str\_start\_299}+{}$\&{sizeof} (\\{str\_299})${}-\T{1},{}$\6 +\\{str\_start\_301}${}\K\\{str\_start\_300}+{}$\&{sizeof} (\\{str\_300})${}-\T{1},{}$\6 +\\{str\_start\_302}${}\K\\{str\_start\_301}+{}$\&{sizeof} (\\{str\_301})${}-\T{1},{}$\6 +\\{str\_start\_303}${}\K\\{str\_start\_302}+{}$\&{sizeof} (\\{str\_302})${}-\T{1},{}$\6 +\\{str\_start\_304}${}\K\\{str\_start\_303}+{}$\&{sizeof} (\\{str\_303})${}-\T{1},{}$\6 +\\{str\_start\_305}${}\K\\{str\_start\_304}+{}$\&{sizeof} (\\{str\_304})${}-\T{1},{}$\6 +\\{str\_start\_306}${}\K\\{str\_start\_305}+{}$\&{sizeof} (\\{str\_305})${}-\T{1},{}$\6 +\\{str\_start\_307}${}\K\\{str\_start\_306}+{}$\&{sizeof} (\\{str\_306})${}-\T{1},{}$\6 +\\{str\_start\_308}${}\K\\{str\_start\_307}+{}$\&{sizeof} (\\{str\_307})${}-\T{1},{}$\6 +\\{str\_start\_309}${}\K\\{str\_start\_308}+{}$\&{sizeof} (\\{str\_308})${}-\T{1},{}$\6 +\\{str\_start\_310}${}\K\\{str\_start\_309}+{}$\&{sizeof} (\\{str\_309})${}-\T{1},{}$\6 +\\{str\_start\_311}${}\K\\{str\_start\_310}+{}$\&{sizeof} (\\{str\_310})${}-\T{1},{}$\6 +\\{str\_start\_312}${}\K\\{str\_start\_311}+{}$\&{sizeof} (\\{str\_311})${}-\T{1},{}$\6 +\\{str\_start\_313}${}\K\\{str\_start\_312}+{}$\&{sizeof} (\\{str\_312})${}-\T{1},{}$\6 +\\{str\_start\_314}${}\K\\{str\_start\_313}+{}$\&{sizeof} (\\{str\_313})${}-\T{1},{}$\6 +\\{str\_start\_315}${}\K\\{str\_start\_314}+{}$\&{sizeof} (\\{str\_314})${}-\T{1},{}$\6 +\\{str\_start\_316}${}\K\\{str\_start\_315}+{}$\&{sizeof} (\\{str\_315})${}-\T{1},{}$\6 +\\{str\_start\_317}${}\K\\{str\_start\_316}+{}$\&{sizeof} (\\{str\_316})${}-\T{1},{}$\6 +\\{str\_start\_318}${}\K\\{str\_start\_317}+{}$\&{sizeof} (\\{str\_317})${}-\T{1},{}$\6 +\\{str\_start\_319}${}\K\\{str\_start\_318}+{}$\&{sizeof} (\\{str\_318})${}-\T{1},{}$\6 +\\{str\_start\_320}${}\K\\{str\_start\_319}+{}$\&{sizeof} (\\{str\_319})${}-\T{1},{}$\6 +\\{str\_start\_321}${}\K\\{str\_start\_320}+{}$\&{sizeof} (\\{str\_320})${}-\T{1},{}$\6 +\\{str\_start\_322}${}\K\\{str\_start\_321}+{}$\&{sizeof} (\\{str\_321})${}-\T{1},{}$\6 +\\{str\_start\_323}${}\K\\{str\_start\_322}+{}$\&{sizeof} (\\{str\_322})${}-\T{1},{}$\6 +\\{str\_start\_324}${}\K\\{str\_start\_323}+{}$\&{sizeof} (\\{str\_323})${}-\T{1},{}$\6 +\\{str\_start\_325}${}\K\\{str\_start\_324}+{}$\&{sizeof} (\\{str\_324})${}-\T{1},{}$\6 +\\{str\_start\_326}${}\K\\{str\_start\_325}+{}$\&{sizeof} (\\{str\_325})${}-\T{1},{}$\6 +\\{str\_start\_327}${}\K\\{str\_start\_326}+{}$\&{sizeof} (\\{str\_326})${}-\T{1},{}$\6 +\\{str\_start\_328}${}\K\\{str\_start\_327}+{}$\&{sizeof} (\\{str\_327})${}-\T{1},{}$\6 +\\{str\_start\_329}${}\K\\{str\_start\_328}+{}$\&{sizeof} (\\{str\_328})${}-\T{1},{}$\6 +\\{str\_start\_330}${}\K\\{str\_start\_329}+{}$\&{sizeof} (\\{str\_329})${}-\T{1},{}$\6 +\\{str\_start\_331}${}\K\\{str\_start\_330}+{}$\&{sizeof} (\\{str\_330})${}-\T{1},{}$\6 +\\{str\_start\_332}${}\K\\{str\_start\_331}+{}$\&{sizeof} (\\{str\_331})${}-\T{1},{}$\6 +\\{str\_start\_333}${}\K\\{str\_start\_332}+{}$\&{sizeof} (\\{str\_332})${}-\T{1},{}$\6 +\\{str\_start\_334}${}\K\\{str\_start\_333}+{}$\&{sizeof} (\\{str\_333})${}-\T{1},{}$\6 +\\{str\_start\_335}${}\K\\{str\_start\_334}+{}$\&{sizeof} (\\{str\_334})${}-\T{1},{}$\6 +\\{str\_start\_336}${}\K\\{str\_start\_335}+{}$\&{sizeof} (\\{str\_335})${}-\T{1},{}$\6 +\\{str\_start\_337}${}\K\\{str\_start\_336}+{}$\&{sizeof} (\\{str\_336})${}-\T{1},{}$\6 +\\{str\_start\_338}${}\K\\{str\_start\_337}+{}$\&{sizeof} (\\{str\_337})${}-\T{1},{}$\6 +\\{str\_start\_339}${}\K\\{str\_start\_338}+{}$\&{sizeof} (\\{str\_338})${}-\T{1},{}$\6 +\\{str\_start\_340}${}\K\\{str\_start\_339}+{}$\&{sizeof} (\\{str\_339})${}-\T{1},{}$\6 +\\{str\_start\_341}${}\K\\{str\_start\_340}+{}$\&{sizeof} (\\{str\_340})${}-\T{1},{}$\6 +\\{str\_start\_342}${}\K\\{str\_start\_341}+{}$\&{sizeof} (\\{str\_341})${}-\T{1},{}$\6 +\\{str\_start\_343}${}\K\\{str\_start\_342}+{}$\&{sizeof} (\\{str\_342})${}-\T{1},{}$\6 +\\{str\_start\_344}${}\K\\{str\_start\_343}+{}$\&{sizeof} (\\{str\_343})${}-\T{1},{}$\6 +\\{str\_start\_345}${}\K\\{str\_start\_344}+{}$\&{sizeof} (\\{str\_344})${}-\T{1},{}$\6 +\\{str\_start\_346}${}\K\\{str\_start\_345}+{}$\&{sizeof} (\\{str\_345})${}-\T{1},{}$\6 +\\{str\_start\_347}${}\K\\{str\_start\_346}+{}$\&{sizeof} (\\{str\_346})${}-\T{1},{}$\6 +\\{str\_start\_348}${}\K\\{str\_start\_347}+{}$\&{sizeof} (\\{str\_347})${}-\T{1},{}$\6 +\\{str\_start\_349}${}\K\\{str\_start\_348}+{}$\&{sizeof} (\\{str\_348})${}-\T{1},{}$\6 +\\{str\_start\_350}${}\K\\{str\_start\_349}+{}$\&{sizeof} (\\{str\_349})${}-\T{1},{}$\6 +\\{str\_start\_351}${}\K\\{str\_start\_350}+{}$\&{sizeof} (\\{str\_350})${}-\T{1},{}$\6 +\\{str\_start\_352}${}\K\\{str\_start\_351}+{}$\&{sizeof} (\\{str\_351})${}-\T{1},{}$\6 +\\{str\_start\_353}${}\K\\{str\_start\_352}+{}$\&{sizeof} (\\{str\_352})${}-\T{1},{}$\6 +\\{str\_start\_354}${}\K\\{str\_start\_353}+{}$\&{sizeof} (\\{str\_353})${}-\T{1},{}$\6 +\\{str\_start\_355}${}\K\\{str\_start\_354}+{}$\&{sizeof} (\\{str\_354})${}-\T{1},{}$\6 +\\{str\_start\_356}${}\K\\{str\_start\_355}+{}$\&{sizeof} (\\{str\_355})${}-\T{1},{}$\6 +\\{str\_start\_357}${}\K\\{str\_start\_356}+{}$\&{sizeof} (\\{str\_356})${}-\T{1},{}$\6 +\\{str\_start\_358}${}\K\\{str\_start\_357}+{}$\&{sizeof} (\\{str\_357})${}-\T{1},{}$\6 +\\{str\_start\_359}${}\K\\{str\_start\_358}+{}$\&{sizeof} (\\{str\_358})${}-\T{1},{}$\6 +\\{str\_start\_360}${}\K\\{str\_start\_359}+{}$\&{sizeof} (\\{str\_359})${}-\T{1},{}$\6 +\\{str\_start\_361}${}\K\\{str\_start\_360}+{}$\&{sizeof} (\\{str\_360})${}-\T{1},{}$\6 +\\{str\_start\_362}${}\K\\{str\_start\_361}+{}$\&{sizeof} (\\{str\_361})${}-\T{1},{}$\6 +\\{str\_start\_363}${}\K\\{str\_start\_362}+{}$\&{sizeof} (\\{str\_362})${}-\T{1},{}$\6 +\\{str\_start\_364}${}\K\\{str\_start\_363}+{}$\&{sizeof} (\\{str\_363})${}-\T{1},{}$\6 +\\{str\_start\_365}${}\K\\{str\_start\_364}+{}$\&{sizeof} (\\{str\_364})${}-\T{1},{}$\6 +\\{str\_start\_366}${}\K\\{str\_start\_365}+{}$\&{sizeof} (\\{str\_365})${}-\T{1},{}$\6 +\\{str\_start\_367}${}\K\\{str\_start\_366}+{}$\&{sizeof} (\\{str\_366})${}-\T{1},{}$\6 +\\{str\_start\_368}${}\K\\{str\_start\_367}+{}$\&{sizeof} (\\{str\_367})${}-\T{1},{}$\6 +\\{str\_start\_369}${}\K\\{str\_start\_368}+{}$\&{sizeof} (\\{str\_368})${}-\T{1},{}$\6 +\\{str\_start\_370}${}\K\\{str\_start\_369}+{}$\&{sizeof} (\\{str\_369})${}-\T{1},{}$\6 +\\{str\_start\_371}${}\K\\{str\_start\_370}+{}$\&{sizeof} (\\{str\_370})${}-\T{1},{}$\6 +\\{str\_start\_372}${}\K\\{str\_start\_371}+{}$\&{sizeof} (\\{str\_371})${}-\T{1},{}$\6 +\\{str\_start\_373}${}\K\\{str\_start\_372}+{}$\&{sizeof} (\\{str\_372})${}-\T{1},{}$\6 +\\{str\_start\_374}${}\K\\{str\_start\_373}+{}$\&{sizeof} (\\{str\_373})${}-\T{1},{}$\6 +\\{str\_start\_375}${}\K\\{str\_start\_374}+{}$\&{sizeof} (\\{str\_374})${}-\T{1},{}$\6 +\\{str\_start\_376}${}\K\\{str\_start\_375}+{}$\&{sizeof} (\\{str\_375})${}-\T{1},{}$\6 +\\{str\_start\_377}${}\K\\{str\_start\_376}+{}$\&{sizeof} (\\{str\_376})${}-\T{1},{}$\6 +\\{str\_start\_378}${}\K\\{str\_start\_377}+{}$\&{sizeof} (\\{str\_377})${}-\T{1},{}$\6 +\\{str\_start\_379}${}\K\\{str\_start\_378}+{}$\&{sizeof} (\\{str\_378})${}-\T{1},{}$\6 +\\{str\_start\_380}${}\K\\{str\_start\_379}+{}$\&{sizeof} (\\{str\_379})${}-\T{1},{}$\6 +\\{str\_start\_381}${}\K\\{str\_start\_380}+{}$\&{sizeof} (\\{str\_380})${}-\T{1},{}$\6 +\\{str\_start\_382}${}\K\\{str\_start\_381}+{}$\&{sizeof} (\\{str\_381})${}-\T{1},{}$\6 +\\{str\_start\_383}${}\K\\{str\_start\_382}+{}$\&{sizeof} (\\{str\_382})${}-\T{1},{}$\6 +\\{str\_start\_384}${}\K\\{str\_start\_383}+{}$\&{sizeof} (\\{str\_383})${}-\T{1},{}$\6 +\\{str\_start\_385}${}\K\\{str\_start\_384}+{}$\&{sizeof} (\\{str\_384})${}-\T{1},{}$\6 +\\{str\_start\_386}${}\K\\{str\_start\_385}+{}$\&{sizeof} (\\{str\_385})${}-\T{1},{}$\6 +\\{str\_start\_387}${}\K\\{str\_start\_386}+{}$\&{sizeof} (\\{str\_386})${}-\T{1},{}$\6 +\\{str\_start\_388}${}\K\\{str\_start\_387}+{}$\&{sizeof} (\\{str\_387})${}-\T{1},{}$\6 +\\{str\_start\_389}${}\K\\{str\_start\_388}+{}$\&{sizeof} (\\{str\_388})${}-\T{1},{}$\6 +\\{str\_start\_390}${}\K\\{str\_start\_389}+{}$\&{sizeof} (\\{str\_389})${}-\T{1},{}$\6 +\\{str\_start\_391}${}\K\\{str\_start\_390}+{}$\&{sizeof} (\\{str\_390})${}-\T{1},{}$\6 +\\{str\_start\_392}${}\K\\{str\_start\_391}+{}$\&{sizeof} (\\{str\_391})${}-\T{1},{}$\6 +\\{str\_start\_393}${}\K\\{str\_start\_392}+{}$\&{sizeof} (\\{str\_392})${}-\T{1},{}$\6 +\\{str\_start\_394}${}\K\\{str\_start\_393}+{}$\&{sizeof} (\\{str\_393})${}-\T{1},{}$\6 +\\{str\_start\_395}${}\K\\{str\_start\_394}+{}$\&{sizeof} (\\{str\_394})${}-\T{1},{}$\6 +\\{str\_start\_396}${}\K\\{str\_start\_395}+{}$\&{sizeof} (\\{str\_395})${}-\T{1},{}$\6 +\\{str\_start\_397}${}\K\\{str\_start\_396}+{}$\&{sizeof} (\\{str\_396})${}-\T{1},{}$\6 +\\{str\_start\_398}${}\K\\{str\_start\_397}+{}$\&{sizeof} (\\{str\_397})${}-\T{1},{}$\6 +\\{str\_start\_399}${}\K\\{str\_start\_398}+{}$\&{sizeof} (\\{str\_398})${}-\T{1},{}$\6 +\\{str\_start\_400}${}\K\\{str\_start\_399}+{}$\&{sizeof} (\\{str\_399})${}-\T{1},{}$\6 +\\{str\_start\_401}${}\K\\{str\_start\_400}+{}$\&{sizeof} (\\{str\_400})${}-\T{1},{}$\6 +\\{str\_start\_402}${}\K\\{str\_start\_401}+{}$\&{sizeof} (\\{str\_401})${}-\T{1},{}$\6 +\\{str\_start\_403}${}\K\\{str\_start\_402}+{}$\&{sizeof} (\\{str\_402})${}-\T{1},{}$\6 +\\{str\_start\_404}${}\K\\{str\_start\_403}+{}$\&{sizeof} (\\{str\_403})${}-\T{1},{}$\6 +\\{str\_start\_405}${}\K\\{str\_start\_404}+{}$\&{sizeof} (\\{str\_404})${}-\T{1},{}$\6 +\\{str\_start\_406}${}\K\\{str\_start\_405}+{}$\&{sizeof} (\\{str\_405})${}-\T{1},{}$\6 +\\{str\_start\_407}${}\K\\{str\_start\_406}+{}$\&{sizeof} (\\{str\_406})${}-\T{1},{}$\6 +\\{str\_start\_408}${}\K\\{str\_start\_407}+{}$\&{sizeof} (\\{str\_407})${}-\T{1},{}$\6 +\\{str\_start\_409}${}\K\\{str\_start\_408}+{}$\&{sizeof} (\\{str\_408})${}-\T{1},{}$\6 +\\{str\_start\_410}${}\K\\{str\_start\_409}+{}$\&{sizeof} (\\{str\_409})${}-\T{1},{}$\6 +\\{str\_start\_411}${}\K\\{str\_start\_410}+{}$\&{sizeof} (\\{str\_410})${}-\T{1},{}$\6 +\\{str\_start\_412}${}\K\\{str\_start\_411}+{}$\&{sizeof} (\\{str\_411})${}-\T{1},{}$\6 +\\{str\_start\_413}${}\K\\{str\_start\_412}+{}$\&{sizeof} (\\{str\_412})${}-\T{1},{}$\6 +\\{str\_start\_414}${}\K\\{str\_start\_413}+{}$\&{sizeof} (\\{str\_413})${}-\T{1},{}$\6 +\\{str\_start\_415}${}\K\\{str\_start\_414}+{}$\&{sizeof} (\\{str\_414})${}-\T{1},{}$\6 +\\{str\_start\_416}${}\K\\{str\_start\_415}+{}$\&{sizeof} (\\{str\_415})${}-\T{1},{}$\6 +\\{str\_start\_417}${}\K\\{str\_start\_416}+{}$\&{sizeof} (\\{str\_416})${}-\T{1},{}$\6 +\\{str\_start\_418}${}\K\\{str\_start\_417}+{}$\&{sizeof} (\\{str\_417})${}-\T{1},{}$\6 +\\{str\_start\_419}${}\K\\{str\_start\_418}+{}$\&{sizeof} (\\{str\_418})${}-\T{1},{}$\6 +\\{str\_start\_420}${}\K\\{str\_start\_419}+{}$\&{sizeof} (\\{str\_419})${}-\T{1},{}$\6 +\\{str\_start\_421}${}\K\\{str\_start\_420}+{}$\&{sizeof} (\\{str\_420})${}-\T{1},{}$\6 +\\{str\_start\_422}${}\K\\{str\_start\_421}+{}$\&{sizeof} (\\{str\_421})${}-\T{1},{}$\6 +\\{str\_start\_423}${}\K\\{str\_start\_422}+{}$\&{sizeof} (\\{str\_422})${}-\T{1},{}$\6 +\\{str\_start\_424}${}\K\\{str\_start\_423}+{}$\&{sizeof} (\\{str\_423})${}-\T{1},{}$\6 +\\{str\_start\_425}${}\K\\{str\_start\_424}+{}$\&{sizeof} (\\{str\_424})${}-\T{1},{}$\6 +\\{str\_start\_426}${}\K\\{str\_start\_425}+{}$\&{sizeof} (\\{str\_425})${}-\T{1},{}$\6 +\\{str\_start\_427}${}\K\\{str\_start\_426}+{}$\&{sizeof} (\\{str\_426})${}-\T{1},{}$\6 +\\{str\_start\_428}${}\K\\{str\_start\_427}+{}$\&{sizeof} (\\{str\_427})${}-\T{1},{}$\6 +\\{str\_start\_429}${}\K\\{str\_start\_428}+{}$\&{sizeof} (\\{str\_428})${}-\T{1},{}$\6 +\\{str\_start\_430}${}\K\\{str\_start\_429}+{}$\&{sizeof} (\\{str\_429})${}-\T{1},{}$\6 +\\{str\_start\_431}${}\K\\{str\_start\_430}+{}$\&{sizeof} (\\{str\_430})${}-\T{1},{}$\6 +\\{str\_start\_432}${}\K\\{str\_start\_431}+{}$\&{sizeof} (\\{str\_431})${}-\T{1},{}$\6 +\\{str\_start\_433}${}\K\\{str\_start\_432}+{}$\&{sizeof} (\\{str\_432})${}-\T{1},{}$\6 +\\{str\_start\_434}${}\K\\{str\_start\_433}+{}$\&{sizeof} (\\{str\_433})${}-\T{1},{}$\6 +\\{str\_start\_435}${}\K\\{str\_start\_434}+{}$\&{sizeof} (\\{str\_434})${}-\T{1},{}$\6 +\\{str\_start\_436}${}\K\\{str\_start\_435}+{}$\&{sizeof} (\\{str\_435})${}-\T{1},{}$\6 +\\{str\_start\_437}${}\K\\{str\_start\_436}+{}$\&{sizeof} (\\{str\_436})${}-\T{1},{}$\6 +\\{str\_start\_438}${}\K\\{str\_start\_437}+{}$\&{sizeof} (\\{str\_437})${}-\T{1},{}$\6 +\\{str\_start\_439}${}\K\\{str\_start\_438}+{}$\&{sizeof} (\\{str\_438})${}-\T{1},{}$\6 +\\{str\_start\_440}${}\K\\{str\_start\_439}+{}$\&{sizeof} (\\{str\_439})${}-\T{1},{}$\6 +\\{str\_start\_441}${}\K\\{str\_start\_440}+{}$\&{sizeof} (\\{str\_440})${}-\T{1},{}$\6 +\\{str\_start\_442}${}\K\\{str\_start\_441}+{}$\&{sizeof} (\\{str\_441})${}-\T{1},{}$\6 +\\{str\_start\_443}${}\K\\{str\_start\_442}+{}$\&{sizeof} (\\{str\_442})${}-\T{1},{}$\6 +\\{str\_start\_444}${}\K\\{str\_start\_443}+{}$\&{sizeof} (\\{str\_443})${}-\T{1},{}$\6 +\\{str\_start\_445}${}\K\\{str\_start\_444}+{}$\&{sizeof} (\\{str\_444})${}-\T{1},{}$\6 +\\{str\_start\_446}${}\K\\{str\_start\_445}+{}$\&{sizeof} (\\{str\_445})${}-\T{1},{}$\6 +\\{str\_start\_447}${}\K\\{str\_start\_446}+{}$\&{sizeof} (\\{str\_446})${}-\T{1},{}$\6 +\\{str\_start\_448}${}\K\\{str\_start\_447}+{}$\&{sizeof} (\\{str\_447})${}-\T{1},{}$\6 +\\{str\_start\_449}${}\K\\{str\_start\_448}+{}$\&{sizeof} (\\{str\_448})${}-\T{1},{}$\6 +\\{str\_start\_450}${}\K\\{str\_start\_449}+{}$\&{sizeof} (\\{str\_449})${}-\T{1},{}$\6 +\\{str\_start\_451}${}\K\\{str\_start\_450}+{}$\&{sizeof} (\\{str\_450})${}-\T{1},{}$\6 +\\{str\_start\_452}${}\K\\{str\_start\_451}+{}$\&{sizeof} (\\{str\_451})${}-\T{1},{}$\6 +\\{str\_start\_453}${}\K\\{str\_start\_452}+{}$\&{sizeof} (\\{str\_452})${}-\T{1},{}$\6 +\\{str\_start\_454}${}\K\\{str\_start\_453}+{}$\&{sizeof} (\\{str\_453})${}-\T{1},{}$\6 +\\{str\_start\_455}${}\K\\{str\_start\_454}+{}$\&{sizeof} (\\{str\_454})${}-\T{1},{}$\6 +\\{str\_start\_456}${}\K\\{str\_start\_455}+{}$\&{sizeof} (\\{str\_455})${}-\T{1},{}$\6 +\\{str\_start\_457}${}\K\\{str\_start\_456}+{}$\&{sizeof} (\\{str\_456})${}-\T{1},{}$\6 +\\{str\_start\_458}${}\K\\{str\_start\_457}+{}$\&{sizeof} (\\{str\_457})${}-\T{1},{}$\6 +\\{str\_start\_459}${}\K\\{str\_start\_458}+{}$\&{sizeof} (\\{str\_458})${}-\T{1},{}$\6 +\\{str\_start\_460}${}\K\\{str\_start\_459}+{}$\&{sizeof} (\\{str\_459})${}-\T{1},{}$\6 +\\{str\_start\_461}${}\K\\{str\_start\_460}+{}$\&{sizeof} (\\{str\_460})${}-\T{1},{}$\6 +\\{str\_start\_462}${}\K\\{str\_start\_461}+{}$\&{sizeof} (\\{str\_461})${}-\T{1},{}$\6 +\\{str\_start\_463}${}\K\\{str\_start\_462}+{}$\&{sizeof} (\\{str\_462})${}-\T{1},{}$\6 +\\{str\_start\_464}${}\K\\{str\_start\_463}+{}$\&{sizeof} (\\{str\_463})${}-\T{1},{}$\6 +\\{str\_start\_465}${}\K\\{str\_start\_464}+{}$\&{sizeof} (\\{str\_464})${}-\T{1},{}$\6 +\\{str\_start\_466}${}\K\\{str\_start\_465}+{}$\&{sizeof} (\\{str\_465})${}-\T{1},{}$\6 +\\{str\_start\_467}${}\K\\{str\_start\_466}+{}$\&{sizeof} (\\{str\_466})${}-\T{1},{}$\6 +\\{str\_start\_468}${}\K\\{str\_start\_467}+{}$\&{sizeof} (\\{str\_467})${}-\T{1},{}$\6 +\\{str\_start\_469}${}\K\\{str\_start\_468}+{}$\&{sizeof} (\\{str\_468})${}-\T{1},{}$\6 +\\{str\_start\_470}${}\K\\{str\_start\_469}+{}$\&{sizeof} (\\{str\_469})${}-\T{1},{}$\6 +\\{str\_start\_471}${}\K\\{str\_start\_470}+{}$\&{sizeof} (\\{str\_470})${}-\T{1},{}$\6 +\\{str\_start\_472}${}\K\\{str\_start\_471}+{}$\&{sizeof} (\\{str\_471})${}-\T{1},{}$\6 +\\{str\_start\_473}${}\K\\{str\_start\_472}+{}$\&{sizeof} (\\{str\_472})${}-\T{1},{}$\6 +\\{str\_start\_474}${}\K\\{str\_start\_473}+{}$\&{sizeof} (\\{str\_473})${}-\T{1},{}$\6 +\\{str\_start\_475}${}\K\\{str\_start\_474}+{}$\&{sizeof} (\\{str\_474})${}-\T{1},{}$\6 +\\{str\_start\_476}${}\K\\{str\_start\_475}+{}$\&{sizeof} (\\{str\_475})${}-\T{1},{}$\6 +\\{str\_start\_477}${}\K\\{str\_start\_476}+{}$\&{sizeof} (\\{str\_476})${}-\T{1},{}$\6 +\\{str\_start\_478}${}\K\\{str\_start\_477}+{}$\&{sizeof} (\\{str\_477})${}-\T{1},{}$\6 +\\{str\_start\_479}${}\K\\{str\_start\_478}+{}$\&{sizeof} (\\{str\_478})${}-\T{1},{}$\6 +\\{str\_start\_480}${}\K\\{str\_start\_479}+{}$\&{sizeof} (\\{str\_479})${}-\T{1},{}$\6 +\\{str\_start\_481}${}\K\\{str\_start\_480}+{}$\&{sizeof} (\\{str\_480})${}-\T{1},{}$\6 +\\{str\_start\_482}${}\K\\{str\_start\_481}+{}$\&{sizeof} (\\{str\_481})${}-\T{1},{}$\6 +\\{str\_start\_483}${}\K\\{str\_start\_482}+{}$\&{sizeof} (\\{str\_482})${}-\T{1},{}$\6 +\\{str\_start\_484}${}\K\\{str\_start\_483}+{}$\&{sizeof} (\\{str\_483})${}-\T{1},{}$\6 +\\{str\_start\_485}${}\K\\{str\_start\_484}+{}$\&{sizeof} (\\{str\_484})${}-\T{1},{}$\6 +\\{str\_start\_486}${}\K\\{str\_start\_485}+{}$\&{sizeof} (\\{str\_485})${}-\T{1},{}$\6 +\\{str\_start\_487}${}\K\\{str\_start\_486}+{}$\&{sizeof} (\\{str\_486})${}-\T{1},{}$\6 +\\{str\_start\_488}${}\K\\{str\_start\_487}+{}$\&{sizeof} (\\{str\_487})${}-\T{1},{}$\6 +\\{str\_start\_489}${}\K\\{str\_start\_488}+{}$\&{sizeof} (\\{str\_488})${}-\T{1},{}$\6 +\\{str\_start\_490}${}\K\\{str\_start\_489}+{}$\&{sizeof} (\\{str\_489})${}-\T{1},{}$\6 +\\{str\_start\_491}${}\K\\{str\_start\_490}+{}$\&{sizeof} (\\{str\_490})${}-\T{1},{}$\6 +\\{str\_start\_492}${}\K\\{str\_start\_491}+{}$\&{sizeof} (\\{str\_491})${}-\T{1},{}$\6 +\\{str\_start\_493}${}\K\\{str\_start\_492}+{}$\&{sizeof} (\\{str\_492})${}-\T{1},{}$\6 +\\{str\_start\_494}${}\K\\{str\_start\_493}+{}$\&{sizeof} (\\{str\_493})${}-\T{1},{}$\6 +\\{str\_start\_495}${}\K\\{str\_start\_494}+{}$\&{sizeof} (\\{str\_494})${}-\T{1},{}$\6 +\\{str\_start\_496}${}\K\\{str\_start\_495}+{}$\&{sizeof} (\\{str\_495})${}-\T{1},{}$\6 +\\{str\_start\_497}${}\K\\{str\_start\_496}+{}$\&{sizeof} (\\{str\_496})${}-\T{1},{}$\6 +\\{str\_start\_498}${}\K\\{str\_start\_497}+{}$\&{sizeof} (\\{str\_497})${}-\T{1},{}$\6 +\\{str\_start\_499}${}\K\\{str\_start\_498}+{}$\&{sizeof} (\\{str\_498})${}-\T{1},{}$\6 +\\{str\_start\_500}${}\K\\{str\_start\_499}+{}$\&{sizeof} (\\{str\_499})${}-\T{1},{}$\6 +\\{str\_start\_501}${}\K\\{str\_start\_500}+{}$\&{sizeof} (\\{str\_500})${}-\T{1},{}$\6 +\\{str\_start\_502}${}\K\\{str\_start\_501}+{}$\&{sizeof} (\\{str\_501})${}-\T{1},{}$\6 +\\{str\_start\_503}${}\K\\{str\_start\_502}+{}$\&{sizeof} (\\{str\_502})${}-\T{1},{}$\6 +\\{str\_start\_504}${}\K\\{str\_start\_503}+{}$\&{sizeof} (\\{str\_503})${}-\T{1},{}$\6 +\\{str\_start\_505}${}\K\\{str\_start\_504}+{}$\&{sizeof} (\\{str\_504})${}-\T{1},{}$\6 +\\{str\_start\_506}${}\K\\{str\_start\_505}+{}$\&{sizeof} (\\{str\_505})${}-\T{1},{}$\6 +\\{str\_start\_507}${}\K\\{str\_start\_506}+{}$\&{sizeof} (\\{str\_506})${}-\T{1},{}$\6 +\\{str\_start\_508}${}\K\\{str\_start\_507}+{}$\&{sizeof} (\\{str\_507})${}-\T{1},{}$\6 +\\{str\_start\_509}${}\K\\{str\_start\_508}+{}$\&{sizeof} (\\{str\_508})${}-\T{1},{}$\6 +\\{str\_start\_510}${}\K\\{str\_start\_509}+{}$\&{sizeof} (\\{str\_509})${}-\T{1},{}$\6 +\\{str\_start\_511}${}\K\\{str\_start\_510}+{}$\&{sizeof} (\\{str\_510})${}-\T{1},{}$\6 +\\{str\_start\_512}${}\K\\{str\_start\_511}+{}$\&{sizeof} (\\{str\_511})${}-\T{1},{}$\6 +\\{str\_start\_513}${}\K\\{str\_start\_512}+{}$\&{sizeof} (\\{str\_512})${}-\T{1},{}$\6 +\\{str\_start\_514}${}\K\\{str\_start\_513}+{}$\&{sizeof} (\\{str\_513})${}-\T{1},{}$\6 +\\{str\_start\_515}${}\K\\{str\_start\_514}+{}$\&{sizeof} (\\{str\_514})${}-\T{1},{}$\6 +\\{str\_start\_516}${}\K\\{str\_start\_515}+{}$\&{sizeof} (\\{str\_515})${}-\T{1},{}$\6 +\\{str\_start\_517}${}\K\\{str\_start\_516}+{}$\&{sizeof} (\\{str\_516})${}-\T{1},{}$\6 +\\{str\_start\_518}${}\K\\{str\_start\_517}+{}$\&{sizeof} (\\{str\_517})${}-\T{1},{}$\6 +\\{str\_start\_519}${}\K\\{str\_start\_518}+{}$\&{sizeof} (\\{str\_518})${}-\T{1},{}$\6 +\\{str\_start\_520}${}\K\\{str\_start\_519}+{}$\&{sizeof} (\\{str\_519})${}-\T{1},{}$\6 +\\{str\_start\_521}${}\K\\{str\_start\_520}+{}$\&{sizeof} (\\{str\_520})${}-\T{1},{}$\6 +\\{str\_start\_522}${}\K\\{str\_start\_521}+{}$\&{sizeof} (\\{str\_521})${}-\T{1},{}$\6 +\\{str\_start\_523}${}\K\\{str\_start\_522}+{}$\&{sizeof} (\\{str\_522})${}-\T{1},{}$\6 +\\{str\_start\_524}${}\K\\{str\_start\_523}+{}$\&{sizeof} (\\{str\_523})${}-\T{1},{}$\6 +\\{str\_start\_525}${}\K\\{str\_start\_524}+{}$\&{sizeof} (\\{str\_524})${}-\T{1},{}$\6 +\\{str\_start\_526}${}\K\\{str\_start\_525}+{}$\&{sizeof} (\\{str\_525})${}-\T{1},{}$\6 +\\{str\_start\_527}${}\K\\{str\_start\_526}+{}$\&{sizeof} (\\{str\_526})${}-\T{1},{}$\6 +\\{str\_start\_528}${}\K\\{str\_start\_527}+{}$\&{sizeof} (\\{str\_527})${}-\T{1},{}$\6 +\\{str\_start\_529}${}\K\\{str\_start\_528}+{}$\&{sizeof} (\\{str\_528})${}-\T{1},{}$\6 +\\{str\_start\_530}${}\K\\{str\_start\_529}+{}$\&{sizeof} (\\{str\_529})${}-\T{1},{}$\6 +\\{str\_start\_531}${}\K\\{str\_start\_530}+{}$\&{sizeof} (\\{str\_530})${}-\T{1},{}$\6 +\\{str\_start\_532}${}\K\\{str\_start\_531}+{}$\&{sizeof} (\\{str\_531})${}-\T{1},{}$\6 +\\{str\_start\_533}${}\K\\{str\_start\_532}+{}$\&{sizeof} (\\{str\_532})${}-\T{1},{}$\6 +\\{str\_start\_534}${}\K\\{str\_start\_533}+{}$\&{sizeof} (\\{str\_533})${}-\T{1},{}$\6 +\\{str\_start\_535}${}\K\\{str\_start\_534}+{}$\&{sizeof} (\\{str\_534})${}-\T{1},{}$\6 +\\{str\_start\_536}${}\K\\{str\_start\_535}+{}$\&{sizeof} (\\{str\_535})${}-\T{1},{}$\6 +\\{str\_start\_537}${}\K\\{str\_start\_536}+{}$\&{sizeof} (\\{str\_536})${}-\T{1},{}$\6 +\\{str\_start\_538}${}\K\\{str\_start\_537}+{}$\&{sizeof} (\\{str\_537})${}-\T{1},{}$\6 +\\{str\_start\_539}${}\K\\{str\_start\_538}+{}$\&{sizeof} (\\{str\_538})${}-\T{1},{}$\6 +\\{str\_start\_540}${}\K\\{str\_start\_539}+{}$\&{sizeof} (\\{str\_539})${}-\T{1},{}$\6 +\\{str\_start\_541}${}\K\\{str\_start\_540}+{}$\&{sizeof} (\\{str\_540})${}-\T{1},{}$\6 +\\{str\_start\_542}${}\K\\{str\_start\_541}+{}$\&{sizeof} (\\{str\_541})${}-\T{1},{}$\6 +\\{str\_start\_543}${}\K\\{str\_start\_542}+{}$\&{sizeof} (\\{str\_542})${}-\T{1},{}$\6 +\\{str\_start\_544}${}\K\\{str\_start\_543}+{}$\&{sizeof} (\\{str\_543})${}-\T{1},{}$\6 +\\{str\_start\_545}${}\K\\{str\_start\_544}+{}$\&{sizeof} (\\{str\_544})${}-\T{1},{}$\6 +\\{str\_start\_546}${}\K\\{str\_start\_545}+{}$\&{sizeof} (\\{str\_545})${}-\T{1},{}$\6 +\\{str\_start\_547}${}\K\\{str\_start\_546}+{}$\&{sizeof} (\\{str\_546})${}-\T{1},{}$\6 +\\{str\_start\_548}${}\K\\{str\_start\_547}+{}$\&{sizeof} (\\{str\_547})${}-\T{1},{}$\6 +\\{str\_start\_549}${}\K\\{str\_start\_548}+{}$\&{sizeof} (\\{str\_548})${}-\T{1},{}$\6 +\\{str\_start\_550}${}\K\\{str\_start\_549}+{}$\&{sizeof} (\\{str\_549})${}-\T{1},{}$\6 +\\{str\_start\_551}${}\K\\{str\_start\_550}+{}$\&{sizeof} (\\{str\_550})${}-\T{1},{}$\6 +\\{str\_start\_552}${}\K\\{str\_start\_551}+{}$\&{sizeof} (\\{str\_551})${}-\T{1},{}$\6 +\\{str\_start\_553}${}\K\\{str\_start\_552}+{}$\&{sizeof} (\\{str\_552})${}-\T{1},{}$\6 +\\{str\_start\_554}${}\K\\{str\_start\_553}+{}$\&{sizeof} (\\{str\_553})${}-\T{1},{}$\6 +\\{str\_start\_555}${}\K\\{str\_start\_554}+{}$\&{sizeof} (\\{str\_554})${}-\T{1},{}$\6 +\\{str\_start\_556}${}\K\\{str\_start\_555}+{}$\&{sizeof} (\\{str\_555})${}-\T{1},{}$\6 +\\{str\_start\_557}${}\K\\{str\_start\_556}+{}$\&{sizeof} (\\{str\_556})${}-\T{1},{}$\6 +\\{str\_start\_558}${}\K\\{str\_start\_557}+{}$\&{sizeof} (\\{str\_557})${}-\T{1},{}$\6 +\\{str\_start\_559}${}\K\\{str\_start\_558}+{}$\&{sizeof} (\\{str\_558})${}-\T{1},{}$\6 +\\{str\_start\_560}${}\K\\{str\_start\_559}+{}$\&{sizeof} (\\{str\_559})${}-\T{1},{}$\6 +\\{str\_start\_561}${}\K\\{str\_start\_560}+{}$\&{sizeof} (\\{str\_560})${}-\T{1},{}$\6 +\\{str\_start\_562}${}\K\\{str\_start\_561}+{}$\&{sizeof} (\\{str\_561})${}-\T{1},{}$\6 +\\{str\_start\_563}${}\K\\{str\_start\_562}+{}$\&{sizeof} (\\{str\_562})${}-\T{1},{}$\6 +\\{str\_start\_564}${}\K\\{str\_start\_563}+{}$\&{sizeof} (\\{str\_563})${}-\T{1},{}$\6 +\\{str\_start\_565}${}\K\\{str\_start\_564}+{}$\&{sizeof} (\\{str\_564})${}-\T{1},{}$\6 +\\{str\_start\_566}${}\K\\{str\_start\_565}+{}$\&{sizeof} (\\{str\_565})${}-\T{1},{}$\6 +\\{str\_start\_567}${}\K\\{str\_start\_566}+{}$\&{sizeof} (\\{str\_566})${}-\T{1},{}$\6 +\\{str\_start\_568}${}\K\\{str\_start\_567}+{}$\&{sizeof} (\\{str\_567})${}-\T{1},{}$\6 +\\{str\_start\_569}${}\K\\{str\_start\_568}+{}$\&{sizeof} (\\{str\_568})${}-\T{1},{}$\6 +\\{str\_start\_570}${}\K\\{str\_start\_569}+{}$\&{sizeof} (\\{str\_569})${}-\T{1},{}$\6 +\\{str\_start\_571}${}\K\\{str\_start\_570}+{}$\&{sizeof} (\\{str\_570})${}-\T{1},{}$\6 +\\{str\_start\_572}${}\K\\{str\_start\_571}+{}$\&{sizeof} (\\{str\_571})${}-\T{1},{}$\6 +\\{str\_start\_573}${}\K\\{str\_start\_572}+{}$\&{sizeof} (\\{str\_572})${}-\T{1},{}$\6 +\\{str\_start\_574}${}\K\\{str\_start\_573}+{}$\&{sizeof} (\\{str\_573})${}-\T{1},{}$\6 +\\{str\_start\_575}${}\K\\{str\_start\_574}+{}$\&{sizeof} (\\{str\_574})${}-\T{1},{}$\6 +\\{str\_start\_576}${}\K\\{str\_start\_575}+{}$\&{sizeof} (\\{str\_575})${}-\T{1},{}$\6 +\\{str\_start\_577}${}\K\\{str\_start\_576}+{}$\&{sizeof} (\\{str\_576})${}-\T{1},{}$\6 +\\{str\_start\_578}${}\K\\{str\_start\_577}+{}$\&{sizeof} (\\{str\_577})${}-\T{1},{}$\6 +\\{str\_start\_579}${}\K\\{str\_start\_578}+{}$\&{sizeof} (\\{str\_578})${}-\T{1},{}$\6 +\\{str\_start\_580}${}\K\\{str\_start\_579}+{}$\&{sizeof} (\\{str\_579})${}-\T{1},{}$\6 +\\{str\_start\_581}${}\K\\{str\_start\_580}+{}$\&{sizeof} (\\{str\_580})${}-\T{1},{}$\6 +\\{str\_start\_582}${}\K\\{str\_start\_581}+{}$\&{sizeof} (\\{str\_581})${}-\T{1},{}$\6 +\\{str\_start\_583}${}\K\\{str\_start\_582}+{}$\&{sizeof} (\\{str\_582})${}-\T{1},{}$\6 +\\{str\_start\_584}${}\K\\{str\_start\_583}+{}$\&{sizeof} (\\{str\_583})${}-\T{1},{}$\6 +\\{str\_start\_585}${}\K\\{str\_start\_584}+{}$\&{sizeof} (\\{str\_584})${}-\T{1},{}$\6 +\\{str\_start\_586}${}\K\\{str\_start\_585}+{}$\&{sizeof} (\\{str\_585})${}-\T{1},{}$\6 +\\{str\_start\_587}${}\K\\{str\_start\_586}+{}$\&{sizeof} (\\{str\_586})${}-\T{1},{}$\6 +\\{str\_start\_588}${}\K\\{str\_start\_587}+{}$\&{sizeof} (\\{str\_587})${}-\T{1},{}$\6 +\\{str\_start\_589}${}\K\\{str\_start\_588}+{}$\&{sizeof} (\\{str\_588})${}-\T{1},{}$\6 +\\{str\_start\_590}${}\K\\{str\_start\_589}+{}$\&{sizeof} (\\{str\_589})${}-\T{1},{}$\6 +\\{str\_start\_591}${}\K\\{str\_start\_590}+{}$\&{sizeof} (\\{str\_590})${}-\T{1},{}$\6 +\\{str\_start\_592}${}\K\\{str\_start\_591}+{}$\&{sizeof} (\\{str\_591})${}-\T{1},{}$\6 +\\{str\_start\_593}${}\K\\{str\_start\_592}+{}$\&{sizeof} (\\{str\_592})${}-\T{1},{}$\6 +\\{str\_start\_594}${}\K\\{str\_start\_593}+{}$\&{sizeof} (\\{str\_593})${}-\T{1},{}$\6 +\\{str\_start\_595}${}\K\\{str\_start\_594}+{}$\&{sizeof} (\\{str\_594})${}-\T{1},{}$\6 +\\{str\_start\_596}${}\K\\{str\_start\_595}+{}$\&{sizeof} (\\{str\_595})${}-\T{1},{}$\6 +\\{str\_start\_597}${}\K\\{str\_start\_596}+{}$\&{sizeof} (\\{str\_596})${}-\T{1},{}$\6 +\\{str\_start\_598}${}\K\\{str\_start\_597}+{}$\&{sizeof} (\\{str\_597})${}-\T{1},{}$\6 +\\{str\_start\_599}${}\K\\{str\_start\_598}+{}$\&{sizeof} (\\{str\_598})${}-\T{1},{}$\6 +\\{str\_start\_600}${}\K\\{str\_start\_599}+{}$\&{sizeof} (\\{str\_599})${}-\T{1},{}$\6 +\\{str\_start\_601}${}\K\\{str\_start\_600}+{}$\&{sizeof} (\\{str\_600})${}-\T{1},{}$\6 +\\{str\_start\_602}${}\K\\{str\_start\_601}+{}$\&{sizeof} (\\{str\_601})${}-\T{1},{}$\6 +\\{str\_start\_603}${}\K\\{str\_start\_602}+{}$\&{sizeof} (\\{str\_602})${}-\T{1},{}$\6 +\\{str\_start\_604}${}\K\\{str\_start\_603}+{}$\&{sizeof} (\\{str\_603})${}-\T{1},{}$\6 +\\{str\_start\_605}${}\K\\{str\_start\_604}+{}$\&{sizeof} (\\{str\_604})${}-\T{1},{}$\6 +\\{str\_start\_606}${}\K\\{str\_start\_605}+{}$\&{sizeof} (\\{str\_605})${}-\T{1},{}$\6 +\\{str\_start\_607}${}\K\\{str\_start\_606}+{}$\&{sizeof} (\\{str\_606})${}-\T{1},{}$\6 +\\{str\_start\_608}${}\K\\{str\_start\_607}+{}$\&{sizeof} (\\{str\_607})${}-\T{1},{}$\6 +\\{str\_start\_609}${}\K\\{str\_start\_608}+{}$\&{sizeof} (\\{str\_608})${}-\T{1},{}$\6 +\\{str\_start\_610}${}\K\\{str\_start\_609}+{}$\&{sizeof} (\\{str\_609})${}-\T{1},{}$\6 +\\{str\_start\_611}${}\K\\{str\_start\_610}+{}$\&{sizeof} (\\{str\_610})${}-\T{1},{}$\6 +\\{str\_start\_612}${}\K\\{str\_start\_611}+{}$\&{sizeof} (\\{str\_611})${}-\T{1},{}$\6 +\\{str\_start\_613}${}\K\\{str\_start\_612}+{}$\&{sizeof} (\\{str\_612})${}-\T{1},{}$\6 +\\{str\_start\_614}${}\K\\{str\_start\_613}+{}$\&{sizeof} (\\{str\_613})${}-\T{1},{}$\6 +\\{str\_start\_615}${}\K\\{str\_start\_614}+{}$\&{sizeof} (\\{str\_614})${}-\T{1},{}$\6 +\\{str\_start\_616}${}\K\\{str\_start\_615}+{}$\&{sizeof} (\\{str\_615})${}-\T{1},{}$\6 +\\{str\_start\_617}${}\K\\{str\_start\_616}+{}$\&{sizeof} (\\{str\_616})${}-\T{1},{}$\6 +\\{str\_start\_618}${}\K\\{str\_start\_617}+{}$\&{sizeof} (\\{str\_617})${}-\T{1},{}$\6 +\\{str\_start\_619}${}\K\\{str\_start\_618}+{}$\&{sizeof} (\\{str\_618})${}-\T{1},{}$\6 +\\{str\_start\_620}${}\K\\{str\_start\_619}+{}$\&{sizeof} (\\{str\_619})${}-\T{1},{}$\6 +\\{str\_start\_621}${}\K\\{str\_start\_620}+{}$\&{sizeof} (\\{str\_620})${}-\T{1},{}$\6 +\\{str\_start\_622}${}\K\\{str\_start\_621}+{}$\&{sizeof} (\\{str\_621})${}-\T{1},{}$\6 +\\{str\_start\_623}${}\K\\{str\_start\_622}+{}$\&{sizeof} (\\{str\_622})${}-\T{1},{}$\6 +\\{str\_start\_624}${}\K\\{str\_start\_623}+{}$\&{sizeof} (\\{str\_623})${}-\T{1},{}$\6 +\\{str\_start\_625}${}\K\\{str\_start\_624}+{}$\&{sizeof} (\\{str\_624})${}-\T{1},{}$\6 +\\{str\_start\_626}${}\K\\{str\_start\_625}+{}$\&{sizeof} (\\{str\_625})${}-\T{1},{}$\6 +\\{str\_start\_627}${}\K\\{str\_start\_626}+{}$\&{sizeof} (\\{str\_626})${}-\T{1},{}$\6 +\\{str\_start\_628}${}\K\\{str\_start\_627}+{}$\&{sizeof} (\\{str\_627})${}-\T{1},{}$\6 +\\{str\_start\_629}${}\K\\{str\_start\_628}+{}$\&{sizeof} (\\{str\_628})${}-\T{1},{}$\6 +\\{str\_start\_630}${}\K\\{str\_start\_629}+{}$\&{sizeof} (\\{str\_629})${}-\T{1},{}$\6 +\\{str\_start\_631}${}\K\\{str\_start\_630}+{}$\&{sizeof} (\\{str\_630})${}-\T{1},{}$\6 +\\{str\_start\_632}${}\K\\{str\_start\_631}+{}$\&{sizeof} (\\{str\_631})${}-\T{1},{}$\6 +\\{str\_start\_633}${}\K\\{str\_start\_632}+{}$\&{sizeof} (\\{str\_632})${}-\T{1},{}$\6 +\\{str\_start\_634}${}\K\\{str\_start\_633}+{}$\&{sizeof} (\\{str\_633})${}-\T{1},{}$\6 +\\{str\_start\_635}${}\K\\{str\_start\_634}+{}$\&{sizeof} (\\{str\_634})${}-\T{1},{}$\6 +\\{str\_start\_636}${}\K\\{str\_start\_635}+{}$\&{sizeof} (\\{str\_635})${}-\T{1},{}$\6 +\\{str\_start\_637}${}\K\\{str\_start\_636}+{}$\&{sizeof} (\\{str\_636})${}-\T{1},{}$\6 +\\{str\_start\_638}${}\K\\{str\_start\_637}+{}$\&{sizeof} (\\{str\_637})${}-\T{1},{}$\6 +\\{str\_start\_639}${}\K\\{str\_start\_638}+{}$\&{sizeof} (\\{str\_638})${}-\T{1},{}$\6 +\\{str\_start\_640}${}\K\\{str\_start\_639}+{}$\&{sizeof} (\\{str\_639})${}-\T{1},{}$\6 +\\{str\_start\_641}${}\K\\{str\_start\_640}+{}$\&{sizeof} (\\{str\_640})${}-\T{1},{}$\6 +\\{str\_start\_642}${}\K\\{str\_start\_641}+{}$\&{sizeof} (\\{str\_641})${}-\T{1},{}$\6 +\\{str\_start\_643}${}\K\\{str\_start\_642}+{}$\&{sizeof} (\\{str\_642})${}-\T{1},{}$\6 +\\{str\_start\_644}${}\K\\{str\_start\_643}+{}$\&{sizeof} (\\{str\_643})${}-\T{1},{}$\6 +\\{str\_start\_645}${}\K\\{str\_start\_644}+{}$\&{sizeof} (\\{str\_644})${}-\T{1},{}$\6 +\\{str\_start\_646}${}\K\\{str\_start\_645}+{}$\&{sizeof} (\\{str\_645})${}-\T{1},{}$\6 +\\{str\_start\_647}${}\K\\{str\_start\_646}+{}$\&{sizeof} (\\{str\_646})${}-\T{1},{}$\6 +\\{str\_start\_648}${}\K\\{str\_start\_647}+{}$\&{sizeof} (\\{str\_647})${}-\T{1},{}$\6 +\\{str\_start\_649}${}\K\\{str\_start\_648}+{}$\&{sizeof} (\\{str\_648})${}-\T{1},{}$\6 +\\{str\_start\_650}${}\K\\{str\_start\_649}+{}$\&{sizeof} (\\{str\_649})${}-\T{1},{}$\6 +\\{str\_start\_651}${}\K\\{str\_start\_650}+{}$\&{sizeof} (\\{str\_650})${}-\T{1},{}$\6 +\\{str\_start\_652}${}\K\\{str\_start\_651}+{}$\&{sizeof} (\\{str\_651})${}-\T{1},{}$\6 +\\{str\_start\_653}${}\K\\{str\_start\_652}+{}$\&{sizeof} (\\{str\_652})${}-\T{1},{}$\6 +\\{str\_start\_654}${}\K\\{str\_start\_653}+{}$\&{sizeof} (\\{str\_653})${}-\T{1},{}$\6 +\\{str\_start\_655}${}\K\\{str\_start\_654}+{}$\&{sizeof} (\\{str\_654})${}-\T{1},{}$\6 +\\{str\_start\_656}${}\K\\{str\_start\_655}+{}$\&{sizeof} (\\{str\_655})${}-\T{1},{}$\6 +\\{str\_start\_657}${}\K\\{str\_start\_656}+{}$\&{sizeof} (\\{str\_656})${}-\T{1},{}$\6 +\\{str\_start\_658}${}\K\\{str\_start\_657}+{}$\&{sizeof} (\\{str\_657})${}-\T{1},{}$\6 +\\{str\_start\_659}${}\K\\{str\_start\_658}+{}$\&{sizeof} (\\{str\_658})${}-\T{1},{}$\6 +\\{str\_start\_660}${}\K\\{str\_start\_659}+{}$\&{sizeof} (\\{str\_659})${}-\T{1},{}$\6 +\\{str\_start\_661}${}\K\\{str\_start\_660}+{}$\&{sizeof} (\\{str\_660})${}-\T{1},{}$\6 +\\{str\_start\_662}${}\K\\{str\_start\_661}+{}$\&{sizeof} (\\{str\_661})${}-\T{1},{}$\6 +\\{str\_start\_663}${}\K\\{str\_start\_662}+{}$\&{sizeof} (\\{str\_662})${}-\T{1},{}$\6 +\\{str\_start\_664}${}\K\\{str\_start\_663}+{}$\&{sizeof} (\\{str\_663})${}-\T{1},{}$\6 +\\{str\_start\_665}${}\K\\{str\_start\_664}+{}$\&{sizeof} (\\{str\_664})${}-\T{1},{}$\6 +\\{str\_start\_666}${}\K\\{str\_start\_665}+{}$\&{sizeof} (\\{str\_665})${}-\T{1},{}$\6 +\\{str\_start\_667}${}\K\\{str\_start\_666}+{}$\&{sizeof} (\\{str\_666})${}-\T{1},{}$\6 +\\{str\_start\_668}${}\K\\{str\_start\_667}+{}$\&{sizeof} (\\{str\_667})${}-\T{1},{}$\6 +\\{str\_start\_end}\2\6 +${}\}{}$ \&{str\_starts};\par +\U39.\fi + +\M{1796}\B\X1796:\\{pool\_ptr} initialization\X${}\E{}$\6 +\\{str\_start\_668}\par +\U39.\fi + +\M{1797}\B\X1797:\\{str\_ptr} initialization\X${}\E{}$\6 +\T{668}\par +\U39.\fi + +\N{1}{1798}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 +\fin +\con |