summaryrefslogtreecommitdiff
path: root/web/web2w
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /web/web2w
Initial commit
Diffstat (limited to 'web/web2w')
-rw-r--r--web/web2w/COPYING.TXT674
-rw-r--r--web/web2w/Makefile86
-rw-r--r--web/web2w/README47
-rw-r--r--web/web2w/TeXfonts/README21
-rw-r--r--web/web2w/TeXformats/README6
-rw-r--r--web/web2w/TeXinputs/README6
-rw-r--r--web/web2w/common.patch51
-rw-r--r--web/web2w/ctangle.patch46
-rw-r--r--web/web2w/ctex.c26514
-rw-r--r--web/web2w/ctex.idx3851
-rw-r--r--web/web2w/ctex.patch907
-rw-r--r--web/web2w/ctex.scn2129
-rw-r--r--web/web2w/ctex.tex38140
-rw-r--r--web/web2w/ctex.w26873
-rw-r--r--web/web2w/cweave.patch54
-rw-r--r--web/web2w/pascal.tab.c3352
-rw-r--r--web/web2w/pascal.tab.h279
-rw-r--r--web/web2w/pascal.y783
-rw-r--r--web/web2w/triptest.patch56
-rw-r--r--web/web2w/web.l261
-rw-r--r--web/web2w/web.lex.c3290
-rw-r--r--web/web2w/web2w.c2297
-rw-r--r--web/web2w/web2w.h347
-rw-r--r--web/web2w/web2w.pdfbin0 -> 793221 bytes
-rw-r--r--web/web2w/web2w.w4989
25 files changed, 115059 insertions, 0 deletions
diff --git a/web/web2w/COPYING.TXT b/web/web2w/COPYING.TXT
new file mode 100644
index 0000000000..94a9ed024d
--- /dev/null
+++ b/web/web2w/COPYING.TXT
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/web/web2w/Makefile b/web/web2w/Makefile
new file mode 100644
index 0000000000..f35b168618
--- /dev/null
+++ b/web/web2w/Makefile
@@ -0,0 +1,86 @@
+
+
+all: ctex ctex.dvi
+
+
+cweb/cweave.w: cweave.patch
+ patch --verbose cweb/cweave.w cweave.patch
+
+cweb/ctangle.w: ctangle.patch
+ patch --verbose cweb/ctangle.w ctangle.patch
+
+cweb/common.w: common.patch
+ patch --verbose cweb/common.w common.patch
+
+CWEAVE=cweb/cweave
+CTANGLE=cweb/ctangle
+
+cweb/ctangle: cweb/ctangle.w cweb/common.w
+ cd cweb ;\
+ if [ ! -x ./ctangle ] ; then $(CC) $(CFLAGS) -o ctangle ctangle.c common.c ; fi ;\
+ ./ctangle ctangle.w ; \
+ ./ctangle common.w ; \
+ $(CC) $(CFLAGS) -o ctangle ctangle.c common.c ; \
+ cd ..
+
+cweb/cweave: $(CTANGLE) cweb/cweave.w cweb/common.w
+ cd cweb ;\
+ ./ctangle cweave.w ; \
+ ./ctangle common.w ; \
+ $(CC) $(CFLAGS) -o cweave cweave.c common.c ; \
+ cd ..
+
+
+web.lex.c : web.l web2w.h pascal.tab.h
+ flex -o web.lex.c web.l
+
+pascal.tab.c pascal.tab.h: pascal.y
+ bison -d -v $(NAMEPREFIX) pascal.y
+
+web2w.c web2w.h: $(CTANGLE) web2w.w
+ $(CTANGLE) web2w.w
+
+
+web2w: web2w.c web.lex.c pascal.tab.c
+ $(CC) -o web2w web2w.c web.lex.c pascal.tab.c
+
+web2w.tex: $(CWEAVE) web2w.w
+ $(CWEAVE) web2w.w
+
+ctex.w: tex.w
+ patch --verbose -o ctex.w tex.w ctex.patch
+
+tex.w: web2w
+ ./web2w -o tex.w tex/tex.web
+
+ctex.c: $(CTANGLE) ctex.w
+ $(CTANGLE) ctex.w
+
+ctex.tex: $(CWEAVE) ctex.w
+ $(CWEAVE) ctex.w
+
+ctex: ctex.c
+ $(CC) ctex.c -lm -o ctex
+
+cinitex: ctex.c
+ $(CC) -DINIT ctex.c -lm -o cinitex
+
+
+ctex.pdf: ctex.tex
+ pdftex ctex.tex
+
+
+plain.fmt: cinitex
+ echo "plain \\dump" | ./cinitex
+ cp plain.fmt TeXformats/
+
+ctex.dvi: ctex ctex.tex plain.fmt
+ echo "&plain ctex" | ./ctex
+
+
+
+clean:
+ rm -f *.idx *.log *.dvi *.scn *.toc *~
+ rm -f cinitex ctex web2w
+ $(MAKE) -C cweb clean
+
diff --git a/web/web2w/README b/web/web2w/README
new file mode 100644
index 0000000000..3accff5291
--- /dev/null
+++ b/web/web2w/README
@@ -0,0 +1,47 @@
+README
+
+This file is part of web2w, Version 0.4
+
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+
+You find the license in the file COPYING.TXT in the
+same directory where you find this README file.
+
+The file web2w.pdf is protected by copyright. You may, however,
+read the file in its electronic form and may print a copy for
+your personal use. You may not use the file for any commercial
+purpose.
+
+The content of the file is available as a book (ISBN 1-548-58234-4)
+from CreateSpace: https://www.createspace.com/7315198
+If you need it printed, consider ordering the book.
+
+
+HOW TO USE web2w
+
+For a description on how to use web2w, see the file web2w.pdf
+(or the printed book) in Chapter 11: Generating TeX, Running TeX,
+and Passing the Trip Test.
+
+----------------------------------------------
+Martin Ruckert
+Department of Mathematics and Computer Science
+Munich University of Applied Sciences
+Lothstrasse 64
+80335 Munich
+GERMANY \ No newline at end of file
diff --git a/web/web2w/TeXfonts/README b/web/web2w/TeXfonts/README
new file mode 100644
index 0000000000..a018c23320
--- /dev/null
+++ b/web/web2w/TeXfonts/README
@@ -0,0 +1,21 @@
+README
+
+This directory is searched for TeX's font metric files
+It should contain these files:
+
+cmb10.tfm cmfib8.tfm cmr7.tfm cmssi10.tfm cmtex9.tfm
+cmbsy10.tfm cminch.tfm cmr8.tfm cmssi12.tfm cmti10.tfm
+cmbx10.tfm cmitt10.tfm cmr9.tfm cmssi17.tfm cmti12.tfm
+cmbx12.tfm cmmi10.tfm cmsa10.tfm cmssi8.tfm cmti7.tfm
+cmbx5.tfm cmmi12.tfm cmsl10.tfm cmssi9.tfm cmti8.tfm
+cmbx6.tfm cmmi5.tfm cmsl12.tfm cmssq8.tfm cmti9.tfm
+cmbx7.tfm cmmi6.tfm cmsl8.tfm cmssqi8.tfm cmtt10.tfm
+cmbx8.tfm cmmi7.tfm cmsl9.tfm cmsy10.tfm cmtt12.tfm
+cmbx9.tfm cmmi8.tfm cmsltt10.tfm cmsy5.tfm cmtt8.tfm
+cmbxsl10.tfm cmmi9.tfm cmss10.tfm cmsy6.tfm cmtt9.tfm
+cmbxti10.tfm cmmib10.tfm cmss12.tfm cmsy7.tfm cmu10.tfm
+cmcsc10.tfm cmr10.tfm cmss17.tfm cmsy8.tfm cmvtt10.tfm
+cmdunh10.tfm cmr12.tfm cmss8.tfm cmsy9.tfm dummy.tfm
+cmex10.tfm cmr17.tfm cmss9.tfm cmtcsc10.tfm logo10.tfm
+cmff10.tfm cmr5.tfm cmssbx10.tfm cmtex10.tfm manfnt.tfm
+cmfi10.tfm cmr6.tfm cmssdc10.tfm cmtex8.tfm old_manfnt.tfm
diff --git a/web/web2w/TeXformats/README b/web/web2w/TeXformats/README
new file mode 100644
index 0000000000..636d3cf474
--- /dev/null
+++ b/web/web2w/TeXformats/README
@@ -0,0 +1,6 @@
+README
+
+This directory is searched for TeX's input files
+It should contain these files:
+
+plain.fmt
diff --git a/web/web2w/TeXinputs/README b/web/web2w/TeXinputs/README
new file mode 100644
index 0000000000..0806955e8d
--- /dev/null
+++ b/web/web2w/TeXinputs/README
@@ -0,0 +1,6 @@
+README
+
+This directory is searched for TeX's input files
+It should contain these files:
+
+cwebmac.tex hyphen.tex plain.tex
diff --git a/web/web2w/common.patch b/web/web2w/common.patch
new file mode 100644
index 0000000000..c148879feb
--- /dev/null
+++ b/web/web2w/common.patch
@@ -0,0 +1,51 @@
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+--- /home/ruckert/hint/web2w/cweb/cweb/common.w 2002-02-01 00:00:00.000000000 +0100
++++ /home/ruckert/hint/web2w/cweb/common.w 2017-07-29 12:02:35.580013918 +0200
+@@ -150,8 +150,8 @@
+ some of \.{CWEB}'s routines use the fact that it is safe to refer to
+ |*(limit+2)| without overstepping the bounds of the array.
+
+-@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
+-@d longest_name 1000
++@d buf_size 5000 /* for \.{CWEAVE} and \.{CTANGLE} */
++@d longest_name 10000
+ @d long_buf_size (buf_size+longest_name) /* for \.{CWEAVE} */
+ @d xisspace(c) (isspace(c)&&((unsigned char)c<0200))
+ @d xisupper(c) (isupper(c)&&((unsigned char)c<0200))
+@@ -412,7 +412,7 @@
+ the |cur_file| has changed, we tell \.{CTANGLE} to print this
+ information in the \CEE/ file by means of the |print_where| flag.
+
+-@d max_sections 2000 /* number of identifiers, strings, section names;
++@d max_sections 5000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+
+ @<Defin...@>=
+@@ -586,9 +586,9 @@
+ the |byte_mem| array (the address where the name begins) and other data.
+ A |name_pointer| variable is a pointer into |name_dir|.
+
+-@d max_bytes 90000 /* the number of bytes in identifiers,
++@d max_bytes 150000 /* the number of bytes in identifiers,
+ index entries, and section names; must be less than $2^{24}$ */
+-@d max_names 4000 /* number of identifiers, strings, section names;
++@d max_names 6000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+
+ @<Definitions that...@>=
diff --git a/web/web2w/ctangle.patch b/web/web2w/ctangle.patch
new file mode 100644
index 0000000000..be3f550dcc
--- /dev/null
+++ b/web/web2w/ctangle.patch
@@ -0,0 +1,46 @@
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+--- /home/ruckert/hint/web2w/cweb/cweb/ctangle.w 2005-12-06 00:00:00.000000000 +0100
++++ /home/ruckert/hint/web2w/cweb/ctangle.w 2017-08-01 20:42:19.087176524 +0200
+@@ -106,19 +106,19 @@
+ @ The following parameters were sufficient in the original \.{TANGLE} to
+ handle \TEX/,
+ so they should be sufficient for most applications of \.{CTANGLE}.
+-If you change |max_bytes|, |max_names|, or |hash_size| you should also
++If you change |max_bytes|, |max_names|, |buf_size| or |hash_size| you should also
+ change them in the file |"common.w"|.
+
+-@d max_bytes 90000 /* the number of bytes in identifiers,
++@d max_bytes 150000 /* the number of bytes in identifiers,
+ index entries, and section names; used in |"common.w"| */
+-@d max_toks 270000 /* number of bytes in compressed \CEE/ code */
+-@d max_names 4000 /* number of identifiers, strings, section names;
++@d max_toks 300000 /* number of bytes in compressed \CEE/ code */
++@d max_names 6000 /* number of identifiers, strings, section names;
+ must be less than 10240; used in |"common.w"| */
+-@d max_texts 2500 /* number of replacement texts, must be less than 10240 */
++@d max_texts 10200 /* number of replacement texts, must be less than 10240 */
+ @d hash_size 353 /* should be prime; used in |"common.w"| */
+ @d longest_name 10000 /* section names shouldn't be longer than this */
+-@d stack_size 50 /* number of simultaneous levels of macro expansion */
+-@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
++@d stack_size 4000 /* number of simultaneous levels of macro expansion */
++@d buf_size 5000 /* for \.{CWEAVE} and \.{CTANGLE} */
+
+ @ The next few sections contain stuff from the file |"common.w"| that must
+ be included in both |"ctangle.w"| and |"cweave.w"|. It appears in
diff --git a/web/web2w/ctex.c b/web/web2w/ctex.c
new file mode 100644
index 0000000000..d7697c03ba
--- /dev/null
+++ b/web/web2w/ctex.c
@@ -0,0 +1,26514 @@
+/*4:*/
+#line 261 "tex.w"
+/*9:*/
+#line 340 "tex.w"
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#define odd(X) ((X)&1)
+#define chr(X) ((unsigned char)(X))
+#define ord(X) ((int)(X))
+
+#if __SIZEOF_FLOAT__==4
+typedef float float32_t;
+#else
+#error float type must have size 4
+#endif
+
+#define banner "This is TeX, Version 3.14159265 (HINT)" \
+
+#define mem_bot 0 \
+
+#define mem_top 30000 \
+ \
+
+#define font_base 0 \
+
+#define hash_size 2100 \
+
+#define hash_prime 1777
+#define hyph_size 307 \
+ \
+
+#define done6 36
+#define incr(X) X= X+1
+#define decr(X) X= X-1
+#define negate(X) X= -X
+#define loop while(true)
+#define do_nothing
+#define empty 0 \
+
+#define text_char unsigned char
+#define first_text_char 0
+#define last_text_char 255 \
+
+#define null_code 00
+#define carriage_return 015
+#define invalid_code 0177 \
+
+#define reset_OK(X) erstat(X) ==0
+#define rewrite_OK(X) erstat(X) ==0 \
+
+#define t_open_in term_in.f= stdin
+#define t_open_out term_out.f= stdout \
+
+#define update_terminal fflush(term_out.f)
+#define clear_terminal fflush(term_in.f)
+#define wake_up_terminal do_nothing \
+
+#define loc cur_input.loc_field \
+
+#define si(X) X
+#define so(X) X \
+
+#define length(X) (str_start[X+1]-str_start[X]) \
+ \
+
+#define cur_length (pool_ptr-str_start[str_ptr]) \
+
+#define append_char(X) \
+{str_pool[pool_ptr]= si(X) ;incr(pool_ptr) ; \
+}
+#define flush_char decr(pool_ptr)
+#define str_room(X) \
+{if(pool_ptr+X> pool_size) \
+overflow("pool size",pool_size-init_pool_ptr) ; \
+ \
+} \
+
+#define flush_string {decr(str_ptr) ;pool_ptr= str_start[str_ptr]; \
+} \
+
+#define app_lc_hex(X) l= X; \
+if(l<10) append_char(l+'0') else append_char(l-10+'a') \
+
+#define bad_pool(X) {wake_up_terminal;write_ln(term_out,X) ; \
+a_close(&pool_file) ;return false; \
+}
+#define no_print 16
+#define term_only 17
+#define log_only 18
+#define term_and_log 19
+#define pseudo 20
+#define new_string 21
+#define max_selector 21 \
+
+#define print_ASCII print \
+
+#define prompt_input(X) {wake_up_terminal;print_str(X) ;term_input() ; \
+} \
+
+#define batch_mode 0
+#define nonstop_mode 1
+#define scroll_mode 2
+#define error_stop_mode 3
+#define print_err(X) {if(interaction==error_stop_mode) wake_up_terminal; \
+print_nl("! ") ;print_str(X) ; \
+} \
+
+#define spotless 0
+#define warning_issued 1
+#define error_message_issued 2
+#define fatal_error_stop 3 \
+
+#define hlp1(X) help_line[0]= X;}
+#define hlp2(X) help_line[1]= X;hlp1
+#define hlp3(X) help_line[2]= X;hlp2
+#define hlp4(X) help_line[3]= X;hlp3
+#define hlp5(X) help_line[4]= X;hlp4
+#define hlp6(X) help_line[5]= X;hlp5
+#define help0 help_ptr= 0
+#define help1 {help_ptr= 1;hlp1
+#define help2 {help_ptr= 2;hlp2
+#define help3 {help_ptr= 3;hlp3
+#define help4 {help_ptr= 4;hlp4
+#define help5 {help_ptr= 5;hlp5
+#define help6 {help_ptr= 6;hlp6 \
+
+#define succumb {if(interaction==error_stop_mode) \
+interaction= scroll_mode; \
+if(log_opened) error() ; \
+if(interaction> batch_mode) debug_help() ; \
+history= fatal_error_stop;jump_out() ; \
+} \
+
+#define check_interrupt {if(interrupt!=0) pause_for_instructions() ; \
+} \
+
+#define unity 0200000
+#define two 0400000 \
+
+#define nx_plus_y(X,Y,Z) mult_and_add(X,Y,Z,07777777777)
+#define mult_integers(X,Y) mult_and_add(X,Y,0,017777777777) \
+
+#define inf_bad 10000 \
+
+#define set_glue_ratio_zero(X) X= 0.0
+#define set_glue_ratio_one(X) X= 1.0
+#define float(X) ((double) (X) )
+#define unfloat(X) ((glue_ratio) (X) )
+#define float_constant(X) ((double) (X) ) \
+
+#define min_quarterword 0
+#define max_quarterword 255
+#define min_halfword 0
+#define max_halfword 65535 \
+
+#define qi(X) X+min_quarterword \
+
+#define qo(X) X-min_quarterword \
+
+#define hi(X) X+min_halfword \
+
+#define ho(X) X-min_halfword \
+ \
+
+#define sc i \
+
+#define pointer halfword
+#define null min_halfword \
+
+#define link(X) mem[X].hh.rh
+#define info(X) mem[X].hh.lh \
+
+#define free_avail(X) \
+{link(X) = avail;avail= X; \
+decr_dyn_used; \
+} \
+
+#define fast_get_avail(X) \
+{X= avail; \
+if(X==null) X= get_avail() ; \
+else{avail= link(X) ;link(X) = null; \
+incr_dyn_used; \
+} \
+} \
+
+#define empty_flag max_halfword
+#define is_empty(X) (link(X) ==empty_flag)
+#define node_size info
+#define llink(X) info(X+1)
+#define rlink(X) link(X+1) \
+
+#define type(X) mem[X].hh.b0
+#define subtype(X) mem[X].hh.b1 \
+
+#define is_char_node(X) (X>=hi_mem_min) \
+
+#define font type
+#define character subtype \
+
+#define hlist_node 0
+#define box_node_size 7
+#define width_offset 1
+#define depth_offset 2
+#define height_offset 3
+#define width(X) mem[X+width_offset].sc
+#define depth(X) mem[X+depth_offset].sc
+#define height(X) mem[X+height_offset].sc
+#define shift_amount(X) mem[X+4].sc
+#define list_offset 5
+#define list_ptr(X) link(X+list_offset)
+#define glue_order(X) subtype(X+list_offset)
+#define glue_sign(X) type(X+list_offset)
+#define normal 0
+#define stretching 1
+#define shrinking 2
+#define glue_offset 6
+#define glue_set(X) mem[X+glue_offset].gr \
+ \
+
+#define vlist_node 1 \
+
+#define rule_node 2
+#define rule_node_size 4
+#define null_flag -010000000000
+#define is_running(X) (X==null_flag) \
+
+#define ins_node 3
+#define ins_node_size 5
+#define float_cost(X) mem[X+1].i
+#define ins_ptr(X) info(X+4)
+#define split_top_ptr(X) link(X+4) \
+
+#define mark_node 4
+#define small_node_size 2
+#define mark_ptr(X) mem[X+1].i \
+
+#define adjust_node 5
+#define adjust_ptr mark_ptr \
+
+#define ligature_node 6
+#define lig_char(X) X+1
+#define lig_ptr(X) link(lig_char(X) ) \
+
+#define disc_node 7
+#define replace_count subtype
+#define pre_break llink
+#define post_break rlink \
+
+#define whatsit_node 8 \
+
+#define math_node 9
+#define before 0
+#define after 1 \
+
+#define precedes_break(X) (type(X) <math_node)
+#define non_discardable(X) (type(X) <math_node) \
+
+#define glue_node 10
+#define cond_math_glue 98
+#define mu_glue 99
+#define a_leaders 100
+#define c_leaders 101
+#define x_leaders 102
+#define glue_ptr llink
+#define leader_ptr rlink \
+
+#define glue_spec_size 4
+#define glue_ref_count(X) link(X)
+#define stretch(X) mem[X+2].sc
+#define shrink(X) mem[X+3].sc
+#define stretch_order type
+#define shrink_order subtype
+#define fil 1
+#define fill 2
+#define filll 3 \
+
+#define kern_node 11
+#define explicit 1
+#define acc_kern 2 \
+
+#define penalty_node 12
+#define inf_penalty inf_bad
+#define eject_penalty (-inf_penalty)
+#define penalty(X) mem[X+1].i \
+
+#define unset_node 13
+#define glue_stretch(X) mem[X+glue_offset].sc
+#define glue_shrink shift_amount
+#define span_count subtype \
+
+#define zero_glue mem_bot
+#define fil_glue zero_glue+glue_spec_size
+#define fill_glue fil_glue+glue_spec_size
+#define ss_glue fill_glue+glue_spec_size
+#define fil_neg_glue ss_glue+glue_spec_size
+#define lo_mem_stat_max fil_neg_glue+glue_spec_size-1 \
+ \
+
+#define page_ins_head mem_top
+#define contrib_head mem_top-1
+#define page_head mem_top-2
+#define temp_head mem_top-3
+#define hold_head mem_top-4
+#define adjust_head mem_top-5
+#define active mem_top-7
+#define align_head mem_top-8
+#define end_span mem_top-9
+#define omit_template mem_top-10
+#define null_list mem_top-11
+#define lig_trick mem_top-12
+#define garbage mem_top-12
+#define backup_head mem_top-13
+#define hi_mem_stat_min mem_top-13 \
+
+#define hi_mem_stat_usage 14 \
+
+#define node_list_display(X) \
+{append_char('.') ;show_node_list(X) ;flush_char; \
+} \
+
+#define token_ref_count(X) info(X) \
+
+#define fast_delete_glue_ref(X) \
+{if(glue_ref_count(X) ==null) free_node(X,glue_spec_size) ; \
+else decr(glue_ref_count(X) ) ; \
+} \
+
+#define add_token_ref(X) incr(token_ref_count(X) )
+#define add_glue_ref(X) incr(glue_ref_count(X) ) \
+
+#define escape 0 \
+
+#define relax 0
+#define left_brace 1
+#define right_brace 2
+#define math_shift 3
+#define tab_mark 4
+#define car_ret 5
+#define out_param 5
+#define mac_param 6
+#define sup_mark 7
+#define sub_mark 8
+#define ignore 9
+#define endv 9
+#define spacer 10
+#define letter 11
+#define other_char 12
+#define active_char 13
+#define par_end 13
+#define match 13
+#define comment 14
+#define end_match 14
+#define stop 14
+#define invalid_char 15
+#define delim_num 15
+#define max_char_code 15 \
+
+#define char_num 16
+#define math_char_num 17
+#define mark 18
+#define xray 19
+#define make_box 20
+#define hmove 21
+#define vmove 22
+#define un_hbox 23
+#define un_vbox 24
+#define remove_item 25 \
+
+#define hskip 26
+#define vskip 27
+#define mskip 28
+#define kern 29
+#define mkern 30
+#define leader_ship 31
+#define halign 32
+#define valign 33
+#define no_align 34
+#define vrule 35
+#define hrule 36
+#define insert 37
+#define vadjust 38
+#define ignore_spaces 39
+#define after_assignment 40
+#define after_group 41
+#define break_penalty 42
+#define start_par 43
+#define ital_corr 44
+#define accent 45
+#define math_accent 46
+#define discretionary 47
+#define eq_no 48
+#define left_right 49
+#define math_comp 50
+#define limit_switch 51
+#define above 52
+#define math_style 53
+#define math_choice 54
+#define non_script 55
+#define vcenter 56
+#define case_shift 57
+#define message 58
+#define extension 59
+#define in_stream 60
+#define begin_group 61
+#define end_group 62
+#define omit 63
+#define ex_space 64
+#define no_boundary 65
+#define radical 66
+#define end_cs_name 67
+#define min_internal 68
+#define char_given 68
+#define math_given 69
+#define last_item 70 \
+
+#define max_non_prefixed_command 70 \
+
+#define toks_register 71
+#define assign_toks 72
+#define assign_int 73
+#define assign_dimen 74
+#define assign_glue 75
+#define assign_mu_glue 76
+#define assign_font_dimen 77
+#define assign_font_int 78 \
+
+#define set_aux 79
+#define set_prev_graf 80
+#define set_page_dimen 81
+#define set_page_int 82 \
+
+#define set_box_dimen 83
+#define set_shape 84
+#define def_code 85
+#define def_family 86
+#define set_font 87
+#define def_font 88
+#define register 89
+#define max_internal 89
+#define advance 90
+#define multiply 91
+#define divide 92
+#define prefix 93
+#define let 94
+#define shorthand_def 95
+#define read_to_cs 96
+#define def 97
+#define set_box 98
+#define hyph_data 99
+#define set_interaction 100
+#define max_command 100 \
+
+#define undefined_cs (max_command+1)
+#define expand_after (max_command+2)
+#define no_expand (max_command+3)
+#define input (max_command+4)
+#define if_test (max_command+5)
+#define fi_or_else (max_command+6)
+#define cs_name (max_command+7)
+#define convert (max_command+8)
+#define the (max_command+9)
+#define top_bot_mark (max_command+10)
+#define call (max_command+11)
+#define long_call (max_command+12)
+#define outer_call (max_command+13)
+#define long_outer_call (max_command+14)
+#define end_template (max_command+15)
+#define dont_expand (max_command+16)
+#define glue_ref (max_command+17)
+#define shape_ref (max_command+18)
+#define box_ref (max_command+19)
+#define data (max_command+20) \
+
+#define vmode 1
+#define hmode (vmode+max_command+1)
+#define mmode (hmode+max_command+1) \
+
+#define ignore_depth -65536000 \
+
+#define mode cur_list.mode_field
+#define head cur_list.head_field
+#define tail cur_list.tail_field
+#define prev_graf cur_list.pg_field
+#define aux cur_list.aux_field
+#define prev_depth aux.sc
+#define space_factor aux.hh.lh
+#define clang aux.hh.rh
+#define incompleat_noad aux.i
+#define mode_line cur_list.ml_field \
+
+#define tail_append(X) {link(tail) = X;tail= link(tail) ; \
+} \
+
+#define eq_level_field(X) X.hh.b1
+#define eq_type_field(X) X.hh.b0
+#define equiv_field(X) X.hh.rh
+#define eq_level(X) eq_level_field(eqtb[X])
+#define eq_type(X) eq_type_field(eqtb[X])
+#define equiv(X) equiv_field(eqtb[X])
+#define level_zero min_quarterword
+#define level_one (level_zero+1) \
+
+#define active_base 1
+#define single_base (active_base+256)
+#define null_cs (single_base+256)
+#define hash_base (null_cs+1)
+#define frozen_control_sequence (hash_base+hash_size)
+#define frozen_protection frozen_control_sequence
+#define frozen_cr (frozen_control_sequence+1)
+#define frozen_end_group (frozen_control_sequence+2)
+#define frozen_right (frozen_control_sequence+3)
+#define frozen_fi (frozen_control_sequence+4)
+#define frozen_end_template (frozen_control_sequence+5)
+#define frozen_endv (frozen_control_sequence+6)
+#define frozen_relax (frozen_control_sequence+7)
+#define end_write (frozen_control_sequence+8)
+#define frozen_dont_expand (frozen_control_sequence+9) \
+
+#define frozen_null_font (frozen_control_sequence+10) \
+
+#define font_id_base (frozen_null_font-font_base) \
+
+#define undefined_control_sequence (frozen_null_font+257)
+#define glue_base (undefined_control_sequence+1) \
+
+#define line_skip_code 0
+#define baseline_skip_code 1
+#define par_skip_code 2
+#define above_display_skip_code 3
+#define below_display_skip_code 4
+#define above_display_short_skip_code 5 \
+
+#define below_display_short_skip_code 6 \
+
+#define left_skip_code 7
+#define right_skip_code 8
+#define top_skip_code 9
+#define split_top_skip_code 10
+#define tab_skip_code 11
+#define space_skip_code 12
+#define xspace_skip_code 13
+#define par_fill_skip_code 14
+#define thin_mu_skip_code 15
+#define med_mu_skip_code 16
+#define thick_mu_skip_code 17
+#define glue_pars 18
+#define skip_base (glue_base+glue_pars)
+#define mu_skip_base (skip_base+256)
+#define local_base (mu_skip_base+256) \
+
+#define skip(X) equiv(skip_base+X)
+#define mu_skip(X) equiv(mu_skip_base+X)
+#define glue_par(X) equiv(glue_base+X)
+#define line_skip glue_par(line_skip_code)
+#define baseline_skip glue_par(baseline_skip_code)
+#define par_skip glue_par(par_skip_code)
+#define above_display_skip glue_par(above_display_skip_code)
+#define below_display_skip glue_par(below_display_skip_code)
+#define above_display_short_skip glue_par(above_display_short_skip_code)
+#define below_display_short_skip glue_par(below_display_short_skip_code)
+#define left_skip glue_par(left_skip_code)
+#define right_skip glue_par(right_skip_code)
+#define top_skip glue_par(top_skip_code)
+#define split_top_skip glue_par(split_top_skip_code)
+#define tab_skip glue_par(tab_skip_code)
+#define space_skip glue_par(space_skip_code)
+#define xspace_skip glue_par(xspace_skip_code)
+#define par_fill_skip glue_par(par_fill_skip_code)
+#define thin_mu_skip glue_par(thin_mu_skip_code)
+#define med_mu_skip glue_par(med_mu_skip_code)
+#define thick_mu_skip glue_par(thick_mu_skip_code) \
+
+#define par_shape_loc local_base
+#define output_routine_loc (local_base+1)
+#define every_par_loc (local_base+2)
+#define every_math_loc (local_base+3)
+#define every_display_loc (local_base+4)
+#define every_hbox_loc (local_base+5)
+#define every_vbox_loc (local_base+6)
+#define every_job_loc (local_base+7)
+#define every_cr_loc (local_base+8)
+#define err_help_loc (local_base+9)
+#define toks_base (local_base+10)
+#define box_base (toks_base+256)
+#define cur_font_loc (box_base+256)
+#define math_font_base (cur_font_loc+1)
+#define cat_code_base (math_font_base+48) \
+
+#define lc_code_base (cat_code_base+256)
+#define uc_code_base (lc_code_base+256)
+#define sf_code_base (uc_code_base+256)
+#define math_code_base (sf_code_base+256)
+#define int_base (math_code_base+256) \
+
+#define par_shape_ptr equiv(par_shape_loc)
+#define output_routine equiv(output_routine_loc)
+#define every_par equiv(every_par_loc)
+#define every_math equiv(every_math_loc)
+#define every_display equiv(every_display_loc)
+#define every_hbox equiv(every_hbox_loc)
+#define every_vbox equiv(every_vbox_loc)
+#define every_job equiv(every_job_loc)
+#define every_cr equiv(every_cr_loc)
+#define err_help equiv(err_help_loc)
+#define toks(X) equiv(toks_base+X)
+#define box(X) equiv(box_base+X)
+#define cur_font equiv(cur_font_loc)
+#define fam_fnt(X) equiv(math_font_base+X)
+#define cat_code(X) equiv(cat_code_base+X)
+#define lc_code(X) equiv(lc_code_base+X)
+#define uc_code(X) equiv(uc_code_base+X)
+#define sf_code(X) equiv(sf_code_base+X)
+#define math_code(X) equiv(math_code_base+X) \
+ \
+
+#define null_font font_base
+#define var_code 070000 \
+
+#define pretolerance_code 0
+#define tolerance_code 1
+#define line_penalty_code 2
+#define hyphen_penalty_code 3
+#define ex_hyphen_penalty_code 4
+#define club_penalty_code 5
+#define widow_penalty_code 6
+#define display_widow_penalty_code 7
+#define broken_penalty_code 8
+#define bin_op_penalty_code 9
+#define rel_penalty_code 10
+#define pre_display_penalty_code 11 \
+
+#define post_display_penalty_code 12 \
+
+#define inter_line_penalty_code 13
+#define double_hyphen_demerits_code 14
+#define final_hyphen_demerits_code 15
+#define adj_demerits_code 16
+#define mag_code 17
+#define delimiter_factor_code 18
+#define looseness_code 19
+#define time_code 20
+#define day_code 21
+#define month_code 22
+#define year_code 23
+#define show_box_breadth_code 24
+#define show_box_depth_code 25
+#define hbadness_code 26
+#define vbadness_code 27
+#define pausing_code 28
+#define tracing_online_code 29
+#define tracing_macros_code 30
+#define tracing_stats_code 31
+#define tracing_paragraphs_code 32
+#define tracing_pages_code 33
+#define tracing_output_code 34
+#define tracing_lost_chars_code 35
+#define tracing_commands_code 36
+#define tracing_restores_code 37
+#define uc_hyph_code 38
+#define output_penalty_code 39
+#define max_dead_cycles_code 40
+#define hang_after_code 41
+#define floating_penalty_code 42
+#define global_defs_code 43
+#define cur_fam_code 44
+#define escape_char_code 45
+#define default_hyphen_char_code 46
+#define default_skew_char_code 47
+#define end_line_char_code 48
+#define new_line_char_code 49
+#define language_code 50
+#define left_hyphen_min_code 51
+#define right_hyphen_min_code 52
+#define holding_inserts_code 53
+#define error_context_lines_code 54
+#define int_pars 55
+#define count_base (int_base+int_pars)
+#define del_code_base (count_base+256)
+#define dimen_base (del_code_base+256) \
+
+#define del_code(X) eqtb[del_code_base+X].i
+#define count(X) eqtb[count_base+X].i
+#define int_par(X) eqtb[int_base+X].i
+#define pretolerance int_par(pretolerance_code)
+#define tolerance int_par(tolerance_code)
+#define line_penalty int_par(line_penalty_code)
+#define hyphen_penalty int_par(hyphen_penalty_code)
+#define ex_hyphen_penalty int_par(ex_hyphen_penalty_code)
+#define club_penalty int_par(club_penalty_code)
+#define widow_penalty int_par(widow_penalty_code)
+#define display_widow_penalty int_par(display_widow_penalty_code)
+#define broken_penalty int_par(broken_penalty_code)
+#define bin_op_penalty int_par(bin_op_penalty_code)
+#define rel_penalty int_par(rel_penalty_code)
+#define pre_display_penalty int_par(pre_display_penalty_code)
+#define post_display_penalty int_par(post_display_penalty_code)
+#define inter_line_penalty int_par(inter_line_penalty_code)
+#define double_hyphen_demerits int_par(double_hyphen_demerits_code)
+#define final_hyphen_demerits int_par(final_hyphen_demerits_code)
+#define adj_demerits int_par(adj_demerits_code)
+#define mag int_par(mag_code)
+#define delimiter_factor int_par(delimiter_factor_code)
+#define looseness int_par(looseness_code)
+#define time int_par(time_code)
+#define day int_par(day_code)
+#define month int_par(month_code)
+#define year int_par(year_code)
+#define show_box_breadth int_par(show_box_breadth_code)
+#define show_box_depth int_par(show_box_depth_code)
+#define hbadness int_par(hbadness_code)
+#define vbadness int_par(vbadness_code)
+#define pausing int_par(pausing_code)
+#define tracing_online int_par(tracing_online_code)
+#define tracing_macros int_par(tracing_macros_code)
+#define tracing_stats int_par(tracing_stats_code)
+#define tracing_paragraphs int_par(tracing_paragraphs_code)
+#define tracing_pages int_par(tracing_pages_code)
+#define tracing_output int_par(tracing_output_code)
+#define tracing_lost_chars int_par(tracing_lost_chars_code)
+#define tracing_commands int_par(tracing_commands_code)
+#define tracing_restores int_par(tracing_restores_code)
+#define uc_hyph int_par(uc_hyph_code)
+#define output_penalty int_par(output_penalty_code)
+#define max_dead_cycles int_par(max_dead_cycles_code)
+#define hang_after int_par(hang_after_code)
+#define floating_penalty int_par(floating_penalty_code)
+#define global_defs int_par(global_defs_code)
+#define cur_fam int_par(cur_fam_code)
+#define escape_char int_par(escape_char_code)
+#define default_hyphen_char int_par(default_hyphen_char_code)
+#define default_skew_char int_par(default_skew_char_code)
+#define end_line_char int_par(end_line_char_code)
+#define new_line_char int_par(new_line_char_code)
+#define language int_par(language_code)
+#define left_hyphen_min int_par(left_hyphen_min_code)
+#define right_hyphen_min int_par(right_hyphen_min_code)
+#define holding_inserts int_par(holding_inserts_code)
+#define error_context_lines int_par(error_context_lines_code) \
+
+#define par_indent_code 0
+#define math_surround_code 1
+#define line_skip_limit_code 2
+#define hsize_code 3
+#define vsize_code 4
+#define max_depth_code 5
+#define split_max_depth_code 6
+#define box_max_depth_code 7
+#define hfuzz_code 8
+#define vfuzz_code 9
+#define delimiter_shortfall_code 10
+#define null_delimiter_space_code 11
+#define script_space_code 12
+#define pre_display_size_code 13
+#define display_width_code 14
+#define display_indent_code 15
+#define overfull_rule_code 16
+#define hang_indent_code 17
+#define h_offset_code 18
+#define v_offset_code 19
+#define emergency_stretch_code 20
+#define dimen_pars 21
+#define scaled_base (dimen_base+dimen_pars) \
+
+#define eqtb_size (scaled_base+255) \
+
+#define dimen(X) eqtb[scaled_base+X].sc
+#define dimen_par(X) eqtb[dimen_base+X].sc
+#define par_indent dimen_par(par_indent_code)
+#define math_surround dimen_par(math_surround_code)
+#define line_skip_limit dimen_par(line_skip_limit_code)
+#define hsize dimen_par(hsize_code)
+#define vsize dimen_par(vsize_code)
+#define max_depth dimen_par(max_depth_code)
+#define split_max_depth dimen_par(split_max_depth_code)
+#define box_max_depth dimen_par(box_max_depth_code)
+#define hfuzz dimen_par(hfuzz_code)
+#define vfuzz dimen_par(vfuzz_code)
+#define delimiter_shortfall dimen_par(delimiter_shortfall_code)
+#define null_delimiter_space dimen_par(null_delimiter_space_code)
+#define script_space dimen_par(script_space_code)
+#define pre_display_size dimen_par(pre_display_size_code)
+#define display_width dimen_par(display_width_code)
+#define display_indent dimen_par(display_indent_code)
+#define overfull_rule dimen_par(overfull_rule_code)
+#define hang_indent dimen_par(hang_indent_code)
+#define h_offset dimen_par(h_offset_code)
+#define v_offset dimen_par(v_offset_code)
+#define emergency_stretch dimen_par(emergency_stretch_code) \
+
+#define next(X) hash[X].lh
+#define text(X) hash[X].rh
+#define hash_is_full (hash_used==hash_base)
+#define font_id_text(X) text(font_id_base+X) \
+
+#define save_type(X) save_stack[X].hh.b0
+#define save_level(X) save_stack[X].hh.b1 \
+
+#define save_index(X) save_stack[X].hh.rh \
+
+#define restore_old_value 0
+#define restore_zero 1
+#define insert_token 2
+#define level_boundary 3 \
+
+#define bottom_level 0
+#define simple_group 1
+#define hbox_group 2
+#define adjusted_hbox_group 3
+#define vbox_group 4
+#define vtop_group 5
+#define align_group 6
+#define no_align_group 7
+#define output_group 8
+#define math_group 9
+#define disc_group 10
+#define insert_group 11
+#define vcenter_group 12
+#define math_choice_group 13
+#define semi_simple_group 14
+#define math_shift_group 15
+#define math_left_group 16
+#define max_group_code 16 \
+
+#define check_full_save_stack if(save_ptr> max_save_stack) \
+{max_save_stack= save_ptr; \
+if(max_save_stack> save_size-6) overflow("save size",save_size) ; \
+ \
+} \
+
+#define saved(X) save_stack[save_ptr+X].i \
+
+#define cs_token_flag 07777 \
+
+#define left_brace_token 00400
+#define left_brace_limit 01000
+#define right_brace_token 01000
+#define right_brace_limit 01400
+#define math_shift_token 01400
+#define tab_token 02000
+#define out_param_token 02400
+#define space_token 05040
+#define letter_token 05400
+#define other_token 06000
+#define match_token 06400
+#define end_match_token 07000 \
+
+#define chr_cmd(X) {print_str(X) ;print_ASCII(chr_code) ; \
+} \
+
+#define state cur_input.state_field
+#define index cur_input.index_field
+#define start cur_input.start_field
+#define limit cur_input.limit_field
+#define name cur_input.name_field \
+
+#define mid_line 1
+#define skip_blanks (2+max_char_code)
+#define new_line (3+max_char_code+max_char_code) \
+
+#define terminal_input (name==0)
+#define cur_file input_file[index] \
+
+#define skipping 1
+#define defining 2
+#define matching 3
+#define aligning 4
+#define absorbing 5 \
+
+#define token_list 0
+#define token_type index
+#define param_start limit
+#define parameter 0
+#define u_template 1
+#define v_template 2
+#define backed_up 3
+#define inserted 4
+#define macro 5
+#define output_text 6
+#define every_par_text 7
+#define every_math_text 8
+#define every_display_text 9
+#define every_hbox_text 10
+#define every_vbox_text 11
+#define every_job_text 12
+#define every_cr_text 13
+#define mark_text 14
+#define write_text 15 \
+
+#define begin_pseudoprint \
+{l= tally;tally= 0;selector= pseudo; \
+trick_count= 1000000; \
+}
+#define set_trick_count \
+{first_count= tally; \
+trick_count= tally+1+error_line-half_error_line; \
+if(trick_count<error_line) trick_count= error_line; \
+} \
+
+#define push_input \
+{if(input_ptr> max_in_stack) \
+{max_in_stack= input_ptr; \
+if(input_ptr==stack_size) overflow("input stack size",stack_size) ; \
+ \
+} \
+input_stack[input_ptr]= cur_input; \
+incr(input_ptr) ; \
+} \
+
+#define pop_input \
+{decr(input_ptr) ;cur_input= input_stack[input_ptr]; \
+} \
+
+#define back_list(X) begin_token_list(X,backed_up)
+#define ins_list(X) begin_token_list(X,inserted) \
+
+#define any_state_plus(X) case mid_line+X:case skip_blanks+X:case new_line+X \
+
+#define add_delims_to(X) X+math_shift:X+tab_mark:X+mac_param: \
+X+sub_mark:X+letter:X+other_char \
+
+#define is_hex(X) (((X>='0') &&(X<='9') ) ||((X>='a') &&(X<='f') ) )
+#define hex_to_cur_chr \
+if(c<='9') cur_chr= c-'0';else cur_chr= c-'a'+10; \
+if(cc<='9') cur_chr= 16*cur_chr+cc-'0'; \
+else cur_chr= 16*cur_chr+cc-'a'+10 \
+
+#define no_expand_flag 257 \
+
+#define end_line_char_inactive (end_line_char<0) ||(end_line_char> 255) \
+
+#define store_new_token(X) {q= get_avail() ;link(p) = q;info(q) = X; \
+p= q; \
+}
+#define fast_store_new_token(X) {fast_get_avail(q) ;link(p) = q;info(q) = X; \
+p= q; \
+} \
+
+#define top_mark_code 0
+#define first_mark_code 1
+#define bot_mark_code 2
+#define split_first_mark_code 3
+#define split_bot_mark_code 4
+#define top_mark cur_mark[top_mark_code]
+#define first_mark cur_mark[first_mark_code]
+#define bot_mark cur_mark[bot_mark_code]
+#define split_first_mark cur_mark[split_first_mark_code]
+#define split_bot_mark cur_mark[split_bot_mark_code] \
+
+#define int_val 0
+#define dimen_val 1
+#define glue_val 2
+#define mu_val 3
+#define ident_val 4
+#define tok_val 5 \
+
+#define scanned_result_end(X) cur_val_level= X;}
+#define scanned_result(X) {cur_val= X;scanned_result_end \
+
+#define input_line_no_code (glue_val+1)
+#define badness_code (glue_val+2) \
+
+#define max_dimen 07777777777 \
+
+#define octal_token (other_token+'\'')
+#define hex_token (other_token+'"')
+#define alpha_token (other_token+'`')
+#define point_token (other_token+'.')
+#define continental_point_token (other_token+',') \
+
+#define infinity 017777777777
+#define zero_token (other_token+'0')
+#define A_token (letter_token+'A')
+#define other_A_token (other_token+'A') \
+
+#define scan_normal_dimen scan_dimen(false,false,false) \
+
+#define set_conversion_end(X) denom= X;}
+#define set_conversion(X) {num= X;set_conversion_end \
+
+#define default_rule 26214 \
+
+#define number_code 0
+#define roman_numeral_code 1
+#define string_code 2
+#define meaning_code 3
+#define font_name_code 4
+#define job_name_code 5 \
+
+#define closed 2
+#define just_open 1 \
+
+#define if_char_code 0
+#define if_cat_code 1
+#define if_int_code 2
+#define if_dim_code 3
+#define if_odd_code 4
+#define if_vmode_code 5
+#define if_hmode_code 6
+#define if_mmode_code 7
+#define if_inner_code 8
+#define if_void_code 9
+#define if_hbox_code 10
+#define if_vbox_code 11
+#define ifx_code 12
+#define if_eof_code 13
+#define if_true_code 14
+#define if_false_code 15
+#define if_case_code 16 \
+
+#define if_node_size 2
+#define if_line_field(X) mem[X+1].i
+#define if_code 1
+#define fi_code 2
+#define else_code 3
+#define or_code 4 \
+
+#define get_x_token_or_active_char \
+{get_x_token() ; \
+if(cur_cmd==relax) if(cur_chr==no_expand_flag) \
+{cur_cmd= active_char; \
+cur_chr= cur_tok-cs_token_flag-active_base; \
+} \
+} \
+
+#define append_to_name(X) {c= X;incr(k) ; \
+if(k<=file_name_size) name_of_file[k]= xchr[c]; \
+} \
+
+#define format_default_length 20
+#define format_area_length 11
+#define format_ext_length 4
+#define format_extension_str ".fmt" \
+
+#define pack_cur_name pack_file_name(cur_name,cur_area,cur_ext) \
+
+#define no_tag 0
+#define lig_tag 1
+#define list_tag 2
+#define ext_tag 3 \
+
+#define stop_flag qi(128)
+#define kern_flag qi(128)
+#define skip_byte(X) X.b0
+#define next_char(X) X.b1
+#define op_byte(X) X.b2
+#define rem_byte(X) X.b3 \
+
+#define ext_top(X) X.b0
+#define ext_mid(X) X.b1
+#define ext_bot(X) X.b2
+#define ext_rep(X) X.b3 \
+
+#define slant_code 1
+#define space_code 2
+#define space_stretch_code 3
+#define space_shrink_code 4
+#define x_height_code 5
+#define quad_code 6
+#define extra_space_code 7 \
+
+#define non_char qi(256)
+#define non_address 0 \
+
+#define char_info_end(X) X].qqqq
+#define char_info(X) font_info[char_base[X]+char_info_end
+#define char_width_end(X) X.b0].sc
+#define char_width(X) font_info[width_base[X]+char_width_end
+#define char_exists(X) (X.b0> min_quarterword)
+#define char_italic_end(X) (qo(X.b2) ) /4].sc
+#define char_italic(X) font_info[italic_base[X]+char_italic_end
+#define height_depth(X) qo(X.b1)
+#define char_height_end(X) (X) /16].sc
+#define char_height(X) font_info[height_base[X]+char_height_end
+#define char_depth_end(X) (X) %16].sc
+#define char_depth(X) font_info[depth_base[X]+char_depth_end
+#define char_tag(X) ((qo(X.b2) ) %4) \
+
+#define char_kern_end(X) 256*op_byte(X) +rem_byte(X) ].sc
+#define char_kern(X) font_info[kern_base[X]+char_kern_end
+#define kern_base_offset 256*(128+min_quarterword)
+#define lig_kern_start(X) lig_kern_base[X]+rem_byte
+#define lig_kern_restart_end(X) 256*op_byte(X) +rem_byte(X) +32768-kern_base_offset
+#define lig_kern_restart(X) lig_kern_base[X]+lig_kern_restart_end \
+
+#define param_end(X) param_base[X]].sc
+#define param(X) font_info[X+param_end
+#define slant param(slant_code)
+#define space param(space_code)
+#define space_stretch param(space_stretch_code)
+#define space_shrink param(space_shrink_code)
+#define x_height param(x_height_code)
+#define quad param(quad_code)
+#define extra_space param(extra_space_code) \
+
+#define abort goto bad_tfm \
+
+#define start_font_error_message print_err("Font ") ;sprint_cs(u) ; \
+print_char('=') ;print_file_name(nom,aire,empty_string) ; \
+if(s>=0) \
+{print_str(" at ") ;print_scaled(s) ;print_str("pt") ; \
+} \
+else if(s!=-1000) \
+{print_str(" scaled ") ;print_int(-s) ; \
+} \
+
+#define fget get(tfm_file)
+#define fbyte tfm_file.d
+#define read_sixteen(X) {X= fbyte; \
+if(X> 127) abort; \
+fget;X= X*0400+fbyte; \
+}
+#define store_four_quarters(X) {fget;a= fbyte;qw.b0= qi(a) ; \
+fget;b= fbyte;qw.b1= qi(b) ; \
+fget;c= fbyte;qw.b2= qi(c) ; \
+fget;d= fbyte;qw.b3= qi(d) ; \
+X= qw; \
+} \
+
+#define check_byte_range(X) {if((X<bc) ||(X> ec) ) abort;}
+#define current_character_being_worked_on k+bc-fmem_ptr \
+
+#define store_scaled(X) {fget;a= fbyte;fget;b= fbyte; \
+fget;c= fbyte;fget;d= fbyte; \
+sw= (((((d*z) /0400) +(c*z) ) /0400) +(b*z) ) /beta; \
+if(a==0) X= sw;else if(a==255) X= sw-alpha;else abort; \
+} \
+
+#define check_existence(X) \
+{check_byte_range(X) ; \
+qw= char_info(f) (X) ; \
+if(!char_exists(qw) ) abort; \
+} \
+
+#define adjust(X) X[f]= qo(X[f]) \
+ \
+
+#define set_char_0 0
+#define set1 128
+#define set_rule 132
+#define put_rule 137
+#define nop 138
+#define bop 139
+#define eop 140
+#define push 141
+#define pop 142
+#define right1 143
+#define w0 147
+#define w1 148
+#define x0 152
+#define x1 153
+#define down1 157
+#define y0 161
+#define y1 162
+#define z0 166
+#define z1 167
+#define fnt_num_0 171
+#define fnt1 235
+#define xxx1 239
+#define xxx4 242
+#define fnt_def1 243
+#define pre 247
+#define post 248
+#define post_post 249 \
+
+#define id_byte 2 \
+
+#define dvi_out(X) {dvi_buf[dvi_ptr]= X;incr(dvi_ptr) ; \
+if(dvi_ptr==dvi_limit) dvi_swap() ; \
+} \
+
+#define movement_node_size 3
+#define location(X) mem[X+2].i \
+
+#define y_here 1
+#define z_here 2
+#define yz_OK 3
+#define y_OK 4
+#define z_OK 5
+#define d_fixed 6 \
+
+#define none_seen 0
+#define y_seen 6
+#define z_seen 12 \
+
+#define synch_h if(cur_h!=dvi_h) \
+{movement(cur_h-dvi_h,right1) ;dvi_h= cur_h; \
+}
+#define synch_v if(cur_v!=dvi_v) \
+{movement(cur_v-dvi_v,down1) ;dvi_v= cur_v; \
+} \
+
+#define billion float_constant(1000000000)
+#define vet_glue(X) glue_temp= X; \
+if(glue_temp> billion) \
+glue_temp= billion; \
+else if(glue_temp<-billion) \
+glue_temp= -billion \
+
+#define exactly 0
+#define additional 1
+#define natural 0,additional \
+
+#define noad_size 4
+#define nucleus(X) X+1
+#define supscr(X) X+2
+#define subscr(X) X+3
+#define math_type link
+#define fam font
+#define math_char 1
+#define sub_box 2
+#define sub_mlist 3
+#define math_text_char 4 \
+
+#define ord_noad (unset_node+3)
+#define op_noad (ord_noad+1)
+#define bin_noad (ord_noad+2)
+#define rel_noad (ord_noad+3)
+#define open_noad (ord_noad+4)
+#define close_noad (ord_noad+5)
+#define punct_noad (ord_noad+6)
+#define inner_noad (ord_noad+7)
+#define limits 1
+#define no_limits 2 \
+
+#define left_delimiter(X) X+4
+#define right_delimiter(X) X+5
+#define radical_noad (inner_noad+1)
+#define radical_noad_size 5
+#define fraction_noad (radical_noad+1)
+#define fraction_noad_size 6
+#define small_fam(X) mem[X].qqqq.b0
+#define small_char(X) mem[X].qqqq.b1
+#define large_fam(X) mem[X].qqqq.b2
+#define large_char(X) mem[X].qqqq.b3
+#define thickness width
+#define default_code 010000000000
+#define numerator supscr
+#define denominator subscr \
+
+#define under_noad (fraction_noad+1)
+#define over_noad (under_noad+1)
+#define accent_noad (over_noad+1)
+#define accent_noad_size 5
+#define accent_chr(X) X+4
+#define vcenter_noad (accent_noad+1)
+#define left_noad (vcenter_noad+1)
+#define right_noad (left_noad+1)
+#define delimiter nucleus
+#define scripts_allowed(X) (type(X) >=ord_noad) &&(type(X) <left_noad) \
+
+#define style_node (unset_node+1)
+#define style_node_size 3
+#define display_style 0
+#define text_style 2
+#define script_style 4
+#define script_script_style 6
+#define cramped 1 \
+
+#define choice_node (unset_node+2)
+#define display_mlist(X) info(X+1)
+#define text_mlist(X) link(X+1)
+#define script_mlist(X) info(X+2)
+#define script_script_mlist(X) link(X+2) \
+
+#define text_size 0
+#define script_size 16
+#define script_script_size 32 \
+
+#define mathsy_end(X) fam_fnt(2+X) ]].sc
+#define mathsy(X) font_info[X+param_base[mathsy_end
+#define math_x_height mathsy(5)
+#define math_quad mathsy(6)
+#define num1 mathsy(8)
+#define num2 mathsy(9)
+#define num3 mathsy(10)
+#define denom1 mathsy(11)
+#define denom2 mathsy(12)
+#define sup1 mathsy(13)
+#define sup2 mathsy(14)
+#define sup3 mathsy(15)
+#define sub1 mathsy(16)
+#define sub2 mathsy(17)
+#define sup_drop mathsy(18)
+#define sub_drop mathsy(19)
+#define delim1 mathsy(20) \
+
+#define delim2 mathsy(21)
+#define axis_height mathsy(22)
+#define total_mathsy_params 22 \
+
+#define mathex(X) font_info[X+param_base[fam_fnt(3+cur_size) ]].sc
+#define default_rule_thickness mathex(8)
+#define big_op_spacing1 mathex(9)
+#define big_op_spacing2 mathex(10)
+#define big_op_spacing3 mathex(11)
+#define big_op_spacing4 mathex(12)
+#define big_op_spacing5 mathex(13)
+#define total_mathex_params 13 \
+
+#define cramped_style(X) 2*(X/2) +cramped
+#define sub_style(X) 2*(X/4) +script_style+cramped
+#define sup_style(X) 2*(X/4) +script_style+(X%2)
+#define num_style(X) X+2-2*(X/6)
+#define denom_style(X) 2*(X/2) +cramped+2-2*(X/6) \
+
+#define mu_mult(X) nx_plus_y(n,X,xn_over_d(X,f,0200000) ) \
+
+#define new_hlist(X) mem[nucleus(X) ].i \
+
+#define choose_mlist(X) {p= X(q) ;X(q) = null;} \
+
+#define math_spacing_str \
+ \
+"math_spacing" \
+ \
+
+#define u_part(X) mem[X+height_offset].i
+#define v_part(X) mem[X+depth_offset].i
+#define extra_info(X) info(X+list_offset) \
+
+#define preamble link(align_head)
+#define align_stack_node_size 5 \
+
+#define span_code 256
+#define cr_code 257
+#define cr_cr_code (cr_code+1)
+#define end_template_token cs_token_flag+frozen_end_template \
+
+#define span_node_size 2 \
+
+#define tight_fit 3 \
+
+#define loose_fit 1 \
+
+#define very_loose_fit 0 \
+
+#define decent_fit 2 \
+
+#define active_node_size 3
+#define fitness subtype
+#define break_node rlink
+#define line_number llink
+#define total_demerits(X) mem[X+2].i
+#define unhyphenated 0
+#define hyphenated 1
+#define last_active active \
+
+#define passive_node_size 2
+#define cur_break rlink
+#define prev_break llink
+#define serial info \
+
+#define delta_node_size 7
+#define delta_node 2 \
+
+#define do_all_six(X) X(1) ;X(2) ;X(3) ;X(4) ;X(5) ;X(6) \
+
+#define check_shrinkage(X) if((shrink_order(X) !=normal) &&(shrink(X) !=0) ) \
+{X= finite_shrink(X) ; \
+} \
+
+#define copy_to_cur_active(X) cur_active_width[X]= active_width[X]
+#define update_width(X) \
+cur_active_width[X]= cur_active_width[X]+mem[r+X].sc \
+
+#define awful_bad 07777777777 \
+
+#define set_break_width_to_background(X) break_width[X]= background[X] \
+
+#define convert_to_break_width(X) \
+mem[prev_r+X].sc= mem[prev_r+X].sc \
+-cur_active_width[X]+break_width[X]
+#define store_break_width(X) active_width[X]= break_width[X]
+#define new_delta_to_break_width(X) \
+mem[q+X].sc= break_width[X]-cur_active_width[X] \
+
+#define new_delta_from_break_width(X) mem[q+X].sc= \
+cur_active_width[X]-break_width[X] \
+
+#define combine_two_deltas(X) mem[prev_r+X].sc= mem[prev_r+X].sc+mem[r+X].sc
+#define downdate_width(X) cur_active_width[X]= cur_active_width[X]- \
+mem[prev_r+X].sc \
+
+#define update_active(X) active_width[X]= active_width[X]+mem[r+X].sc \
+
+#define store_background(X) active_width[X]= background[X] \
+
+#define act_width active_width[1]
+#define kern_break {if(!is_char_node(link(cur_p) ) &&auto_breaking) \
+if(type(link(cur_p) ) ==glue_node) try_break(0,unhyphenated) ; \
+act_width= act_width+width(cur_p) ; \
+} \
+
+#define next_break prev_break \
+
+#define append_charnode_to_t(X) {link(t) = get_avail() ;t= link(t) ; \
+font(t) = hf;character(t) = X; \
+}
+#define set_cur_r {if(j<n) cur_r= qi(hu[j+1]) ;else cur_r= bchar; \
+if(odd(hyf[j]) ) cur_rh= hchar;else cur_rh= non_char; \
+} \
+
+#define wrap_lig(X) if(ligature_present) \
+{p= new_ligature(hf,cur_l,link(cur_q) ) ; \
+if(lft_hit) \
+{subtype(p) = 2;lft_hit= false; \
+} \
+if(X) if(lig_stack==null) \
+{incr(subtype(p) ) ;rt_hit= false; \
+} \
+link(cur_q) = p;t= p;ligature_present= false; \
+}
+#define pop_lig_stack {if(lig_ptr(lig_stack) > null) \
+{link(t) = lig_ptr(lig_stack) ; \
+t= link(t) ;incr(j) ; \
+} \
+p= lig_stack;lig_stack= link(p) ;free_node(p,small_node_size) ; \
+if(lig_stack==null) set_cur_r else cur_r= character(lig_stack) ; \
+} \
+
+#define advance_major_tail {major_tail= link(major_tail) ;incr(r_count) ; \
+} \
+
+#define trie_link(X) trie[X].rh
+#define trie_char(X) trie[X].b1
+#define trie_op(X) trie[X].b0 \
+
+#define set_cur_lang if(language<=0) cur_lang= 0; \
+else if(language> 255) cur_lang= 0; \
+else cur_lang= language \
+
+#define trie_root trie_l[0] \
+
+#define trie_ref trie_hash
+#define trie_back(X) trie[X].lh \
+
+#define active_height active_width
+#define cur_height active_height[1]
+#define set_height_zero(X) active_height[X]= 0 \
+
+#define deplorable 100000 \
+
+#define inserts_only 1 \
+
+#define box_there 2 \
+
+#define page_ins_node_size 4
+#define inserting 0
+#define split_up 1
+#define broken_ptr(X) link(X+1) \
+
+#define broken_ins(X) info(X+1)
+#define last_ins_ptr(X) link(X+2)
+#define best_ins_ptr(X) info(X+2) \
+
+#define page_goal page_so_far[0]
+#define page_total page_so_far[1]
+#define page_shrink page_so_far[6]
+#define page_depth page_so_far[7] \
+
+#define print_plus_end(X) print_str(X) ;}
+#define print_plus(X) if(page_so_far[X]!=0) \
+{print_str(" plus ") ;print_scaled(page_so_far[X]) ;print_plus_end \
+
+#define set_page_so_far_zero(X) page_so_far[X]= 0 \
+
+#define contrib_tail nest[0].tail_field \
+
+#define adjust_space_factor \
+main_s= sf_code(cur_chr) ; \
+if(main_s==1000) space_factor= 1000; \
+else if(main_s<1000) \
+{if(main_s> 0) space_factor= main_s; \
+} \
+else if(space_factor<1000) space_factor= 1000; \
+else space_factor= main_s \
+
+#define pack_lig(X) \
+{main_p= new_ligature(main_f,cur_l,link(cur_q) ) ; \
+if(lft_hit) \
+{subtype(main_p) = 2;lft_hit= false; \
+} \
+if(X) if(lig_stack==null) \
+{incr(subtype(main_p) ) ;rt_hit= false; \
+} \
+link(cur_q) = main_p;tail= main_p;ligature_present= false; \
+} \
+
+#define wrapup(X) if(cur_l<non_char) \
+{if(link(cur_q) > null) \
+if(character(tail) ==qi(hyphen_char[main_f]) ) ins_disc= true; \
+if(ligature_present) pack_lig(X) ; \
+if(ins_disc) \
+{ins_disc= false; \
+if(mode> 0) tail_append(new_disc() ) ; \
+} \
+} \
+
+#define any_mode(X) case vmode+X:case hmode+X:case mmode+X \
+
+#define non_math(X) case vmode+X:case hmode+X \
+
+#define fil_code 0
+#define fill_code 1
+#define ss_code 2
+#define fil_neg_code 3
+#define skip_code 4
+#define mskip_code 5 \
+
+#define box_flag 010000000000
+#define ship_out_flag box_flag+512
+#define leader_flag box_flag+513
+#define box_code 0
+#define copy_code 1
+#define last_box_code 2
+#define vsplit_code 3
+#define vtop_code 4 \
+
+#define fam_in_range ((cur_fam>=0) &&(cur_fam<16) ) \
+
+#define above_code 0
+#define over_code 1
+#define atop_code 2
+#define delimited_code 3 \
+
+#define global (a>=4)
+#define define(X,Y,Z) if(global) geq_define(X,Y,Z) ;else eq_define(X,Y,Z)
+#define word_define(X,Y) if(global) geq_word_define(X,Y) ;else eq_word_define(X,Y) \
+
+#define char_def_code 0
+#define math_char_def_code 1
+#define count_def_code 2
+#define dimen_def_code 3
+#define skip_def_code 4
+#define mu_skip_def_code 5
+#define toks_def_code 6 \
+
+#define show_code 0
+#define show_box_code 1
+#define show_the_code 2
+#define show_lists 3 \
+
+#define too_small(X) {wake_up_terminal; \
+wterm_ln("---! Must increase the %s",X) ; \
+ \
+goto bad_fmt; \
+} \
+
+#define dump_wd(X) {fmt_file.d= X;put(fmt_file) ;}
+#define dump_int(X) {fmt_file.d.i= X;put(fmt_file) ;}
+#define dump_hh(X) {fmt_file.d.hh= X;put(fmt_file) ;}
+#define dump_qqqq(X) {fmt_file.d.qqqq= X;put(fmt_file) ;} \
+
+#define undump_wd(X) {get(fmt_file) ;X= fmt_file.d;}
+#define undump_int(X) {get(fmt_file) ;X= fmt_file.d.i;}
+#define undump_hh(X) {get(fmt_file) ;X= fmt_file.d.hh;}
+#define undump_qqqq(X) {get(fmt_file) ;X= fmt_file.d.qqqq;}
+#define undump_end_end(X) X= x;}
+#define undump_end(X) (x> X) ) goto bad_fmt;else undump_end_end
+#define undump(X) {undump_int(x) ;if((x<X) ||undump_end
+#define undump_size_end_end(X) too_small(X) else undump_end_end
+#define undump_size_end(X) if(x> X) undump_size_end_end
+#define undump_size(X) {undump_int(x) ; \
+if(x<X) goto bad_fmt;undump_size_end \
+
+#define dump_four_ASCII \
+w.b0= qi(so(str_pool[k]) ) ;w.b1= qi(so(str_pool[k+1]) ) ; \
+w.b2= qi(so(str_pool[k+2]) ) ;w.b3= qi(so(str_pool[k+3]) ) ; \
+dump_qqqq(w) \
+
+#define undump_four_ASCII \
+undump_qqqq(w) ; \
+str_pool[k]= si(qo(w.b0) ) ;str_pool[k+1]= si(qo(w.b1) ) ; \
+str_pool[k+2]= si(qo(w.b2) ) ;str_pool[k+3]= si(qo(w.b3) ) \
+
+#define write_node_size 2
+#define open_node_size 3
+#define open_node 0
+#define write_node 1
+#define close_node 2
+#define special_node 3
+#define language_node 4
+#define what_lang(X) link(X+1)
+#define what_lhm(X) type(X+1)
+#define what_rhm(X) subtype(X+1)
+#define write_tokens(X) link(X+1)
+#define write_stream(X) info(X+1)
+#define open_name(X) link(X+1)
+#define open_area(X) info(X+2)
+#define open_ext(X) link(X+2) \
+
+#define immediate_code 4
+#define set_language_code 5 \
+
+#define adv_past(X) if(subtype(X) ==language_node) \
+{cur_lang= what_lang(X) ;l_hyf= what_lhm(X) ;r_hyf= what_rhm(X) ;} \
+
+#define end_write_token cs_token_flag+end_write \
+
+#define str_0_255 "^^@^^A^^B^^C^^D^^E^^F^^G^^H^^I^^J^^K^^L^^M^^N^^O" \
+"^^P^^Q^^R^^S^^T^^U^^V^^W^^X^^Y^^Z^^[^^\\^^]^^^^^_" \
+" !\"#$%&'()*+,-./" \
+"0123456789:;<=>?" \
+"@ABCDEFGHIJKLMNO" \
+"PQRSTUVWXYZ[\\]^_" \
+"`abcdefghijklmno" \
+"pqrstuvwxyz{|}~^^?" \
+"^^80^^81^^82^^83^^84^^85^^86^^87^^88^^89^^8a^^8b^^8c^^8d^^8e^^8f" \
+"^^90^^91^^92^^93^^94^^95^^96^^97^^98^^99^^9a^^9b^^9c^^9d^^9e^^9f" \
+"^^a0^^a1^^a2^^a3^^a4^^a5^^a6^^a7^^a8^^a9^^aa^^ab^^ac^^ad^^ae^^af" \
+"^^b0^^b1^^b2^^b3^^b4^^b5^^b6^^b7^^b8^^b9^^ba^^bb^^bc^^bd^^be^^bf" \
+"^^c0^^c1^^c2^^c3^^c4^^c5^^c6^^c7^^c8^^c9^^ca^^cb^^cc^^cd^^ce^^cf" \
+"^^d0^^d1^^d2^^d3^^d4^^d5^^d6^^d7^^d8^^d9^^da^^db^^dc^^dd^^de^^df" \
+"^^e0^^e1^^e2^^e3^^e4^^e5^^e6^^e7^^e8^^e9^^ea^^eb^^ec^^ed^^ee^^ef" \
+"^^f0^^f1^^f2^^f3^^f4^^f5^^f6^^f7^^f8^^f9^^fa^^fb^^fc^^fd^^fe^^ff"
+#define str_start_0_255 0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45, \
+48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93, \
+96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, \
+112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, \
+128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, \
+144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, \
+160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, \
+176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, \
+194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,254, \
+258,262,266,270,274,278,282,286,290,294,298,302,306,310,314,318, \
+322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382, \
+386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446, \
+450,454,458,462,466,470,474,478,482,486,490,494,498,502,506,510, \
+514,518,522,526,530,534,538,542,546,550,554,558,562,566,570,574, \
+578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638, \
+642,646,650,654,658,662,666,670,674,678,682,686,690,694,698,702,
+#define str_256 "???"
+#define str_257 "m2d5c2l5x2v5i"
+#define str_258 "batchmode"
+#define str_259 "nonstopmode"
+#define str_260 "scrollmode"
+#define str_261 "CLOBBERED."
+#define str_262 "fil"
+#define str_263 "unset"
+#define str_264 "rule("
+#define str_265 "insert"
+#define str_266 "glue"
+#define str_267 "nonscript"
+#define str_268 "mskip"
+#define str_269 "mu"
+#define str_270 ""
+#define empty_string 270
+#define str_271 "kern"
+#define str_272 "mkern"
+#define str_273 "math"
+#define str_274 "penalty "
+#define str_275 "discretionary"
+#define str_276 "mark"
+#define str_277 "vadjust"
+#define str_278 "flushing"
+#define str_279 "copying"
+#define str_280 "lineskip"
+#define str_281 "baselineskip"
+#define str_282 "parskip"
+#define str_283 "abovedisplayskip"
+#define str_284 "belowdisplayskip"
+#define str_285 "abovedisplayshortskip"
+#define str_286 "belowdisplayshortskip"
+#define str_287 "leftskip"
+#define str_288 "rightskip"
+#define str_289 "topskip"
+#define str_290 "splittopskip"
+#define str_291 "tabskip"
+#define str_292 "spaceskip"
+#define str_293 "xspaceskip"
+#define str_294 "parfillskip"
+#define str_295 "thinmuskip"
+#define str_296 "medmuskip"
+#define str_297 "thickmuskip"
+#define str_298 "skip"
+#define str_299 "muskip"
+#define str_300 "pt"
+#define str_301 "output"
+#define str_302 "everypar"
+#define str_303 "everymath"
+#define str_304 "everydisplay"
+#define str_305 "everyhbox"
+#define str_306 "everyvbox"
+#define str_307 "everyjob"
+#define str_308 "everycr"
+#define str_309 "errhelp"
+#define str_310 "toks"
+#define str_311 "parshape"
+#define str_312 "box"
+#define str_313 "textfont"
+#define str_314 "scriptfont"
+#define str_315 "scriptscriptfont"
+#define str_316 "catcode"
+#define str_317 "lccode"
+#define str_318 "uccode"
+#define str_319 "sfcode"
+#define str_320 "mathcode"
+#define str_321 "pretolerance"
+#define str_322 "tolerance"
+#define str_323 "linepenalty"
+#define str_324 "hyphenpenalty"
+#define str_325 "exhyphenpenalty"
+#define str_326 "clubpenalty"
+#define str_327 "widowpenalty"
+#define str_328 "displaywidowpenalty"
+#define str_329 "brokenpenalty"
+#define str_330 "binoppenalty"
+#define str_331 "relpenalty"
+#define str_332 "predisplaypenalty"
+#define str_333 "postdisplaypenalty"
+#define str_334 "interlinepenalty"
+#define str_335 "doublehyphendemerits"
+#define str_336 "finalhyphendemerits"
+#define str_337 "adjdemerits"
+#define str_338 "mag"
+#define str_339 "delimiterfactor"
+#define str_340 "looseness"
+#define str_341 "time"
+#define str_342 "day"
+#define str_343 "month"
+#define str_344 "year"
+#define str_345 "showboxbreadth"
+#define str_346 "showboxdepth"
+#define str_347 "hbadness"
+#define str_348 "vbadness"
+#define str_349 "pausing"
+#define str_350 "tracingonline"
+#define str_351 "tracingmacros"
+#define str_352 "tracingstats"
+#define str_353 "tracingparagraphs"
+#define str_354 "tracingpages"
+#define str_355 "tracingoutput"
+#define str_356 "tracinglostchars"
+#define str_357 "tracingcommands"
+#define str_358 "tracingrestores"
+#define str_359 "uchyph"
+#define str_360 "outputpenalty"
+#define str_361 "maxdeadcycles"
+#define str_362 "hangafter"
+#define str_363 "floatingpenalty"
+#define str_364 "globaldefs"
+#define str_365 "fam"
+#define str_366 "escapechar"
+#define str_367 "defaulthyphenchar"
+#define str_368 "defaultskewchar"
+#define str_369 "endlinechar"
+#define str_370 "newlinechar"
+#define str_371 "language"
+#define str_372 "lefthyphenmin"
+#define str_373 "righthyphenmin"
+#define str_374 "holdinginserts"
+#define str_375 "errorcontextlines"
+#define str_376 "count"
+#define str_377 "delcode"
+#define str_378 "parindent"
+#define str_379 "mathsurround"
+#define str_380 "lineskiplimit"
+#define str_381 "hsize"
+#define str_382 "vsize"
+#define str_383 "maxdepth"
+#define str_384 "splitmaxdepth"
+#define str_385 "boxmaxdepth"
+#define str_386 "hfuzz"
+#define str_387 "vfuzz"
+#define str_388 "delimitershortfall"
+#define str_389 "nulldelimiterspace"
+#define str_390 "scriptspace"
+#define str_391 "predisplaysize"
+#define str_392 "displaywidth"
+#define str_393 "displayindent"
+#define str_394 "overfullrule"
+#define str_395 "hangindent"
+#define str_396 "hoffset"
+#define str_397 "voffset"
+#define str_398 "emergencystretch"
+#define str_399 "dimen"
+#define str_400 "notexpanded:"
+#define str_401 "csname"
+#define str_402 "endcsname"
+#define str_403 "IMPOSSIBLE."
+#define str_404 "NONEXISTENT."
+#define str_405 "accent"
+#define str_406 "advance"
+#define str_407 "afterassignment"
+#define str_408 "aftergroup"
+#define str_409 "begingroup"
+#define str_410 "char"
+#define str_411 "delimiter"
+#define str_412 "divide"
+#define str_413 "endgroup"
+#define str_414 "expandafter"
+#define str_415 "font"
+#define str_416 "fontdimen"
+#define str_417 "halign"
+#define str_418 "hrule"
+#define str_419 "ignorespaces"
+#define str_420 "mathaccent"
+#define str_421 "mathchar"
+#define str_422 "mathchoice"
+#define str_423 "multiply"
+#define str_424 "noalign"
+#define str_425 "noboundary"
+#define str_426 "noexpand"
+#define str_427 "omit"
+#define str_428 "penalty"
+#define str_429 "prevgraf"
+#define str_430 "radical"
+#define str_431 "read"
+#define str_432 "relax"
+#define str_433 "setbox"
+#define str_434 "the"
+#define str_435 "valign"
+#define str_436 "vcenter"
+#define str_437 "vrule"
+#define str_438 "curlevel"
+#define str_439 "retaining"
+#define str_440 "restoring"
+#define str_441 "ETC."
+#define str_442 "BAD."
+#define str_443 "write"
+#define str_444 "par"
+#define str_445 "input"
+#define str_446 "endinput"
+#define str_447 "topmark"
+#define str_448 "firstmark"
+#define str_449 "botmark"
+#define str_450 "splitfirstmark"
+#define str_451 "splitbotmark"
+#define str_452 "spacefactor"
+#define str_453 "prevdepth"
+#define str_454 "deadcycles"
+#define str_455 "insertpenalties"
+#define str_456 "wd"
+#define str_457 "ht"
+#define str_458 "dp"
+#define str_459 "lastpenalty"
+#define str_460 "lastkern"
+#define str_461 "lastskip"
+#define str_462 "inputlineno"
+#define str_463 "badness"
+#define str_464 "true"
+#define str_465 "em"
+#define str_466 "ex"
+#define str_467 "in"
+#define str_468 "pc"
+#define str_469 "cm"
+#define str_470 "mm"
+#define str_471 "bp"
+#define str_472 "dd"
+#define str_473 "cc"
+#define str_474 "sp"
+#define str_475 "plus"
+#define str_476 "minus"
+#define str_477 "width"
+#define str_478 "height"
+#define str_479 "depth"
+#define str_480 "number"
+#define str_481 "romannumeral"
+#define str_482 "string"
+#define str_483 "meaning"
+#define str_484 "fontname"
+#define str_485 "jobname"
+#define str_486 "if"
+#define str_487 "ifcat"
+#define str_488 "ifnum"
+#define str_489 "ifdim"
+#define str_490 "ifodd"
+#define str_491 "ifvmode"
+#define str_492 "ifhmode"
+#define str_493 "ifmmode"
+#define str_494 "ifinner"
+#define str_495 "ifvoid"
+#define str_496 "ifhbox"
+#define str_497 "ifvbox"
+#define str_498 "ifx"
+#define str_499 "ifeof"
+#define str_500 "iftrue"
+#define str_501 "iffalse"
+#define str_502 "ifcase"
+#define str_503 "fi"
+#define str_504 "or"
+#define str_505 "else"
+#define str_506 "TeXinputs/"
+#define TEX_area 506
+#define str_507 "TeXfonts/"
+#define TEX_font_area 507
+#define str_508 ".fmt"
+#define format_extension 508
+#define str_509 ".log"
+#define str_510 ".dvi"
+#define str_511 "input file name"
+#define str_512 ".tex"
+#define str_513 "texput"
+#define str_514 "nullfont"
+#define str_515 ".tfm"
+#define str_516 "vlistout"
+#define str_517 "to"
+#define str_518 "spread"
+#define str_519 "vpack"
+#define str_520 "displaystyle"
+#define str_521 "textstyle"
+#define str_522 "scriptstyle"
+#define str_523 "scriptscriptstyle"
+#define str_524 "mathord"
+#define str_525 "mathop"
+#define str_526 "mathbin"
+#define str_527 "mathrel"
+#define str_528 "mathopen"
+#define str_529 "mathclose"
+#define str_530 "mathpunct"
+#define str_531 "mathinner"
+#define str_532 "overline"
+#define str_533 "underline"
+#define str_534 "left"
+#define str_535 "right"
+#define str_536 "limits"
+#define str_537 "nolimits"
+#define str_538 "fraction, thickness "
+#define str_539 "mlist1"
+#define str_540 "mlist2"
+#define str_541 "mlist3"
+#define str_542 "0234000122*4000133**3**344*0400400*000000234000111*1111112341011"
+#define math_spacing 542
+#define str_543 "mlist4"
+#define str_544 "span"
+#define str_545 "cr"
+#define str_546 "crcr"
+#define str_547 "endtemplate"
+#define str_548 "endv"
+#define str_549 "256 spans"
+#define str_550 "align1"
+#define str_551 "align0"
+#define str_552 "disc1"
+#define str_553 "disc2"
+#define str_554 "paragraph"
+#define str_555 "disc3"
+#define str_556 "disc4"
+#define str_557 "line breaking"
+#define str_558 "hyphenation"
+#define str_559 "patterns"
+#define str_560 "pruning"
+#define str_561 "vertbreak"
+#define str_562 "vsplit"
+#define str_563 "vbox"
+#define str_564 "pagegoal"
+#define str_565 "pagetotal"
+#define str_566 "pagestretch"
+#define str_567 "pagefilstretch"
+#define str_568 "pagefillstretch"
+#define str_569 "pagefilllstretch"
+#define str_570 "pageshrink"
+#define str_571 "pagedepth"
+#define str_572 "page"
+#define str_573 "end"
+#define str_574 "dump"
+#define str_575 "hskip"
+#define str_576 "hfil"
+#define str_577 "hfill"
+#define str_578 "hss"
+#define str_579 "hfilneg"
+#define str_580 "vskip"
+#define str_581 "vfil"
+#define str_582 "vfill"
+#define str_583 "vss"
+#define str_584 "vfilneg"
+#define str_585 "right."
+#define str_586 "rightbrace"
+#define str_587 "moveleft"
+#define str_588 "moveright"
+#define str_589 "raise"
+#define str_590 "lower"
+#define str_591 "copy"
+#define str_592 "lastbox"
+#define str_593 "vtop"
+#define str_594 "hbox"
+#define str_595 "shipout"
+#define str_596 "leaders"
+#define str_597 "cleaders"
+#define str_598 "xleaders"
+#define str_599 "indent"
+#define str_600 "noindent"
+#define str_601 "unpenalty"
+#define str_602 "unkern"
+#define str_603 "unskip"
+#define str_604 "unhbox"
+#define str_605 "unhcopy"
+#define str_606 "unvbox"
+#define str_607 "unvcopy"
+#define str_608 "eqno"
+#define str_609 "leqno"
+#define str_610 "displaylimits"
+#define str_611 "above"
+#define str_612 "over"
+#define str_613 "atop"
+#define str_614 "abovewithdelims"
+#define str_615 "overwithdelims"
+#define str_616 "atopwithdelims"
+#define str_617 "display"
+#define str_618 "long"
+#define str_619 "outer"
+#define str_620 "global"
+#define str_621 "def"
+#define str_622 "gdef"
+#define str_623 "edef"
+#define str_624 "xdef"
+#define str_625 "prefix"
+#define str_626 "inaccessible"
+#define str_627 "let"
+#define str_628 "futurelet"
+#define str_629 "chardef"
+#define str_630 "mathchardef"
+#define str_631 "countdef"
+#define str_632 "dimendef"
+#define str_633 "skipdef"
+#define str_634 "muskipdef"
+#define str_635 "toksdef"
+#define str_636 "by"
+#define str_637 "hyphenchar"
+#define str_638 "skewchar"
+#define str_639 "FONT"
+#define str_640 "at"
+#define str_641 "scaled"
+#define str_642 "errorstopmode"
+#define str_643 "openin"
+#define str_644 "closein"
+#define str_645 "message"
+#define str_646 "errmessage"
+#define str_647 "lowercase"
+#define str_648 "uppercase"
+#define str_649 "show"
+#define str_650 "showbox"
+#define str_651 "showthe"
+#define str_652 "showlists"
+#define str_653 "long macro"
+#define str_654 "outer macro"
+#define str_655 "outer endtemplate"
+#define str_656 " (INITEX)"
+#define str_657 "end occurred "
+#define str_658 "openout"
+#define str_659 "closeout"
+#define str_660 "special"
+#define str_661 "immediate"
+#define str_662 "setlanguage"
+#define str_663 "ext1"
+#define str_664 "ext2"
+#define str_665 "ext3"
+#define str_666 "endwrite"
+#define str_667 "ext4"
+
+#line 358 "tex.w"
+
+
+/*:9*//*56:*/
+#line 1447 "tex.w"
+
+#define put(file) fwrite(&((file).d),sizeof((file).d),1,(file).f)
+#define get(file) fread(&((file).d),sizeof((file).d),1,(file).f)
+
+#define reset(file,name,mode) ((file).f= fopen((char *)(name)+1,mode),\
+ (file).f!=NULL?get(file):0)
+#define rewrite(file,name,mode) ((file).f= fopen((char *)(name)+1,mode))
+#define close(file) fclose((file).f)
+#define eof(file) feof((file).f)
+#define eoln(file) ((file).d=='\n'||eof(file))
+#define erstat(file) ((file).f==NULL?-1:ferror((file).f))
+
+#define read(file,x) ((x)= (file).d,get(file))
+#define read_ln(file) do get(file); while (!eoln(file))
+
+#define write(file, format,...) fprintf(file.f,format,## __VA_ARGS__)
+#define write_ln(file,...) write(file,__VA_ARGS__"\n")
+
+#define wterm(format,...) write(term_out,format, ## __VA_ARGS__)
+#define wterm_ln(format,...) wterm(format "\n", ## __VA_ARGS__)
+#define wterm_cr write(term_out,"\n")
+#define wlog(format, ...) write(log_file,format, ## __VA_ARGS__)
+#define wlog_ln(format, ...) wlog(format "\n", ## __VA_ARGS__)
+#define wlog_cr write(log_file,"\n")
+
+/*:56*/
+#line 261 "tex.w"
+
+
+/*6:*/
+#line 289 "tex.w"
+
+
+
+
+/*:6*/
+#line 263 "tex.w"
+
+/*11:*/
+#line 396 "tex.w"
+
+enum{mem_max= 30000};
+
+
+enum{mem_min= 0};
+
+
+enum{buf_size= 500};
+
+
+enum{error_line= 72};
+enum{half_error_line= 42};
+
+enum{max_print_line= 79};
+enum{stack_size= 200};
+enum{max_in_open= 6};
+
+enum{font_max= 75};
+
+enum{font_mem_size= 20000};
+enum{param_size= 60};
+enum{nest_size= 40};
+enum{max_strings= 3000};
+enum{string_vacancies= 8000};
+
+
+enum{pool_size= 32000};
+
+
+
+enum{save_size= 600};
+
+enum{trie_size= 8000};
+
+enum{trie_op_size= 500};
+enum{dvi_buf_size= 800};
+enum{file_name_size= 40};
+const char*pool_name= "TeXformats:TEX.POOL ";
+
+
+
+/*:11*/
+#line 264 "tex.w"
+
+/*18:*/
+#line 539 "tex.w"
+
+typedef uint8_t ASCII_code;
+
+/*:18*//*25:*/
+#line 774 "tex.w"
+
+typedef uint8_t eight_bits;
+typedef struct{FILE*f;text_char d;}alpha_file;
+typedef struct{FILE*f;eight_bits d;}byte_file;
+
+/*:25*//*38:*/
+#line 1132 "tex.w"
+
+typedef uint16_t pool_pointer;
+typedef uint16_t str_number;
+typedef uint8_t packed_ASCII_code;
+
+/*:38*//*101:*/
+#line 2198 "tex.w"
+
+typedef int scaled;
+typedef uint32_t nonnegative_integer;
+typedef uint8_t small_number;
+
+/*:101*//*109:*/
+#line 2390 "tex.w"
+
+typedef float32_t glue_ratio;
+
+/*:109*//*113:*/
+#line 2494 "tex.w"
+
+typedef uint8_t quarterword;
+typedef uint16_t halfword;
+typedef uint8_t two_choices;
+typedef uint8_t four_choices;
+typedef struct{
+halfword rh;
+union{
+halfword lh;
+struct{quarterword b0;quarterword b1;};
+};}two_halves;
+typedef struct{
+quarterword b0;
+quarterword b1;
+quarterword b2;
+quarterword b3;
+}four_quarters;
+typedef struct{
+union{
+int i;
+glue_ratio gr;
+two_halves hh;
+four_quarters qqqq;
+};}memory_word;
+typedef struct{FILE*f;memory_word d;}word_file;
+
+/*:113*//*150:*/
+#line 3212 "tex.w"
+
+typedef uint8_t glue_ord;
+
+/*:150*//*212:*/
+#line 4369 "tex.w"
+
+typedef struct{int16_t mode_field;
+pointer head_field,tail_field;
+int pg_field,ml_field;
+memory_word aux_field;
+}list_state_record;
+
+/*:212*//*269:*/
+#line 5934 "tex.w"
+
+typedef uint8_t group_code;
+
+/*:269*//*300:*/
+#line 6514 "tex.w"
+
+typedef struct{
+quarterword state_field,index_field;
+halfword start_field,loc_field,limit_field,name_field;
+}in_state_record;
+
+/*:300*//*548:*/
+#line 10743 "tex.w"
+
+typedef uint8_t internal_font_number;
+typedef uint16_t font_index;
+
+/*:548*//*594:*/
+#line 11923 "tex.w"
+
+typedef uint16_t dvi_index;
+
+/*:594*//*920:*/
+#line 18138 "tex.w"
+
+typedef uint16_t trie_pointer;
+
+/*:920*//*925:*/
+#line 18204 "tex.w"
+
+typedef uint16_t hyph_pointer;
+
+/*:925*/
+#line 265 "tex.w"
+
+/*13:*/
+#line 467 "tex.w"
+
+int bad;
+
+/*:13*//*20:*/
+#line 579 "tex.w"
+
+ASCII_code xord[256];
+
+uint8_t xchr[256];
+
+
+/*:20*//*26:*/
+#line 791 "tex.w"
+
+uint8_t name_of_file0[file_name_size+1]= {0},*const name_of_file= name_of_file0-1;
+
+uint8_t name_length;
+
+
+/*:26*//*30:*/
+#line 891 "tex.w"
+
+ASCII_code buffer[buf_size+1];
+uint16_t first;
+uint16_t last;
+uint16_t max_buf_stack;
+
+/*:30*//*32:*/
+#line 964 "tex.w"
+
+alpha_file term_in;
+alpha_file term_out;
+
+/*:32*//*39:*/
+#line 1137 "tex.w"
+
+/*1795:*/
+#line 26438 "tex.w"
+
+typedef enum{
+str_start_256= sizeof(str_0_255)-1,
+str_start_257= str_start_256+sizeof(str_256)-1,
+str_start_258= str_start_257+sizeof(str_257)-1,
+str_start_259= str_start_258+sizeof(str_258)-1,
+str_start_260= str_start_259+sizeof(str_259)-1,
+str_start_261= str_start_260+sizeof(str_260)-1,
+str_start_262= str_start_261+sizeof(str_261)-1,
+str_start_263= str_start_262+sizeof(str_262)-1,
+str_start_264= str_start_263+sizeof(str_263)-1,
+str_start_265= str_start_264+sizeof(str_264)-1,
+str_start_266= str_start_265+sizeof(str_265)-1,
+str_start_267= str_start_266+sizeof(str_266)-1,
+str_start_268= str_start_267+sizeof(str_267)-1,
+str_start_269= str_start_268+sizeof(str_268)-1,
+str_start_270= str_start_269+sizeof(str_269)-1,
+str_start_271= str_start_270+sizeof(str_270)-1,
+str_start_272= str_start_271+sizeof(str_271)-1,
+str_start_273= str_start_272+sizeof(str_272)-1,
+str_start_274= str_start_273+sizeof(str_273)-1,
+str_start_275= str_start_274+sizeof(str_274)-1,
+str_start_276= str_start_275+sizeof(str_275)-1,
+str_start_277= str_start_276+sizeof(str_276)-1,
+str_start_278= str_start_277+sizeof(str_277)-1,
+str_start_279= str_start_278+sizeof(str_278)-1,
+str_start_280= str_start_279+sizeof(str_279)-1,
+str_start_281= str_start_280+sizeof(str_280)-1,
+str_start_282= str_start_281+sizeof(str_281)-1,
+str_start_283= str_start_282+sizeof(str_282)-1,
+str_start_284= str_start_283+sizeof(str_283)-1,
+str_start_285= str_start_284+sizeof(str_284)-1,
+str_start_286= str_start_285+sizeof(str_285)-1,
+str_start_287= str_start_286+sizeof(str_286)-1,
+str_start_288= str_start_287+sizeof(str_287)-1,
+str_start_289= str_start_288+sizeof(str_288)-1,
+str_start_290= str_start_289+sizeof(str_289)-1,
+str_start_291= str_start_290+sizeof(str_290)-1,
+str_start_292= str_start_291+sizeof(str_291)-1,
+str_start_293= str_start_292+sizeof(str_292)-1,
+str_start_294= str_start_293+sizeof(str_293)-1,
+str_start_295= str_start_294+sizeof(str_294)-1,
+str_start_296= str_start_295+sizeof(str_295)-1,
+str_start_297= str_start_296+sizeof(str_296)-1,
+str_start_298= str_start_297+sizeof(str_297)-1,
+str_start_299= str_start_298+sizeof(str_298)-1,
+str_start_300= str_start_299+sizeof(str_299)-1,
+str_start_301= str_start_300+sizeof(str_300)-1,
+str_start_302= str_start_301+sizeof(str_301)-1,
+str_start_303= str_start_302+sizeof(str_302)-1,
+str_start_304= str_start_303+sizeof(str_303)-1,
+str_start_305= str_start_304+sizeof(str_304)-1,
+str_start_306= str_start_305+sizeof(str_305)-1,
+str_start_307= str_start_306+sizeof(str_306)-1,
+str_start_308= str_start_307+sizeof(str_307)-1,
+str_start_309= str_start_308+sizeof(str_308)-1,
+str_start_310= str_start_309+sizeof(str_309)-1,
+str_start_311= str_start_310+sizeof(str_310)-1,
+str_start_312= str_start_311+sizeof(str_311)-1,
+str_start_313= str_start_312+sizeof(str_312)-1,
+str_start_314= str_start_313+sizeof(str_313)-1,
+str_start_315= str_start_314+sizeof(str_314)-1,
+str_start_316= str_start_315+sizeof(str_315)-1,
+str_start_317= str_start_316+sizeof(str_316)-1,
+str_start_318= str_start_317+sizeof(str_317)-1,
+str_start_319= str_start_318+sizeof(str_318)-1,
+str_start_320= str_start_319+sizeof(str_319)-1,
+str_start_321= str_start_320+sizeof(str_320)-1,
+str_start_322= str_start_321+sizeof(str_321)-1,
+str_start_323= str_start_322+sizeof(str_322)-1,
+str_start_324= str_start_323+sizeof(str_323)-1,
+str_start_325= str_start_324+sizeof(str_324)-1,
+str_start_326= str_start_325+sizeof(str_325)-1,
+str_start_327= str_start_326+sizeof(str_326)-1,
+str_start_328= str_start_327+sizeof(str_327)-1,
+str_start_329= str_start_328+sizeof(str_328)-1,
+str_start_330= str_start_329+sizeof(str_329)-1,
+str_start_331= str_start_330+sizeof(str_330)-1,
+str_start_332= str_start_331+sizeof(str_331)-1,
+str_start_333= str_start_332+sizeof(str_332)-1,
+str_start_334= str_start_333+sizeof(str_333)-1,
+str_start_335= str_start_334+sizeof(str_334)-1,
+str_start_336= str_start_335+sizeof(str_335)-1,
+str_start_337= str_start_336+sizeof(str_336)-1,
+str_start_338= str_start_337+sizeof(str_337)-1,
+str_start_339= str_start_338+sizeof(str_338)-1,
+str_start_340= str_start_339+sizeof(str_339)-1,
+str_start_341= str_start_340+sizeof(str_340)-1,
+str_start_342= str_start_341+sizeof(str_341)-1,
+str_start_343= str_start_342+sizeof(str_342)-1,
+str_start_344= str_start_343+sizeof(str_343)-1,
+str_start_345= str_start_344+sizeof(str_344)-1,
+str_start_346= str_start_345+sizeof(str_345)-1,
+str_start_347= str_start_346+sizeof(str_346)-1,
+str_start_348= str_start_347+sizeof(str_347)-1,
+str_start_349= str_start_348+sizeof(str_348)-1,
+str_start_350= str_start_349+sizeof(str_349)-1,
+str_start_351= str_start_350+sizeof(str_350)-1,
+str_start_352= str_start_351+sizeof(str_351)-1,
+str_start_353= str_start_352+sizeof(str_352)-1,
+str_start_354= str_start_353+sizeof(str_353)-1,
+str_start_355= str_start_354+sizeof(str_354)-1,
+str_start_356= str_start_355+sizeof(str_355)-1,
+str_start_357= str_start_356+sizeof(str_356)-1,
+str_start_358= str_start_357+sizeof(str_357)-1,
+str_start_359= str_start_358+sizeof(str_358)-1,
+str_start_360= str_start_359+sizeof(str_359)-1,
+str_start_361= str_start_360+sizeof(str_360)-1,
+str_start_362= str_start_361+sizeof(str_361)-1,
+str_start_363= str_start_362+sizeof(str_362)-1,
+str_start_364= str_start_363+sizeof(str_363)-1,
+str_start_365= str_start_364+sizeof(str_364)-1,
+str_start_366= str_start_365+sizeof(str_365)-1,
+str_start_367= str_start_366+sizeof(str_366)-1,
+str_start_368= str_start_367+sizeof(str_367)-1,
+str_start_369= str_start_368+sizeof(str_368)-1,
+str_start_370= str_start_369+sizeof(str_369)-1,
+str_start_371= str_start_370+sizeof(str_370)-1,
+str_start_372= str_start_371+sizeof(str_371)-1,
+str_start_373= str_start_372+sizeof(str_372)-1,
+str_start_374= str_start_373+sizeof(str_373)-1,
+str_start_375= str_start_374+sizeof(str_374)-1,
+str_start_376= str_start_375+sizeof(str_375)-1,
+str_start_377= str_start_376+sizeof(str_376)-1,
+str_start_378= str_start_377+sizeof(str_377)-1,
+str_start_379= str_start_378+sizeof(str_378)-1,
+str_start_380= str_start_379+sizeof(str_379)-1,
+str_start_381= str_start_380+sizeof(str_380)-1,
+str_start_382= str_start_381+sizeof(str_381)-1,
+str_start_383= str_start_382+sizeof(str_382)-1,
+str_start_384= str_start_383+sizeof(str_383)-1,
+str_start_385= str_start_384+sizeof(str_384)-1,
+str_start_386= str_start_385+sizeof(str_385)-1,
+str_start_387= str_start_386+sizeof(str_386)-1,
+str_start_388= str_start_387+sizeof(str_387)-1,
+str_start_389= str_start_388+sizeof(str_388)-1,
+str_start_390= str_start_389+sizeof(str_389)-1,
+str_start_391= str_start_390+sizeof(str_390)-1,
+str_start_392= str_start_391+sizeof(str_391)-1,
+str_start_393= str_start_392+sizeof(str_392)-1,
+str_start_394= str_start_393+sizeof(str_393)-1,
+str_start_395= str_start_394+sizeof(str_394)-1,
+str_start_396= str_start_395+sizeof(str_395)-1,
+str_start_397= str_start_396+sizeof(str_396)-1,
+str_start_398= str_start_397+sizeof(str_397)-1,
+str_start_399= str_start_398+sizeof(str_398)-1,
+str_start_400= str_start_399+sizeof(str_399)-1,
+str_start_401= str_start_400+sizeof(str_400)-1,
+str_start_402= str_start_401+sizeof(str_401)-1,
+str_start_403= str_start_402+sizeof(str_402)-1,
+str_start_404= str_start_403+sizeof(str_403)-1,
+str_start_405= str_start_404+sizeof(str_404)-1,
+str_start_406= str_start_405+sizeof(str_405)-1,
+str_start_407= str_start_406+sizeof(str_406)-1,
+str_start_408= str_start_407+sizeof(str_407)-1,
+str_start_409= str_start_408+sizeof(str_408)-1,
+str_start_410= str_start_409+sizeof(str_409)-1,
+str_start_411= str_start_410+sizeof(str_410)-1,
+str_start_412= str_start_411+sizeof(str_411)-1,
+str_start_413= str_start_412+sizeof(str_412)-1,
+str_start_414= str_start_413+sizeof(str_413)-1,
+str_start_415= str_start_414+sizeof(str_414)-1,
+str_start_416= str_start_415+sizeof(str_415)-1,
+str_start_417= str_start_416+sizeof(str_416)-1,
+str_start_418= str_start_417+sizeof(str_417)-1,
+str_start_419= str_start_418+sizeof(str_418)-1,
+str_start_420= str_start_419+sizeof(str_419)-1,
+str_start_421= str_start_420+sizeof(str_420)-1,
+str_start_422= str_start_421+sizeof(str_421)-1,
+str_start_423= str_start_422+sizeof(str_422)-1,
+str_start_424= str_start_423+sizeof(str_423)-1,
+str_start_425= str_start_424+sizeof(str_424)-1,
+str_start_426= str_start_425+sizeof(str_425)-1,
+str_start_427= str_start_426+sizeof(str_426)-1,
+str_start_428= str_start_427+sizeof(str_427)-1,
+str_start_429= str_start_428+sizeof(str_428)-1,
+str_start_430= str_start_429+sizeof(str_429)-1,
+str_start_431= str_start_430+sizeof(str_430)-1,
+str_start_432= str_start_431+sizeof(str_431)-1,
+str_start_433= str_start_432+sizeof(str_432)-1,
+str_start_434= str_start_433+sizeof(str_433)-1,
+str_start_435= str_start_434+sizeof(str_434)-1,
+str_start_436= str_start_435+sizeof(str_435)-1,
+str_start_437= str_start_436+sizeof(str_436)-1,
+str_start_438= str_start_437+sizeof(str_437)-1,
+str_start_439= str_start_438+sizeof(str_438)-1,
+str_start_440= str_start_439+sizeof(str_439)-1,
+str_start_441= str_start_440+sizeof(str_440)-1,
+str_start_442= str_start_441+sizeof(str_441)-1,
+str_start_443= str_start_442+sizeof(str_442)-1,
+str_start_444= str_start_443+sizeof(str_443)-1,
+str_start_445= str_start_444+sizeof(str_444)-1,
+str_start_446= str_start_445+sizeof(str_445)-1,
+str_start_447= str_start_446+sizeof(str_446)-1,
+str_start_448= str_start_447+sizeof(str_447)-1,
+str_start_449= str_start_448+sizeof(str_448)-1,
+str_start_450= str_start_449+sizeof(str_449)-1,
+str_start_451= str_start_450+sizeof(str_450)-1,
+str_start_452= str_start_451+sizeof(str_451)-1,
+str_start_453= str_start_452+sizeof(str_452)-1,
+str_start_454= str_start_453+sizeof(str_453)-1,
+str_start_455= str_start_454+sizeof(str_454)-1,
+str_start_456= str_start_455+sizeof(str_455)-1,
+str_start_457= str_start_456+sizeof(str_456)-1,
+str_start_458= str_start_457+sizeof(str_457)-1,
+str_start_459= str_start_458+sizeof(str_458)-1,
+str_start_460= str_start_459+sizeof(str_459)-1,
+str_start_461= str_start_460+sizeof(str_460)-1,
+str_start_462= str_start_461+sizeof(str_461)-1,
+str_start_463= str_start_462+sizeof(str_462)-1,
+str_start_464= str_start_463+sizeof(str_463)-1,
+str_start_465= str_start_464+sizeof(str_464)-1,
+str_start_466= str_start_465+sizeof(str_465)-1,
+str_start_467= str_start_466+sizeof(str_466)-1,
+str_start_468= str_start_467+sizeof(str_467)-1,
+str_start_469= str_start_468+sizeof(str_468)-1,
+str_start_470= str_start_469+sizeof(str_469)-1,
+str_start_471= str_start_470+sizeof(str_470)-1,
+str_start_472= str_start_471+sizeof(str_471)-1,
+str_start_473= str_start_472+sizeof(str_472)-1,
+str_start_474= str_start_473+sizeof(str_473)-1,
+str_start_475= str_start_474+sizeof(str_474)-1,
+str_start_476= str_start_475+sizeof(str_475)-1,
+str_start_477= str_start_476+sizeof(str_476)-1,
+str_start_478= str_start_477+sizeof(str_477)-1,
+str_start_479= str_start_478+sizeof(str_478)-1,
+str_start_480= str_start_479+sizeof(str_479)-1,
+str_start_481= str_start_480+sizeof(str_480)-1,
+str_start_482= str_start_481+sizeof(str_481)-1,
+str_start_483= str_start_482+sizeof(str_482)-1,
+str_start_484= str_start_483+sizeof(str_483)-1,
+str_start_485= str_start_484+sizeof(str_484)-1,
+str_start_486= str_start_485+sizeof(str_485)-1,
+str_start_487= str_start_486+sizeof(str_486)-1,
+str_start_488= str_start_487+sizeof(str_487)-1,
+str_start_489= str_start_488+sizeof(str_488)-1,
+str_start_490= str_start_489+sizeof(str_489)-1,
+str_start_491= str_start_490+sizeof(str_490)-1,
+str_start_492= str_start_491+sizeof(str_491)-1,
+str_start_493= str_start_492+sizeof(str_492)-1,
+str_start_494= str_start_493+sizeof(str_493)-1,
+str_start_495= str_start_494+sizeof(str_494)-1,
+str_start_496= str_start_495+sizeof(str_495)-1,
+str_start_497= str_start_496+sizeof(str_496)-1,
+str_start_498= str_start_497+sizeof(str_497)-1,
+str_start_499= str_start_498+sizeof(str_498)-1,
+str_start_500= str_start_499+sizeof(str_499)-1,
+str_start_501= str_start_500+sizeof(str_500)-1,
+str_start_502= str_start_501+sizeof(str_501)-1,
+str_start_503= str_start_502+sizeof(str_502)-1,
+str_start_504= str_start_503+sizeof(str_503)-1,
+str_start_505= str_start_504+sizeof(str_504)-1,
+str_start_506= str_start_505+sizeof(str_505)-1,
+str_start_507= str_start_506+sizeof(str_506)-1,
+str_start_508= str_start_507+sizeof(str_507)-1,
+str_start_509= str_start_508+sizeof(str_508)-1,
+str_start_510= str_start_509+sizeof(str_509)-1,
+str_start_511= str_start_510+sizeof(str_510)-1,
+str_start_512= str_start_511+sizeof(str_511)-1,
+str_start_513= str_start_512+sizeof(str_512)-1,
+str_start_514= str_start_513+sizeof(str_513)-1,
+str_start_515= str_start_514+sizeof(str_514)-1,
+str_start_516= str_start_515+sizeof(str_515)-1,
+str_start_517= str_start_516+sizeof(str_516)-1,
+str_start_518= str_start_517+sizeof(str_517)-1,
+str_start_519= str_start_518+sizeof(str_518)-1,
+str_start_520= str_start_519+sizeof(str_519)-1,
+str_start_521= str_start_520+sizeof(str_520)-1,
+str_start_522= str_start_521+sizeof(str_521)-1,
+str_start_523= str_start_522+sizeof(str_522)-1,
+str_start_524= str_start_523+sizeof(str_523)-1,
+str_start_525= str_start_524+sizeof(str_524)-1,
+str_start_526= str_start_525+sizeof(str_525)-1,
+str_start_527= str_start_526+sizeof(str_526)-1,
+str_start_528= str_start_527+sizeof(str_527)-1,
+str_start_529= str_start_528+sizeof(str_528)-1,
+str_start_530= str_start_529+sizeof(str_529)-1,
+str_start_531= str_start_530+sizeof(str_530)-1,
+str_start_532= str_start_531+sizeof(str_531)-1,
+str_start_533= str_start_532+sizeof(str_532)-1,
+str_start_534= str_start_533+sizeof(str_533)-1,
+str_start_535= str_start_534+sizeof(str_534)-1,
+str_start_536= str_start_535+sizeof(str_535)-1,
+str_start_537= str_start_536+sizeof(str_536)-1,
+str_start_538= str_start_537+sizeof(str_537)-1,
+str_start_539= str_start_538+sizeof(str_538)-1,
+str_start_540= str_start_539+sizeof(str_539)-1,
+str_start_541= str_start_540+sizeof(str_540)-1,
+str_start_542= str_start_541+sizeof(str_541)-1,
+str_start_543= str_start_542+sizeof(str_542)-1,
+str_start_544= str_start_543+sizeof(str_543)-1,
+str_start_545= str_start_544+sizeof(str_544)-1,
+str_start_546= str_start_545+sizeof(str_545)-1,
+str_start_547= str_start_546+sizeof(str_546)-1,
+str_start_548= str_start_547+sizeof(str_547)-1,
+str_start_549= str_start_548+sizeof(str_548)-1,
+str_start_550= str_start_549+sizeof(str_549)-1,
+str_start_551= str_start_550+sizeof(str_550)-1,
+str_start_552= str_start_551+sizeof(str_551)-1,
+str_start_553= str_start_552+sizeof(str_552)-1,
+str_start_554= str_start_553+sizeof(str_553)-1,
+str_start_555= str_start_554+sizeof(str_554)-1,
+str_start_556= str_start_555+sizeof(str_555)-1,
+str_start_557= str_start_556+sizeof(str_556)-1,
+str_start_558= str_start_557+sizeof(str_557)-1,
+str_start_559= str_start_558+sizeof(str_558)-1,
+str_start_560= str_start_559+sizeof(str_559)-1,
+str_start_561= str_start_560+sizeof(str_560)-1,
+str_start_562= str_start_561+sizeof(str_561)-1,
+str_start_563= str_start_562+sizeof(str_562)-1,
+str_start_564= str_start_563+sizeof(str_563)-1,
+str_start_565= str_start_564+sizeof(str_564)-1,
+str_start_566= str_start_565+sizeof(str_565)-1,
+str_start_567= str_start_566+sizeof(str_566)-1,
+str_start_568= str_start_567+sizeof(str_567)-1,
+str_start_569= str_start_568+sizeof(str_568)-1,
+str_start_570= str_start_569+sizeof(str_569)-1,
+str_start_571= str_start_570+sizeof(str_570)-1,
+str_start_572= str_start_571+sizeof(str_571)-1,
+str_start_573= str_start_572+sizeof(str_572)-1,
+str_start_574= str_start_573+sizeof(str_573)-1,
+str_start_575= str_start_574+sizeof(str_574)-1,
+str_start_576= str_start_575+sizeof(str_575)-1,
+str_start_577= str_start_576+sizeof(str_576)-1,
+str_start_578= str_start_577+sizeof(str_577)-1,
+str_start_579= str_start_578+sizeof(str_578)-1,
+str_start_580= str_start_579+sizeof(str_579)-1,
+str_start_581= str_start_580+sizeof(str_580)-1,
+str_start_582= str_start_581+sizeof(str_581)-1,
+str_start_583= str_start_582+sizeof(str_582)-1,
+str_start_584= str_start_583+sizeof(str_583)-1,
+str_start_585= str_start_584+sizeof(str_584)-1,
+str_start_586= str_start_585+sizeof(str_585)-1,
+str_start_587= str_start_586+sizeof(str_586)-1,
+str_start_588= str_start_587+sizeof(str_587)-1,
+str_start_589= str_start_588+sizeof(str_588)-1,
+str_start_590= str_start_589+sizeof(str_589)-1,
+str_start_591= str_start_590+sizeof(str_590)-1,
+str_start_592= str_start_591+sizeof(str_591)-1,
+str_start_593= str_start_592+sizeof(str_592)-1,
+str_start_594= str_start_593+sizeof(str_593)-1,
+str_start_595= str_start_594+sizeof(str_594)-1,
+str_start_596= str_start_595+sizeof(str_595)-1,
+str_start_597= str_start_596+sizeof(str_596)-1,
+str_start_598= str_start_597+sizeof(str_597)-1,
+str_start_599= str_start_598+sizeof(str_598)-1,
+str_start_600= str_start_599+sizeof(str_599)-1,
+str_start_601= str_start_600+sizeof(str_600)-1,
+str_start_602= str_start_601+sizeof(str_601)-1,
+str_start_603= str_start_602+sizeof(str_602)-1,
+str_start_604= str_start_603+sizeof(str_603)-1,
+str_start_605= str_start_604+sizeof(str_604)-1,
+str_start_606= str_start_605+sizeof(str_605)-1,
+str_start_607= str_start_606+sizeof(str_606)-1,
+str_start_608= str_start_607+sizeof(str_607)-1,
+str_start_609= str_start_608+sizeof(str_608)-1,
+str_start_610= str_start_609+sizeof(str_609)-1,
+str_start_611= str_start_610+sizeof(str_610)-1,
+str_start_612= str_start_611+sizeof(str_611)-1,
+str_start_613= str_start_612+sizeof(str_612)-1,
+str_start_614= str_start_613+sizeof(str_613)-1,
+str_start_615= str_start_614+sizeof(str_614)-1,
+str_start_616= str_start_615+sizeof(str_615)-1,
+str_start_617= str_start_616+sizeof(str_616)-1,
+str_start_618= str_start_617+sizeof(str_617)-1,
+str_start_619= str_start_618+sizeof(str_618)-1,
+str_start_620= str_start_619+sizeof(str_619)-1,
+str_start_621= str_start_620+sizeof(str_620)-1,
+str_start_622= str_start_621+sizeof(str_621)-1,
+str_start_623= str_start_622+sizeof(str_622)-1,
+str_start_624= str_start_623+sizeof(str_623)-1,
+str_start_625= str_start_624+sizeof(str_624)-1,
+str_start_626= str_start_625+sizeof(str_625)-1,
+str_start_627= str_start_626+sizeof(str_626)-1,
+str_start_628= str_start_627+sizeof(str_627)-1,
+str_start_629= str_start_628+sizeof(str_628)-1,
+str_start_630= str_start_629+sizeof(str_629)-1,
+str_start_631= str_start_630+sizeof(str_630)-1,
+str_start_632= str_start_631+sizeof(str_631)-1,
+str_start_633= str_start_632+sizeof(str_632)-1,
+str_start_634= str_start_633+sizeof(str_633)-1,
+str_start_635= str_start_634+sizeof(str_634)-1,
+str_start_636= str_start_635+sizeof(str_635)-1,
+str_start_637= str_start_636+sizeof(str_636)-1,
+str_start_638= str_start_637+sizeof(str_637)-1,
+str_start_639= str_start_638+sizeof(str_638)-1,
+str_start_640= str_start_639+sizeof(str_639)-1,
+str_start_641= str_start_640+sizeof(str_640)-1,
+str_start_642= str_start_641+sizeof(str_641)-1,
+str_start_643= str_start_642+sizeof(str_642)-1,
+str_start_644= str_start_643+sizeof(str_643)-1,
+str_start_645= str_start_644+sizeof(str_644)-1,
+str_start_646= str_start_645+sizeof(str_645)-1,
+str_start_647= str_start_646+sizeof(str_646)-1,
+str_start_648= str_start_647+sizeof(str_647)-1,
+str_start_649= str_start_648+sizeof(str_648)-1,
+str_start_650= str_start_649+sizeof(str_649)-1,
+str_start_651= str_start_650+sizeof(str_650)-1,
+str_start_652= str_start_651+sizeof(str_651)-1,
+str_start_653= str_start_652+sizeof(str_652)-1,
+str_start_654= str_start_653+sizeof(str_653)-1,
+str_start_655= str_start_654+sizeof(str_654)-1,
+str_start_656= str_start_655+sizeof(str_655)-1,
+str_start_657= str_start_656+sizeof(str_656)-1,
+str_start_658= str_start_657+sizeof(str_657)-1,
+str_start_659= str_start_658+sizeof(str_658)-1,
+str_start_660= str_start_659+sizeof(str_659)-1,
+str_start_661= str_start_660+sizeof(str_660)-1,
+str_start_662= str_start_661+sizeof(str_661)-1,
+str_start_663= str_start_662+sizeof(str_662)-1,
+str_start_664= str_start_663+sizeof(str_663)-1,
+str_start_665= str_start_664+sizeof(str_664)-1,
+str_start_666= str_start_665+sizeof(str_665)-1,
+str_start_667= str_start_666+sizeof(str_666)-1,
+str_start_668= str_start_667+sizeof(str_667)-1,
+str_start_end}str_starts;
+
+/*:1795*/
+#line 1138 "tex.w"
+
+packed_ASCII_code str_pool[pool_size+1]= /*1793:*/
+#line 26275 "tex.w"
+
+str_0_255
+str_256 str_257 str_258 str_259 str_260 str_261 str_262 str_263
+str_264 str_265 str_266 str_267 str_268 str_269 str_270 str_271
+str_272 str_273 str_274 str_275 str_276 str_277 str_278 str_279
+str_280 str_281 str_282 str_283 str_284 str_285 str_286 str_287
+str_288 str_289 str_290 str_291 str_292 str_293 str_294 str_295
+str_296 str_297 str_298 str_299 str_300 str_301 str_302 str_303
+str_304 str_305 str_306 str_307 str_308 str_309 str_310 str_311
+str_312 str_313 str_314 str_315 str_316 str_317 str_318 str_319
+str_320 str_321 str_322 str_323 str_324 str_325 str_326 str_327
+str_328 str_329 str_330 str_331 str_332 str_333 str_334 str_335
+str_336 str_337 str_338 str_339 str_340 str_341 str_342 str_343
+str_344 str_345 str_346 str_347 str_348 str_349 str_350 str_351
+str_352 str_353 str_354 str_355 str_356 str_357 str_358 str_359
+str_360 str_361 str_362 str_363 str_364 str_365 str_366 str_367
+str_368 str_369 str_370 str_371 str_372 str_373 str_374 str_375
+str_376 str_377 str_378 str_379 str_380 str_381 str_382 str_383
+str_384 str_385 str_386 str_387 str_388 str_389 str_390 str_391
+str_392 str_393 str_394 str_395 str_396 str_397 str_398 str_399
+str_400 str_401 str_402 str_403 str_404 str_405 str_406 str_407
+str_408 str_409 str_410 str_411 str_412 str_413 str_414 str_415
+str_416 str_417 str_418 str_419 str_420 str_421 str_422 str_423
+str_424 str_425 str_426 str_427 str_428 str_429 str_430 str_431
+str_432 str_433 str_434 str_435 str_436 str_437 str_438 str_439
+str_440 str_441 str_442 str_443 str_444 str_445 str_446 str_447
+str_448 str_449 str_450 str_451 str_452 str_453 str_454 str_455
+str_456 str_457 str_458 str_459 str_460 str_461 str_462 str_463
+str_464 str_465 str_466 str_467 str_468 str_469 str_470 str_471
+str_472 str_473 str_474 str_475 str_476 str_477 str_478 str_479
+str_480 str_481 str_482 str_483 str_484 str_485 str_486 str_487
+str_488 str_489 str_490 str_491 str_492 str_493 str_494 str_495
+str_496 str_497 str_498 str_499 str_500 str_501 str_502 str_503
+str_504 str_505 str_506 str_507 str_508 str_509 str_510 str_511
+str_512 str_513 str_514 str_515 str_516 str_517 str_518 str_519
+str_520 str_521 str_522 str_523 str_524 str_525 str_526 str_527
+str_528 str_529 str_530 str_531 str_532 str_533 str_534 str_535
+str_536 str_537 str_538 str_539 str_540 str_541 str_542 str_543
+str_544 str_545 str_546 str_547 str_548 str_549 str_550 str_551
+str_552 str_553 str_554 str_555 str_556 str_557 str_558 str_559
+str_560 str_561 str_562 str_563 str_564 str_565 str_566 str_567
+str_568 str_569 str_570 str_571 str_572 str_573 str_574 str_575
+str_576 str_577 str_578 str_579 str_580 str_581 str_582 str_583
+str_584 str_585 str_586 str_587 str_588 str_589 str_590 str_591
+str_592 str_593 str_594 str_595 str_596 str_597 str_598 str_599
+str_600 str_601 str_602 str_603 str_604 str_605 str_606 str_607
+str_608 str_609 str_610 str_611 str_612 str_613 str_614 str_615
+str_616 str_617 str_618 str_619 str_620 str_621 str_622 str_623
+str_624 str_625 str_626 str_627 str_628 str_629 str_630 str_631
+str_632 str_633 str_634 str_635 str_636 str_637 str_638 str_639
+str_640 str_641 str_642 str_643 str_644 str_645 str_646 str_647
+str_648 str_649 str_650 str_651 str_652 str_653 str_654 str_655
+str_656 str_657 str_658 str_659 str_660 str_661 str_662 str_663
+str_664 str_665 str_666 str_667
+
+/*:1793*/
+#line 1139 "tex.w"
+;
+pool_pointer str_start[max_strings+1]= {/*1794:*/
+#line 26330 "tex.w"
+
+str_start_0_255
+str_start_256,str_start_257,str_start_258,str_start_259,
+str_start_260,str_start_261,str_start_262,str_start_263,
+str_start_264,str_start_265,str_start_266,str_start_267,
+str_start_268,str_start_269,str_start_270,str_start_271,
+str_start_272,str_start_273,str_start_274,str_start_275,
+str_start_276,str_start_277,str_start_278,str_start_279,
+str_start_280,str_start_281,str_start_282,str_start_283,
+str_start_284,str_start_285,str_start_286,str_start_287,
+str_start_288,str_start_289,str_start_290,str_start_291,
+str_start_292,str_start_293,str_start_294,str_start_295,
+str_start_296,str_start_297,str_start_298,str_start_299,
+str_start_300,str_start_301,str_start_302,str_start_303,
+str_start_304,str_start_305,str_start_306,str_start_307,
+str_start_308,str_start_309,str_start_310,str_start_311,
+str_start_312,str_start_313,str_start_314,str_start_315,
+str_start_316,str_start_317,str_start_318,str_start_319,
+str_start_320,str_start_321,str_start_322,str_start_323,
+str_start_324,str_start_325,str_start_326,str_start_327,
+str_start_328,str_start_329,str_start_330,str_start_331,
+str_start_332,str_start_333,str_start_334,str_start_335,
+str_start_336,str_start_337,str_start_338,str_start_339,
+str_start_340,str_start_341,str_start_342,str_start_343,
+str_start_344,str_start_345,str_start_346,str_start_347,
+str_start_348,str_start_349,str_start_350,str_start_351,
+str_start_352,str_start_353,str_start_354,str_start_355,
+str_start_356,str_start_357,str_start_358,str_start_359,
+str_start_360,str_start_361,str_start_362,str_start_363,
+str_start_364,str_start_365,str_start_366,str_start_367,
+str_start_368,str_start_369,str_start_370,str_start_371,
+str_start_372,str_start_373,str_start_374,str_start_375,
+str_start_376,str_start_377,str_start_378,str_start_379,
+str_start_380,str_start_381,str_start_382,str_start_383,
+str_start_384,str_start_385,str_start_386,str_start_387,
+str_start_388,str_start_389,str_start_390,str_start_391,
+str_start_392,str_start_393,str_start_394,str_start_395,
+str_start_396,str_start_397,str_start_398,str_start_399,
+str_start_400,str_start_401,str_start_402,str_start_403,
+str_start_404,str_start_405,str_start_406,str_start_407,
+str_start_408,str_start_409,str_start_410,str_start_411,
+str_start_412,str_start_413,str_start_414,str_start_415,
+str_start_416,str_start_417,str_start_418,str_start_419,
+str_start_420,str_start_421,str_start_422,str_start_423,
+str_start_424,str_start_425,str_start_426,str_start_427,
+str_start_428,str_start_429,str_start_430,str_start_431,
+str_start_432,str_start_433,str_start_434,str_start_435,
+str_start_436,str_start_437,str_start_438,str_start_439,
+str_start_440,str_start_441,str_start_442,str_start_443,
+str_start_444,str_start_445,str_start_446,str_start_447,
+str_start_448,str_start_449,str_start_450,str_start_451,
+str_start_452,str_start_453,str_start_454,str_start_455,
+str_start_456,str_start_457,str_start_458,str_start_459,
+str_start_460,str_start_461,str_start_462,str_start_463,
+str_start_464,str_start_465,str_start_466,str_start_467,
+str_start_468,str_start_469,str_start_470,str_start_471,
+str_start_472,str_start_473,str_start_474,str_start_475,
+str_start_476,str_start_477,str_start_478,str_start_479,
+str_start_480,str_start_481,str_start_482,str_start_483,
+str_start_484,str_start_485,str_start_486,str_start_487,
+str_start_488,str_start_489,str_start_490,str_start_491,
+str_start_492,str_start_493,str_start_494,str_start_495,
+str_start_496,str_start_497,str_start_498,str_start_499,
+str_start_500,str_start_501,str_start_502,str_start_503,
+str_start_504,str_start_505,str_start_506,str_start_507,
+str_start_508,str_start_509,str_start_510,str_start_511,
+str_start_512,str_start_513,str_start_514,str_start_515,
+str_start_516,str_start_517,str_start_518,str_start_519,
+str_start_520,str_start_521,str_start_522,str_start_523,
+str_start_524,str_start_525,str_start_526,str_start_527,
+str_start_528,str_start_529,str_start_530,str_start_531,
+str_start_532,str_start_533,str_start_534,str_start_535,
+str_start_536,str_start_537,str_start_538,str_start_539,
+str_start_540,str_start_541,str_start_542,str_start_543,
+str_start_544,str_start_545,str_start_546,str_start_547,
+str_start_548,str_start_549,str_start_550,str_start_551,
+str_start_552,str_start_553,str_start_554,str_start_555,
+str_start_556,str_start_557,str_start_558,str_start_559,
+str_start_560,str_start_561,str_start_562,str_start_563,
+str_start_564,str_start_565,str_start_566,str_start_567,
+str_start_568,str_start_569,str_start_570,str_start_571,
+str_start_572,str_start_573,str_start_574,str_start_575,
+str_start_576,str_start_577,str_start_578,str_start_579,
+str_start_580,str_start_581,str_start_582,str_start_583,
+str_start_584,str_start_585,str_start_586,str_start_587,
+str_start_588,str_start_589,str_start_590,str_start_591,
+str_start_592,str_start_593,str_start_594,str_start_595,
+str_start_596,str_start_597,str_start_598,str_start_599,
+str_start_600,str_start_601,str_start_602,str_start_603,
+str_start_604,str_start_605,str_start_606,str_start_607,
+str_start_608,str_start_609,str_start_610,str_start_611,
+str_start_612,str_start_613,str_start_614,str_start_615,
+str_start_616,str_start_617,str_start_618,str_start_619,
+str_start_620,str_start_621,str_start_622,str_start_623,
+str_start_624,str_start_625,str_start_626,str_start_627,
+str_start_628,str_start_629,str_start_630,str_start_631,
+str_start_632,str_start_633,str_start_634,str_start_635,
+str_start_636,str_start_637,str_start_638,str_start_639,
+str_start_640,str_start_641,str_start_642,str_start_643,
+str_start_644,str_start_645,str_start_646,str_start_647,
+str_start_648,str_start_649,str_start_650,str_start_651,
+str_start_652,str_start_653,str_start_654,str_start_655,
+str_start_656,str_start_657,str_start_658,str_start_659,
+str_start_660,str_start_661,str_start_662,str_start_663,
+str_start_664,str_start_665,str_start_666,str_start_667,
+str_start_668
+
+/*:1794*/
+#line 1140 "tex.w"
+};
+pool_pointer pool_ptr= /*1796:*/
+#line 26855 "tex.w"
+str_start_668
+
+/*:1796*/
+#line 1141 "tex.w"
+;
+str_number str_ptr= /*1797:*/
+#line 26857 "tex.w"
+668
+
+/*:1797*/
+#line 1142 "tex.w"
+;
+pool_pointer init_pool_ptr;
+str_number init_str_ptr;
+
+/*:39*//*50:*/
+#line 1316 "tex.w"
+
+#ifdef INIT
+alpha_file pool_file;
+#endif
+
+/*:50*//*54:*/
+#line 1424 "tex.w"
+
+alpha_file log_file;
+uint8_t selector;
+uint8_t dig[23];
+int tally;
+uint8_t term_offset;
+
+uint8_t file_offset;
+
+ASCII_code trick_buf[error_line+1];
+
+int trick_count;
+int first_count;
+
+/*:54*//*73:*/
+#line 1770 "tex.w"
+
+uint8_t interaction;
+
+/*:73*//*76:*/
+#line 1811 "tex.w"
+
+bool deletions_allowed;
+bool set_box_allowed;
+uint8_t history;
+int8_t error_count;
+
+
+/*:76*//*79:*/
+#line 1870 "tex.w"
+
+char*help_line[6];
+uint8_t help_ptr;
+bool use_err_help;
+
+/*:79*//*96:*/
+#line 2135 "tex.w"
+
+int interrupt;
+bool OK_to_interrupt;
+
+/*:96*//*104:*/
+#line 2268 "tex.w"
+
+bool arith_error;
+scaled rem;
+
+/*:104*//*115:*/
+#line 2557 "tex.w"
+
+pointer temp_ptr;
+
+/*:115*//*116:*/
+#line 2589 "tex.w"
+
+memory_word mem0[mem_max-mem_min+1],*const mem= mem0-mem_min;
+pointer lo_mem_max;
+pointer hi_mem_min;
+
+/*:116*//*117:*/
+#line 2602 "tex.w"
+
+int var_used,dyn_used;
+#ifdef DEBUG
+#define incr_dyn_used incr(dyn_used)
+#define decr_dyn_used decr(dyn_used)
+#else
+#define incr_dyn_used
+#define decr_dyn_used
+#endif
+
+/*:117*//*118:*/
+#line 2625 "tex.w"
+
+pointer avail;
+pointer mem_end;
+
+/*:118*//*124:*/
+#line 2725 "tex.w"
+
+pointer rover;
+
+/*:124*//*165:*/
+#line 3428 "tex.w"
+
+#ifdef DEBUG
+bool is_free0[mem_max-mem_min+1],*const is_free= is_free0-mem_min;
+bool was_free0[mem_max-mem_min+1],*const was_free= was_free0-mem_min;
+
+pointer was_mem_end,was_lo_max,was_hi_min;
+
+bool panicking;
+#endif
+
+/*:165*//*173:*/
+#line 3582 "tex.w"
+
+int font_in_short_display;
+
+/*:173*//*181:*/
+#line 3710 "tex.w"
+
+int depth_threshold;
+int breadth_max;
+
+/*:181*//*213:*/
+#line 4387 "tex.w"
+
+list_state_record nest[nest_size+1];
+uint8_t nest_ptr;
+uint8_t max_nest_stack;
+list_state_record cur_list;
+int16_t shown_mode;
+
+/*:213*//*246:*/
+#line 5336 "tex.w"
+
+uint8_t old_setting;
+
+/*:246*//*253:*/
+#line 5502 "tex.w"
+
+memory_word eqtb0[eqtb_size-active_base+1],*const eqtb= eqtb0-active_base;
+quarterword xeq_level0[eqtb_size-int_base+1],*const xeq_level= xeq_level0-int_base;
+
+/*:253*//*256:*/
+#line 5550 "tex.w"
+
+two_halves hash0[undefined_control_sequence-hash_base],*const hash= hash0-hash_base;
+
+pointer hash_used;
+bool no_new_control_sequence;
+int cs_count;
+
+/*:256*//*271:*/
+#line 5943 "tex.w"
+
+memory_word save_stack[save_size+1];
+uint16_t save_ptr;
+uint16_t max_save_stack;
+quarterword cur_level;
+group_code cur_group;
+uint16_t cur_boundary;
+
+/*:271*//*286:*/
+#line 6185 "tex.w"
+
+int mag_set;
+
+/*:286*//*297:*/
+#line 6443 "tex.w"
+
+eight_bits cur_cmd;
+halfword cur_chr;
+pointer cur_cs;
+halfword cur_tok;
+
+/*:297*//*301:*/
+#line 6520 "tex.w"
+
+in_state_record input_stack[stack_size+1];
+uint8_t input_ptr;
+uint8_t max_in_stack;
+in_state_record cur_input;
+
+
+/*:301*//*304:*/
+#line 6622 "tex.w"
+
+uint8_t in_open;
+uint8_t open_parens;
+alpha_file input_file0[max_in_open],*const input_file= input_file0-1;
+int line;
+int line_stack0[max_in_open],*const line_stack= line_stack0-1;
+
+/*:304*//*305:*/
+#line 6665 "tex.w"
+
+uint8_t scanner_status;
+pointer warning_index;
+pointer def_ref;
+
+/*:305*//*308:*/
+#line 6789 "tex.w"
+
+pointer param_stack[param_size+1];
+
+uint8_t param_ptr;
+int max_param_stack;
+
+
+/*:308*//*309:*/
+#line 6806 "tex.w"
+
+int align_state;
+
+/*:309*//*310:*/
+#line 6817 "tex.w"
+
+uint8_t base_ptr;
+
+/*:310*//*333:*/
+#line 7194 "tex.w"
+
+pointer par_loc;
+halfword par_token;
+
+/*:333*//*361:*/
+#line 7611 "tex.w"
+
+bool force_eof;
+
+/*:361*//*382:*/
+#line 7925 "tex.w"
+
+pointer cur_mark0[split_bot_mark_code-top_mark_code+1],*const cur_mark= cur_mark0-top_mark_code;
+
+
+/*:382*//*387:*/
+#line 7974 "tex.w"
+
+uint8_t long_state;
+
+/*:387*//*388:*/
+#line 7985 "tex.w"
+
+pointer pstack[9];
+
+/*:388*//*410:*/
+#line 8369 "tex.w"
+
+int cur_val;
+uint8_t cur_val_level;
+
+/*:410*//*438:*/
+#line 8740 "tex.w"
+
+small_number radix;
+
+/*:438*//*447:*/
+#line 8875 "tex.w"
+
+glue_ord cur_order;
+
+/*:447*//*480:*/
+#line 9482 "tex.w"
+
+alpha_file read_file[16];
+uint8_t read_open[17];
+
+/*:480*//*489:*/
+#line 9669 "tex.w"
+
+pointer cond_ptr;
+uint8_t if_limit;
+small_number cur_if;
+int if_line;
+
+/*:489*//*493:*/
+#line 9695 "tex.w"
+
+int skip_line;
+
+/*:493*//*512:*/
+#line 10022 "tex.w"
+
+str_number cur_name;
+str_number cur_area;
+str_number cur_ext;
+
+/*:512*//*513:*/
+#line 10038 "tex.w"
+
+pool_pointer area_delimiter;
+pool_pointer ext_delimiter;
+
+/*:513*//*520:*/
+#line 10138 "tex.w"
+
+ASCII_code TEX_format_default[1+format_default_length+1]= " TeXformats/plain.fmt";
+
+
+
+
+/*:520*//*526:*/
+#line 10269 "tex.w"
+
+bool name_in_progress;
+str_number job_name;
+bool log_opened;
+
+/*:526*//*532:*/
+#line 10342 "tex.w"
+
+byte_file dvi_file;
+str_number output_file_name;
+str_number log_name;
+
+/*:532*//*539:*/
+#line 10465 "tex.w"
+
+byte_file tfm_file;
+
+/*:539*//*549:*/
+#line 10752 "tex.w"
+
+memory_word font_info[font_mem_size+1];
+
+font_index fmem_ptr;
+internal_font_number font_ptr;
+four_quarters font_check0[font_max-font_base+1],*const font_check= font_check0-font_base;
+scaled font_size0[font_max-font_base+1],*const font_size= font_size0-font_base;
+scaled font_dsize0[font_max-font_base+1],*const font_dsize= font_dsize0-font_base;
+font_index font_params0[font_max-font_base+1],*const font_params= font_params0-font_base;
+
+str_number font_name0[font_max-font_base+1],*const font_name= font_name0-font_base;
+str_number font_area0[font_max-font_base+1],*const font_area= font_area0-font_base;
+eight_bits font_bc0[font_max-font_base+1],*const font_bc= font_bc0-font_base;
+
+eight_bits font_ec0[font_max-font_base+1],*const font_ec= font_ec0-font_base;
+
+pointer font_glue0[font_max-font_base+1],*const font_glue= font_glue0-font_base;
+
+bool font_used0[font_max-font_base+1],*const font_used= font_used0-font_base;
+
+int hyphen_char0[font_max-font_base+1],*const hyphen_char= hyphen_char0-font_base;
+
+int skew_char0[font_max-font_base+1],*const skew_char= skew_char0-font_base;
+
+font_index bchar_label0[font_max-font_base+1],*const bchar_label= bchar_label0-font_base;
+
+
+uint16_t font_bchar0[font_max-font_base+1],*const font_bchar= font_bchar0-font_base;
+
+uint16_t font_false_bchar0[font_max-font_base+1],*const font_false_bchar= font_false_bchar0-font_base;
+
+
+/*:549*//*550:*/
+#line 10793 "tex.w"
+
+int char_base0[font_max-font_base+1],*const char_base= char_base0-font_base;
+
+int width_base0[font_max-font_base+1],*const width_base= width_base0-font_base;
+
+int height_base0[font_max-font_base+1],*const height_base= height_base0-font_base;
+
+int depth_base0[font_max-font_base+1],*const depth_base= depth_base0-font_base;
+
+int italic_base0[font_max-font_base+1],*const italic_base= italic_base0-font_base;
+
+int lig_kern_base0[font_max-font_base+1],*const lig_kern_base= lig_kern_base0-font_base;
+
+int kern_base0[font_max-font_base+1],*const kern_base= kern_base0-font_base;
+
+int exten_base0[font_max-font_base+1],*const exten_base= exten_base0-font_base;
+
+int param_base0[font_max-font_base+1],*const param_base= param_base0-font_base;
+
+
+/*:550*//*555:*/
+#line 10887 "tex.w"
+
+four_quarters null_character;
+
+/*:555*//*592:*/
+#line 11882 "tex.w"
+
+int total_pages;
+scaled max_v;
+scaled max_h;
+int max_push;
+int last_bop;
+int dead_cycles;
+bool doing_leaders;
+
+quarterword c,f;
+scaled rule_ht,rule_dp,rule_wd;
+pointer g;
+int lq,lr;
+
+/*:592*//*595:*/
+#line 11930 "tex.w"
+
+eight_bits dvi_buf[dvi_buf_size+1];
+dvi_index half_buf;
+dvi_index dvi_limit;
+dvi_index dvi_ptr;
+int dvi_offset;
+
+int dvi_gone;
+
+/*:595*//*605:*/
+#line 12095 "tex.w"
+
+pointer down_ptr,right_ptr;
+
+/*:605*//*616:*/
+#line 12317 "tex.w"
+
+scaled dvi_h,dvi_v;
+scaled cur_h,cur_v;
+internal_font_number dvi_f;
+int cur_s;
+
+/*:616*//*646:*/
+#line 12921 "tex.w"
+
+scaled total_stretch0[filll-normal+1],*const total_stretch= total_stretch0-normal,total_shrink0[filll-normal+1],*const total_shrink= total_shrink0-normal;
+
+int last_badness;
+
+/*:646*//*647:*/
+#line 12931 "tex.w"
+
+pointer adjust_tail;
+
+/*:647*//*661:*/
+#line 13105 "tex.w"
+
+int pack_begin_line;
+
+
+/*:661*//*684:*/
+#line 13522 "tex.w"
+
+two_halves empty_field;
+four_quarters null_delimiter;
+
+/*:684*//*719:*/
+#line 14174 "tex.w"
+
+pointer cur_mlist;
+small_number cur_style;
+small_number cur_size;
+scaled cur_mu;
+bool mlist_penalties;
+
+/*:719*//*724:*/
+#line 14264 "tex.w"
+
+internal_font_number cur_f;
+quarterword cur_c;
+four_quarters cur_i;
+
+
+/*:724*//*764:*/
+#line 15075 "tex.w"
+
+int magic_offset;
+
+/*:764*//*770:*/
+#line 15276 "tex.w"
+
+pointer cur_align;
+pointer cur_span;
+pointer cur_loop;
+pointer align_ptr;
+pointer cur_head,cur_tail;
+
+/*:770*//*814:*/
+#line 16049 "tex.w"
+
+pointer just_box;
+
+/*:814*//*821:*/
+#line 16192 "tex.w"
+
+pointer passive;
+pointer printed_node;
+halfword pass_number;
+
+/*:821*//*823:*/
+#line 16231 "tex.w"
+
+scaled active_width0[6],*const active_width= active_width0-1;
+
+scaled cur_active_width0[6],*const cur_active_width= cur_active_width0-1;
+scaled background0[6],*const background= background0-1;
+scaled break_width0[6],*const break_width= break_width0-1;
+
+/*:823*//*825:*/
+#line 16288 "tex.w"
+
+bool no_shrink_error_yet;
+
+/*:825*//*828:*/
+#line 16340 "tex.w"
+
+pointer cur_p;
+bool second_pass;
+bool final_pass;
+int threshold;
+
+/*:828*//*833:*/
+#line 16441 "tex.w"
+
+int minimal_demerits0[tight_fit-very_loose_fit+1],*const minimal_demerits= minimal_demerits0-very_loose_fit;
+
+int minimum_demerits;
+
+pointer best_place0[tight_fit-very_loose_fit+1],*const best_place= best_place0-very_loose_fit;
+
+halfword best_pl_line0[tight_fit-very_loose_fit+1],*const best_pl_line= best_pl_line0-very_loose_fit;
+
+
+/*:833*//*839:*/
+#line 16559 "tex.w"
+
+scaled disc_width;
+
+/*:839*//*847:*/
+#line 16699 "tex.w"
+
+halfword easy_line;
+halfword last_special_line;
+
+scaled first_width;
+
+scaled second_width;
+scaled first_indent;
+scaled second_indent;
+
+/*:847*//*872:*/
+#line 17210 "tex.w"
+
+pointer best_bet;
+int fewest_demerits;
+halfword best_line;
+int actual_looseness;
+
+int line_diff;
+
+
+/*:872*//*892:*/
+#line 17544 "tex.w"
+
+uint16_t hc[66];
+small_number hn;
+pointer ha,hb;
+internal_font_number hf;
+uint16_t hu[64];
+int hyf_char;
+ASCII_code cur_lang,init_cur_lang;
+int l_hyf,r_hyf,init_l_hyf,init_r_hyf;
+halfword hyf_bchar;
+
+/*:892*//*900:*/
+#line 17677 "tex.w"
+
+uint8_t hyf[65];
+pointer init_list;
+bool init_lig;
+bool init_lft;
+
+/*:900*//*905:*/
+#line 17801 "tex.w"
+
+small_number hyphen_passed;
+
+/*:905*//*907:*/
+#line 17842 "tex.w"
+
+halfword cur_l,cur_r;
+pointer cur_q;
+pointer lig_stack;
+bool ligature_present;
+bool lft_hit,rt_hit;
+
+/*:907*//*921:*/
+#line 18145 "tex.w"
+
+two_halves trie[trie_size+1];
+small_number hyf_distance0[trie_op_size],*const hyf_distance= hyf_distance0-1;
+small_number hyf_num0[trie_op_size],*const hyf_num= hyf_num0-1;
+quarterword hyf_next0[trie_op_size],*const hyf_next= hyf_next0-1;
+uint16_t op_start[256];
+
+/*:921*//*926:*/
+#line 18207 "tex.w"
+
+str_number hyph_word[hyph_size+1];
+pointer hyph_list[hyph_size+1];
+hyph_pointer hyph_count;
+
+/*:926*//*943:*/
+#line 18416 "tex.w"
+
+#ifdef INIT
+uint16_t trie_op_hash0[trie_op_size+trie_op_size+1],*const trie_op_hash= trie_op_hash0+trie_op_size;
+
+quarterword trie_used[256];
+
+ASCII_code trie_op_lang0[trie_op_size],*const trie_op_lang= trie_op_lang0-1;
+
+quarterword trie_op_val0[trie_op_size],*const trie_op_val= trie_op_val0-1;
+
+uint16_t trie_op_ptr;
+#endif
+
+/*:943*//*947:*/
+#line 18509 "tex.w"
+
+#ifdef INIT
+packed_ASCII_code trie_c[trie_size+1];
+
+quarterword trie_o[trie_size+1];
+
+trie_pointer trie_l[trie_size+1];
+
+trie_pointer trie_r[trie_size+1];
+
+trie_pointer trie_ptr;
+trie_pointer trie_hash[trie_size+1];
+
+#endif
+
+/*:947*//*950:*/
+#line 18596 "tex.w"
+
+#ifdef INIT
+bool trie_taken0[trie_size],*const trie_taken= trie_taken0-1;
+
+trie_pointer trie_min[256];
+
+trie_pointer trie_max;
+bool trie_not_ready;
+#endif
+
+/*:950*//*971:*/
+#line 18955 "tex.w"
+
+scaled best_height_plus_depth;
+
+
+/*:971*//*980:*/
+#line 19162 "tex.w"
+
+pointer page_tail;
+uint8_t page_contents;
+scaled page_max_depth;
+pointer best_page_break;
+int least_page_cost;
+scaled best_size;
+
+/*:980*//*982:*/
+#line 19244 "tex.w"
+
+scaled page_so_far[8];
+pointer last_glue;
+int last_penalty;
+scaled last_kern;
+int insert_penalties;
+
+/*:982*//*989:*/
+#line 19378 "tex.w"
+
+bool output_active;
+
+/*:989*//*1032:*/
+#line 20098 "tex.w"
+
+internal_font_number main_f;
+four_quarters main_i;
+four_quarters main_j;
+font_index main_k;
+pointer main_p;
+int main_s;
+halfword bchar;
+halfword false_bchar;
+bool cancel_boundary;
+bool ins_disc;
+
+/*:1032*//*1074:*/
+#line 20871 "tex.w"
+
+pointer cur_box;
+
+/*:1074*//*1266:*/
+#line 23457 "tex.w"
+
+halfword after_token;
+
+/*:1266*//*1281:*/
+#line 23560 "tex.w"
+
+bool long_help_seen;
+
+/*:1281*//*1299:*/
+#line 23746 "tex.w"
+
+str_number format_ident;
+
+/*:1299*//*1305:*/
+#line 23827 "tex.w"
+
+word_file fmt_file;
+
+/*:1305*//*1331:*/
+#line 24280 "tex.w"
+
+int ready_already;
+
+/*:1331*//*1342:*/
+#line 24612 "tex.w"
+
+alpha_file write_file[16];
+bool write_open[18];
+
+/*:1342*//*1345:*/
+#line 24643 "tex.w"
+
+pointer write_loc;
+
+/*:1345*/
+#line 266 "tex.w"
+
+
+void initialize(void)
+{/*19:*/
+#line 572 "tex.w"
+
+int i;
+
+/*:19*//*163:*/
+#line 3387 "tex.w"
+
+int k;
+
+/*:163*//*927:*/
+#line 18212 "tex.w"
+
+hyph_pointer z;
+
+/*:927*/
+#line 269 "tex.w"
+
+/*8:*/
+#line 315 "tex.w"
+
+/*21:*/
+#line 594 "tex.w"
+
+xchr[040]= ' ';
+xchr[041]= '!';
+xchr[042]= '"';
+xchr[043]= '#';
+xchr[044]= '$';
+xchr[045]= '%';
+xchr[046]= '&';
+xchr[047]= '\'';
+xchr[050]= '(';
+xchr[051]= ')';
+xchr[052]= '*';
+xchr[053]= '+';
+xchr[054]= ',';
+xchr[055]= '-';
+xchr[056]= '.';
+xchr[057]= '/';
+xchr[060]= '0';
+xchr[061]= '1';
+xchr[062]= '2';
+xchr[063]= '3';
+xchr[064]= '4';
+xchr[065]= '5';
+xchr[066]= '6';
+xchr[067]= '7';
+xchr[070]= '8';
+xchr[071]= '9';
+xchr[072]= ':';
+xchr[073]= ';';
+xchr[074]= '<';
+xchr[075]= '=';
+xchr[076]= '>';
+xchr[077]= '?';
+xchr[0100]= '@';
+xchr[0101]= 'A';
+xchr[0102]= 'B';
+xchr[0103]= 'C';
+xchr[0104]= 'D';
+xchr[0105]= 'E';
+xchr[0106]= 'F';
+xchr[0107]= 'G';
+xchr[0110]= 'H';
+xchr[0111]= 'I';
+xchr[0112]= 'J';
+xchr[0113]= 'K';
+xchr[0114]= 'L';
+xchr[0115]= 'M';
+xchr[0116]= 'N';
+xchr[0117]= 'O';
+xchr[0120]= 'P';
+xchr[0121]= 'Q';
+xchr[0122]= 'R';
+xchr[0123]= 'S';
+xchr[0124]= 'T';
+xchr[0125]= 'U';
+xchr[0126]= 'V';
+xchr[0127]= 'W';
+xchr[0130]= 'X';
+xchr[0131]= 'Y';
+xchr[0132]= 'Z';
+xchr[0133]= '[';
+xchr[0134]= '\\';
+xchr[0135]= ']';
+xchr[0136]= '^';
+xchr[0137]= '_';
+xchr[0140]= '`';
+xchr[0141]= 'a';
+xchr[0142]= 'b';
+xchr[0143]= 'c';
+xchr[0144]= 'd';
+xchr[0145]= 'e';
+xchr[0146]= 'f';
+xchr[0147]= 'g';
+xchr[0150]= 'h';
+xchr[0151]= 'i';
+xchr[0152]= 'j';
+xchr[0153]= 'k';
+xchr[0154]= 'l';
+xchr[0155]= 'm';
+xchr[0156]= 'n';
+xchr[0157]= 'o';
+xchr[0160]= 'p';
+xchr[0161]= 'q';
+xchr[0162]= 'r';
+xchr[0163]= 's';
+xchr[0164]= 't';
+xchr[0165]= 'u';
+xchr[0166]= 'v';
+xchr[0167]= 'w';
+xchr[0170]= 'x';
+xchr[0171]= 'y';
+xchr[0172]= 'z';
+xchr[0173]= '{';
+xchr[0174]= '|';
+xchr[0175]= '}';
+xchr[0176]= '~';
+
+/*:21*//*23:*/
+#line 725 "tex.w"
+
+for(i= 0;i<=037;i++)xchr[i]= ' ';
+for(i= 0177;i<=0377;i++)xchr[i]= ' ';
+
+/*:23*//*24:*/
+#line 735 "tex.w"
+
+for(i= first_text_char;i<=last_text_char;i++)xord[chr(i)]= invalid_code;
+for(i= 0200;i<=0377;i++)xord[xchr[i]]= i;
+for(i= 0;i<=0176;i++)xord[xchr[i]]= i;
+
+/*:24*//*74:*/
+#line 1773 "tex.w"
+interaction= error_stop_mode;
+
+/*:74*//*77:*/
+#line 1821 "tex.w"
+
+deletions_allowed= true;set_box_allowed= true;
+error_count= 0;
+
+/*:77*//*80:*/
+#line 1875 "tex.w"
+
+help_ptr= 0;use_err_help= false;
+
+/*:80*//*97:*/
+#line 2139 "tex.w"
+
+interrupt= 0;OK_to_interrupt= true;
+
+/*:97*//*166:*/
+#line 3438 "tex.w"
+
+#ifdef DEBUG
+was_mem_end= mem_min;
+was_lo_max= mem_min;was_hi_min= mem_max;
+panicking= false;
+#endif
+
+/*:166*//*215:*/
+#line 4407 "tex.w"
+
+nest_ptr= 0;max_nest_stack= 0;
+mode= vmode;head= contrib_head;tail= contrib_head;
+prev_depth= ignore_depth;mode_line= 0;
+prev_graf= 0;shown_mode= 0;
+/*991:*/
+#line 19388 "tex.w"
+
+page_contents= empty;page_tail= page_head;link(page_head)= null;
+last_glue= max_halfword;last_penalty= 0;last_kern= 0;
+page_depth= 0;page_max_depth= 0
+
+/*:991*/
+#line 4412 "tex.w"
+;
+
+/*:215*//*254:*/
+#line 5506 "tex.w"
+
+for(k= int_base;k<=eqtb_size;k++)xeq_level[k]= level_one;
+
+/*:254*//*257:*/
+#line 5557 "tex.w"
+
+no_new_control_sequence= true;
+next(hash_base)= 0;text(hash_base)= 0;
+for(k= hash_base+1;k<=undefined_control_sequence-1;k++)hash[k]= hash[hash_base];
+
+/*:257*//*272:*/
+#line 5956 "tex.w"
+
+save_ptr= 0;cur_level= level_one;cur_group= bottom_level;cur_boundary= 0;
+max_save_stack= 0;
+
+/*:272*//*287:*/
+#line 6188 "tex.w"
+
+mag_set= 0;
+
+/*:287*//*383:*/
+#line 7929 "tex.w"
+
+top_mark= null;first_mark= null;bot_mark= null;
+split_first_mark= null;split_bot_mark= null;
+
+/*:383*//*439:*/
+#line 8747 "tex.w"
+
+cur_val= 0;cur_val_level= int_val;radix= 0;cur_order= normal;
+
+/*:439*//*481:*/
+#line 9486 "tex.w"
+
+for(k= 0;k<=16;k++)read_open[k]= closed;
+
+/*:481*//*490:*/
+#line 9675 "tex.w"
+
+cond_ptr= null;if_limit= normal;cur_if= 0;if_line= 0;
+
+/*:490*//*551:*/
+#line 10813 "tex.w"
+
+for(k= font_base;k<=font_max;k++)font_used[k]= false;
+
+/*:551*//*556:*/
+#line 10890 "tex.w"
+
+null_character.b0= min_quarterword;null_character.b1= min_quarterword;
+null_character.b2= min_quarterword;null_character.b3= min_quarterword;
+
+/*:556*//*593:*/
+#line 11896 "tex.w"
+
+total_pages= 0;max_v= 0;max_h= 0;max_push= 0;last_bop= -1;
+doing_leaders= false;dead_cycles= 0;cur_s= -1;
+
+/*:593*//*596:*/
+#line 11942 "tex.w"
+
+half_buf= dvi_buf_size/2;dvi_limit= dvi_buf_size;dvi_ptr= 0;
+dvi_offset= 0;dvi_gone= 0;
+
+/*:596*//*606:*/
+#line 12098 "tex.w"
+
+down_ptr= null;right_ptr= null;
+
+/*:606*//*648:*/
+#line 12934 "tex.w"
+adjust_tail= null;last_badness= 0;
+
+/*:648*//*662:*/
+#line 13109 "tex.w"
+
+pack_begin_line= 0;
+
+/*:662*//*685:*/
+#line 13526 "tex.w"
+
+empty_field.rh= empty;empty_field.lh= null;
+null_delimiter.b0= 0;null_delimiter.b1= min_quarterword;
+null_delimiter.b2= 0;null_delimiter.b3= min_quarterword;
+
+/*:685*//*771:*/
+#line 15285 "tex.w"
+
+align_ptr= null;cur_align= null;cur_span= null;cur_loop= null;
+cur_head= null;cur_tail= null;
+
+/*:771*//*928:*/
+#line 18215 "tex.w"
+
+for(z= 0;z<=hyph_size;z++)
+{hyph_word[z]= 0;hyph_list[z]= null;
+}
+hyph_count= 0;
+
+/*:928*//*990:*/
+#line 19381 "tex.w"
+
+output_active= false;insert_penalties= 0;
+
+/*:990*//*1033:*/
+#line 20114 "tex.w"
+
+ligature_present= false;cancel_boundary= false;lft_hit= false;rt_hit= false;
+ins_disc= false;
+
+/*:1033*//*1267:*/
+#line 23460 "tex.w"
+
+after_token= 0;
+
+/*:1267*//*1282:*/
+#line 23563 "tex.w"
+long_help_seen= false;
+
+/*:1282*//*1300:*/
+#line 23749 "tex.w"
+
+format_ident= 0;
+
+/*:1300*//*1343:*/
+#line 24616 "tex.w"
+
+for(k= 0;k<=17;k++)write_open[k]= false;
+
+/*:1343*/
+#line 316 "tex.w"
+
+#ifdef INIT
+/*164:*/
+#line 3390 "tex.w"
+
+for(k= mem_bot+1;k<=lo_mem_stat_max;k++)mem[k].sc= 0;
+
+
+k= mem_bot;while(k<=lo_mem_stat_max)
+
+{glue_ref_count(k)= null+1;
+stretch_order(k)= normal;shrink_order(k)= normal;
+k= k+glue_spec_size;
+}
+stretch(fil_glue)= unity;stretch_order(fil_glue)= fil;
+stretch(fill_glue)= unity;stretch_order(fill_glue)= fill;
+stretch(ss_glue)= unity;stretch_order(ss_glue)= fil;
+shrink(ss_glue)= unity;shrink_order(ss_glue)= fil;
+stretch(fil_neg_glue)= -unity;stretch_order(fil_neg_glue)= fil;
+rover= lo_mem_stat_max+1;
+link(rover)= empty_flag;
+node_size(rover)= 1000;
+llink(rover)= rover;rlink(rover)= rover;
+lo_mem_max= rover+1000;link(lo_mem_max)= null;info(lo_mem_max)= null;
+for(k= hi_mem_stat_min;k<=mem_top;k++)
+mem[k]= mem[lo_mem_max];
+/*790:*/
+#line 15595 "tex.w"
+
+info(omit_template)= end_template_token;
+
+/*:790*//*797:*/
+#line 15701 "tex.w"
+
+link(end_span)= max_quarterword+1;info(end_span)= null;
+
+/*:797*//*820:*/
+#line 16162 "tex.w"
+
+type(last_active)= hyphenated;line_number(last_active)= max_halfword;
+subtype(last_active)= 0;
+
+/*:820*//*981:*/
+#line 19215 "tex.w"
+
+subtype(page_ins_head)= qi(255);
+type(page_ins_head)= split_up;link(page_ins_head)= page_ins_head;
+
+/*:981*//*988:*/
+#line 19372 "tex.w"
+
+type(page_head)= glue_node;subtype(page_head)= normal;
+
+/*:988*/
+#line 3412 "tex.w"
+;
+avail= null;mem_end= mem_top;
+hi_mem_min= hi_mem_stat_min;
+var_used= lo_mem_stat_max+1-mem_bot;dyn_used= hi_mem_stat_usage;
+
+
+/*:164*//*222:*/
+#line 4596 "tex.w"
+
+eq_type(undefined_control_sequence)= undefined_cs;
+equiv(undefined_control_sequence)= null;
+eq_level(undefined_control_sequence)= level_zero;
+for(k= active_base;k<=undefined_control_sequence-1;k++)
+eqtb[k]= eqtb[undefined_control_sequence];
+
+/*:222*//*228:*/
+#line 4751 "tex.w"
+
+equiv(glue_base)= zero_glue;eq_level(glue_base)= level_one;
+eq_type(glue_base)= glue_ref;
+for(k= glue_base+1;k<=local_base-1;k++)eqtb[k]= eqtb[glue_base];
+glue_ref_count(zero_glue)= glue_ref_count(zero_glue)+local_base-glue_base;
+
+/*:228*//*232:*/
+#line 4870 "tex.w"
+
+par_shape_ptr= null;eq_type(par_shape_loc)= shape_ref;
+eq_level(par_shape_loc)= level_one;
+for(k= output_routine_loc;k<=toks_base+255;k++)
+eqtb[k]= eqtb[undefined_control_sequence];
+box(0)= null;eq_type(box_base)= box_ref;eq_level(box_base)= level_one;
+for(k= box_base+1;k<=box_base+255;k++)eqtb[k]= eqtb[box_base];
+cur_font= null_font;eq_type(cur_font_loc)= data;
+eq_level(cur_font_loc)= level_one;
+for(k= math_font_base;k<=math_font_base+47;k++)eqtb[k]= eqtb[cur_font_loc];
+equiv(cat_code_base)= 0;eq_type(cat_code_base)= data;
+eq_level(cat_code_base)= level_one;
+for(k= cat_code_base+1;k<=int_base-1;k++)eqtb[k]= eqtb[cat_code_base];
+for(k= 0;k<=255;k++)
+{cat_code(k)= other_char;math_code(k)= hi(k);sf_code(k)= 1000;
+}
+cat_code(carriage_return)= car_ret;cat_code(' ')= spacer;
+cat_code('\\')= escape;cat_code('%')= comment;
+cat_code(invalid_code)= invalid_char;cat_code(null_code)= ignore;
+for(k= '0';k<='9';k++)math_code(k)= hi(k+var_code);
+for(k= 'A';k<='Z';k++)
+{cat_code(k)= letter;cat_code(k+'a'-'A')= letter;
+math_code(k)= hi(k+var_code+0x100);
+math_code(k+'a'-'A')= hi(k+'a'-'A'+var_code+0x100);
+lc_code(k)= k+'a'-'A';lc_code(k+'a'-'A')= k+'a'-'A';
+uc_code(k)= k;uc_code(k+'a'-'A')= k;
+sf_code(k)= 999;
+}
+
+/*:232*//*240:*/
+#line 5279 "tex.w"
+
+for(k= int_base;k<=del_code_base-1;k++)eqtb[k].i= 0;
+mag= 1000;tolerance= 10000;hang_after= 1;max_dead_cycles= 25;
+escape_char= '\\';end_line_char= carriage_return;
+for(k= 0;k<=255;k++)del_code(k)= -1;
+del_code('.')= 0;
+
+/*:240*//*250:*/
+#line 5471 "tex.w"
+
+for(k= dimen_base;k<=eqtb_size;k++)eqtb[k].sc= 0;
+
+/*:250*//*258:*/
+#line 5562 "tex.w"
+
+hash_used= frozen_control_sequence;
+cs_count= 0;
+eq_type(frozen_dont_expand)= dont_expand;
+text(frozen_dont_expand)= /*1525:*/
+#line 25471 "tex.w"
+400
+/*:1525*/
+#line 5566 "tex.w"
+;
+
+
+/*:258*//*552:*/
+#line 10819 "tex.w"
+
+font_ptr= null_font;fmem_ptr= 7;
+font_name[null_font]= /*1639:*/
+#line 25813 "tex.w"
+514
+/*:1639*/
+#line 10821 "tex.w"
+;font_area[null_font]= empty_string;
+hyphen_char[null_font]= '-';skew_char[null_font]= -1;
+bchar_label[null_font]= non_address;
+font_bchar[null_font]= non_char;font_false_bchar[null_font]= non_char;
+font_bc[null_font]= 1;font_ec[null_font]= 0;
+font_size[null_font]= 0;font_dsize[null_font]= 0;
+char_base[null_font]= 0;width_base[null_font]= 0;
+height_base[null_font]= 0;depth_base[null_font]= 0;
+italic_base[null_font]= 0;lig_kern_base[null_font]= 0;
+kern_base[null_font]= 0;exten_base[null_font]= 0;
+font_glue[null_font]= null;font_params[null_font]= 7;
+param_base[null_font]= -1;
+for(k= 0;k<=6;k++)font_info[k].sc= 0;
+
+/*:552*//*946:*/
+#line 18486 "tex.w"
+
+for(k= -trie_op_size;k<=trie_op_size;k++)trie_op_hash[k]= 0;
+for(k= 0;k<=255;k++)trie_used[k]= min_quarterword;
+trie_op_ptr= 0;
+
+/*:946*//*951:*/
+#line 18612 "tex.w"
+
+trie_not_ready= true;trie_root= 0;trie_c[0]= si(0);trie_ptr= 0;
+
+/*:951*//*1216:*/
+#line 22800 "tex.w"
+
+text(frozen_protection)= /*1751:*/
+#line 26149 "tex.w"
+626
+/*:1751*/
+#line 22801 "tex.w"
+;
+
+/*:1216*//*1301:*/
+#line 23752 "tex.w"
+
+format_ident= /*1781:*/
+#line 26239 "tex.w"
+656
+/*:1781*/
+#line 23753 "tex.w"
+;
+
+/*:1301*//*1369:*/
+#line 24851 "tex.w"
+
+text(end_write)= /*1791:*/
+#line 26269 "tex.w"
+666
+/*:1791*/
+#line 24852 "tex.w"
+;eq_level(end_write)= level_one;
+eq_type(end_write)= outer_call;equiv(end_write)= null;
+
+/*:1369*/
+#line 318 "tex.w"
+
+#endif
+
+/*:8*/
+#line 270 "tex.w"
+;
+}
+/*57:*/
+#line 1474 "tex.w"
+
+void print_ln(void)
+{switch(selector){
+case term_and_log:{wterm_cr;wlog_cr;
+term_offset= 0;file_offset= 0;
+}break;
+case log_only:{wlog_cr;file_offset= 0;
+}break;
+case term_only:{wterm_cr;term_offset= 0;
+}break;
+case no_print:case pseudo:case new_string:do_nothing;break;
+default:write_ln(write_file[selector]);
+}
+}
+
+/*:57*//*58:*/
+#line 1493 "tex.w"
+
+void print_char(ASCII_code s)
+{
+if(/*244:*/
+#line 5312 "tex.w"
+s==new_line_char
+
+/*:244*/
+#line 1496 "tex.w"
+)
+if(selector<pseudo)
+{print_ln();return;
+}
+switch(selector){
+case term_and_log:{wterm("%c",xchr[s]);wlog("%c",xchr[s]);
+incr(term_offset);incr(file_offset);
+if(term_offset==max_print_line)
+{wterm_cr;term_offset= 0;
+}
+if(file_offset==max_print_line)
+{wlog_cr;file_offset= 0;
+}
+}break;
+case log_only:{wlog("%c",xchr[s]);incr(file_offset);
+if(file_offset==max_print_line)print_ln();
+}break;
+case term_only:{wterm("%c",xchr[s]);incr(term_offset);
+if(term_offset==max_print_line)print_ln();
+}break;
+case no_print:do_nothing;break;
+case pseudo:if(tally<trick_count)trick_buf[tally%error_line]= s;break;
+case new_string:{if(pool_ptr<pool_size)append_char(s);
+}break;
+default:write(write_file[selector],"%c",xchr[s]);
+}
+incr(tally);
+}
+
+/*:58*//*59:*/
+#line 1533 "tex.w"
+
+void print(int s)
+{
+pool_pointer j;
+int nl;
+if(s>=str_ptr)s= /*1381:*/
+#line 25039 "tex.w"
+256
+/*:1381*/
+#line 1538 "tex.w"
+;
+
+else if(s<256)
+if(s<0)s= /*1381:*/
+#line 25039 "tex.w"
+256
+/*:1381*/
+#line 1541 "tex.w"
+;
+else{if(selector> pseudo)
+{print_char(s);return;
+}
+if((/*244:*/
+#line 5312 "tex.w"
+s==new_line_char
+
+/*:244*/
+#line 1545 "tex.w"
+))
+if(selector<pseudo)
+{print_ln();return;
+}
+nl= new_line_char;new_line_char= -1;
+
+j= str_start[s];
+while(j<str_start[s+1])
+{print_char(so(str_pool[j]));incr(j);
+}
+new_line_char= nl;return;
+}
+j= str_start[s];
+while(j<str_start[s+1])
+{print_char(so(str_pool[j]));incr(j);
+}
+}
+
+void print_str(char*s)
+{while(*s!=0)print_char(*s++);
+}
+
+/*:59*//*60:*/
+#line 1571 "tex.w"
+
+void slow_print(int s)
+{pool_pointer j;
+if((s>=str_ptr)||(s<256))print(s);
+else{j= str_start[s];
+while(j<str_start[s+1])
+{print(so(str_pool[j]));incr(j);
+}
+}
+}
+
+/*:60*//*62:*/
+#line 1598 "tex.w"
+
+void print_nl(char*s)
+{if(((term_offset> 0)&&(odd(selector)))||
+((file_offset> 0)&&(selector>=log_only)))print_ln();
+print_str(s);
+}
+
+/*:62*//*63:*/
+#line 1608 "tex.w"
+
+void print_esc(str_number s)
+{int c;
+/*243:*/
+#line 5310 "tex.w"
+c= escape_char
+
+/*:243*/
+#line 1611 "tex.w"
+;
+if(c>=0)if(c<256)print(c);
+slow_print(s);
+}
+
+/*:63*//*64:*/
+#line 1618 "tex.w"
+
+void print_the_digs(eight_bits k)
+
+{while(k> 0)
+{decr(k);
+if(dig[k]<10)print_char('0'+dig[k]);
+else print_char('A'-10+dig[k]);
+}
+}
+
+/*:64*//*65:*/
+#line 1634 "tex.w"
+
+void print_int(int n)
+{uint8_t k;
+int m;
+k= 0;
+if(n<0)
+{print_char('-');
+if(n> -100000000)negate(n);
+else{m= -1-n;n= m/10;m= (m%10)+1;k= 1;
+if(m<10)dig[0]= m;
+else{dig[0]= 0;incr(n);
+}
+}
+}
+do{dig[k]= n%10;n= n/10;incr(k);
+}while(!(n==0));
+print_the_digs(k);
+}
+
+/*:65*//*262:*/
+#line 5640 "tex.w"
+
+void print_cs(int p)
+{if(p<hash_base)
+if(p>=single_base)
+if(p==null_cs)
+{print_esc(/*1526:*/
+#line 25474 "tex.w"
+401
+/*:1526*/
+#line 5645 "tex.w"
+);print_esc(/*1527:*/
+#line 25477 "tex.w"
+402
+/*:1527*/
+#line 5645 "tex.w"
+);print_char(' ');
+}
+else{print_esc(p-single_base);
+if(cat_code(p-single_base)==letter)print_char(' ');
+}
+else if(p<active_base)print_esc(/*1528:*/
+#line 25480 "tex.w"
+403
+/*:1528*/
+#line 5650 "tex.w"
+);
+
+else print(p-active_base);
+else if(p>=undefined_control_sequence)print_esc(/*1528:*/
+#line 25480 "tex.w"
+403
+/*:1528*/
+#line 5653 "tex.w"
+);
+else if((text(p)<0)||(text(p)>=str_ptr))print_esc(/*1529:*/
+#line 25483 "tex.w"
+404
+/*:1529*/
+#line 5654 "tex.w"
+);
+
+else{print_esc(text(p));
+print_char(' ');
+}
+}
+
+/*:262*//*263:*/
+#line 5664 "tex.w"
+
+void sprint_cs(pointer p)
+{if(p<hash_base)
+if(p<single_base)print(p-active_base);
+else if(p<null_cs)print_esc(p-single_base);
+else{print_esc(/*1526:*/
+#line 25474 "tex.w"
+401
+/*:1526*/
+#line 5669 "tex.w"
+);print_esc(/*1527:*/
+#line 25477 "tex.w"
+402
+/*:1527*/
+#line 5669 "tex.w"
+);
+}
+else print_esc(text(p));
+}
+
+/*:263*//*518:*/
+#line 10100 "tex.w"
+
+void print_file_name(int n,int a,int e)
+{slow_print(a);slow_print(n);slow_print(e);
+}
+
+/*:518*//*699:*/
+#line 13817 "tex.w"
+
+void print_size(int s)
+{if(s==text_size)print_esc(/*1438:*/
+#line 25210 "tex.w"
+313
+/*:1438*/
+#line 13819 "tex.w"
+);
+else if(s==script_size)print_esc(/*1439:*/
+#line 25213 "tex.w"
+314
+/*:1439*/
+#line 13820 "tex.w"
+);
+else print_esc(/*1440:*/
+#line 25216 "tex.w"
+315
+/*:1440*/
+#line 13821 "tex.w"
+);
+}
+
+/*:699*//*1355:*/
+#line 24737 "tex.w"
+
+void print_write_whatsit(str_number s,pointer p)
+{print_esc(s);
+if(write_stream(p)<16)print_int(write_stream(p));
+else if(write_stream(p)==16)print_char('*');
+
+else print_char('-');
+}
+
+/*:1355*/
+#line 272 "tex.w"
+
+/*78:*/
+#line 1836 "tex.w"
+
+void normalize_selector(void);
+void get_token(void);
+void term_input(void);
+void show_context(void);
+void begin_file_reading(void);
+void open_log_file(void);
+void close_files_and_terminate(void);
+void clear_for_error_prompt(void);
+void give_err_help(void);
+#ifdef DEBUG
+void debug_help(void);
+#else
+#define debug_help() do_nothing
+#endif
+
+/*:78*//*81:*/
+#line 1888 "tex.w"
+
+void jump_out(void)
+{close_files_and_terminate();exit(0);
+}
+
+/*:81*//*82:*/
+#line 1895 "tex.w"
+
+void error(void)
+{
+ASCII_code c;
+int s1,s2,s3,s4;
+
+if(history<error_message_issued)history= error_message_issued;
+print_char('.');show_context();
+if(interaction==error_stop_mode)/*83:*/
+#line 1913 "tex.w"
+
+loop{resume:clear_for_error_prompt();prompt_input("? ");
+
+if(last==first)return;
+c= buffer[first];
+if(c>='a')c= c+'A'-'a';
+/*84:*/
+#line 1934 "tex.w"
+
+switch(c){
+case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':if(deletions_allowed)
+/*88:*/
+#line 2007 "tex.w"
+
+{s1= cur_tok;s2= cur_cmd;s3= cur_chr;s4= align_state;
+align_state= 1000000;OK_to_interrupt= false;
+if((last> first+1)&&(buffer[first+1]>='0')&&(buffer[first+1]<='9'))
+c= c*10+buffer[first+1]-'0'*11;
+else c= c-'0';
+while(c> 0)
+{get_token();
+decr(c);
+}
+cur_tok= s1;cur_cmd= s2;cur_chr= s3;align_state= s4;OK_to_interrupt= true;
+help2("I have just deleted some text, as you asked.")
+("You can now delete more, or insert, or whatever.");
+show_context();goto resume;
+}
+
+/*:88*/
+#line 1937 "tex.w"
+break;
+
+#ifdef DEBUG
+case'D':{debug_help();goto resume;}
+#endif
+case'E':if(base_ptr> 0)
+{print_nl("You want to edit file ");
+
+slow_print(input_stack[base_ptr].name_field);
+print_str(" at line ");print_int(line);
+interaction= scroll_mode;jump_out();
+}break;
+case'H':/*89:*/
+#line 2023 "tex.w"
+
+{if(use_err_help)
+{give_err_help();use_err_help= false;
+}
+else{if(help_ptr==0)
+help2("Sorry, I don't know how to help in this situation.")
+("Maybe you should try asking a human?");
+do{decr(help_ptr);print_str(help_line[help_ptr]);print_ln();
+}while(!(help_ptr==0));
+}
+help4("Sorry, I already gave what help I could...")
+("Maybe you should try asking a human?")
+("An error might have occurred before I noticed any problems.")
+("``If all else fails, read the instructions.'");
+goto resume;
+}
+
+/*:89*/
+#line 1949 "tex.w"
+
+case'I':/*87:*/
+#line 1991 "tex.w"
+
+{begin_file_reading();
+
+if(last> first+1)
+{loc= first+1;buffer[first]= ' ';
+}
+else{prompt_input("insert>");loc= first;
+
+}
+first= last;
+cur_input.limit_field= last-1;
+return;
+}
+
+/*:87*/
+#line 1950 "tex.w"
+
+case'Q':case'R':case'S':/*86:*/
+#line 1974 "tex.w"
+
+{error_count= 0;interaction= batch_mode+c-'Q';
+print_str("OK, entering ");
+switch(c){
+case'Q':{print_esc(/*1383:*/
+#line 25045 "tex.w"
+258
+/*:1383*/
+#line 1978 "tex.w"
+);decr(selector);
+}break;
+case'R':print_esc(/*1384:*/
+#line 25048 "tex.w"
+259
+/*:1384*/
+#line 1980 "tex.w"
+);break;
+case'S':print_esc(/*1385:*/
+#line 25051 "tex.w"
+260
+/*:1385*/
+#line 1981 "tex.w"
+);
+}
+print_str("...");print_ln();update_terminal;return;
+}
+
+/*:86*/
+#line 1951 "tex.w"
+
+case'X':{interaction= scroll_mode;jump_out();
+}break;
+default:do_nothing;
+}
+/*85:*/
+#line 1958 "tex.w"
+
+{print_str("Type <return> to proceed, S to scroll future error messages,");
+
+print_nl("R to run without stopping, Q to run quietly,");
+print_nl("I to insert something, ");
+if(base_ptr> 0)print_str("E to edit your file,");
+if(deletions_allowed)
+print_nl("1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
+print_nl("H for help, X to quit.");
+}
+
+/*:85*/
+#line 1956 "tex.w"
+
+
+/*:84*/
+#line 1919 "tex.w"
+;
+}
+
+/*:83*/
+#line 1903 "tex.w"
+;
+incr(error_count);
+if(error_count==100)
+{print_nl("(That makes 100 errors; please try again.)");
+
+history= fatal_error_stop;jump_out();
+}
+/*90:*/
+#line 2040 "tex.w"
+
+if(interaction> batch_mode)decr(selector);
+if(use_err_help)
+{print_ln();give_err_help();
+}
+else while(help_ptr> 0)
+{decr(help_ptr);print_nl(help_line[help_ptr]);
+}
+print_ln();
+if(interaction> batch_mode)incr(selector);
+print_ln()
+
+/*:90*/
+#line 1910 "tex.w"
+;
+}
+
+/*:82*//*93:*/
+#line 2079 "tex.w"
+
+void fatal_error(char*s)
+{normalize_selector();
+print_err("Emergency stop");help1(s);succumb;
+
+}
+
+/*:93*//*94:*/
+#line 2088 "tex.w"
+
+void overflow(char*s,int n)
+{normalize_selector();
+print_err("TeX capacity exceeded, sorry [");
+
+print_str(s);print_char('=');print_int(n);print_char(']');
+help2("If you really absolutely need more capacity,")
+("you can ask a wizard to enlarge me.");
+succumb;
+}
+
+/*:94*//*95:*/
+#line 2107 "tex.w"
+
+void confusion(str_number s)
+
+{normalize_selector();
+if(history<error_message_issued)
+{print_err("This can't happen (");print(s);print_char(')');
+
+help1("I'm broken. Please show this to someone who can fix can fix");
+}
+else{print_err("I can't go on meeting you like this");
+
+help2("One of your faux pas seems to have wounded me deeply...")
+("in fact, I'm barely conscious. Please fix it and try again.");
+}
+succumb;
+}
+
+/*:95*/
+#line 273 "tex.w"
+
+
+/*:4*//*27:*/
+#line 823 "tex.w"
+bool a_open_in(alpha_file*f)
+
+{reset((*f),name_of_file,"r");return reset_OK((*f));
+}
+
+bool a_open_out(alpha_file*f)
+
+{rewrite((*f),name_of_file,"w");return rewrite_OK((*f));
+}
+
+bool b_open_in(byte_file*f)
+
+{reset((*f),name_of_file,"rb");return reset_OK((*f));
+}
+
+bool b_open_out(byte_file*f)
+
+{rewrite((*f),name_of_file,"wb");return rewrite_OK((*f));
+}
+
+bool w_open_in(word_file*f)
+
+{reset((*f),name_of_file,"rb");return reset_OK((*f));
+}
+
+bool w_open_out(word_file*f)
+
+{rewrite((*f),name_of_file,"wb");return rewrite_OK((*f));
+}
+
+/*:27*//*28:*/
+#line 864 "tex.w"
+void a_close(alpha_file*f)
+{close((*f));
+}
+
+void b_close(byte_file*f)
+{close((*f));
+}
+
+void w_close(word_file*f)
+{close((*f));
+}
+
+/*:28*//*31:*/
+#line 937 "tex.w"
+bool input_ln(alpha_file*f,bool bypass_eoln)
+
+{uint16_t last_nonblank;
+if(bypass_eoln)if(!eof((*f)))get((*f));
+
+last= first;
+if(eof((*f)))return false;
+else{last_nonblank= first;
+while(!eoln((*f)))
+{if(last>=max_buf_stack)
+{max_buf_stack= last+1;
+if(max_buf_stack==buf_size)
+/*35:*/
+#line 1023 "tex.w"
+
+if(format_ident==0)
+{write_ln(term_out,"Buffer size exceeded!");exit(0);
+
+}
+else{cur_input.loc_field= first;cur_input.limit_field= last-1;
+overflow("buffer size",buf_size);
+
+}
+
+/*:35*/
+#line 949 "tex.w"
+;
+}
+buffer[last]= xord[(*f).d];get((*f));incr(last);
+if(buffer[last-1]!=' ')last_nonblank= last;
+}
+last= last_nonblank;return true;
+}
+}
+
+/*:31*//*37:*/
+#line 1067 "tex.w"
+bool init_terminal(void)
+{
+t_open_in;
+loop{wake_up_terminal;write(term_out,"**");update_terminal;
+
+if(!input_ln(&term_in,true))
+{write_ln(term_out);
+write(term_out,"! End of file on the terminal... why?");
+
+return false;
+}
+loc= first;
+while((loc<last)&&(buffer[loc]==' '))incr(loc);
+if(loc<last)
+{return true;
+
+}
+write_ln(term_out,"Please type the name of your input file.");
+}
+}
+
+/*:37*//*43:*/
+#line 1185 "tex.w"
+str_number make_string(void)
+{if(str_ptr==max_strings)
+overflow("number of strings",max_strings-init_str_ptr);
+
+incr(str_ptr);str_start[str_ptr]= pool_ptr;
+return str_ptr-1;
+}
+
+/*:43*//*45:*/
+#line 1204 "tex.w"
+bool str_eq_buf(str_number s,int k)
+
+{
+pool_pointer j;
+bool result;
+j= str_start[s];
+while(j<str_start[s+1])
+{if(so(str_pool[j])!=buffer[k])
+{result= false;goto not_found;
+}
+incr(j);incr(k);
+}
+result= true;
+not_found:return result;
+}
+
+/*:45*//*46:*/
+#line 1223 "tex.w"
+bool str_eq_str(str_number s,str_number t)
+
+{
+pool_pointer j,k;
+bool result;
+result= false;
+if(length(s)!=length(t))goto not_found;
+j= str_start[s];k= str_start[t];
+while(j<str_start[s+1])
+{if(str_pool[j]!=str_pool[k])goto not_found;
+incr(j);incr(k);
+}
+result= true;
+not_found:return result;
+}
+
+/*:46*//*47:*/
+#line 1245 "tex.w"
+
+#ifdef INIT
+bool get_strings_started(void)
+
+{
+int k,l;
+uint8_t m,n;
+str_number g;
+int a;
+bool c;
+pool_ptr= 0;str_ptr= 0;str_start[0]= 0;
+/*48:*/
+#line 1265 "tex.w"
+
+for(k= 0;k<=255;k++)
+{if(/*49:*/
+#line 1305 "tex.w"
+
+(k<' ')||(k> '~')
+
+/*:49*/
+#line 1267 "tex.w"
+)
+{append_char('^');append_char('^');
+if(k<0100)append_char(k+0100)
+else if(k<0200)append_char(k-0100)
+else{app_lc_hex(k/16);app_lc_hex(k%16);
+}
+}
+else append_char(k);
+g= make_string();
+}
+
+/*:48*/
+#line 1256 "tex.w"
+;
+/*51:*/
+#line 1324 "tex.w"
+
+{int k;for(k= 1;k<=file_name_size;k++)name_of_file[k]= pool_name[k-1];}
+if(a_open_in(&pool_file))
+{c= false;
+do{/*52:*/
+#line 1336 "tex.w"
+
+{if(eof(pool_file))bad_pool("! TEX.POOL has no check sum.");
+
+read(pool_file,m);read(pool_file,n);
+if(m=='*')/*53:*/
+#line 1362 "tex.w"
+
+{a= 0;k= 1;
+loop{if((xord[n]<'0')||(xord[n]> '9'))
+bad_pool("! TEX.POOL check sum doesn't have nine digits.");
+
+a= 10*a+xord[n]-'0';
+if(k==9)goto done;
+incr(k);read(pool_file,n);
+}
+done:if(a!=0)bad_pool("! TEX.POOL doesn't match; TANGLE me again.");
+
+c= true;
+}
+
+/*:53*/
+#line 1340 "tex.w"
+
+else{if((xord[m]<'0')||(xord[m]> '9')||
+(xord[n]<'0')||(xord[n]> '9'))
+bad_pool("! TEX.POOL line doesn't begin with two digits.");
+
+l= xord[m]*10+xord[n]-'0'*11;
+if(pool_ptr+l+string_vacancies> pool_size)
+bad_pool("! You have to increase POOLSIZE.");
+
+for(k= 1;k<=l;k++)
+{if(eoln(pool_file))m= ' ';else read(pool_file,m);
+append_char(xord[m]);
+}
+read_ln(pool_file);g= make_string();
+}
+}
+
+/*:52*/
+#line 1329 "tex.w"
+;
+}while(!(c));
+a_close(&pool_file);return true;
+}
+else bad_pool("! I can't read TEX.POOL.")
+
+
+/*:51*/
+#line 1258 "tex.w"
+;
+}
+#endif
+
+/*:47*//*66:*/
+#line 1656 "tex.w"
+void print_two(int n)
+{n= abs(n)%100;print_char('0'+(n/10));
+print_char('0'+(n%10));
+}
+
+/*:66*//*67:*/
+#line 1663 "tex.w"
+void print_hex(int n)
+
+{uint8_t k;
+k= 0;print_char('"');
+do{dig[k]= n%16;n= n/16;incr(k);
+}while(!(n==0));
+print_the_digs(k);
+}
+
+/*:67*//*69:*/
+#line 1683 "tex.w"
+void print_roman_int(int n)
+{
+pool_pointer j,k;
+nonnegative_integer u,v;
+j= str_start[/*1382:*/
+#line 25042 "tex.w"
+257
+/*:1382*/
+#line 1687 "tex.w"
+];v= 1000;
+loop{while(n>=v)
+{print_char(so(str_pool[j]));n= n-v;
+}
+if(n<=0)return;
+k= j+2;u= v/(so(str_pool[k-1])-'0');
+if(str_pool[k-1]==si('2'))
+{k= k+2;u= u/(so(str_pool[k-1])-'0');
+}
+if(n+u>=v)
+{print_char(so(str_pool[k]));n= n+u;
+}
+else{j= j+2;v= v/(so(str_pool[j-1])-'0');
+}
+}
+}
+
+/*:69*//*70:*/
+#line 1707 "tex.w"
+void print_current_string(void)
+{pool_pointer j;
+j= str_start[str_ptr];
+while(j<pool_ptr)
+{print_char(so(str_pool[j]));incr(j);
+}
+}
+
+/*:70*//*71:*/
+#line 1725 "tex.w"
+void term_input(void)
+{int k;
+update_terminal;
+if(!input_ln(&term_in,true))fatal_error("End of file on the terminal!");
+
+term_offset= 0;
+decr(selector);
+if(last!=first)for(k= first;k<=last-1;k++)print(buffer[k]);
+print_ln();incr(selector);
+}
+
+/*:71*//*91:*/
+#line 2055 "tex.w"
+void int_error(int n)
+{print_str(" (");print_int(n);print_char(')');error();
+}
+
+/*:91*//*92:*/
+#line 2063 "tex.w"
+void normalize_selector(void)
+{if(log_opened)selector= term_and_log;
+else selector= term_only;
+if(job_name==0)open_log_file();
+if(interaction==batch_mode)decr(selector);
+}
+
+/*:92*//*98:*/
+#line 2147 "tex.w"
+void pause_for_instructions(void)
+{if(OK_to_interrupt)
+{interaction= error_stop_mode;
+if((selector==log_only)||(selector==no_print))
+incr(selector);
+print_err("Interruption");
+
+help3("You rang?")
+("Try to insert some instructions for me (e.g.,`I\\showlists'),")
+("unless you just want to quit by typing `X'.");
+deletions_allowed= false;error();deletions_allowed= true;
+interrupt= 0;
+}
+}
+
+/*:98*//*100:*/
+#line 2186 "tex.w"
+int half(int x)
+{if(odd(x))return(x+1)/2;
+else return x/2;
+}
+
+/*:100*//*102:*/
+#line 2207 "tex.w"
+scaled round_decimals(small_number k)
+
+{int a;
+a= 0;
+while(k> 0)
+{decr(k);a= (a+dig[k]*two)/10;
+}
+return(a+1)/2;
+}
+
+/*:102*//*103:*/
+#line 2229 "tex.w"
+void print_scaled(scaled s)
+
+{scaled delta;
+if(s<0)
+{print_char('-');negate(s);
+}
+print_int(s/unity);
+print_char('.');
+s= 10*(s%unity)+5;delta= 10;
+do{if(delta> unity)s= s+0100000-50000;
+print_char('0'+(s/unity));s= 10*(s%unity);delta= delta*10;
+}while(!(s<=delta));
+}
+
+/*:103*//*105:*/
+#line 2279 "tex.w"
+scaled mult_and_add(int n,scaled x,scaled y,scaled max_answer)
+{if(n<0)
+{negate(x);negate(n);
+}
+if(n==0)return y;
+else if(((x<=(max_answer-y)/n)&&(-x<=(max_answer+y)/n)))
+return n*x+y;
+else{arith_error= true;return 0;
+}
+}
+
+/*:105*//*106:*/
+#line 2292 "tex.w"
+scaled x_over_n(scaled x,int n)
+{bool negative;
+scaled x_over_n;negative= false;
+if(n==0)
+{arith_error= true;x_over_n= 0;rem= x;
+}
+else{if(n<0)
+{negate(x);negate(n);negative= true;
+}
+if(x>=0)
+{x_over_n= x/n;rem= x%n;
+}
+else{x_over_n= -((-x)/n);rem= -((-x)%n);
+}
+}
+if(negative)negate(rem);
+return x_over_n;}
+
+/*:106*//*107:*/
+#line 2317 "tex.w"
+scaled xn_over_d(scaled x,int n,int d)
+{bool positive;
+nonnegative_integer t,u,v;
+scaled xn_over_d;if(x>=0)positive= true;
+else{negate(x);positive= false;
+}
+t= (x%0100000)*n;
+u= (x/0100000)*n+(t/0100000);
+v= (u%d)*0100000+(t%0100000);
+if(u/d>=0100000)arith_error= true;
+else u= 0100000*(u/d)+(v/d);
+if(positive)
+{xn_over_d= u;rem= v%d;
+}
+else{xn_over_d= -u;rem= -(v%d);
+}
+return xn_over_d;}
+
+/*:107*//*108:*/
+#line 2355 "tex.w"
+halfword badness(scaled t,scaled s)
+{int r;
+
+if(t==0)return 0;
+else if(s<=0)return inf_bad;
+else{if(t<=7230584)r= (t*297)/s;
+else if(s>=1663497)r= t/(s/297);
+else r= t;
+if(r> 1290)return inf_bad;
+else return(r*r*r+0400000)/01000000;
+}
+}
+
+/*:108*//*114:*/
+#line 2524 "tex.w"
+
+#ifdef DEBUG
+void print_word(memory_word w)
+
+{print_int(w.i);print_char(' ');
+print_scaled(w.sc);print_char(' ');
+print_scaled(round(unity*float(w.gr)));print_ln();
+
+print_int(w.hh.lh);print_char('=');print_int(w.hh.b0);print_char(':');
+print_int(w.hh.b1);print_char(';');print_int(w.hh.rh);print_char(' ');
+print_int(w.qqqq.b0);print_char(':');print_int(w.qqqq.b1);print_char(':');
+print_int(w.qqqq.b2);print_char(':');print_int(w.qqqq.b3);
+}
+#endif
+
+/*:114*//*119:*/
+#line 2633 "tex.w"
+/*292:*/
+#line 6322 "tex.w"
+
+void show_token_list(int p,int q,int l)
+{
+int m,c;
+ASCII_code match_chr;
+ASCII_code n;
+match_chr= '#';n= '0';tally= 0;
+while((p!=null)&&(tally<l))
+{if(p==q)/*320:*/
+#line 7002 "tex.w"
+set_trick_count
+
+/*:320*/
+#line 6330 "tex.w"
+;
+/*293:*/
+#line 6339 "tex.w"
+
+if((p<hi_mem_min)||(p> mem_end))
+{print_esc(/*1386:*/
+#line 25054 "tex.w"
+261
+/*:1386*/
+#line 6341 "tex.w"
+);return;
+
+}
+if(info(p)>=cs_token_flag)print_cs(info(p)-cs_token_flag);
+else{m= info(p)/0400;c= info(p)%0400;
+if(info(p)<0)print_esc(/*1567:*/
+#line 25597 "tex.w"
+442
+/*:1567*/
+#line 6346 "tex.w"
+);
+
+else/*294:*/
+#line 6355 "tex.w"
+
+switch(m){
+case left_brace:case right_brace:case math_shift:case tab_mark:case sup_mark:case sub_mark:case spacer:
+case letter:case other_char:print(c);break;
+case mac_param:{print(c);print(c);
+}break;
+case out_param:{print(match_chr);
+if(c<=9)print_char(c+'0');
+else{print_char('!');return;
+}
+}break;
+case match:{match_chr= c;print(c);incr(n);print_char(n);
+if(n> '9')return;
+}break;
+case end_match:print_str("->");break;
+
+default:print_esc(/*1567:*/
+#line 25597 "tex.w"
+442
+/*:1567*/
+#line 6371 "tex.w"
+);
+
+}
+
+/*:294*/
+#line 6348 "tex.w"
+;
+}
+
+/*:293*/
+#line 6331 "tex.w"
+;
+p= link(p);
+}
+if(p!=null)print_esc(/*1566:*/
+#line 25594 "tex.w"
+441
+/*:1566*/
+#line 6334 "tex.w"
+);
+
+
+}
+
+/*:292*/
+#line 2633 "tex.w"
+
+/*306:*/
+#line 6673 "tex.w"
+
+void runaway(void)
+{pointer p;
+if(scanner_status> skipping)
+{print_nl("Runaway ");
+
+switch(scanner_status){
+case defining:{print_str("definition");p= def_ref;
+}break;
+case matching:{print_str("argument");p= temp_head;
+}break;
+case aligning:{print_str("preamble");p= hold_head;
+}break;
+case absorbing:{print_str("text");p= def_ref;
+}
+}
+print_char('?');print_ln();show_token_list(link(p),null,error_line-10);
+}
+}
+
+/*:306*/
+#line 2634 "tex.w"
+
+
+/*:119*//*120:*/
+#line 2645 "tex.w"
+pointer get_avail(void)
+{pointer p;
+p= avail;
+if(p!=null)avail= link(avail);
+else if(mem_end<mem_max)
+{incr(mem_end);p= mem_end;
+}
+else{decr(hi_mem_min);p= hi_mem_min;
+if(hi_mem_min<=lo_mem_max)
+{runaway();
+overflow("main memory size",mem_max+1-mem_min);
+
+
+}
+}
+link(p)= null;
+incr_dyn_used;
+return p;
+}
+
+/*:120*//*123:*/
+#line 2691 "tex.w"
+void flush_list(pointer p)
+
+{pointer q,r;
+if(p!=null)
+{r= p;
+do{q= r;r= link(r);
+decr_dyn_used;
+}while(!(r==null));
+link(q)= avail;avail= p;
+}
+}
+
+/*:123*//*125:*/
+#line 2736 "tex.w"
+pointer get_node(int s)
+{
+pointer p;
+pointer q;
+int r;
+int t;
+restart:p= rover;
+do{/*127:*/
+#line 2786 "tex.w"
+
+q= p+node_size(p);
+
+while(is_empty(q))
+{t= rlink(q);
+if(q==rover)rover= t;
+llink(t)= llink(q);rlink(llink(q))= t;
+q= q+node_size(q);
+}
+r= q-s;
+if(r> p+1)/*128:*/
+#line 2801 "tex.w"
+
+{node_size(p)= r-p;
+
+rover= p;
+goto found;
+}
+
+/*:128*/
+#line 2796 "tex.w"
+;
+if(r==p)if(rlink(p)!=p)
+/*129:*/
+#line 2810 "tex.w"
+
+{rover= rlink(p);t= llink(p);
+llink(rover)= t;rlink(t)= rover;
+goto found;
+}
+
+/*:129*/
+#line 2798 "tex.w"
+;
+node_size(p)= q-p
+
+/*:127*/
+#line 2744 "tex.w"
+;
+
+p= rlink(p);
+}while(!(p==rover));
+if(s==010000000000)
+{return max_halfword;
+}
+if(lo_mem_max+2<hi_mem_min)if(lo_mem_max+2<=mem_bot+max_halfword)
+/*126:*/
+#line 2771 "tex.w"
+
+{if(hi_mem_min-lo_mem_max>=1998)t= lo_mem_max+1000;
+else t= lo_mem_max+1+(hi_mem_min-lo_mem_max)/2;
+
+p= llink(rover);q= lo_mem_max;rlink(p)= q;llink(rover)= q;
+if(t> mem_bot+max_halfword)t= mem_bot+max_halfword;
+rlink(q)= rover;llink(q)= p;link(q)= empty_flag;node_size(q)= t-lo_mem_max;
+lo_mem_max= t;link(lo_mem_max)= null;info(lo_mem_max)= null;
+rover= q;goto restart;
+}
+
+/*:126*/
+#line 2752 "tex.w"
+;
+overflow("main memory size",mem_max+1-mem_min);
+
+
+found:link(r)= null;
+#ifdef STAT
+var_used= var_used+s;
+#endif
+
+return r;
+}
+
+/*:125*//*130:*/
+#line 2821 "tex.w"
+void free_node(pointer p,halfword s)
+
+{pointer q;
+node_size(p)= s;link(p)= empty_flag;
+q= llink(rover);llink(p)= q;rlink(p)= rover;
+llink(rover)= p;rlink(q)= p;
+#ifdef STAT
+var_used= var_used-s;
+#endif
+
+}
+
+/*:130*//*131:*/
+#line 2838 "tex.w"
+
+#ifdef INIT
+void sort_avail(void)
+
+{pointer p,q,r;
+pointer old_rover;
+p= get_node(010000000000);
+p= rlink(rover);rlink(rover)= max_halfword;old_rover= rover;
+while(p!=old_rover)/*132:*/
+#line 2860 "tex.w"
+
+if(p<rover)
+{q= p;p= rlink(q);rlink(q)= rover;rover= q;
+}
+else{q= rover;
+while(rlink(q)<p)q= rlink(q);
+r= rlink(p);rlink(p)= rlink(q);rlink(q)= p;p= r;
+}
+
+/*:132*/
+#line 2847 "tex.w"
+;
+p= rover;
+while(rlink(p)!=max_halfword)
+{llink(rlink(p))= p;p= rlink(p);
+}
+rlink(p)= rover;llink(rover)= p;
+}
+#endif
+
+/*:131*//*136:*/
+#line 2969 "tex.w"
+pointer new_null_box(void)
+{pointer p;
+p= get_node(box_node_size);type(p)= hlist_node;
+subtype(p)= min_quarterword;
+width(p)= 0;depth(p)= 0;height(p)= 0;shift_amount(p)= 0;list_ptr(p)= null;
+glue_sign(p)= normal;glue_order(p)= normal;set_glue_ratio_zero(glue_set(p));
+return p;
+}
+
+/*:136*//*139:*/
+#line 2999 "tex.w"
+pointer new_rule(void)
+{pointer p;
+p= get_node(rule_node_size);type(p)= rule_node;
+subtype(p)= 0;
+width(p)= null_flag;depth(p)= null_flag;height(p)= null_flag;
+return p;
+}
+
+/*:139*//*144:*/
+#line 3068 "tex.w"
+pointer new_ligature(quarterword f,quarterword c,pointer q)
+{pointer p;
+p= get_node(small_node_size);type(p)= ligature_node;
+font(lig_char(p))= f;character(lig_char(p))= c;lig_ptr(p)= q;
+subtype(p)= 0;return p;
+}
+
+pointer new_lig_item(quarterword c)
+{pointer p;
+p= get_node(small_node_size);character(p)= c;lig_ptr(p)= null;
+return p;
+}
+
+/*:144*//*145:*/
+#line 3103 "tex.w"
+pointer new_disc(void)
+{pointer p;
+p= get_node(small_node_size);type(p)= disc_node;
+replace_count(p)= 0;pre_break(p)= null;post_break(p)= null;
+return p;
+}
+
+/*:145*//*147:*/
+#line 3137 "tex.w"
+pointer new_math(scaled w,small_number s)
+{pointer p;
+p= get_node(small_node_size);type(p)= math_node;
+subtype(p)= s;width(p)= w;return p;
+}
+
+/*:147*//*151:*/
+#line 3219 "tex.w"
+pointer new_spec(pointer p)
+{pointer q;
+q= get_node(glue_spec_size);
+mem[q]= mem[p];glue_ref_count(q)= null;
+width(q)= width(p);stretch(q)= stretch(p);shrink(q)= shrink(p);
+return q;
+}
+
+/*:151*//*152:*/
+#line 3232 "tex.w"
+pointer new_param_glue(small_number n)
+{pointer p;
+pointer q;
+p= get_node(small_node_size);type(p)= glue_node;subtype(p)= n+1;
+leader_ptr(p)= null;
+q= /*224:*/
+#line 4665 "tex.w"
+glue_par(n)
+
+/*:224*/
+#line 3237 "tex.w"
+;
+glue_ptr(p)= q;incr(glue_ref_count(q));
+return p;
+}
+
+/*:152*//*153:*/
+#line 3245 "tex.w"
+pointer new_glue(pointer q)
+{pointer p;
+p= get_node(small_node_size);type(p)= glue_node;subtype(p)= normal;
+leader_ptr(p)= null;glue_ptr(p)= q;incr(glue_ref_count(q));
+return p;
+}
+
+/*:153*//*154:*/
+#line 3259 "tex.w"
+pointer new_skip_param(small_number n)
+{pointer p;
+temp_ptr= new_spec(/*224:*/
+#line 4665 "tex.w"
+glue_par(n)
+
+/*:224*/
+#line 3261 "tex.w"
+);
+p= new_glue(temp_ptr);glue_ref_count(temp_ptr)= null;subtype(p)= n+1;
+return p;
+}
+
+/*:154*//*156:*/
+#line 3283 "tex.w"
+pointer new_kern(scaled w)
+{pointer p;
+p= get_node(small_node_size);type(p)= kern_node;
+subtype(p)= normal;
+width(p)= w;
+return p;
+}
+
+/*:156*//*158:*/
+#line 3306 "tex.w"
+pointer new_penalty(int m)
+{pointer p;
+p= get_node(small_node_size);type(p)= penalty_node;
+subtype(p)= 0;
+penalty(p)= m;return p;
+}
+
+/*:158*//*167:*/
+#line 3449 "tex.w"
+
+#ifdef DEBUG
+void check_mem(bool print_locs)
+{
+pointer p,q;
+bool clobbered;
+for(p= mem_min;p<=lo_mem_max;p++)is_free[p]= false;
+
+for(p= hi_mem_min;p<=mem_end;p++)is_free[p]= false;
+/*168:*/
+#line 3469 "tex.w"
+
+p= avail;q= null;clobbered= false;
+while(p!=null)
+{if((p> mem_end)||(p<hi_mem_min))clobbered= true;
+else if(is_free[p])clobbered= true;
+if(clobbered)
+{print_nl("AVAIL list clobbered at ");
+
+print_int(q);goto done1;
+}
+is_free[p]= true;q= p;p= link(q);
+}
+done1:
+
+/*:168*/
+#line 3458 "tex.w"
+;
+/*169:*/
+#line 3483 "tex.w"
+
+p= rover;q= null;clobbered= false;
+do{if((p>=lo_mem_max)||(p<mem_min))clobbered= true;
+else if((rlink(p)>=lo_mem_max)||(rlink(p)<mem_min))clobbered= true;
+else if(!(is_empty(p))||(node_size(p)<2)||
+(p+node_size(p)> lo_mem_max)||(llink(rlink(p))!=p))clobbered= true;
+if(clobbered)
+{print_nl("Double-AVAIL list clobbered at ");
+print_int(q);goto done2;
+}
+for(q= p;q<=p+node_size(p)-1;q++)
+{if(is_free[q])
+{print_nl("Doubly free location at ");
+
+print_int(q);goto done2;
+}
+is_free[q]= true;
+}
+q= p;p= rlink(p);
+}while(!(p==rover));
+done2:
+
+/*:169*/
+#line 3459 "tex.w"
+;
+/*170:*/
+#line 3505 "tex.w"
+
+p= mem_min;
+while(p<=lo_mem_max)
+{if(is_empty(p))
+{print_nl("Bad flag at ");print_int(p);
+
+}
+while((p<=lo_mem_max)&&!is_free[p])incr(p);
+while((p<=lo_mem_max)&&is_free[p])incr(p);
+}
+
+/*:170*/
+#line 3460 "tex.w"
+;
+if(print_locs)/*171:*/
+#line 3516 "tex.w"
+
+{print_nl("New busy locs:");
+for(p= mem_min;p<=lo_mem_max;p++)
+if(!is_free[p]&&((p> was_lo_max)||was_free[p]))
+{print_char(' ');print_int(p);
+}
+for(p= hi_mem_min;p<=mem_end;p++)
+if(!is_free[p]&&
+((p<was_hi_min)||(p> was_mem_end)||was_free[p]))
+{print_char(' ');print_int(p);
+}
+}
+
+/*:171*/
+#line 3461 "tex.w"
+;
+for(p= mem_min;p<=lo_mem_max;p++)was_free[p]= is_free[p];
+for(p= hi_mem_min;p<=mem_end;p++)was_free[p]= is_free[p];
+
+was_mem_end= mem_end;was_lo_max= lo_mem_max;was_hi_min= hi_mem_min;
+}
+#endif
+
+/*:167*//*172:*/
+#line 3538 "tex.w"
+
+#ifdef DEBUG
+void search_mem(pointer p)
+{int q;
+for(q= mem_min;q<=lo_mem_max;q++)
+{if(link(q)==p)
+{print_nl("LINK(");print_int(q);print_char(')');
+}
+if(info(q)==p)
+{print_nl("INFO(");print_int(q);print_char(')');
+}
+}
+for(q= hi_mem_min;q<=mem_end;q++)
+{if(link(q)==p)
+{print_nl("LINK(");print_int(q);print_char(')');
+}
+if(info(q)==p)
+{print_nl("INFO(");print_int(q);print_char(')');
+}
+}
+/*255:*/
+#line 5513 "tex.w"
+
+for(q= active_base;q<=box_base+255;q++)
+{if(equiv(q)==p)
+{print_nl("EQUIV(");print_int(q);print_char(')');
+}
+}
+
+/*:255*/
+#line 3558 "tex.w"
+;
+/*285:*/
+#line 6172 "tex.w"
+
+if(save_ptr> 0)for(q= 0;q<=save_ptr-1;q++)
+{if(equiv_field(save_stack[q])==p)
+{print_nl("SAVE(");print_int(q);print_char(')');
+}
+}
+
+/*:285*/
+#line 3559 "tex.w"
+;
+/*933:*/
+#line 18262 "tex.w"
+
+for(q= 0;q<=hyph_size;q++)
+{if(hyph_list[q]==p)
+{print_nl("HYPH(");print_int(q);print_char(')');
+}
+}
+
+/*:933*/
+#line 3560 "tex.w"
+;
+}
+#endif
+
+/*:172*//*174:*/
+#line 3588 "tex.w"
+void short_display(int p)
+{int n;
+while(p> mem_min)
+{if(is_char_node(p))
+{if(p<=mem_end)
+{if(font(p)!=font_in_short_display)
+{if((font(p)<font_base)||(font(p)> font_max))
+print_char('*');
+
+else/*267:*/
+#line 5855 "tex.w"
+
+print_esc(font_id_text(font(p)))
+
+/*:267*/
+#line 3597 "tex.w"
+;
+print_char(' ');font_in_short_display= font(p);
+}
+print_ASCII(qo(character(p)));
+}
+}
+else/*175:*/
+#line 3608 "tex.w"
+
+switch(type(p)){
+case hlist_node:case vlist_node:case ins_node:case whatsit_node:case mark_node:case adjust_node:
+case unset_node:print_str("[]");break;
+case rule_node:print_char('|');break;
+case glue_node:if(glue_ptr(p)!=zero_glue)print_char(' ');break;
+case math_node:print_char('$');break;
+case ligature_node:short_display(lig_ptr(p));break;
+case disc_node:{short_display(pre_break(p));
+short_display(post_break(p));
+n= replace_count(p);
+while(n> 0)
+{if(link(p)!=null)p= link(p);
+decr(n);
+}
+}break;
+default:do_nothing;
+}
+
+/*:175*/
+#line 3603 "tex.w"
+;
+p= link(p);
+}
+}
+
+/*:174*//*176:*/
+#line 3631 "tex.w"
+void print_font_and_char(int p)
+{if(p> mem_end)print_esc(/*1386:*/
+#line 25054 "tex.w"
+261
+/*:1386*/
+#line 3632 "tex.w"
+);
+else{if((font(p)<font_base)||(font(p)> font_max))print_char('*');
+
+else/*267:*/
+#line 5855 "tex.w"
+
+print_esc(font_id_text(font(p)))
+
+/*:267*/
+#line 3635 "tex.w"
+;
+print_char(' ');print_ASCII(qo(character(p)));
+}
+}
+
+void print_mark(int p)
+{print_char('{');
+if((p<hi_mem_min)||(p> mem_end))print_esc(/*1386:*/
+#line 25054 "tex.w"
+261
+/*:1386*/
+#line 3642 "tex.w"
+);
+else show_token_list(link(p),null,max_print_line-10);
+print_char('}');
+}
+
+void print_rule_dimen(scaled d)
+{if(is_running(d))print_char('*');else print_scaled(d);
+
+}
+
+/*:176*//*177:*/
+#line 3655 "tex.w"
+void print_glue(scaled d,int order,str_number s)
+
+{print_scaled(d);
+if((order<normal)||(order> filll))print_str("foul");
+else if(order> normal)
+{print_str("fil");
+while(order> fil)
+{print_char('l');decr(order);
+}
+}
+else if(s!=0)print(s);
+}
+
+/*:177*//*178:*/
+#line 3670 "tex.w"
+void print_spec(int p,str_number s)
+
+{if((p<mem_min)||(p>=lo_mem_max))print_char('*');
+
+else{print_scaled(width(p));
+if(s!=0)print(s);
+if(stretch(p)!=0)
+{print_str(" plus ");print_glue(stretch(p),stretch_order(p),s);
+}
+if(shrink(p)!=0)
+{print_str(" minus ");print_glue(shrink(p),shrink_order(p),s);
+}
+}
+}
+
+/*:178*//*179:*/
+#line 3688 "tex.w"
+/*691:*/
+#line 13645 "tex.w"
+
+void print_fam_and_char(pointer p)
+{print_esc(/*1490:*/
+#line 25366 "tex.w"
+365
+/*:1490*/
+#line 13647 "tex.w"
+);print_int(fam(p));print_char(' ');
+print_ASCII(qo(character(p)));
+}
+
+void print_delimiter(pointer p)
+{int a;
+a= small_fam(p)*256+qo(small_char(p));
+a= a*0x1000+large_fam(p)*256+qo(large_char(p));
+if(a<0)print_int(a);
+else print_hex(a);
+}
+
+/*:691*//*692:*/
+#line 13666 "tex.w"
+
+void show_info(void);
+void print_subsidiary_data(pointer p,ASCII_code c)
+
+{if(cur_length>=depth_threshold)
+{if(math_type(p)!=empty)print_str(" []");
+}
+else{append_char(c);
+temp_ptr= p;
+switch(math_type(p)){
+case math_char:{print_ln();print_current_string();print_fam_and_char(p);
+}break;
+case sub_box:show_info();break;
+case sub_mlist:if(info(p)==null)
+{print_ln();print_current_string();print_str("{}");
+}
+else show_info();break;
+default:do_nothing;
+}
+flush_char;
+}
+}
+
+/*:692*//*694:*/
+#line 13703 "tex.w"
+
+void print_style(int c)
+{switch(c/2){
+case 0:print_esc(/*1645:*/
+#line 25831 "tex.w"
+520
+/*:1645*/
+#line 13706 "tex.w"
+);break;
+case 1:print_esc(/*1646:*/
+#line 25834 "tex.w"
+521
+/*:1646*/
+#line 13707 "tex.w"
+);break;
+case 2:print_esc(/*1647:*/
+#line 25837 "tex.w"
+522
+/*:1647*/
+#line 13708 "tex.w"
+);break;
+case 3:print_esc(/*1648:*/
+#line 25840 "tex.w"
+523
+/*:1648*/
+#line 13709 "tex.w"
+);break;
+default:print_str("Unknown style!");
+}
+}
+
+/*:694*/
+#line 3688 "tex.w"
+
+/*225:*/
+#line 4671 "tex.w"
+
+void print_skip_param(int n)
+{switch(n){
+case line_skip_code:print_esc(/*1405:*/
+#line 25111 "tex.w"
+280
+/*:1405*/
+#line 4674 "tex.w"
+);break;
+case baseline_skip_code:print_esc(/*1406:*/
+#line 25114 "tex.w"
+281
+/*:1406*/
+#line 4675 "tex.w"
+);break;
+case par_skip_code:print_esc(/*1407:*/
+#line 25117 "tex.w"
+282
+/*:1407*/
+#line 4676 "tex.w"
+);break;
+case above_display_skip_code:print_esc(/*1408:*/
+#line 25120 "tex.w"
+283
+/*:1408*/
+#line 4677 "tex.w"
+);break;
+case below_display_skip_code:print_esc(/*1409:*/
+#line 25123 "tex.w"
+284
+/*:1409*/
+#line 4678 "tex.w"
+);break;
+case above_display_short_skip_code:print_esc(/*1410:*/
+#line 25126 "tex.w"
+285
+/*:1410*/
+#line 4679 "tex.w"
+);break;
+case below_display_short_skip_code:print_esc(/*1411:*/
+#line 25129 "tex.w"
+286
+/*:1411*/
+#line 4680 "tex.w"
+);break;
+case left_skip_code:print_esc(/*1412:*/
+#line 25132 "tex.w"
+287
+/*:1412*/
+#line 4681 "tex.w"
+);break;
+case right_skip_code:print_esc(/*1413:*/
+#line 25135 "tex.w"
+288
+/*:1413*/
+#line 4682 "tex.w"
+);break;
+case top_skip_code:print_esc(/*1414:*/
+#line 25138 "tex.w"
+289
+/*:1414*/
+#line 4683 "tex.w"
+);break;
+case split_top_skip_code:print_esc(/*1415:*/
+#line 25141 "tex.w"
+290
+/*:1415*/
+#line 4684 "tex.w"
+);break;
+case tab_skip_code:print_esc(/*1416:*/
+#line 25144 "tex.w"
+291
+/*:1416*/
+#line 4685 "tex.w"
+);break;
+case space_skip_code:print_esc(/*1417:*/
+#line 25147 "tex.w"
+292
+/*:1417*/
+#line 4686 "tex.w"
+);break;
+case xspace_skip_code:print_esc(/*1418:*/
+#line 25150 "tex.w"
+293
+/*:1418*/
+#line 4687 "tex.w"
+);break;
+case par_fill_skip_code:print_esc(/*1419:*/
+#line 25153 "tex.w"
+294
+/*:1419*/
+#line 4688 "tex.w"
+);break;
+case thin_mu_skip_code:print_esc(/*1420:*/
+#line 25156 "tex.w"
+295
+/*:1420*/
+#line 4689 "tex.w"
+);break;
+case med_mu_skip_code:print_esc(/*1421:*/
+#line 25159 "tex.w"
+296
+/*:1421*/
+#line 4690 "tex.w"
+);break;
+case thick_mu_skip_code:print_esc(/*1422:*/
+#line 25162 "tex.w"
+297
+/*:1422*/
+#line 4691 "tex.w"
+);break;
+default:print_str("[unknown glue parameter!]");
+}
+}
+
+/*:225*/
+#line 3689 "tex.w"
+
+
+/*:179*//*182:*/
+#line 3726 "tex.w"
+void show_node_list(int p)
+{
+int n;
+double g;
+if(cur_length> depth_threshold)
+{if(p> null)print_str(" []");
+
+return;
+}
+n= 0;
+while(p> mem_min)
+{print_ln();print_current_string();
+if(p> mem_end)
+{print_str("Bad link, display aborted.");return;
+
+}
+incr(n);if(n> breadth_max)
+{print_str("etc.");return;
+
+}
+/*183:*/
+#line 3752 "tex.w"
+
+if(is_char_node(p))print_font_and_char(p);
+else switch(type(p)){
+case hlist_node:case vlist_node:case unset_node:/*184:*/
+#line 3771 "tex.w"
+
+{if(type(p)==hlist_node)print_esc('h');
+else if(type(p)==vlist_node)print_esc('v');
+else print_esc(/*1388:*/
+#line 25060 "tex.w"
+263
+/*:1388*/
+#line 3774 "tex.w"
+);
+print_str("box(");print_scaled(height(p));print_char('+');
+print_scaled(depth(p));print_str(")x");print_scaled(width(p));
+if(type(p)==unset_node)
+/*185:*/
+#line 3787 "tex.w"
+
+{if(span_count(p)!=min_quarterword)
+{print_str(" (");print_int(qo(span_count(p))+1);
+print_str(" columns)");
+}
+if(glue_stretch(p)!=0)
+{print_str(", stretch ");print_glue(glue_stretch(p),glue_order(p),0);
+}
+if(glue_shrink(p)!=0)
+{print_str(", shrink ");print_glue(glue_shrink(p),glue_sign(p),0);
+}
+}
+
+/*:185*/
+#line 3778 "tex.w"
+
+else{/*186:*/
+#line 3810 "tex.w"
+
+g= float(glue_set(p));
+if((g!=float_constant(0))&&(glue_sign(p)!=normal))
+{print_str(", glue set ");
+if(glue_sign(p)==shrinking)print_str("- ");
+if(abs(mem[p+glue_offset].i)<04000000)print_str("?.?");
+else if(abs(g)> float_constant(20000))
+{if(g> float_constant(0))print_char('>');
+else print_str("< -");
+print_glue(20000*unity,glue_order(p),0);
+}
+else print_glue(round(unity*g),glue_order(p),0);
+
+}
+
+/*:186*/
+#line 3779 "tex.w"
+;
+if(shift_amount(p)!=0)
+{print_str(", shifted ");print_scaled(shift_amount(p));
+}
+}
+node_list_display(list_ptr(p));
+}
+
+/*:184*/
+#line 3755 "tex.w"
+break;
+case rule_node:/*187:*/
+#line 3825 "tex.w"
+
+{print_esc(/*1389:*/
+#line 25063 "tex.w"
+264
+/*:1389*/
+#line 3826 "tex.w"
+);print_rule_dimen(height(p));print_char('+');
+print_rule_dimen(depth(p));print_str(")x");print_rule_dimen(width(p));
+}
+
+/*:187*/
+#line 3756 "tex.w"
+break;
+case ins_node:/*188:*/
+#line 3830 "tex.w"
+
+{print_esc(/*1390:*/
+#line 25066 "tex.w"
+265
+/*:1390*/
+#line 3831 "tex.w"
+);print_int(qo(subtype(p)));
+print_str(", natural size ");print_scaled(height(p));
+print_str("; split(");print_spec(split_top_ptr(p),0);
+print_char(',');print_scaled(depth(p));
+print_str("); float cost ");print_int(float_cost(p));
+node_list_display(ins_ptr(p));
+}
+
+/*:188*/
+#line 3757 "tex.w"
+break;
+case whatsit_node:/*1356:*/
+#line 24746 "tex.w"
+
+switch(subtype(p)){
+case open_node:{print_write_whatsit(/*1783:*/
+#line 26245 "tex.w"
+658
+/*:1783*/
+#line 24748 "tex.w"
+,p);
+print_char('=');print_file_name(open_name(p),open_area(p),open_ext(p));
+}break;
+case write_node:{print_write_whatsit(/*1568:*/
+#line 25600 "tex.w"
+443
+/*:1568*/
+#line 24751 "tex.w"
+,p);
+print_mark(write_tokens(p));
+}break;
+case close_node:print_write_whatsit(/*1784:*/
+#line 26248 "tex.w"
+659
+/*:1784*/
+#line 24754 "tex.w"
+,p);break;
+case special_node:{print_esc(/*1785:*/
+#line 26251 "tex.w"
+660
+/*:1785*/
+#line 24755 "tex.w"
+);
+print_mark(write_tokens(p));
+}break;
+case language_node:{print_esc(/*1787:*/
+#line 26257 "tex.w"
+662
+/*:1787*/
+#line 24758 "tex.w"
+);
+print_int(what_lang(p));print_str(" (hyphenmin ");
+print_int(what_lhm(p));print_char(',');
+print_int(what_rhm(p));print_char(')');
+}break;
+default:print_str("whatsit?");
+}
+
+/*:1356*/
+#line 3758 "tex.w"
+break;
+case glue_node:/*189:*/
+#line 3839 "tex.w"
+
+if(subtype(p)>=a_leaders)/*190:*/
+#line 3857 "tex.w"
+
+{print_esc(empty_string);
+if(subtype(p)==c_leaders)print_char('c');
+else if(subtype(p)==x_leaders)print_char('x');
+print_str("leaders ");print_spec(glue_ptr(p),0);
+node_list_display(leader_ptr(p));
+}
+
+/*:190*/
+#line 3840 "tex.w"
+
+else{print_esc(/*1391:*/
+#line 25069 "tex.w"
+266
+/*:1391*/
+#line 3841 "tex.w"
+);
+if(subtype(p)!=normal)
+{print_char('(');
+if(subtype(p)<cond_math_glue)
+print_skip_param(subtype(p)-1);
+else if(subtype(p)==cond_math_glue)print_esc(/*1392:*/
+#line 25072 "tex.w"
+267
+/*:1392*/
+#line 3846 "tex.w"
+);
+else print_esc(/*1393:*/
+#line 25075 "tex.w"
+268
+/*:1393*/
+#line 3847 "tex.w"
+);
+print_char(')');
+}
+if(subtype(p)!=cond_math_glue)
+{print_char(' ');
+if(subtype(p)<cond_math_glue)print_spec(glue_ptr(p),0);
+else print_spec(glue_ptr(p),/*1394:*/
+#line 25078 "tex.w"
+269
+/*:1394*/
+#line 3853 "tex.w"
+);
+}
+}
+
+/*:189*/
+#line 3759 "tex.w"
+break;
+case kern_node:/*191:*/
+#line 3867 "tex.w"
+
+if(subtype(p)!=mu_glue)
+{print_esc(/*1396:*/
+#line 25084 "tex.w"
+271
+/*:1396*/
+#line 3869 "tex.w"
+);
+if(subtype(p)!=normal)print_char(' ');
+print_scaled(width(p));
+if(subtype(p)==acc_kern)print_str(" (for accent)");
+
+}
+else{print_esc(/*1397:*/
+#line 25087 "tex.w"
+272
+/*:1397*/
+#line 3875 "tex.w"
+);print_scaled(width(p));print_str("mu");
+}
+
+/*:191*/
+#line 3760 "tex.w"
+break;
+case math_node:/*192:*/
+#line 3878 "tex.w"
+
+{print_esc(/*1398:*/
+#line 25090 "tex.w"
+273
+/*:1398*/
+#line 3879 "tex.w"
+);
+if(subtype(p)==before)print_str("on");
+else print_str("off");
+if(width(p)!=0)
+{print_str(", surrounded ");print_scaled(width(p));
+}
+}
+
+/*:192*/
+#line 3761 "tex.w"
+break;
+case ligature_node:/*193:*/
+#line 3887 "tex.w"
+
+{print_font_and_char(lig_char(p));print_str(" (ligature ");
+if(subtype(p)> 1)print_char('|');
+font_in_short_display= font(lig_char(p));short_display(lig_ptr(p));
+if(odd(subtype(p)))print_char('|');
+print_char(')');
+}
+
+/*:193*/
+#line 3762 "tex.w"
+break;
+case penalty_node:/*194:*/
+#line 3895 "tex.w"
+
+{print_esc(/*1399:*/
+#line 25093 "tex.w"
+274
+/*:1399*/
+#line 3896 "tex.w"
+);print_int(penalty(p));
+}
+
+/*:194*/
+#line 3763 "tex.w"
+break;
+case disc_node:/*195:*/
+#line 3902 "tex.w"
+
+{print_esc(/*1400:*/
+#line 25096 "tex.w"
+275
+/*:1400*/
+#line 3903 "tex.w"
+);
+if(replace_count(p)> 0)
+{print_str(" replacing ");print_int(replace_count(p));
+}
+node_list_display(pre_break(p));
+append_char('|');show_node_list(post_break(p));flush_char;
+}
+
+/*:195*/
+#line 3764 "tex.w"
+break;
+case mark_node:/*196:*/
+#line 3911 "tex.w"
+
+{print_esc(/*1401:*/
+#line 25099 "tex.w"
+276
+/*:1401*/
+#line 3912 "tex.w"
+);print_mark(mark_ptr(p));
+}
+
+/*:196*/
+#line 3765 "tex.w"
+break;
+case adjust_node:/*197:*/
+#line 3915 "tex.w"
+
+{print_esc(/*1402:*/
+#line 25102 "tex.w"
+277
+/*:1402*/
+#line 3916 "tex.w"
+);node_list_display(adjust_ptr(p));
+}
+
+/*:197*/
+#line 3766 "tex.w"
+break;
+/*690:*/
+#line 13635 "tex.w"
+
+case style_node:print_style(subtype(p));break;
+case choice_node:/*695:*/
+#line 13714 "tex.w"
+
+{print_esc(/*1547:*/
+#line 25537 "tex.w"
+422
+/*:1547*/
+#line 13715 "tex.w"
+);
+append_char('D');show_node_list(display_mlist(p));flush_char;
+append_char('T');show_node_list(text_mlist(p));flush_char;
+append_char('S');show_node_list(script_mlist(p));flush_char;
+append_char('s');show_node_list(script_script_mlist(p));flush_char;
+}
+
+/*:695*/
+#line 13637 "tex.w"
+break;
+case ord_noad:case op_noad:case bin_noad:case rel_noad:case open_noad:case close_noad:case punct_noad:case inner_noad:
+case radical_noad:case over_noad:case under_noad:case vcenter_noad:case accent_noad:
+case left_noad:case right_noad:/*696:*/
+#line 13722 "tex.w"
+
+{switch(type(p)){
+case ord_noad:print_esc(/*1649:*/
+#line 25843 "tex.w"
+524
+/*:1649*/
+#line 13724 "tex.w"
+);break;
+case op_noad:print_esc(/*1650:*/
+#line 25846 "tex.w"
+525
+/*:1650*/
+#line 13725 "tex.w"
+);break;
+case bin_noad:print_esc(/*1651:*/
+#line 25849 "tex.w"
+526
+/*:1651*/
+#line 13726 "tex.w"
+);break;
+case rel_noad:print_esc(/*1652:*/
+#line 25852 "tex.w"
+527
+/*:1652*/
+#line 13727 "tex.w"
+);break;
+case open_noad:print_esc(/*1653:*/
+#line 25855 "tex.w"
+528
+/*:1653*/
+#line 13728 "tex.w"
+);break;
+case close_noad:print_esc(/*1654:*/
+#line 25858 "tex.w"
+529
+/*:1654*/
+#line 13729 "tex.w"
+);break;
+case punct_noad:print_esc(/*1655:*/
+#line 25861 "tex.w"
+530
+/*:1655*/
+#line 13730 "tex.w"
+);break;
+case inner_noad:print_esc(/*1656:*/
+#line 25864 "tex.w"
+531
+/*:1656*/
+#line 13731 "tex.w"
+);break;
+case over_noad:print_esc(/*1657:*/
+#line 25867 "tex.w"
+532
+/*:1657*/
+#line 13732 "tex.w"
+);break;
+case under_noad:print_esc(/*1658:*/
+#line 25870 "tex.w"
+533
+/*:1658*/
+#line 13733 "tex.w"
+);break;
+case vcenter_noad:print_esc(/*1561:*/
+#line 25579 "tex.w"
+436
+/*:1561*/
+#line 13734 "tex.w"
+);break;
+case radical_noad:{print_esc(/*1555:*/
+#line 25561 "tex.w"
+430
+/*:1555*/
+#line 13735 "tex.w"
+);print_delimiter(left_delimiter(p));
+}break;
+case accent_noad:{print_esc(/*1530:*/
+#line 25486 "tex.w"
+405
+/*:1530*/
+#line 13737 "tex.w"
+);print_fam_and_char(accent_chr(p));
+}break;
+case left_noad:{print_esc(/*1659:*/
+#line 25873 "tex.w"
+534
+/*:1659*/
+#line 13739 "tex.w"
+);print_delimiter(delimiter(p));
+}break;
+case right_noad:{print_esc(/*1660:*/
+#line 25876 "tex.w"
+535
+/*:1660*/
+#line 13741 "tex.w"
+);print_delimiter(delimiter(p));
+}
+}
+if(subtype(p)!=normal)
+if(subtype(p)==limits)print_esc(/*1661:*/
+#line 25879 "tex.w"
+536
+/*:1661*/
+#line 13745 "tex.w"
+);
+else print_esc(/*1662:*/
+#line 25882 "tex.w"
+537
+/*:1662*/
+#line 13746 "tex.w"
+);
+if(type(p)<left_noad)print_subsidiary_data(nucleus(p),'.');
+print_subsidiary_data(supscr(p),'^');
+print_subsidiary_data(subscr(p),'_');
+}
+
+/*:696*/
+#line 13640 "tex.w"
+break;
+case fraction_noad:/*697:*/
+#line 13752 "tex.w"
+
+{print_esc(/*1663:*/
+#line 25885 "tex.w"
+538
+/*:1663*/
+#line 13753 "tex.w"
+);
+if(thickness(p)==default_code)print_str("= default");
+else print_scaled(thickness(p));
+if((small_fam(left_delimiter(p))!=0)||
+(small_char(left_delimiter(p))!=min_quarterword)||
+(large_fam(left_delimiter(p))!=0)||
+(large_char(left_delimiter(p))!=min_quarterword))
+{print_str(", left-delimiter ");print_delimiter(left_delimiter(p));
+}
+if((small_fam(right_delimiter(p))!=0)||
+(small_char(right_delimiter(p))!=min_quarterword)||
+(large_fam(right_delimiter(p))!=0)||
+(large_char(right_delimiter(p))!=min_quarterword))
+{print_str(", right-delimiter ");print_delimiter(right_delimiter(p));
+}
+print_subsidiary_data(numerator(p),'\\');
+print_subsidiary_data(denominator(p),'/');
+}
+
+/*:697*/
+#line 13641 "tex.w"
+break;
+
+/*:690*/
+#line 3767 "tex.w"
+
+default:print_str("Unknown node type!");
+}
+
+/*:183*/
+#line 3746 "tex.w"
+;
+p= link(p);
+}
+
+}
+
+/*:182*//*198:*/
+#line 3922 "tex.w"
+void show_box(pointer p)
+{/*236:*/
+#line 5085 "tex.w"
+
+depth_threshold= show_box_depth;
+breadth_max= show_box_breadth
+
+/*:236*/
+#line 3923 "tex.w"
+;
+if(breadth_max<=0)breadth_max= 5;
+if(pool_ptr+depth_threshold>=pool_size)
+depth_threshold= pool_size-pool_ptr-1;
+
+show_node_list(p);
+print_ln();
+}
+
+/*:198*//*200:*/
+#line 3946 "tex.w"
+void delete_token_ref(pointer p)
+
+{if(token_ref_count(p)==null)flush_list(p);
+else decr(token_ref_count(p));
+}
+
+/*:200*//*201:*/
+#line 3960 "tex.w"
+void delete_glue_ref(pointer p)
+fast_delete_glue_ref(p)
+
+/*:201*//*202:*/
+#line 3968 "tex.w"
+void flush_node_list(pointer p)
+{
+pointer q;
+while(p!=null)
+
+{q= link(p);
+if(is_char_node(p))free_avail(p)
+else{switch(type(p)){
+case hlist_node:case vlist_node:case unset_node:{flush_node_list(list_ptr(p));
+free_node(p,box_node_size);goto done;
+}
+case rule_node:{free_node(p,rule_node_size);goto done;
+}
+case ins_node:{flush_node_list(ins_ptr(p));
+delete_glue_ref(split_top_ptr(p));
+free_node(p,ins_node_size);goto done;
+}
+case whatsit_node:/*1358:*/
+#line 24780 "tex.w"
+
+{switch(subtype(p)){
+case open_node:free_node(p,open_node_size);break;
+case write_node:case special_node:{delete_token_ref(write_tokens(p));
+free_node(p,write_node_size);goto done;
+}
+case close_node:case language_node:free_node(p,small_node_size);break;
+default:confusion(/*1790:*/
+#line 26266 "tex.w"
+665
+/*:1790*/
+#line 24787 "tex.w"
+);
+
+}
+goto done;
+}
+
+/*:1358*/
+#line 3985 "tex.w"
+
+case glue_node:{fast_delete_glue_ref(glue_ptr(p));
+if(leader_ptr(p)!=null)flush_node_list(leader_ptr(p));
+}break;
+case kern_node:case math_node:case penalty_node:do_nothing;break;
+case ligature_node:flush_node_list(lig_ptr(p));break;
+case mark_node:delete_token_ref(mark_ptr(p));break;
+case disc_node:{flush_node_list(pre_break(p));
+flush_node_list(post_break(p));
+}break;
+case adjust_node:flush_node_list(adjust_ptr(p));break;
+/*698:*/
+#line 13774 "tex.w"
+
+case style_node:{free_node(p,style_node_size);goto done;
+}
+case choice_node:{flush_node_list(display_mlist(p));
+flush_node_list(text_mlist(p));
+flush_node_list(script_mlist(p));
+flush_node_list(script_script_mlist(p));
+free_node(p,style_node_size);goto done;
+}
+case ord_noad:case op_noad:case bin_noad:case rel_noad:case open_noad:case close_noad:case punct_noad:case inner_noad:
+case radical_noad:case over_noad:case under_noad:case vcenter_noad:case accent_noad:
+{if(math_type(nucleus(p))>=sub_box)
+flush_node_list(info(nucleus(p)));
+if(math_type(supscr(p))>=sub_box)
+flush_node_list(info(supscr(p)));
+if(math_type(subscr(p))>=sub_box)
+flush_node_list(info(subscr(p)));
+if(type(p)==radical_noad)free_node(p,radical_noad_size);
+else if(type(p)==accent_noad)free_node(p,accent_noad_size);
+else free_node(p,noad_size);
+goto done;
+}
+case left_noad:case right_noad:{free_node(p,noad_size);goto done;
+}
+case fraction_noad:{flush_node_list(info(numerator(p)));
+flush_node_list(info(denominator(p)));
+free_node(p,fraction_noad_size);goto done;
+}
+
+/*:698*/
+#line 3996 "tex.w"
+
+default:confusion(/*1403:*/
+#line 25105 "tex.w"
+278
+/*:1403*/
+#line 3997 "tex.w"
+);
+
+}
+free_node(p,small_node_size);
+done:;}
+p= q;
+}
+}
+
+/*:202*//*204:*/
+#line 4030 "tex.w"
+pointer copy_node_list(pointer p)
+
+{pointer h;
+pointer q;
+pointer r;
+uint8_t words;
+h= get_avail();q= h;
+while(p!=null)
+{/*205:*/
+#line 4045 "tex.w"
+
+words= 1;
+if(is_char_node(p))r= get_avail();
+else/*206:*/
+#line 4054 "tex.w"
+
+switch(type(p)){
+case hlist_node:case vlist_node:case unset_node:{r= get_node(box_node_size);
+mem[r+6]= mem[p+6];mem[r+5]= mem[p+5];
+list_ptr(r)= copy_node_list(list_ptr(p));
+words= 5;
+}break;
+case rule_node:{r= get_node(rule_node_size);words= rule_node_size;
+}break;
+case ins_node:{r= get_node(ins_node_size);mem[r+4]= mem[p+4];
+add_glue_ref(split_top_ptr(p));
+ins_ptr(r)= copy_node_list(ins_ptr(p));
+words= ins_node_size-1;
+}break;
+case whatsit_node:/*1357:*/
+#line 24766 "tex.w"
+
+switch(subtype(p)){
+case open_node:{r= get_node(open_node_size);words= open_node_size;
+}break;
+case write_node:case special_node:{r= get_node(write_node_size);
+add_token_ref(write_tokens(p));words= write_node_size;
+}break;
+case close_node:case language_node:{r= get_node(small_node_size);
+words= small_node_size;
+}break;
+default:confusion(/*1789:*/
+#line 26263 "tex.w"
+664
+/*:1789*/
+#line 24776 "tex.w"
+);
+
+}
+
+/*:1357*/
+#line 4069 "tex.w"
+break;
+case glue_node:{r= get_node(small_node_size);add_glue_ref(glue_ptr(p));
+glue_ptr(r)= glue_ptr(p);leader_ptr(r)= copy_node_list(leader_ptr(p));
+}break;
+case kern_node:case math_node:case penalty_node:{r= get_node(small_node_size);
+words= small_node_size;
+}break;
+case ligature_node:{r= get_node(small_node_size);
+mem[lig_char(r)]= mem[lig_char(p)];
+lig_ptr(r)= copy_node_list(lig_ptr(p));
+}break;
+case disc_node:{r= get_node(small_node_size);
+pre_break(r)= copy_node_list(pre_break(p));
+post_break(r)= copy_node_list(post_break(p));
+}break;
+case mark_node:{r= get_node(small_node_size);add_token_ref(mark_ptr(p));
+words= small_node_size;
+}break;
+case adjust_node:{r= get_node(small_node_size);
+adjust_ptr(r)= copy_node_list(adjust_ptr(p));
+}break;
+default:confusion(/*1404:*/
+#line 25108 "tex.w"
+279
+/*:1404*/
+#line 4090 "tex.w"
+);
+
+}
+
+/*:206*/
+#line 4049 "tex.w"
+;
+while(words> 0)
+{decr(words);mem[r+words]= mem[p+words];
+}
+
+/*:205*/
+#line 4038 "tex.w"
+;
+link(q)= r;q= r;p= link(p);
+}
+link(q)= null;q= link(h);free_avail(h);
+return q;
+}
+
+/*:204*//*211:*/
+#line 4304 "tex.w"
+void print_mode(int m)
+{if(m> 0)
+switch(m/(max_command+1)){
+case 0:print_str("vertical");break;
+case 1:print_str("horizontal");break;
+case 2:print_str("display math");
+}
+else if(m==0)print_str("no");
+else switch((-m)/(max_command+1)){
+case 0:print_str("internal vertical");break;
+case 1:print_str("restricted horizontal");break;
+case 2:print_str("math");
+}
+print_str(" mode");
+}
+
+/*:211*//*216:*/
+#line 4418 "tex.w"
+void push_nest(void)
+{if(nest_ptr> max_nest_stack)
+{max_nest_stack= nest_ptr;
+if(nest_ptr==nest_size)overflow("semantic nest size",nest_size);
+
+}
+nest[nest_ptr]= cur_list;
+incr(nest_ptr);head= get_avail();tail= head;prev_graf= 0;mode_line= line;
+}
+
+/*:216*//*217:*/
+#line 4433 "tex.w"
+void pop_nest(void)
+{free_avail(head);decr(nest_ptr);cur_list= nest[nest_ptr];
+}
+
+/*:217*//*218:*/
+#line 4439 "tex.w"
+void print_totals(void);
+void show_activities(void)
+{int p;
+int16_t m;
+memory_word a;
+pointer q,r;
+int t;
+nest[nest_ptr]= cur_list;
+print_nl("");print_ln();
+for(p= nest_ptr;p>=0;p--)
+{m= nest[p].mode_field;a= nest[p].aux_field;
+print_nl("### ");print_mode(m);
+print_str(" entered at line ");print_int(abs(nest[p].ml_field));
+if(m==hmode)if(nest[p].pg_field!=040600000)
+{print_str(" (language");print_int(nest[p].pg_field%0200000);
+print_str(":hyphenmin");print_int(nest[p].pg_field/020000000);
+print_char(',');print_int((nest[p].pg_field/0200000)%0100);
+print_char(')');
+}
+if(nest[p].ml_field<0)print_str(" (\\output routine)");
+if(p==0)
+{/*986:*/
+#line 19296 "tex.w"
+
+if(page_head!=page_tail)
+{print_nl("### current page:");
+if(output_active)print_str(" (held over for next output)");
+
+show_box(link(page_head));
+if(page_contents> empty)
+{print_nl("total height ");print_totals();
+
+print_nl(" goal height ");print_scaled(page_goal);
+
+r= link(page_ins_head);
+while(r!=page_ins_head)
+{print_ln();print_esc(/*1390:*/
+#line 25066 "tex.w"
+265
+/*:1390*/
+#line 19309 "tex.w"
+);t= qo(subtype(r));
+print_int(t);print_str(" adds ");
+if(count(t)==1000)t= height(r);
+else t= x_over_n(height(r),1000)*count(t);
+print_scaled(t);
+if(type(r)==split_up)
+{q= page_head;t= 0;
+do{q= link(q);
+if((type(q)==ins_node)&&(subtype(q)==subtype(r)))incr(t);
+}while(!(q==broken_ins(r)));
+print_str(", #");print_int(t);print_str(" might split");
+}
+r= link(r);
+}
+}
+}
+
+/*:986*/
+#line 4460 "tex.w"
+;
+if(link(contrib_head)!=null)
+print_nl("### recent contributions:");
+}
+show_box(link(nest[p].head_field));
+/*219:*/
+#line 4469 "tex.w"
+
+switch(abs(m)/(max_command+1)){
+case 0:{print_nl("prevdepth ");
+if(a.sc<=ignore_depth)print_str("ignored");
+else print_scaled(a.sc);
+if(nest[p].pg_field!=0)
+{print_str(", prevgraf ");
+print_int(nest[p].pg_field);print_str(" line");
+if(nest[p].pg_field!=1)print_char('s');
+}
+}break;
+case 1:{print_nl("spacefactor ");print_int(a.hh.lh);
+if(m> 0)if(a.hh.rh> 0)
+{print_str(", current language ");print_int(a.hh.rh);
+}
+}break;
+case 2:if(a.i!=null)
+{print_str("this will be denominator of:");show_box(a.i);
+}
+}
+
+/*:219*/
+#line 4465 "tex.w"
+;
+}
+}
+
+/*:218*//*237:*/
+#line 5091 "tex.w"
+void print_param(int n)
+{switch(n){
+case pretolerance_code:print_esc(/*1446:*/
+#line 25234 "tex.w"
+321
+/*:1446*/
+#line 5093 "tex.w"
+);break;
+case tolerance_code:print_esc(/*1447:*/
+#line 25237 "tex.w"
+322
+/*:1447*/
+#line 5094 "tex.w"
+);break;
+case line_penalty_code:print_esc(/*1448:*/
+#line 25240 "tex.w"
+323
+/*:1448*/
+#line 5095 "tex.w"
+);break;
+case hyphen_penalty_code:print_esc(/*1449:*/
+#line 25243 "tex.w"
+324
+/*:1449*/
+#line 5096 "tex.w"
+);break;
+case ex_hyphen_penalty_code:print_esc(/*1450:*/
+#line 25246 "tex.w"
+325
+/*:1450*/
+#line 5097 "tex.w"
+);break;
+case club_penalty_code:print_esc(/*1451:*/
+#line 25249 "tex.w"
+326
+/*:1451*/
+#line 5098 "tex.w"
+);break;
+case widow_penalty_code:print_esc(/*1452:*/
+#line 25252 "tex.w"
+327
+/*:1452*/
+#line 5099 "tex.w"
+);break;
+case display_widow_penalty_code:print_esc(/*1453:*/
+#line 25255 "tex.w"
+328
+/*:1453*/
+#line 5100 "tex.w"
+);break;
+case broken_penalty_code:print_esc(/*1454:*/
+#line 25258 "tex.w"
+329
+/*:1454*/
+#line 5101 "tex.w"
+);break;
+case bin_op_penalty_code:print_esc(/*1455:*/
+#line 25261 "tex.w"
+330
+/*:1455*/
+#line 5102 "tex.w"
+);break;
+case rel_penalty_code:print_esc(/*1456:*/
+#line 25264 "tex.w"
+331
+/*:1456*/
+#line 5103 "tex.w"
+);break;
+case pre_display_penalty_code:print_esc(/*1457:*/
+#line 25267 "tex.w"
+332
+/*:1457*/
+#line 5104 "tex.w"
+);break;
+case post_display_penalty_code:print_esc(/*1458:*/
+#line 25270 "tex.w"
+333
+/*:1458*/
+#line 5105 "tex.w"
+);break;
+case inter_line_penalty_code:print_esc(/*1459:*/
+#line 25273 "tex.w"
+334
+/*:1459*/
+#line 5106 "tex.w"
+);break;
+case double_hyphen_demerits_code:print_esc(/*1460:*/
+#line 25276 "tex.w"
+335
+/*:1460*/
+#line 5107 "tex.w"
+);break;
+case final_hyphen_demerits_code:print_esc(/*1461:*/
+#line 25279 "tex.w"
+336
+/*:1461*/
+#line 5108 "tex.w"
+);break;
+case adj_demerits_code:print_esc(/*1462:*/
+#line 25282 "tex.w"
+337
+/*:1462*/
+#line 5109 "tex.w"
+);break;
+case mag_code:print_esc(/*1463:*/
+#line 25285 "tex.w"
+338
+/*:1463*/
+#line 5110 "tex.w"
+);break;
+case delimiter_factor_code:print_esc(/*1464:*/
+#line 25288 "tex.w"
+339
+/*:1464*/
+#line 5111 "tex.w"
+);break;
+case looseness_code:print_esc(/*1465:*/
+#line 25291 "tex.w"
+340
+/*:1465*/
+#line 5112 "tex.w"
+);break;
+case time_code:print_esc(/*1466:*/
+#line 25294 "tex.w"
+341
+/*:1466*/
+#line 5113 "tex.w"
+);break;
+case day_code:print_esc(/*1467:*/
+#line 25297 "tex.w"
+342
+/*:1467*/
+#line 5114 "tex.w"
+);break;
+case month_code:print_esc(/*1468:*/
+#line 25300 "tex.w"
+343
+/*:1468*/
+#line 5115 "tex.w"
+);break;
+case year_code:print_esc(/*1469:*/
+#line 25303 "tex.w"
+344
+/*:1469*/
+#line 5116 "tex.w"
+);break;
+case show_box_breadth_code:print_esc(/*1470:*/
+#line 25306 "tex.w"
+345
+/*:1470*/
+#line 5117 "tex.w"
+);break;
+case show_box_depth_code:print_esc(/*1471:*/
+#line 25309 "tex.w"
+346
+/*:1471*/
+#line 5118 "tex.w"
+);break;
+case hbadness_code:print_esc(/*1472:*/
+#line 25312 "tex.w"
+347
+/*:1472*/
+#line 5119 "tex.w"
+);break;
+case vbadness_code:print_esc(/*1473:*/
+#line 25315 "tex.w"
+348
+/*:1473*/
+#line 5120 "tex.w"
+);break;
+case pausing_code:print_esc(/*1474:*/
+#line 25318 "tex.w"
+349
+/*:1474*/
+#line 5121 "tex.w"
+);break;
+case tracing_online_code:print_esc(/*1475:*/
+#line 25321 "tex.w"
+350
+/*:1475*/
+#line 5122 "tex.w"
+);break;
+case tracing_macros_code:print_esc(/*1476:*/
+#line 25324 "tex.w"
+351
+/*:1476*/
+#line 5123 "tex.w"
+);break;
+case tracing_stats_code:print_esc(/*1477:*/
+#line 25327 "tex.w"
+352
+/*:1477*/
+#line 5124 "tex.w"
+);break;
+case tracing_paragraphs_code:print_esc(/*1478:*/
+#line 25330 "tex.w"
+353
+/*:1478*/
+#line 5125 "tex.w"
+);break;
+case tracing_pages_code:print_esc(/*1479:*/
+#line 25333 "tex.w"
+354
+/*:1479*/
+#line 5126 "tex.w"
+);break;
+case tracing_output_code:print_esc(/*1480:*/
+#line 25336 "tex.w"
+355
+/*:1480*/
+#line 5127 "tex.w"
+);break;
+case tracing_lost_chars_code:print_esc(/*1481:*/
+#line 25339 "tex.w"
+356
+/*:1481*/
+#line 5128 "tex.w"
+);break;
+case tracing_commands_code:print_esc(/*1482:*/
+#line 25342 "tex.w"
+357
+/*:1482*/
+#line 5129 "tex.w"
+);break;
+case tracing_restores_code:print_esc(/*1483:*/
+#line 25345 "tex.w"
+358
+/*:1483*/
+#line 5130 "tex.w"
+);break;
+case uc_hyph_code:print_esc(/*1484:*/
+#line 25348 "tex.w"
+359
+/*:1484*/
+#line 5131 "tex.w"
+);break;
+case output_penalty_code:print_esc(/*1485:*/
+#line 25351 "tex.w"
+360
+/*:1485*/
+#line 5132 "tex.w"
+);break;
+case max_dead_cycles_code:print_esc(/*1486:*/
+#line 25354 "tex.w"
+361
+/*:1486*/
+#line 5133 "tex.w"
+);break;
+case hang_after_code:print_esc(/*1487:*/
+#line 25357 "tex.w"
+362
+/*:1487*/
+#line 5134 "tex.w"
+);break;
+case floating_penalty_code:print_esc(/*1488:*/
+#line 25360 "tex.w"
+363
+/*:1488*/
+#line 5135 "tex.w"
+);break;
+case global_defs_code:print_esc(/*1489:*/
+#line 25363 "tex.w"
+364
+/*:1489*/
+#line 5136 "tex.w"
+);break;
+case cur_fam_code:print_esc(/*1490:*/
+#line 25366 "tex.w"
+365
+/*:1490*/
+#line 5137 "tex.w"
+);break;
+case escape_char_code:print_esc(/*1491:*/
+#line 25369 "tex.w"
+366
+/*:1491*/
+#line 5138 "tex.w"
+);break;
+case default_hyphen_char_code:print_esc(/*1492:*/
+#line 25372 "tex.w"
+367
+/*:1492*/
+#line 5139 "tex.w"
+);break;
+case default_skew_char_code:print_esc(/*1493:*/
+#line 25375 "tex.w"
+368
+/*:1493*/
+#line 5140 "tex.w"
+);break;
+case end_line_char_code:print_esc(/*1494:*/
+#line 25378 "tex.w"
+369
+/*:1494*/
+#line 5141 "tex.w"
+);break;
+case new_line_char_code:print_esc(/*1495:*/
+#line 25381 "tex.w"
+370
+/*:1495*/
+#line 5142 "tex.w"
+);break;
+case language_code:print_esc(/*1496:*/
+#line 25384 "tex.w"
+371
+/*:1496*/
+#line 5143 "tex.w"
+);break;
+case left_hyphen_min_code:print_esc(/*1497:*/
+#line 25387 "tex.w"
+372
+/*:1497*/
+#line 5144 "tex.w"
+);break;
+case right_hyphen_min_code:print_esc(/*1498:*/
+#line 25390 "tex.w"
+373
+/*:1498*/
+#line 5145 "tex.w"
+);break;
+case holding_inserts_code:print_esc(/*1499:*/
+#line 25393 "tex.w"
+374
+/*:1499*/
+#line 5146 "tex.w"
+);break;
+case error_context_lines_code:print_esc(/*1500:*/
+#line 25396 "tex.w"
+375
+/*:1500*/
+#line 5147 "tex.w"
+);break;
+default:print_str("[unknown integer parameter!]");
+}
+}
+
+/*:237*//*241:*/
+#line 5293 "tex.w"
+void fix_date_and_time(void)
+{time= 12*60;
+day= 4;
+month= 7;
+year= 1776;
+}
+
+/*:241*//*245:*/
+#line 5318 "tex.w"
+void begin_diagnostic(void)
+{old_setting= selector;
+if((tracing_online<=0)&&(selector==term_and_log))
+{decr(selector);
+if(history==spotless)history= warning_issued;
+}
+}
+
+void end_diagnostic(bool blank_line)
+
+{print_nl("");
+if(blank_line)print_ln();
+selector= old_setting;
+}
+
+/*:245*//*247:*/
+#line 5392 "tex.w"
+void print_length_param(int n)
+{switch(n){
+case par_indent_code:print_esc(/*1503:*/
+#line 25405 "tex.w"
+378
+/*:1503*/
+#line 5394 "tex.w"
+);break;
+case math_surround_code:print_esc(/*1504:*/
+#line 25408 "tex.w"
+379
+/*:1504*/
+#line 5395 "tex.w"
+);break;
+case line_skip_limit_code:print_esc(/*1505:*/
+#line 25411 "tex.w"
+380
+/*:1505*/
+#line 5396 "tex.w"
+);break;
+case hsize_code:print_esc(/*1506:*/
+#line 25414 "tex.w"
+381
+/*:1506*/
+#line 5397 "tex.w"
+);break;
+case vsize_code:print_esc(/*1507:*/
+#line 25417 "tex.w"
+382
+/*:1507*/
+#line 5398 "tex.w"
+);break;
+case max_depth_code:print_esc(/*1508:*/
+#line 25420 "tex.w"
+383
+/*:1508*/
+#line 5399 "tex.w"
+);break;
+case split_max_depth_code:print_esc(/*1509:*/
+#line 25423 "tex.w"
+384
+/*:1509*/
+#line 5400 "tex.w"
+);break;
+case box_max_depth_code:print_esc(/*1510:*/
+#line 25426 "tex.w"
+385
+/*:1510*/
+#line 5401 "tex.w"
+);break;
+case hfuzz_code:print_esc(/*1511:*/
+#line 25429 "tex.w"
+386
+/*:1511*/
+#line 5402 "tex.w"
+);break;
+case vfuzz_code:print_esc(/*1512:*/
+#line 25432 "tex.w"
+387
+/*:1512*/
+#line 5403 "tex.w"
+);break;
+case delimiter_shortfall_code:print_esc(/*1513:*/
+#line 25435 "tex.w"
+388
+/*:1513*/
+#line 5404 "tex.w"
+);break;
+case null_delimiter_space_code:print_esc(/*1514:*/
+#line 25438 "tex.w"
+389
+/*:1514*/
+#line 5405 "tex.w"
+);break;
+case script_space_code:print_esc(/*1515:*/
+#line 25441 "tex.w"
+390
+/*:1515*/
+#line 5406 "tex.w"
+);break;
+case pre_display_size_code:print_esc(/*1516:*/
+#line 25444 "tex.w"
+391
+/*:1516*/
+#line 5407 "tex.w"
+);break;
+case display_width_code:print_esc(/*1517:*/
+#line 25447 "tex.w"
+392
+/*:1517*/
+#line 5408 "tex.w"
+);break;
+case display_indent_code:print_esc(/*1518:*/
+#line 25450 "tex.w"
+393
+/*:1518*/
+#line 5409 "tex.w"
+);break;
+case overfull_rule_code:print_esc(/*1519:*/
+#line 25453 "tex.w"
+394
+/*:1519*/
+#line 5410 "tex.w"
+);break;
+case hang_indent_code:print_esc(/*1520:*/
+#line 25456 "tex.w"
+395
+/*:1520*/
+#line 5411 "tex.w"
+);break;
+case h_offset_code:print_esc(/*1521:*/
+#line 25459 "tex.w"
+396
+/*:1521*/
+#line 5412 "tex.w"
+);break;
+case v_offset_code:print_esc(/*1522:*/
+#line 25462 "tex.w"
+397
+/*:1522*/
+#line 5413 "tex.w"
+);break;
+case emergency_stretch_code:print_esc(/*1523:*/
+#line 25465 "tex.w"
+398
+/*:1523*/
+#line 5414 "tex.w"
+);break;
+default:print_str("[unknown dimen parameter!]");
+}
+}
+
+/*:247*//*252:*/
+#line 5484 "tex.w"
+/*298:*/
+#line 6463 "tex.w"
+
+void print_cmd_chr(quarterword cmd,halfword chr_code)
+{switch(cmd){
+case left_brace:chr_cmd("begin-group character ")break;
+case right_brace:chr_cmd("end-group character ")break;
+case math_shift:chr_cmd("math shift character ")break;
+case mac_param:chr_cmd("macro parameter character ")break;
+case sup_mark:chr_cmd("superscript character ")break;
+case sub_mark:chr_cmd("subscript character ")break;
+case endv:print_str("end of alignment template");break;
+case spacer:chr_cmd("blank space ")break;
+case letter:chr_cmd("the letter ")break;
+case other_char:chr_cmd("the character ")break;
+/*227:*/
+#line 4740 "tex.w"
+
+case assign_glue:case assign_mu_glue:if(chr_code<skip_base)
+print_skip_param(chr_code-glue_base);
+else if(chr_code<mu_skip_base)
+{print_esc(/*1423:*/
+#line 25165 "tex.w"
+298
+/*:1423*/
+#line 4744 "tex.w"
+);print_int(chr_code-skip_base);
+}
+else{print_esc(/*1424:*/
+#line 25168 "tex.w"
+299
+/*:1424*/
+#line 4746 "tex.w"
+);print_int(chr_code-mu_skip_base);
+}break;
+
+/*:227*//*231:*/
+#line 4841 "tex.w"
+
+case assign_toks:if(chr_code>=toks_base)
+{print_esc(/*1435:*/
+#line 25201 "tex.w"
+310
+/*:1435*/
+#line 4843 "tex.w"
+);print_int(chr_code-toks_base);
+}
+else switch(chr_code){
+case output_routine_loc:print_esc(/*1426:*/
+#line 25174 "tex.w"
+301
+/*:1426*/
+#line 4846 "tex.w"
+);break;
+case every_par_loc:print_esc(/*1427:*/
+#line 25177 "tex.w"
+302
+/*:1427*/
+#line 4847 "tex.w"
+);break;
+case every_math_loc:print_esc(/*1428:*/
+#line 25180 "tex.w"
+303
+/*:1428*/
+#line 4848 "tex.w"
+);break;
+case every_display_loc:print_esc(/*1429:*/
+#line 25183 "tex.w"
+304
+/*:1429*/
+#line 4849 "tex.w"
+);break;
+case every_hbox_loc:print_esc(/*1430:*/
+#line 25186 "tex.w"
+305
+/*:1430*/
+#line 4850 "tex.w"
+);break;
+case every_vbox_loc:print_esc(/*1431:*/
+#line 25189 "tex.w"
+306
+/*:1431*/
+#line 4851 "tex.w"
+);break;
+case every_job_loc:print_esc(/*1432:*/
+#line 25192 "tex.w"
+307
+/*:1432*/
+#line 4852 "tex.w"
+);break;
+case every_cr_loc:print_esc(/*1433:*/
+#line 25195 "tex.w"
+308
+/*:1433*/
+#line 4853 "tex.w"
+);break;
+default:print_esc(/*1434:*/
+#line 25198 "tex.w"
+309
+/*:1434*/
+#line 4854 "tex.w"
+);
+}break;
+
+/*:231*//*239:*/
+#line 5269 "tex.w"
+
+case assign_int:if(chr_code<count_base)print_param(chr_code-int_base);
+else{print_esc(/*1501:*/
+#line 25399 "tex.w"
+376
+/*:1501*/
+#line 5271 "tex.w"
+);print_int(chr_code-count_base);
+}break;
+
+/*:239*//*249:*/
+#line 5465 "tex.w"
+
+case assign_dimen:if(chr_code<scaled_base)
+print_length_param(chr_code-dimen_base);
+else{print_esc(/*1524:*/
+#line 25468 "tex.w"
+399
+/*:1524*/
+#line 5468 "tex.w"
+);print_int(chr_code-scaled_base);
+}break;
+
+/*:249*//*266:*/
+#line 5797 "tex.w"
+
+case accent:print_esc(/*1530:*/
+#line 25486 "tex.w"
+405
+/*:1530*/
+#line 5798 "tex.w"
+);break;
+case advance:print_esc(/*1531:*/
+#line 25489 "tex.w"
+406
+/*:1531*/
+#line 5799 "tex.w"
+);break;
+case after_assignment:print_esc(/*1532:*/
+#line 25492 "tex.w"
+407
+/*:1532*/
+#line 5800 "tex.w"
+);break;
+case after_group:print_esc(/*1533:*/
+#line 25495 "tex.w"
+408
+/*:1533*/
+#line 5801 "tex.w"
+);break;
+case assign_font_dimen:print_esc(/*1541:*/
+#line 25519 "tex.w"
+416
+/*:1541*/
+#line 5802 "tex.w"
+);break;
+case begin_group:print_esc(/*1534:*/
+#line 25498 "tex.w"
+409
+/*:1534*/
+#line 5803 "tex.w"
+);break;
+case break_penalty:print_esc(/*1553:*/
+#line 25555 "tex.w"
+428
+/*:1553*/
+#line 5804 "tex.w"
+);break;
+case char_num:print_esc(/*1535:*/
+#line 25501 "tex.w"
+410
+/*:1535*/
+#line 5805 "tex.w"
+);break;
+case cs_name:print_esc(/*1526:*/
+#line 25474 "tex.w"
+401
+/*:1526*/
+#line 5806 "tex.w"
+);break;
+case def_font:print_esc(/*1540:*/
+#line 25516 "tex.w"
+415
+/*:1540*/
+#line 5807 "tex.w"
+);break;
+case delim_num:print_esc(/*1536:*/
+#line 25504 "tex.w"
+411
+/*:1536*/
+#line 5808 "tex.w"
+);break;
+case divide:print_esc(/*1537:*/
+#line 25507 "tex.w"
+412
+/*:1537*/
+#line 5809 "tex.w"
+);break;
+case end_cs_name:print_esc(/*1527:*/
+#line 25477 "tex.w"
+402
+/*:1527*/
+#line 5810 "tex.w"
+);break;
+case end_group:print_esc(/*1538:*/
+#line 25510 "tex.w"
+413
+/*:1538*/
+#line 5811 "tex.w"
+);break;
+case ex_space:print_esc(' ');break;
+case expand_after:print_esc(/*1539:*/
+#line 25513 "tex.w"
+414
+/*:1539*/
+#line 5813 "tex.w"
+);break;
+case halign:print_esc(/*1542:*/
+#line 25522 "tex.w"
+417
+/*:1542*/
+#line 5814 "tex.w"
+);break;
+case hrule:print_esc(/*1543:*/
+#line 25525 "tex.w"
+418
+/*:1543*/
+#line 5815 "tex.w"
+);break;
+case ignore_spaces:print_esc(/*1544:*/
+#line 25528 "tex.w"
+419
+/*:1544*/
+#line 5816 "tex.w"
+);break;
+case insert:print_esc(/*1390:*/
+#line 25066 "tex.w"
+265
+/*:1390*/
+#line 5817 "tex.w"
+);break;
+case ital_corr:print_esc('/');break;
+case mark:print_esc(/*1401:*/
+#line 25099 "tex.w"
+276
+/*:1401*/
+#line 5819 "tex.w"
+);break;
+case math_accent:print_esc(/*1545:*/
+#line 25531 "tex.w"
+420
+/*:1545*/
+#line 5820 "tex.w"
+);break;
+case math_char_num:print_esc(/*1546:*/
+#line 25534 "tex.w"
+421
+/*:1546*/
+#line 5821 "tex.w"
+);break;
+case math_choice:print_esc(/*1547:*/
+#line 25537 "tex.w"
+422
+/*:1547*/
+#line 5822 "tex.w"
+);break;
+case multiply:print_esc(/*1548:*/
+#line 25540 "tex.w"
+423
+/*:1548*/
+#line 5823 "tex.w"
+);break;
+case no_align:print_esc(/*1549:*/
+#line 25543 "tex.w"
+424
+/*:1549*/
+#line 5824 "tex.w"
+);break;
+case no_boundary:print_esc(/*1550:*/
+#line 25546 "tex.w"
+425
+/*:1550*/
+#line 5825 "tex.w"
+);break;
+case no_expand:print_esc(/*1551:*/
+#line 25549 "tex.w"
+426
+/*:1551*/
+#line 5826 "tex.w"
+);break;
+case non_script:print_esc(/*1392:*/
+#line 25072 "tex.w"
+267
+/*:1392*/
+#line 5827 "tex.w"
+);break;
+case omit:print_esc(/*1552:*/
+#line 25552 "tex.w"
+427
+/*:1552*/
+#line 5828 "tex.w"
+);break;
+case radical:print_esc(/*1555:*/
+#line 25561 "tex.w"
+430
+/*:1555*/
+#line 5829 "tex.w"
+);break;
+case read_to_cs:print_esc(/*1556:*/
+#line 25564 "tex.w"
+431
+/*:1556*/
+#line 5830 "tex.w"
+);break;
+case relax:print_esc(/*1557:*/
+#line 25567 "tex.w"
+432
+/*:1557*/
+#line 5831 "tex.w"
+);break;
+case set_box:print_esc(/*1558:*/
+#line 25570 "tex.w"
+433
+/*:1558*/
+#line 5832 "tex.w"
+);break;
+case set_prev_graf:print_esc(/*1554:*/
+#line 25558 "tex.w"
+429
+/*:1554*/
+#line 5833 "tex.w"
+);break;
+case set_shape:print_esc(/*1436:*/
+#line 25204 "tex.w"
+311
+/*:1436*/
+#line 5834 "tex.w"
+);break;
+case the:print_esc(/*1559:*/
+#line 25573 "tex.w"
+434
+/*:1559*/
+#line 5835 "tex.w"
+);break;
+case toks_register:print_esc(/*1435:*/
+#line 25201 "tex.w"
+310
+/*:1435*/
+#line 5836 "tex.w"
+);break;
+case vadjust:print_esc(/*1402:*/
+#line 25102 "tex.w"
+277
+/*:1402*/
+#line 5837 "tex.w"
+);break;
+case valign:print_esc(/*1560:*/
+#line 25576 "tex.w"
+435
+/*:1560*/
+#line 5838 "tex.w"
+);break;
+case vcenter:print_esc(/*1561:*/
+#line 25579 "tex.w"
+436
+/*:1561*/
+#line 5839 "tex.w"
+);break;
+case vrule:print_esc(/*1562:*/
+#line 25582 "tex.w"
+437
+/*:1562*/
+#line 5840 "tex.w"
+);break;
+
+/*:266*//*335:*/
+#line 7203 "tex.w"
+
+case par_end:print_esc(/*1569:*/
+#line 25603 "tex.w"
+444
+/*:1569*/
+#line 7204 "tex.w"
+);break;
+
+/*:335*//*377:*/
+#line 7854 "tex.w"
+
+case input:if(chr_code==0)print_esc(/*1570:*/
+#line 25606 "tex.w"
+445
+/*:1570*/
+#line 7855 "tex.w"
+);else print_esc(/*1571:*/
+#line 25609 "tex.w"
+446
+/*:1571*/
+#line 7855 "tex.w"
+);break;
+
+/*:377*//*385:*/
+#line 7945 "tex.w"
+
+case top_bot_mark:switch(chr_code){
+case first_mark_code:print_esc(/*1573:*/
+#line 25615 "tex.w"
+448
+/*:1573*/
+#line 7947 "tex.w"
+);break;
+case bot_mark_code:print_esc(/*1574:*/
+#line 25618 "tex.w"
+449
+/*:1574*/
+#line 7948 "tex.w"
+);break;
+case split_first_mark_code:print_esc(/*1575:*/
+#line 25621 "tex.w"
+450
+/*:1575*/
+#line 7949 "tex.w"
+);break;
+case split_bot_mark_code:print_esc(/*1576:*/
+#line 25624 "tex.w"
+451
+/*:1576*/
+#line 7950 "tex.w"
+);break;
+default:print_esc(/*1572:*/
+#line 25612 "tex.w"
+447
+/*:1572*/
+#line 7951 "tex.w"
+);
+}break;
+
+/*:385*//*412:*/
+#line 8388 "tex.w"
+
+case register:if(chr_code==int_val)print_esc(/*1501:*/
+#line 25399 "tex.w"
+376
+/*:1501*/
+#line 8389 "tex.w"
+);
+else if(chr_code==dimen_val)print_esc(/*1524:*/
+#line 25468 "tex.w"
+399
+/*:1524*/
+#line 8390 "tex.w"
+);
+else if(chr_code==glue_val)print_esc(/*1423:*/
+#line 25165 "tex.w"
+298
+/*:1423*/
+#line 8391 "tex.w"
+);
+else print_esc(/*1424:*/
+#line 25168 "tex.w"
+299
+/*:1424*/
+#line 8392 "tex.w"
+);break;
+
+/*:412*//*417:*/
+#line 8498 "tex.w"
+
+case set_aux:if(chr_code==vmode)print_esc(/*1578:*/
+#line 25630 "tex.w"
+453
+/*:1578*/
+#line 8499 "tex.w"
+);
+else print_esc(/*1577:*/
+#line 25627 "tex.w"
+452
+/*:1577*/
+#line 8500 "tex.w"
+);break;
+case set_page_int:if(chr_code==0)print_esc(/*1579:*/
+#line 25633 "tex.w"
+454
+/*:1579*/
+#line 8501 "tex.w"
+);
+else print_esc(/*1580:*/
+#line 25636 "tex.w"
+455
+/*:1580*/
+#line 8502 "tex.w"
+);break;
+case set_box_dimen:if(chr_code==width_offset)print_esc(/*1581:*/
+#line 25639 "tex.w"
+456
+/*:1581*/
+#line 8503 "tex.w"
+);
+else if(chr_code==height_offset)print_esc(/*1582:*/
+#line 25642 "tex.w"
+457
+/*:1582*/
+#line 8504 "tex.w"
+);
+else print_esc(/*1583:*/
+#line 25645 "tex.w"
+458
+/*:1583*/
+#line 8505 "tex.w"
+);break;
+case last_item:switch(chr_code){
+case int_val:print_esc(/*1584:*/
+#line 25648 "tex.w"
+459
+/*:1584*/
+#line 8507 "tex.w"
+);break;
+case dimen_val:print_esc(/*1585:*/
+#line 25651 "tex.w"
+460
+/*:1585*/
+#line 8508 "tex.w"
+);break;
+case glue_val:print_esc(/*1586:*/
+#line 25654 "tex.w"
+461
+/*:1586*/
+#line 8509 "tex.w"
+);break;
+case input_line_no_code:print_esc(/*1587:*/
+#line 25657 "tex.w"
+462
+/*:1587*/
+#line 8510 "tex.w"
+);break;
+default:print_esc(/*1588:*/
+#line 25660 "tex.w"
+463
+/*:1588*/
+#line 8511 "tex.w"
+);
+}break;
+
+/*:417*//*469:*/
+#line 9287 "tex.w"
+
+case convert:switch(chr_code){
+case number_code:print_esc(/*1605:*/
+#line 25711 "tex.w"
+480
+/*:1605*/
+#line 9289 "tex.w"
+);break;
+case roman_numeral_code:print_esc(/*1606:*/
+#line 25714 "tex.w"
+481
+/*:1606*/
+#line 9290 "tex.w"
+);break;
+case string_code:print_esc(/*1607:*/
+#line 25717 "tex.w"
+482
+/*:1607*/
+#line 9291 "tex.w"
+);break;
+case meaning_code:print_esc(/*1608:*/
+#line 25720 "tex.w"
+483
+/*:1608*/
+#line 9292 "tex.w"
+);break;
+case font_name_code:print_esc(/*1609:*/
+#line 25723 "tex.w"
+484
+/*:1609*/
+#line 9293 "tex.w"
+);break;
+default:print_esc(/*1610:*/
+#line 25726 "tex.w"
+485
+/*:1610*/
+#line 9294 "tex.w"
+);
+}break;
+
+/*:469*//*488:*/
+#line 9625 "tex.w"
+
+case if_test:switch(chr_code){
+case if_cat_code:print_esc(/*1612:*/
+#line 25732 "tex.w"
+487
+/*:1612*/
+#line 9627 "tex.w"
+);break;
+case if_int_code:print_esc(/*1613:*/
+#line 25735 "tex.w"
+488
+/*:1613*/
+#line 9628 "tex.w"
+);break;
+case if_dim_code:print_esc(/*1614:*/
+#line 25738 "tex.w"
+489
+/*:1614*/
+#line 9629 "tex.w"
+);break;
+case if_odd_code:print_esc(/*1615:*/
+#line 25741 "tex.w"
+490
+/*:1615*/
+#line 9630 "tex.w"
+);break;
+case if_vmode_code:print_esc(/*1616:*/
+#line 25744 "tex.w"
+491
+/*:1616*/
+#line 9631 "tex.w"
+);break;
+case if_hmode_code:print_esc(/*1617:*/
+#line 25747 "tex.w"
+492
+/*:1617*/
+#line 9632 "tex.w"
+);break;
+case if_mmode_code:print_esc(/*1618:*/
+#line 25750 "tex.w"
+493
+/*:1618*/
+#line 9633 "tex.w"
+);break;
+case if_inner_code:print_esc(/*1619:*/
+#line 25753 "tex.w"
+494
+/*:1619*/
+#line 9634 "tex.w"
+);break;
+case if_void_code:print_esc(/*1620:*/
+#line 25756 "tex.w"
+495
+/*:1620*/
+#line 9635 "tex.w"
+);break;
+case if_hbox_code:print_esc(/*1621:*/
+#line 25759 "tex.w"
+496
+/*:1621*/
+#line 9636 "tex.w"
+);break;
+case if_vbox_code:print_esc(/*1622:*/
+#line 25762 "tex.w"
+497
+/*:1622*/
+#line 9637 "tex.w"
+);break;
+case ifx_code:print_esc(/*1623:*/
+#line 25765 "tex.w"
+498
+/*:1623*/
+#line 9638 "tex.w"
+);break;
+case if_eof_code:print_esc(/*1624:*/
+#line 25768 "tex.w"
+499
+/*:1624*/
+#line 9639 "tex.w"
+);break;
+case if_true_code:print_esc(/*1625:*/
+#line 25771 "tex.w"
+500
+/*:1625*/
+#line 9640 "tex.w"
+);break;
+case if_false_code:print_esc(/*1626:*/
+#line 25774 "tex.w"
+501
+/*:1626*/
+#line 9641 "tex.w"
+);break;
+case if_case_code:print_esc(/*1627:*/
+#line 25777 "tex.w"
+502
+/*:1627*/
+#line 9642 "tex.w"
+);break;
+default:print_esc(/*1611:*/
+#line 25729 "tex.w"
+486
+/*:1611*/
+#line 9643 "tex.w"
+);
+}break;
+
+/*:488*//*492:*/
+#line 9687 "tex.w"
+
+case fi_or_else:if(chr_code==fi_code)print_esc(/*1628:*/
+#line 25780 "tex.w"
+503
+/*:1628*/
+#line 9688 "tex.w"
+);
+else if(chr_code==or_code)print_esc(/*1629:*/
+#line 25783 "tex.w"
+504
+/*:1629*/
+#line 9689 "tex.w"
+);
+else print_esc(/*1630:*/
+#line 25786 "tex.w"
+505
+/*:1630*/
+#line 9690 "tex.w"
+);break;
+
+/*:492*//*781:*/
+#line 15430 "tex.w"
+
+case tab_mark:if(chr_code==span_code)print_esc(/*1669:*/
+#line 25903 "tex.w"
+544
+/*:1669*/
+#line 15431 "tex.w"
+);
+else chr_cmd("alignment tab character ")break;
+case car_ret:if(chr_code==cr_code)print_esc(/*1670:*/
+#line 25906 "tex.w"
+545
+/*:1670*/
+#line 15433 "tex.w"
+);
+else print_esc(/*1671:*/
+#line 25909 "tex.w"
+546
+/*:1671*/
+#line 15434 "tex.w"
+);break;
+
+/*:781*//*984:*/
+#line 19269 "tex.w"
+
+case set_page_dimen:switch(chr_code){
+case 0:print_esc(/*1689:*/
+#line 25963 "tex.w"
+564
+/*:1689*/
+#line 19271 "tex.w"
+);break;
+case 1:print_esc(/*1690:*/
+#line 25966 "tex.w"
+565
+/*:1690*/
+#line 19272 "tex.w"
+);break;
+case 2:print_esc(/*1691:*/
+#line 25969 "tex.w"
+566
+/*:1691*/
+#line 19273 "tex.w"
+);break;
+case 3:print_esc(/*1692:*/
+#line 25972 "tex.w"
+567
+/*:1692*/
+#line 19274 "tex.w"
+);break;
+case 4:print_esc(/*1693:*/
+#line 25975 "tex.w"
+568
+/*:1693*/
+#line 19275 "tex.w"
+);break;
+case 5:print_esc(/*1694:*/
+#line 25978 "tex.w"
+569
+/*:1694*/
+#line 19276 "tex.w"
+);break;
+case 6:print_esc(/*1695:*/
+#line 25981 "tex.w"
+570
+/*:1695*/
+#line 19277 "tex.w"
+);break;
+default:print_esc(/*1696:*/
+#line 25984 "tex.w"
+571
+/*:1696*/
+#line 19278 "tex.w"
+);
+}break;
+
+/*:984*//*1053:*/
+#line 20477 "tex.w"
+
+case stop:if(chr_code==1)print_esc(/*1699:*/
+#line 25993 "tex.w"
+574
+/*:1699*/
+#line 20478 "tex.w"
+);else print_esc(/*1698:*/
+#line 25990 "tex.w"
+573
+/*:1698*/
+#line 20478 "tex.w"
+);break;
+
+/*:1053*//*1059:*/
+#line 20575 "tex.w"
+
+case hskip:switch(chr_code){
+case skip_code:print_esc(/*1700:*/
+#line 25996 "tex.w"
+575
+/*:1700*/
+#line 20577 "tex.w"
+);break;
+case fil_code:print_esc(/*1701:*/
+#line 25999 "tex.w"
+576
+/*:1701*/
+#line 20578 "tex.w"
+);break;
+case fill_code:print_esc(/*1702:*/
+#line 26002 "tex.w"
+577
+/*:1702*/
+#line 20579 "tex.w"
+);break;
+case ss_code:print_esc(/*1703:*/
+#line 26005 "tex.w"
+578
+/*:1703*/
+#line 20580 "tex.w"
+);break;
+default:print_esc(/*1704:*/
+#line 26008 "tex.w"
+579
+/*:1704*/
+#line 20581 "tex.w"
+);
+}break;
+case vskip:switch(chr_code){
+case skip_code:print_esc(/*1705:*/
+#line 26011 "tex.w"
+580
+/*:1705*/
+#line 20584 "tex.w"
+);break;
+case fil_code:print_esc(/*1706:*/
+#line 26014 "tex.w"
+581
+/*:1706*/
+#line 20585 "tex.w"
+);break;
+case fill_code:print_esc(/*1707:*/
+#line 26017 "tex.w"
+582
+/*:1707*/
+#line 20586 "tex.w"
+);break;
+case ss_code:print_esc(/*1708:*/
+#line 26020 "tex.w"
+583
+/*:1708*/
+#line 20587 "tex.w"
+);break;
+default:print_esc(/*1709:*/
+#line 26023 "tex.w"
+584
+/*:1709*/
+#line 20588 "tex.w"
+);
+}break;
+case mskip:print_esc(/*1393:*/
+#line 25075 "tex.w"
+268
+/*:1393*/
+#line 20590 "tex.w"
+);break;
+case kern:print_esc(/*1396:*/
+#line 25084 "tex.w"
+271
+/*:1396*/
+#line 20591 "tex.w"
+);break;
+case mkern:print_esc(/*1397:*/
+#line 25087 "tex.w"
+272
+/*:1397*/
+#line 20592 "tex.w"
+);break;
+
+/*:1059*//*1072:*/
+#line 20837 "tex.w"
+
+case hmove:if(chr_code==1)print_esc(/*1712:*/
+#line 26032 "tex.w"
+587
+/*:1712*/
+#line 20838 "tex.w"
+);else print_esc(/*1713:*/
+#line 26035 "tex.w"
+588
+/*:1713*/
+#line 20838 "tex.w"
+);break;
+case vmove:if(chr_code==1)print_esc(/*1714:*/
+#line 26038 "tex.w"
+589
+/*:1714*/
+#line 20839 "tex.w"
+);else print_esc(/*1715:*/
+#line 26041 "tex.w"
+590
+/*:1715*/
+#line 20839 "tex.w"
+);break;
+case make_box:switch(chr_code){
+case box_code:print_esc(/*1437:*/
+#line 25207 "tex.w"
+312
+/*:1437*/
+#line 20841 "tex.w"
+);break;
+case copy_code:print_esc(/*1716:*/
+#line 26044 "tex.w"
+591
+/*:1716*/
+#line 20842 "tex.w"
+);break;
+case last_box_code:print_esc(/*1717:*/
+#line 26047 "tex.w"
+592
+/*:1717*/
+#line 20843 "tex.w"
+);break;
+case vsplit_code:print_esc(/*1687:*/
+#line 25957 "tex.w"
+562
+/*:1687*/
+#line 20844 "tex.w"
+);break;
+case vtop_code:print_esc(/*1718:*/
+#line 26050 "tex.w"
+593
+/*:1718*/
+#line 20845 "tex.w"
+);break;
+case vtop_code+vmode:print_esc(/*1688:*/
+#line 25960 "tex.w"
+563
+/*:1688*/
+#line 20846 "tex.w"
+);break;
+default:print_esc(/*1719:*/
+#line 26053 "tex.w"
+594
+/*:1719*/
+#line 20847 "tex.w"
+);
+}break;
+case leader_ship:if(chr_code==a_leaders)print_esc(/*1721:*/
+#line 26059 "tex.w"
+596
+/*:1721*/
+#line 20849 "tex.w"
+);
+else if(chr_code==c_leaders)print_esc(/*1722:*/
+#line 26062 "tex.w"
+597
+/*:1722*/
+#line 20850 "tex.w"
+);
+else if(chr_code==x_leaders)print_esc(/*1723:*/
+#line 26065 "tex.w"
+598
+/*:1723*/
+#line 20851 "tex.w"
+);
+else print_esc(/*1720:*/
+#line 26056 "tex.w"
+595
+/*:1720*/
+#line 20852 "tex.w"
+);break;
+
+/*:1072*//*1089:*/
+#line 21098 "tex.w"
+
+case start_par:if(chr_code==0)print_esc(/*1725:*/
+#line 26071 "tex.w"
+600
+/*:1725*/
+#line 21099 "tex.w"
+);else print_esc(/*1724:*/
+#line 26068 "tex.w"
+599
+/*:1724*/
+#line 21099 "tex.w"
+);break;
+
+/*:1089*//*1108:*/
+#line 21316 "tex.w"
+
+case remove_item:if(chr_code==glue_node)print_esc(/*1728:*/
+#line 26080 "tex.w"
+603
+/*:1728*/
+#line 21317 "tex.w"
+);
+else if(chr_code==kern_node)print_esc(/*1727:*/
+#line 26077 "tex.w"
+602
+/*:1727*/
+#line 21318 "tex.w"
+);
+else print_esc(/*1726:*/
+#line 26074 "tex.w"
+601
+/*:1726*/
+#line 21319 "tex.w"
+);break;
+case un_hbox:if(chr_code==copy_code)print_esc(/*1730:*/
+#line 26086 "tex.w"
+605
+/*:1730*/
+#line 21320 "tex.w"
+);
+else print_esc(/*1729:*/
+#line 26083 "tex.w"
+604
+/*:1729*/
+#line 21321 "tex.w"
+);break;
+case un_vbox:if(chr_code==copy_code)print_esc(/*1732:*/
+#line 26092 "tex.w"
+607
+/*:1732*/
+#line 21322 "tex.w"
+);
+else print_esc(/*1731:*/
+#line 26089 "tex.w"
+606
+/*:1731*/
+#line 21323 "tex.w"
+);break;
+
+/*:1108*//*1115:*/
+#line 21387 "tex.w"
+
+case discretionary:if(chr_code==1)
+print_esc('-');else print_esc(/*1400:*/
+#line 25096 "tex.w"
+275
+/*:1400*/
+#line 21389 "tex.w"
+);break;
+
+/*:1115*//*1143:*/
+#line 21746 "tex.w"
+
+case eq_no:if(chr_code==1)print_esc(/*1734:*/
+#line 26098 "tex.w"
+609
+/*:1734*/
+#line 21747 "tex.w"
+);else print_esc(/*1733:*/
+#line 26095 "tex.w"
+608
+/*:1733*/
+#line 21747 "tex.w"
+);break;
+
+/*:1143*//*1157:*/
+#line 21994 "tex.w"
+
+case math_comp:switch(chr_code){
+case ord_noad:print_esc(/*1649:*/
+#line 25843 "tex.w"
+524
+/*:1649*/
+#line 21996 "tex.w"
+);break;
+case op_noad:print_esc(/*1650:*/
+#line 25846 "tex.w"
+525
+/*:1650*/
+#line 21997 "tex.w"
+);break;
+case bin_noad:print_esc(/*1651:*/
+#line 25849 "tex.w"
+526
+/*:1651*/
+#line 21998 "tex.w"
+);break;
+case rel_noad:print_esc(/*1652:*/
+#line 25852 "tex.w"
+527
+/*:1652*/
+#line 21999 "tex.w"
+);break;
+case open_noad:print_esc(/*1653:*/
+#line 25855 "tex.w"
+528
+/*:1653*/
+#line 22000 "tex.w"
+);break;
+case close_noad:print_esc(/*1654:*/
+#line 25858 "tex.w"
+529
+/*:1654*/
+#line 22001 "tex.w"
+);break;
+case punct_noad:print_esc(/*1655:*/
+#line 25861 "tex.w"
+530
+/*:1655*/
+#line 22002 "tex.w"
+);break;
+case inner_noad:print_esc(/*1656:*/
+#line 25864 "tex.w"
+531
+/*:1656*/
+#line 22003 "tex.w"
+);break;
+case under_noad:print_esc(/*1658:*/
+#line 25870 "tex.w"
+533
+/*:1658*/
+#line 22004 "tex.w"
+);break;
+default:print_esc(/*1657:*/
+#line 25867 "tex.w"
+532
+/*:1657*/
+#line 22005 "tex.w"
+);
+}break;
+case limit_switch:if(chr_code==limits)print_esc(/*1661:*/
+#line 25879 "tex.w"
+536
+/*:1661*/
+#line 22007 "tex.w"
+);
+else if(chr_code==no_limits)print_esc(/*1662:*/
+#line 25882 "tex.w"
+537
+/*:1662*/
+#line 22008 "tex.w"
+);
+else print_esc(/*1735:*/
+#line 26101 "tex.w"
+610
+/*:1735*/
+#line 22009 "tex.w"
+);break;
+
+/*:1157*//*1170:*/
+#line 22130 "tex.w"
+
+case math_style:print_style(chr_code);break;
+
+/*:1170*//*1179:*/
+#line 22233 "tex.w"
+
+case above:switch(chr_code){
+case over_code:print_esc(/*1737:*/
+#line 26107 "tex.w"
+612
+/*:1737*/
+#line 22235 "tex.w"
+);break;
+case atop_code:print_esc(/*1738:*/
+#line 26110 "tex.w"
+613
+/*:1738*/
+#line 22236 "tex.w"
+);break;
+case delimited_code+above_code:print_esc(/*1739:*/
+#line 26113 "tex.w"
+614
+/*:1739*/
+#line 22237 "tex.w"
+);break;
+case delimited_code+over_code:print_esc(/*1740:*/
+#line 26116 "tex.w"
+615
+/*:1740*/
+#line 22238 "tex.w"
+);break;
+case delimited_code+atop_code:print_esc(/*1741:*/
+#line 26119 "tex.w"
+616
+/*:1741*/
+#line 22239 "tex.w"
+);break;
+default:print_esc(/*1736:*/
+#line 26104 "tex.w"
+611
+/*:1736*/
+#line 22240 "tex.w"
+);
+}break;
+
+/*:1179*//*1189:*/
+#line 22354 "tex.w"
+
+case left_right:if(chr_code==left_noad)print_esc(/*1659:*/
+#line 25873 "tex.w"
+534
+/*:1659*/
+#line 22355 "tex.w"
+);
+else print_esc(/*1660:*/
+#line 25876 "tex.w"
+535
+/*:1660*/
+#line 22356 "tex.w"
+);break;
+
+/*:1189*//*1209:*/
+#line 22667 "tex.w"
+
+case prefix:if(chr_code==1)print_esc(/*1743:*/
+#line 26125 "tex.w"
+618
+/*:1743*/
+#line 22668 "tex.w"
+);
+else if(chr_code==2)print_esc(/*1744:*/
+#line 26128 "tex.w"
+619
+/*:1744*/
+#line 22669 "tex.w"
+);
+else print_esc(/*1745:*/
+#line 26131 "tex.w"
+620
+/*:1745*/
+#line 22670 "tex.w"
+);break;
+case def:if(chr_code==0)print_esc(/*1746:*/
+#line 26134 "tex.w"
+621
+/*:1746*/
+#line 22671 "tex.w"
+);
+else if(chr_code==1)print_esc(/*1747:*/
+#line 26137 "tex.w"
+622
+/*:1747*/
+#line 22672 "tex.w"
+);
+else if(chr_code==2)print_esc(/*1748:*/
+#line 26140 "tex.w"
+623
+/*:1748*/
+#line 22673 "tex.w"
+);
+else print_esc(/*1749:*/
+#line 26143 "tex.w"
+624
+/*:1749*/
+#line 22674 "tex.w"
+);break;
+
+/*:1209*//*1220:*/
+#line 22827 "tex.w"
+
+case let:if(chr_code!=normal)print_esc(/*1753:*/
+#line 26155 "tex.w"
+628
+/*:1753*/
+#line 22828 "tex.w"
+);else print_esc(/*1752:*/
+#line 26152 "tex.w"
+627
+/*:1752*/
+#line 22828 "tex.w"
+);break;
+
+/*:1220*//*1223:*/
+#line 22879 "tex.w"
+
+case shorthand_def:switch(chr_code){
+case char_def_code:print_esc(/*1754:*/
+#line 26158 "tex.w"
+629
+/*:1754*/
+#line 22881 "tex.w"
+);break;
+case math_char_def_code:print_esc(/*1755:*/
+#line 26161 "tex.w"
+630
+/*:1755*/
+#line 22882 "tex.w"
+);break;
+case count_def_code:print_esc(/*1756:*/
+#line 26164 "tex.w"
+631
+/*:1756*/
+#line 22883 "tex.w"
+);break;
+case dimen_def_code:print_esc(/*1757:*/
+#line 26167 "tex.w"
+632
+/*:1757*/
+#line 22884 "tex.w"
+);break;
+case skip_def_code:print_esc(/*1758:*/
+#line 26170 "tex.w"
+633
+/*:1758*/
+#line 22885 "tex.w"
+);break;
+case mu_skip_def_code:print_esc(/*1759:*/
+#line 26173 "tex.w"
+634
+/*:1759*/
+#line 22886 "tex.w"
+);break;
+default:print_esc(/*1760:*/
+#line 26176 "tex.w"
+635
+/*:1760*/
+#line 22887 "tex.w"
+);
+}break;
+case char_given:{print_esc(/*1535:*/
+#line 25501 "tex.w"
+410
+/*:1535*/
+#line 22889 "tex.w"
+);print_hex(chr_code);
+}break;
+case math_given:{print_esc(/*1546:*/
+#line 25534 "tex.w"
+421
+/*:1546*/
+#line 22891 "tex.w"
+);print_hex(chr_code);
+}break;
+
+/*:1223*//*1231:*/
+#line 23023 "tex.w"
+
+case def_code:if(chr_code==cat_code_base)print_esc(/*1441:*/
+#line 25219 "tex.w"
+316
+/*:1441*/
+#line 23024 "tex.w"
+);
+else if(chr_code==math_code_base)print_esc(/*1445:*/
+#line 25231 "tex.w"
+320
+/*:1445*/
+#line 23025 "tex.w"
+);
+else if(chr_code==lc_code_base)print_esc(/*1442:*/
+#line 25222 "tex.w"
+317
+/*:1442*/
+#line 23026 "tex.w"
+);
+else if(chr_code==uc_code_base)print_esc(/*1443:*/
+#line 25225 "tex.w"
+318
+/*:1443*/
+#line 23027 "tex.w"
+);
+else if(chr_code==sf_code_base)print_esc(/*1444:*/
+#line 25228 "tex.w"
+319
+/*:1444*/
+#line 23028 "tex.w"
+);
+else print_esc(/*1502:*/
+#line 25402 "tex.w"
+377
+/*:1502*/
+#line 23029 "tex.w"
+);break;
+case def_family:print_size(chr_code-math_font_base);break;
+
+/*:1231*//*1251:*/
+#line 23294 "tex.w"
+
+case hyph_data:if(chr_code==1)print_esc(/*1684:*/
+#line 25948 "tex.w"
+559
+/*:1684*/
+#line 23295 "tex.w"
+);
+else print_esc(/*1683:*/
+#line 25945 "tex.w"
+558
+/*:1683*/
+#line 23296 "tex.w"
+);break;
+
+/*:1251*//*1255:*/
+#line 23331 "tex.w"
+
+case assign_font_int:if(chr_code==0)print_esc(/*1762:*/
+#line 26182 "tex.w"
+637
+/*:1762*/
+#line 23332 "tex.w"
+);
+else print_esc(/*1763:*/
+#line 26185 "tex.w"
+638
+/*:1763*/
+#line 23333 "tex.w"
+);break;
+
+/*:1255*//*1261:*/
+#line 23416 "tex.w"
+
+case set_font:{print_str("select font ");slow_print(font_name[chr_code]);
+if(font_size[chr_code]!=font_dsize[chr_code])
+{print_str(" at ");print_scaled(font_size[chr_code]);
+print_str("pt");
+}
+}break;
+
+/*:1261*//*1263:*/
+#line 23434 "tex.w"
+
+case set_interaction:switch(chr_code){
+case batch_mode:print_esc(/*1383:*/
+#line 25045 "tex.w"
+258
+/*:1383*/
+#line 23436 "tex.w"
+);break;
+case nonstop_mode:print_esc(/*1384:*/
+#line 25048 "tex.w"
+259
+/*:1384*/
+#line 23437 "tex.w"
+);break;
+case scroll_mode:print_esc(/*1385:*/
+#line 25051 "tex.w"
+260
+/*:1385*/
+#line 23438 "tex.w"
+);break;
+default:print_esc(/*1767:*/
+#line 26197 "tex.w"
+642
+/*:1767*/
+#line 23439 "tex.w"
+);
+}break;
+
+/*:1263*//*1273:*/
+#line 23496 "tex.w"
+
+case in_stream:if(chr_code==0)print_esc(/*1769:*/
+#line 26203 "tex.w"
+644
+/*:1769*/
+#line 23497 "tex.w"
+);
+else print_esc(/*1768:*/
+#line 26200 "tex.w"
+643
+/*:1768*/
+#line 23498 "tex.w"
+);break;
+
+/*:1273*//*1278:*/
+#line 23531 "tex.w"
+
+case message:if(chr_code==0)print_esc(/*1770:*/
+#line 26206 "tex.w"
+645
+/*:1770*/
+#line 23532 "tex.w"
+);
+else print_esc(/*1771:*/
+#line 26209 "tex.w"
+646
+/*:1771*/
+#line 23533 "tex.w"
+);break;
+
+/*:1278*//*1287:*/
+#line 23598 "tex.w"
+
+case case_shift:if(chr_code==lc_code_base)print_esc(/*1772:*/
+#line 26212 "tex.w"
+647
+/*:1772*/
+#line 23599 "tex.w"
+);
+else print_esc(/*1773:*/
+#line 26215 "tex.w"
+648
+/*:1773*/
+#line 23600 "tex.w"
+);break;
+
+/*:1287*//*1292:*/
+#line 23649 "tex.w"
+
+case xray:switch(chr_code){
+case show_box_code:print_esc(/*1775:*/
+#line 26221 "tex.w"
+650
+/*:1775*/
+#line 23651 "tex.w"
+);break;
+case show_the_code:print_esc(/*1776:*/
+#line 26224 "tex.w"
+651
+/*:1776*/
+#line 23652 "tex.w"
+);break;
+case show_lists:print_esc(/*1777:*/
+#line 26227 "tex.w"
+652
+/*:1777*/
+#line 23653 "tex.w"
+);break;
+default:print_esc(/*1774:*/
+#line 26218 "tex.w"
+649
+/*:1774*/
+#line 23654 "tex.w"
+);
+}break;
+
+/*:1292*//*1295:*/
+#line 23698 "tex.w"
+
+case undefined_cs:print_str("undefined");break;
+case call:print_str("macro");break;
+case long_call:print_esc(/*1778:*/
+#line 26230 "tex.w"
+653
+/*:1778*/
+#line 23701 "tex.w"
+);break;
+case outer_call:print_esc(/*1779:*/
+#line 26233 "tex.w"
+654
+/*:1779*/
+#line 23702 "tex.w"
+);break;
+case long_outer_call:{print_esc(/*1743:*/
+#line 26125 "tex.w"
+618
+/*:1743*/
+#line 23703 "tex.w"
+);print_esc(/*1779:*/
+#line 26233 "tex.w"
+654
+/*:1779*/
+#line 23703 "tex.w"
+);
+}break;
+case end_template:print_esc(/*1780:*/
+#line 26236 "tex.w"
+655
+/*:1780*/
+#line 23705 "tex.w"
+);break;
+
+/*:1295*//*1346:*/
+#line 24646 "tex.w"
+
+case extension:switch(chr_code){
+case open_node:print_esc(/*1783:*/
+#line 26245 "tex.w"
+658
+/*:1783*/
+#line 24648 "tex.w"
+);break;
+case write_node:print_esc(/*1568:*/
+#line 25600 "tex.w"
+443
+/*:1568*/
+#line 24649 "tex.w"
+);break;
+case close_node:print_esc(/*1784:*/
+#line 26248 "tex.w"
+659
+/*:1784*/
+#line 24650 "tex.w"
+);break;
+case special_node:print_esc(/*1785:*/
+#line 26251 "tex.w"
+660
+/*:1785*/
+#line 24651 "tex.w"
+);break;
+case immediate_code:print_esc(/*1786:*/
+#line 26254 "tex.w"
+661
+/*:1786*/
+#line 24652 "tex.w"
+);break;
+case set_language_code:print_esc(/*1787:*/
+#line 26257 "tex.w"
+662
+/*:1787*/
+#line 24653 "tex.w"
+);break;
+default:print_str("[unknown extension!]");
+}break;
+
+/*:1346*/
+#line 6476 "tex.w"
+
+default:print_str("[unknown command code!]");
+}
+}
+
+/*:298*/
+#line 5484 "tex.w"
+
+#ifdef STAT
+void show_eqtb(pointer n)
+{if(n<active_base)print_char('?');
+else if(n<glue_base)/*223:*/
+#line 4607 "tex.w"
+
+{sprint_cs(n);print_char('=');print_cmd_chr(eq_type(n),equiv(n));
+if(eq_type(n)>=call)
+{print_char(':');show_token_list(link(equiv(n)),null,32);
+}
+}
+
+/*:223*/
+#line 5488 "tex.w"
+
+else if(n<local_base)/*229:*/
+#line 4757 "tex.w"
+
+if(n<skip_base)
+{print_skip_param(n-glue_base);print_char('=');
+if(n<glue_base+thin_mu_skip_code)print_spec(equiv(n),/*1425:*/
+#line 25171 "tex.w"
+300
+/*:1425*/
+#line 4760 "tex.w"
+);
+else print_spec(equiv(n),/*1394:*/
+#line 25078 "tex.w"
+269
+/*:1394*/
+#line 4761 "tex.w"
+);
+}
+else if(n<mu_skip_base)
+{print_esc(/*1423:*/
+#line 25165 "tex.w"
+298
+/*:1423*/
+#line 4764 "tex.w"
+);print_int(n-skip_base);print_char('=');
+print_spec(equiv(n),/*1425:*/
+#line 25171 "tex.w"
+300
+/*:1425*/
+#line 4765 "tex.w"
+);
+}
+else{print_esc(/*1424:*/
+#line 25168 "tex.w"
+299
+/*:1424*/
+#line 4767 "tex.w"
+);print_int(n-mu_skip_base);print_char('=');
+print_spec(equiv(n),/*1394:*/
+#line 25078 "tex.w"
+269
+/*:1394*/
+#line 4768 "tex.w"
+);
+}
+
+/*:229*/
+#line 5489 "tex.w"
+
+else if(n<int_base)/*233:*/
+#line 4899 "tex.w"
+
+if(n==par_shape_loc)
+{print_esc(/*1436:*/
+#line 25204 "tex.w"
+311
+/*:1436*/
+#line 4901 "tex.w"
+);print_char('=');
+if(par_shape_ptr==null)print_char('0');
+else print_int(info(par_shape_ptr));
+}
+else if(n<toks_base)
+{print_cmd_chr(assign_toks,n);print_char('=');
+if(equiv(n)!=null)show_token_list(link(equiv(n)),null,32);
+}
+else if(n<box_base)
+{print_esc(/*1435:*/
+#line 25201 "tex.w"
+310
+/*:1435*/
+#line 4910 "tex.w"
+);print_int(n-toks_base);print_char('=');
+if(equiv(n)!=null)show_token_list(link(equiv(n)),null,32);
+}
+else if(n<cur_font_loc)
+{print_esc(/*1437:*/
+#line 25207 "tex.w"
+312
+/*:1437*/
+#line 4914 "tex.w"
+);print_int(n-box_base);print_char('=');
+if(equiv(n)==null)print_str("void");
+else{depth_threshold= 0;breadth_max= 1;show_node_list(equiv(n));
+}
+}
+else if(n<cat_code_base)/*234:*/
+#line 4922 "tex.w"
+
+{if(n==cur_font_loc)print_str("current font");
+else if(n<math_font_base+16)
+{print_esc(/*1438:*/
+#line 25210 "tex.w"
+313
+/*:1438*/
+#line 4925 "tex.w"
+);print_int(n-math_font_base);
+}
+else if(n<math_font_base+32)
+{print_esc(/*1439:*/
+#line 25213 "tex.w"
+314
+/*:1439*/
+#line 4928 "tex.w"
+);print_int(n-math_font_base-16);
+}
+else{print_esc(/*1440:*/
+#line 25216 "tex.w"
+315
+/*:1440*/
+#line 4930 "tex.w"
+);print_int(n-math_font_base-32);
+}
+print_char('=');
+print_esc(hash[font_id_base+equiv(n)].rh);
+
+}
+
+/*:234*/
+#line 4919 "tex.w"
+
+else/*235:*/
+#line 4937 "tex.w"
+
+if(n<math_code_base)
+{if(n<lc_code_base)
+{print_esc(/*1441:*/
+#line 25219 "tex.w"
+316
+/*:1441*/
+#line 4940 "tex.w"
+);print_int(n-cat_code_base);
+}
+else if(n<uc_code_base)
+{print_esc(/*1442:*/
+#line 25222 "tex.w"
+317
+/*:1442*/
+#line 4943 "tex.w"
+);print_int(n-lc_code_base);
+}
+else if(n<sf_code_base)
+{print_esc(/*1443:*/
+#line 25225 "tex.w"
+318
+/*:1443*/
+#line 4946 "tex.w"
+);print_int(n-uc_code_base);
+}
+else{print_esc(/*1444:*/
+#line 25228 "tex.w"
+319
+/*:1444*/
+#line 4948 "tex.w"
+);print_int(n-sf_code_base);
+}
+print_char('=');print_int(equiv(n));
+}
+else{print_esc(/*1445:*/
+#line 25231 "tex.w"
+320
+/*:1445*/
+#line 4952 "tex.w"
+);print_int(n-math_code_base);
+print_char('=');print_int(ho(equiv(n)));
+}
+
+/*:235*/
+#line 4920 "tex.w"
+
+
+/*:233*/
+#line 5490 "tex.w"
+
+else if(n<dimen_base)/*242:*/
+#line 5300 "tex.w"
+
+{if(n<count_base)print_param(n-int_base);
+else if(n<del_code_base)
+{print_esc(/*1501:*/
+#line 25399 "tex.w"
+376
+/*:1501*/
+#line 5303 "tex.w"
+);print_int(n-count_base);
+}
+else{print_esc(/*1502:*/
+#line 25402 "tex.w"
+377
+/*:1502*/
+#line 5305 "tex.w"
+);print_int(n-del_code_base);
+}
+print_char('=');print_int(eqtb[n].i);
+}
+
+/*:242*/
+#line 5491 "tex.w"
+
+else if(n<=eqtb_size)/*251:*/
+#line 5474 "tex.w"
+
+{if(n<scaled_base)print_length_param(n-dimen_base);
+else{print_esc(/*1524:*/
+#line 25468 "tex.w"
+399
+/*:1524*/
+#line 5476 "tex.w"
+);print_int(n-scaled_base);
+}
+print_char('=');print_scaled(eqtb[n].sc);print_str("pt");
+}
+
+/*:251*/
+#line 5492 "tex.w"
+
+else print_char('?');
+}
+#endif
+
+/*:252*//*259:*/
+#line 5577 "tex.w"
+pointer id_lookup(int j,int l)
+{
+int h;
+int d;
+pointer p;
+pointer k;
+/*261:*/
+#line 5624 "tex.w"
+
+h= buffer[j];
+for(k= j+1;k<=j+l-1;k++)
+{h= h+h+buffer[k];
+while(h>=hash_prime)h= h-hash_prime;
+}
+
+/*:261*/
+#line 5583 "tex.w"
+;
+p= h+hash_base;
+loop{if(text(p)> 0)if(length(text(p))==l)
+if(str_eq_buf(text(p),j))goto found;
+if(next(p)==0)
+{if(no_new_control_sequence)
+p= undefined_control_sequence;
+else/*260:*/
+#line 5598 "tex.w"
+
+{if(text(p)> 0)
+{do{if(hash_is_full)overflow("hash size",hash_size);
+
+decr(hash_used);
+}while(!(text(hash_used)==0));
+next(p)= hash_used;p= hash_used;
+}
+str_room(l);d= cur_length;
+while(pool_ptr> str_start[str_ptr])
+{decr(pool_ptr);str_pool[pool_ptr+l]= str_pool[pool_ptr];
+}
+for(k= j;k<=j+l-1;k++)append_char(buffer[k]);
+text(p)= make_string();pool_ptr= pool_ptr+d;
+#ifdef STAT
+incr(cs_count);
+#endif
+
+}
+
+/*:260*/
+#line 5590 "tex.w"
+;
+goto found;
+}
+p= next(p);
+}
+found:return p;
+}
+
+/*:259*//*264:*/
+#line 5680 "tex.w"
+
+#ifdef INIT
+void primitive(str_number s,quarterword c,halfword o)
+{pool_pointer k;
+int j;
+small_number l;
+if(s<256)cur_val= s+single_base;
+else{k= str_start[s];l= str_start[s+1]-k;
+
+for(j= 0;j<=l-1;j++)buffer[j]= so(str_pool[k+j]);
+cur_val= id_lookup(0,l);
+flush_string;text(cur_val)= s;
+}
+eq_level(cur_val)= level_one;eq_type(cur_val)= c;equiv(cur_val)= o;
+}
+#endif
+
+/*:264*//*274:*/
+#line 5987 "tex.w"
+void new_save_level(group_code c)
+{check_full_save_stack;
+save_type(save_ptr)= level_boundary;save_level(save_ptr)= cur_group;
+save_index(save_ptr)= cur_boundary;
+if(cur_level==max_quarterword)overflow("grouping levels",
+
+max_quarterword-min_quarterword);
+
+cur_boundary= save_ptr;incr(cur_level);incr(save_ptr);cur_group= c;
+}
+
+/*:274*//*275:*/
+#line 6004 "tex.w"
+void eq_destroy(memory_word w)
+{pointer q;
+switch(eq_type_field(w)){
+case call:case long_call:case outer_call:case long_outer_call:delete_token_ref(equiv_field(w));break;
+case glue_ref:delete_glue_ref(equiv_field(w));break;
+case shape_ref:{q= equiv_field(w);
+if(q!=null)free_node(q,info(q)+info(q)+1);
+}break;
+case box_ref:flush_node_list(equiv_field(w));break;
+default:do_nothing;
+}
+}
+
+/*:275*//*276:*/
+#line 6020 "tex.w"
+void eq_save(pointer p,quarterword l)
+{check_full_save_stack;
+if(l==level_zero)save_type(save_ptr)= restore_zero;
+else{save_stack[save_ptr]= eqtb[p];incr(save_ptr);
+save_type(save_ptr)= restore_old_value;
+}
+save_level(save_ptr)= l;save_index(save_ptr)= p;incr(save_ptr);
+}
+
+/*:276*//*277:*/
+#line 6037 "tex.w"
+void eq_define(pointer p,quarterword t,halfword e)
+
+{if(eq_level(p)==cur_level)eq_destroy(eqtb[p]);
+else if(cur_level> level_one)eq_save(p,eq_level(p));
+eq_level(p)= cur_level;eq_type(p)= t;equiv(p)= e;
+}
+
+/*:277*//*278:*/
+#line 6048 "tex.w"
+void eq_word_define(pointer p,int w)
+{if(xeq_level[p]!=cur_level)
+{eq_save(p,xeq_level[p]);xeq_level[p]= cur_level;
+}
+eqtb[p].i= w;
+}
+
+/*:278*//*279:*/
+#line 6060 "tex.w"
+void geq_define(pointer p,quarterword t,halfword e)
+
+{eq_destroy(eqtb[p]);
+eq_level(p)= level_one;eq_type(p)= t;equiv(p)= e;
+}
+
+void geq_word_define(pointer p,int w)
+{eqtb[p].i= w;xeq_level[p]= level_one;
+}
+
+/*:279*//*280:*/
+#line 6072 "tex.w"
+void save_for_after(halfword t)
+{if(cur_level> level_one)
+{check_full_save_stack;
+save_type(save_ptr)= insert_token;save_level(save_ptr)= level_zero;
+save_index(save_ptr)= t;incr(save_ptr);
+}
+}
+
+/*:280*//*281:*/
+#line 6084 "tex.w"
+/*284:*/
+#line 6155 "tex.w"
+
+#ifdef STAT
+void restore_trace(pointer p,str_number s)
+
+{begin_diagnostic();print_char('{');print(s);print_char(' ');
+show_eqtb(p);print_char('}');
+end_diagnostic(false);
+}
+#endif
+
+/*:284*/
+#line 6084 "tex.w"
+
+void back_input(void);
+void unsave(void)
+{
+pointer p;
+quarterword l;
+halfword t;
+if(cur_level> level_one)
+{decr(cur_level);
+/*282:*/
+#line 6099 "tex.w"
+
+loop{decr(save_ptr);
+if(save_type(save_ptr)==level_boundary)goto done;
+p= save_index(save_ptr);
+if(save_type(save_ptr)==insert_token)
+/*326:*/
+#line 7097 "tex.w"
+
+{t= cur_tok;cur_tok= p;back_input();cur_tok= t;
+}
+
+/*:326*/
+#line 6104 "tex.w"
+
+else{if(save_type(save_ptr)==restore_old_value)
+{l= save_level(save_ptr);decr(save_ptr);
+}
+else save_stack[save_ptr]= eqtb[undefined_control_sequence];
+/*283:*/
+#line 6121 "tex.w"
+
+if(p<int_base)
+if(eq_level(p)==level_one)
+{eq_destroy(save_stack[save_ptr]);
+
+#ifdef STAT
+if(tracing_restores> 0)restore_trace(p,/*1564:*/
+#line 25588 "tex.w"
+439
+/*:1564*/
+#line 6127 "tex.w"
+);
+#endif
+
+}
+else{eq_destroy(eqtb[p]);
+eqtb[p]= save_stack[save_ptr];
+
+#ifdef STAT
+if(tracing_restores> 0)restore_trace(p,/*1565:*/
+#line 25591 "tex.w"
+440
+/*:1565*/
+#line 6135 "tex.w"
+);
+#endif
+
+}
+else if(xeq_level[p]!=level_one)
+{eqtb[p]= save_stack[save_ptr];xeq_level[p]= l;
+
+#ifdef STAT
+if(tracing_restores> 0)restore_trace(p,/*1565:*/
+#line 25591 "tex.w"
+440
+/*:1565*/
+#line 6143 "tex.w"
+);
+#endif
+
+}
+else{
+
+#ifdef STAT
+if(tracing_restores> 0)restore_trace(p,/*1564:*/
+#line 25588 "tex.w"
+439
+/*:1564*/
+#line 6150 "tex.w"
+);
+#endif
+
+}
+
+/*:283*/
+#line 6110 "tex.w"
+;
+}
+}
+done:cur_group= save_level(save_ptr);cur_boundary= save_index(save_ptr)
+
+/*:282*/
+#line 6093 "tex.w"
+;
+}
+else confusion(/*1563:*/
+#line 25585 "tex.w"
+438
+/*:1563*/
+#line 6095 "tex.w"
+);
+
+}
+
+/*:281*//*288:*/
+#line 6194 "tex.w"
+void prepare_mag(void)
+{if((mag_set> 0)&&(mag!=mag_set))
+{print_err("Incompatible magnification (");print_int(mag);
+
+print_str(");");print_nl(" the previous value will be retained");
+help2("I can handle only one magnification ratio per job. So I've")
+("reverted to the magnification you used earlier on this run.");
+int_error(mag_set);
+geq_word_define(int_base+mag_code,mag_set);
+}
+if((mag<=0)||(mag> 32768))
+{print_err("Illegal magnification has been changed to 1000");
+
+help1("The magnification ratio must be between 1 and 32768.");
+int_error(mag);geq_word_define(int_base+mag_code,1000);
+}
+mag_set= mag;
+}
+
+/*:288*//*295:*/
+#line 6378 "tex.w"
+void token_show(pointer p)
+{if(p!=null)show_token_list(link(p),null,10000000);
+}
+
+/*:295*//*296:*/
+#line 6385 "tex.w"
+void print_meaning(void)
+{print_cmd_chr(cur_cmd,cur_chr);
+if(cur_cmd>=call)
+{print_char(':');print_ln();token_show(cur_chr);
+}
+else if(cur_cmd==top_bot_mark)
+{print_char(':');print_ln();
+token_show(cur_mark[cur_chr]);
+}
+}
+
+/*:296*//*299:*/
+#line 6483 "tex.w"
+void show_cur_cmd_chr(void)
+{begin_diagnostic();print_nl("{");
+if(mode!=shown_mode)
+{print_mode(mode);print_str(": ");shown_mode= mode;
+}
+print_cmd_chr(cur_cmd,cur_chr);print_char('}');
+end_diagnostic(false);
+}
+
+/*:299*//*311:*/
+#line 6827 "tex.w"
+void show_context(void)
+{
+uint8_t old_setting;
+int nn;
+bool bottom_line;
+/*315:*/
+#line 6939 "tex.w"
+
+int i;
+uint16_t j;
+uint8_t l;
+int m;
+uint8_t n;
+int p;
+int q;
+
+/*:315*/
+#line 6832 "tex.w"
+
+base_ptr= input_ptr;input_stack[base_ptr]= cur_input;
+
+nn= -1;bottom_line= false;
+loop{cur_input= input_stack[base_ptr];
+if((state!=token_list))
+if((name> 17)||(base_ptr==0))bottom_line= true;
+if((base_ptr==input_ptr)||bottom_line||(nn<error_context_lines))
+/*312:*/
+#line 6850 "tex.w"
+
+{if((base_ptr==input_ptr)||(state!=token_list)||
+(token_type!=backed_up)||(loc!=null))
+
+{tally= 0;
+old_setting= selector;
+if(state!=token_list)
+{/*313:*/
+#line 6874 "tex.w"
+
+if(name<=17)
+if(terminal_input)
+if(base_ptr==0)print_nl("<*>");else print_nl("<insert> ");
+else{print_nl("<read ");
+if(name==17)print_char('*');else print_int(name-1);
+
+print_char('>');
+}
+else{print_nl("l.");print_int(line);
+}
+print_char(' ')
+
+/*:313*/
+#line 6857 "tex.w"
+;
+/*318:*/
+#line 6985 "tex.w"
+
+begin_pseudoprint;
+if(buffer[limit]==end_line_char)j= limit;
+else j= limit+1;
+if(j> 0)for(i= start;i<=j-1;i++)
+{if(i==loc)set_trick_count;
+print(buffer[i]);
+}
+
+/*:318*/
+#line 6858 "tex.w"
+;
+}
+else{/*314:*/
+#line 6887 "tex.w"
+
+switch(token_type){
+case parameter:print_nl("<argument> ");break;
+case u_template:case v_template:print_nl("<template> ");break;
+case backed_up:if(loc==null)print_nl("<recently read> ");
+else print_nl("<to be read again> ");break;
+case inserted:print_nl("<inserted text> ");break;
+case macro:{print_ln();print_cs(name);
+}break;
+case output_text:print_nl("<output> ");break;
+case every_par_text:print_nl("<everypar> ");break;
+case every_math_text:print_nl("<everymath> ");break;
+case every_display_text:print_nl("<everydisplay> ");break;
+case every_hbox_text:print_nl("<everyhbox> ");break;
+case every_vbox_text:print_nl("<everyvbox> ");break;
+case every_job_text:print_nl("<everyjob> ");break;
+case every_cr_text:print_nl("<everycr> ");break;
+case mark_text:print_nl("<mark> ");break;
+case write_text:print_nl("<write> ");break;
+default:print_nl("?");
+}
+
+/*:314*/
+#line 6860 "tex.w"
+;
+/*319:*/
+#line 6994 "tex.w"
+
+begin_pseudoprint;
+if(token_type<macro)show_token_list(start,loc,100000);
+else show_token_list(link(start),loc,100000)
+
+/*:319*/
+#line 6861 "tex.w"
+;
+}
+selector= old_setting;
+/*317:*/
+#line 6963 "tex.w"
+
+if(trick_count==1000000)set_trick_count;
+
+if(tally<trick_count)m= tally-first_count;
+else m= trick_count-first_count;
+if(l+first_count<=half_error_line)
+{p= 0;n= l+first_count;
+}
+else{print_str("...");p= l+first_count-half_error_line+3;
+n= half_error_line;
+}
+for(q= p;q<=first_count-1;q++)print_char(trick_buf[q%error_line]);
+print_ln();
+for(q= 1;q<=n;q++)print_char(' ');
+if(m+n<=error_line)p= first_count+m;else p= first_count+(error_line-n-3);
+for(q= first_count;q<=p-1;q++)print_char(trick_buf[q%error_line]);
+if(m+n> error_line)print_str("...")
+
+/*:317*/
+#line 6864 "tex.w"
+;
+incr(nn);
+}
+}
+
+/*:312*/
+#line 6840 "tex.w"
+
+else if(nn==error_context_lines)
+{print_nl("...");incr(nn);
+}
+if(bottom_line)goto done;
+decr(base_ptr);
+}
+done:cur_input= input_stack[input_ptr];
+}
+
+/*:311*//*323:*/
+#line 7033 "tex.w"
+void begin_token_list(pointer p,quarterword t)
+{push_input;state= token_list;start= p;token_type= t;
+if(t>=macro)
+{add_token_ref(p);
+if(t==macro)param_start= param_ptr;
+else{loc= link(p);
+if(tracing_macros> 1)
+{begin_diagnostic();print_nl("");
+switch(t){
+case mark_text:print_esc(/*1401:*/
+#line 25099 "tex.w"
+276
+/*:1401*/
+#line 7042 "tex.w"
+);break;
+case write_text:print_esc(/*1568:*/
+#line 25600 "tex.w"
+443
+/*:1568*/
+#line 7043 "tex.w"
+);break;
+default:print_cmd_chr(assign_toks,t-output_text+output_routine_loc);
+}
+print_str("->");token_show(p);end_diagnostic(false);
+}
+}
+}
+else loc= p;
+}
+
+/*:323*//*324:*/
+#line 7058 "tex.w"
+void end_token_list(void)
+{if(token_type>=backed_up)
+{if(token_type<=inserted)flush_list(start);
+else{delete_token_ref(start);
+if(token_type==macro)
+while(param_ptr> param_start)
+{decr(param_ptr);
+flush_list(param_stack[param_ptr]);
+}
+}
+}
+else if(token_type==u_template)
+if(align_state> 500000)align_state= 0;
+else fatal_error("(interwoven alignment preambles are not allowed)");
+
+pop_input;
+check_interrupt;
+}
+
+/*:324*//*325:*/
+#line 7085 "tex.w"
+void back_input(void)
+{pointer p;
+while((state==token_list)&&(loc==null)&&(token_type!=v_template))
+end_token_list();
+p= get_avail();info(p)= cur_tok;
+if(cur_tok<right_brace_limit)
+if(cur_tok<left_brace_limit)decr(align_state);
+else incr(align_state);
+push_input;state= token_list;start= p;token_type= backed_up;
+loc= p;
+}
+
+/*:325*//*327:*/
+#line 7106 "tex.w"
+void back_error(void)
+{OK_to_interrupt= false;back_input();OK_to_interrupt= true;error();
+}
+
+void ins_error(void)
+{OK_to_interrupt= false;back_input();token_type= inserted;
+OK_to_interrupt= true;error();
+}
+
+/*:327*//*328:*/
+#line 7121 "tex.w"
+void begin_file_reading(void)
+{if(in_open==max_in_open)overflow("text input levels",max_in_open);
+
+if(first==buf_size)overflow("buffer size",buf_size);
+
+incr(in_open);push_input;index= in_open;
+line_stack[index]= line;start= first;state= mid_line;
+name= 0;
+}
+
+/*:328*//*329:*/
+#line 7134 "tex.w"
+void end_file_reading(void)
+{first= start;line= line_stack[index];
+if(name> 17)a_close(&cur_file);
+pop_input;decr(in_open);
+}
+
+/*:329*//*330:*/
+#line 7144 "tex.w"
+void clear_for_error_prompt(void)
+{while((state!=token_list)&&terminal_input&&
+(input_ptr> 0)&&(loc> limit))end_file_reading();
+print_ln();clear_terminal;
+}
+
+/*:330*//*336:*/
+#line 7211 "tex.w"
+void check_outer_validity(void)
+{pointer p;
+pointer q;
+if(scanner_status!=normal)
+{deletions_allowed= false;
+/*337:*/
+#line 7237 "tex.w"
+
+if(cur_cs!=0)
+{if((state==token_list)||(name<1)||(name> 17))
+{p= get_avail();info(p)= cs_token_flag+cur_cs;
+back_list(p);
+}
+cur_cmd= spacer;cur_chr= ' ';
+}
+
+/*:337*/
+#line 7216 "tex.w"
+;
+if(scanner_status> skipping)
+/*338:*/
+#line 7246 "tex.w"
+
+{runaway();
+if(cur_cs==0)print_err("File ended")
+
+else{cur_cs= 0;print_err("Forbidden control sequence found");
+
+}
+print_str(" while scanning ");
+/*339:*/
+#line 7271 "tex.w"
+
+p= get_avail();
+switch(scanner_status){
+case defining:{print_str("definition");info(p)= right_brace_token+'}';
+}break;
+case matching:{print_str("use");info(p)= par_token;long_state= outer_call;
+}break;
+case aligning:{print_str("preamble");info(p)= right_brace_token+'}';q= p;
+p= get_avail();link(p)= q;info(p)= cs_token_flag+frozen_cr;
+align_state= -1000000;
+}break;
+case absorbing:{print_str("text");info(p)= right_brace_token+'}';
+}
+}
+ins_list(p)
+
+/*:339*/
+#line 7255 "tex.w"
+;
+print_str(" of ");sprint_cs(warning_index);
+help4("I suspect you have forgotten a `}', causing me")
+("to read past where you wanted me to stop.")
+("I'll try to recover; but if the error is serious,")
+("you'd better type `E' or `X' now and fix your file.");
+error();
+}
+
+/*:338*/
+#line 7218 "tex.w"
+
+else{print_err("Incomplete ");print_cmd_chr(if_test,cur_if);
+
+print_str("; all text was ignored after line ");print_int(skip_line);
+help3("A forbidden control sequence occurred in skipped text.")
+("This kind of error happens when you say `\\if...' and forget")
+("the matching `\\fi'. I've inserted a `\\fi'; this might work.");
+if(cur_cs!=0)cur_cs= 0;
+else help_line[2]=
+"The file ended while I was skipping conditional text.";
+cur_tok= cs_token_flag+frozen_fi;ins_error();
+}
+deletions_allowed= true;
+}
+}
+
+/*:336*//*340:*/
+#line 7289 "tex.w"
+void firm_up_the_line(void);
+
+/*:340*//*341:*/
+#line 7295 "tex.w"
+void get_next(void)
+{
+
+
+
+
+
+uint16_t k;
+halfword t;
+uint8_t cat;
+ASCII_code c,cc;
+uint8_t d;
+restart:cur_cs= 0;
+if(state!=token_list)
+/*343:*/
+#line 7325 "tex.w"
+
+
+{get_cur_chr:if(loc<=limit)
+{cur_chr= buffer[loc];incr(loc);
+reswitch:cur_cmd= cat_code(cur_chr);
+/*344:*/
+#line 7349 "tex.w"
+
+switch(state+cur_cmd){
+/*345:*/
+#line 7363 "tex.w"
+
+any_state_plus(ignore):case skip_blanks+spacer:case new_line+spacer
+
+/*:345*/
+#line 7351 "tex.w"
+:goto get_cur_chr;
+any_state_plus(escape):/*354:*/
+#line 7469 "tex.w"
+
+{if(loc> limit)cur_cs= null_cs;
+else{start_cs:k= loc;cur_chr= buffer[k];cat= cat_code(cur_chr);
+incr(k);
+if(cat==letter)state= skip_blanks;
+else if(cat==spacer)state= skip_blanks;
+else state= mid_line;
+if((cat==letter)&&(k<=limit))
+/*356:*/
+#line 7515 "tex.w"
+
+{do{cur_chr= buffer[k];cat= cat_code(cur_chr);incr(k);
+}while(!((cat!=letter)||(k> limit)));
+/*355:*/
+#line 7494 "tex.w"
+
+{if(buffer[k]==cur_chr)if(cat==sup_mark)if(k<limit)
+{c= buffer[k+1];if(c<0200)
+{d= 2;
+if(is_hex(c))if(k+2<=limit)
+{cc= buffer[k+2];if(is_hex(cc))incr(d);
+}
+if(d> 2)
+{hex_to_cur_chr;buffer[k-1]= cur_chr;
+}
+else if(c<0100)buffer[k-1]= c+0100;
+else buffer[k-1]= c-0100;
+limit= limit-d;first= first-d;
+while(k<=limit)
+{buffer[k]= buffer[k+d];incr(k);
+}
+goto start_cs;
+}
+}
+}
+
+/*:355*/
+#line 7518 "tex.w"
+;
+if(cat!=letter)decr(k);
+
+if(k> loc+1)
+{cur_cs= id_lookup(loc,k-loc);loc= k;goto found;
+}
+}
+
+/*:356*/
+#line 7479 "tex.w"
+
+else/*355:*/
+#line 7494 "tex.w"
+
+{if(buffer[k]==cur_chr)if(cat==sup_mark)if(k<limit)
+{c= buffer[k+1];if(c<0200)
+{d= 2;
+if(is_hex(c))if(k+2<=limit)
+{cc= buffer[k+2];if(is_hex(cc))incr(d);
+}
+if(d> 2)
+{hex_to_cur_chr;buffer[k-1]= cur_chr;
+}
+else if(c<0100)buffer[k-1]= c+0100;
+else buffer[k-1]= c-0100;
+limit= limit-d;first= first-d;
+while(k<=limit)
+{buffer[k]= buffer[k+d];incr(k);
+}
+goto start_cs;
+}
+}
+}
+
+/*:355*/
+#line 7480 "tex.w"
+;
+cur_cs= single_base+buffer[loc];incr(loc);
+}
+found:cur_cmd= eq_type(cur_cs);cur_chr= equiv(cur_cs);
+if(cur_cmd>=outer_call)check_outer_validity();
+}
+
+/*:354*/
+#line 7353 "tex.w"
+break;
+any_state_plus(active_char):/*353:*/
+#line 7448 "tex.w"
+
+{cur_cs= cur_chr+active_base;
+cur_cmd= eq_type(cur_cs);cur_chr= equiv(cur_cs);state= mid_line;
+if(cur_cmd>=outer_call)check_outer_validity();
+}
+
+/*:353*/
+#line 7355 "tex.w"
+break;
+any_state_plus(sup_mark):/*352:*/
+#line 7432 "tex.w"
+
+{if(cur_chr==buffer[loc])if(loc<limit)
+{c= buffer[loc+1];if(c<0200)
+{loc= loc+2;
+if(is_hex(c))if(loc<=limit)
+{cc= buffer[loc];if(is_hex(cc))
+{incr(loc);hex_to_cur_chr;goto reswitch;
+}
+}
+if(c<0100)cur_chr= c+0100;else cur_chr= c-0100;
+goto reswitch;
+}
+}
+state= mid_line;
+}
+
+/*:352*/
+#line 7357 "tex.w"
+break;
+any_state_plus(invalid_char):/*346:*/
+#line 7370 "tex.w"
+
+{print_err("Text line contains an invalid character");
+
+help2("A funny symbol that I can't read has just been input.")
+("Continue, and I'll forget that it ever happened.");
+deletions_allowed= false;error();deletions_allowed= true;
+goto restart;
+}
+
+/*:346*/
+#line 7358 "tex.w"
+
+/*347:*/
+#line 7382 "tex.w"
+
+case mid_line+spacer:/*349:*/
+#line 7410 "tex.w"
+
+{state= skip_blanks;cur_chr= ' ';
+}
+
+/*:349*/
+#line 7383 "tex.w"
+break;
+case mid_line+car_ret:/*348:*/
+#line 7404 "tex.w"
+
+{loc= limit+1;cur_cmd= spacer;cur_chr= ' ';
+}
+
+/*:348*/
+#line 7384 "tex.w"
+break;
+case skip_blanks+car_ret:any_state_plus(comment):
+/*350:*/
+#line 7414 "tex.w"
+
+{loc= limit+1;goto get_cur_chr;
+}
+
+/*:350*/
+#line 7386 "tex.w"
+
+case new_line+car_ret:/*351:*/
+#line 7418 "tex.w"
+
+{loc= limit+1;cur_cs= par_loc;cur_cmd= eq_type(cur_cs);
+cur_chr= equiv(cur_cs);
+if(cur_cmd>=outer_call)check_outer_validity();
+}
+
+/*:351*/
+#line 7387 "tex.w"
+break;
+case mid_line+left_brace:incr(align_state);break;
+case skip_blanks+left_brace:case new_line+left_brace:{
+state= mid_line;incr(align_state);
+}break;
+case mid_line+right_brace:decr(align_state);break;
+case skip_blanks+right_brace:case new_line+right_brace:{
+state= mid_line;decr(align_state);
+}break;
+add_delims_to(case skip_blanks):add_delims_to(case new_line):state= mid_line;break;
+
+/*:347*/
+#line 7359 "tex.w"
+
+default:do_nothing;
+}
+
+/*:344*/
+#line 7331 "tex.w"
+;
+}
+else{state= new_line;
+/*360:*/
+#line 7578 "tex.w"
+
+if(name> 17)/*362:*/
+#line 7614 "tex.w"
+
+{incr(line);first= start;
+if(!force_eof)
+{if(input_ln(&cur_file,true))
+firm_up_the_line();
+else force_eof= true;
+}
+if(force_eof)
+{print_char(')');decr(open_parens);
+update_terminal;
+force_eof= false;
+end_file_reading();
+check_outer_validity();goto restart;
+}
+if(end_line_char_inactive)decr(limit);
+else buffer[limit]= end_line_char;
+first= limit+1;loc= start;
+}
+
+/*:362*/
+#line 7580 "tex.w"
+
+else{if(!terminal_input)
+{cur_cmd= 0;cur_chr= 0;return;
+}
+if(input_ptr> 0)
+{end_file_reading();goto restart;
+}
+if(selector<log_only)open_log_file();
+if(interaction> nonstop_mode)
+{if(end_line_char_inactive)incr(limit);
+if(limit==start)
+print_nl("(Please type a command or say `\\end')");
+
+print_ln();first= start;
+prompt_input("*");
+
+limit= last;
+if(end_line_char_inactive)decr(limit);
+else buffer[limit]= end_line_char;
+first= limit+1;
+loc= start;
+}
+else fatal_error("*** (job aborted, no legal \\end found)");
+
+
+
+}
+
+/*:360*/
+#line 7335 "tex.w"
+;
+check_interrupt;
+goto get_cur_chr;
+}
+}
+
+/*:343*/
+#line 7309 "tex.w"
+
+else/*357:*/
+#line 7529 "tex.w"
+
+if(loc!=null)
+
+{t= info(loc);loc= link(loc);
+if(t>=cs_token_flag)
+{cur_cs= t-cs_token_flag;
+cur_cmd= eq_type(cur_cs);cur_chr= equiv(cur_cs);
+if(cur_cmd>=outer_call)
+if(cur_cmd==dont_expand)
+/*358:*/
+#line 7560 "tex.w"
+
+{cur_cs= info(loc)-cs_token_flag;loc= null;
+cur_cmd= eq_type(cur_cs);cur_chr= equiv(cur_cs);
+if(cur_cmd> max_command)
+{cur_cmd= relax;cur_chr= no_expand_flag;
+}
+}
+
+/*:358*/
+#line 7538 "tex.w"
+
+else check_outer_validity();
+}
+else{cur_cmd= t/0400;cur_chr= t%0400;
+switch(cur_cmd){
+case left_brace:incr(align_state);break;
+case right_brace:decr(align_state);break;
+case out_param:/*359:*/
+#line 7568 "tex.w"
+
+{begin_token_list(param_stack[param_start+cur_chr-1],parameter);
+goto restart;
+}
+
+/*:359*/
+#line 7545 "tex.w"
+
+default:do_nothing;
+}
+}
+}
+else{
+end_token_list();goto restart;
+}
+
+/*:357*/
+#line 7311 "tex.w"
+;
+/*342:*/
+#line 7321 "tex.w"
+
+if(cur_cmd<=car_ret)if(cur_cmd>=tab_mark)if(align_state==0)
+/*789:*/
+#line 15582 "tex.w"
+
+{if((scanner_status==aligning)||(cur_align==null))
+fatal_error("(interwoven alignment preambles are not allowed)");
+
+cur_cmd= extra_info(cur_align);extra_info(cur_align)= cur_chr;
+if(cur_cmd==omit)begin_token_list(omit_template,v_template);
+else begin_token_list(v_part(cur_align),v_template);
+align_state= 1000000;goto restart;
+}
+
+/*:789*/
+#line 7323 "tex.w"
+
+
+/*:342*/
+#line 7312 "tex.w"
+;
+}
+
+/*:341*//*363:*/
+#line 7640 "tex.w"
+void firm_up_the_line(void)
+{int k;
+limit= last;
+if(pausing> 0)if(interaction> nonstop_mode)
+{wake_up_terminal;print_ln();
+if(start<limit)for(k= start;k<=limit-1;k++)print(buffer[k]);
+first= limit;prompt_input("=>");
+
+if(last> first)
+{for(k= first;k<=last-1;k++)
+buffer[k+start-first]= buffer[k];
+limit= start+last-first;
+}
+}
+}
+
+/*:363*//*365:*/
+#line 7679 "tex.w"
+void get_token(void)
+{no_new_control_sequence= false;get_next();no_new_control_sequence= true;
+
+if(cur_cs==0)cur_tok= (cur_cmd*0400)+cur_chr;
+else cur_tok= cs_token_flag+cur_cs;
+}
+
+/*:365*//*366:*/
+#line 7705 "tex.w"
+/*389:*/
+#line 8001 "tex.w"
+
+void macro_call(void)
+{
+pointer r;
+pointer p;
+pointer q;
+pointer s;
+pointer t;
+pointer u,v;
+pointer rbrace_ptr;
+small_number n;
+halfword unbalance;
+int m;
+pointer ref_count;
+small_number save_scanner_status;
+pointer save_warning_index;
+ASCII_code match_chr;
+save_scanner_status= scanner_status;save_warning_index= warning_index;
+warning_index= cur_cs;ref_count= cur_chr;r= link(ref_count);n= 0;
+if(tracing_macros> 0)/*401:*/
+#line 8225 "tex.w"
+
+{begin_diagnostic();print_ln();print_cs(warning_index);
+token_show(ref_count);end_diagnostic(false);
+}
+
+/*:401*/
+#line 8020 "tex.w"
+;
+if(info(r)!=end_match_token)
+/*391:*/
+#line 8057 "tex.w"
+
+{scanner_status= matching;unbalance= 0;
+long_state= eq_type(cur_cs);
+if(long_state>=outer_call)long_state= long_state-2;
+do{link(temp_head)= null;
+if((info(r)> match_token+255)||(info(r)<match_token))s= null;
+else{match_chr= info(r)-match_token;s= link(r);r= s;
+p= temp_head;m= 0;
+}
+/*392:*/
+#line 8077 "tex.w"
+
+resume:get_token();
+if(cur_tok==info(r))
+/*394:*/
+#line 8109 "tex.w"
+
+{r= link(r);
+if((info(r)>=match_token)&&(info(r)<=end_match_token))
+{if(cur_tok<left_brace_limit)decr(align_state);
+goto found;
+}
+else goto resume;
+}
+
+/*:394*/
+#line 8081 "tex.w"
+;
+/*397:*/
+#line 8165 "tex.w"
+
+if(s!=r)
+if(s==null)/*398:*/
+#line 8182 "tex.w"
+
+{print_err("Use of ");sprint_cs(warning_index);
+
+print_str(" doesn't match its definition");
+help4("If you say, e.g., `\\def\\a1{...}', then you must always")
+("put `1' after `\\a', since control sequence names are")
+("made up of letters only. The macro here has not been")
+("followed by the required stuff, so I'm ignoring it.");
+error();goto end;
+}
+
+/*:398*/
+#line 8167 "tex.w"
+
+else{t= s;
+do{store_new_token(info(t));incr(m);u= link(t);v= s;
+loop{if(u==r)
+if(cur_tok!=info(v))goto done;
+else{r= link(v);goto resume;
+}
+if(info(u)!=info(v))goto done;
+u= link(u);v= link(v);
+}
+done:t= link(t);
+}while(!(t==r));
+r= s;
+}
+
+/*:397*/
+#line 8083 "tex.w"
+;
+if(cur_tok==par_token)if(long_state!=long_call)
+/*396:*/
+#line 8134 "tex.w"
+
+{if(long_state==call)
+{runaway();print_err("Paragraph ended before ");
+
+sprint_cs(warning_index);print_str(" was complete");
+help3("I suspect you've forgotten a `}', causing me to apply this")
+("control sequence to too much text. How can we recover?")
+("My plan is to forget the whole thing and hope for the best.");
+back_error();
+}
+pstack[n]= link(temp_head);align_state= align_state-unbalance;
+for(m= 0;m<=n;m++)flush_list(pstack[m]);
+goto end;
+}
+
+/*:396*/
+#line 8085 "tex.w"
+;
+if(cur_tok<right_brace_limit)
+if(cur_tok<left_brace_limit)
+/*399:*/
+#line 8193 "tex.w"
+
+{unbalance= 1;
+
+loop{fast_store_new_token(cur_tok);get_token();
+if(cur_tok==par_token)if(long_state!=long_call)
+/*396:*/
+#line 8134 "tex.w"
+
+{if(long_state==call)
+{runaway();print_err("Paragraph ended before ");
+
+sprint_cs(warning_index);print_str(" was complete");
+help3("I suspect you've forgotten a `}', causing me to apply this")
+("control sequence to too much text. How can we recover?")
+("My plan is to forget the whole thing and hope for the best.");
+back_error();
+}
+pstack[n]= link(temp_head);align_state= align_state-unbalance;
+for(m= 0;m<=n;m++)flush_list(pstack[m]);
+goto end;
+}
+
+/*:396*/
+#line 8198 "tex.w"
+;
+if(cur_tok<right_brace_limit)
+if(cur_tok<left_brace_limit)incr(unbalance);
+else{decr(unbalance);
+if(unbalance==0)goto done1;
+}
+}
+done1:rbrace_ptr= p;store_new_token(cur_tok);
+}
+
+/*:399*/
+#line 8088 "tex.w"
+
+else/*395:*/
+#line 8118 "tex.w"
+
+{back_input();print_err("Argument of ");sprint_cs(warning_index);
+
+print_str(" has an extra }");
+help6("I've run across a `}' that doesn't seem to match anything.")
+("For example, `\\def\\a#1{...}' and `\\a}' would produce")
+("this error. If you simply proceed now, the `\\par' that")
+("I've just inserted will cause me to report a runaway")
+("argument that might be the root of the problem. But if")
+("your `}' was spurious, just type `2' and it will go away.");
+incr(align_state);long_state= call;cur_tok= par_token;ins_error();
+goto resume;
+}
+
+/*:395*/
+#line 8089 "tex.w"
+
+else/*393:*/
+#line 8097 "tex.w"
+
+{if(cur_tok==space_token)
+if(info(r)<=end_match_token)
+if(info(r)>=match_token)goto resume;
+store_new_token(cur_tok);
+}
+
+/*:393*/
+#line 8091 "tex.w"
+;
+incr(m);
+if(info(r)> end_match_token)goto resume;
+if(info(r)<match_token)goto resume;
+found:if(s!=null)/*400:*/
+#line 8211 "tex.w"
+
+{if((m==1)&&(info(p)<right_brace_limit)&&(p!=temp_head))
+{link(rbrace_ptr)= null;free_avail(p);
+p= link(temp_head);pstack[n]= link(p);free_avail(p);
+}
+else pstack[n]= link(temp_head);
+incr(n);
+if(tracing_macros> 0)
+{begin_diagnostic();print_nl("");print(match_chr);print_int(n);
+print_str("<-");show_token_list(pstack[n-1],null,1000);
+end_diagnostic(false);
+}
+}
+
+/*:400*/
+#line 8095 "tex.w"
+
+
+/*:392*/
+#line 8067 "tex.w"
+;
+
+}while(!(info(r)==end_match_token));
+}
+
+/*:391*/
+#line 8023 "tex.w"
+;
+/*390:*/
+#line 8032 "tex.w"
+
+while((state==token_list)&&(loc==null)&&(token_type!=v_template))
+end_token_list();
+begin_token_list(ref_count,macro);name= warning_index;loc= link(r);
+if(n> 0)
+{if(param_ptr+n> max_param_stack)
+{max_param_stack= param_ptr+n;
+if(max_param_stack> param_size)
+overflow("parameter stack size",param_size);
+
+}
+for(m= 0;m<=n-1;m++)param_stack[param_ptr+m]= pstack[m];
+param_ptr= param_ptr+n;
+}
+
+/*:390*/
+#line 8024 "tex.w"
+;
+end:scanner_status= save_scanner_status;warning_index= save_warning_index;
+}
+
+/*:389*/
+#line 7705 "tex.w"
+
+/*379:*/
+#line 7865 "tex.w"
+
+void insert_relax(void)
+{cur_tok= cs_token_flag+cur_cs;back_input();
+cur_tok= cs_token_flag+frozen_relax;back_input();token_type= inserted;
+}
+
+/*:379*/
+#line 7706 "tex.w"
+
+void pass_text(void);
+void start_input(void);
+void conditional(void);
+void get_x_token(void);
+void conv_toks(void);
+void ins_the_toks(void);
+void expand(void)
+{halfword t;
+pointer p,q,r;
+uint16_t j;
+int cv_backup;
+small_number cvl_backup,radix_backup,co_backup;
+
+pointer backup_backup;
+small_number save_scanner_status;
+cv_backup= cur_val;cvl_backup= cur_val_level;radix_backup= radix;
+co_backup= cur_order;backup_backup= link(backup_head);
+if(cur_cmd<call)/*367:*/
+#line 7731 "tex.w"
+
+{if(tracing_commands> 1)show_cur_cmd_chr();
+switch(cur_cmd){
+case top_bot_mark:/*386:*/
+#line 7957 "tex.w"
+
+{if(cur_mark[cur_chr]!=null)
+begin_token_list(cur_mark[cur_chr],mark_text);
+}
+
+/*:386*/
+#line 7734 "tex.w"
+break;
+case expand_after:/*368:*/
+#line 7749 "tex.w"
+
+{get_token();t= cur_tok;get_token();
+if(cur_cmd> max_command)expand();else back_input();
+cur_tok= t;back_input();
+}
+
+/*:368*/
+#line 7735 "tex.w"
+break;
+case no_expand:/*369:*/
+#line 7763 "tex.w"
+
+{save_scanner_status= scanner_status;scanner_status= normal;
+get_token();scanner_status= save_scanner_status;t= cur_tok;
+back_input();
+if(t>=cs_token_flag)
+{p= get_avail();info(p)= cs_token_flag+frozen_dont_expand;
+link(p)= loc;start= p;loc= p;
+}
+}
+
+/*:369*/
+#line 7736 "tex.w"
+break;
+case cs_name:/*372:*/
+#line 7795 "tex.w"
+
+{r= get_avail();p= r;
+do{get_x_token();
+if(cur_cs==0)store_new_token(cur_tok);
+}while(!(cur_cs!=0));
+if(cur_cmd!=end_cs_name)/*373:*/
+#line 7809 "tex.w"
+
+{print_err("Missing ");print_esc(/*1527:*/
+#line 25477 "tex.w"
+402
+/*:1527*/
+#line 7810 "tex.w"
+);print_str(" inserted");
+
+help2("The control sequence marked <to be read again> should")
+("not appear between \\csname and \\endcsname.");
+back_error();
+}
+
+/*:373*/
+#line 7800 "tex.w"
+;
+/*374:*/
+#line 7817 "tex.w"
+
+j= first;p= link(r);
+while(p!=null)
+{if(j>=max_buf_stack)
+{max_buf_stack= j+1;
+if(max_buf_stack==buf_size)
+overflow("buffer size",buf_size);
+
+}
+buffer[j]= info(p)%0400;incr(j);p= link(p);
+}
+if(j> first+1)
+{no_new_control_sequence= false;cur_cs= id_lookup(first,j-first);
+no_new_control_sequence= true;
+}
+else if(j==first)cur_cs= null_cs;
+else cur_cs= single_base+buffer[first]
+
+/*:374*/
+#line 7801 "tex.w"
+;
+flush_list(r);
+if(eq_type(cur_cs)==undefined_cs)
+{eq_define(cur_cs,relax,256);
+}
+cur_tok= cur_cs+cs_token_flag;back_input();
+}
+
+/*:372*/
+#line 7737 "tex.w"
+break;
+case convert:conv_toks();break;
+case the:ins_the_toks();break;
+case if_test:conditional();break;
+case fi_or_else:/*510:*/
+#line 9940 "tex.w"
+
+if(cur_chr> if_limit)
+if(if_limit==if_code)insert_relax();
+else{print_err("Extra ");print_cmd_chr(fi_or_else,cur_chr);
+
+
+
+help1("I'm ignoring this; it doesn't match any \\if.");
+error();
+}
+else{while(cur_chr!=fi_code)pass_text();
+/*496:*/
+#line 9732 "tex.w"
+
+{p= cond_ptr;if_line= if_line_field(p);
+cur_if= subtype(p);if_limit= type(p);cond_ptr= link(p);
+free_node(p,if_node_size);
+}
+
+/*:496*/
+#line 9951 "tex.w"
+;
+}
+
+/*:510*/
+#line 7741 "tex.w"
+break;
+case input:/*378:*/
+#line 7857 "tex.w"
+
+if(cur_chr> 0)force_eof= true;
+else if(name_in_progress)insert_relax();
+else start_input()
+
+/*:378*/
+#line 7742 "tex.w"
+;break;
+default:/*370:*/
+#line 7773 "tex.w"
+
+{print_err("Undefined control sequence");
+
+help5("The control sequence at the end of the top line")
+("of your error message was never \\def'ed. If you have")
+("misspelled it (e.g., `\\hobx'), type `I' and the correct")
+("spelling (e.g., `I\\hbox'). Otherwise just continue,")
+("and I'll forget about whatever was undefined.");
+error();
+}
+
+/*:370*/
+#line 7743 "tex.w"
+
+}
+}
+
+/*:367*/
+#line 7724 "tex.w"
+
+else if(cur_cmd<end_template)macro_call();
+else/*375:*/
+#line 7841 "tex.w"
+
+{cur_tok= cs_token_flag+frozen_endv;back_input();
+}
+
+/*:375*/
+#line 7726 "tex.w"
+;
+cur_val= cv_backup;cur_val_level= cvl_backup;radix= radix_backup;
+cur_order= co_backup;link(backup_head)= backup_backup;
+}
+
+/*:366*//*380:*/
+#line 7875 "tex.w"
+void get_x_token(void)
+
+{
+restart:get_next();
+
+if(cur_cmd<=max_command)goto done;
+if(cur_cmd>=call)
+if(cur_cmd<end_template)macro_call();
+else{cur_cs= frozen_endv;cur_cmd= endv;
+goto done;
+}
+else expand();
+goto restart;
+done:if(cur_cs==0)cur_tok= (cur_cmd*0400)+cur_chr;
+else cur_tok= cs_token_flag+cur_cs;
+}
+
+/*:380*//*381:*/
+#line 7895 "tex.w"
+void x_token(void)
+{while(cur_cmd> max_command)
+{expand();
+get_next();
+}
+if(cur_cs==0)cur_tok= (cur_cmd*0400)+cur_chr;
+else cur_tok= cs_token_flag+cur_cs;
+}
+
+/*:381*//*403:*/
+#line 8243 "tex.w"
+void scan_left_brace(void)
+{/*404:*/
+#line 8257 "tex.w"
+
+do{get_x_token();
+}while(!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+/*:404*/
+#line 8244 "tex.w"
+;
+if(cur_cmd!=left_brace)
+{print_err("Missing { inserted");
+
+help4("A left brace was mandatory here, so I've put one in.")
+("You might want to delete and/or insert some corrections")
+("so that I will find a matching right brace soon.")
+("(If you're confused by all this, try typing `I}' now.)");
+back_error();cur_tok= left_brace_token+'{';cur_cmd= left_brace;
+cur_chr= '{';incr(align_state);
+}
+}
+
+/*:403*//*405:*/
+#line 8264 "tex.w"
+void scan_optional_equals(void)
+{/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 8265 "tex.w"
+;
+if(cur_tok!=other_token+'=')back_input();
+}
+
+/*:405*//*407:*/
+#line 8288 "tex.w"
+bool scan_keyword(str_number s)
+{
+pointer p;
+pointer q;
+pool_pointer k;
+p= backup_head;link(p)= null;k= str_start[s];
+while(k<str_start[s+1])
+{get_x_token();
+
+if((cur_cs==0)&&
+((cur_chr==so(str_pool[k]))||(cur_chr==so(str_pool[k])-'a'+'A')))
+{store_new_token(cur_tok);incr(k);
+}
+else if((cur_cmd!=spacer)||(p!=backup_head))
+{back_input();
+if(p!=backup_head)back_list(link(backup_head));
+return false;
+}
+}
+flush_list(link(backup_head));return true;
+}
+
+/*:407*//*408:*/
+#line 8313 "tex.w"
+void mu_error(void)
+{print_err("Incompatible glue units");
+
+help1("I'm going to assume that 1mu=1pt when they're mixed.");
+error();
+}
+
+/*:408*//*409:*/
+#line 8330 "tex.w"
+void scan_int(void);
+/*433:*/
+#line 8666 "tex.w"
+
+void scan_eight_bit_int(void)
+{scan_int();
+if((cur_val<0)||(cur_val> 255))
+{print_err("Bad register code");
+
+help2("A register number must be between 0 and 255.")
+("I changed this one to zero.");int_error(cur_val);cur_val= 0;
+}
+}
+
+/*:433*//*434:*/
+#line 8677 "tex.w"
+
+void scan_char_num(void)
+{scan_int();
+if((cur_val<0)||(cur_val> 255))
+{print_err("Bad character code");
+
+help2("A character number must be between 0 and 255.")
+("I changed this one to zero.");int_error(cur_val);cur_val= 0;
+}
+}
+
+/*:434*//*435:*/
+#line 8691 "tex.w"
+
+void scan_four_bit_int(void)
+{scan_int();
+if((cur_val<0)||(cur_val> 15))
+{print_err("Bad number");
+
+help2("Since I expected to read a number between 0 and 15,")
+("I changed this one to zero.");int_error(cur_val);cur_val= 0;
+}
+}
+
+/*:435*//*436:*/
+#line 8702 "tex.w"
+
+void scan_fifteen_bit_int(void)
+{scan_int();
+if((cur_val<0)||(cur_val> 077777))
+{print_err("Bad mathchar");
+
+help2("A mathchar number must be between 0 and 32767.")
+("I changed this one to zero.");int_error(cur_val);cur_val= 0;
+}
+}
+
+/*:436*//*437:*/
+#line 8713 "tex.w"
+
+void scan_twenty_seven_bit_int(void)
+{scan_int();
+if((cur_val<0)||(cur_val> 0777777777))
+{print_err("Bad delimiter code");
+
+help2("A numeric delimiter code must be between 0 and 2^{27}-1.")
+("I changed this one to zero.");int_error(cur_val);cur_val= 0;
+}
+}
+
+/*:437*/
+#line 8331 "tex.w"
+
+/*577:*/
+#line 11265 "tex.w"
+
+void scan_font_ident(void)
+{internal_font_number f;
+halfword m;
+/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 11269 "tex.w"
+;
+if(cur_cmd==def_font)f= cur_font;
+else if(cur_cmd==set_font)f= cur_chr;
+else if(cur_cmd==def_family)
+{m= cur_chr;scan_four_bit_int();f= equiv(m+cur_val);
+}
+else{print_err("Missing font identifier");
+
+help2("I was looking for a control sequence whose")
+("current meaning has been defined by \\font.");
+back_error();f= null_font;
+}
+cur_val= f;
+}
+
+/*:577*//*578:*/
+#line 11288 "tex.w"
+
+void find_font_dimen(bool writing)
+
+{internal_font_number f;
+int n;
+scan_int();n= cur_val;scan_font_ident();f= cur_val;
+if(n<=0)cur_val= fmem_ptr;
+else{if(writing&&(n<=space_shrink_code)&&
+(n>=space_code)&&(font_glue[f]!=null))
+{delete_glue_ref(font_glue[f]);
+font_glue[f]= null;
+}
+if(n> font_params[f])
+if(f<font_ptr)cur_val= fmem_ptr;
+else/*580:*/
+#line 11319 "tex.w"
+
+{do{if(fmem_ptr==font_mem_size)
+overflow("font memory",font_mem_size);
+
+font_info[fmem_ptr].sc= 0;incr(fmem_ptr);incr(font_params[f]);
+}while(!(n==font_params[f]));
+cur_val= fmem_ptr-1;
+}
+
+/*:580*/
+#line 11302 "tex.w"
+
+else cur_val= n+param_base[f];
+}
+/*579:*/
+#line 11308 "tex.w"
+
+if(cur_val==fmem_ptr)
+{print_err("Font ");print_esc(font_id_text(f));
+print_str(" has only ");print_int(font_params[f]);
+print_str(" fontdimen parameters");
+
+help2("To increase the number of font parameters, you must")
+("use \\fontdimen immediately after the \\font is loaded.");
+error();
+}
+
+/*:579*/
+#line 11305 "tex.w"
+;
+}
+
+/*:578*/
+#line 8332 "tex.w"
+
+
+/*:409*//*413:*/
+#line 8403 "tex.w"
+void scan_something_internal(small_number level,bool negative)
+
+{halfword m;
+uint8_t p;
+m= cur_chr;
+switch(cur_cmd){
+case def_code:/*414:*/
+#line 8433 "tex.w"
+
+{scan_char_num();
+if(m==math_code_base)scanned_result(ho(math_code(cur_val)))(int_val)
+else if(m<math_code_base)scanned_result(equiv(m+cur_val))(int_val)
+else scanned_result(eqtb[m+cur_val].i)(int_val);
+}
+
+/*:414*/
+#line 8409 "tex.w"
+break;
+case toks_register:case assign_toks:case def_family:case set_font:case def_font:/*415:*/
+#line 8440 "tex.w"
+
+if(level!=tok_val)
+{print_err("Missing number, treated as zero");
+
+help3("A number should have been here; I inserted `0'.")
+("(If you can't figure out why I needed to see a number,")
+("look up `weird error' in the index to The TeXbook.)");
+
+back_error();scanned_result(0)(dimen_val);
+}
+else if(cur_cmd<=assign_toks)
+{if(cur_cmd<assign_toks)
+{scan_eight_bit_int();m= toks_base+cur_val;
+}
+scanned_result(equiv(m))(tok_val);
+}
+else{back_input();scan_font_ident();
+scanned_result(font_id_base+cur_val)(ident_val);
+}
+
+/*:415*/
+#line 8411 "tex.w"
+break;
+case assign_int:scanned_result(eqtb[m].i)(int_val)break;
+case assign_dimen:scanned_result(eqtb[m].sc)(dimen_val)break;
+case assign_glue:scanned_result(equiv(m))(glue_val)break;
+case assign_mu_glue:scanned_result(equiv(m))(mu_val)break;
+case set_aux:/*418:*/
+#line 8514 "tex.w"
+
+if(abs(mode)!=m)
+{print_err("Improper ");print_cmd_chr(set_aux,m);
+
+
+help4("You can refer to \\spacefactor only in horizontal mode;")
+("you can refer to \\prevdepth only in vertical mode; and")
+("neither of these is meaningful inside \\write. So")
+("I'm forgetting what you said and using zero instead.");
+error();
+if(level!=tok_val)scanned_result(0)(dimen_val)
+else scanned_result(0)(int_val);
+}
+else if(m==vmode)scanned_result(prev_depth)(dimen_val)
+else scanned_result(space_factor)(int_val)
+
+/*:418*/
+#line 8416 "tex.w"
+break;
+case set_prev_graf:/*422:*/
+#line 8553 "tex.w"
+
+if(mode==0)scanned_result(0)(int_val)
+else{nest[nest_ptr]= cur_list;p= nest_ptr;
+while(abs(nest[p].mode_field)!=vmode)decr(p);
+scanned_result(nest[p].pg_field)(int_val);
+}
+
+/*:422*/
+#line 8417 "tex.w"
+break;
+case set_page_int:/*419:*/
+#line 8530 "tex.w"
+
+{if(m==0)cur_val= dead_cycles;else cur_val= insert_penalties;
+cur_val_level= int_val;
+}
+
+/*:419*/
+#line 8418 "tex.w"
+break;
+case set_page_dimen:/*421:*/
+#line 8546 "tex.w"
+
+{if((page_contents==empty)&&(!output_active))
+if(m==0)cur_val= max_dimen;else cur_val= 0;
+else cur_val= page_so_far[m];
+cur_val_level= dimen_val;
+}
+
+/*:421*/
+#line 8419 "tex.w"
+break;
+case set_shape:/*423:*/
+#line 8560 "tex.w"
+
+{if(par_shape_ptr==null)cur_val= 0;
+else cur_val= info(par_shape_ptr);
+cur_val_level= int_val;
+}
+
+/*:423*/
+#line 8420 "tex.w"
+break;
+case set_box_dimen:/*420:*/
+#line 8535 "tex.w"
+
+{scan_eight_bit_int();
+if(box(cur_val)==null)cur_val= 0;else cur_val= mem[box(cur_val)+m].sc;
+cur_val_level= dimen_val;
+}
+
+/*:420*/
+#line 8421 "tex.w"
+break;
+case char_given:case math_given:scanned_result(cur_chr)(int_val)break;
+case assign_font_dimen:/*425:*/
+#line 8597 "tex.w"
+
+{find_font_dimen(false);font_info[fmem_ptr].sc= 0;
+scanned_result(font_info[cur_val].sc)(dimen_val);
+}
+
+/*:425*/
+#line 8423 "tex.w"
+break;
+case assign_font_int:/*426:*/
+#line 8602 "tex.w"
+
+{scan_font_ident();
+if(m==0)scanned_result(hyphen_char[cur_val])(int_val)
+else scanned_result(skew_char[cur_val])(int_val);
+}
+
+/*:426*/
+#line 8424 "tex.w"
+break;
+case register:/*427:*/
+#line 8608 "tex.w"
+
+{scan_eight_bit_int();
+switch(m){
+case int_val:cur_val= count(cur_val);break;
+case dimen_val:cur_val= dimen(cur_val);break;
+case glue_val:cur_val= skip(cur_val);break;
+case mu_val:cur_val= mu_skip(cur_val);
+}
+cur_val_level= m;
+}
+
+/*:427*/
+#line 8425 "tex.w"
+break;
+case last_item:/*424:*/
+#line 8572 "tex.w"
+
+if(cur_chr> glue_val)
+{if(cur_chr==input_line_no_code)cur_val= line;
+else cur_val= last_badness;
+cur_val_level= int_val;
+}
+else{if(cur_chr==glue_val)cur_val= zero_glue;else cur_val= 0;
+cur_val_level= cur_chr;
+if(!is_char_node(tail)&&(mode!=0))
+switch(cur_chr){
+case int_val:if(type(tail)==penalty_node)cur_val= penalty(tail);break;
+case dimen_val:if(type(tail)==kern_node)cur_val= width(tail);break;
+case glue_val:if(type(tail)==glue_node)
+{cur_val= glue_ptr(tail);
+if(subtype(tail)==mu_glue)cur_val_level= mu_val;
+}
+}
+else if((mode==vmode)&&(tail==head))
+switch(cur_chr){
+case int_val:cur_val= last_penalty;break;
+case dimen_val:cur_val= last_kern;break;
+case glue_val:if(last_glue!=max_halfword)cur_val= last_glue;
+}
+}
+
+/*:424*/
+#line 8426 "tex.w"
+break;
+default:/*428:*/
+#line 8619 "tex.w"
+
+{print_err("You can't use `");print_cmd_chr(cur_cmd,cur_chr);
+
+print_str("' after ");print_esc(/*1559:*/
+#line 25573 "tex.w"
+434
+/*:1559*/
+#line 8622 "tex.w"
+);
+help1("I'm forgetting what you said and using zero instead.");
+error();
+if(level!=tok_val)scanned_result(0)(dimen_val)
+else scanned_result(0)(int_val);
+}
+
+/*:428*/
+#line 8427 "tex.w"
+
+}
+while(cur_val_level> level)/*429:*/
+#line 8635 "tex.w"
+
+{if(cur_val_level==glue_val)cur_val= width(cur_val);
+else if(cur_val_level==mu_val)mu_error();
+decr(cur_val_level);
+}
+
+/*:429*/
+#line 8429 "tex.w"
+;
+/*430:*/
+#line 8645 "tex.w"
+
+if(negative)
+if(cur_val_level>=glue_val)
+{cur_val= new_spec(cur_val);
+/*431:*/
+#line 8655 "tex.w"
+
+{negate(width(cur_val));
+negate(stretch(cur_val));
+negate(shrink(cur_val));
+}
+
+/*:431*/
+#line 8649 "tex.w"
+;
+}
+else negate(cur_val);
+else if((cur_val_level>=glue_val)&&(cur_val_level<=mu_val))
+add_glue_ref(cur_val)
+
+/*:430*/
+#line 8430 "tex.w"
+;
+}
+
+/*:413*//*440:*/
+#line 8756 "tex.w"
+void scan_int(void)
+{
+bool negative;
+int m;
+small_number d;
+bool vacuous;
+bool OK_so_far;
+radix= 0;OK_so_far= true;
+/*441:*/
+#line 8772 "tex.w"
+
+negative= false;
+do{/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 8774 "tex.w"
+;
+if(cur_tok==other_token+'-')
+{negative= !negative;cur_tok= other_token+'+';
+}
+}while(!(cur_tok!=other_token+'+'))
+
+/*:441*/
+#line 8764 "tex.w"
+;
+if(cur_tok==alpha_token)/*442:*/
+#line 8783 "tex.w"
+
+{get_token();
+if(cur_tok<cs_token_flag)
+{cur_val= cur_chr;
+if(cur_cmd<=right_brace)
+if(cur_cmd==right_brace)incr(align_state);
+else decr(align_state);
+}
+else if(cur_tok<cs_token_flag+single_base)
+cur_val= cur_tok-cs_token_flag-active_base;
+else cur_val= cur_tok-cs_token_flag-single_base;
+if(cur_val> 255)
+{print_err("Improper alphabetic constant");
+
+help2("A one-character control sequence belongs after a ` mark.")
+("So I'm essentially inserting \\0 here.");
+cur_val= '0';back_error();
+}
+else/*443:*/
+#line 8804 "tex.w"
+
+{get_x_token();if(cur_cmd!=spacer)back_input();
+}
+
+/*:443*/
+#line 8801 "tex.w"
+;
+}
+
+/*:442*/
+#line 8765 "tex.w"
+
+else if((cur_cmd>=min_internal)&&(cur_cmd<=max_internal))
+scan_something_internal(int_val,false);
+else/*444:*/
+#line 8808 "tex.w"
+
+{radix= 10;m= 214748364;
+if(cur_tok==octal_token)
+{radix= 8;m= 02000000000;get_x_token();
+}
+else if(cur_tok==hex_token)
+{radix= 16;m= 01000000000;get_x_token();
+}
+vacuous= true;cur_val= 0;
+/*445:*/
+#line 8827 "tex.w"
+
+loop{if((cur_tok<zero_token+radix)&&(cur_tok>=zero_token)&&
+(cur_tok<=zero_token+9))d= cur_tok-zero_token;
+else if(radix==16)
+if((cur_tok<=A_token+5)&&(cur_tok>=A_token))d= cur_tok-A_token+10;
+else if((cur_tok<=other_A_token+5)&&(cur_tok>=other_A_token))
+d= cur_tok-other_A_token+10;
+else goto done;
+else goto done;
+vacuous= false;
+if((cur_val>=m)&&((cur_val> m)||(d> 7)||(radix!=10)))
+{if(OK_so_far)
+{print_err("Number too big");
+
+help2("I can only go up to 2147483647='17777777777=\"7FFFFFFF,")
+("so I'm using that number instead of yours.");
+error();cur_val= infinity;OK_so_far= false;
+}
+}
+else cur_val= cur_val*radix+d;
+get_x_token();
+}
+done:
+
+/*:445*/
+#line 8817 "tex.w"
+;
+if(vacuous)/*446:*/
+#line 8851 "tex.w"
+
+{print_err("Missing number, treated as zero");
+
+help3("A number should have been here; I inserted `0'.")
+("(If you can't figure out why I needed to see a number,")
+("look up `weird error' in the index to The TeXbook.)");
+
+back_error();
+}
+
+/*:446*/
+#line 8818 "tex.w"
+
+else if(cur_cmd!=spacer)back_input();
+}
+
+/*:444*/
+#line 8768 "tex.w"
+;
+if(negative)negate(cur_val);
+}
+
+/*:440*//*448:*/
+#line 8890 "tex.w"
+void scan_dimen(bool mu,bool inf,bool shortcut)
+
+{
+bool negative;
+int f;
+/*450:*/
+#line 8932 "tex.w"
+
+uint32_t num,denom;
+int k,kk;
+pointer p,q;
+scaled v;
+int save_cur_val;
+
+/*:450*/
+#line 8895 "tex.w"
+
+f= 0;arith_error= false;cur_order= normal;negative= false;
+if(!shortcut)
+{/*441:*/
+#line 8772 "tex.w"
+
+negative= false;
+do{/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 8774 "tex.w"
+;
+if(cur_tok==other_token+'-')
+{negative= !negative;cur_tok= other_token+'+';
+}
+}while(!(cur_tok!=other_token+'+'))
+
+/*:441*/
+#line 8898 "tex.w"
+;
+if((cur_cmd>=min_internal)&&(cur_cmd<=max_internal))
+/*449:*/
+#line 8921 "tex.w"
+
+if(mu)
+{scan_something_internal(mu_val,false);
+/*451:*/
+#line 8943 "tex.w"
+
+if(cur_val_level>=glue_val)
+{v= width(cur_val);delete_glue_ref(cur_val);cur_val= v;
+}
+
+/*:451*/
+#line 8924 "tex.w"
+;
+if(cur_val_level==mu_val)goto attach_sign;
+if(cur_val_level!=int_val)mu_error();
+}
+else{scan_something_internal(dimen_val,false);
+if(cur_val_level==dimen_val)goto attach_sign;
+}
+
+/*:449*/
+#line 8900 "tex.w"
+
+else{back_input();
+if(cur_tok==continental_point_token)cur_tok= point_token;
+if(cur_tok!=point_token)scan_int();
+else{radix= 10;cur_val= 0;
+}
+if(cur_tok==continental_point_token)cur_tok= point_token;
+if((radix==10)&&(cur_tok==point_token))/*452:*/
+#line 8954 "tex.w"
+
+{k= 0;p= null;get_token();
+loop{get_x_token();
+if((cur_tok> zero_token+9)||(cur_tok<zero_token))goto done1;
+if(k<17)
+{q= get_avail();link(q)= p;info(q)= cur_tok-zero_token;
+p= q;incr(k);
+}
+}
+done1:for(kk= k;kk>=1;kk--)
+{dig[kk-1]= info(p);q= p;p= link(p);free_avail(q);
+}
+f= round_decimals(k);
+if(cur_cmd!=spacer)back_input();
+}
+
+/*:452*/
+#line 8907 "tex.w"
+;
+}
+}
+if(cur_val<0)
+{negative= !negative;negate(cur_val);
+}
+/*453:*/
+#line 8977 "tex.w"
+
+if(inf)/*454:*/
+#line 8995 "tex.w"
+
+if(scan_keyword(/*1387:*/
+#line 25057 "tex.w"
+262
+/*:1387*/
+#line 8996 "tex.w"
+))
+
+{cur_order= fil;
+while(scan_keyword('l'))
+{if(cur_order==filll)
+{print_err("Illegal unit of measure (");
+
+print_str("replaced by filll)");
+help1("I dddon't go any higher than filll.");error();
+}
+else incr(cur_order);
+}
+goto attach_fraction;
+}
+
+/*:454*/
+#line 8978 "tex.w"
+;
+/*455:*/
+#line 9011 "tex.w"
+
+save_cur_val= cur_val;
+/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 9013 "tex.w"
+;
+if((cur_cmd<min_internal)||(cur_cmd> max_internal))back_input();
+else{if(mu)
+{scan_something_internal(mu_val,false);/*451:*/
+#line 8943 "tex.w"
+
+if(cur_val_level>=glue_val)
+{v= width(cur_val);delete_glue_ref(cur_val);cur_val= v;
+}
+
+/*:451*/
+#line 9016 "tex.w"
+;
+if(cur_val_level!=mu_val)mu_error();
+}
+else scan_something_internal(dimen_val,false);
+v= cur_val;goto found;
+}
+if(mu)goto not_found;
+if(scan_keyword(/*1590:*/
+#line 25666 "tex.w"
+465
+/*:1590*/
+#line 9023 "tex.w"
+))v= (/*558:*/
+#line 10924 "tex.w"
+quad(cur_font)
+
+/*:558*/
+#line 9023 "tex.w"
+);
+
+else if(scan_keyword(/*1591:*/
+#line 25669 "tex.w"
+466
+/*:1591*/
+#line 9025 "tex.w"
+))v= (/*559:*/
+#line 10926 "tex.w"
+x_height(cur_font)
+
+/*:559*/
+#line 9025 "tex.w"
+);
+
+else goto not_found;
+/*443:*/
+#line 8804 "tex.w"
+
+{get_x_token();if(cur_cmd!=spacer)back_input();
+}
+
+/*:443*/
+#line 9028 "tex.w"
+;
+found:cur_val= nx_plus_y(save_cur_val,v,xn_over_d(v,f,0200000));
+goto attach_sign;
+not_found:
+
+/*:455*/
+#line 8980 "tex.w"
+;
+if(mu)/*456:*/
+#line 9033 "tex.w"
+
+if(scan_keyword(/*1394:*/
+#line 25078 "tex.w"
+269
+/*:1394*/
+#line 9034 "tex.w"
+))goto attach_fraction;
+
+else{print_err("Illegal unit of measure (");print_str("mu inserted)");
+
+help4("The unit of measurement in math glue must be mu.")
+("To recover gracefully from this error, it's best to")
+("delete the erroneous units; e.g., type `2' to delete")
+("two letters. (See Chapter 27 of The TeXbook.)");
+
+error();goto attach_fraction;
+}
+
+/*:456*/
+#line 8981 "tex.w"
+;
+if(scan_keyword(/*1589:*/
+#line 25663 "tex.w"
+464
+/*:1589*/
+#line 8982 "tex.w"
+))/*457:*/
+#line 9046 "tex.w"
+
+{prepare_mag();
+if(mag!=1000)
+{cur_val= xn_over_d(cur_val,1000,mag);
+f= (1000*f+0200000*rem)/mag;
+cur_val= cur_val+(f/0200000);f= f%0200000;
+}
+}
+
+/*:457*/
+#line 8982 "tex.w"
+;
+
+if(scan_keyword(/*1425:*/
+#line 25171 "tex.w"
+300
+/*:1425*/
+#line 8984 "tex.w"
+))goto attach_fraction;
+
+/*458:*/
+#line 9065 "tex.w"
+
+if(scan_keyword(/*1592:*/
+#line 25672 "tex.w"
+467
+/*:1592*/
+#line 9066 "tex.w"
+))set_conversion(7227)(100)
+
+else if(scan_keyword(/*1593:*/
+#line 25675 "tex.w"
+468
+/*:1593*/
+#line 9068 "tex.w"
+))set_conversion(12)(1)
+
+else if(scan_keyword(/*1594:*/
+#line 25678 "tex.w"
+469
+/*:1594*/
+#line 9070 "tex.w"
+))set_conversion(7227)(254)
+
+else if(scan_keyword(/*1595:*/
+#line 25681 "tex.w"
+470
+/*:1595*/
+#line 9072 "tex.w"
+))set_conversion(7227)(2540)
+
+else if(scan_keyword(/*1596:*/
+#line 25684 "tex.w"
+471
+/*:1596*/
+#line 9074 "tex.w"
+))set_conversion(7227)(7200)
+
+else if(scan_keyword(/*1597:*/
+#line 25687 "tex.w"
+472
+/*:1597*/
+#line 9076 "tex.w"
+))set_conversion(1238)(1157)
+
+else if(scan_keyword(/*1598:*/
+#line 25690 "tex.w"
+473
+/*:1598*/
+#line 9078 "tex.w"
+))set_conversion(14856)(1157)
+
+else if(scan_keyword(/*1599:*/
+#line 25693 "tex.w"
+474
+/*:1599*/
+#line 9080 "tex.w"
+))goto done;
+
+else/*459:*/
+#line 9088 "tex.w"
+
+{print_err("Illegal unit of measure (");print_str("pt inserted)");
+
+help6("Dimensions can be in units of em, ex, in, pt, pc,")
+("cm, mm, dd, cc, bp, or sp; but yours is a new one!")
+("I'll assume that you meant to say pt, for printer's points.")
+("To recover gracefully from this error, it's best to")
+("delete the erroneous units; e.g., type `2' to delete")
+("two letters. (See Chapter 27 of The TeXbook.)");
+
+error();goto done2;
+}
+
+
+/*:459*/
+#line 9082 "tex.w"
+;
+cur_val= xn_over_d(cur_val,num,denom);
+f= (num*f+0200000*rem)/denom;
+cur_val= cur_val+(f/0200000);f= f%0200000;
+done2:
+
+/*:458*/
+#line 8987 "tex.w"
+;
+attach_fraction:if(cur_val>=040000)arith_error= true;
+else cur_val= cur_val*unity+f;
+done:
+
+/*:453*/
+#line 8914 "tex.w"
+;
+/*443:*/
+#line 8804 "tex.w"
+
+{get_x_token();if(cur_cmd!=spacer)back_input();
+}
+
+/*:443*/
+#line 8915 "tex.w"
+;
+attach_sign:if(arith_error||(abs(cur_val)>=010000000000))
+/*460:*/
+#line 9102 "tex.w"
+
+{print_err("Dimension too large");
+
+help2("I can't work with sizes bigger than about 19 feet.")
+("Continue and I'll use the largest value I can.");
+error();cur_val= max_dimen;arith_error= false;
+}
+
+/*:460*/
+#line 8917 "tex.w"
+;
+if(negative)negate(cur_val);
+}
+
+/*:448*//*461:*/
+#line 9120 "tex.w"
+void scan_glue(small_number level)
+
+{
+bool negative;
+pointer q;
+bool mu;
+mu= (level==mu_val);/*441:*/
+#line 8772 "tex.w"
+
+negative= false;
+do{/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 8774 "tex.w"
+;
+if(cur_tok==other_token+'-')
+{negative= !negative;cur_tok= other_token+'+';
+}
+}while(!(cur_tok!=other_token+'+'))
+
+/*:441*/
+#line 9126 "tex.w"
+;
+if((cur_cmd>=min_internal)&&(cur_cmd<=max_internal))
+{scan_something_internal(level,negative);
+if(cur_val_level>=glue_val)
+{if(cur_val_level!=level)mu_error();
+return;
+}
+if(cur_val_level==int_val)scan_dimen(mu,false,true);
+else if(level==mu_val)mu_error();
+}
+else{back_input();scan_dimen(mu,false,false);
+if(negative)negate(cur_val);
+}
+/*462:*/
+#line 9143 "tex.w"
+
+q= new_spec(zero_glue);width(q)= cur_val;
+if(scan_keyword(/*1600:*/
+#line 25696 "tex.w"
+475
+/*:1600*/
+#line 9145 "tex.w"
+))
+
+{scan_dimen(mu,true,false);
+stretch(q)= cur_val;stretch_order(q)= cur_order;
+}
+if(scan_keyword(/*1601:*/
+#line 25699 "tex.w"
+476
+/*:1601*/
+#line 9150 "tex.w"
+))
+
+{scan_dimen(mu,true,false);
+shrink(q)= cur_val;shrink_order(q)= cur_order;
+}
+cur_val= q
+
+/*:462*/
+#line 9140 "tex.w"
+;
+}
+
+/*:461*//*463:*/
+#line 9166 "tex.w"
+pointer scan_rule_spec(void)
+{
+pointer q;
+q= new_rule();
+if(cur_cmd==vrule)width(q)= default_rule;
+else{height(q)= default_rule;depth(q)= 0;
+}
+reswitch:if(scan_keyword(/*1602:*/
+#line 25702 "tex.w"
+477
+/*:1602*/
+#line 9173 "tex.w"
+))
+
+{scan_normal_dimen;width(q)= cur_val;goto reswitch;
+}
+if(scan_keyword(/*1603:*/
+#line 25705 "tex.w"
+478
+/*:1603*/
+#line 9177 "tex.w"
+))
+
+{scan_normal_dimen;height(q)= cur_val;goto reswitch;
+}
+if(scan_keyword(/*1604:*/
+#line 25708 "tex.w"
+479
+/*:1604*/
+#line 9181 "tex.w"
+))
+
+{scan_normal_dimen;depth(q)= cur_val;goto reswitch;
+}
+return q;
+}
+
+/*:463*//*464:*/
+#line 9200 "tex.w"
+pointer str_toks(pool_pointer b)
+
+{pointer p;
+pointer q;
+halfword t;
+pool_pointer k;
+str_room(1);
+p= temp_head;link(p)= null;k= b;
+while(k<pool_ptr)
+{t= so(str_pool[k]);
+if(t==' ')t= space_token;
+else t= other_token+t;
+fast_store_new_token(t);
+incr(k);
+}
+pool_ptr= b;return p;
+}
+
+/*:464*//*465:*/
+#line 9225 "tex.w"
+pointer the_toks(void)
+{uint8_t old_setting;
+pointer p,q,r;
+pool_pointer b;
+get_x_token();scan_something_internal(tok_val,false);
+if(cur_val_level>=ident_val)/*466:*/
+#line 9245 "tex.w"
+
+{p= temp_head;link(p)= null;
+if(cur_val_level==ident_val)store_new_token(cs_token_flag+cur_val)
+else if(cur_val!=null)
+{r= link(cur_val);
+while(r!=null)
+{fast_store_new_token(info(r));r= link(r);
+}
+}
+return p;
+}
+
+/*:466*/
+#line 9230 "tex.w"
+
+else{old_setting= selector;selector= new_string;b= pool_ptr;
+switch(cur_val_level){
+case int_val:print_int(cur_val);break;
+case dimen_val:{print_scaled(cur_val);print_str("pt");
+}break;
+case glue_val:{print_spec(cur_val,/*1425:*/
+#line 25171 "tex.w"
+300
+/*:1425*/
+#line 9236 "tex.w"
+);delete_glue_ref(cur_val);
+}break;
+case mu_val:{print_spec(cur_val,/*1394:*/
+#line 25078 "tex.w"
+269
+/*:1394*/
+#line 9238 "tex.w"
+);delete_glue_ref(cur_val);
+}
+}
+selector= old_setting;return str_toks(b);
+}
+}
+
+/*:465*//*467:*/
+#line 9259 "tex.w"
+void ins_the_toks(void)
+{link(garbage)= the_toks();ins_list(link(temp_head));
+}
+
+/*:467*//*470:*/
+#line 9301 "tex.w"
+void conv_toks(void)
+{uint8_t old_setting;
+uint8_t c;
+small_number save_scanner_status;
+pool_pointer b;
+c= cur_chr;/*471:*/
+#line 9312 "tex.w"
+
+switch(c){
+case number_code:case roman_numeral_code:scan_int();break;
+case string_code:case meaning_code:{save_scanner_status= scanner_status;
+scanner_status= normal;get_token();scanner_status= save_scanner_status;
+}break;
+case font_name_code:scan_font_ident();break;
+case job_name_code:if(job_name==0)open_log_file();
+}
+
+/*:471*/
+#line 9306 "tex.w"
+;
+old_setting= selector;selector= new_string;b= pool_ptr;
+/*472:*/
+#line 9322 "tex.w"
+
+switch(c){
+case number_code:print_int(cur_val);break;
+case roman_numeral_code:print_roman_int(cur_val);break;
+case string_code:if(cur_cs!=0)sprint_cs(cur_cs);
+else print_char(cur_chr);break;
+case meaning_code:print_meaning();break;
+case font_name_code:{print(font_name[cur_val]);
+if(font_size[cur_val]!=font_dsize[cur_val])
+{print_str(" at ");print_scaled(font_size[cur_val]);
+print_str("pt");
+}
+}break;
+case job_name_code:print(job_name);
+}
+
+/*:472*/
+#line 9308 "tex.w"
+;
+selector= old_setting;link(garbage)= str_toks(b);ins_list(link(temp_head));
+}
+
+/*:470*//*473:*/
+#line 9362 "tex.w"
+pointer scan_toks(bool macro_def,bool xpand)
+{
+halfword t;
+halfword s;
+pointer p;
+pointer q;
+halfword unbalance;
+halfword hash_brace;
+if(macro_def)scanner_status= defining;
+else scanner_status= absorbing;
+warning_index= cur_cs;def_ref= get_avail();token_ref_count(def_ref)= null;
+p= def_ref;hash_brace= 0;t= zero_token;
+if(macro_def)/*474:*/
+#line 9382 "tex.w"
+
+{loop{get_token();
+if(cur_tok<right_brace_limit)goto done1;
+if(cur_cmd==mac_param)
+/*476:*/
+#line 9403 "tex.w"
+
+{s= match_token+cur_chr;get_token();
+if(cur_cmd==left_brace)
+{hash_brace= cur_tok;
+store_new_token(cur_tok);store_new_token(end_match_token);
+goto done;
+}
+if(t==zero_token+9)
+{print_err("You already have nine parameters");
+
+help1("I'm going to ignore the # sign you just used.");error();
+}
+else{incr(t);
+if(cur_tok!=t)
+{print_err("Parameters must be numbered consecutively");
+
+help2("I've inserted the digit you should have used after the #.")
+("Type `1' to delete what you did use.");back_error();
+}
+cur_tok= s;
+}
+}
+
+/*:476*/
+#line 9388 "tex.w"
+;
+store_new_token(cur_tok);
+}
+done1:store_new_token(end_match_token);
+if(cur_cmd==right_brace)
+/*475:*/
+#line 9396 "tex.w"
+
+{print_err("Missing { inserted");incr(align_state);
+
+help2("Where was the left brace? You said something like `\\def\\a}',")
+("which I'm going to interpret as `\\def\\a{}'.");error();goto found;
+}
+
+/*:475*/
+#line 9393 "tex.w"
+;
+done:;}
+
+/*:474*/
+#line 9374 "tex.w"
+
+else scan_left_brace();
+/*477:*/
+#line 9426 "tex.w"
+
+unbalance= 1;
+loop{if(xpand)/*478:*/
+#line 9443 "tex.w"
+
+{loop{get_next();
+if(cur_cmd<=max_command)goto done2;
+if(cur_cmd!=the)expand();
+else{q= the_toks();
+if(link(temp_head)!=null)
+{link(p)= link(temp_head);p= q;
+}
+}
+}
+done2:x_token();
+}
+
+/*:478*/
+#line 9428 "tex.w"
+
+else get_token();
+if(cur_tok<right_brace_limit)
+if(cur_cmd<right_brace)incr(unbalance);
+else{decr(unbalance);
+if(unbalance==0)goto found;
+}
+else if(cur_cmd==mac_param)
+if(macro_def)/*479:*/
+#line 9456 "tex.w"
+
+{s= cur_tok;
+if(xpand)get_x_token();else get_token();
+if(cur_cmd!=mac_param)
+if((cur_tok<=zero_token)||(cur_tok> t))
+{print_err("Illegal parameter number in definition of ");
+
+sprint_cs(warning_index);
+help3("You meant to type ## instead of #, right?")
+("Or maybe a } was forgotten somewhere earlier, and things")
+("are all screwed up? I'm going to assume that you meant ##.");
+back_error();cur_tok= s;
+}
+else cur_tok= out_param_token-'0'+cur_chr;
+}
+
+/*:479*/
+#line 9436 "tex.w"
+;
+store_new_token(cur_tok);
+}
+
+/*:477*/
+#line 9376 "tex.w"
+;
+found:scanner_status= normal;
+if(hash_brace!=0)store_new_token(hash_brace);
+return p;
+}
+
+/*:473*//*482:*/
+#line 9493 "tex.w"
+void read_toks(int n,pointer r)
+{
+pointer p;
+pointer q;
+int s;
+small_number m;
+scanner_status= defining;warning_index= r;
+def_ref= get_avail();token_ref_count(def_ref)= null;
+p= def_ref;
+store_new_token(end_match_token);
+if((n<0)||(n> 15))m= 16;else m= n;
+s= align_state;align_state= 1000000;
+do{/*483:*/
+#line 9510 "tex.w"
+
+begin_file_reading();name= m+1;
+if(read_open[m]==closed)/*484:*/
+#line 9534 "tex.w"
+
+if(interaction> nonstop_mode)
+if(n<0)prompt_input("")
+else{wake_up_terminal;
+print_ln();sprint_cs(r);prompt_input("=");n= -1;
+}
+else fatal_error("*** (cannot \\read from terminal in nonstop modes)")
+
+
+/*:484*/
+#line 9512 "tex.w"
+;
+else if(read_open[m]==just_open)/*485:*/
+#line 9547 "tex.w"
+
+if(input_ln(&read_file[m],false))read_open[m]= normal;
+else{a_close(&read_file[m]);read_open[m]= closed;
+}
+
+/*:485*/
+#line 9513 "tex.w"
+
+else/*486:*/
+#line 9555 "tex.w"
+
+{if(!input_ln(&read_file[m],true))
+{a_close(&read_file[m]);read_open[m]= closed;
+if(align_state!=1000000)
+{runaway();
+print_err("File ended within ");print_esc(/*1556:*/
+#line 25564 "tex.w"
+431
+/*:1556*/
+#line 9560 "tex.w"
+);
+
+help1("This \\read has unbalanced braces.");
+align_state= 1000000;error();
+}
+}
+}
+
+/*:486*/
+#line 9514 "tex.w"
+;
+limit= last;
+if(end_line_char_inactive)decr(limit);
+else buffer[limit]= end_line_char;
+first= limit+1;loc= start;state= new_line;
+loop{get_token();
+if(cur_tok==0)goto done;
+
+if(align_state<1000000)
+{do{get_token();}while(!(cur_tok==0));
+align_state= 1000000;goto done;
+}
+store_new_token(cur_tok);
+}
+done:end_file_reading()
+
+/*:483*/
+#line 9505 "tex.w"
+;
+}while(!(align_state==1000000));
+cur_val= def_ref;scanner_status= normal;align_state= s;
+}
+
+/*:482*//*494:*/
+#line 9704 "tex.w"
+void pass_text(void)
+{
+int l;
+small_number save_scanner_status;
+save_scanner_status= scanner_status;scanner_status= skipping;l= 0;
+skip_line= line;
+loop{get_next();
+if(cur_cmd==fi_or_else)
+{if(l==0)goto done;
+if(cur_chr==fi_code)decr(l);
+}
+else if(cur_cmd==if_test)incr(l);
+}
+done:scanner_status= save_scanner_status;
+}
+
+/*:494*//*497:*/
+#line 9741 "tex.w"
+void change_if_limit(small_number l,pointer p)
+{
+pointer q;
+if(p==cond_ptr)if_limit= l;
+else{q= cond_ptr;
+loop{if(q==null)confusion(/*1611:*/
+#line 25729 "tex.w"
+486
+/*:1611*/
+#line 9746 "tex.w"
+);
+
+if(link(q)==p)
+{type(q)= l;return;
+}
+q= link(q);
+}
+}
+}
+
+/*:497*//*498:*/
+#line 9761 "tex.w"
+void conditional(void)
+{
+bool b;
+uint8_t r;
+int m,n;
+pointer p,q;
+small_number save_scanner_status;
+pointer save_cond_ptr;
+small_number this_if;
+/*495:*/
+#line 9726 "tex.w"
+
+{p= get_node(if_node_size);link(p)= cond_ptr;type(p)= if_limit;
+subtype(p)= cur_if;if_line_field(p)= if_line;
+cond_ptr= p;cur_if= cur_chr;if_limit= if_code;if_line= line;
+}
+
+/*:495*/
+#line 9770 "tex.w"
+;save_cond_ptr= cond_ptr;this_if= cur_chr;
+/*501:*/
+#line 9799 "tex.w"
+
+switch(this_if){
+case if_char_code:case if_cat_code:/*506:*/
+#line 9870 "tex.w"
+
+{get_x_token_or_active_char;
+if((cur_cmd> active_char)||(cur_chr> 255))
+{m= relax;n= 256;
+}
+else{m= cur_cmd;n= cur_chr;
+}
+get_x_token_or_active_char;
+if((cur_cmd> active_char)||(cur_chr> 255))
+{cur_cmd= relax;cur_chr= 256;
+}
+if(this_if==if_char_code)b= (n==cur_chr);else b= (m==cur_cmd);
+}
+
+/*:506*/
+#line 9801 "tex.w"
+break;
+case if_int_code:case if_dim_code:/*503:*/
+#line 9827 "tex.w"
+
+{if(this_if==if_int_code)scan_int();else scan_normal_dimen;
+n= cur_val;/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 9829 "tex.w"
+;
+if((cur_tok>=other_token+'<')&&(cur_tok<=other_token+'>'))
+r= cur_tok-other_token;
+else{print_err("Missing = inserted for ");
+
+print_cmd_chr(if_test,this_if);
+help1("I was expecting to see `<', `=', or `>'. Didn't.");
+back_error();r= '=';
+}
+if(this_if==if_int_code)scan_int();else scan_normal_dimen;
+switch(r){
+case'<':b= (n<cur_val);break;
+case'=':b= (n==cur_val);break;
+case'>':b= (n> cur_val);
+}
+}
+
+/*:503*/
+#line 9802 "tex.w"
+break;
+case if_odd_code:/*504:*/
+#line 9846 "tex.w"
+
+{scan_int();b= odd(cur_val);
+}
+
+/*:504*/
+#line 9803 "tex.w"
+break;
+case if_vmode_code:b= (abs(mode)==vmode);break;
+case if_hmode_code:b= (abs(mode)==hmode);break;
+case if_mmode_code:b= (abs(mode)==mmode);break;
+case if_inner_code:b= (mode<0);break;
+case if_void_code:case if_hbox_code:case if_vbox_code:/*505:*/
+#line 9850 "tex.w"
+
+{scan_eight_bit_int();p= box(cur_val);
+if(this_if==if_void_code)b= (p==null);
+else if(p==null)b= false;
+else if(this_if==if_hbox_code)b= (type(p)==hlist_node);
+else b= (type(p)==vlist_node);
+}
+
+/*:505*/
+#line 9808 "tex.w"
+break;
+case ifx_code:/*507:*/
+#line 9891 "tex.w"
+
+{save_scanner_status= scanner_status;scanner_status= normal;
+get_next();n= cur_cs;p= cur_cmd;q= cur_chr;
+get_next();if(cur_cmd!=p)b= false;
+else if(cur_cmd<call)b= (cur_chr==q);
+else/*508:*/
+#line 9908 "tex.w"
+
+{p= link(cur_chr);q= link(equiv(n));
+if(p==q)b= true;
+else{while((p!=null)&&(q!=null))
+if(info(p)!=info(q))p= null;
+else{p= link(p);q= link(q);
+}
+b= ((p==null)&&(q==null));
+}
+}
+
+/*:508*/
+#line 9896 "tex.w"
+;
+scanner_status= save_scanner_status;
+}
+
+/*:507*/
+#line 9809 "tex.w"
+break;
+case if_eof_code:{scan_four_bit_int();b= (read_open[cur_val]==closed);
+}break;
+case if_true_code:b= true;break;
+case if_false_code:b= false;break;
+case if_case_code:/*509:*/
+#line 9919 "tex.w"
+
+{scan_int();n= cur_val;
+if(tracing_commands> 1)
+{begin_diagnostic();print_str("{case ");print_int(n);print_char('}');
+end_diagnostic(false);
+}
+while(n!=0)
+{pass_text();
+if(cond_ptr==save_cond_ptr)
+if(cur_chr==or_code)decr(n);
+else goto common_ending;
+else if(cur_chr==fi_code)/*496:*/
+#line 9732 "tex.w"
+
+{p= cond_ptr;if_line= if_line_field(p);
+cur_if= subtype(p);if_limit= type(p);cond_ptr= link(p);
+free_node(p,if_node_size);
+}
+
+/*:496*/
+#line 9930 "tex.w"
+;
+}
+change_if_limit(or_code,save_cond_ptr);
+return;
+}
+
+/*:509*/
+#line 9814 "tex.w"
+;
+}
+
+/*:501*/
+#line 9771 "tex.w"
+;
+if(tracing_commands> 1)/*502:*/
+#line 9817 "tex.w"
+
+{begin_diagnostic();
+if(b)print_str("{true}");else print_str("{false}");
+end_diagnostic(false);
+}
+
+/*:502*/
+#line 9772 "tex.w"
+;
+if(b)
+{change_if_limit(else_code,save_cond_ptr);
+return;
+}
+/*500:*/
+#line 9787 "tex.w"
+
+loop{pass_text();
+if(cond_ptr==save_cond_ptr)
+{if(cur_chr!=or_code)goto common_ending;
+print_err("Extra ");print_esc(/*1629:*/
+#line 25783 "tex.w"
+504
+/*:1629*/
+#line 9791 "tex.w"
+);
+
+help1("I'm ignoring this; it doesn't match any \\if.");
+error();
+}
+else if(cur_chr==fi_code)/*496:*/
+#line 9732 "tex.w"
+
+{p= cond_ptr;if_line= if_line_field(p);
+cur_if= subtype(p);if_limit= type(p);cond_ptr= link(p);
+free_node(p,if_node_size);
+}
+
+/*:496*/
+#line 9796 "tex.w"
+;
+}
+
+/*:500*/
+#line 9777 "tex.w"
+;
+common_ending:if(cur_chr==fi_code)/*496:*/
+#line 9732 "tex.w"
+
+{p= cond_ptr;if_line= if_line_field(p);
+cur_if= subtype(p);if_limit= type(p);cond_ptr= link(p);
+free_node(p,if_node_size);
+}
+
+/*:496*/
+#line 9778 "tex.w"
+
+else if_limit= fi_code;
+}
+
+/*:498*//*515:*/
+#line 10054 "tex.w"
+void begin_name(void)
+{area_delimiter= 0;ext_delimiter= 0;
+}
+
+/*:515*//*516:*/
+#line 10064 "tex.w"
+bool more_name(ASCII_code c)
+{if(c==' ')return false;
+else{str_room(1);append_char(c);
+if((c=='>')||(c==':'))
+{area_delimiter= cur_length;ext_delimiter= 0;
+}
+else if((c=='.')&&(ext_delimiter==0))ext_delimiter= cur_length;
+return true;
+}
+}
+
+/*:516*//*517:*/
+#line 10078 "tex.w"
+void end_name(void)
+{if(str_ptr+3> max_strings)
+overflow("number of strings",max_strings-init_str_ptr);
+
+if(area_delimiter==0)cur_area= empty_string;
+else{cur_area= str_ptr;
+str_start[str_ptr+1]= str_start[str_ptr]+area_delimiter;incr(str_ptr);
+}
+if(ext_delimiter==0)
+{cur_ext= empty_string;cur_name= make_string();
+}
+else{cur_name= str_ptr;
+str_start[str_ptr+1]= str_start[str_ptr]+ext_delimiter-area_delimiter-1;
+incr(str_ptr);cur_ext= make_string();
+}
+}
+
+/*:517*//*519:*/
+#line 10115 "tex.w"
+void pack_file_name(str_number n,str_number a,str_number e)
+{int k;
+ASCII_code c;
+int j;
+k= 0;
+for(j= str_start[a];j<=str_start[a+1]-1;j++)append_to_name(so(str_pool[j]));
+for(j= str_start[n];j<=str_start[n+1]-1;j++)append_to_name(so(str_pool[j]));
+for(j= str_start[e];j<=str_start[e+1]-1;j++)append_to_name(so(str_pool[j]));
+if(k<=file_name_size)name_length= k;else name_length= file_name_size;
+name_of_file[name_length+1]= 0;
+}
+
+/*:519*//*522:*/
+#line 10158 "tex.w"
+void pack_buffered_name(small_number n,int a,int b)
+{int k;
+ASCII_code c;
+int j;
+if(n+b-a+1+format_ext_length> file_name_size)
+b= a+file_name_size-n-1-format_ext_length;
+k= 0;
+for(j= 1;j<=n;j++)append_to_name(xord[TEX_format_default[j]]);
+for(j= a;j<=b;j++)append_to_name(buffer[j]);
+for(j= format_default_length-format_ext_length+1;j<=format_default_length;j++)
+append_to_name(xord[TEX_format_default[j]]);
+if(k<=file_name_size)name_length= k;else name_length= file_name_size;
+name_of_file[name_length+1]= 0;
+}
+
+/*:522*//*524:*/
+#line 10220 "tex.w"
+str_number make_name_string(void)
+{int k;
+if((pool_ptr+name_length> pool_size)||(str_ptr==max_strings)||
+(cur_length> 0))
+return'?';
+else{for(k= 1;k<=name_length;k++)append_char(xord[name_of_file[k]]);
+return make_string();
+}
+}
+str_number a_make_name_string(alpha_file*f)
+{return make_name_string();
+}
+str_number b_make_name_string(byte_file*f)
+{return make_name_string();
+}
+str_number w_make_name_string(word_file*f)
+{return make_name_string();
+}
+
+/*:524*//*525:*/
+#line 10244 "tex.w"
+void scan_file_name(void)
+{
+name_in_progress= true;begin_name();
+/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 10247 "tex.w"
+;
+loop{if((cur_cmd> other_char)||(cur_chr> 255))
+{back_input();goto done;
+}
+if(!more_name(cur_chr))goto done;
+get_x_token();
+}
+done:end_name();name_in_progress= false;
+}
+
+/*:525*//*528:*/
+#line 10287 "tex.w"
+void pack_job_name(str_number s)
+
+{cur_area= empty_string;cur_ext= s;
+cur_name= job_name;pack_cur_name;
+}
+
+/*:528*//*529:*/
+#line 10300 "tex.w"
+void prompt_file_name(char*s,str_number e)
+{
+uint16_t k;
+if(interaction==scroll_mode)wake_up_terminal;
+if(strcmp(s,"input file name")==0)print_err("I can't find file `")
+
+else print_err("I can't write on file `");
+
+print_file_name(cur_name,cur_area,cur_ext);print_str("'.");
+if(e==/*1637:*/
+#line 25807 "tex.w"
+512
+/*:1637*/
+#line 10309 "tex.w"
+)show_context();
+print_nl("Please type another ");print_str(s);
+
+if(interaction<scroll_mode)
+fatal_error("*** (job aborted, file error in nonstop mode)");
+
+clear_terminal;prompt_input(": ");/*530:*/
+#line 10320 "tex.w"
+
+{begin_name();k= first;
+while((buffer[k]==' ')&&(k<last))incr(k);
+loop{if(k==last)goto done;
+if(!more_name(buffer[k]))goto done;
+incr(k);
+}
+done:end_name();
+}
+
+/*:530*/
+#line 10315 "tex.w"
+;
+if(cur_ext==empty_string)cur_ext= e;
+pack_cur_name;
+}
+
+/*:529*//*534:*/
+#line 10352 "tex.w"
+void open_log_file(void)
+{uint8_t old_setting;
+int k;
+uint16_t l;
+ASCII_code months[]= " JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
+old_setting= selector;
+if(job_name==0)job_name= /*1638:*/
+#line 25810 "tex.w"
+513
+/*:1638*/
+#line 10358 "tex.w"
+;
+
+pack_job_name(/*1634:*/
+#line 25798 "tex.w"
+509
+/*:1634*/
+#line 10360 "tex.w"
+);
+while(!a_open_out(&log_file))/*535:*/
+#line 10389 "tex.w"
+
+{selector= term_only;
+prompt_file_name("transcript file name",/*1634:*/
+#line 25798 "tex.w"
+509
+/*:1634*/
+#line 10391 "tex.w"
+);
+}
+
+/*:535*/
+#line 10361 "tex.w"
+;
+log_name= a_make_name_string(&log_file);
+selector= log_only;log_opened= true;
+/*536:*/
+#line 10394 "tex.w"
+
+{wlog("%s",banner);
+slow_print(format_ident);print_str(" ");
+print_int(day);print_char(' ');
+for(k= 3*month-2;k<=3*month;k++)wlog("%c",months[k]);
+print_char(' ');print_int(year);print_char(' ');
+print_two(time/60);print_char(':');print_two(time%60);
+}
+
+/*:536*/
+#line 10364 "tex.w"
+;
+input_stack[input_ptr]= cur_input;
+print_nl("**");
+
+l= input_stack[0].limit_field;
+if(buffer[l]==end_line_char)decr(l);
+for(k= 1;k<=l;k++)print(buffer[k]);
+print_ln();
+selector= old_setting+2;
+}
+
+/*:534*//*537:*/
+#line 10406 "tex.w"
+void start_input(void)
+{
+scan_file_name();
+if(cur_ext==empty_string)cur_ext= /*1637:*/
+#line 25807 "tex.w"
+512
+/*:1637*/
+#line 10409 "tex.w"
+;
+pack_cur_name;
+loop{begin_file_reading();
+if(a_open_in(&cur_file))goto done;
+if(cur_area==empty_string)
+{pack_file_name(cur_name,TEX_area,cur_ext);
+if(a_open_in(&cur_file))goto done;
+}
+end_file_reading();
+prompt_file_name("input file name",/*1637:*/
+#line 25807 "tex.w"
+512
+/*:1637*/
+#line 10418 "tex.w"
+);
+}
+done:name= a_make_name_string(&cur_file);
+if(job_name==0)
+{job_name= cur_name;open_log_file();
+}
+
+if(term_offset+length(name)> max_print_line-2)print_ln();
+else if((term_offset> 0)||(file_offset> 0))print_char(' ');
+print_char('(');incr(open_parens);slow_print(name);update_terminal;
+state= new_line;
+if(name==str_ptr-1)
+{flush_string;name= cur_name;
+}
+/*538:*/
+#line 10441 "tex.w"
+
+{line= 1;
+if(input_ln(&cur_file,false))do_nothing;
+firm_up_the_line();
+if(end_line_char_inactive)decr(limit);
+else buffer[limit]= end_line_char;
+first= limit+1;loc= start;
+}
+
+/*:538*/
+#line 10432 "tex.w"
+;
+}
+
+/*:537*//*560:*/
+#line 10946 "tex.w"
+internal_font_number read_font_info(pointer u,str_number nom,str_number aire,
+scaled s)
+{
+font_index k;
+bool file_opened;
+halfword lf,lh,bc,ec,nw,nh,nd,ni,nl,nk,ne,np;
+
+internal_font_number f;
+internal_font_number g;
+eight_bits a,b,c,d;
+four_quarters qw;scaled sw;
+int bch_label;
+uint16_t bchar;
+scaled z;
+int alpha;uint8_t beta;
+
+g= null_font;
+/*562:*/
+#line 10999 "tex.w"
+
+/*563:*/
+#line 11011 "tex.w"
+
+file_opened= false;
+if(aire==empty_string)pack_file_name(nom,TEX_font_area,/*1640:*/
+#line 25816 "tex.w"
+515
+/*:1640*/
+#line 11013 "tex.w"
+);
+else pack_file_name(nom,aire,/*1640:*/
+#line 25816 "tex.w"
+515
+/*:1640*/
+#line 11014 "tex.w"
+);
+if(!b_open_in(&tfm_file))abort;
+file_opened= true
+
+/*:563*/
+#line 11000 "tex.w"
+;
+/*565:*/
+#line 11039 "tex.w"
+
+{read_sixteen(lf);
+fget;read_sixteen(lh);
+fget;read_sixteen(bc);
+fget;read_sixteen(ec);
+if((bc> ec+1)||(ec> 255))abort;
+if(bc> 255)
+{bc= 1;ec= 0;
+}
+fget;read_sixteen(nw);
+fget;read_sixteen(nh);
+fget;read_sixteen(nd);
+fget;read_sixteen(ni);
+fget;read_sixteen(nl);
+fget;read_sixteen(nk);
+fget;read_sixteen(ne);
+fget;read_sixteen(np);
+if(lf!=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np)abort;
+if((nw==0)||(nh==0)||(nd==0)||(ni==0))abort;
+}
+
+/*:565*/
+#line 11001 "tex.w"
+;
+/*566:*/
+#line 11066 "tex.w"
+
+lf= lf-6-lh;
+if(np<7)lf= lf+7-np;
+if((font_ptr==font_max)||(fmem_ptr+lf> font_mem_size))
+/*567:*/
+#line 11082 "tex.w"
+
+{start_font_error_message;
+print_str(" not loaded: Not enough room left");
+
+help4("I'm afraid I won't be able to make use of this font,")
+("because my memory for character-size data is too small.")
+("If you're really stuck, ask a wizard to enlarge me.")
+("Or maybe try `I\\font<same font id>=<name of loaded font>'.");
+error();goto done;
+}
+
+/*:567*/
+#line 11070 "tex.w"
+;
+f= font_ptr+1;
+char_base[f]= fmem_ptr-bc;
+width_base[f]= char_base[f]+ec+1;
+height_base[f]= width_base[f]+nw;
+depth_base[f]= height_base[f]+nh;
+italic_base[f]= depth_base[f]+nd;
+lig_kern_base[f]= italic_base[f]+ni;
+kern_base[f]= lig_kern_base[f]+nl-kern_base_offset;
+exten_base[f]= kern_base[f]+kern_base_offset+nk;
+param_base[f]= exten_base[f]+ne
+
+/*:566*/
+#line 11002 "tex.w"
+;
+/*568:*/
+#line 11095 "tex.w"
+
+{if(lh<2)abort;
+store_four_quarters(font_check[f]);
+fget;read_sixteen(z);
+fget;z= z*0400+fbyte;fget;z= (z*020)+(fbyte/020);
+if(z<unity)abort;
+while(lh> 2)
+{fget;fget;fget;fget;decr(lh);
+}
+font_dsize[f]= z;
+if(s!=-1000)
+if(s>=0)z= s;
+else z= xn_over_d(z,-s,1000);
+font_size[f]= z;
+}
+
+/*:568*/
+#line 11003 "tex.w"
+;
+/*569:*/
+#line 11111 "tex.w"
+
+for(k= fmem_ptr;k<=width_base[f]-1;k++)
+{store_four_quarters(font_info[k].qqqq);
+if((a>=nw)||(b/020>=nh)||(b%020>=nd)||
+(c/4>=ni))abort;
+switch(c%4){
+case lig_tag:if(d>=nl)abort;break;
+case ext_tag:if(d>=ne)abort;break;
+case list_tag:/*570:*/
+#line 11132 "tex.w"
+
+{check_byte_range(d);
+while(d<current_character_being_worked_on)
+{qw= char_info(f)(d);
+
+if(char_tag(qw)!=list_tag)goto not_found;
+d= qo(rem_byte(qw));
+}
+if(d==current_character_being_worked_on)abort;
+not_found:;}
+
+/*:570*/
+#line 11119 "tex.w"
+break;
+default:do_nothing;
+}
+}
+
+/*:569*/
+#line 11004 "tex.w"
+;
+/*571:*/
+#line 11167 "tex.w"
+
+{/*572:*/
+#line 11177 "tex.w"
+
+{alpha= 16;
+while(z>=040000000)
+{z= z/2;alpha= alpha+alpha;
+}
+beta= 256/alpha;alpha= alpha*z;
+}
+
+/*:572*/
+#line 11168 "tex.w"
+;
+for(k= width_base[f];k<=lig_kern_base[f]-1;k++)
+store_scaled(font_info[k].sc);
+if(font_info[width_base[f]].sc!=0)abort;
+if(font_info[height_base[f]].sc!=0)abort;
+if(font_info[depth_base[f]].sc!=0)abort;
+if(font_info[italic_base[f]].sc!=0)abort;
+}
+
+/*:571*/
+#line 11005 "tex.w"
+;
+/*573:*/
+#line 11191 "tex.w"
+
+bch_label= 077777;bchar= 256;
+if(nl> 0)
+{for(k= lig_kern_base[f];k<=kern_base[f]+kern_base_offset-1;k++)
+{store_four_quarters(font_info[k].qqqq);
+if(a> 128)
+{if(256*c+d>=nl)abort;
+if(a==255)if(k==lig_kern_base[f])bchar= b;
+}
+else{if(b!=bchar)check_existence(b);
+if(c<128)check_existence(d)
+else if(256*(c-128)+d>=nk)abort;
+if(a<128)if(k-lig_kern_base[f]+a+1>=nl)abort;
+}
+}
+if(a==255)bch_label= 256*c+d;
+}
+for(k= kern_base[f]+kern_base_offset;k<=exten_base[f]-1;k++)
+store_scaled(font_info[k].sc);
+
+/*:573*/
+#line 11006 "tex.w"
+;
+/*574:*/
+#line 11211 "tex.w"
+
+for(k= exten_base[f];k<=param_base[f]-1;k++)
+{store_four_quarters(font_info[k].qqqq);
+if(a!=0)check_existence(a);
+if(b!=0)check_existence(b);
+if(c!=0)check_existence(c);
+check_existence(d);
+}
+
+/*:574*/
+#line 11007 "tex.w"
+;
+/*575:*/
+#line 11223 "tex.w"
+
+{for(k= 1;k<=np;k++)
+if(k==1)
+{fget;sw= fbyte;if(sw> 127)sw= sw-256;
+fget;sw= sw*0400+fbyte;fget;sw= sw*0400+fbyte;
+fget;font_info[param_base[f]].sc=
+(sw*020)+(fbyte/020);
+}
+else store_scaled(font_info[param_base[f]+k-1].sc);
+if(eof(tfm_file))abort;
+for(k= np+1;k<=7;k++)font_info[param_base[f]+k-1].sc= 0;
+}
+
+/*:575*/
+#line 11008 "tex.w"
+;
+/*576:*/
+#line 11243 "tex.w"
+
+if(np>=7)font_params[f]= np;else font_params[f]= 7;
+hyphen_char[f]= default_hyphen_char;skew_char[f]= default_skew_char;
+if(bch_label<nl)bchar_label[f]= bch_label+lig_kern_base[f];
+else bchar_label[f]= non_address;
+font_bchar[f]= qi(bchar);
+font_false_bchar[f]= qi(bchar);
+if(bchar<=ec)if(bchar>=bc)
+{qw= char_info(f)(bchar);
+if(char_exists(qw))font_false_bchar[f]= non_char;
+}
+font_name[f]= nom;
+font_area[f]= aire;
+font_bc[f]= bc;font_ec[f]= ec;font_glue[f]= null;
+adjust(char_base);adjust(width_base);adjust(lig_kern_base);
+adjust(kern_base);adjust(exten_base);
+decr(param_base[f]);
+fmem_ptr= fmem_ptr+lf;font_ptr= f;g= f;goto done
+
+/*:576*/
+#line 11009 "tex.w"
+
+
+/*:562*/
+#line 10965 "tex.w"
+;
+bad_tfm:/*561:*/
+#line 10987 "tex.w"
+
+start_font_error_message;
+
+if(file_opened)print_str(" not loadable: Bad metric (TFM) file");
+else print_str(" not loadable: Metric (TFM) file not found");
+help5("I wasn't able to read the size data for this font,")
+("so I will ignore the font specification.")
+("[Wizards can fix TFM files using TFtoPL/PLtoTF.]")
+("You might try inserting a different font spec;")
+("e.g., type `I\\font<same font id>=<substitute font name>'.");
+error()
+
+/*:561*/
+#line 10966 "tex.w"
+;
+done:if(file_opened)b_close(&tfm_file);
+return g;
+}
+
+/*:560*//*581:*/
+#line 11333 "tex.w"
+void char_warning(internal_font_number f,eight_bits c)
+{if(tracing_lost_chars> 0)
+{begin_diagnostic();
+print_nl("Missing character: There is no ");
+
+print_ASCII(c);print_str(" in font ");
+slow_print(font_name[f]);print_char('!');end_diagnostic(false);
+}
+}
+
+/*:581*//*582:*/
+#line 11347 "tex.w"
+pointer new_character(internal_font_number f,eight_bits c)
+{
+pointer p;
+if(font_bc[f]<=c)if(font_ec[f]>=c)
+if(char_exists(char_info(f)(qi(c))))
+{p= get_avail();font(p)= f;character(p)= qi(c);
+return p;
+}
+char_warning(f,c);
+return null;
+}
+
+/*:582*//*597:*/
+#line 11957 "tex.w"
+void write_dvi(dvi_index a,dvi_index b)
+{int k;
+for(k= a;k<=b;k++)write(dvi_file,"%c",dvi_buf[k]);
+}
+
+/*:597*//*598:*/
+#line 11969 "tex.w"
+void dvi_swap(void)
+{if(dvi_limit==dvi_buf_size)
+{write_dvi(0,half_buf-1);dvi_limit= half_buf;
+dvi_offset= dvi_offset+dvi_buf_size;dvi_ptr= 0;
+}
+else{write_dvi(half_buf,dvi_buf_size-1);dvi_limit= dvi_buf_size;
+}
+dvi_gone= dvi_gone+half_buf;
+}
+
+/*:598*//*600:*/
+#line 11989 "tex.w"
+void dvi_four(int x)
+{if(x>=0)dvi_out(x/0100000000)
+else{x= x+010000000000;
+x= x+010000000000;
+dvi_out((x/0100000000)+128);
+}
+x= x%0100000000;dvi_out(x/0200000);
+x= x%0200000;dvi_out(x/0400);
+dvi_out(x%0400);
+}
+
+/*:600*//*601:*/
+#line 12005 "tex.w"
+void dvi_pop(int l)
+{if((l==dvi_offset+dvi_ptr)&&(dvi_ptr> 0))decr(dvi_ptr);
+else dvi_out(pop);
+}
+
+/*:601*//*602:*/
+#line 12013 "tex.w"
+void dvi_font_def(internal_font_number f)
+{int k;
+dvi_out(fnt_def1);
+dvi_out(f-font_base-1);
+dvi_out(qo(font_check[f].b0));
+dvi_out(qo(font_check[f].b1));
+dvi_out(qo(font_check[f].b2));
+dvi_out(qo(font_check[f].b3));
+dvi_four(font_size[f]);
+dvi_four(font_dsize[f]);
+dvi_out(length(font_area[f]));
+dvi_out(length(font_name[f]));
+/*603:*/
+#line 12028 "tex.w"
+
+for(k= str_start[font_area[f]];k<=str_start[font_area[f]+1]-1;k++)
+dvi_out(so(str_pool[k]));
+for(k= str_start[font_name[f]];k<=str_start[font_name[f]+1]-1;k++)
+dvi_out(so(str_pool[k]))
+
+/*:603*/
+#line 12025 "tex.w"
+;
+}
+
+/*:602*//*607:*/
+#line 12107 "tex.w"
+void movement(scaled w,eight_bits o)
+{
+small_number mstate;
+pointer p,q;
+int k;
+q= get_node(movement_node_size);
+width(q)= w;location(q)= dvi_offset+dvi_ptr;
+if(o==down1)
+{link(q)= down_ptr;down_ptr= q;
+}
+else{link(q)= right_ptr;right_ptr= q;
+}
+/*611:*/
+#line 12222 "tex.w"
+
+p= link(q);mstate= none_seen;
+while(p!=null)
+{if(width(p)==w)/*612:*/
+#line 12241 "tex.w"
+
+switch(mstate+info(p)){
+case none_seen+yz_OK:case none_seen+y_OK:case z_seen+yz_OK:case z_seen+y_OK:
+if(location(p)<dvi_gone)goto not_found;
+else/*613:*/
+#line 12253 "tex.w"
+
+{k= location(p)-dvi_offset;
+if(k<0)k= k+dvi_buf_size;
+dvi_buf[k]= dvi_buf[k]+y1-down1;
+info(p)= y_here;goto found;
+}
+
+/*:613*/
+#line 12245 "tex.w"
+break;
+case none_seen+z_OK:case y_seen+yz_OK:case y_seen+z_OK:
+if(location(p)<dvi_gone)goto not_found;
+else/*614:*/
+#line 12260 "tex.w"
+
+{k= location(p)-dvi_offset;
+if(k<0)k= k+dvi_buf_size;
+dvi_buf[k]= dvi_buf[k]+z1-down1;
+info(p)= z_here;goto found;
+}
+
+/*:614*/
+#line 12248 "tex.w"
+break;
+case none_seen+y_here:case none_seen+z_here:case y_seen+z_here:case z_seen+y_here:goto found;
+default:do_nothing;
+}
+
+/*:612*/
+#line 12226 "tex.w"
+
+else switch(mstate+info(p)){
+case none_seen+y_here:mstate= y_seen;break;
+case none_seen+z_here:mstate= z_seen;break;
+case y_seen+z_here:case z_seen+y_here:goto not_found;
+default:do_nothing;
+}
+p= link(p);
+}
+not_found:
+
+/*:611*/
+#line 12120 "tex.w"
+;
+/*610:*/
+#line 12189 "tex.w"
+
+info(q)= yz_OK;
+if(abs(w)>=040000000)
+{dvi_out(o+3);
+dvi_four(w);return;
+}
+if(abs(w)>=0100000)
+{dvi_out(o+2);
+if(w<0)w= w+0100000000;
+dvi_out(w/0200000);w= w%0200000;goto label2;
+}
+if(abs(w)>=0200)
+{dvi_out(o+1);
+if(w<0)w= w+0200000;
+goto label2;
+}
+dvi_out(o);
+if(w<0)w= w+0400;
+goto label1;
+label2:dvi_out(w/0400);
+label1:dvi_out(w%0400);return
+
+/*:610*/
+#line 12121 "tex.w"
+;
+found:/*609:*/
+#line 12165 "tex.w"
+
+info(q)= info(p);
+if(info(q)==y_here)
+{dvi_out(o+y0-down1);
+while(link(q)!=p)
+{q= link(q);
+switch(info(q)){
+case yz_OK:info(q)= z_OK;break;
+case y_OK:info(q)= d_fixed;break;
+default:do_nothing;
+}
+}
+}
+else{dvi_out(o+z0-down1);
+while(link(q)!=p)
+{q= link(q);
+switch(info(q)){
+case yz_OK:info(q)= y_OK;break;
+case z_OK:info(q)= d_fixed;break;
+default:do_nothing;
+}
+}
+}
+
+/*:609*/
+#line 12122 "tex.w"
+;
+}
+
+/*:607*//*615:*/
+#line 12273 "tex.w"
+void prune_movements(int l)
+
+{
+pointer p;
+while(down_ptr!=null)
+{if(location(down_ptr)<l)goto done;
+p= down_ptr;down_ptr= link(p);free_node(p,movement_node_size);
+}
+done:while(right_ptr!=null)
+{if(location(right_ptr)<l)return;
+p= right_ptr;right_ptr= link(p);free_node(p,movement_node_size);
+}
+}
+
+/*:615*//*618:*/
+#line 12350 "tex.w"
+void vlist_out(void);
+
+
+/*:618*//*619:*/
+#line 12359 "tex.w"
+/*1368:*/
+#line 24824 "tex.w"
+
+void special_out(pointer p)
+{uint8_t old_setting;
+int k;
+synch_h;synch_v;
+old_setting= selector;selector= new_string;
+show_token_list(link(write_tokens(p)),null,pool_size-pool_ptr);
+selector= old_setting;
+str_room(1);
+if(cur_length<256)
+{dvi_out(xxx1);dvi_out(cur_length);
+}
+else{dvi_out(xxx4);dvi_four(cur_length);
+}
+for(k= str_start[str_ptr];k<=pool_ptr-1;k++)dvi_out(so(str_pool[k]));
+pool_ptr= str_start[str_ptr];
+}
+
+/*:1368*//*1370:*/
+#line 24855 "tex.w"
+
+void write_out(pointer p)
+{uint8_t old_setting;
+int old_mode;
+small_number j;
+pointer q,r;
+/*1371:*/
+#line 24882 "tex.w"
+
+q= get_avail();info(q)= right_brace_token+'}';
+r= get_avail();link(q)= r;info(r)= end_write_token;ins_list(q);
+begin_token_list(write_tokens(p),write_text);
+q= get_avail();info(q)= left_brace_token+'{';ins_list(q);
+
+
+old_mode= mode;mode= 0;
+
+cur_cs= write_loc;q= scan_toks(false,true);
+get_token();if(cur_tok!=end_write_token)
+/*1372:*/
+#line 24897 "tex.w"
+
+{print_err("Unbalanced write command");
+
+help2("On this page there's a \\write with fewer real {'s than }'s.")
+("I can't handle that very well; good luck.");error();
+do{get_token();
+}while(!(cur_tok==end_write_token));
+}
+
+/*:1372*/
+#line 24893 "tex.w"
+;
+mode= old_mode;
+end_token_list()
+
+/*:1371*/
+#line 24861 "tex.w"
+;
+old_setting= selector;j= write_stream(p);
+if(write_open[j])selector= j;
+else{
+if((j==17)&&(selector==term_and_log))selector= log_only;
+print_nl("");
+}
+token_show(def_ref);print_ln();
+flush_list(def_ref);selector= old_setting;
+}
+
+/*:1370*//*1373:*/
+#line 24909 "tex.w"
+
+void out_what(pointer p)
+{small_number j;
+switch(subtype(p)){
+case open_node:case write_node:case close_node:/*1374:*/
+#line 24927 "tex.w"
+
+if(!doing_leaders)
+{j= write_stream(p);
+if(subtype(p)==write_node)write_out(p);
+else{if(write_open[j])a_close(&write_file[j]);
+if(subtype(p)==close_node)write_open[j]= false;
+else if(j<16)
+{cur_name= open_name(p);cur_area= open_area(p);
+cur_ext= open_ext(p);
+if(cur_ext==empty_string)cur_ext= /*1637:*/
+#line 25807 "tex.w"
+512
+/*:1637*/
+#line 24936 "tex.w"
+;
+pack_cur_name;
+while(!a_open_out(&write_file[j]))
+prompt_file_name("output file name",/*1637:*/
+#line 25807 "tex.w"
+512
+/*:1637*/
+#line 24939 "tex.w"
+);
+write_open[j]= true;
+}
+}
+}
+
+/*:1374*/
+#line 24914 "tex.w"
+break;
+case special_node:special_out(p);break;
+case language_node:do_nothing;break;
+default:confusion(/*1792:*/
+#line 26272 "tex.w"
+667
+
+/*:1792*/
+#line 24917 "tex.w"
+);
+
+}
+}
+
+/*:1373*/
+#line 12359 "tex.w"
+
+void hlist_out(void)
+{
+scaled base_line;
+scaled left_edge;
+scaled save_h,save_v;
+pointer this_box;
+glue_ord g_order;
+uint8_t g_sign;
+pointer p;
+int save_loc;
+pointer leader_box;
+scaled leader_wd;
+scaled lx;
+bool outer_doing_leaders;
+scaled edge;
+double glue_temp;
+double cur_glue;
+scaled cur_g;
+cur_g= 0;cur_glue= float_constant(0);
+this_box= temp_ptr;g_order= glue_order(this_box);
+g_sign= glue_sign(this_box);p= list_ptr(this_box);
+incr(cur_s);
+if(cur_s> 0)dvi_out(push);
+if(cur_s> max_push)max_push= cur_s;
+save_loc= dvi_offset+dvi_ptr;base_line= cur_v;left_edge= cur_h;
+while(p!=null)/*620:*/
+#line 12398 "tex.w"
+
+reswitch:if(is_char_node(p))
+{synch_h;synch_v;
+do{f= font(p);c= character(p);
+if(f!=dvi_f)/*621:*/
+#line 12412 "tex.w"
+
+{if(!font_used[f])
+{dvi_font_def(f);font_used[f]= true;
+}
+if(f<=64+font_base)dvi_out(f-font_base-1+fnt_num_0)
+else{dvi_out(fnt1);dvi_out(f-font_base-1);
+}
+dvi_f= f;
+}
+
+/*:621*/
+#line 12402 "tex.w"
+;
+if(c>=qi(128))dvi_out(set1);
+dvi_out(qo(c));
+cur_h= cur_h+char_width(f)(char_info(f)(c));
+p= link(p);
+}while(!(!is_char_node(p)));
+dvi_h= cur_h;
+}
+else/*622:*/
+#line 12422 "tex.w"
+
+{switch(type(p)){
+case hlist_node:case vlist_node:/*623:*/
+#line 12440 "tex.w"
+
+if(list_ptr(p)==null)cur_h= cur_h+width(p);
+else{save_h= dvi_h;save_v= dvi_v;
+cur_v= base_line+shift_amount(p);
+temp_ptr= p;edge= cur_h;
+if(type(p)==vlist_node)vlist_out();else hlist_out();
+dvi_h= save_h;dvi_v= save_v;
+cur_h= edge+width(p);cur_v= base_line;
+}
+
+/*:623*/
+#line 12424 "tex.w"
+break;
+case rule_node:{rule_ht= height(p);rule_dp= depth(p);rule_wd= width(p);
+goto fin_rule;
+}
+case whatsit_node:/*1367:*/
+#line 24817 "tex.w"
+
+out_what(p)
+
+/*:1367*/
+#line 12428 "tex.w"
+;break;
+case glue_node:/*625:*/
+#line 12467 "tex.w"
+
+{g= glue_ptr(p);rule_wd= width(g)-cur_g;
+if(g_sign!=normal)
+{if(g_sign==stretching)
+{if(stretch_order(g)==g_order)
+{cur_glue= cur_glue+stretch(g);
+vet_glue(float(glue_set(this_box))*cur_glue);
+
+cur_g= round(glue_temp);
+}
+}
+else if(shrink_order(g)==g_order)
+{cur_glue= cur_glue-shrink(g);
+vet_glue(float(glue_set(this_box))*cur_glue);
+cur_g= round(glue_temp);
+}
+}
+rule_wd= rule_wd+cur_g;
+if(subtype(p)>=a_leaders)
+/*626:*/
+#line 12490 "tex.w"
+
+{leader_box= leader_ptr(p);
+if(type(leader_box)==rule_node)
+{rule_ht= height(leader_box);rule_dp= depth(leader_box);
+goto fin_rule;
+}
+leader_wd= width(leader_box);
+if((leader_wd> 0)&&(rule_wd> 0))
+{rule_wd= rule_wd+10;
+edge= cur_h+rule_wd;lx= 0;
+/*627:*/
+#line 12524 "tex.w"
+
+if(subtype(p)==a_leaders)
+{save_h= cur_h;
+cur_h= left_edge+leader_wd*((cur_h-left_edge)/leader_wd);
+if(cur_h<save_h)cur_h= cur_h+leader_wd;
+}
+else{lq= rule_wd/leader_wd;
+lr= rule_wd%leader_wd;
+if(subtype(p)==c_leaders)cur_h= cur_h+(lr/2);
+else{lx= lr/(lq+1);
+cur_h= cur_h+((lr-(lq-1)*lx)/2);
+}
+}
+
+/*:627*/
+#line 12501 "tex.w"
+;
+while(cur_h+leader_wd<=edge)
+/*628:*/
+#line 12541 "tex.w"
+
+{cur_v= base_line+shift_amount(leader_box);synch_v;save_v= dvi_v;
+synch_h;save_h= dvi_h;temp_ptr= leader_box;
+outer_doing_leaders= doing_leaders;doing_leaders= true;
+if(type(leader_box)==vlist_node)vlist_out();else hlist_out();
+doing_leaders= outer_doing_leaders;
+dvi_v= save_v;dvi_h= save_h;cur_v= base_line;
+cur_h= save_h+leader_wd+lx;
+}
+
+/*:628*/
+#line 12503 "tex.w"
+;
+cur_h= edge-10;goto next_p;
+}
+}
+
+/*:626*/
+#line 12486 "tex.w"
+;
+goto move_past;
+}
+
+/*:625*/
+#line 12429 "tex.w"
+
+case kern_node:case math_node:cur_h= cur_h+width(p);break;
+case ligature_node:/*652:*/
+#line 12994 "tex.w"
+
+{mem[lig_trick]= mem[lig_char(p)];link(lig_trick)= link(p);
+p= lig_trick;goto reswitch;
+}
+
+/*:652*/
+#line 12431 "tex.w"
+
+default:do_nothing;
+}
+goto next_p;
+fin_rule:/*624:*/
+#line 12450 "tex.w"
+
+if(is_running(rule_ht))rule_ht= height(this_box);
+if(is_running(rule_dp))rule_dp= depth(this_box);
+rule_ht= rule_ht+rule_dp;
+if((rule_ht> 0)&&(rule_wd> 0))
+{synch_h;cur_v= base_line+rule_dp;synch_v;
+dvi_out(set_rule);dvi_four(rule_ht);dvi_four(rule_wd);
+cur_v= base_line;dvi_h= dvi_h+rule_wd;
+}
+
+/*:624*/
+#line 12435 "tex.w"
+;
+move_past:cur_h= cur_h+rule_wd;
+next_p:p= link(p);
+}
+
+/*:622*/
+#line 12410 "tex.w"
+
+
+/*:620*/
+#line 12386 "tex.w"
+;
+prune_movements(save_loc);
+if(cur_s> 0)dvi_pop(save_loc);
+decr(cur_s);
+}
+
+/*:619*//*629:*/
+#line 12553 "tex.w"
+void vlist_out(void)
+{
+scaled left_edge;
+scaled top_edge;
+scaled save_h,save_v;
+pointer this_box;
+glue_ord g_order;
+uint8_t g_sign;
+pointer p;
+int save_loc;
+pointer leader_box;
+scaled leader_ht;
+scaled lx;
+bool outer_doing_leaders;
+scaled edge;
+double glue_temp;
+double cur_glue;
+scaled cur_g;
+cur_g= 0;cur_glue= float_constant(0);
+this_box= temp_ptr;g_order= glue_order(this_box);
+g_sign= glue_sign(this_box);p= list_ptr(this_box);
+incr(cur_s);
+if(cur_s> 0)dvi_out(push);
+if(cur_s> max_push)max_push= cur_s;
+save_loc= dvi_offset+dvi_ptr;left_edge= cur_h;cur_v= cur_v-height(this_box);
+top_edge= cur_v;
+while(p!=null)/*630:*/
+#line 12586 "tex.w"
+
+{if(is_char_node(p))confusion(/*1641:*/
+#line 25819 "tex.w"
+516
+/*:1641*/
+#line 12587 "tex.w"
+);
+
+else/*631:*/
+#line 12593 "tex.w"
+
+{switch(type(p)){
+case hlist_node:case vlist_node:/*632:*/
+#line 12613 "tex.w"
+
+if(list_ptr(p)==null)cur_v= cur_v+height(p)+depth(p);
+else{cur_v= cur_v+height(p);synch_v;
+save_h= dvi_h;save_v= dvi_v;
+cur_h= left_edge+shift_amount(p);
+temp_ptr= p;
+if(type(p)==vlist_node)vlist_out();else hlist_out();
+dvi_h= save_h;dvi_v= save_v;
+cur_v= save_v+depth(p);cur_h= left_edge;
+}
+
+/*:632*/
+#line 12595 "tex.w"
+break;
+case rule_node:{rule_ht= height(p);rule_dp= depth(p);rule_wd= width(p);
+goto fin_rule;
+}
+case whatsit_node:/*1366:*/
+#line 24814 "tex.w"
+
+out_what(p)
+
+/*:1366*/
+#line 12599 "tex.w"
+;break;
+case glue_node:/*634:*/
+#line 12634 "tex.w"
+
+{g= glue_ptr(p);rule_ht= width(g)-cur_g;
+if(g_sign!=normal)
+{if(g_sign==stretching)
+{if(stretch_order(g)==g_order)
+{cur_glue= cur_glue+stretch(g);
+vet_glue(float(glue_set(this_box))*cur_glue);
+
+cur_g= round(glue_temp);
+}
+}
+else if(shrink_order(g)==g_order)
+{cur_glue= cur_glue-shrink(g);
+vet_glue(float(glue_set(this_box))*cur_glue);
+cur_g= round(glue_temp);
+}
+}
+rule_ht= rule_ht+cur_g;
+if(subtype(p)>=a_leaders)
+/*635:*/
+#line 12657 "tex.w"
+
+{leader_box= leader_ptr(p);
+if(type(leader_box)==rule_node)
+{rule_wd= width(leader_box);rule_dp= 0;
+goto fin_rule;
+}
+leader_ht= height(leader_box)+depth(leader_box);
+if((leader_ht> 0)&&(rule_ht> 0))
+{rule_ht= rule_ht+10;
+edge= cur_v+rule_ht;lx= 0;
+/*636:*/
+#line 12675 "tex.w"
+
+if(subtype(p)==a_leaders)
+{save_v= cur_v;
+cur_v= top_edge+leader_ht*((cur_v-top_edge)/leader_ht);
+if(cur_v<save_v)cur_v= cur_v+leader_ht;
+}
+else{lq= rule_ht/leader_ht;
+lr= rule_ht%leader_ht;
+if(subtype(p)==c_leaders)cur_v= cur_v+(lr/2);
+else{lx= lr/(lq+1);
+cur_v= cur_v+((lr-(lq-1)*lx)/2);
+}
+}
+
+/*:636*/
+#line 12668 "tex.w"
+;
+while(cur_v+leader_ht<=edge)
+/*637:*/
+#line 12692 "tex.w"
+
+{cur_h= left_edge+shift_amount(leader_box);synch_h;save_h= dvi_h;
+cur_v= cur_v+height(leader_box);synch_v;save_v= dvi_v;
+temp_ptr= leader_box;
+outer_doing_leaders= doing_leaders;doing_leaders= true;
+if(type(leader_box)==vlist_node)vlist_out();else hlist_out();
+doing_leaders= outer_doing_leaders;
+dvi_v= save_v;dvi_h= save_h;cur_h= left_edge;
+cur_v= save_v-height(leader_box)+leader_ht+lx;
+}
+
+/*:637*/
+#line 12670 "tex.w"
+;
+cur_v= edge-10;goto next_p;
+}
+}
+
+/*:635*/
+#line 12653 "tex.w"
+;
+goto move_past;
+}
+
+/*:634*/
+#line 12600 "tex.w"
+
+case kern_node:cur_v= cur_v+width(p);break;
+default:do_nothing;
+}
+goto next_p;
+fin_rule:/*633:*/
+#line 12624 "tex.w"
+
+if(is_running(rule_wd))rule_wd= width(this_box);
+rule_ht= rule_ht+rule_dp;
+cur_v= cur_v+rule_ht;
+if((rule_ht> 0)&&(rule_wd> 0))
+{synch_h;synch_v;
+dvi_out(put_rule);dvi_four(rule_ht);dvi_four(rule_wd);
+}
+goto next_p
+
+/*:633*/
+#line 12605 "tex.w"
+;
+move_past:cur_v= cur_v+rule_ht;
+}
+
+/*:631*/
+#line 12589 "tex.w"
+;
+next_p:p= link(p);
+}
+
+/*:630*/
+#line 12580 "tex.w"
+;
+prune_movements(save_loc);
+if(cur_s> 0)dvi_pop(save_loc);
+decr(cur_s);
+}
+
+/*:629*//*638:*/
+#line 12706 "tex.w"
+void ship_out(pointer p)
+{
+int page_loc;
+uint8_t j,k;
+int s;
+uint8_t old_setting;
+if(tracing_output> 0)
+{print_nl("");print_ln();
+print_str("Completed box being shipped out");
+
+}
+if(term_offset> max_print_line-9)print_ln();
+else if((term_offset> 0)||(file_offset> 0))print_char(' ');
+print_char('[');j= 9;
+while((count(j)==0)&&(j> 0))decr(j);
+for(k= 0;k<=j;k++)
+{print_int(count(k));
+if(k<j)print_char('.');
+}
+update_terminal;
+if(tracing_output> 0)
+{print_char(']');
+begin_diagnostic();show_box(p);end_diagnostic(true);
+}
+/*640:*/
+#line 12756 "tex.w"
+
+/*641:*/
+#line 12772 "tex.w"
+
+if((height(p)> max_dimen)||(depth(p)> max_dimen)||
+(height(p)+depth(p)+v_offset> max_dimen)||
+(width(p)+h_offset> max_dimen))
+{print_err("Huge page cannot be shipped out");
+
+help2("The page just created is more than 18 feet tall or")
+("more than 18 feet wide, so I suspect something went wrong.");
+error();
+if(tracing_output<=0)
+{begin_diagnostic();
+print_nl("The following box has been deleted:");
+
+show_box(p);
+end_diagnostic(true);
+}
+goto done;
+}
+if(height(p)+depth(p)+v_offset> max_v)max_v= height(p)+depth(p)+v_offset;
+if(width(p)+h_offset> max_h)max_h= width(p)+h_offset
+
+/*:641*/
+#line 12757 "tex.w"
+;
+/*617:*/
+#line 12323 "tex.w"
+
+dvi_h= 0;dvi_v= 0;cur_h= h_offset;dvi_f= null_font;
+/*531:*/
+#line 10333 "tex.w"
+
+if(output_file_name==0)
+{if(job_name==0)open_log_file();
+pack_job_name(/*1635:*/
+#line 25801 "tex.w"
+510
+/*:1635*/
+#line 10336 "tex.w"
+);
+while(!b_open_out(&dvi_file))
+prompt_file_name("file name for output",/*1635:*/
+#line 25801 "tex.w"
+510
+/*:1635*/
+#line 10338 "tex.w"
+);
+output_file_name= b_make_name_string(&dvi_file);
+}
+
+/*:531*/
+#line 12325 "tex.w"
+;
+if(total_pages==0)
+{dvi_out(pre);dvi_out(id_byte);
+
+dvi_four(25400000);dvi_four(473628672);
+prepare_mag();dvi_four(mag);
+old_setting= selector;selector= new_string;
+print_str(" TeX output ");print_int(year);print_char('.');
+print_two(month);print_char('.');print_two(day);
+print_char(':');print_two(time/60);
+print_two(time%60);
+selector= old_setting;dvi_out(cur_length);
+for(s= str_start[str_ptr];s<=pool_ptr-1;s++)dvi_out(so(str_pool[s]));
+pool_ptr= str_start[str_ptr];
+}
+
+/*:617*/
+#line 12758 "tex.w"
+;
+page_loc= dvi_offset+dvi_ptr;
+dvi_out(bop);
+for(k= 0;k<=9;k++)dvi_four(count(k));
+dvi_four(last_bop);last_bop= page_loc;
+cur_v= height(p)+v_offset;temp_ptr= p;
+if(type(p)==vlist_node)vlist_out();else hlist_out();
+dvi_out(eop);incr(total_pages);cur_s= -1;
+done:
+
+/*:640*/
+#line 12730 "tex.w"
+;
+if(tracing_output<=0)print_char(']');
+dead_cycles= 0;
+update_terminal;
+/*639:*/
+#line 12737 "tex.w"
+
+#ifdef STAT
+if(tracing_stats> 1)
+{print_nl("Memory usage before: ");
+
+print_int(var_used);print_char('&');
+print_int(dyn_used);print_char(';');
+}
+#endif
+flush_node_list(p);
+#ifdef STAT
+if(tracing_stats> 1)
+{print_str(" after: ");
+print_int(var_used);print_char('&');
+print_int(dyn_used);print_str("; still untouched: ");
+print_int(hi_mem_min-lo_mem_max-1);print_ln();
+}
+#endif
+
+/*:639*/
+#line 12734 "tex.w"
+;
+}
+
+/*:638*//*645:*/
+#line 12883 "tex.w"
+void scan_spec(group_code c,bool three_codes)
+
+{
+int s;
+uint8_t spec_code;
+if(three_codes)s= saved(0);
+if(scan_keyword(/*1642:*/
+#line 25822 "tex.w"
+517
+/*:1642*/
+#line 12889 "tex.w"
+))spec_code= exactly;
+
+else if(scan_keyword(/*1643:*/
+#line 25825 "tex.w"
+518
+/*:1643*/
+#line 12891 "tex.w"
+))spec_code= additional;
+
+else{spec_code= additional;cur_val= 0;
+goto found;
+}
+scan_normal_dimen;
+found:if(three_codes)
+{saved(0)= s;incr(save_ptr);
+}
+saved(0)= spec_code;saved(1)= cur_val;save_ptr= save_ptr+2;
+new_save_level(c);scan_left_brace();
+}
+
+/*:645*//*649:*/
+#line 12938 "tex.w"
+pointer hpack(pointer p,scaled w,small_number m)
+{
+pointer r;
+pointer q;
+scaled h,d,x;
+scaled s;
+pointer g;
+glue_ord o;
+internal_font_number f;
+four_quarters i;
+eight_bits hd;
+last_badness= 0;r= get_node(box_node_size);type(r)= hlist_node;
+subtype(r)= min_quarterword;shift_amount(r)= 0;
+q= r+list_offset;link(q)= p;
+h= 0;/*650:*/
+#line 12965 "tex.w"
+
+d= 0;x= 0;
+total_stretch[normal]= 0;total_shrink[normal]= 0;
+total_stretch[fil]= 0;total_shrink[fil]= 0;
+total_stretch[fill]= 0;total_shrink[fill]= 0;
+total_stretch[filll]= 0;total_shrink[filll]= 0
+
+/*:650*/
+#line 12952 "tex.w"
+;
+while(p!=null)/*651:*/
+#line 12972 "tex.w"
+
+
+{reswitch:while(is_char_node(p))
+/*654:*/
+#line 13015 "tex.w"
+
+{f= font(p);i= char_info(f)(character(p));hd= height_depth(i);
+x= x+char_width(f)(i);
+s= char_height(f)(hd);if(s> h)h= s;
+s= char_depth(f)(hd);if(s> d)d= s;
+p= link(p);
+}
+
+/*:654*/
+#line 12976 "tex.w"
+;
+if(p!=null)
+{switch(type(p)){
+case hlist_node:case vlist_node:case rule_node:case unset_node:
+/*653:*/
+#line 13003 "tex.w"
+
+{x= x+width(p);
+if(type(p)>=rule_node)s= 0;else s= shift_amount(p);
+if(height(p)-s> h)h= height(p)-s;
+if(depth(p)+s> d)d= depth(p)+s;
+}
+
+/*:653*/
+#line 12980 "tex.w"
+break;
+case ins_node:case mark_node:case adjust_node:if(adjust_tail!=null)
+/*655:*/
+#line 13030 "tex.w"
+
+{while(link(q)!=p)q= link(q);
+if(type(p)==adjust_node)
+{link(adjust_tail)= adjust_ptr(p);
+while(link(adjust_tail)!=null)adjust_tail= link(adjust_tail);
+p= link(p);free_node(link(q),small_node_size);
+}
+else{link(adjust_tail)= p;adjust_tail= p;p= link(p);
+}
+link(q)= p;p= q;
+}
+
+/*:655*/
+#line 12982 "tex.w"
+break;
+case whatsit_node:/*1360:*/
+#line 24795 "tex.w"
+do_nothing
+
+/*:1360*/
+#line 12983 "tex.w"
+;break;
+case glue_node:/*656:*/
+#line 13042 "tex.w"
+
+{g= glue_ptr(p);x= x+width(g);
+o= stretch_order(g);total_stretch[o]= total_stretch[o]+stretch(g);
+o= shrink_order(g);total_shrink[o]= total_shrink[o]+shrink(g);
+if(subtype(p)>=a_leaders)
+{g= leader_ptr(p);
+if(height(g)> h)h= height(g);
+if(depth(g)> d)d= depth(g);
+}
+}
+
+/*:656*/
+#line 12984 "tex.w"
+break;
+case kern_node:case math_node:x= x+width(p);break;
+case ligature_node:/*652:*/
+#line 12994 "tex.w"
+
+{mem[lig_trick]= mem[lig_char(p)];link(lig_trick)= link(p);
+p= lig_trick;goto reswitch;
+}
+
+/*:652*/
+#line 12986 "tex.w"
+
+default:do_nothing;
+}
+p= link(p);
+}
+}
+
+
+/*:651*/
+#line 12955 "tex.w"
+;
+if(adjust_tail!=null)link(adjust_tail)= null;
+height(r)= h;depth(r)= d;
+/*657:*/
+#line 13056 "tex.w"
+
+if(m==additional)w= x+w;
+width(r)= w;x= w-x;
+if(x==0)
+{glue_sign(r)= normal;glue_order(r)= normal;
+set_glue_ratio_zero(glue_set(r));
+goto end;
+}
+else if(x> 0)/*658:*/
+#line 13068 "tex.w"
+
+{/*659:*/
+#line 13082 "tex.w"
+
+if(total_stretch[filll]!=0)o= filll;
+else if(total_stretch[fill]!=0)o= fill;
+else if(total_stretch[fil]!=0)o= fil;
+else o= normal
+
+/*:659*/
+#line 13069 "tex.w"
+;
+glue_order(r)= o;glue_sign(r)= stretching;
+if(total_stretch[o]!=0)glue_set(r)= unfloat(x/(double)total_stretch[o]);
+
+else{glue_sign(r)= normal;
+set_glue_ratio_zero(glue_set(r));
+}
+if(o==normal)if(list_ptr(r)!=null)
+/*660:*/
+#line 13088 "tex.w"
+
+{last_badness= badness(x,total_stretch[normal]);
+if(last_badness> hbadness)
+{print_ln();
+if(last_badness> 100)print_nl("Underfull");else print_nl("Loose");
+print_str(" \\hbox (badness ");print_int(last_badness);
+
+
+goto common_ending;
+}
+}
+
+/*:660*/
+#line 13078 "tex.w"
+;
+goto end;
+}
+
+/*:658*/
+#line 13065 "tex.w"
+
+else/*664:*/
+#line 13127 "tex.w"
+
+{/*665:*/
+#line 13146 "tex.w"
+
+if(total_shrink[filll]!=0)o= filll;
+else if(total_shrink[fill]!=0)o= fill;
+else if(total_shrink[fil]!=0)o= fil;
+else o= normal
+
+/*:665*/
+#line 13128 "tex.w"
+;
+glue_order(r)= o;glue_sign(r)= shrinking;
+if(total_shrink[o]!=0)glue_set(r)= unfloat((-x)/(double)total_shrink[o]);
+
+else{glue_sign(r)= normal;
+set_glue_ratio_zero(glue_set(r));
+}
+if((total_shrink[o]<-x)&&(o==normal)&&(list_ptr(r)!=null))
+{last_badness= 1000000;
+set_glue_ratio_one(glue_set(r));
+/*666:*/
+#line 13152 "tex.w"
+
+if((-x-total_shrink[normal]> hfuzz)||(hbadness<100))
+{if((overfull_rule> 0)&&(-x-total_shrink[normal]> hfuzz))
+{while(link(q)!=null)q= link(q);
+link(q)= new_rule();
+width(link(q))= overfull_rule;
+}
+print_ln();print_nl("Overfull \\hbox (");
+
+print_scaled(-x-total_shrink[normal]);print_str("pt too wide");
+goto common_ending;
+}
+
+/*:666*/
+#line 13139 "tex.w"
+;
+}
+else if(o==normal)if(list_ptr(r)!=null)
+/*667:*/
+#line 13165 "tex.w"
+
+{last_badness= badness(-x,total_shrink[normal]);
+if(last_badness> hbadness)
+{print_ln();print_nl("Tight \\hbox (badness ");print_int(last_badness);
+
+goto common_ending;
+}
+}
+
+/*:667*/
+#line 13142 "tex.w"
+;
+goto end;
+}
+
+/*:664*/
+#line 13066 "tex.w"
+
+
+/*:657*/
+#line 12959 "tex.w"
+;
+common_ending:/*663:*/
+#line 13112 "tex.w"
+
+if(output_active)print_str(") has occurred while \\output is active");
+else{if(pack_begin_line!=0)
+{if(pack_begin_line> 0)print_str(") in paragraph at lines ");
+else print_str(") in alignment at lines ");
+print_int(abs(pack_begin_line));
+print_str("--");
+}
+else print_str(") detected at line ");
+print_int(line);
+}
+print_ln();
+font_in_short_display= null_font;short_display(list_ptr(r));print_ln();
+begin_diagnostic();show_box(r);end_diagnostic(true)
+
+/*:663*/
+#line 12961 "tex.w"
+;
+end:return r;
+}
+
+/*:649*//*668:*/
+#line 13181 "tex.w"
+
+#define vpack(...) vpackage(__VA_ARGS__, max_dimen)
+
+
+pointer vpackage(pointer p,scaled h,small_number m,scaled l)
+{
+pointer r;
+scaled w,d,x;
+scaled s;
+pointer g;
+glue_ord o;
+last_badness= 0;r= get_node(box_node_size);type(r)= vlist_node;
+subtype(r)= min_quarterword;shift_amount(r)= 0;
+list_ptr(r)= p;
+w= 0;/*650:*/
+#line 12965 "tex.w"
+
+d= 0;x= 0;
+total_stretch[normal]= 0;total_shrink[normal]= 0;
+total_stretch[fil]= 0;total_shrink[fil]= 0;
+total_stretch[fill]= 0;total_shrink[fill]= 0;
+total_stretch[filll]= 0;total_shrink[filll]= 0
+
+/*:650*/
+#line 13195 "tex.w"
+;
+while(p!=null)/*669:*/
+#line 13210 "tex.w"
+
+{if(is_char_node(p))confusion(/*1644:*/
+#line 25828 "tex.w"
+519
+/*:1644*/
+#line 13211 "tex.w"
+);
+
+else switch(type(p)){
+case hlist_node:case vlist_node:case rule_node:case unset_node:
+/*670:*/
+#line 13225 "tex.w"
+
+{x= x+d+height(p);d= depth(p);
+if(type(p)>=rule_node)s= 0;else s= shift_amount(p);
+if(width(p)+s> w)w= width(p)+s;
+}
+
+/*:670*/
+#line 13215 "tex.w"
+break;
+case whatsit_node:/*1359:*/
+#line 24793 "tex.w"
+do_nothing
+
+/*:1359*/
+#line 13216 "tex.w"
+;break;
+case glue_node:/*671:*/
+#line 13231 "tex.w"
+
+{x= x+d;d= 0;
+g= glue_ptr(p);x= x+width(g);
+o= stretch_order(g);total_stretch[o]= total_stretch[o]+stretch(g);
+o= shrink_order(g);total_shrink[o]= total_shrink[o]+shrink(g);
+if(subtype(p)>=a_leaders)
+{g= leader_ptr(p);
+if(width(g)> w)w= width(g);
+}
+}
+
+/*:671*/
+#line 13217 "tex.w"
+break;
+case kern_node:{x= x+d+width(p);d= 0;
+}break;
+default:do_nothing;
+}
+p= link(p);
+}
+
+/*:669*/
+#line 13197 "tex.w"
+;
+width(r)= w;
+if(d> l)
+{x= x+d-l;depth(r)= l;
+}
+else depth(r)= d;
+/*672:*/
+#line 13245 "tex.w"
+
+if(m==additional)h= x+h;
+height(r)= h;x= h-x;
+if(x==0)
+{glue_sign(r)= normal;glue_order(r)= normal;
+set_glue_ratio_zero(glue_set(r));
+goto end;
+}
+else if(x> 0)/*673:*/
+#line 13257 "tex.w"
+
+{/*659:*/
+#line 13082 "tex.w"
+
+if(total_stretch[filll]!=0)o= filll;
+else if(total_stretch[fill]!=0)o= fill;
+else if(total_stretch[fil]!=0)o= fil;
+else o= normal
+
+/*:659*/
+#line 13258 "tex.w"
+;
+glue_order(r)= o;glue_sign(r)= stretching;
+if(total_stretch[o]!=0)glue_set(r)= unfloat(x/(double)total_stretch[o]);
+
+else{glue_sign(r)= normal;
+set_glue_ratio_zero(glue_set(r));
+}
+if(o==normal)if(list_ptr(r)!=null)
+/*674:*/
+#line 13271 "tex.w"
+
+{last_badness= badness(x,total_stretch[normal]);
+if(last_badness> vbadness)
+{print_ln();
+if(last_badness> 100)print_nl("Underfull");else print_nl("Loose");
+print_str(" \\vbox (badness ");print_int(last_badness);
+
+
+goto common_ending;
+}
+}
+
+/*:674*/
+#line 13267 "tex.w"
+;
+goto end;
+}
+
+/*:673*/
+#line 13254 "tex.w"
+
+else/*676:*/
+#line 13296 "tex.w"
+
+{/*665:*/
+#line 13146 "tex.w"
+
+if(total_shrink[filll]!=0)o= filll;
+else if(total_shrink[fill]!=0)o= fill;
+else if(total_shrink[fil]!=0)o= fil;
+else o= normal
+
+/*:665*/
+#line 13297 "tex.w"
+;
+glue_order(r)= o;glue_sign(r)= shrinking;
+if(total_shrink[o]!=0)glue_set(r)= unfloat((-x)/(double)total_shrink[o]);
+
+else{glue_sign(r)= normal;
+set_glue_ratio_zero(glue_set(r));
+}
+if((total_shrink[o]<-x)&&(o==normal)&&(list_ptr(r)!=null))
+{last_badness= 1000000;
+set_glue_ratio_one(glue_set(r));
+/*677:*/
+#line 13315 "tex.w"
+
+if((-x-total_shrink[normal]> vfuzz)||(vbadness<100))
+{print_ln();print_nl("Overfull \\vbox (");
+
+print_scaled(-x-total_shrink[normal]);print_str("pt too high");
+goto common_ending;
+}
+
+/*:677*/
+#line 13308 "tex.w"
+;
+}
+else if(o==normal)if(list_ptr(r)!=null)
+/*678:*/
+#line 13323 "tex.w"
+
+{last_badness= badness(-x,total_shrink[normal]);
+if(last_badness> vbadness)
+{print_ln();print_nl("Tight \\vbox (badness ");print_int(last_badness);
+
+goto common_ending;
+}
+}
+
+/*:678*/
+#line 13311 "tex.w"
+;
+goto end;
+}
+
+/*:676*/
+#line 13255 "tex.w"
+
+
+/*:672*/
+#line 13204 "tex.w"
+;
+common_ending:/*675:*/
+#line 13283 "tex.w"
+
+if(output_active)print_str(") has occurred while \\output is active");
+else{if(pack_begin_line!=0)
+{print_str(") in alignment at lines ");
+print_int(abs(pack_begin_line));
+print_str("--");
+}
+else print_str(") detected at line ");
+print_int(line);
+print_ln();
+}
+begin_diagnostic();show_box(r);end_diagnostic(true)
+
+/*:675*/
+#line 13206 "tex.w"
+;
+end:return r;
+}
+
+/*:668*//*679:*/
+#line 13335 "tex.w"
+void append_to_vlist(pointer b)
+{scaled d;
+pointer p;
+if(prev_depth> ignore_depth)
+{d= width(baseline_skip)-prev_depth-height(b);
+if(d<line_skip_limit)p= new_param_glue(line_skip_code);
+else{p= new_skip_param(baseline_skip_code);
+width(temp_ptr)= d;
+}
+link(tail)= p;tail= p;
+}
+link(tail)= b;tail= b;prev_depth= depth(b);
+}
+
+/*:679*//*686:*/
+#line 13533 "tex.w"
+pointer new_noad(void)
+{pointer p;
+p= get_node(noad_size);
+type(p)= ord_noad;subtype(p)= normal;
+mem[nucleus(p)].hh= empty_field;
+mem[subscr(p)].hh= empty_field;
+mem[supscr(p)].hh= empty_field;
+return p;
+}
+
+/*:686*//*688:*/
+#line 13594 "tex.w"
+pointer new_style(small_number s)
+{pointer p;
+p= get_node(style_node_size);type(p)= style_node;
+subtype(p)= s;width(p)= 0;depth(p)= 0;
+return p;
+}
+
+/*:688*//*689:*/
+#line 13611 "tex.w"
+pointer new_choice(void)
+{pointer p;
+p= get_node(style_node_size);type(p)= choice_node;
+subtype(p)= 0;
+display_mlist(p)= null;text_mlist(p)= null;script_mlist(p)= null;
+script_script_mlist(p)= null;
+return p;
+}
+
+/*:689*//*693:*/
+#line 13699 "tex.w"
+void show_info(void)
+{show_node_list(info(temp_ptr));
+}
+
+/*:693*//*704:*/
+#line 13894 "tex.w"
+pointer fraction_rule(scaled t)
+
+{pointer p;
+p= new_rule();height(p)= t;depth(p)= 0;return p;
+}
+
+/*:704*//*705:*/
+#line 13904 "tex.w"
+pointer overbar(pointer b,scaled k,scaled t)
+{pointer p,q;
+p= new_kern(k);link(p)= b;q= fraction_rule(t);link(q)= p;
+p= new_kern(t);link(p)= q;return vpack(p,natural);
+}
+
+/*:705*//*706:*/
+#line 13925 "tex.w"
+/*709:*/
+#line 13997 "tex.w"
+
+pointer char_box(internal_font_number f,quarterword c)
+{four_quarters q;
+eight_bits hd;
+pointer b,p;
+q= char_info(f)(c);hd= height_depth(q);
+b= new_null_box();width(b)= char_width(f)(q)+char_italic(f)(q);
+height(b)= char_height(f)(hd);depth(b)= char_depth(f)(hd);
+p= get_avail();character(p)= c;font(p)= f;list_ptr(b)= p;return b;
+}
+
+/*:709*//*711:*/
+#line 14021 "tex.w"
+
+void stack_into_box(pointer b,internal_font_number f,
+quarterword c)
+{pointer p;
+p= char_box(f,c);link(p)= list_ptr(b);list_ptr(b)= p;
+height(b)= height(p);
+}
+
+/*:711*//*712:*/
+#line 14032 "tex.w"
+
+scaled height_plus_depth(internal_font_number f,quarterword c)
+{four_quarters q;
+eight_bits hd;
+q= char_info(f)(c);hd= height_depth(q);
+return char_height(f)(hd)+char_depth(f)(hd);
+}
+
+/*:712*/
+#line 13925 "tex.w"
+
+pointer var_delimiter(pointer d,small_number s,scaled v)
+{
+pointer b;
+internal_font_number f,g;
+quarterword c,x,y;
+int m,n;
+scaled u;
+scaled w;
+four_quarters q;
+eight_bits hd;
+four_quarters r;
+small_number z;
+bool large_attempt;
+f= null_font;w= 0;large_attempt= false;
+z= small_fam(d);x= small_char(d);
+loop{/*707:*/
+#line 13959 "tex.w"
+
+if((z!=0)||(x!=min_quarterword))
+{z= z+s+16;
+do{z= z-16;g= fam_fnt(z);
+if(g!=null_font)
+/*708:*/
+#line 13970 "tex.w"
+
+{y= x;
+if((qo(y)>=font_bc[g])&&(qo(y)<=font_ec[g]))
+{resume:q= char_info(g)(y);
+if(char_exists(q))
+{if(char_tag(q)==ext_tag)
+{f= g;c= y;goto found;
+}
+hd= height_depth(q);
+u= char_height(g)(hd)+char_depth(g)(hd);
+if(u> w)
+{f= g;c= y;w= u;
+if(u>=v)goto found;
+}
+if(char_tag(q)==list_tag)
+{y= rem_byte(q);goto resume;
+}
+}
+}
+}
+
+/*:708*/
+#line 13966 "tex.w"
+;
+}while(!(z<16));
+}
+
+/*:707*/
+#line 13942 "tex.w"
+;
+if(large_attempt)goto found;
+large_attempt= true;z= large_fam(d);x= large_char(d);
+}
+found:if(f!=null_font)
+/*710:*/
+#line 14011 "tex.w"
+
+if(char_tag(q)==ext_tag)
+/*713:*/
+#line 14040 "tex.w"
+
+{b= new_null_box();
+type(b)= vlist_node;
+r= font_info[exten_base[f]+rem_byte(q)].qqqq;
+/*714:*/
+#line 14065 "tex.w"
+
+c= ext_rep(r);u= height_plus_depth(f,c);
+w= 0;q= char_info(f)(c);width(b)= char_width(f)(q)+char_italic(f)(q);
+c= ext_bot(r);if(c!=min_quarterword)w= w+height_plus_depth(f,c);
+c= ext_mid(r);if(c!=min_quarterword)w= w+height_plus_depth(f,c);
+c= ext_top(r);if(c!=min_quarterword)w= w+height_plus_depth(f,c);
+n= 0;
+if(u> 0)while(w<v)
+{w= w+u;incr(n);
+if(ext_mid(r)!=min_quarterword)w= w+u;
+}
+
+/*:714*/
+#line 14045 "tex.w"
+;
+c= ext_bot(r);
+if(c!=min_quarterword)stack_into_box(b,f,c);
+c= ext_rep(r);
+for(m= 1;m<=n;m++)stack_into_box(b,f,c);
+c= ext_mid(r);
+if(c!=min_quarterword)
+{stack_into_box(b,f,c);c= ext_rep(r);
+for(m= 1;m<=n;m++)stack_into_box(b,f,c);
+}
+c= ext_top(r);
+if(c!=min_quarterword)stack_into_box(b,f,c);
+depth(b)= w-height(b);
+}
+
+/*:713*/
+#line 14014 "tex.w"
+
+else b= char_box(f,c)
+
+/*:710*/
+#line 13947 "tex.w"
+;
+else{b= new_null_box();
+width(b)= null_delimiter_space;
+}
+shift_amount(b)= half(height(b)-depth(b))-axis_height(s);
+return b;
+}
+
+/*:706*//*715:*/
+#line 14090 "tex.w"
+pointer rebox(pointer b,scaled w)
+{pointer p;
+internal_font_number f;
+scaled v;
+if((width(b)!=w)&&(list_ptr(b)!=null))
+{if(type(b)==vlist_node)b= hpack(b,natural);
+p= list_ptr(b);
+if((is_char_node(p))&&(link(p)==null))
+{f= font(p);v= char_width(f)(char_info(f)(character(p)));
+if(v!=width(b))link(p)= new_kern(width(b)-v);
+}
+free_node(b,box_node_size);
+b= new_glue(ss_glue);link(b)= p;
+while(link(p)!=null)p= link(p);
+link(p)= new_glue(ss_glue);
+return hpack(b,w,exactly);
+}
+else{width(b)= w;return b;
+}
+}
+
+/*:715*//*716:*/
+#line 14116 "tex.w"
+pointer math_glue(pointer g,scaled m)
+{pointer p;
+int n;
+scaled f;
+n= x_over_n(m,0200000);f= rem;
+if(f<0)
+{decr(n);f= f+0200000;
+}
+p= get_node(glue_spec_size);
+width(p)= mu_mult(width(g));
+stretch_order(p)= stretch_order(g);
+if(stretch_order(p)==normal)stretch(p)= mu_mult(stretch(g));
+else stretch(p)= stretch(g);
+shrink_order(p)= shrink_order(g);
+if(shrink_order(p)==normal)shrink(p)= mu_mult(shrink(g));
+else shrink(p)= shrink(g);
+return p;
+}
+
+/*:716*//*717:*/
+#line 14138 "tex.w"
+void math_kern(pointer p,scaled m)
+{int n;
+scaled f;
+if(subtype(p)==mu_glue)
+{n= x_over_n(m,0200000);f= rem;
+if(f<0)
+{decr(n);f= f+0200000;
+}
+width(p)= mu_mult(width(p));subtype(p)= explicit;
+}
+}
+
+/*:717*//*718:*/
+#line 14153 "tex.w"
+void flush_math(void)
+{flush_node_list(link(head));flush_node_list(incompleat_noad);
+link(head)= null;tail= head;incompleat_noad= null;
+}
+
+/*:718*//*720:*/
+#line 14190 "tex.w"
+void mlist_to_hlist(void);
+pointer clean_box(pointer p,small_number s)
+{
+pointer q;
+small_number save_style;
+pointer x;
+pointer r;
+switch(math_type(p)){
+case math_char:{cur_mlist= new_noad();mem[nucleus(cur_mlist)]= mem[p];
+}break;
+case sub_box:{q= info(p);goto found;
+}
+case sub_mlist:cur_mlist= info(p);break;
+default:{q= new_null_box();goto found;
+}
+}
+save_style= cur_style;cur_style= s;mlist_penalties= false;
+mlist_to_hlist();q= link(temp_head);
+cur_style= save_style;
+/*703:*/
+#line 13884 "tex.w"
+
+{if(cur_style<script_style)cur_size= text_size;
+else cur_size= 16*((cur_style-text_style)/2);
+cur_mu= x_over_n(math_quad(cur_size),18);
+}
+
+/*:703*/
+#line 14209 "tex.w"
+;
+found:if(is_char_node(q)||(q==null))x= hpack(q,natural);
+else if((link(q)==null)&&(type(q)<=vlist_node)&&(shift_amount(q)==0))
+x= q;
+else x= hpack(q,natural);
+/*721:*/
+#line 14220 "tex.w"
+
+q= list_ptr(x);
+if(is_char_node(q))
+{r= link(q);
+if(r!=null)if(link(r)==null)if(!is_char_node(r))
+if(type(r)==kern_node)
+{free_node(r,small_node_size);link(q)= null;
+}
+}
+
+/*:721*/
+#line 14214 "tex.w"
+;
+return x;
+}
+
+/*:720*//*722:*/
+#line 14237 "tex.w"
+void fetch(pointer a)
+{cur_c= character(a);cur_f= fam_fnt(fam(a)+cur_size);
+if(cur_f==null_font)
+/*723:*/
+#line 14251 "tex.w"
+
+{print_err("");print_size(cur_size);print_char(' ');
+print_int(fam(a));print_str(" is undefined (character ");
+print_ASCII(qo(cur_c));print_char(')');
+help4("Somewhere in the math formula just ended, you used the")
+("stated character from an undefined font family. For example,")
+("plain TeX doesn't allow \\it or \\sl in subscripts. Proceed,")
+("and I'll try to forget that I needed that character.");
+error();cur_i= null_character;math_type(a)= empty;
+}
+
+/*:723*/
+#line 14240 "tex.w"
+
+else{if((qo(cur_c)>=font_bc[cur_f])&&(qo(cur_c)<=font_ec[cur_f]))
+cur_i= char_info(cur_f)(cur_c);
+else cur_i= null_character;
+if(!(char_exists(cur_i)))
+{char_warning(cur_f,qo(cur_c));
+math_type(a)= empty;
+}
+}
+}
+
+/*:722*//*726:*/
+#line 14291 "tex.w"
+/*734:*/
+#line 14443 "tex.w"
+
+void make_over(pointer q)
+{info(nucleus(q))=
+overbar(clean_box(nucleus(q),cramped_style(cur_style)),
+3*default_rule_thickness,default_rule_thickness);
+math_type(nucleus(q))= sub_box;
+}
+
+/*:734*//*735:*/
+#line 14451 "tex.w"
+
+void make_under(pointer q)
+{pointer p,x,y;
+scaled delta;
+x= clean_box(nucleus(q),cur_style);
+p= new_kern(3*default_rule_thickness);link(x)= p;
+link(p)= fraction_rule(default_rule_thickness);
+y= vpack(x,natural);
+delta= height(y)+depth(y)+default_rule_thickness;
+height(y)= height(x);depth(y)= delta-height(y);
+info(nucleus(q))= y;math_type(nucleus(q))= sub_box;
+}
+
+/*:735*//*736:*/
+#line 14464 "tex.w"
+
+void make_vcenter(pointer q)
+{pointer v;
+scaled delta;
+v= info(nucleus(q));
+if(type(v)!=vlist_node)confusion(/*1561:*/
+#line 25579 "tex.w"
+436
+/*:1561*/
+#line 14469 "tex.w"
+);
+
+delta= height(v)+depth(v);
+height(v)= axis_height(cur_size)+half(delta);
+depth(v)= delta-height(v);
+}
+
+/*:736*//*737:*/
+#line 14485 "tex.w"
+
+void make_radical(pointer q)
+{pointer x,y;
+scaled delta,clr;
+x= clean_box(nucleus(q),cramped_style(cur_style));
+if(cur_style<text_style)
+clr= default_rule_thickness+(abs(math_x_height(cur_size))/4);
+else{clr= default_rule_thickness;clr= clr+(abs(clr)/4);
+}
+y= var_delimiter(left_delimiter(q),cur_size,height(x)+depth(x)+clr+
+default_rule_thickness);
+delta= depth(y)-(height(x)+depth(x)+clr);
+if(delta> 0)clr= clr+half(delta);
+shift_amount(y)= -(height(x)+clr);
+link(y)= overbar(x,clr,height(y));
+info(nucleus(q))= hpack(y,natural);math_type(nucleus(q))= sub_box;
+}
+
+/*:737*//*738:*/
+#line 14507 "tex.w"
+
+void make_math_accent(pointer q)
+{
+pointer p,x,y;
+int a;
+quarterword c;
+internal_font_number f;
+four_quarters i;
+scaled s;
+scaled h;
+scaled delta;
+scaled w;
+fetch(accent_chr(q));
+if(char_exists(cur_i))
+{i= cur_i;c= cur_c;f= cur_f;
+/*741:*/
+#line 14554 "tex.w"
+
+s= 0;
+if(math_type(nucleus(q))==math_char)
+{fetch(nucleus(q));
+if(char_tag(cur_i)==lig_tag)
+{a= lig_kern_start(cur_f)(cur_i);
+cur_i= font_info[a].qqqq;
+if(skip_byte(cur_i)> stop_flag)
+{a= lig_kern_restart(cur_f)(cur_i);
+cur_i= font_info[a].qqqq;
+}
+loop{if(qo(next_char(cur_i))==skew_char[cur_f])
+{if(op_byte(cur_i)>=kern_flag)
+if(skip_byte(cur_i)<=stop_flag)s= char_kern(cur_f)(cur_i);
+goto done1;
+}
+if(skip_byte(cur_i)>=stop_flag)goto done1;
+a= a+qo(skip_byte(cur_i))+1;
+cur_i= font_info[a].qqqq;
+}
+}
+}
+done1:
+
+/*:741*/
+#line 14522 "tex.w"
+;
+x= clean_box(nucleus(q),cramped_style(cur_style));w= width(x);h= height(x);
+/*740:*/
+#line 14544 "tex.w"
+
+loop{if(char_tag(i)!=list_tag)goto done;
+y= rem_byte(i);
+i= char_info(f)(y);
+if(!char_exists(i))goto done;
+if(char_width(f)(i)> w)goto done;
+c= y;
+}
+done:
+
+/*:740*/
+#line 14524 "tex.w"
+;
+if(h<x_height(f))delta= h;else delta= x_height(f);
+if((math_type(supscr(q))!=empty)||(math_type(subscr(q))!=empty))
+if(math_type(nucleus(q))==math_char)
+/*742:*/
+#line 14578 "tex.w"
+
+{flush_node_list(x);x= new_noad();
+mem[nucleus(x)]= mem[nucleus(q)];
+mem[supscr(x)]= mem[supscr(q)];
+mem[subscr(x)]= mem[subscr(q)];
+mem[supscr(q)].hh= empty_field;
+mem[subscr(q)].hh= empty_field;
+math_type(nucleus(q))= sub_mlist;info(nucleus(q))= x;
+x= clean_box(nucleus(q),cur_style);delta= delta+height(x)-h;h= height(x);
+}
+
+/*:742*/
+#line 14528 "tex.w"
+;
+y= char_box(f,c);
+shift_amount(y)= s+half(w-width(y));
+width(y)= 0;p= new_kern(-delta);link(p)= x;link(y)= p;
+y= vpack(y,natural);width(y)= width(x);
+if(height(y)<h)/*739:*/
+#line 14539 "tex.w"
+
+{p= new_kern(h-height(y));link(p)= list_ptr(y);list_ptr(y)= p;
+height(y)= h;
+}
+
+/*:739*/
+#line 14533 "tex.w"
+;
+info(nucleus(q))= y;
+math_type(nucleus(q))= sub_box;
+}
+}
+
+/*:738*//*743:*/
+#line 14592 "tex.w"
+
+void make_fraction(pointer q)
+{pointer p,v,x,y,z;
+scaled delta,delta1,delta2,shift_up,shift_down,clr;
+
+if(thickness(q)==default_code)thickness(q)= default_rule_thickness;
+/*744:*/
+#line 14609 "tex.w"
+
+x= clean_box(numerator(q),num_style(cur_style));
+z= clean_box(denominator(q),denom_style(cur_style));
+if(width(x)<width(z))x= rebox(x,width(z));
+else z= rebox(z,width(x));
+if(cur_style<text_style)
+{shift_up= num1(cur_size);shift_down= denom1(cur_size);
+}
+else{shift_down= denom2(cur_size);
+if(thickness(q)!=0)shift_up= num2(cur_size);
+else shift_up= num3(cur_size);
+}
+
+/*:744*/
+#line 14600 "tex.w"
+;
+if(thickness(q)==0)/*745:*/
+#line 14626 "tex.w"
+
+{if(cur_style<text_style)clr= 7*default_rule_thickness;
+else clr= 3*default_rule_thickness;
+delta= half(clr-((shift_up-depth(x))-(height(z)-shift_down)));
+if(delta> 0)
+{shift_up= shift_up+delta;
+shift_down= shift_down+delta;
+}
+}
+
+/*:745*/
+#line 14602 "tex.w"
+
+else/*746:*/
+#line 14639 "tex.w"
+
+{if(cur_style<text_style)clr= 3*thickness(q);
+else clr= thickness(q);
+delta= half(thickness(q));
+delta1= clr-((shift_up-depth(x))-(axis_height(cur_size)+delta));
+delta2= clr-((axis_height(cur_size)-delta)-(height(z)-shift_down));
+if(delta1> 0)shift_up= shift_up+delta1;
+if(delta2> 0)shift_down= shift_down+delta2;
+}
+
+/*:746*/
+#line 14603 "tex.w"
+;
+/*747:*/
+#line 14649 "tex.w"
+
+v= new_null_box();type(v)= vlist_node;
+height(v)= shift_up+height(x);depth(v)= depth(z)+shift_down;
+width(v)= width(x);
+if(thickness(q)==0)
+{p= new_kern((shift_up-depth(x))-(height(z)-shift_down));
+link(p)= z;
+}
+else{y= fraction_rule(thickness(q));
+p= new_kern((axis_height(cur_size)-delta)-(height(z)-shift_down));
+link(y)= p;link(p)= z;
+p= new_kern((shift_up-depth(x))-(axis_height(cur_size)+delta));
+link(p)= y;
+}
+link(x)= p;list_ptr(v)= x
+
+/*:747*/
+#line 14604 "tex.w"
+;
+/*748:*/
+#line 14665 "tex.w"
+
+if(cur_style<text_style)delta= delim1(cur_size);
+else delta= delim2(cur_size);
+x= var_delimiter(left_delimiter(q),cur_size,delta);link(x)= v;
+z= var_delimiter(right_delimiter(q),cur_size,delta);link(v)= z;
+new_hlist(q)= hpack(x,natural)
+
+/*:748*/
+#line 14606 "tex.w"
+;
+}
+
+/*:743*//*749:*/
+#line 14687 "tex.w"
+
+scaled make_op(pointer q)
+{scaled delta;
+pointer p,v,x,y,z;
+quarterword c;four_quarters i;
+scaled shift_up,shift_down;
+if((subtype(q)==normal)&&(cur_style<text_style))
+subtype(q)= limits;
+if(math_type(nucleus(q))==math_char)
+{fetch(nucleus(q));
+if((cur_style<text_style)&&(char_tag(cur_i)==list_tag))
+{c= rem_byte(cur_i);i= char_info(cur_f)(c);
+if(char_exists(i))
+{cur_c= c;cur_i= i;character(nucleus(q))= c;
+}
+}
+delta= char_italic(cur_f)(cur_i);x= clean_box(nucleus(q),cur_style);
+if((math_type(subscr(q))!=empty)&&(subtype(q)!=limits))
+width(x)= width(x)-delta;
+shift_amount(x)= half(height(x)-depth(x))-axis_height(cur_size);
+
+math_type(nucleus(q))= sub_box;info(nucleus(q))= x;
+}
+else delta= 0;
+if(subtype(q)==limits)
+/*750:*/
+#line 14719 "tex.w"
+
+{x= clean_box(supscr(q),sup_style(cur_style));
+y= clean_box(nucleus(q),cur_style);
+z= clean_box(subscr(q),sub_style(cur_style));
+v= new_null_box();type(v)= vlist_node;width(v)= width(y);
+if(width(x)> width(v))width(v)= width(x);
+if(width(z)> width(v))width(v)= width(z);
+x= rebox(x,width(v));y= rebox(y,width(v));z= rebox(z,width(v));
+shift_amount(x)= half(delta);shift_amount(z)= -shift_amount(x);
+height(v)= height(y);depth(v)= depth(y);
+/*751:*/
+#line 14739 "tex.w"
+
+if(math_type(supscr(q))==empty)
+{free_node(x,box_node_size);list_ptr(v)= y;
+}
+else{shift_up= big_op_spacing3-depth(x);
+if(shift_up<big_op_spacing1)shift_up= big_op_spacing1;
+p= new_kern(shift_up);link(p)= y;link(x)= p;
+p= new_kern(big_op_spacing5);link(p)= x;list_ptr(v)= p;
+height(v)= height(v)+big_op_spacing5+height(x)+depth(x)+shift_up;
+}
+if(math_type(subscr(q))==empty)free_node(z,box_node_size);
+else{shift_down= big_op_spacing4-height(z);
+if(shift_down<big_op_spacing2)shift_down= big_op_spacing2;
+p= new_kern(shift_down);link(y)= p;link(p)= z;
+p= new_kern(big_op_spacing5);link(z)= p;
+depth(v)= depth(v)+big_op_spacing5+height(z)+depth(z)+shift_down;
+}
+
+/*:751*/
+#line 14730 "tex.w"
+;
+new_hlist(q)= v;
+}
+
+/*:750*/
+#line 14712 "tex.w"
+;
+return delta;
+}
+
+/*:749*//*752:*/
+#line 14767 "tex.w"
+
+void make_ord(pointer q)
+{
+int a;
+pointer p,r;
+restart:
+if(math_type(subscr(q))==empty)if(math_type(supscr(q))==empty)
+if(math_type(nucleus(q))==math_char)
+{p= link(q);
+if(p!=null)if((type(p)>=ord_noad)&&(type(p)<=punct_noad))
+if(math_type(nucleus(p))==math_char)
+if(fam(nucleus(p))==fam(nucleus(q)))
+{math_type(nucleus(q))= math_text_char;
+fetch(nucleus(q));
+if(char_tag(cur_i)==lig_tag)
+{a= lig_kern_start(cur_f)(cur_i);
+cur_c= character(nucleus(p));
+cur_i= font_info[a].qqqq;
+if(skip_byte(cur_i)> stop_flag)
+{a= lig_kern_restart(cur_f)(cur_i);
+cur_i= font_info[a].qqqq;
+}
+loop{/*753:*/
+#line 14809 "tex.w"
+
+if(next_char(cur_i)==cur_c)if(skip_byte(cur_i)<=stop_flag)
+if(op_byte(cur_i)>=kern_flag)
+{p= new_kern(char_kern(cur_f)(cur_i));
+link(p)= link(q);link(q)= p;return;
+}
+else{check_interrupt;
+switch(op_byte(cur_i)){
+qi(case 1):qi(case 5):character(nucleus(q))= rem_byte(cur_i);break;
+qi(case 2):qi(case 6):character(nucleus(p))= rem_byte(cur_i);break;
+qi(case 3):qi(case 7):qi(case 11):{r= new_noad();
+character(nucleus(r))= rem_byte(cur_i);
+fam(nucleus(r))= fam(nucleus(q));
+link(q)= r;link(r)= p;
+if(op_byte(cur_i)<qi(11))math_type(nucleus(r))= math_char;
+else math_type(nucleus(r))= math_text_char;
+}break;
+default:{link(q)= link(p);
+character(nucleus(q))= rem_byte(cur_i);
+mem[subscr(q)]= mem[subscr(p)];mem[supscr(q)]= mem[supscr(p)];
+free_node(p,noad_size);
+}
+}
+if(op_byte(cur_i)> qi(3))return;
+math_type(nucleus(q))= math_char;goto restart;
+}
+
+/*:753*/
+#line 14791 "tex.w"
+;
+if(skip_byte(cur_i)>=stop_flag)return;
+a= a+qo(skip_byte(cur_i))+1;
+cur_i= font_info[a].qqqq;
+}
+}
+}
+}
+}
+
+/*:752*//*756:*/
+#line 14891 "tex.w"
+
+void make_scripts(pointer q,scaled delta)
+{pointer p,x,y,z;
+scaled shift_up,shift_down,clr;
+small_number t;
+p= new_hlist(q);
+if(is_char_node(p))
+{shift_up= 0;shift_down= 0;
+}
+else{z= hpack(p,natural);
+if(cur_style<script_style)t= script_size;else t= script_script_size;
+shift_up= height(z)-sup_drop(t);
+shift_down= depth(z)+sub_drop(t);
+free_node(z,box_node_size);
+}
+if(math_type(supscr(q))==empty)
+/*757:*/
+#line 14923 "tex.w"
+
+{x= clean_box(subscr(q),sub_style(cur_style));
+width(x)= width(x)+script_space;
+if(shift_down<sub1(cur_size))shift_down= sub1(cur_size);
+clr= height(x)-(abs(math_x_height(cur_size)*4)/5);
+if(shift_down<clr)shift_down= clr;
+shift_amount(x)= shift_down;
+}
+
+/*:757*/
+#line 14907 "tex.w"
+
+else{/*758:*/
+#line 14935 "tex.w"
+
+{x= clean_box(supscr(q),sup_style(cur_style));
+width(x)= width(x)+script_space;
+if(odd(cur_style))clr= sup3(cur_size);
+else if(cur_style<text_style)clr= sup1(cur_size);
+else clr= sup2(cur_size);
+if(shift_up<clr)shift_up= clr;
+clr= depth(x)+(abs(math_x_height(cur_size))/4);
+if(shift_up<clr)shift_up= clr;
+}
+
+/*:758*/
+#line 14908 "tex.w"
+;
+if(math_type(subscr(q))==empty)shift_amount(x)= -shift_up;
+else/*759:*/
+#line 14952 "tex.w"
+
+{y= clean_box(subscr(q),sub_style(cur_style));
+width(y)= width(y)+script_space;
+if(shift_down<sub2(cur_size))shift_down= sub2(cur_size);
+clr= 4*default_rule_thickness-
+((shift_up-depth(x))-(height(y)-shift_down));
+if(clr> 0)
+{shift_down= shift_down+clr;
+clr= (abs(math_x_height(cur_size)*4)/5)-(shift_up-depth(x));
+if(clr> 0)
+{shift_up= shift_up+clr;
+shift_down= shift_down-clr;
+}
+}
+shift_amount(x)= delta;
+p= new_kern((shift_up-depth(x))-(height(y)-shift_down));link(x)= p;link(p)= y;
+x= vpack(x,natural);shift_amount(x)= shift_down;
+}
+
+/*:759*/
+#line 14911 "tex.w"
+;
+}
+if(new_hlist(q)==null)new_hlist(q)= x;
+else{p= new_hlist(q);
+while(link(p)!=null)p= link(p);
+link(p)= x;
+}
+}
+
+/*:756*//*762:*/
+#line 15024 "tex.w"
+
+small_number make_left_right(pointer q,small_number style,
+scaled max_d,scaled max_h)
+{scaled delta,delta1,delta2;
+if(style<script_style)cur_size= text_size;
+else cur_size= 16*((style-text_style)/2);
+delta2= max_d+axis_height(cur_size);
+delta1= max_h+max_d-delta2;
+if(delta2> delta1)delta1= delta2;
+delta= (delta1/500)*delimiter_factor;
+delta2= delta1+delta1-delimiter_shortfall;
+if(delta<delta2)delta= delta2;
+new_hlist(q)= var_delimiter(delimiter(q),cur_size,delta);
+return type(q)-(left_noad-open_noad);
+}
+
+/*:762*/
+#line 14291 "tex.w"
+
+void mlist_to_hlist(void)
+{
+
+pointer mlist;
+bool penalties;
+small_number style;
+small_number save_style;
+pointer q;
+pointer r;
+small_number r_type;
+small_number t;
+pointer p,x,y,z;
+int pen;
+small_number s;
+scaled max_h,max_d;
+scaled delta;
+mlist= cur_mlist;penalties= mlist_penalties;
+style= cur_style;
+q= mlist;r= null;r_type= op_noad;max_h= 0;max_d= 0;
+/*703:*/
+#line 13884 "tex.w"
+
+{if(cur_style<script_style)cur_size= text_size;
+else cur_size= 16*((cur_style-text_style)/2);
+cur_mu= x_over_n(math_quad(cur_size),18);
+}
+
+/*:703*/
+#line 14311 "tex.w"
+;
+while(q!=null)/*727:*/
+#line 14322 "tex.w"
+
+{/*728:*/
+#line 14338 "tex.w"
+
+reswitch:delta= 0;
+switch(type(q)){
+case bin_noad:switch(r_type){
+case bin_noad:case op_noad:case rel_noad:case open_noad:case punct_noad:case left_noad:
+{type(q)= ord_noad;goto reswitch;
+}
+default:do_nothing;
+}break;
+case rel_noad:case close_noad:case punct_noad:case right_noad:{
+/*729:*/
+#line 14358 "tex.w"
+
+if(r_type==bin_noad)type(r)= ord_noad
+
+/*:729*/
+#line 14348 "tex.w"
+;
+if(type(q)==right_noad)goto done_with_noad;
+}break;
+/*733:*/
+#line 14422 "tex.w"
+
+case left_noad:goto done_with_noad;
+case fraction_noad:{make_fraction(q);goto check_dimensions;
+}
+case op_noad:{delta= make_op(q);
+if(subtype(q)==limits)goto check_dimensions;
+}break;
+case ord_noad:make_ord(q);break;
+case open_noad:case inner_noad:do_nothing;break;
+case radical_noad:make_radical(q);break;
+case over_noad:make_over(q);break;
+case under_noad:make_under(q);break;
+case accent_noad:make_math_accent(q);break;
+case vcenter_noad:make_vcenter(q);break;
+
+/*:733*/
+#line 14351 "tex.w"
+
+/*730:*/
+#line 14361 "tex.w"
+
+case style_node:{cur_style= subtype(q);
+/*703:*/
+#line 13884 "tex.w"
+
+{if(cur_style<script_style)cur_size= text_size;
+else cur_size= 16*((cur_style-text_style)/2);
+cur_mu= x_over_n(math_quad(cur_size),18);
+}
+
+/*:703*/
+#line 14363 "tex.w"
+;
+goto done_with_node;
+}
+case choice_node:/*731:*/
+#line 14381 "tex.w"
+
+{switch(cur_style/2){
+case 0:choose_mlist(display_mlist)break;
+case 1:choose_mlist(text_mlist)break;
+case 2:choose_mlist(script_mlist)break;
+case 3:choose_mlist(script_script_mlist);
+}
+flush_node_list(display_mlist(q));
+flush_node_list(text_mlist(q));
+flush_node_list(script_mlist(q));
+flush_node_list(script_script_mlist(q));
+type(q)= style_node;subtype(q)= cur_style;width(q)= 0;depth(q)= 0;
+if(p!=null)
+{z= link(q);link(q)= p;
+while(link(p)!=null)p= link(p);
+link(p)= z;
+}
+goto done_with_node;
+}
+
+/*:731*/
+#line 14367 "tex.w"
+
+case ins_node:case mark_node:case adjust_node:
+case whatsit_node:case penalty_node:case disc_node:goto done_with_node;
+case rule_node:{if(height(q)> max_h)max_h= height(q);
+if(depth(q)> max_d)max_d= depth(q);goto done_with_node;
+}
+case glue_node:{/*732:*/
+#line 14409 "tex.w"
+
+if(subtype(q)==mu_glue)
+{x= glue_ptr(q);
+y= math_glue(x,cur_mu);delete_glue_ref(x);glue_ptr(q)= y;
+subtype(q)= normal;
+}
+else if((cur_size!=text_size)&&(subtype(q)==cond_math_glue))
+{p= link(q);
+if(p!=null)if((type(p)==glue_node)||(type(p)==kern_node))
+{link(q)= link(p);link(p)= null;flush_node_list(p);
+}
+}
+
+/*:732*/
+#line 14373 "tex.w"
+;
+goto done_with_node;
+}
+case kern_node:{math_kern(q,cur_mu);goto done_with_node;
+}
+
+/*:730*/
+#line 14352 "tex.w"
+
+default:confusion(/*1664:*/
+#line 25888 "tex.w"
+539
+/*:1664*/
+#line 14353 "tex.w"
+);
+
+}
+/*754:*/
+#line 14848 "tex.w"
+
+switch(math_type(nucleus(q))){
+case math_char:case math_text_char:
+/*755:*/
+#line 14870 "tex.w"
+
+{fetch(nucleus(q));
+if(char_exists(cur_i))
+{delta= char_italic(cur_f)(cur_i);p= new_character(cur_f,qo(cur_c));
+if((math_type(nucleus(q))==math_text_char)&&(space(cur_f)!=0))
+delta= 0;
+if((math_type(subscr(q))==empty)&&(delta!=0))
+{link(p)= new_kern(delta);delta= 0;
+}
+}
+else p= null;
+}
+
+/*:755*/
+#line 14853 "tex.w"
+break;
+case empty:p= null;break;
+case sub_box:p= info(nucleus(q));break;
+case sub_mlist:{cur_mlist= info(nucleus(q));save_style= cur_style;
+mlist_penalties= false;mlist_to_hlist();
+
+cur_style= save_style;/*703:*/
+#line 13884 "tex.w"
+
+{if(cur_style<script_style)cur_size= text_size;
+else cur_size= 16*((cur_style-text_style)/2);
+cur_mu= x_over_n(math_quad(cur_size),18);
+}
+
+/*:703*/
+#line 14859 "tex.w"
+;
+p= hpack(link(temp_head),natural);
+}break;
+default:confusion(/*1665:*/
+#line 25891 "tex.w"
+540
+/*:1665*/
+#line 14862 "tex.w"
+);
+
+}
+new_hlist(q)= p;
+if((math_type(subscr(q))==empty)&&(math_type(supscr(q))==empty))
+goto check_dimensions;
+make_scripts(q,delta)
+
+/*:754*/
+#line 14356 "tex.w"
+
+
+/*:728*/
+#line 14325 "tex.w"
+;
+check_dimensions:z= hpack(new_hlist(q),natural);
+if(height(z)> max_h)max_h= height(z);
+if(depth(z)> max_d)max_d= depth(z);
+free_node(z,box_node_size);
+done_with_noad:r= q;r_type= type(r);
+done_with_node:q= link(q);
+}
+
+/*:727*/
+#line 14313 "tex.w"
+;
+/*729:*/
+#line 14358 "tex.w"
+
+if(r_type==bin_noad)type(r)= ord_noad
+
+/*:729*/
+#line 14314 "tex.w"
+;
+/*760:*/
+#line 14977 "tex.w"
+
+p= temp_head;link(p)= null;q= mlist;r_type= 0;cur_style= style;
+/*703:*/
+#line 13884 "tex.w"
+
+{if(cur_style<script_style)cur_size= text_size;
+else cur_size= 16*((cur_style-text_style)/2);
+cur_mu= x_over_n(math_quad(cur_size),18);
+}
+
+/*:703*/
+#line 14979 "tex.w"
+;
+while(q!=null)
+{/*761:*/
+#line 14994 "tex.w"
+
+t= ord_noad;s= noad_size;pen= inf_penalty;
+switch(type(q)){
+case op_noad:case open_noad:case close_noad:case punct_noad:case inner_noad:t= type(q);break;
+case bin_noad:{t= bin_noad;pen= bin_op_penalty;
+}break;
+case rel_noad:{t= rel_noad;pen= rel_penalty;
+}break;
+case ord_noad:case vcenter_noad:case over_noad:case under_noad:do_nothing;break;
+case radical_noad:s= radical_noad_size;break;
+case accent_noad:s= accent_noad_size;break;
+case fraction_noad:{t= inner_noad;s= fraction_noad_size;
+}break;
+case left_noad:case right_noad:t= make_left_right(q,style,max_d,max_h);break;
+case style_node:/*763:*/
+#line 15040 "tex.w"
+
+{cur_style= subtype(q);s= style_node_size;
+/*703:*/
+#line 13884 "tex.w"
+
+{if(cur_style<script_style)cur_size= text_size;
+else cur_size= 16*((cur_style-text_style)/2);
+cur_mu= x_over_n(math_quad(cur_size),18);
+}
+
+/*:703*/
+#line 15042 "tex.w"
+;
+goto delete_q;
+}
+
+/*:763*/
+#line 15008 "tex.w"
+
+case whatsit_node:case penalty_node:case rule_node:case disc_node:case adjust_node:case ins_node:case mark_node:
+case glue_node:case kern_node:
+{link(p)= q;p= q;q= link(q);link(p)= null;goto done;
+}
+default:confusion(/*1666:*/
+#line 25894 "tex.w"
+541
+/*:1666*/
+#line 15013 "tex.w"
+);
+
+}
+
+/*:761*/
+#line 14984 "tex.w"
+;
+/*766:*/
+#line 15081 "tex.w"
+
+if(r_type> 0)
+{switch(so(str_pool[r_type*8+t+magic_offset])){
+case'0':x= 0;break;
+case'1':if(cur_style<script_style)x= thin_mu_skip_code;else x= 0;break;
+case'2':x= thin_mu_skip_code;break;
+case'3':if(cur_style<script_style)x= med_mu_skip_code;else x= 0;break;
+case'4':if(cur_style<script_style)x= thick_mu_skip_code;else x= 0;break;
+default:confusion(/*1668:*/
+#line 25900 "tex.w"
+543
+/*:1668*/
+#line 15089 "tex.w"
+);
+
+}
+if(x!=0)
+{y= math_glue(glue_par(x),cur_mu);
+z= new_glue(y);glue_ref_count(y)= null;link(p)= z;p= z;
+subtype(z)= x+1;
+}
+}
+
+/*:766*/
+#line 14985 "tex.w"
+;
+/*767:*/
+#line 15103 "tex.w"
+
+if(new_hlist(q)!=null)
+{link(p)= new_hlist(q);
+do{p= link(p);
+}while(!(link(p)==null));
+}
+if(penalties)if(link(q)!=null)if(pen<inf_penalty)
+{r_type= type(link(q));
+if(r_type!=penalty_node)if(r_type!=rel_noad)
+{z= new_penalty(pen);link(p)= z;p= z;
+}
+}
+
+/*:767*/
+#line 14986 "tex.w"
+;
+r_type= t;
+delete_q:r= q;q= link(q);free_node(r,s);
+done:;}
+
+/*:760*/
+#line 14316 "tex.w"
+;
+}
+
+/*:726*//*772:*/
+#line 15292 "tex.w"
+void push_alignment(void)
+{pointer p;
+p= get_node(align_stack_node_size);
+link(p)= align_ptr;info(p)= cur_align;
+llink(p)= preamble;rlink(p)= cur_span;
+mem[p+2].i= cur_loop;mem[p+3].i= align_state;
+info(p+4)= cur_head;link(p+4)= cur_tail;
+align_ptr= p;
+cur_head= get_avail();
+}
+
+void pop_alignment(void)
+{pointer p;
+free_avail(cur_head);
+p= align_ptr;
+cur_tail= link(p+4);cur_head= info(p+4);
+align_state= mem[p+3].i;cur_loop= mem[p+2].i;
+cur_span= rlink(p);preamble= llink(p);
+cur_align= info(p);align_ptr= link(p);
+free_node(p,align_stack_node_size);
+}
+
+/*:772*//*774:*/
+#line 15332 "tex.w"
+/*782:*/
+#line 15444 "tex.w"
+
+void get_preamble_token(void)
+{
+restart:get_token();
+while((cur_chr==span_code)&&(cur_cmd==tab_mark))
+{get_token();
+if(cur_cmd> max_command)
+{expand();get_token();
+}
+}
+if(cur_cmd==endv)
+fatal_error("(interwoven alignment preambles are not allowed)");
+
+if((cur_cmd==assign_glue)&&(cur_chr==glue_base+tab_skip_code))
+{scan_optional_equals();scan_glue(glue_val);
+if(global_defs> 0)geq_define(glue_base+tab_skip_code,glue_ref,cur_val);
+else eq_define(glue_base+tab_skip_code,glue_ref,cur_val);
+goto restart;
+}
+}
+
+/*:782*/
+#line 15332 "tex.w"
+
+void align_peek(void);
+void normal_paragraph(void);
+void init_align(void)
+{
+pointer save_cs_ptr;
+pointer p;
+save_cs_ptr= cur_cs;
+push_alignment();align_state= -1000000;
+/*776:*/
+#line 15365 "tex.w"
+
+if((mode==mmode)&&((tail!=head)||(incompleat_noad!=null)))
+{print_err("Improper ");print_esc(/*1542:*/
+#line 25522 "tex.w"
+417
+/*:1542*/
+#line 15367 "tex.w"
+);print_str(" inside $$'s");
+
+help3("Displays can use special alignments (like \\eqalignno)")
+("only if nothing but the alignment itself is between $$'s.")
+("So I've deleted the formulas that preceded this alignment.");
+error();flush_math();
+}
+
+/*:776*/
+#line 15341 "tex.w"
+;
+push_nest();
+/*775:*/
+#line 15356 "tex.w"
+
+if(mode==mmode)
+{mode= -vmode;prev_depth= nest[nest_ptr-2].aux_field.sc;
+}
+else if(mode> 0)negate(mode)
+
+/*:775*/
+#line 15343 "tex.w"
+;
+scan_spec(align_group,false);
+/*777:*/
+#line 15375 "tex.w"
+
+preamble= null;cur_align= align_head;cur_loop= null;scanner_status= aligning;
+warning_index= save_cs_ptr;align_state= -1000000;
+
+loop{/*778:*/
+#line 15386 "tex.w"
+
+link(cur_align)= new_param_glue(tab_skip_code);
+cur_align= link(cur_align)
+
+/*:778*/
+#line 15379 "tex.w"
+;
+if(cur_cmd==car_ret)goto done;
+/*779:*/
+#line 15390 "tex.w"
+
+/*783:*/
+#line 15467 "tex.w"
+
+p= hold_head;link(p)= null;
+loop{get_preamble_token();
+if(cur_cmd==mac_param)goto done1;
+if((cur_cmd<=car_ret)&&(cur_cmd>=tab_mark)&&(align_state==-1000000))
+if((p==hold_head)&&(cur_loop==null)&&(cur_cmd==tab_mark)
+)cur_loop= cur_align;
+else{print_err("Missing # inserted in alignment preamble");
+
+help3("There should be exactly one # between &'s, when an")
+("\\halign or \\valign is being set up. In this case you had")
+("none, so I've put one in; maybe that will work.");
+back_error();goto done1;
+}
+else if((cur_cmd!=spacer)||(p!=hold_head))
+{link(p)= get_avail();p= link(p);info(p)= cur_tok;
+}
+}
+done1:
+
+/*:783*/
+#line 15391 "tex.w"
+;
+link(cur_align)= new_null_box();cur_align= link(cur_align);
+info(cur_align)= end_span;width(cur_align)= null_flag;
+u_part(cur_align)= link(hold_head);
+/*784:*/
+#line 15487 "tex.w"
+
+p= hold_head;link(p)= null;
+loop{resume:get_preamble_token();
+if((cur_cmd<=car_ret)&&(cur_cmd>=tab_mark)&&(align_state==-1000000))
+goto done2;
+if(cur_cmd==mac_param)
+{print_err("Only one # is allowed per tab");
+
+help3("There should be exactly one # between &'s, when an")
+("\\halign or \\valign is being set up. In this case you had")
+("more than one, so I'm ignoring all but the first.");
+error();goto resume;
+}
+link(p)= get_avail();p= link(p);info(p)= cur_tok;
+}
+done2:link(p)= get_avail();p= link(p);
+info(p)= end_template_token
+
+/*:784*/
+#line 15395 "tex.w"
+;
+v_part(cur_align)= link(hold_head)
+
+/*:779*/
+#line 15382 "tex.w"
+;
+}
+done:scanner_status= normal
+
+/*:777*/
+#line 15345 "tex.w"
+;
+new_save_level(align_group);
+if(every_cr!=null)begin_token_list(every_cr,every_cr_text);
+align_peek();
+}
+
+/*:774*//*786:*/
+#line 15537 "tex.w"
+/*787:*/
+#line 15550 "tex.w"
+
+void init_span(pointer p)
+{push_nest();
+if(mode==-hmode)space_factor= 1000;
+else{prev_depth= ignore_depth;normal_paragraph();
+}
+cur_span= p;
+}
+
+/*:787*/
+#line 15537 "tex.w"
+
+void init_row(void)
+{push_nest();mode= (-hmode-vmode)-mode;
+if(mode==-hmode)space_factor= 0;else prev_depth= 0;
+tail_append(new_glue(glue_ptr(preamble)));
+subtype(tail)= tab_skip_code+1;
+cur_align= link(preamble);cur_tail= cur_head;init_span(cur_align);
+}
+
+/*:786*//*788:*/
+#line 15566 "tex.w"
+void init_col(void)
+{extra_info(cur_align)= cur_cmd;
+if(cur_cmd==omit)align_state= 0;
+else{back_input();begin_token_list(u_part(cur_align),u_template);
+}
+}
+
+/*:788*//*791:*/
+#line 15603 "tex.w"
+bool fin_col(void)
+{
+pointer p;
+pointer q,r;
+pointer s;
+pointer u;
+scaled w;
+glue_ord o;
+halfword n;
+if(cur_align==null)confusion(/*1673:*/
+#line 25915 "tex.w"
+548
+/*:1673*/
+#line 15612 "tex.w"
+);
+q= link(cur_align);if(q==null)confusion(/*1673:*/
+#line 25915 "tex.w"
+548
+/*:1673*/
+#line 15613 "tex.w"
+);
+
+if(align_state<500000)
+fatal_error("(interwoven alignment preambles are not allowed)");
+
+p= link(q);
+/*792:*/
+#line 15634 "tex.w"
+
+if((p==null)&&(extra_info(cur_align)<cr_code))
+if(cur_loop!=null)/*793:*/
+#line 15646 "tex.w"
+
+{link(q)= new_null_box();p= link(q);
+info(p)= end_span;width(p)= null_flag;cur_loop= link(cur_loop);
+/*794:*/
+#line 15654 "tex.w"
+
+q= hold_head;r= u_part(cur_loop);
+while(r!=null)
+{link(q)= get_avail();q= link(q);info(q)= info(r);r= link(r);
+}
+link(q)= null;u_part(p)= link(hold_head);
+q= hold_head;r= v_part(cur_loop);
+while(r!=null)
+{link(q)= get_avail();q= link(q);info(q)= info(r);r= link(r);
+}
+link(q)= null;v_part(p)= link(hold_head)
+
+/*:794*/
+#line 15649 "tex.w"
+;
+cur_loop= link(cur_loop);
+link(p)= new_glue(glue_ptr(cur_loop));
+}
+
+/*:793*/
+#line 15636 "tex.w"
+
+else{print_err("Extra alignment tab has been changed to ");
+
+print_esc(/*1670:*/
+#line 25906 "tex.w"
+545
+/*:1670*/
+#line 15639 "tex.w"
+);
+help3("You have given more \\span or & marks than there were")
+("in the preamble to the \\halign or \\valign now in progress.")
+("So I'll assume that you meant to type \\cr instead.");
+extra_info(cur_align)= cr_code;error();
+}
+
+/*:792*/
+#line 15619 "tex.w"
+;
+if(extra_info(cur_align)!=span_code)
+{unsave();new_save_level(align_group);
+/*796:*/
+#line 15670 "tex.w"
+
+{if(mode==-hmode)
+{adjust_tail= cur_tail;u= hpack(link(head),natural);w= width(u);
+cur_tail= adjust_tail;adjust_tail= null;
+}
+else{u= vpackage(link(head),natural,0);w= height(u);
+}
+n= min_quarterword;
+if(cur_span!=cur_align)/*798:*/
+#line 15704 "tex.w"
+
+{q= cur_span;
+do{incr(n);q= link(link(q));
+}while(!(q==cur_align));
+if(n> max_quarterword)confusion(/*1674:*/
+#line 25918 "tex.w"
+549
+/*:1674*/
+#line 15708 "tex.w"
+);
+
+
+q= cur_span;while(link(info(q))<n)q= info(q);
+if(link(info(q))> n)
+{s= get_node(span_node_size);info(s)= info(q);link(s)= n;
+info(q)= s;width(s)= w;
+}
+else if(width(info(q))<w)width(info(q))= w;
+}
+
+/*:798*/
+#line 15678 "tex.w"
+
+else if(w> width(cur_align))width(cur_align)= w;
+type(u)= unset_node;span_count(u)= n;
+/*659:*/
+#line 13082 "tex.w"
+
+if(total_stretch[filll]!=0)o= filll;
+else if(total_stretch[fill]!=0)o= fill;
+else if(total_stretch[fil]!=0)o= fil;
+else o= normal
+
+/*:659*/
+#line 15681 "tex.w"
+;
+glue_order(u)= o;glue_stretch(u)= total_stretch[o];
+/*665:*/
+#line 13146 "tex.w"
+
+if(total_shrink[filll]!=0)o= filll;
+else if(total_shrink[fill]!=0)o= fill;
+else if(total_shrink[fil]!=0)o= fil;
+else o= normal
+
+/*:665*/
+#line 15683 "tex.w"
+;
+glue_sign(u)= o;glue_shrink(u)= total_shrink[o];
+pop_nest();link(tail)= u;tail= u;
+}
+
+/*:796*/
+#line 15622 "tex.w"
+;
+/*795:*/
+#line 15666 "tex.w"
+
+tail_append(new_glue(glue_ptr(link(cur_align))));
+subtype(tail)= tab_skip_code+1
+
+/*:795*/
+#line 15623 "tex.w"
+;
+if(extra_info(cur_align)>=cr_code)
+{return true;
+}
+init_span(p);
+}
+align_state= 1000000;/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 15629 "tex.w"
+;
+cur_align= p;
+init_col();return false;
+}
+
+/*:791*//*799:*/
+#line 15724 "tex.w"
+void fin_row(void)
+{pointer p;
+if(mode==-hmode)
+{p= hpack(link(head),natural);
+pop_nest();append_to_vlist(p);
+if(cur_head!=cur_tail)
+{link(tail)= link(cur_head);tail= cur_tail;
+}
+}
+else{p= vpack(link(head),natural);pop_nest();
+link(tail)= p;tail= p;space_factor= 1000;
+}
+type(p)= unset_node;glue_stretch(p)= 0;
+if(every_cr!=null)begin_token_list(every_cr,every_cr_text);
+align_peek();
+}
+
+/*:799*//*800:*/
+#line 15745 "tex.w"
+void do_assignments(void);
+void resume_after_display(void);
+void build_page(void);
+void fin_align(void)
+{pointer p,q,r,s,u,v;
+scaled t,w;
+scaled o;
+halfword n;
+scaled rule_save;
+memory_word aux_save;
+if(cur_group!=align_group)confusion(/*1675:*/
+#line 25921 "tex.w"
+550
+/*:1675*/
+#line 15755 "tex.w"
+);
+
+unsave();
+if(cur_group!=align_group)confusion(/*1676:*/
+#line 25924 "tex.w"
+551
+/*:1676*/
+#line 15758 "tex.w"
+);
+unsave();
+if(nest[nest_ptr-1].mode_field==mmode)o= display_indent;
+else o= 0;
+/*801:*/
+#line 15795 "tex.w"
+
+q= link(preamble);
+do{flush_list(u_part(q));flush_list(v_part(q));
+p= link(link(q));
+if(width(q)==null_flag)
+/*802:*/
+#line 15809 "tex.w"
+
+{width(q)= 0;r= link(q);s= glue_ptr(r);
+if(s!=zero_glue)
+{add_glue_ref(zero_glue);delete_glue_ref(s);
+glue_ptr(r)= zero_glue;
+}
+}
+
+/*:802*/
+#line 15800 "tex.w"
+;
+if(info(q)!=end_span)
+/*803:*/
+#line 15824 "tex.w"
+
+{t= width(q)+width(glue_ptr(link(q)));
+r= info(q);s= end_span;info(s)= p;n= min_quarterword+1;
+do{width(r)= width(r)-t;u= info(r);
+while(link(r)> n)
+{s= info(s);n= link(info(s))+1;
+}
+if(link(r)<n)
+{info(r)= info(s);info(s)= r;decr(link(r));s= r;
+}
+else{if(width(r)> width(info(s)))width(info(s))= width(r);
+free_node(r,span_node_size);
+}
+r= u;
+}while(!(r==end_span));
+}
+
+/*:803*/
+#line 15803 "tex.w"
+;
+type(q)= unset_node;span_count(q)= min_quarterword;height(q)= 0;
+depth(q)= 0;glue_order(q)= normal;glue_sign(q)= normal;
+glue_stretch(q)= 0;glue_shrink(q)= 0;q= p;
+}while(!(q==null))
+
+/*:801*/
+#line 15763 "tex.w"
+;
+/*804:*/
+#line 15847 "tex.w"
+
+save_ptr= save_ptr-2;pack_begin_line= -mode_line;
+if(mode==-vmode)
+{rule_save= overfull_rule;
+overfull_rule= 0;
+p= hpack(preamble,saved(1),saved(0));overfull_rule= rule_save;
+}
+else{q= link(preamble);
+do{height(q)= width(q);width(q)= 0;q= link(link(q));
+}while(!(q==null));
+p= vpack(preamble,saved(1),saved(0));
+q= link(preamble);
+do{width(q)= height(q);height(q)= 0;q= link(link(q));
+}while(!(q==null));
+}
+pack_begin_line= 0
+
+/*:804*/
+#line 15765 "tex.w"
+;
+/*805:*/
+#line 15864 "tex.w"
+
+q= link(head);s= head;
+while(q!=null)
+{if(!is_char_node(q))
+if(type(q)==unset_node)
+/*807:*/
+#line 15888 "tex.w"
+
+{if(mode==-vmode)
+{type(q)= hlist_node;width(q)= width(p);
+}
+else{type(q)= vlist_node;height(q)= height(p);
+}
+glue_order(q)= glue_order(p);glue_sign(q)= glue_sign(p);
+glue_set(q)= glue_set(p);shift_amount(q)= o;
+r= link(list_ptr(q));s= link(list_ptr(p));
+do{/*808:*/
+#line 15907 "tex.w"
+
+n= span_count(r);t= width(s);w= t;u= hold_head;
+while(n> min_quarterword)
+{decr(n);
+/*809:*/
+#line 15924 "tex.w"
+
+s= link(s);v= glue_ptr(s);link(u)= new_glue(v);u= link(u);
+subtype(u)= tab_skip_code+1;t= t+width(v);
+if(glue_sign(p)==stretching)
+{if(stretch_order(v)==glue_order(p))
+t= t+round(float(glue_set(p))*stretch(v));
+
+}
+else if(glue_sign(p)==shrinking)
+{if(shrink_order(v)==glue_order(p))
+t= t-round(float(glue_set(p))*shrink(v));
+}
+s= link(s);link(u)= new_null_box();u= link(u);t= t+width(s);
+if(mode==-vmode)width(u)= width(s);else
+{type(u)= vlist_node;height(u)= width(s);
+}
+
+/*:809*/
+#line 15912 "tex.w"
+;
+}
+if(mode==-vmode)
+/*810:*/
+#line 15941 "tex.w"
+
+{height(r)= height(q);depth(r)= depth(q);
+if(t==width(r))
+{glue_sign(r)= normal;glue_order(r)= normal;
+set_glue_ratio_zero(glue_set(r));
+}
+else if(t> width(r))
+{glue_sign(r)= stretching;
+if(glue_stretch(r)==0)set_glue_ratio_zero(glue_set(r));
+else glue_set(r)= unfloat((t-width(r))/(double)glue_stretch(r));
+
+}
+else{glue_order(r)= glue_sign(r);glue_sign(r)= shrinking;
+if(glue_shrink(r)==0)set_glue_ratio_zero(glue_set(r));
+else if((glue_order(r)==normal)&&(width(r)-t> glue_shrink(r)))
+set_glue_ratio_one(glue_set(r));
+else glue_set(r)= unfloat((width(r)-t)/(double)glue_shrink(r));
+}
+width(r)= w;type(r)= hlist_node;
+}
+
+/*:810*/
+#line 15916 "tex.w"
+
+else/*811:*/
+#line 15962 "tex.w"
+
+{width(r)= width(q);
+if(t==height(r))
+{glue_sign(r)= normal;glue_order(r)= normal;
+set_glue_ratio_zero(glue_set(r));
+}
+else if(t> height(r))
+{glue_sign(r)= stretching;
+if(glue_stretch(r)==0)set_glue_ratio_zero(glue_set(r));
+else glue_set(r)= unfloat((t-height(r))/(double)glue_stretch(r));
+
+}
+else{glue_order(r)= glue_sign(r);glue_sign(r)= shrinking;
+if(glue_shrink(r)==0)set_glue_ratio_zero(glue_set(r));
+else if((glue_order(r)==normal)&&(height(r)-t> glue_shrink(r)))
+set_glue_ratio_one(glue_set(r));
+else glue_set(r)= unfloat((height(r)-t)/(double)glue_shrink(r));
+}
+height(r)= w;type(r)= vlist_node;
+}
+
+/*:811*/
+#line 15918 "tex.w"
+;
+shift_amount(r)= 0;
+if(u!=hold_head)
+{link(u)= link(r);link(r)= link(hold_head);r= u;
+}
+
+/*:808*/
+#line 15897 "tex.w"
+;
+r= link(link(r));s= link(link(s));
+}while(!(r==null));
+}
+
+/*:807*/
+#line 15869 "tex.w"
+
+else if(type(q)==rule_node)
+/*806:*/
+#line 15875 "tex.w"
+
+{if(is_running(width(q)))width(q)= width(p);
+if(is_running(height(q)))height(q)= height(p);
+if(is_running(depth(q)))depth(q)= depth(p);
+if(o!=0)
+{r= link(q);link(q)= null;q= hpack(q,natural);
+shift_amount(q)= o;link(q)= r;link(s)= q;
+}
+}
+
+/*:806*/
+#line 15871 "tex.w"
+;
+s= q;q= link(q);
+}
+
+/*:805*/
+#line 15766 "tex.w"
+;
+flush_node_list(p);pop_alignment();
+/*812:*/
+#line 15993 "tex.w"
+
+aux_save= aux;p= link(head);q= tail;pop_nest();
+if(mode==mmode)/*1206:*/
+#line 22615 "tex.w"
+
+{do_assignments();
+if(cur_cmd!=math_shift)/*1207:*/
+#line 22629 "tex.w"
+
+{print_err("Missing $$ inserted");
+
+help2("Displays can use special alignments (like \\eqalignno)")
+("only if nothing but the alignment itself is between $$'s.");
+back_error();
+}
+
+/*:1207*/
+#line 22617 "tex.w"
+
+else/*1197:*/
+#line 22467 "tex.w"
+
+{get_x_token();
+if(cur_cmd!=math_shift)
+{print_err("Display math should end with $$");
+
+help2("The `$' that I just saw supposedly matches a previous `$$'.")
+("So I shall assume that you typed `$$' both times.");
+back_error();
+}
+}
+
+/*:1197*/
+#line 22618 "tex.w"
+;
+pop_nest();
+tail_append(new_penalty(pre_display_penalty));
+tail_append(new_param_glue(above_display_skip_code));
+link(tail)= p;
+if(p!=null)tail= q;
+tail_append(new_penalty(post_display_penalty));
+tail_append(new_param_glue(below_display_skip_code));
+prev_depth= aux_save.sc;resume_after_display();
+}
+
+/*:1206*/
+#line 15995 "tex.w"
+
+else{aux= aux_save;link(tail)= p;
+if(p!=null)tail= q;
+if(mode==vmode)build_page();
+}
+
+/*:812*/
+#line 15768 "tex.w"
+;
+}
+/*785:*/
+#line 15515 "tex.w"
+
+void align_peek(void)
+{
+restart:align_state= 1000000;/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 15518 "tex.w"
+;
+if(cur_cmd==no_align)
+{scan_left_brace();new_save_level(no_align_group);
+if(mode==-vmode)normal_paragraph();
+}
+else if(cur_cmd==right_brace)fin_align();
+else if((cur_cmd==car_ret)&&(cur_chr==cr_cr_code))
+goto restart;
+else{init_row();
+init_col();
+}
+}
+
+/*:785*/
+#line 15770 "tex.w"
+
+
+/*:800*//*815:*/
+#line 16057 "tex.w"
+/*826:*/
+#line 16291 "tex.w"
+
+pointer finite_shrink(pointer p)
+{pointer q;
+if(no_shrink_error_yet)
+{no_shrink_error_yet= false;
+print_err("Infinite glue shrinkage found in a paragraph");
+
+help5("The paragraph just ended includes some glue that has")
+("infinite shrinkability, e.g., `\\hskip 0pt minus 1fil'.")
+("Such glue doesn't belong there---it allows a paragraph")
+("of any length to fit on one line. But it's safe to proceed,")
+("since the offensive shrinkability has been made finite.");
+error();
+}
+q= new_spec(p);shrink_order(q)= normal;
+delete_glue_ref(p);return q;
+}
+
+/*:826*//*829:*/
+#line 16363 "tex.w"
+
+void try_break(int pi,small_number break_type)
+{
+pointer r;
+pointer prev_r;
+halfword old_l;
+bool no_break_yet;
+/*830:*/
+#line 16391 "tex.w"
+
+pointer prev_prev_r;
+pointer s;
+pointer q;
+pointer v;
+int t;
+internal_font_number f;
+halfword l;
+bool node_r_stays_active;
+scaled line_width;
+uint8_t fit_class;
+halfword b;
+int d;
+bool artificial_demerits;
+#ifdef STAT
+pointer save_link;
+#endif
+scaled shortfall;
+
+/*:830*/
+#line 16370 "tex.w"
+
+/*831:*/
+#line 16410 "tex.w"
+
+if(abs(pi)>=inf_penalty)
+if(pi> 0)goto end;
+else pi= eject_penalty
+
+/*:831*/
+#line 16371 "tex.w"
+;
+no_break_yet= true;prev_r= active;old_l= 0;
+do_all_six(copy_to_cur_active);
+loop{resume:r= link(prev_r);
+/*832:*/
+#line 16420 "tex.w"
+
+
+if(type(r)==delta_node)
+{do_all_six(update_width);
+prev_prev_r= prev_r;prev_r= r;goto resume;
+}
+
+/*:832*/
+#line 16376 "tex.w"
+;
+/*835:*/
+#line 16465 "tex.w"
+
+{l= line_number(r);
+if(l> old_l)
+{
+if((minimum_demerits<awful_bad)&&
+((old_l!=easy_line)||(r==last_active)))
+/*836:*/
+#line 16483 "tex.w"
+
+{if(no_break_yet)/*837:*/
+#line 16519 "tex.w"
+
+{no_break_yet= false;do_all_six(set_break_width_to_background);
+s= cur_p;
+if(break_type> unhyphenated)if(cur_p!=null)
+/*840:*/
+#line 16562 "tex.w"
+
+{t= replace_count(cur_p);v= cur_p;s= post_break(cur_p);
+while(t> 0)
+{decr(t);v= link(v);
+/*841:*/
+#line 16580 "tex.w"
+
+if(is_char_node(v))
+{f= font(v);
+break_width[1]= break_width[1]-char_width(f)(char_info(f)(character(v)));
+}
+else switch(type(v)){
+case ligature_node:{f= font(lig_char(v));
+break_width[1]= break_width[1]-
+char_width(f)(char_info(f)(character(lig_char(v))));
+}break;
+case hlist_node:case vlist_node:case rule_node:case kern_node:
+break_width[1]= break_width[1]-width(v);break;
+default:confusion(/*1677:*/
+#line 25927 "tex.w"
+552
+/*:1677*/
+#line 16592 "tex.w"
+);
+
+}
+
+/*:841*/
+#line 16566 "tex.w"
+;
+}
+while(s!=null)
+{/*842:*/
+#line 16596 "tex.w"
+
+if(is_char_node(s))
+{f= font(s);
+break_width[1]= break_width[1]+char_width(f)(char_info(f)(character(s)));
+}
+else switch(type(s)){
+case ligature_node:{f= font(lig_char(s));
+break_width[1]= break_width[1]+
+char_width(f)(char_info(f)(character(lig_char(s))));
+}break;
+case hlist_node:case vlist_node:case rule_node:case kern_node:
+break_width[1]= break_width[1]+width(s);break;
+default:confusion(/*1678:*/
+#line 25930 "tex.w"
+553
+/*:1678*/
+#line 16608 "tex.w"
+);
+
+}
+
+/*:842*/
+#line 16569 "tex.w"
+;
+s= link(s);
+}
+break_width[1]= break_width[1]+disc_width;
+if(post_break(cur_p)==null)s= link(v);
+
+}
+
+/*:840*/
+#line 16523 "tex.w"
+;
+while(s!=null)
+{if(is_char_node(s))goto done;
+switch(type(s)){
+case glue_node:/*838:*/
+#line 16538 "tex.w"
+
+{v= glue_ptr(s);break_width[1]= break_width[1]-width(v);
+break_width[2+stretch_order(v)]= break_width[2+stretch_order(v)]-stretch(v);
+break_width[6]= break_width[6]-shrink(v);
+}
+
+/*:838*/
+#line 16527 "tex.w"
+break;
+case penalty_node:do_nothing;break;
+case math_node:break_width[1]= break_width[1]-width(s);break;
+case kern_node:if(subtype(s)!=explicit)goto done;
+else break_width[1]= break_width[1]-width(s);break;
+default:goto done;
+}
+s= link(s);
+}
+done:;}
+
+/*:837*/
+#line 16484 "tex.w"
+;
+/*843:*/
+#line 16621 "tex.w"
+
+if(type(prev_r)==delta_node)
+{do_all_six(convert_to_break_width);
+}
+else if(prev_r==active)
+{do_all_six(store_break_width);
+}
+else{q= get_node(delta_node_size);link(q)= r;type(q)= delta_node;
+subtype(q)= 0;
+do_all_six(new_delta_to_break_width);
+link(prev_r)= q;prev_prev_r= prev_r;prev_r= q;
+}
+
+/*:843*/
+#line 16485 "tex.w"
+;
+if(abs(adj_demerits)>=awful_bad-minimum_demerits)
+minimum_demerits= awful_bad-1;
+else minimum_demerits= minimum_demerits+abs(adj_demerits);
+for(fit_class= very_loose_fit;fit_class<=tight_fit;fit_class++)
+{if(minimal_demerits[fit_class]<=minimum_demerits)
+/*845:*/
+#line 16651 "tex.w"
+
+{q= get_node(passive_node_size);
+link(q)= passive;passive= q;cur_break(q)= cur_p;
+#ifdef STAT
+incr(pass_number);serial(q)= pass_number;
+#endif
+
+prev_break(q)= best_place[fit_class];
+q= get_node(active_node_size);break_node(q)= passive;
+line_number(q)= best_pl_line[fit_class]+1;
+fitness(q)= fit_class;type(q)= break_type;
+total_demerits(q)= minimal_demerits[fit_class];
+link(q)= r;link(prev_r)= q;prev_r= q;
+#ifdef STAT
+if(tracing_paragraphs> 0)
+/*846:*/
+#line 16671 "tex.w"
+
+{print_nl("@@");print_int(serial(passive));
+
+print_str(": line ");print_int(line_number(q)-1);
+print_char('.');print_int(fit_class);
+if(break_type==hyphenated)print_char('-');
+print_str(" t=");print_int(total_demerits(q));
+print_str(" -> @@");
+if(prev_break(passive)==null)print_char('0');
+else print_int(serial(prev_break(passive)));
+}
+
+/*:846*/
+#line 16666 "tex.w"
+;
+#endif
+
+}
+
+/*:845*/
+#line 16491 "tex.w"
+;
+minimal_demerits[fit_class]= awful_bad;
+}
+minimum_demerits= awful_bad;
+/*844:*/
+#line 16640 "tex.w"
+
+if(r!=last_active)
+{q= get_node(delta_node_size);link(q)= r;type(q)= delta_node;
+subtype(q)= 0;
+do_all_six(new_delta_from_break_width);
+link(prev_r)= q;prev_prev_r= prev_r;prev_r= q;
+}
+
+/*:844*/
+#line 16495 "tex.w"
+;
+}
+
+/*:836*/
+#line 16471 "tex.w"
+;
+if(r==last_active)goto end;
+/*850:*/
+#line 16747 "tex.w"
+
+if(l> easy_line)
+{line_width= second_width;old_l= max_halfword-1;
+}
+else{old_l= l;
+if(l> last_special_line)line_width= second_width;
+else if(par_shape_ptr==null)line_width= first_width;
+else line_width= mem[par_shape_ptr+2*l].sc;
+}
+
+/*:850*/
+#line 16473 "tex.w"
+;
+}
+}
+
+/*:835*/
+#line 16379 "tex.w"
+;
+/*851:*/
+#line 16767 "tex.w"
+
+{artificial_demerits= false;
+
+shortfall= line_width-cur_active_width[1];
+if(shortfall> 0)
+/*852:*/
+#line 16797 "tex.w"
+
+if((cur_active_width[3]!=0)||(cur_active_width[4]!=0)||
+(cur_active_width[5]!=0))
+{b= 0;fit_class= decent_fit;
+}
+else{if(shortfall> 7230584)if(cur_active_width[2]<1663497)
+{b= inf_bad;fit_class= very_loose_fit;goto done1;
+}
+b= badness(shortfall,cur_active_width[2]);
+if(b> 12)
+if(b> 99)fit_class= very_loose_fit;
+else fit_class= loose_fit;
+else fit_class= decent_fit;
+done1:;
+}
+
+/*:852*/
+#line 16773 "tex.w"
+
+else/*853:*/
+#line 16816 "tex.w"
+
+{if(-shortfall> cur_active_width[6])b= inf_bad+1;
+else b= badness(-shortfall,cur_active_width[6]);
+if(b> 12)fit_class= tight_fit;else fit_class= decent_fit;
+}
+
+/*:853*/
+#line 16775 "tex.w"
+;
+if((b> inf_bad)||(pi==eject_penalty))
+/*854:*/
+#line 16831 "tex.w"
+
+{if(final_pass&&(minimum_demerits==awful_bad)&&
+(link(r)==last_active)&&
+(prev_r==active))
+artificial_demerits= true;
+else if(b> threshold)goto deactivate;
+node_r_stays_active= false;
+}
+
+/*:854*/
+#line 16778 "tex.w"
+
+else{prev_r= r;
+if(b> threshold)goto resume;
+node_r_stays_active= true;
+}
+/*855:*/
+#line 16847 "tex.w"
+
+if(artificial_demerits)d= 0;
+else/*859:*/
+#line 16908 "tex.w"
+
+{d= line_penalty+b;
+if(abs(d)>=10000)d= 100000000;else d= d*d;
+if(pi!=0)
+if(pi> 0)d= d+pi*pi;
+else if(pi> eject_penalty)d= d-pi*pi;
+if((break_type==hyphenated)&&(type(r)==hyphenated))
+if(cur_p!=null)d= d+double_hyphen_demerits;
+else d= d+final_hyphen_demerits;
+if(abs(fit_class-fitness(r))> 1)d= d+adj_demerits;
+}
+
+/*:859*/
+#line 16849 "tex.w"
+;
+#ifdef STAT
+if(tracing_paragraphs> 0)
+/*856:*/
+#line 16863 "tex.w"
+
+{if(printed_node!=cur_p)
+/*857:*/
+#line 16885 "tex.w"
+
+{print_nl("");
+if(cur_p==null)short_display(link(printed_node));
+else{save_link= link(cur_p);
+link(cur_p)= null;print_nl("");short_display(link(printed_node));
+link(cur_p)= save_link;
+}
+printed_node= cur_p;
+}
+
+/*:857*/
+#line 16865 "tex.w"
+;
+print_nl("@");
+
+if(cur_p==null)print_esc(/*1569:*/
+#line 25603 "tex.w"
+444
+/*:1569*/
+#line 16868 "tex.w"
+);
+else if(type(cur_p)!=glue_node)
+{if(type(cur_p)==penalty_node)print_esc(/*1553:*/
+#line 25555 "tex.w"
+428
+/*:1553*/
+#line 16870 "tex.w"
+);
+else if(type(cur_p)==disc_node)print_esc(/*1400:*/
+#line 25096 "tex.w"
+275
+/*:1400*/
+#line 16871 "tex.w"
+);
+else if(type(cur_p)==kern_node)print_esc(/*1396:*/
+#line 25084 "tex.w"
+271
+/*:1396*/
+#line 16872 "tex.w"
+);
+else print_esc(/*1398:*/
+#line 25090 "tex.w"
+273
+/*:1398*/
+#line 16873 "tex.w"
+);
+}
+print_str(" via @@");
+if(break_node(r)==null)print_char('0');
+else print_int(serial(break_node(r)));
+print_str(" b=");
+if(b> inf_bad)print_char('*');else print_int(b);
+
+print_str(" p=");print_int(pi);print_str(" d=");
+if(artificial_demerits)print_char('*');else print_int(d);
+}
+
+/*:856*/
+#line 16852 "tex.w"
+;
+#endif
+
+d= d+total_demerits(r);
+
+if(d<=minimal_demerits[fit_class])
+{minimal_demerits[fit_class]= d;
+best_place[fit_class]= break_node(r);best_pl_line[fit_class]= l;
+if(d<minimum_demerits)minimum_demerits= d;
+}
+
+/*:855*/
+#line 16783 "tex.w"
+;
+if(node_r_stays_active)goto resume;
+deactivate:/*860:*/
+#line 16930 "tex.w"
+
+link(prev_r)= link(r);free_node(r,active_node_size);
+if(prev_r==active)/*861:*/
+#line 16955 "tex.w"
+
+{r= link(active);
+if(type(r)==delta_node)
+{do_all_six(update_active);
+do_all_six(copy_to_cur_active);
+link(active)= link(r);free_node(r,delta_node_size);
+}
+}
+
+/*:861*/
+#line 16933 "tex.w"
+
+else if(type(prev_r)==delta_node)
+{r= link(prev_r);
+if(r==last_active)
+{do_all_six(downdate_width);
+link(prev_prev_r)= last_active;
+free_node(prev_r,delta_node_size);prev_r= prev_prev_r;
+}
+else if(type(r)==delta_node)
+{do_all_six(update_width);
+do_all_six(combine_two_deltas);
+link(prev_r)= link(r);free_node(r,delta_node_size);
+}
+}
+
+/*:860*/
+#line 16785 "tex.w"
+;
+}
+
+/*:851*/
+#line 16382 "tex.w"
+;
+}
+end:;
+#ifdef STAT
+/*858:*/
+#line 16900 "tex.w"
+
+if(cur_p==printed_node)if(cur_p!=null)if(type(cur_p)==disc_node)
+{t= replace_count(cur_p);
+while(t> 0)
+{decr(t);printed_node= link(printed_node);
+}
+}
+
+/*:858*/
+#line 16386 "tex.w"
+;
+#endif
+
+}
+
+/*:829*//*877:*/
+#line 17281 "tex.w"
+
+void post_line_break(int final_widow_penalty)
+{
+pointer q,r,s;
+bool disc_break;
+bool post_disc_break;
+scaled cur_width;
+scaled cur_indent;
+quarterword t;
+int pen;
+halfword cur_line;
+/*878:*/
+#line 17312 "tex.w"
+
+q= break_node(best_bet);cur_p= null;
+do{r= q;q= prev_break(q);next_break(r)= cur_p;cur_p= r;
+}while(!(q==null))
+
+/*:878*/
+#line 17292 "tex.w"
+;
+cur_line= prev_graf+1;
+do{/*880:*/
+#line 17349 "tex.w"
+
+/*881:*/
+#line 17361 "tex.w"
+
+q= cur_break(cur_p);disc_break= false;post_disc_break= false;
+if(q!=null)
+if(type(q)==glue_node)
+{delete_glue_ref(glue_ptr(q));
+glue_ptr(q)= right_skip;
+subtype(q)= right_skip_code+1;add_glue_ref(right_skip);
+goto done;
+}
+else{if(type(q)==disc_node)
+/*882:*/
+#line 17380 "tex.w"
+
+{t= replace_count(q);
+/*883:*/
+#line 17388 "tex.w"
+
+if(t==0)r= link(q);
+else{r= q;
+while(t> 1)
+{r= link(r);decr(t);
+}
+s= link(r);
+r= link(s);link(s)= null;
+flush_node_list(link(q));replace_count(q)= 0;
+}
+
+/*:883*/
+#line 17382 "tex.w"
+;
+if(post_break(q)!=null)/*884:*/
+#line 17402 "tex.w"
+
+{s= post_break(q);
+while(link(s)!=null)s= link(s);
+link(s)= r;r= post_break(q);post_break(q)= null;post_disc_break= true;
+}
+
+/*:884*/
+#line 17383 "tex.w"
+;
+if(pre_break(q)!=null)/*885:*/
+#line 17411 "tex.w"
+
+{s= pre_break(q);link(q)= s;
+while(link(s)!=null)s= link(s);
+pre_break(q)= null;q= s;
+}
+
+/*:885*/
+#line 17384 "tex.w"
+;
+link(q)= r;disc_break= true;
+}
+
+/*:882*/
+#line 17371 "tex.w"
+
+else if((type(q)==math_node)||(type(q)==kern_node))width(q)= 0;
+}
+else{q= temp_head;
+while(link(q)!=null)q= link(q);
+}
+/*886:*/
+#line 17417 "tex.w"
+
+r= new_param_glue(right_skip_code);link(r)= link(q);link(q)= r;q= r
+
+/*:886*/
+#line 17377 "tex.w"
+;
+done:
+
+/*:881*/
+#line 17351 "tex.w"
+;
+/*887:*/
+#line 17424 "tex.w"
+
+r= link(q);link(q)= null;q= link(temp_head);link(temp_head)= r;
+if(left_skip!=zero_glue)
+{r= new_param_glue(left_skip_code);
+link(r)= q;q= r;
+}
+
+/*:887*/
+#line 17352 "tex.w"
+;
+/*889:*/
+#line 17443 "tex.w"
+
+if(cur_line> last_special_line)
+{cur_width= second_width;cur_indent= second_indent;
+}
+else if(par_shape_ptr==null)
+{cur_width= first_width;cur_indent= first_indent;
+}
+else{cur_width= mem[par_shape_ptr+2*cur_line].sc;
+cur_indent= mem[par_shape_ptr+2*cur_line-1].sc;
+}
+adjust_tail= adjust_head;just_box= hpack(q,cur_width,exactly);
+shift_amount(just_box)= cur_indent
+
+/*:889*/
+#line 17353 "tex.w"
+;
+/*888:*/
+#line 17431 "tex.w"
+
+append_to_vlist(just_box);
+if(adjust_head!=adjust_tail)
+{link(tail)= link(adjust_head);tail= adjust_tail;
+}
+adjust_tail= null
+
+/*:888*/
+#line 17355 "tex.w"
+;
+/*890:*/
+#line 17463 "tex.w"
+
+if(cur_line+1!=best_line)
+{pen= inter_line_penalty;
+if(cur_line==prev_graf+1)pen= pen+club_penalty;
+if(cur_line+2==best_line)pen= pen+final_widow_penalty;
+if(disc_break)pen= pen+broken_penalty;
+if(pen!=0)
+{r= new_penalty(pen);
+link(tail)= r;tail= r;
+}
+}
+
+/*:890*/
+#line 17356 "tex.w"
+
+
+/*:880*/
+#line 17295 "tex.w"
+;
+incr(cur_line);cur_p= next_break(cur_p);
+if(cur_p!=null)if(!post_disc_break)
+/*879:*/
+#line 17324 "tex.w"
+
+{r= temp_head;
+loop{q= link(r);
+if(q==cur_break(cur_p))goto done1;
+
+
+if(is_char_node(q))goto done1;
+if(non_discardable(q))goto done1;
+if(type(q)==kern_node)if(subtype(q)!=explicit)goto done1;
+r= q;
+}
+done1:if(r!=temp_head)
+{link(r)= null;flush_node_list(link(temp_head));
+link(temp_head)= q;
+}
+}
+
+/*:879*/
+#line 17298 "tex.w"
+;
+}while(!(cur_p==null));
+if((cur_line!=best_line)||(link(temp_head)!=null))
+confusion(/*1682:*/
+#line 25942 "tex.w"
+557
+/*:1682*/
+#line 17301 "tex.w"
+);
+
+prev_graf= best_line-1;
+}
+
+/*:877*//*895:*/
+#line 17576 "tex.w"
+
+/*906:*/
+#line 17804 "tex.w"
+
+
+small_number reconstitute(small_number j,small_number n,halfword bchar,halfword hchar)
+{
+pointer p;
+pointer t;
+four_quarters q;
+halfword cur_rh;
+halfword test_char;
+scaled w;
+font_index k;
+hyphen_passed= 0;t= hold_head;w= 0;link(hold_head)= null;
+
+/*908:*/
+#line 17856 "tex.w"
+
+cur_l= qi(hu[j]);cur_q= t;
+if(j==0)
+{ligature_present= init_lig;p= init_list;
+if(ligature_present)lft_hit= init_lft;
+while(p> null)
+{append_charnode_to_t(character(p));p= link(p);
+}
+}
+else if(cur_l<non_char)append_charnode_to_t(cur_l);
+lig_stack= null;set_cur_r
+
+/*:908*/
+#line 17817 "tex.w"
+;
+resume:/*909:*/
+#line 17872 "tex.w"
+
+if(cur_l==non_char)
+{k= bchar_label[hf];
+if(k==non_address)goto done;else q= font_info[k].qqqq;
+}
+else{q= char_info(hf)(cur_l);
+if(char_tag(q)!=lig_tag)goto done;
+k= lig_kern_start(hf)(q);q= font_info[k].qqqq;
+if(skip_byte(q)> stop_flag)
+{k= lig_kern_restart(hf)(q);q= font_info[k].qqqq;
+}
+}
+if(cur_rh<non_char)test_char= cur_rh;else test_char= cur_r;
+loop{if(next_char(q)==test_char)if(skip_byte(q)<=stop_flag)
+if(cur_rh<non_char)
+{hyphen_passed= j;hchar= non_char;cur_rh= non_char;
+goto resume;
+}
+else{if(hchar<non_char)if(odd(hyf[j]))
+{hyphen_passed= j;hchar= non_char;
+}
+if(op_byte(q)<kern_flag)
+/*911:*/
+#line 17934 "tex.w"
+
+{if(cur_l==non_char)lft_hit= true;
+if(j==n)if(lig_stack==null)rt_hit= true;
+check_interrupt;
+switch(op_byte(q)){
+qi(case 1):qi(case 5):{cur_l= rem_byte(q);
+ligature_present= true;
+}break;
+qi(case 2):qi(case 6):{cur_r= rem_byte(q);
+if(lig_stack> null)character(lig_stack)= cur_r;
+else{lig_stack= new_lig_item(cur_r);
+if(j==n)bchar= non_char;
+else{p= get_avail();lig_ptr(lig_stack)= p;
+character(p)= qi(hu[j+1]);font(p)= hf;
+}
+}
+}break;
+qi(case 3):{cur_r= rem_byte(q);
+p= lig_stack;lig_stack= new_lig_item(cur_r);link(lig_stack)= p;
+}break;
+qi(case 7):qi(case 11):{wrap_lig(false);
+cur_q= t;cur_l= rem_byte(q);ligature_present= true;
+}break;
+default:{cur_l= rem_byte(q);ligature_present= true;
+if(lig_stack> null)pop_lig_stack
+else if(j==n)goto done;
+else{append_charnode_to_t(cur_r);incr(j);set_cur_r;
+}
+}
+}
+if(op_byte(q)> qi(4))if(op_byte(q)!=qi(7))goto done;
+goto resume;
+}
+
+/*:911*/
+#line 17895 "tex.w"
+;
+w= char_kern(hf)(q);goto done;
+}
+if(skip_byte(q)>=stop_flag)
+if(cur_rh==non_char)goto done;
+else{cur_rh= non_char;goto resume;
+}
+k= k+qo(skip_byte(q))+1;q= font_info[k].qqqq;
+}
+done:
+
+/*:909*/
+#line 17819 "tex.w"
+;
+/*910:*/
+#line 17924 "tex.w"
+
+wrap_lig(rt_hit);
+if(w!=0)
+{link(t)= new_kern(w);t= link(t);w= 0;
+}
+if(lig_stack> null)
+{cur_q= t;cur_l= character(lig_stack);ligature_present= true;
+pop_lig_stack;goto resume;
+}
+
+/*:910*/
+#line 17821 "tex.w"
+;
+return j;
+}
+
+/*:906*/
+#line 17577 "tex.w"
+
+void hyphenate(void)
+{
+/*901:*/
+#line 17683 "tex.w"
+
+int i,j,l;
+pointer q,r,s;
+halfword bchar;
+
+/*:901*//*912:*/
+#line 17977 "tex.w"
+
+pointer major_tail,minor_tail;
+
+ASCII_code c;
+uint8_t c_loc;
+int r_count;
+pointer hyf_node;
+
+/*:912*//*922:*/
+#line 18152 "tex.w"
+
+trie_pointer z;
+int v;
+
+/*:922*//*929:*/
+#line 18224 "tex.w"
+
+hyph_pointer h;
+str_number k;
+pool_pointer u;
+
+/*:929*/
+#line 17580 "tex.w"
+
+/*923:*/
+#line 18161 "tex.w"
+
+for(j= 0;j<=hn;j++)hyf[j]= 0;
+/*930:*/
+#line 18233 "tex.w"
+
+h= hc[1];incr(hn);hc[hn]= cur_lang;
+for(j= 2;j<=hn;j++)h= (h+h+hc[j])%hyph_size;
+loop{/*931:*/
+#line 18242 "tex.w"
+
+k= hyph_word[h];if(k==0)goto not_found;
+if(length(k)<hn)goto not_found;
+if(length(k)==hn)
+{j= 1;u= str_start[k];
+do{if(so(str_pool[u])<hc[j])goto not_found;
+if(so(str_pool[u])> hc[j])goto done;
+incr(j);incr(u);
+}while(!(j> hn));
+/*932:*/
+#line 18256 "tex.w"
+
+s= hyph_list[h];
+while(s!=null)
+{hyf[info(s)]= 1;s= link(s);
+}
+
+/*:932*/
+#line 18251 "tex.w"
+;
+decr(hn);goto found;
+}
+done:
+
+/*:931*/
+#line 18237 "tex.w"
+;
+if(h> 0)decr(h);else h= hyph_size;
+}
+not_found:decr(hn)
+
+/*:930*/
+#line 18164 "tex.w"
+;
+if(trie_char(cur_lang+1)!=qi(cur_lang))return;
+hc[0]= 0;hc[hn+1]= 0;hc[hn+2]= 256;
+for(j= 0;j<=hn-r_hyf+1;j++)
+{z= trie_link(cur_lang+1)+hc[j];l= j;
+while(hc[l]==qo(trie_char(z)))
+{if(trie_op(z)!=min_quarterword)
+/*924:*/
+#line 18178 "tex.w"
+
+{v= trie_op(z);
+do{v= v+op_start[cur_lang];i= l-hyf_distance[v];
+if(hyf_num[v]> hyf[i])hyf[i]= hyf_num[v];
+v= hyf_next[v];
+}while(!(v==min_quarterword));
+}
+
+/*:924*/
+#line 18171 "tex.w"
+;
+incr(l);z= trie_link(z)+hc[l];
+}
+}
+found:for(j= 0;j<=l_hyf-1;j++)hyf[j]= 0;
+for(j= 0;j<=r_hyf-1;j++)hyf[hn-j]= 0
+
+/*:923*/
+#line 17581 "tex.w"
+;
+/*902:*/
+#line 17695 "tex.w"
+
+for(j= l_hyf;j<=hn-r_hyf;j++)if(odd(hyf[j]))goto found1;
+return;
+found1:
+
+/*:902*/
+#line 17582 "tex.w"
+;
+/*903:*/
+#line 17711 "tex.w"
+
+q= link(hb);link(hb)= null;r= link(ha);link(ha)= null;bchar= hyf_bchar;
+if(is_char_node(ha))
+if(font(ha)!=hf)goto found2;
+else{init_list= ha;init_lig= false;hu[0]= qo(character(ha));
+}
+else if(type(ha)==ligature_node)
+if(font(lig_char(ha))!=hf)goto found2;
+else{init_list= lig_ptr(ha);init_lig= true;init_lft= (subtype(ha)> 1);
+hu[0]= qo(character(lig_char(ha)));
+if(init_list==null)if(init_lft)
+{hu[0]= 256;init_lig= false;
+}
+free_node(ha,small_node_size);
+}
+else{
+if(!is_char_node(r))if(type(r)==ligature_node)
+if(subtype(r)> 1)goto found2;
+j= 1;s= ha;init_list= null;goto common_ending;
+}
+s= cur_p;
+while(link(s)!=ha)s= link(s);
+j= 0;goto common_ending;
+found2:s= ha;j= 0;hu[0]= 256;init_lig= false;init_list= null;
+common_ending:flush_node_list(r);
+/*913:*/
+#line 17987 "tex.w"
+
+do{l= j;j= reconstitute(j,hn,bchar,qi(hyf_char))+1;
+if(hyphen_passed==0)
+{link(s)= link(hold_head);
+while(link(s)> null)s= link(s);
+if(odd(hyf[j-1]))
+{l= j;hyphen_passed= j-1;link(hold_head)= null;
+}
+}
+if(hyphen_passed> 0)
+/*914:*/
+#line 18012 "tex.w"
+
+do{r= get_node(small_node_size);
+link(r)= link(hold_head);type(r)= disc_node;
+major_tail= r;r_count= 0;
+while(link(major_tail)> null)advance_major_tail;
+i= hyphen_passed;hyf[i]= 0;
+/*915:*/
+#line 18028 "tex.w"
+
+minor_tail= null;pre_break(r)= null;hyf_node= new_character(hf,hyf_char);
+if(hyf_node!=null)
+{incr(i);c= hu[i];hu[i]= hyf_char;free_avail(hyf_node);
+}
+while(l<=i)
+{l= reconstitute(l,i,font_bchar[hf],non_char)+1;
+if(link(hold_head)> null)
+{if(minor_tail==null)pre_break(r)= link(hold_head);
+else link(minor_tail)= link(hold_head);
+minor_tail= link(hold_head);
+while(link(minor_tail)> null)minor_tail= link(minor_tail);
+}
+}
+if(hyf_node!=null)
+{hu[i]= c;
+l= i;decr(i);
+}
+
+/*:915*/
+#line 18018 "tex.w"
+;
+/*916:*/
+#line 18049 "tex.w"
+
+minor_tail= null;post_break(r)= null;c_loc= 0;
+if(bchar_label[hf]!=non_address)
+{decr(l);c= hu[l];c_loc= l;hu[l]= 256;
+}
+while(l<j)
+{do{l= reconstitute(l,hn,bchar,non_char)+1;
+if(c_loc> 0)
+{hu[c_loc]= c;c_loc= 0;
+}
+if(link(hold_head)> null)
+{if(minor_tail==null)post_break(r)= link(hold_head);
+else link(minor_tail)= link(hold_head);
+minor_tail= link(hold_head);
+while(link(minor_tail)> null)minor_tail= link(minor_tail);
+}
+}while(!(l>=j));
+while(l> j)
+/*917:*/
+#line 18070 "tex.w"
+
+{j= reconstitute(j,hn,bchar,non_char)+1;
+link(major_tail)= link(hold_head);
+while(link(major_tail)> null)advance_major_tail;
+}
+
+/*:917*/
+#line 18067 "tex.w"
+;
+}
+
+/*:916*/
+#line 18020 "tex.w"
+;
+/*918:*/
+#line 18080 "tex.w"
+
+if(r_count> 127)
+{link(s)= link(r);link(r)= null;flush_node_list(r);
+}
+else{link(s)= r;replace_count(r)= r_count;
+}
+s= major_tail
+
+/*:918*/
+#line 18021 "tex.w"
+;
+hyphen_passed= j-1;link(hold_head)= null;
+}while(!(!odd(hyf[j-1])))
+
+/*:914*/
+#line 17998 "tex.w"
+;
+}while(!(j> hn));
+link(s)= q
+
+/*:913*/
+#line 17736 "tex.w"
+;
+flush_list(init_list)
+
+/*:903*/
+#line 17583 "tex.w"
+;
+}
+
+/*:895*//*942:*/
+#line 18389 "tex.w"
+
+#ifdef INIT
+/*944:*/
+#line 18436 "tex.w"
+
+quarterword new_trie_op(small_number d,small_number n,quarterword v)
+{
+int16_t h;
+quarterword u;
+uint16_t l;
+h= abs(n+313*d+361*v+1009*cur_lang)%(trie_op_size+trie_op_size)
+-trie_op_size;
+loop{l= trie_op_hash[h];
+if(l==0)
+{if(trie_op_ptr==trie_op_size)
+overflow("pattern memory ops",trie_op_size);
+u= trie_used[cur_lang];
+if(u==max_quarterword)
+overflow("pattern memory ops per language",
+max_quarterword-min_quarterword);
+incr(trie_op_ptr);incr(u);trie_used[cur_lang]= u;
+hyf_distance[trie_op_ptr]= d;
+hyf_num[trie_op_ptr]= n;hyf_next[trie_op_ptr]= v;
+trie_op_lang[trie_op_ptr]= cur_lang;trie_op_hash[h]= trie_op_ptr;
+trie_op_val[trie_op_ptr]= u;return u;
+}
+if((hyf_distance[l]==d)&&(hyf_num[l]==n)&&(hyf_next[l]==v)
+&&(trie_op_lang[l]==cur_lang))
+{return trie_op_val[l];
+}
+if(h> -trie_op_size)decr(h);else h= trie_op_size;
+}
+}
+
+/*:944*//*948:*/
+#line 18538 "tex.w"
+
+trie_pointer trie_node(trie_pointer p)
+
+{
+trie_pointer h;
+trie_pointer q;
+h= abs(trie_c[p]+1009*trie_o[p]+
+2718*trie_l[p]+3142*trie_r[p])%trie_size;
+loop{q= trie_hash[h];
+if(q==0)
+{trie_hash[h]= p;return p;
+}
+if((trie_c[q]==trie_c[p])&&(trie_o[q]==trie_o[p])&&
+(trie_l[q]==trie_l[p])&&(trie_r[q]==trie_r[p]))
+{return q;
+}
+if(h> 0)decr(h);else h= trie_size;
+}
+}
+
+/*:948*//*949:*/
+#line 18564 "tex.w"
+
+trie_pointer compress_trie(trie_pointer p)
+{if(p==0)return 0;
+else{trie_l[p]= compress_trie(trie_l[p]);
+trie_r[p]= compress_trie(trie_r[p]);
+return trie_node(p);
+}
+}
+
+/*:949*//*953:*/
+#line 18635 "tex.w"
+
+void first_fit(trie_pointer p)
+{
+trie_pointer h;
+trie_pointer z;
+trie_pointer q;
+ASCII_code c;
+trie_pointer l,r;
+uint16_t ll;
+c= so(trie_c[p]);
+z= trie_min[c];
+loop{h= z-c;
+/*954:*/
+#line 18660 "tex.w"
+
+if(trie_max<h+256)
+{if(trie_size<=h+256)overflow("pattern memory",trie_size);
+
+do{incr(trie_max);trie_taken[trie_max]= false;
+trie_link(trie_max)= trie_max+1;trie_back(trie_max)= trie_max-1;
+}while(!(trie_max==h+256));
+}
+
+/*:954*/
+#line 18647 "tex.w"
+;
+if(trie_taken[h])goto not_found;
+/*955:*/
+#line 18669 "tex.w"
+
+q= trie_r[p];
+while(q> 0)
+{if(trie_link(h+so(trie_c[q]))==0)goto not_found;
+q= trie_r[q];
+}
+goto found
+
+/*:955*/
+#line 18650 "tex.w"
+;
+not_found:z= trie_link(z);
+}
+found:/*956:*/
+#line 18677 "tex.w"
+
+trie_taken[h]= true;trie_ref[p]= h;q= p;
+do{z= h+so(trie_c[q]);l= trie_back(z);r= trie_link(z);
+trie_back(r)= l;trie_link(l)= r;trie_link(z)= 0;
+if(l<256)
+{if(z<256)ll= z;else ll= 256;
+do{trie_min[l]= r;incr(l);
+}while(!(l==ll));
+}
+q= trie_r[q];
+}while(!(q==0))
+
+/*:956*/
+#line 18653 "tex.w"
+;
+}
+
+/*:953*//*957:*/
+#line 18692 "tex.w"
+
+void trie_pack(trie_pointer p)
+{trie_pointer q;
+do{q= trie_l[p];
+if((q> 0)&&(trie_ref[q]==0))
+{first_fit(q);trie_pack(q);
+}
+p= trie_r[p];
+}while(!(p==0));
+}
+
+/*:957*//*959:*/
+#line 18728 "tex.w"
+
+void trie_fix(trie_pointer p)
+{trie_pointer q;
+ASCII_code c;
+trie_pointer z;
+z= trie_ref[p];
+do{q= trie_l[p];c= so(trie_c[p]);
+trie_link(z+c)= trie_ref[q];trie_char(z+c)= qi(c);trie_op(z+c)= trie_o[p];
+if(q> 0)trie_fix(q);
+p= trie_r[p];
+}while(!(p==0));
+}
+
+/*:959*//*960:*/
+#line 18745 "tex.w"
+
+void new_patterns(void)
+{
+uint8_t k,l;
+
+bool digit_sensed;
+quarterword v;
+trie_pointer p,q;
+bool first_child;
+ASCII_code c;
+if(trie_not_ready)
+{set_cur_lang;scan_left_brace();
+/*961:*/
+#line 18769 "tex.w"
+
+k= 0;hyf[0]= 0;digit_sensed= false;
+loop{get_x_token();
+switch(cur_cmd){
+case letter:case other_char:/*962:*/
+#line 18787 "tex.w"
+
+if(digit_sensed||(cur_chr<'0')||(cur_chr> '9'))
+{if(cur_chr=='.')cur_chr= 0;
+else{cur_chr= lc_code(cur_chr);
+if(cur_chr==0)
+{print_err("Nonletter");
+
+help1("(See Appendix H.)");error();
+}
+}
+if(k<63)
+{incr(k);hc[k]= cur_chr;hyf[k]= 0;digit_sensed= false;
+}
+}
+else if(k<63)
+{hyf[k]= cur_chr-'0';digit_sensed= true;
+}
+
+/*:962*/
+#line 18773 "tex.w"
+break;
+case spacer:case right_brace:{if(k> 0)
+/*963:*/
+#line 18809 "tex.w"
+
+{/*965:*/
+#line 18837 "tex.w"
+
+if(hc[1]==0)hyf[0]= 0;
+if(hc[k]==0)hyf[k]= 0;
+l= k;v= min_quarterword;
+loop{if(hyf[l]!=0)v= new_trie_op(k-l,hyf[l],v);
+if(l> 0)decr(l);else goto done1;
+}
+done1:
+
+/*:965*/
+#line 18810 "tex.w"
+;
+q= 0;hc[0]= cur_lang;
+while(l<=k)
+{c= hc[l];incr(l);p= trie_l[q];first_child= true;
+while((p> 0)&&(c> so(trie_c[p])))
+{q= p;p= trie_r[q];first_child= false;
+}
+if((p==0)||(c<so(trie_c[p])))
+/*964:*/
+#line 18829 "tex.w"
+
+{if(trie_ptr==trie_size)overflow("pattern memory",trie_size);
+
+incr(trie_ptr);trie_r[trie_ptr]= p;p= trie_ptr;trie_l[p]= 0;
+if(first_child)trie_l[q]= p;else trie_r[q]= p;
+trie_c[p]= si(c);trie_o[p]= min_quarterword;
+}
+
+/*:964*/
+#line 18818 "tex.w"
+;
+q= p;
+}
+if(trie_o[q]!=min_quarterword)
+{print_err("Duplicate pattern");
+
+help1("(See Appendix H.)");error();
+}
+trie_o[q]= v;
+}
+
+/*:963*/
+#line 18775 "tex.w"
+;
+if(cur_cmd==right_brace)goto done;
+k= 0;hyf[0]= 0;digit_sensed= false;
+}break;
+default:{print_err("Bad ");print_esc(/*1684:*/
+#line 25948 "tex.w"
+559
+/*:1684*/
+#line 18779 "tex.w"
+);
+
+help1("(See Appendix H.)");error();
+}
+}
+}
+done:
+
+/*:961*/
+#line 18757 "tex.w"
+;
+}
+else{print_err("Too late for ");print_esc(/*1684:*/
+#line 25948 "tex.w"
+559
+/*:1684*/
+#line 18759 "tex.w"
+);
+help1("All patterns must be given before typesetting begins.");
+error();link(garbage)= scan_toks(false,false);flush_list(def_ref);
+}
+}
+
+/*:960*//*966:*/
+#line 18853 "tex.w"
+
+void init_trie(void)
+{trie_pointer p;
+int j,k,t;
+trie_pointer r,s;
+two_halves h;
+/*952:*/
+#line 18620 "tex.w"
+
+/*945:*/
+#line 18470 "tex.w"
+
+op_start[0]= -min_quarterword;
+for(j= 1;j<=255;j++)op_start[j]= op_start[j-1]+qo(trie_used[j-1]);
+for(j= 1;j<=trie_op_ptr;j++)
+trie_op_hash[j]= op_start[trie_op_lang[j]]+trie_op_val[j];
+for(j= 1;j<=trie_op_ptr;j++)while(trie_op_hash[j]> j)
+{k= trie_op_hash[j];
+t= hyf_distance[k];hyf_distance[k]= hyf_distance[j];hyf_distance[j]= t;
+t= hyf_num[k];hyf_num[k]= hyf_num[j];hyf_num[j]= t;
+t= hyf_next[k];hyf_next[k]= hyf_next[j];hyf_next[j]= t;
+trie_op_hash[j]= trie_op_hash[k];trie_op_hash[k]= k;
+}
+
+/*:945*/
+#line 18621 "tex.w"
+;
+for(p= 0;p<=trie_size;p++)trie_hash[p]= 0;
+trie_root= compress_trie(trie_root);
+for(p= 0;p<=trie_ptr;p++)trie_ref[p]= 0;
+for(p= 0;p<=255;p++)trie_min[p]= p+1;
+trie_link(0)= 1;trie_max= 0
+
+/*:952*/
+#line 18859 "tex.w"
+;
+if(trie_root!=0)
+{first_fit(trie_root);trie_pack(trie_root);
+}
+/*958:*/
+#line 18708 "tex.w"
+
+h.rh= 0;h.b0= min_quarterword;h.b1= min_quarterword;
+
+if(trie_root==0)
+{for(r= 0;r<=256;r++)trie[r]= h;
+trie_max= 256;
+}
+else{trie_fix(trie_root);
+r= 0;
+do{s= trie_link(r);trie[r]= h;r= s;
+}while(!(r> trie_max));
+}
+trie_char(0)= qi('?');
+
+/*:958*/
+#line 18863 "tex.w"
+;
+trie_not_ready= false;
+}
+
+/*:966*/
+#line 18391 "tex.w"
+
+#endif
+
+/*:942*/
+#line 16057 "tex.w"
+
+void line_break(int final_widow_penalty)
+{
+/*862:*/
+#line 16984 "tex.w"
+
+bool auto_breaking;
+pointer prev_p;
+pointer q,r,s,prev_s;
+internal_font_number f;
+
+/*:862*//*893:*/
+#line 17557 "tex.w"
+
+small_number j;
+uint8_t c;
+
+/*:893*/
+#line 16060 "tex.w"
+
+pack_begin_line= mode_line;
+/*816:*/
+#line 16081 "tex.w"
+
+link(temp_head)= link(head);
+if(is_char_node(tail))tail_append(new_penalty(inf_penalty))
+else if(type(tail)!=glue_node)tail_append(new_penalty(inf_penalty))
+else{type(tail)= penalty_node;delete_glue_ref(glue_ptr(tail));
+flush_node_list(leader_ptr(tail));penalty(tail)= inf_penalty;
+}
+link(tail)= new_param_glue(par_fill_skip_code);
+init_cur_lang= prev_graf%0200000;
+init_l_hyf= prev_graf/020000000;
+init_r_hyf= (prev_graf/0200000)%0100;
+pop_nest();
+
+/*:816*//*827:*/
+#line 16309 "tex.w"
+
+no_shrink_error_yet= true;
+check_shrinkage(left_skip);check_shrinkage(right_skip);
+q= left_skip;r= right_skip;background[1]= width(q)+width(r);
+background[2]= 0;background[3]= 0;background[4]= 0;background[5]= 0;
+background[2+stretch_order(q)]= stretch(q);
+background[2+stretch_order(r)]= background[2+stretch_order(r)]+stretch(r);
+background[6]= shrink(q)+shrink(r);
+
+/*:827*//*834:*/
+#line 16451 "tex.w"
+
+minimum_demerits= awful_bad;
+minimal_demerits[tight_fit]= awful_bad;
+minimal_demerits[decent_fit]= awful_bad;
+minimal_demerits[loose_fit]= awful_bad;
+minimal_demerits[very_loose_fit]= awful_bad;
+
+/*:834*//*848:*/
+#line 16712 "tex.w"
+
+if(par_shape_ptr==null)
+if(hang_indent==0)
+{last_special_line= 0;second_width= hsize;
+second_indent= 0;
+}
+else/*849:*/
+#line 16726 "tex.w"
+
+{last_special_line= abs(hang_after);
+if(hang_after<0)
+{first_width= hsize-abs(hang_indent);
+if(hang_indent>=0)first_indent= hang_indent;
+else first_indent= 0;
+second_width= hsize;second_indent= 0;
+}
+else{first_width= hsize;first_indent= 0;
+second_width= hsize-abs(hang_indent);
+if(hang_indent>=0)second_indent= hang_indent;
+else second_indent= 0;
+}
+}
+
+/*:849*/
+#line 16718 "tex.w"
+
+else{last_special_line= info(par_shape_ptr)-1;
+second_width= mem[par_shape_ptr+2*(last_special_line+1)].sc;
+second_indent= mem[par_shape_ptr+2*last_special_line+1].sc;
+}
+if(looseness==0)easy_line= last_special_line;
+else easy_line= max_halfword
+
+/*:848*/
+#line 16062 "tex.w"
+;
+/*863:*/
+#line 16994 "tex.w"
+
+threshold= pretolerance;
+if(threshold>=0)
+{
+#ifdef STAT
+if(tracing_paragraphs> 0)
+{begin_diagnostic();print_nl("@firstpass");}
+#endif
+
+second_pass= false;final_pass= false;
+}
+else{threshold= tolerance;second_pass= true;
+final_pass= (emergency_stretch<=0);
+
+#ifdef STAT
+if(tracing_paragraphs> 0)begin_diagnostic();
+#endif
+
+}
+loop{if(threshold> inf_bad)threshold= inf_bad;
+if(second_pass)/*891:*/
+#line 17530 "tex.w"
+
+{
+#ifdef INIT
+if(trie_not_ready)init_trie();
+#endif
+
+cur_lang= init_cur_lang;l_hyf= init_l_hyf;r_hyf= init_r_hyf;
+}
+
+/*:891*/
+#line 17014 "tex.w"
+;
+/*864:*/
+#line 17053 "tex.w"
+
+q= get_node(active_node_size);
+type(q)= unhyphenated;fitness(q)= decent_fit;
+link(q)= last_active;break_node(q)= null;
+line_number(q)= prev_graf+1;total_demerits(q)= 0;link(active)= q;
+do_all_six(store_background);
+passive= null;printed_node= temp_head;pass_number= 0;
+font_in_short_display= null_font
+
+/*:864*/
+#line 17015 "tex.w"
+;
+cur_p= link(temp_head);auto_breaking= true;
+prev_p= cur_p;
+while((cur_p!=null)&&(link(active)!=last_active))
+/*866:*/
+#line 17089 "tex.w"
+
+{if(is_char_node(cur_p))
+/*867:*/
+#line 17123 "tex.w"
+
+{prev_p= cur_p;
+do{f= font(cur_p);
+act_width= act_width+char_width(f)(char_info(f)(character(cur_p)));
+cur_p= link(cur_p);
+}while(!(!is_char_node(cur_p)));
+}
+
+/*:867*/
+#line 17091 "tex.w"
+;
+switch(type(cur_p)){
+case hlist_node:case vlist_node:case rule_node:act_width= act_width+width(cur_p);break;
+case whatsit_node:/*1362:*/
+#line 24802 "tex.w"
+
+adv_past(cur_p)
+
+/*:1362*/
+#line 17094 "tex.w"
+break;
+case glue_node:{/*868:*/
+#line 17134 "tex.w"
+
+if(auto_breaking)
+{if(is_char_node(prev_p))try_break(0,unhyphenated);
+else if(precedes_break(prev_p))try_break(0,unhyphenated);
+else if((type(prev_p)==kern_node)&&(subtype(prev_p)!=explicit))
+try_break(0,unhyphenated);
+}
+check_shrinkage(glue_ptr(cur_p));q= glue_ptr(cur_p);
+act_width= act_width+width(q);
+active_width[2+stretch_order(q)]=
+active_width[2+stretch_order(q)]+stretch(q);
+active_width[6]= active_width[6]+shrink(q)
+
+/*:868*/
+#line 17096 "tex.w"
+;
+if(second_pass&&auto_breaking)
+/*894:*/
+#line 17564 "tex.w"
+
+{prev_s= cur_p;s= link(prev_s);
+if(s!=null)
+{/*896:*/
+#line 17589 "tex.w"
+
+loop{if(is_char_node(s))
+{c= qo(character(s));hf= font(s);
+}
+else if(type(s)==ligature_node)
+if(lig_ptr(s)==null)goto resume;
+else{q= lig_ptr(s);c= qo(character(q));hf= font(q);
+}
+else if((type(s)==kern_node)&&(subtype(s)==normal))goto resume;
+else if(type(s)==whatsit_node)
+{/*1363:*/
+#line 24805 "tex.w"
+
+adv_past(s)
+
+/*:1363*/
+#line 17599 "tex.w"
+;
+goto resume;
+}
+else goto done1;
+if(lc_code(c)!=0)
+if((lc_code(c)==c)||(uc_hyph> 0))goto done2;
+else goto done1;
+resume:prev_s= s;s= link(prev_s);
+}
+done2:hyf_char= hyphen_char[hf];
+if(hyf_char<0)goto done1;
+if(hyf_char> 255)goto done1;
+ha= prev_s
+
+/*:896*/
+#line 17567 "tex.w"
+;
+if(l_hyf+r_hyf> 63)goto done1;
+/*897:*/
+#line 17615 "tex.w"
+
+hn= 0;
+loop{if(is_char_node(s))
+{if(font(s)!=hf)goto done3;
+hyf_bchar= character(s);c= qo(hyf_bchar);
+if(lc_code(c)==0)goto done3;
+if(hn==63)goto done3;
+hb= s;incr(hn);hu[hn]= c;hc[hn]= lc_code(c);hyf_bchar= non_char;
+}
+else if(type(s)==ligature_node)
+/*898:*/
+#line 17641 "tex.w"
+
+{if(font(lig_char(s))!=hf)goto done3;
+j= hn;q= lig_ptr(s);if(q> null)hyf_bchar= character(q);
+while(q> null)
+{c= qo(character(q));
+if(lc_code(c)==0)goto done3;
+if(j==63)goto done3;
+incr(j);hu[j]= c;hc[j]= lc_code(c);
+q= link(q);
+}
+hb= s;hn= j;
+if(odd(subtype(s)))hyf_bchar= font_bchar[hf];else hyf_bchar= non_char;
+}
+
+/*:898*/
+#line 17626 "tex.w"
+
+else if((type(s)==kern_node)&&(subtype(s)==normal))
+{hb= s;
+hyf_bchar= font_bchar[hf];
+}
+else goto done3;
+s= link(s);
+}
+done3:
+
+/*:897*/
+#line 17569 "tex.w"
+;
+/*899:*/
+#line 17655 "tex.w"
+
+if(hn<l_hyf+r_hyf)goto done1;
+loop{if(!(is_char_node(s)))
+switch(type(s)){
+case ligature_node:do_nothing;break;
+case kern_node:if(subtype(s)!=normal)goto done4;break;
+case whatsit_node:case glue_node:case penalty_node:case ins_node:case adjust_node:case mark_node:
+goto done4;
+default:goto done1;
+}
+s= link(s);
+}
+done4:
+
+/*:899*/
+#line 17571 "tex.w"
+;
+hyphenate();
+}
+done1:;}
+
+/*:894*/
+#line 17098 "tex.w"
+;
+}break;
+case kern_node:if(subtype(cur_p)==explicit)kern_break
+else act_width= act_width+width(cur_p);break;
+case ligature_node:{f= font(lig_char(cur_p));
+act_width= act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
+}break;
+case disc_node:/*869:*/
+#line 17150 "tex.w"
+
+{s= pre_break(cur_p);disc_width= 0;
+if(s==null)try_break(ex_hyphen_penalty,hyphenated);
+else{do{/*870:*/
+#line 17168 "tex.w"
+
+if(is_char_node(s))
+{f= font(s);
+disc_width= disc_width+char_width(f)(char_info(f)(character(s)));
+}
+else switch(type(s)){
+case ligature_node:{f= font(lig_char(s));
+disc_width= disc_width+
+char_width(f)(char_info(f)(character(lig_char(s))));
+}break;
+case hlist_node:case vlist_node:case rule_node:case kern_node:
+disc_width= disc_width+width(s);break;
+default:confusion(/*1680:*/
+#line 25936 "tex.w"
+555
+/*:1680*/
+#line 17180 "tex.w"
+);
+
+}
+
+/*:870*/
+#line 17153 "tex.w"
+;
+s= link(s);
+}while(!(s==null));
+act_width= act_width+disc_width;
+try_break(hyphen_penalty,hyphenated);
+act_width= act_width-disc_width;
+}
+r= replace_count(cur_p);s= link(cur_p);
+while(r> 0)
+{/*871:*/
+#line 17184 "tex.w"
+
+if(is_char_node(s))
+{f= font(s);
+act_width= act_width+char_width(f)(char_info(f)(character(s)));
+}
+else switch(type(s)){
+case ligature_node:{f= font(lig_char(s));
+act_width= act_width+
+char_width(f)(char_info(f)(character(lig_char(s))));
+}break;
+case hlist_node:case vlist_node:case rule_node:case kern_node:
+act_width= act_width+width(s);break;
+default:confusion(/*1681:*/
+#line 25939 "tex.w"
+556
+/*:1681*/
+#line 17196 "tex.w"
+);
+
+}
+
+/*:871*/
+#line 17162 "tex.w"
+;
+decr(r);s= link(s);
+}
+prev_p= cur_p;cur_p= s;goto done5;
+}
+
+/*:869*/
+#line 17105 "tex.w"
+
+case math_node:{auto_breaking= (subtype(cur_p)==after);kern_break;
+}break;
+case penalty_node:try_break(penalty(cur_p),unhyphenated);break;
+case mark_node:case ins_node:case adjust_node:do_nothing;break;
+default:confusion(/*1679:*/
+#line 25933 "tex.w"
+554
+/*:1679*/
+#line 17110 "tex.w"
+);
+
+}
+prev_p= cur_p;cur_p= link(cur_p);
+done5:;}
+
+/*:866*/
+#line 17021 "tex.w"
+;
+if(cur_p==null)
+/*873:*/
+#line 17219 "tex.w"
+
+{try_break(eject_penalty,hyphenated);
+if(link(active)!=last_active)
+{/*874:*/
+#line 17229 "tex.w"
+
+r= link(active);fewest_demerits= awful_bad;
+do{if(type(r)!=delta_node)if(total_demerits(r)<fewest_demerits)
+{fewest_demerits= total_demerits(r);best_bet= r;
+}
+r= link(r);
+}while(!(r==last_active));
+best_line= line_number(best_bet)
+
+/*:874*/
+#line 17222 "tex.w"
+;
+if(looseness==0)goto done;
+/*875:*/
+#line 17243 "tex.w"
+
+{r= link(active);actual_looseness= 0;
+do{if(type(r)!=delta_node)
+{line_diff= line_number(r)-best_line;
+if(((line_diff<actual_looseness)&&(looseness<=line_diff))||
+((line_diff> actual_looseness)&&(looseness>=line_diff)))
+{best_bet= r;actual_looseness= line_diff;
+fewest_demerits= total_demerits(r);
+}
+else if((line_diff==actual_looseness)&&
+(total_demerits(r)<fewest_demerits))
+{best_bet= r;fewest_demerits= total_demerits(r);
+}
+}
+r= link(r);
+}while(!(r==last_active));
+best_line= line_number(best_bet);
+}
+
+/*:875*/
+#line 17224 "tex.w"
+;
+if((actual_looseness==looseness)||final_pass)goto done;
+}
+}
+
+/*:873*/
+#line 17024 "tex.w"
+;
+/*865:*/
+#line 17062 "tex.w"
+
+q= link(active);
+while(q!=last_active)
+{cur_p= link(q);
+if(type(q)==delta_node)free_node(q,delta_node_size);
+else free_node(q,active_node_size);
+q= cur_p;
+}
+q= passive;
+while(q!=null)
+{cur_p= link(q);
+free_node(q,passive_node_size);
+q= cur_p;
+}
+
+/*:865*/
+#line 17025 "tex.w"
+;
+if(!second_pass)
+{
+#ifdef STAT
+if(tracing_paragraphs> 0)print_nl("@secondpass");
+#endif
+threshold= tolerance;second_pass= true;final_pass= (emergency_stretch<=0);
+}
+else{
+#ifdef STAT
+if(tracing_paragraphs> 0)
+print_nl("@emergencypass");
+#endif
+background[2]= background[2]+emergency_stretch;final_pass= true;
+}
+}
+done:
+#ifdef STAT
+if(tracing_paragraphs> 0)
+{end_diagnostic(true);normalize_selector();
+}
+#endif
+
+/*:863*/
+#line 16063 "tex.w"
+;
+/*876:*/
+#line 17267 "tex.w"
+
+post_line_break(final_widow_penalty)
+
+/*:876*/
+#line 16065 "tex.w"
+;
+/*865:*/
+#line 17062 "tex.w"
+
+q= link(active);
+while(q!=last_active)
+{cur_p= link(q);
+if(type(q)==delta_node)free_node(q,delta_node_size);
+else free_node(q,active_node_size);
+q= cur_p;
+}
+q= passive;
+while(q!=null)
+{cur_p= link(q);
+free_node(q,passive_node_size);
+q= cur_p;
+}
+
+/*:865*/
+#line 16066 "tex.w"
+;
+pack_begin_line= 0;
+}
+
+/*:815*//*934:*/
+#line 18280 "tex.w"
+void new_hyph_exceptions(void)
+{
+uint8_t n;
+int j;
+hyph_pointer h;
+str_number k;
+pointer p;
+pointer q;
+str_number s,t;
+pool_pointer u,v;
+scan_left_brace();
+set_cur_lang;
+/*935:*/
+#line 18296 "tex.w"
+
+n= 0;p= null;
+loop{get_x_token();
+reswitch:switch(cur_cmd){
+case letter:case other_char:case char_given:/*937:*/
+#line 18321 "tex.w"
+
+if(cur_chr=='-')/*938:*/
+#line 18335 "tex.w"
+
+{if(n<63)
+{q= get_avail();link(q)= p;info(q)= n;p= q;
+}
+}
+
+/*:938*/
+#line 18322 "tex.w"
+
+else{if(lc_code(cur_chr)==0)
+{print_err("Not a letter");
+
+help2("Letters in \\hyphenation words must have \\lccode>0.")
+("Proceed; I'll ignore the character I just read.");
+error();
+}
+else if(n<63)
+{incr(n);hc[n]= lc_code(cur_chr);
+}
+}
+
+/*:937*/
+#line 18300 "tex.w"
+break;
+case char_num:{scan_char_num();cur_chr= cur_val;cur_cmd= char_given;
+goto reswitch;
+}
+case spacer:case right_brace:{if(n> 1)/*939:*/
+#line 18341 "tex.w"
+
+{incr(n);hc[n]= cur_lang;str_room(n);h= 0;
+for(j= 1;j<=n;j++)
+{h= (h+h+hc[j])%hyph_size;
+append_char(hc[j]);
+}
+s= make_string();
+/*940:*/
+#line 18351 "tex.w"
+
+if(hyph_count==hyph_size)overflow("exception dictionary",hyph_size);
+
+incr(hyph_count);
+while(hyph_word[h]!=0)
+{/*941:*/
+#line 18362 "tex.w"
+
+k= hyph_word[h];
+if(length(k)<length(s))goto found;
+if(length(k)> length(s))goto not_found;
+u= str_start[k];v= str_start[s];
+do{if(str_pool[u]<str_pool[v])goto found;
+if(str_pool[u]> str_pool[v])goto not_found;
+incr(u);incr(v);
+}while(!(u==str_start[k+1]));
+found:q= hyph_list[h];hyph_list[h]= p;p= q;
+t= hyph_word[h];hyph_word[h]= s;s= t;
+not_found:
+
+/*:941*/
+#line 18357 "tex.w"
+;
+if(h> 0)decr(h);else h= hyph_size;
+}
+hyph_word[h]= s;hyph_list[h]= p
+
+/*:940*/
+#line 18348 "tex.w"
+;
+}
+
+/*:939*/
+#line 18304 "tex.w"
+;
+if(cur_cmd==right_brace)return;
+n= 0;p= null;
+}break;
+default:/*936:*/
+#line 18312 "tex.w"
+
+{print_err("Improper ");print_esc(/*1683:*/
+#line 25945 "tex.w"
+558
+/*:1683*/
+#line 18313 "tex.w"
+);
+
+print_str(" will be flushed");
+help2("Hyphenation exceptions must contain only letters")
+("and hyphens. But continue; I'll forgive and forget.");
+error();
+}
+
+/*:936*/
+#line 18308 "tex.w"
+
+}
+}
+
+/*:935*/
+#line 18293 "tex.w"
+;
+}
+
+/*:934*//*968:*/
+#line 18886 "tex.w"
+pointer prune_page_top(pointer p)
+{pointer prev_p;
+pointer q;
+prev_p= temp_head;link(temp_head)= p;
+while(p!=null)
+switch(type(p)){
+case hlist_node:case vlist_node:case rule_node:/*969:*/
+#line 18905 "tex.w"
+
+{q= new_skip_param(split_top_skip_code);link(prev_p)= q;link(q)= p;
+
+if(width(temp_ptr)> height(p))width(temp_ptr)= width(temp_ptr)-height(p);
+else width(temp_ptr)= 0;
+p= null;
+}
+
+/*:969*/
+#line 18893 "tex.w"
+break;
+case whatsit_node:case mark_node:case ins_node:{prev_p= p;p= link(prev_p);
+}break;
+case glue_node:case kern_node:case penalty_node:{q= p;p= link(q);link(q)= null;
+link(prev_p)= p;flush_node_list(q);
+}break;
+default:confusion(/*1685:*/
+#line 25951 "tex.w"
+560
+/*:1685*/
+#line 18899 "tex.w"
+);
+
+}
+return link(temp_head);
+}
+
+/*:968*//*970:*/
+#line 18929 "tex.w"
+pointer vert_break(pointer p,scaled h,scaled d)
+
+{
+pointer prev_p;
+
+pointer q,r;
+int pi;
+int b;
+int least_cost;
+pointer best_place;
+scaled prev_dp;
+small_number t;
+prev_p= p;
+least_cost= awful_bad;do_all_six(set_height_zero);prev_dp= 0;
+loop{/*972:*/
+#line 18963 "tex.w"
+
+if(p==null)pi= eject_penalty;
+else/*973:*/
+#line 18978 "tex.w"
+
+switch(type(p)){
+case hlist_node:case vlist_node:case rule_node:{
+cur_height= cur_height+prev_dp+height(p);prev_dp= depth(p);
+goto not_found;
+}
+case whatsit_node:/*1365:*/
+#line 24811 "tex.w"
+
+goto not_found
+
+/*:1365*/
+#line 18984 "tex.w"
+;
+case glue_node:if(precedes_break(prev_p))pi= 0;
+else goto update_heights;break;
+case kern_node:{if(link(p)==null)t= penalty_node;
+else t= type(link(p));
+if(t==glue_node)pi= 0;else goto update_heights;
+}break;
+case penalty_node:pi= penalty(p);break;
+case mark_node:case ins_node:goto not_found;
+default:confusion(/*1686:*/
+#line 25954 "tex.w"
+561
+/*:1686*/
+#line 18993 "tex.w"
+);
+
+}
+
+/*:973*/
+#line 18967 "tex.w"
+;
+/*974:*/
+#line 18999 "tex.w"
+
+if(pi<inf_penalty)
+{/*975:*/
+#line 19013 "tex.w"
+
+if(cur_height<h)
+if((active_height[3]!=0)||(active_height[4]!=0)||
+(active_height[5]!=0))b= 0;
+else b= badness(h-cur_height,active_height[2]);
+else if(cur_height-h> active_height[6])b= awful_bad;
+else b= badness(cur_height-h,active_height[6])
+
+/*:975*/
+#line 19001 "tex.w"
+;
+if(b<awful_bad)
+if(pi<=eject_penalty)b= pi;
+else if(b<inf_bad)b= b+pi;
+else b= deplorable;
+if(b<=least_cost)
+{best_place= p;least_cost= b;
+best_height_plus_depth= cur_height+prev_dp;
+}
+if((b==awful_bad)||(pi<=eject_penalty))goto done;
+}
+
+/*:974*/
+#line 18969 "tex.w"
+;
+if((type(p)<glue_node)||(type(p)> kern_node))goto not_found;
+update_heights:/*976:*/
+#line 19025 "tex.w"
+
+if(type(p)==kern_node)q= p;
+else{q= glue_ptr(p);
+active_height[2+stretch_order(q)]=
+active_height[2+stretch_order(q)]+stretch(q);
+active_height[6]= active_height[6]+shrink(q);
+if((shrink_order(q)!=normal)&&(shrink(q)!=0))
+{
+print_err("Infinite glue shrinkage found in box being split");
+
+help4("The box you are \\vsplitting contains some infinitely")
+("shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.")
+("Such glue doesn't belong there; but you can safely proceed,")
+("since the offensive shrinkability has been made finite.");
+error();r= new_spec(q);shrink_order(r)= normal;delete_glue_ref(q);
+glue_ptr(p)= r;q= r;
+}
+}
+cur_height= cur_height+prev_dp+width(q);prev_dp= 0
+
+/*:976*/
+#line 18972 "tex.w"
+;
+not_found:if(prev_dp> d)
+{cur_height= cur_height+prev_dp-d;
+prev_dp= d;
+}
+
+/*:972*/
+#line 18945 "tex.w"
+;
+prev_p= p;p= link(prev_p);
+}
+done:return best_place;
+}
+
+/*:970*//*977:*/
+#line 19060 "tex.w"
+pointer vsplit(eight_bits n,scaled h)
+
+{
+pointer v;
+pointer p;
+pointer q;
+v= box(n);
+if(split_first_mark!=null)
+{delete_token_ref(split_first_mark);split_first_mark= null;
+delete_token_ref(split_bot_mark);split_bot_mark= null;
+}
+/*978:*/
+#line 19081 "tex.w"
+
+if(v==null)
+{return null;
+}
+if(type(v)!=vlist_node)
+{print_err("");print_esc(/*1687:*/
+#line 25957 "tex.w"
+562
+/*:1687*/
+#line 19086 "tex.w"
+);print_str(" needs a ");
+print_esc(/*1688:*/
+#line 25960 "tex.w"
+563
+/*:1688*/
+#line 19087 "tex.w"
+);
+
+help2("The box you are trying to split is an \\hbox.")
+("I can't split such a box, so I'll leave it alone.");
+error();return null;
+}
+
+/*:978*/
+#line 19071 "tex.w"
+;
+q= vert_break(list_ptr(v),h,split_max_depth);
+/*979:*/
+#line 19097 "tex.w"
+
+p= list_ptr(v);
+if(p==q)list_ptr(v)= null;
+else loop{if(type(p)==mark_node)
+if(split_first_mark==null)
+{split_first_mark= mark_ptr(p);
+split_bot_mark= split_first_mark;
+token_ref_count(split_first_mark)=
+token_ref_count(split_first_mark)+2;
+}
+else{delete_token_ref(split_bot_mark);
+split_bot_mark= mark_ptr(p);
+add_token_ref(split_bot_mark);
+}
+if(link(p)==q)
+{link(p)= null;goto done;
+}
+p= link(p);
+}
+done:
+
+/*:979*/
+#line 19074 "tex.w"
+;
+q= prune_page_top(q);p= list_ptr(v);free_node(v,box_node_size);
+if(q==null)box(n)= null;
+else box(n)= vpack(q,natural);
+return vpackage(p,h,exactly,split_max_depth);
+}
+
+/*:977*//*985:*/
+#line 19285 "tex.w"
+void print_totals(void)
+{print_scaled(page_total);
+print_plus(2)("");
+print_plus(3)("fil");
+print_plus(4)("fill");
+print_plus(5)("filll");
+if(page_shrink!=0)
+{print_str(" minus ");print_scaled(page_shrink);
+}
+}
+
+/*:985*//*987:*/
+#line 19331 "tex.w"
+void freeze_page_specs(small_number s)
+{page_contents= s;
+page_goal= vsize;page_max_depth= max_depth;
+page_depth= 0;do_all_six(set_page_so_far_zero);
+least_page_cost= awful_bad;
+#ifdef STAT
+if(tracing_pages> 0)
+{begin_diagnostic();
+print_nl("%% goal height=");print_scaled(page_goal);
+
+print_str(", max depth=");print_scaled(page_max_depth);
+end_diagnostic(false);
+}
+#endif
+
+}
+
+/*:987*//*992:*/
+#line 19398 "tex.w"
+void box_error(eight_bits n)
+{error();begin_diagnostic();
+print_nl("The following box has been deleted:");
+
+show_box(box(n));end_diagnostic(true);
+flush_node_list(box(n));box(n)= null;
+}
+
+/*:992*//*993:*/
+#line 19409 "tex.w"
+void ensure_vbox(eight_bits n)
+{pointer p;
+p= box(n);
+if(p!=null)if(type(p)==hlist_node)
+{print_err("Insertions can only be added to a vbox");
+
+help3("Tut tut: You're trying to \\insert into a")
+("\\box register that now contains an \\hbox.")
+("Proceed, and I'll discard its present contents.");
+box_error(n);
+}
+}
+
+/*:993*//*994:*/
+#line 19428 "tex.w"
+/*1012:*/
+#line 19723 "tex.w"
+
+void fire_up(pointer c)
+{
+pointer p,q,r,s;
+pointer prev_p;
+uint8_t n;
+bool wait;
+int save_vbadness;
+scaled save_vfuzz;
+pointer save_split_top_skip;
+/*1013:*/
+#line 19752 "tex.w"
+
+if(type(best_page_break)==penalty_node)
+{geq_word_define(int_base+output_penalty_code,penalty(best_page_break));
+penalty(best_page_break)= inf_penalty;
+}
+else geq_word_define(int_base+output_penalty_code,inf_penalty)
+
+/*:1013*/
+#line 19733 "tex.w"
+;
+if(bot_mark!=null)
+{if(top_mark!=null)delete_token_ref(top_mark);
+top_mark= bot_mark;add_token_ref(top_mark);
+delete_token_ref(first_mark);first_mark= null;
+}
+/*1014:*/
+#line 19764 "tex.w"
+
+if(c==best_page_break)best_page_break= null;
+/*1015:*/
+#line 19786 "tex.w"
+
+if(box(255)!=null)
+{print_err("");print_esc(/*1437:*/
+#line 25207 "tex.w"
+312
+/*:1437*/
+#line 19788 "tex.w"
+);print_str("255 is not void");
+
+help2("You shouldn't use \\box255 except in \\output routines.")
+("Proceed, and I'll discard its present contents.");
+box_error(255);
+}
+
+/*:1015*/
+#line 19766 "tex.w"
+;
+insert_penalties= 0;
+save_split_top_skip= split_top_skip;
+if(holding_inserts<=0)
+/*1018:*/
+#line 19840 "tex.w"
+
+{r= link(page_ins_head);
+while(r!=page_ins_head)
+{if(best_ins_ptr(r)!=null)
+{n= qo(subtype(r));ensure_vbox(n);
+if(box(n)==null)box(n)= new_null_box();
+p= box(n)+list_offset;
+while(link(p)!=null)p= link(p);
+last_ins_ptr(r)= p;
+}
+r= link(r);
+}
+}
+
+/*:1018*/
+#line 19770 "tex.w"
+;
+q= hold_head;link(q)= null;prev_p= page_head;p= link(prev_p);
+while(p!=best_page_break)
+{if(type(p)==ins_node)
+{if(holding_inserts<=0)
+/*1020:*/
+#line 19866 "tex.w"
+
+{r= link(page_ins_head);
+while(subtype(r)!=subtype(p))r= link(r);
+if(best_ins_ptr(r)==null)wait= true;
+else{wait= false;s= last_ins_ptr(r);link(s)= ins_ptr(p);
+if(best_ins_ptr(r)==p)
+/*1021:*/
+#line 19882 "tex.w"
+
+{if(type(r)==split_up)
+if((broken_ins(r)==p)&&(broken_ptr(r)!=null))
+{while(link(s)!=broken_ptr(r))s= link(s);
+link(s)= null;
+split_top_skip= split_top_ptr(p);
+ins_ptr(p)= prune_page_top(broken_ptr(r));
+if(ins_ptr(p)!=null)
+{temp_ptr= vpack(ins_ptr(p),natural);
+height(p)= height(temp_ptr)+depth(temp_ptr);
+free_node(temp_ptr,box_node_size);wait= true;
+}
+}
+best_ins_ptr(r)= null;
+n= qo(subtype(r));
+temp_ptr= list_ptr(box(n));
+free_node(box(n),box_node_size);
+box(n)= vpack(temp_ptr,natural);
+}
+
+/*:1021*/
+#line 19873 "tex.w"
+
+else{while(link(s)!=null)s= link(s);
+last_ins_ptr(r)= s;
+}
+}
+/*1022:*/
+#line 19902 "tex.w"
+
+link(prev_p)= link(p);link(p)= null;
+if(wait)
+{link(q)= p;q= p;incr(insert_penalties);
+}
+else{delete_glue_ref(split_top_ptr(p));
+free_node(p,ins_node_size);
+}
+p= prev_p
+
+/*:1022*/
+#line 19879 "tex.w"
+;
+}
+
+/*:1020*/
+#line 19776 "tex.w"
+;
+}
+else if(type(p)==mark_node)/*1016:*/
+#line 19795 "tex.w"
+
+{if(first_mark==null)
+{first_mark= mark_ptr(p);
+add_token_ref(first_mark);
+}
+if(bot_mark!=null)delete_token_ref(bot_mark);
+bot_mark= mark_ptr(p);add_token_ref(bot_mark);
+}
+
+/*:1016*/
+#line 19778 "tex.w"
+;
+prev_p= p;p= link(prev_p);
+}
+split_top_skip= save_split_top_skip;
+/*1017:*/
+#line 19815 "tex.w"
+
+if(p!=null)
+{if(link(contrib_head)==null)
+if(nest_ptr==0)tail= page_tail;
+else contrib_tail= page_tail;
+link(page_tail)= link(contrib_head);
+link(contrib_head)= p;
+link(prev_p)= null;
+}
+save_vbadness= vbadness;vbadness= inf_bad;
+save_vfuzz= vfuzz;vfuzz= max_dimen;
+box(255)= vpackage(link(page_head),best_size,exactly,page_max_depth);
+vbadness= save_vbadness;vfuzz= save_vfuzz;
+if(last_glue!=max_halfword)delete_glue_ref(last_glue);
+/*991:*/
+#line 19388 "tex.w"
+
+page_contents= empty;page_tail= page_head;link(page_head)= null;
+last_glue= max_halfword;last_penalty= 0;last_kern= 0;
+page_depth= 0;page_max_depth= 0
+
+/*:991*/
+#line 19829 "tex.w"
+;
+if(q!=hold_head)
+{link(page_head)= link(hold_head);page_tail= q;
+}
+
+/*:1017*/
+#line 19783 "tex.w"
+;
+/*1019:*/
+#line 19854 "tex.w"
+
+r= link(page_ins_head);
+while(r!=page_ins_head)
+{q= link(r);free_node(r,page_ins_node_size);r= q;
+}
+link(page_ins_head)= page_ins_head
+
+/*:1019*/
+#line 19784 "tex.w"
+
+
+/*:1014*/
+#line 19741 "tex.w"
+;
+if((top_mark!=null)&&(first_mark==null))
+{first_mark= top_mark;add_token_ref(top_mark);
+}
+if(output_routine!=null)
+if(dead_cycles>=max_dead_cycles)
+/*1024:*/
+#line 19927 "tex.w"
+
+{print_err("Output loop---");print_int(dead_cycles);
+
+print_str(" consecutive dead cycles");
+help3("I've concluded that your \\output is awry; it never does a")
+("\\shipout, so I'm shipping \\box255 out myself. Next time")
+("increase \\maxdeadcycles if you want me to be more patient!");error();
+}
+
+/*:1024*/
+#line 19747 "tex.w"
+
+else/*1025:*/
+#line 19936 "tex.w"
+
+{output_active= true;
+incr(dead_cycles);
+push_nest();mode= -vmode;prev_depth= ignore_depth;mode_line= -line;
+begin_token_list(output_routine,output_text);
+new_save_level(output_group);normal_paragraph();
+scan_left_brace();
+return;
+}
+
+/*:1025*/
+#line 19748 "tex.w"
+;
+/*1023:*/
+#line 19916 "tex.w"
+
+{if(link(page_head)!=null)
+{if(link(contrib_head)==null)
+if(nest_ptr==0)tail= page_tail;else contrib_tail= page_tail;
+else link(page_tail)= link(contrib_head);
+link(contrib_head)= link(page_head);
+link(page_head)= null;page_tail= page_head;
+}
+ship_out(box(255));box(255)= null;
+}
+
+/*:1023*/
+#line 19749 "tex.w"
+;
+}
+
+/*:1012*/
+#line 19428 "tex.w"
+
+void build_page(void)
+{
+pointer p;
+pointer q,r;
+int b,c;
+int pi;
+uint8_t n;
+scaled delta,h,w;
+if((link(contrib_head)==null)||output_active)return;
+do{resume:p= link(contrib_head);
+/*996:*/
+#line 19453 "tex.w"
+
+if(last_glue!=max_halfword)delete_glue_ref(last_glue);
+last_penalty= 0;last_kern= 0;
+if(type(p)==glue_node)
+{last_glue= glue_ptr(p);add_glue_ref(last_glue);
+}
+else{last_glue= max_halfword;
+if(type(p)==penalty_node)last_penalty= penalty(p);
+else if(type(p)==kern_node)last_kern= width(p);
+}
+
+/*:996*/
+#line 19439 "tex.w"
+;
+/*997:*/
+#line 19470 "tex.w"
+
+/*1000:*/
+#line 19498 "tex.w"
+
+switch(type(p)){
+case hlist_node:case vlist_node:case rule_node:if(page_contents<box_there)
+/*1001:*/
+#line 19519 "tex.w"
+
+{if(page_contents==empty)freeze_page_specs(box_there);
+else page_contents= box_there;
+q= new_skip_param(top_skip_code);
+if(width(temp_ptr)> height(p))width(temp_ptr)= width(temp_ptr)-height(p);
+else width(temp_ptr)= 0;
+link(q)= p;link(contrib_head)= q;goto resume;
+}
+
+/*:1001*/
+#line 19502 "tex.w"
+
+else/*1002:*/
+#line 19528 "tex.w"
+
+{page_total= page_total+page_depth+height(p);
+page_depth= depth(p);
+goto contribute;
+}
+
+/*:1002*/
+#line 19503 "tex.w"
+break;
+case whatsit_node:/*1364:*/
+#line 24808 "tex.w"
+
+goto contribute
+
+/*:1364*/
+#line 19504 "tex.w"
+;
+case glue_node:if(page_contents<box_there)goto done1;
+else if(precedes_break(page_tail))pi= 0;
+else goto update_heights;break;
+case kern_node:if(page_contents<box_there)goto done1;
+else if(link(p)==null)return;
+else if(type(link(p))==glue_node)pi= 0;
+else goto update_heights;break;
+case penalty_node:if(page_contents<box_there)goto done1;else pi= penalty(p);break;
+case mark_node:goto contribute;
+case ins_node:/*1008:*/
+#line 19615 "tex.w"
+
+{if(page_contents==empty)freeze_page_specs(inserts_only);
+n= subtype(p);r= page_ins_head;
+while(n>=subtype(link(r)))r= link(r);
+n= qo(n);
+if(subtype(r)!=qi(n))
+/*1009:*/
+#line 19643 "tex.w"
+
+{q= get_node(page_ins_node_size);link(q)= link(r);link(r)= q;r= q;
+subtype(r)= qi(n);type(r)= inserting;ensure_vbox(n);
+if(box(n)==null)height(r)= 0;
+else height(r)= height(box(n))+depth(box(n));
+best_ins_ptr(r)= null;
+q= skip(n);
+if(count(n)==1000)h= height(r);
+else h= x_over_n(height(r),1000)*count(n);
+page_goal= page_goal-h-width(q);
+page_so_far[2+stretch_order(q)]= page_so_far[2+stretch_order(q)]+stretch(q);
+page_shrink= page_shrink+shrink(q);
+if((shrink_order(q)!=normal)&&(shrink(q)!=0))
+{print_err("Infinite glue shrinkage inserted from ");print_esc(/*1423:*/
+#line 25165 "tex.w"
+298
+/*:1423*/
+#line 19656 "tex.w"
+);
+
+print_int(n);
+help3("The correction glue for page breaking with insertions")
+("must have finite shrinkability. But you may proceed,")
+("since the offensive shrinkability has been made finite.");
+error();
+}
+}
+
+/*:1009*/
+#line 19622 "tex.w"
+;
+if(type(r)==split_up)insert_penalties= insert_penalties+float_cost(p);
+else{last_ins_ptr(r)= p;
+delta= page_goal-page_total-page_depth+page_shrink;
+
+if(count(n)==1000)h= height(p);
+else h= x_over_n(height(p),1000)*count(n);
+if(((h<=0)||(h<=delta))&&(height(p)+height(r)<=dimen(n)))
+{page_goal= page_goal-h;height(r)= height(r)+height(p);
+}
+else/*1010:*/
+#line 19676 "tex.w"
+
+{if(count(n)<=0)w= max_dimen;
+else{w= page_goal-page_total-page_depth;
+if(count(n)!=1000)w= x_over_n(w,count(n))*1000;
+}
+if(w> dimen(n)-height(r))w= dimen(n)-height(r);
+q= vert_break(ins_ptr(p),w,depth(p));
+height(r)= height(r)+best_height_plus_depth;
+#ifdef STAT
+if(tracing_pages> 0)/*1011:*/
+#line 19696 "tex.w"
+
+{begin_diagnostic();print_nl("% split");print_int(n);
+
+print_str(" to ");print_scaled(w);
+print_char(',');print_scaled(best_height_plus_depth);
+print_str(" p=");
+if(q==null)print_int(eject_penalty);
+else if(type(q)==penalty_node)print_int(penalty(q));
+else print_char('0');
+end_diagnostic(false);
+}
+
+/*:1011*/
+#line 19685 "tex.w"
+;
+#endif
+
+if(count(n)!=1000)
+best_height_plus_depth= x_over_n(best_height_plus_depth,1000)*count(n);
+page_goal= page_goal-best_height_plus_depth;
+type(r)= split_up;broken_ptr(r)= q;broken_ins(r)= p;
+if(q==null)insert_penalties= insert_penalties+eject_penalty;
+else if(type(q)==penalty_node)insert_penalties= insert_penalties+penalty(q);
+}
+
+/*:1010*/
+#line 19632 "tex.w"
+;
+}
+goto contribute;
+}
+
+/*:1008*/
+#line 19514 "tex.w"
+
+default:confusion(/*1697:*/
+#line 25987 "tex.w"
+572
+/*:1697*/
+#line 19515 "tex.w"
+);
+
+}
+
+/*:1000*/
+#line 19474 "tex.w"
+;
+/*1005:*/
+#line 19562 "tex.w"
+
+if(pi<inf_penalty)
+{/*1007:*/
+#line 19607 "tex.w"
+
+if(page_total<page_goal)
+if((page_so_far[3]!=0)||(page_so_far[4]!=0)||
+(page_so_far[5]!=0))b= 0;
+else b= badness(page_goal-page_total,page_so_far[2]);
+else if(page_total-page_goal> page_shrink)b= awful_bad;
+else b= badness(page_total-page_goal,page_shrink)
+
+/*:1007*/
+#line 19565 "tex.w"
+;
+if(b<awful_bad)
+if(pi<=eject_penalty)c= pi;
+else if(b<inf_bad)c= b+pi+insert_penalties;
+else c= deplorable;
+else c= b;
+if(insert_penalties>=10000)c= awful_bad;
+
+#ifdef STAT
+if(tracing_pages> 0)/*1006:*/
+#line 19593 "tex.w"
+
+{begin_diagnostic();print_nl("%");
+print_str(" t=");print_totals();
+print_str(" g=");print_scaled(page_goal);
+print_str(" b=");
+if(b==awful_bad)print_char('*');else print_int(b);
+
+print_str(" p=");print_int(pi);
+print_str(" c=");
+if(c==awful_bad)print_char('*');else print_int(c);
+if(c<=least_page_cost)print_char('#');
+end_diagnostic(false);
+}
+
+/*:1006*/
+#line 19574 "tex.w"
+;
+#endif
+
+if(c<=least_page_cost)
+{best_page_break= p;best_size= page_goal;
+least_page_cost= c;
+r= link(page_ins_head);
+while(r!=page_ins_head)
+{best_ins_ptr(r)= last_ins_ptr(r);
+r= link(r);
+}
+}
+if((c==awful_bad)||(pi<=eject_penalty))
+{fire_up(p);
+if(output_active)return;
+goto done;
+}
+}
+
+/*:1005*/
+#line 19477 "tex.w"
+;
+if((type(p)<glue_node)||(type(p)> kern_node))goto contribute;
+update_heights:/*1004:*/
+#line 19541 "tex.w"
+
+if(type(p)==kern_node)q= p;
+else{q= glue_ptr(p);
+page_so_far[2+stretch_order(q)]=
+page_so_far[2+stretch_order(q)]+stretch(q);
+page_shrink= page_shrink+shrink(q);
+if((shrink_order(q)!=normal)&&(shrink(q)!=0))
+{
+print_err("Infinite glue shrinkage found on current page");
+
+help4("The page about to be output contains some infinitely")
+("shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.")
+("Such glue doesn't belong there; but you can safely proceed,")
+("since the offensive shrinkability has been made finite.");
+error();
+r= new_spec(q);shrink_order(r)= normal;delete_glue_ref(q);
+glue_ptr(p)= r;q= r;
+}
+}
+page_total= page_total+page_depth+width(q);page_depth= 0
+
+/*:1004*/
+#line 19480 "tex.w"
+;
+contribute:/*1003:*/
+#line 19534 "tex.w"
+
+if(page_depth> page_max_depth)
+{page_total=
+page_total+page_depth-page_max_depth;
+page_depth= page_max_depth;
+}
+
+/*:1003*/
+#line 19481 "tex.w"
+;
+/*998:*/
+#line 19486 "tex.w"
+
+link(page_tail)= p;page_tail= p;
+link(contrib_head)= link(p);link(p)= null;goto done
+
+/*:998*/
+#line 19482 "tex.w"
+;
+done1:/*999:*/
+#line 19490 "tex.w"
+
+link(contrib_head)= link(p);link(p)= null;flush_node_list(p)
+
+/*:999*/
+#line 19483 "tex.w"
+;
+done:
+
+/*:997*/
+#line 19442 "tex.w"
+;
+}while(!(link(contrib_head)==null));
+/*995:*/
+#line 19449 "tex.w"
+
+if(nest_ptr==0)tail= contrib_head;
+else contrib_tail= contrib_head
+
+/*:995*/
+#line 19444 "tex.w"
+;
+}
+
+/*:994*//*1030:*/
+#line 20035 "tex.w"
+/*1043:*/
+#line 20361 "tex.w"
+
+void app_space(void)
+{pointer q;
+if((space_factor>=2000)&&(xspace_skip!=zero_glue))
+q= new_param_glue(xspace_skip_code);
+else{if(space_skip!=zero_glue)main_p= space_skip;
+else/*1042:*/
+#line 20350 "tex.w"
+
+{main_p= font_glue[cur_font];
+if(main_p==null)
+{main_p= new_spec(zero_glue);main_k= param_base[cur_font]+space_code;
+width(main_p)= font_info[main_k].sc;
+stretch(main_p)= font_info[main_k+1].sc;
+shrink(main_p)= font_info[main_k+2].sc;
+font_glue[cur_font]= main_p;
+}
+}
+
+/*:1042*/
+#line 20367 "tex.w"
+;
+main_p= new_spec(main_p);
+/*1044:*/
+#line 20375 "tex.w"
+
+if(space_factor>=2000)width(main_p)= width(main_p)+extra_space(cur_font);
+stretch(main_p)= xn_over_d(stretch(main_p),space_factor,1000);
+shrink(main_p)= xn_over_d(shrink(main_p),1000,space_factor)
+
+/*:1044*/
+#line 20369 "tex.w"
+;
+q= new_glue(main_p);glue_ref_count(main_p)= null;
+}
+link(tail)= q;tail= q;
+}
+
+/*:1043*//*1047:*/
+#line 20413 "tex.w"
+
+void insert_dollar_sign(void)
+{back_input();cur_tok= math_shift_token+'$';
+print_err("Missing $ inserted");
+
+help2("I've inserted a begin-math/end-math symbol since I think")
+("you left one out. Proceed, with fingers crossed.");ins_error();
+}
+
+/*:1047*//*1049:*/
+#line 20438 "tex.w"
+
+void you_cant(void)
+{print_err("You can't use `");
+
+print_cmd_chr(cur_cmd,cur_chr);
+print_str("' in ");print_mode(mode);
+}
+
+/*:1049*//*1050:*/
+#line 20446 "tex.w"
+
+void report_illegal_case(void)
+{you_cant();
+help4("Sorry, but I'm not programmed to handle this case;")
+("I'll just pretend that you didn't ask for it.")
+("If you're in the wrong mode, you might be able to")
+("return to the right one by typing `I}' or `I$' or `I\\par'.");
+error();
+}
+
+/*:1050*//*1051:*/
+#line 20461 "tex.w"
+
+bool privileged(void)
+{if(mode> 0)return true;
+else{report_illegal_case();return false;
+}
+}
+
+/*:1051*//*1054:*/
+#line 20488 "tex.w"
+
+bool its_all_over(void)
+{
+if(privileged())
+{if((page_head==page_tail)&&(head==tail)&&(dead_cycles==0))
+{return true;
+}
+back_input();
+tail_append(new_null_box());
+width(tail)= hsize;
+tail_append(new_glue(fill_glue));
+tail_append(new_penalty(-010000000000));
+build_page();
+}
+return false;
+}
+
+/*:1054*//*1060:*/
+#line 20598 "tex.w"
+
+void append_glue(void)
+{small_number s;
+s= cur_chr;
+switch(s){
+case fil_code:cur_val= fil_glue;break;
+case fill_code:cur_val= fill_glue;break;
+case ss_code:cur_val= ss_glue;break;
+case fil_neg_code:cur_val= fil_neg_glue;break;
+case skip_code:scan_glue(glue_val);break;
+case mskip_code:scan_glue(mu_val);
+}
+tail_append(new_glue(cur_val));
+if(s>=skip_code)
+{decr(glue_ref_count(cur_val));
+if(s> skip_code)subtype(tail)= mu_glue;
+}
+}
+
+/*:1060*//*1061:*/
+#line 20617 "tex.w"
+
+void append_kern(void)
+{quarterword s;
+s= cur_chr;scan_dimen(s==mu_glue,false,false);
+tail_append(new_kern(cur_val));subtype(tail)= s;
+}
+
+/*:1061*//*1064:*/
+#line 20661 "tex.w"
+
+void off_save(void)
+{pointer p;
+if(cur_group==bottom_level)
+/*1066:*/
+#line 20700 "tex.w"
+
+{print_err("Extra ");print_cmd_chr(cur_cmd,cur_chr);
+
+help1("Things are pretty mixed up, but I think the worst is over.");
+error();
+}
+
+/*:1066*/
+#line 20665 "tex.w"
+
+else{back_input();p= get_avail();link(temp_head)= p;
+print_err("Missing ");
+/*1065:*/
+#line 20681 "tex.w"
+
+switch(cur_group){
+case semi_simple_group:{info(p)= cs_token_flag+frozen_end_group;
+print_esc(/*1538:*/
+#line 25510 "tex.w"
+413
+/*:1538*/
+#line 20684 "tex.w"
+);
+
+}break;
+case math_shift_group:{info(p)= math_shift_token+'$';print_char('$');
+
+}break;
+case math_left_group:{info(p)= cs_token_flag+frozen_right;link(p)= get_avail();
+p= link(p);info(p)= other_token+'.';print_esc(/*1710:*/
+#line 26026 "tex.w"
+585
+/*:1710*/
+#line 20691 "tex.w"
+);
+
+
+}break;
+default:{info(p)= right_brace_token+'}';print_char('}');
+
+}
+}
+
+/*:1065*/
+#line 20668 "tex.w"
+;
+print_str(" inserted");ins_list(link(temp_head));
+help5("I've inserted something that you may have forgotten.")
+("(See the <inserted text> above.)")
+("With luck, this will get me unwedged. But if you")
+("really didn't forget anything, try typing `2' now; then")
+("my insertion and my current dilemma will both disappear.");
+error();
+}
+}
+
+/*:1064*//*1069:*/
+#line 20736 "tex.w"
+
+void extra_right_brace(void)
+{print_err("Extra }, or forgotten ");
+
+switch(cur_group){
+case semi_simple_group:print_esc(/*1538:*/
+#line 25510 "tex.w"
+413
+/*:1538*/
+#line 20741 "tex.w"
+);break;
+case math_shift_group:print_char('$');break;
+case math_left_group:print_esc(/*1660:*/
+#line 25876 "tex.w"
+535
+/*:1660*/
+#line 20743 "tex.w"
+);
+}
+help5("I've deleted a group-closing symbol because it seems to be")
+("spurious, as in `$x}$'. But perhaps the } is legitimate and")
+("you forgot something else, as in `\\hbox{$x}'. In such cases")
+("the way to recover is to insert both the forgotten and the")
+("deleted material, e.g., by typing `I$}'.");error();
+incr(align_state);
+}
+
+/*:1069*//*1070:*/
+#line 20756 "tex.w"
+
+void normal_paragraph(void)
+{if(looseness!=0)eq_word_define(int_base+looseness_code,0);
+if(hang_indent!=0)eq_word_define(dimen_base+hang_indent_code,0);
+if(hang_after!=1)eq_word_define(int_base+hang_after_code,1);
+if(par_shape_ptr!=null)eq_define(par_shape_loc,shape_ref,null);
+}
+
+/*:1070*//*1075:*/
+#line 20877 "tex.w"
+
+void box_end(int box_context)
+{pointer p;
+if(box_context<box_flag)/*1076:*/
+#line 20892 "tex.w"
+
+{if(cur_box!=null)
+{shift_amount(cur_box)= box_context;
+if(abs(mode)==vmode)
+{append_to_vlist(cur_box);
+if(adjust_tail!=null)
+{if(adjust_head!=adjust_tail)
+{link(tail)= link(adjust_head);tail= adjust_tail;
+}
+adjust_tail= null;
+}
+if(mode> 0)build_page();
+}
+else{if(abs(mode)==hmode)space_factor= 1000;
+else{p= new_noad();
+math_type(nucleus(p))= sub_box;
+info(nucleus(p))= cur_box;cur_box= p;
+}
+link(tail)= cur_box;tail= cur_box;
+}
+}
+}
+
+/*:1076*/
+#line 20881 "tex.w"
+
+else if(box_context<ship_out_flag)/*1077:*/
+#line 20915 "tex.w"
+
+if(box_context<box_flag+256)
+eq_define(box_base-box_flag+box_context,box_ref,cur_box);
+else geq_define(box_base-box_flag-256+box_context,box_ref,cur_box)
+
+/*:1077*/
+#line 20882 "tex.w"
+;
+else if(cur_box!=null)
+if(box_context> ship_out_flag)/*1078:*/
+#line 20920 "tex.w"
+
+{/*404:*/
+#line 8257 "tex.w"
+
+do{get_x_token();
+}while(!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+/*:404*/
+#line 20921 "tex.w"
+;
+if(((cur_cmd==hskip)&&(abs(mode)!=vmode))||
+((cur_cmd==vskip)&&(abs(mode)==vmode)))
+{append_glue();subtype(tail)= box_context-(leader_flag-a_leaders);
+leader_ptr(tail)= cur_box;
+}
+else{print_err("Leaders not followed by proper glue");
+
+help3("You should say `\\leaders <box or rule><hskip or vskip>'.")
+("I found the <box or rule>, but there's no suitable")
+("<hskip or vskip>, so I'm ignoring these leaders.");back_error();
+flush_node_list(cur_box);
+}
+}
+
+/*:1078*/
+#line 20884 "tex.w"
+
+else ship_out(cur_box);
+}
+
+/*:1075*//*1079:*/
+#line 20941 "tex.w"
+
+void begin_box(int box_context)
+{
+pointer p,q;
+int m;
+halfword k;
+eight_bits n;
+switch(cur_chr){
+case box_code:{scan_eight_bit_int();cur_box= box(cur_val);
+box(cur_val)= null;
+}break;
+case copy_code:{scan_eight_bit_int();cur_box= copy_node_list(box(cur_val));
+}break;
+case last_box_code:/*1080:*/
+#line 20965 "tex.w"
+
+{cur_box= null;
+if(abs(mode)==mmode)
+{you_cant();help1("Sorry; this \\lastbox will be void.");error();
+}
+else if((mode==vmode)&&(head==tail))
+{you_cant();
+help2("Sorry...I usually can't take things from the current page.")
+("This \\lastbox will therefore be void.");error();
+}
+else{if(!is_char_node(tail))
+if((type(tail)==hlist_node)||(type(tail)==vlist_node))
+/*1081:*/
+#line 20981 "tex.w"
+
+{q= head;
+do{p= q;
+if(!is_char_node(q))if(type(q)==disc_node)
+{for(m= 1;m<=replace_count(q);m++)p= link(p);
+if(p==tail)goto done;
+}
+q= link(p);
+}while(!(q==tail));
+cur_box= tail;shift_amount(cur_box)= 0;
+tail= p;link(p)= null;
+done:;}
+
+/*:1081*/
+#line 20977 "tex.w"
+;
+}
+}
+
+/*:1080*/
+#line 20955 "tex.w"
+break;
+case vsplit_code:/*1082:*/
+#line 20996 "tex.w"
+
+{scan_eight_bit_int();n= cur_val;
+if(!scan_keyword(/*1642:*/
+#line 25822 "tex.w"
+517
+/*:1642*/
+#line 20998 "tex.w"
+))
+
+{print_err("Missing `to' inserted");
+
+help2("I'm working on `\\vsplit<box number> to <dimen>';")
+("will look for the <dimen> next.");error();
+}
+scan_normal_dimen;
+cur_box= vsplit(n,cur_val);
+}
+
+/*:1082*/
+#line 20956 "tex.w"
+break;
+default:/*1083:*/
+#line 21012 "tex.w"
+
+{k= cur_chr-vtop_code;saved(0)= box_context;
+if(k==hmode)
+if((box_context<box_flag)&&(abs(mode)==vmode))
+scan_spec(adjusted_hbox_group,true);
+else scan_spec(hbox_group,true);
+else{if(k==vmode)scan_spec(vbox_group,true);
+else{scan_spec(vtop_group,true);k= vmode;
+}
+normal_paragraph();
+}
+push_nest();mode= -k;
+if(k==vmode)
+{prev_depth= ignore_depth;
+if(every_vbox!=null)begin_token_list(every_vbox,every_vbox_text);
+}
+else{space_factor= 1000;
+if(every_hbox!=null)begin_token_list(every_hbox,every_hbox_text);
+}
+return;
+}
+
+/*:1083*/
+#line 20957 "tex.w"
+
+}
+box_end(box_context);
+}
+
+/*:1079*//*1084:*/
+#line 21034 "tex.w"
+
+void scan_box(int box_context)
+
+{/*404:*/
+#line 8257 "tex.w"
+
+do{get_x_token();
+}while(!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+/*:404*/
+#line 21037 "tex.w"
+;
+if(cur_cmd==make_box)begin_box(box_context);
+else if((box_context>=leader_flag)&&((cur_cmd==hrule)||(cur_cmd==vrule)))
+{cur_box= scan_rule_spec();box_end(box_context);
+}
+else{
+print_err("A <box> was supposed to be here");
+
+help3("I was expecting to see \\hbox or \\vbox or \\copy or \\box or")
+("something like that. So you might find something missing in")
+("your output. But keep trying; you can fix this later.");back_error();
+}
+}
+
+/*:1084*//*1086:*/
+#line 21064 "tex.w"
+
+void package(small_number c)
+{scaled h;
+pointer p;
+scaled d;
+d= box_max_depth;unsave();save_ptr= save_ptr-3;
+if(mode==-hmode)cur_box= hpack(link(head),saved(2),saved(1));
+else{cur_box= vpackage(link(head),saved(2),saved(1),d);
+if(c==vtop_code)/*1087:*/
+#line 21082 "tex.w"
+
+{h= 0;p= list_ptr(cur_box);
+if(p!=null)if(type(p)<=rule_node)h= height(p);
+depth(cur_box)= depth(cur_box)-h+height(cur_box);height(cur_box)= h;
+}
+
+/*:1087*/
+#line 21072 "tex.w"
+;
+}
+pop_nest();box_end(saved(0));
+}
+
+/*:1086*//*1091:*/
+#line 21110 "tex.w"
+
+small_number norm_min(int h)
+{if(h<=0)return 1;else if(h>=63)return 63;
+else return h;
+}
+
+void new_graf(bool indented)
+{prev_graf= 0;
+if((mode==vmode)||(head!=tail))
+tail_append(new_param_glue(par_skip_code));
+push_nest();mode= hmode;space_factor= 1000;set_cur_lang;clang= cur_lang;
+prev_graf= (norm_min(left_hyphen_min)*0100+norm_min(right_hyphen_min))
+*0200000+cur_lang;
+if(indented)
+{tail= new_null_box();link(head)= tail;width(tail)= par_indent;
+}
+if(every_par!=null)begin_token_list(every_par,every_par_text);
+if(nest_ptr==1)build_page();
+}
+
+/*:1091*//*1093:*/
+#line 21133 "tex.w"
+
+void indent_in_hmode(void)
+{pointer p,q;
+if(cur_chr> 0)
+{p= new_null_box();width(p)= par_indent;
+if(abs(mode)==hmode)space_factor= 1000;
+else{q= new_noad();math_type(nucleus(q))= sub_box;
+info(nucleus(q))= p;p= q;
+}
+tail_append(p);
+}
+}
+
+/*:1093*//*1095:*/
+#line 21161 "tex.w"
+
+void head_for_vmode(void)
+{if(mode<0)
+if(cur_cmd!=hrule)off_save();
+else{print_err("You can't use `");
+print_esc(/*1543:*/
+#line 25525 "tex.w"
+418
+/*:1543*/
+#line 21166 "tex.w"
+);print_str("' here except with leaders");
+
+help2("To put a horizontal rule in an hbox or an alignment,")
+("you should use \\leaders or \\hrulefill (see The TeXbook).");
+error();
+}
+else{back_input();cur_tok= par_token;back_input();token_type= inserted;
+}
+}
+
+/*:1095*//*1096:*/
+#line 21176 "tex.w"
+
+void end_graf(void)
+{if(mode==hmode)
+{if(head==tail)pop_nest();
+else line_break(widow_penalty);
+normal_paragraph();
+error_count= 0;
+}
+}
+
+/*:1096*//*1099:*/
+#line 21196 "tex.w"
+
+void begin_insert_or_adjust(void)
+{if(cur_cmd==vadjust)cur_val= 255;
+else{scan_eight_bit_int();
+if(cur_val==255)
+{print_err("You can't ");print_esc(/*1390:*/
+#line 25066 "tex.w"
+265
+/*:1390*/
+#line 21201 "tex.w"
+);print_int(255);
+
+help1("I'm changing to \\insert0; box 255 is special.");
+error();cur_val= 0;
+}
+}
+saved(0)= cur_val;incr(save_ptr);
+new_save_level(insert_group);scan_left_brace();normal_paragraph();
+push_nest();mode= -vmode;prev_depth= ignore_depth;
+}
+
+/*:1099*//*1101:*/
+#line 21233 "tex.w"
+
+void make_mark(void)
+{pointer p;
+p= scan_toks(false,true);p= get_node(small_node_size);
+type(p)= mark_node;subtype(p)= 0;
+mark_ptr(p)= def_ref;link(tail)= p;tail= p;
+}
+
+/*:1101*//*1103:*/
+#line 21247 "tex.w"
+
+void append_penalty(void)
+{scan_int();tail_append(new_penalty(cur_val));
+if(mode==vmode)build_page();
+}
+
+/*:1103*//*1105:*/
+#line 21266 "tex.w"
+
+void delete_last(void)
+{
+pointer p,q;
+int m;
+if((mode==vmode)&&(tail==head))
+/*1106:*/
+#line 21287 "tex.w"
+
+{if((cur_chr!=glue_node)||(last_glue!=max_halfword))
+{you_cant();
+help2("Sorry...I usually can't take things from the current page.")
+("Try `I\\vskip-\\lastskip' instead.");
+if(cur_chr==kern_node)help_line[0]=
+("Try `I\\kern-\\lastkern' instead.");
+else if(cur_chr!=glue_node)help_line[0]=
+("Perhaps you can make the output routine do it.");
+error();
+}
+}
+
+/*:1106*/
+#line 21272 "tex.w"
+
+else{if(!is_char_node(tail))if(type(tail)==cur_chr)
+{q= head;
+do{p= q;
+if(!is_char_node(q))if(type(q)==disc_node)
+{for(m= 1;m<=replace_count(q);m++)p= link(p);
+if(p==tail)return;
+}
+q= link(p);
+}while(!(q==tail));
+link(p)= null;flush_node_list(tail);tail= p;
+}
+}
+}
+
+/*:1105*//*1110:*/
+#line 21330 "tex.w"
+
+void unpackage(void)
+{
+pointer p;
+uint8_t c;
+c= cur_chr;scan_eight_bit_int();p= box(cur_val);
+if(p==null)return;
+if((abs(mode)==mmode)||((abs(mode)==vmode)&&(type(p)!=vlist_node))||
+((abs(mode)==hmode)&&(type(p)!=hlist_node)))
+{print_err("Incompatible list can't be unboxed");
+
+help3("Sorry, Pandora. (You sneaky devil.)")
+("I refuse to unbox an \\hbox in vertical mode or vice versa.")
+("And I can't open any boxes in math mode.");
+error();return;
+}
+if(c==copy_code)link(tail)= copy_node_list(list_ptr(p));
+else{link(tail)= list_ptr(p);box(cur_val)= null;
+free_node(p,box_node_size);
+}
+while(link(tail)!=null)tail= link(tail);
+}
+
+/*:1110*//*1113:*/
+#line 21363 "tex.w"
+
+void append_italic_correction(void)
+{
+pointer p;
+internal_font_number f;
+if(tail!=head)
+{if(is_char_node(tail))p= tail;
+else if(type(tail)==ligature_node)p= lig_char(tail);
+else return;
+f= font(p);
+tail_append(new_kern(char_italic(f)(char_info(f)(character(p)))));
+subtype(tail)= explicit;
+}
+}
+
+/*:1113*//*1117:*/
+#line 21397 "tex.w"
+
+void append_discretionary(void)
+{int c;
+tail_append(new_disc());
+if(cur_chr==1)
+{c= hyphen_char[cur_font];
+if(c>=0)if(c<256)pre_break(tail)= new_character(cur_font,c);
+}
+else{incr(save_ptr);saved(-1)= 0;new_save_level(disc_group);
+scan_left_brace();push_nest();mode= -hmode;space_factor= 1000;
+}
+}
+
+/*:1117*//*1119:*/
+#line 21417 "tex.w"
+
+void build_discretionary(void)
+{
+pointer p,q;
+int n;
+unsave();
+/*1121:*/
+#line 21459 "tex.w"
+
+q= head;p= link(q);n= 0;
+while(p!=null)
+{if(!is_char_node(p))if(type(p)> rule_node)
+if(type(p)!=kern_node)if(type(p)!=ligature_node)
+{print_err("Improper discretionary list");
+
+help1("Discretionary lists must contain only boxes and kerns.");
+error();
+begin_diagnostic();
+print_nl("The following discretionary sublist has been deleted:");
+
+show_box(p);
+end_diagnostic(true);
+flush_node_list(p);link(q)= null;goto done;
+}
+q= p;p= link(q);incr(n);
+}
+done:
+
+/*:1121*/
+#line 21425 "tex.w"
+;
+p= link(head);pop_nest();
+switch(saved(-1)){
+case 0:pre_break(tail)= p;break;
+case 1:post_break(tail)= p;break;
+case 2:/*1120:*/
+#line 21437 "tex.w"
+
+{if((n> 0)&&(abs(mode)==mmode))
+{print_err("Illegal math ");print_esc(/*1400:*/
+#line 25096 "tex.w"
+275
+/*:1400*/
+#line 21439 "tex.w"
+);
+
+help2("Sorry: The third part of a discretionary break must be")
+("empty, in math formulas. I had to delete your third part.");
+flush_node_list(p);n= 0;error();
+}
+else link(tail)= p;
+if(n<=max_quarterword)replace_count(tail)= n;
+else{print_err("Discretionary list is too long");
+
+help2("Wow---I never thought anybody would tweak me here.")
+("You can't seriously need such a huge discretionary list?");
+error();
+}
+if(n> 0)tail= q;
+decr(save_ptr);return;
+}
+
+/*:1120*/
+#line 21431 "tex.w"
+;
+}
+incr(saved(-1));new_save_level(disc_group);scan_left_brace();
+push_nest();mode= -hmode;space_factor= 1000;
+}
+
+/*:1119*//*1123:*/
+#line 21493 "tex.w"
+
+void make_accent(void)
+{double s,t;
+pointer p,q,r;
+internal_font_number f;
+scaled a,h,x,w,delta;
+four_quarters i;
+scan_char_num();f= cur_font;p= new_character(f,cur_val);
+if(p!=null)
+{x= x_height(f);s= slant(f)/float_constant(65536);
+
+a= char_width(f)(char_info(f)(character(p)));
+do_assignments();
+/*1124:*/
+#line 21513 "tex.w"
+
+q= null;f= cur_font;
+if((cur_cmd==letter)||(cur_cmd==other_char)||(cur_cmd==char_given))
+q= new_character(f,cur_chr);
+else if(cur_cmd==char_num)
+{scan_char_num();q= new_character(f,cur_val);
+}
+else back_input()
+
+/*:1124*/
+#line 21507 "tex.w"
+;
+if(q!=null)/*1125:*/
+#line 21529 "tex.w"
+
+{t= slant(f)/float_constant(65536);
+
+i= char_info(f)(character(q));
+w= char_width(f)(i);h= char_height(f)(height_depth(i));
+if(h!=x)
+{p= hpack(p,natural);shift_amount(p)= x-h;
+}
+delta= round((w-a)/float_constant(2)+h*t-x*s);
+
+
+r= new_kern(delta);subtype(r)= acc_kern;link(tail)= r;link(r)= p;
+tail= new_kern(-a-delta);subtype(tail)= acc_kern;link(p)= tail;p= q;
+}
+
+/*:1125*/
+#line 21508 "tex.w"
+;
+link(tail)= p;tail= p;space_factor= 1000;
+}
+}
+
+/*:1123*//*1127:*/
+#line 21557 "tex.w"
+
+void align_error(void)
+{if(abs(align_state)> 2)
+/*1128:*/
+#line 21577 "tex.w"
+
+{print_err("Misplaced ");print_cmd_chr(cur_cmd,cur_chr);
+
+
+
+if(cur_tok==tab_token+'&')
+{help6("I can't figure out why you would want to use a tab mark")
+("here. If you just want an ampersand, the remedy is")
+("simple: Just type `I\\&' now. But if some right brace")
+("up above has ended a previous alignment prematurely,")
+("you're probably due for more error messages, and you")
+("might try typing `S' now just to see what is salvageable.");
+}
+else{help5("I can't figure out why you would want to use a tab mark")
+("or \\cr or \\span just now. If something like a right brace")
+("up above has ended a previous alignment prematurely,")
+("you're probably due for more error messages, and you")
+("might try typing `S' now just to see what is salvageable.");
+}
+error();
+}
+
+/*:1128*/
+#line 21560 "tex.w"
+
+else{back_input();
+if(align_state<0)
+{print_err("Missing { inserted");
+
+incr(align_state);cur_tok= left_brace_token+'{';
+}
+else{print_err("Missing } inserted");
+
+decr(align_state);cur_tok= right_brace_token+'}';
+}
+help3("I've put in what seems to be necessary to fix")
+("the current column of the current alignment.")
+("Try to go on, since this might almost work.");ins_error();
+}
+}
+
+/*:1127*//*1129:*/
+#line 21602 "tex.w"
+
+void no_align_error(void)
+{print_err("Misplaced ");print_esc(/*1549:*/
+#line 25543 "tex.w"
+424
+/*:1549*/
+#line 21604 "tex.w"
+);
+
+help2("I expect to see \\noalign only after the \\cr of")
+("an alignment. Proceed, and I'll ignore this case.");error();
+}
+void omit_error(void)
+{print_err("Misplaced ");print_esc(/*1552:*/
+#line 25552 "tex.w"
+427
+/*:1552*/
+#line 21610 "tex.w"
+);
+
+help2("I expect to see \\omit only after tab marks or the \\cr of")
+("an alignment. Proceed, and I'll ignore this case.");error();
+}
+
+/*:1129*//*1131:*/
+#line 21632 "tex.w"
+
+void do_endv(void)
+{base_ptr= input_ptr;input_stack[base_ptr]= cur_input;
+while((input_stack[base_ptr].index_field!=v_template)&&
+(input_stack[base_ptr].loc_field==null)&&
+(input_stack[base_ptr].state_field==token_list))decr(base_ptr);
+if((input_stack[base_ptr].index_field!=v_template)||
+(input_stack[base_ptr].loc_field!=null)||
+(input_stack[base_ptr].state_field!=token_list))
+fatal_error("(interwoven alignment preambles are not allowed)");
+
+if(cur_group==align_group)
+{end_graf();
+if(fin_col())fin_row();
+}
+else off_save();
+}
+
+/*:1131*//*1135:*/
+#line 21667 "tex.w"
+
+void cs_error(void)
+{print_err("Extra ");print_esc(/*1527:*/
+#line 25477 "tex.w"
+402
+/*:1527*/
+#line 21669 "tex.w"
+);
+
+help1("I'm ignoring this, since I wasn't doing a \\csname.");
+error();
+}
+
+/*:1135*//*1136:*/
+#line 21685 "tex.w"
+
+void push_math(group_code c)
+{push_nest();mode= -mmode;incompleat_noad= null;new_save_level(c);
+}
+
+/*:1136*//*1138:*/
+#line 21698 "tex.w"
+
+void init_math(void)
+{
+scaled w;
+scaled l;
+scaled s;
+pointer p;
+pointer q;
+internal_font_number f;
+int n;
+scaled v;
+scaled d;
+get_token();
+if((cur_cmd==math_shift)&&(mode> 0))/*1145:*/
+#line 21756 "tex.w"
+
+{if(head==tail)
+{pop_nest();w= -max_dimen;
+}
+else{line_break(display_widow_penalty);
+/*1146:*/
+#line 21776 "tex.w"
+
+v= shift_amount(just_box)+2*quad(cur_font);w= -max_dimen;
+p= list_ptr(just_box);
+while(p!=null)
+{/*1147:*/
+#line 21793 "tex.w"
+
+reswitch:if(is_char_node(p))
+{f= font(p);d= char_width(f)(char_info(f)(character(p)));
+goto found;
+}
+switch(type(p)){
+case hlist_node:case vlist_node:case rule_node:{d= width(p);goto found;
+}
+case ligature_node:/*652:*/
+#line 12994 "tex.w"
+
+{mem[lig_trick]= mem[lig_char(p)];link(lig_trick)= link(p);
+p= lig_trick;goto reswitch;
+}
+
+/*:652*/
+#line 21801 "tex.w"
+
+case kern_node:case math_node:d= width(p);break;
+case glue_node:/*1148:*/
+#line 21815 "tex.w"
+
+{q= glue_ptr(p);d= width(q);
+if(glue_sign(just_box)==stretching)
+{if((glue_order(just_box)==stretch_order(q))&&
+(stretch(q)!=0))
+v= max_dimen;
+}
+else if(glue_sign(just_box)==shrinking)
+{if((glue_order(just_box)==shrink_order(q))&&
+(shrink(q)!=0))
+v= max_dimen;
+}
+if(subtype(p)>=a_leaders)goto found;
+}
+
+/*:1148*/
+#line 21804 "tex.w"
+break;
+case whatsit_node:/*1361:*/
+#line 24797 "tex.w"
+d= 0
+
+/*:1361*/
+#line 21805 "tex.w"
+;break;
+default:d= 0;
+}
+
+/*:1147*/
+#line 21781 "tex.w"
+;
+if(v<max_dimen)v= v+d;
+goto not_found;
+found:if(v<max_dimen)
+{v= v+d;w= v;
+}
+else{w= max_dimen;goto done;
+}
+not_found:p= link(p);
+}
+done:
+
+/*:1146*/
+#line 21763 "tex.w"
+;
+}
+
+/*1149:*/
+#line 21833 "tex.w"
+
+if(par_shape_ptr==null)
+if((hang_indent!=0)&&
+(((hang_after>=0)&&(prev_graf+2> hang_after))||
+(prev_graf+1<-hang_after)))
+{l= hsize-abs(hang_indent);
+if(hang_indent> 0)s= hang_indent;else s= 0;
+}
+else{l= hsize;s= 0;
+}
+else{n= info(par_shape_ptr);
+if(prev_graf+2>=n)p= par_shape_ptr+2*n;
+else p= par_shape_ptr+2*(prev_graf+2);
+s= mem[p-1].sc;l= mem[p].sc;
+}
+
+/*:1149*/
+#line 21766 "tex.w"
+;
+push_math(math_shift_group);mode= mmode;
+eq_word_define(int_base+cur_fam_code,-1);
+eq_word_define(dimen_base+pre_display_size_code,w);
+eq_word_define(dimen_base+display_width_code,l);
+eq_word_define(dimen_base+display_indent_code,s);
+if(every_display!=null)begin_token_list(every_display,every_display_text);
+if(nest_ptr==1)build_page();
+}
+
+/*:1145*/
+#line 21711 "tex.w"
+
+else{back_input();/*1139:*/
+#line 21716 "tex.w"
+
+{push_math(math_shift_group);eq_word_define(int_base+cur_fam_code,-1);
+if(every_math!=null)begin_token_list(every_math,every_math_text);
+}
+
+/*:1139*/
+#line 21712 "tex.w"
+;
+}
+}
+
+/*:1138*//*1142:*/
+#line 21740 "tex.w"
+
+void start_eq_no(void)
+{saved(0)= cur_chr;incr(save_ptr);
+/*1139:*/
+#line 21716 "tex.w"
+
+{push_math(math_shift_group);eq_word_define(int_base+cur_fam_code,-1);
+if(every_math!=null)begin_token_list(every_math,every_math_text);
+}
+
+/*:1139*/
+#line 21743 "tex.w"
+;
+}
+
+/*:1142*//*1151:*/
+#line 21877 "tex.w"
+
+void scan_math(pointer p)
+{
+int c;
+restart:/*404:*/
+#line 8257 "tex.w"
+
+do{get_x_token();
+}while(!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+/*:404*/
+#line 21881 "tex.w"
+;
+reswitch:switch(cur_cmd){
+case letter:case other_char:case char_given:{c= ho(math_code(cur_chr));
+if(c==0100000)
+{/*1152:*/
+#line 21906 "tex.w"
+
+{cur_cs= cur_chr+active_base;
+cur_cmd= eq_type(cur_cs);cur_chr= equiv(cur_cs);
+x_token();back_input();
+}
+
+/*:1152*/
+#line 21885 "tex.w"
+;
+goto restart;
+}
+}break;
+case char_num:{scan_char_num();cur_chr= cur_val;cur_cmd= char_given;
+goto reswitch;
+}
+case math_char_num:{scan_fifteen_bit_int();c= cur_val;
+}break;
+case math_given:c= cur_chr;break;
+case delim_num:{scan_twenty_seven_bit_int();c= cur_val/010000;
+}break;
+default:/*1153:*/
+#line 21915 "tex.w"
+
+{back_input();scan_left_brace();
+saved(0)= p;incr(save_ptr);push_math(math_group);return;
+}
+
+/*:1153*/
+#line 21897 "tex.w"
+
+}
+math_type(p)= math_char;character(p)= qi(c%256);
+if((c>=var_code)&&fam_in_range)fam(p)= cur_fam;
+else fam(p)= (c/256)%16;
+}
+
+/*:1151*//*1155:*/
+#line 21945 "tex.w"
+
+void set_math_char(int c)
+{pointer p;
+if(c>=0100000)
+/*1152:*/
+#line 21906 "tex.w"
+
+{cur_cs= cur_chr+active_base;
+cur_cmd= eq_type(cur_cs);cur_chr= equiv(cur_cs);
+x_token();back_input();
+}
+
+/*:1152*/
+#line 21949 "tex.w"
+
+else{p= new_noad();math_type(nucleus(p))= math_char;
+character(nucleus(p))= qi(c%256);
+fam(nucleus(p))= (c/256)%16;
+if(c>=var_code)
+{if(fam_in_range)fam(nucleus(p))= cur_fam;
+type(p)= ord_noad;
+}
+else type(p)= ord_noad+(c/010000);
+link(tail)= p;tail= p;
+}
+}
+
+/*:1155*//*1159:*/
+#line 22017 "tex.w"
+
+void math_limit_switch(void)
+{
+if(head!=tail)if(type(tail)==op_noad)
+{subtype(tail)= cur_chr;return;
+}
+print_err("Limit controls must follow a math operator");
+
+help1("I'm ignoring this misplaced \\limits or \\nolimits command.");error();
+}
+
+/*:1159*//*1160:*/
+#line 22033 "tex.w"
+
+void scan_delimiter(pointer p,bool r)
+{if(r)scan_twenty_seven_bit_int();
+else{/*404:*/
+#line 8257 "tex.w"
+
+do{get_x_token();
+}while(!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+/*:404*/
+#line 22036 "tex.w"
+;
+switch(cur_cmd){
+case letter:case other_char:cur_val= del_code(cur_chr);break;
+case delim_num:scan_twenty_seven_bit_int();break;
+default:cur_val= -1;
+}
+}
+if(cur_val<0)/*1161:*/
+#line 22051 "tex.w"
+
+{print_err("Missing delimiter (. inserted)");
+
+help6("I was expecting to see something like `(' or `\\{' or")
+("`\\}' here. If you typed, e.g., `{' instead of `\\{', you")
+("should probably delete the `{' by typing `1' now, so that")
+("braces don't get unbalanced. Otherwise just proceed.")
+("Acceptable delimiters are characters whose \\delcode is")
+("nonnegative, or you can use `\\delimiter <delimiter code>'.");
+back_error();cur_val= 0;
+}
+
+/*:1161*/
+#line 22044 "tex.w"
+;
+small_fam(p)= (cur_val/04000000)%16;
+small_char(p)= qi((cur_val/010000)%256);
+large_fam(p)= (cur_val/256)%16;
+large_char(p)= qi(cur_val%256);
+}
+
+/*:1160*//*1163:*/
+#line 22066 "tex.w"
+
+void math_radical(void)
+{tail_append(get_node(radical_noad_size));
+type(tail)= radical_noad;subtype(tail)= normal;
+mem[nucleus(tail)].hh= empty_field;
+mem[subscr(tail)].hh= empty_field;
+mem[supscr(tail)].hh= empty_field;
+scan_delimiter(left_delimiter(tail),true);scan_math(nucleus(tail));
+}
+
+/*:1163*//*1165:*/
+#line 22079 "tex.w"
+
+void math_ac(void)
+{if(cur_cmd==accent)
+/*1166:*/
+#line 22096 "tex.w"
+
+{print_err("Please use ");print_esc(/*1545:*/
+#line 25531 "tex.w"
+420
+/*:1545*/
+#line 22097 "tex.w"
+);
+print_str(" for accents in math mode");
+
+help2("I'm changing \\accent to \\mathaccent here; wish me luck.")
+("(Accents are not the same in formulas as they are in text.)");
+error();
+}
+
+/*:1166*/
+#line 22082 "tex.w"
+;
+tail_append(get_node(accent_noad_size));
+type(tail)= accent_noad;subtype(tail)= normal;
+mem[nucleus(tail)].hh= empty_field;
+mem[subscr(tail)].hh= empty_field;
+mem[supscr(tail)].hh= empty_field;
+math_type(accent_chr(tail))= math_char;
+scan_fifteen_bit_int();
+character(accent_chr(tail))= qi(cur_val%256);
+if((cur_val>=var_code)&&fam_in_range)fam(accent_chr(tail))= cur_fam;
+else fam(accent_chr(tail))= (cur_val/256)%16;
+scan_math(nucleus(tail));
+}
+
+/*:1165*//*1172:*/
+#line 22143 "tex.w"
+
+void append_choices(void)
+{tail_append(new_choice());incr(save_ptr);saved(-1)= 0;
+push_math(math_choice_group);scan_left_brace();
+}
+
+/*:1172*//*1174:*/
+#line 22152 "tex.w"
+
+/*1184:*/
+#line 22297 "tex.w"
+
+pointer fin_mlist(pointer p)
+{pointer q;
+if(incompleat_noad!=null)/*1185:*/
+#line 22306 "tex.w"
+
+{math_type(denominator(incompleat_noad))= sub_mlist;
+info(denominator(incompleat_noad))= link(head);
+if(p==null)q= incompleat_noad;
+else{q= info(numerator(incompleat_noad));
+if(type(q)!=left_noad)confusion(/*1660:*/
+#line 25876 "tex.w"
+535
+/*:1660*/
+#line 22311 "tex.w"
+);
+
+info(numerator(incompleat_noad))= link(q);
+link(q)= incompleat_noad;link(incompleat_noad)= p;
+}
+}
+
+/*:1185*/
+#line 22300 "tex.w"
+
+else{link(tail)= p;q= link(head);
+}
+pop_nest();return q;
+}
+
+/*:1184*/
+#line 22153 "tex.w"
+
+void build_choices(void)
+{
+pointer p;
+unsave();p= fin_mlist(null);
+switch(saved(-1)){
+case 0:display_mlist(tail)= p;break;
+case 1:text_mlist(tail)= p;break;
+case 2:script_mlist(tail)= p;break;
+case 3:{script_script_mlist(tail)= p;decr(save_ptr);return;
+}
+}
+incr(saved(-1));push_math(math_choice_group);scan_left_brace();
+}
+
+/*:1174*//*1176:*/
+#line 22176 "tex.w"
+
+void sub_sup(void)
+{small_number t;
+pointer p;
+t= empty;p= null;
+if(tail!=head)if(scripts_allowed(tail))
+{p= supscr(tail)+cur_cmd-sup_mark;
+t= math_type(p);
+}
+if((p==null)||(t!=empty))/*1177:*/
+#line 22189 "tex.w"
+
+{tail_append(new_noad());
+p= supscr(tail)+cur_cmd-sup_mark;
+if(t!=empty)
+{if(cur_cmd==sup_mark)
+{print_err("Double superscript");
+
+help1("I treat `x^1^2' essentially like `x^1{}^2'.");
+}
+else{print_err("Double subscript");
+
+help1("I treat `x_1_2' essentially like `x_1{}_2'.");
+}
+error();
+}
+}
+
+/*:1177*/
+#line 22185 "tex.w"
+;
+scan_math(p);
+}
+
+/*:1176*//*1181:*/
+#line 22246 "tex.w"
+
+void math_fraction(void)
+{small_number c;
+c= cur_chr;
+if(incompleat_noad!=null)
+/*1183:*/
+#line 22278 "tex.w"
+
+{if(c>=delimited_code)
+{scan_delimiter(garbage,false);scan_delimiter(garbage,false);
+}
+if(c%delimited_code==above_code)scan_normal_dimen;
+print_err("Ambiguous; you need another { and }");
+
+help3("I'm ignoring this fraction specification, since I don't")
+("know whether a construction like `x \\over y \\over z'")
+("means `{x \\over y} \\over z' or `x \\over {y \\over z}'.");
+error();
+}
+
+/*:1183*/
+#line 22251 "tex.w"
+
+else{incompleat_noad= get_node(fraction_noad_size);
+type(incompleat_noad)= fraction_noad;
+subtype(incompleat_noad)= normal;
+math_type(numerator(incompleat_noad))= sub_mlist;
+info(numerator(incompleat_noad))= link(head);
+mem[denominator(incompleat_noad)].hh= empty_field;
+mem[left_delimiter(incompleat_noad)].qqqq= null_delimiter;
+mem[right_delimiter(incompleat_noad)].qqqq= null_delimiter;
+link(head)= null;tail= head;
+/*1182:*/
+#line 22265 "tex.w"
+
+if(c>=delimited_code)
+{scan_delimiter(left_delimiter(incompleat_noad),false);
+scan_delimiter(right_delimiter(incompleat_noad),false);
+}
+switch(c%delimited_code){
+case above_code:{scan_normal_dimen;
+thickness(incompleat_noad)= cur_val;
+}break;
+case over_code:thickness(incompleat_noad)= default_code;break;
+case atop_code:thickness(incompleat_noad)= 0;
+}
+
+/*:1182*/
+#line 22261 "tex.w"
+;
+}
+}
+
+/*:1181*//*1191:*/
+#line 22361 "tex.w"
+
+void math_left_right(void)
+{small_number t;
+pointer p;
+t= cur_chr;
+if((t==right_noad)&&(cur_group!=math_left_group))
+/*1192:*/
+#line 22381 "tex.w"
+
+{if(cur_group==math_shift_group)
+{scan_delimiter(garbage,false);
+print_err("Extra ");print_esc(/*1660:*/
+#line 25876 "tex.w"
+535
+/*:1660*/
+#line 22384 "tex.w"
+);
+
+help1("I'm ignoring a \\right that had no matching \\left.");
+error();
+}
+else off_save();
+}
+
+/*:1192*/
+#line 22367 "tex.w"
+
+else{p= new_noad();type(p)= t;
+scan_delimiter(delimiter(p),false);
+if(t==left_noad)
+{push_math(math_left_group);link(head)= p;tail= p;
+}
+else{p= fin_mlist(p);unsave();
+tail_append(new_noad());type(tail)= inner_noad;
+math_type(nucleus(tail))= sub_mlist;
+info(nucleus(tail))= p;
+}
+}
+}
+
+/*:1191*//*1194:*/
+#line 22398 "tex.w"
+
+void after_math(void)
+{bool l;
+bool danger;
+int m;
+pointer p;
+pointer a;
+/*1198:*/
+#line 22482 "tex.w"
+
+pointer b;
+scaled w;
+scaled z;
+scaled e;
+scaled q;
+scaled d;
+scaled s;
+small_number g1,g2;
+pointer r;
+pointer t;
+
+/*:1198*/
+#line 22405 "tex.w"
+
+danger= false;
+/*1195:*/
+#line 22428 "tex.w"
+
+if((font_params[fam_fnt(2+text_size)]<total_mathsy_params)||
+(font_params[fam_fnt(2+script_size)]<total_mathsy_params)||
+(font_params[fam_fnt(2+script_script_size)]<total_mathsy_params))
+{print_err("Math formula deleted: Insufficient symbol fonts");
+
+help3("Sorry, but I can't typeset math unless \\textfont 2")
+("and \\scriptfont 2 and \\scriptscriptfont 2 have all")
+("the \\fontdimen values needed in math symbol fonts.");
+error();flush_math();danger= true;
+}
+else if((font_params[fam_fnt(3+text_size)]<total_mathex_params)||
+(font_params[fam_fnt(3+script_size)]<total_mathex_params)||
+(font_params[fam_fnt(3+script_script_size)]<total_mathex_params))
+{print_err("Math formula deleted: Insufficient extension fonts");
+help3("Sorry, but I can't typeset math unless \\textfont 3")
+("and \\scriptfont 3 and \\scriptscriptfont 3 have all")
+("the \\fontdimen values needed in math extension fonts.");
+error();flush_math();danger= true;
+}
+
+/*:1195*/
+#line 22408 "tex.w"
+;
+m= mode;l= false;p= fin_mlist(null);
+if(mode==-m)
+{/*1197:*/
+#line 22467 "tex.w"
+
+{get_x_token();
+if(cur_cmd!=math_shift)
+{print_err("Display math should end with $$");
+
+help2("The `$' that I just saw supposedly matches a previous `$$'.")
+("So I shall assume that you typed `$$' both times.");
+back_error();
+}
+}
+
+/*:1197*/
+#line 22411 "tex.w"
+;
+cur_mlist= p;cur_style= text_style;mlist_penalties= false;
+mlist_to_hlist();a= hpack(link(temp_head),natural);
+unsave();decr(save_ptr);
+if(saved(0)==1)l= true;
+danger= false;
+/*1195:*/
+#line 22428 "tex.w"
+
+if((font_params[fam_fnt(2+text_size)]<total_mathsy_params)||
+(font_params[fam_fnt(2+script_size)]<total_mathsy_params)||
+(font_params[fam_fnt(2+script_script_size)]<total_mathsy_params))
+{print_err("Math formula deleted: Insufficient symbol fonts");
+
+help3("Sorry, but I can't typeset math unless \\textfont 2")
+("and \\scriptfont 2 and \\scriptscriptfont 2 have all")
+("the \\fontdimen values needed in math symbol fonts.");
+error();flush_math();danger= true;
+}
+else if((font_params[fam_fnt(3+text_size)]<total_mathex_params)||
+(font_params[fam_fnt(3+script_size)]<total_mathex_params)||
+(font_params[fam_fnt(3+script_script_size)]<total_mathex_params))
+{print_err("Math formula deleted: Insufficient extension fonts");
+help3("Sorry, but I can't typeset math unless \\textfont 3")
+("and \\scriptfont 3 and \\scriptscriptfont 3 have all")
+("the \\fontdimen values needed in math extension fonts.");
+error();flush_math();danger= true;
+}
+
+/*:1195*/
+#line 22418 "tex.w"
+;
+m= mode;p= fin_mlist(null);
+}
+else a= null;
+if(m<0)/*1196:*/
+#line 22455 "tex.w"
+
+{tail_append(new_math(math_surround,before));
+cur_mlist= p;cur_style= text_style;mlist_penalties= (mode> 0);mlist_to_hlist();
+link(tail)= link(temp_head);
+while(link(tail)!=null)tail= link(tail);
+tail_append(new_math(math_surround,after));
+space_factor= 1000;unsave();
+}
+
+/*:1196*/
+#line 22422 "tex.w"
+
+else{if(a==null)/*1197:*/
+#line 22467 "tex.w"
+
+{get_x_token();
+if(cur_cmd!=math_shift)
+{print_err("Display math should end with $$");
+
+help2("The `$' that I just saw supposedly matches a previous `$$'.")
+("So I shall assume that you typed `$$' both times.");
+back_error();
+}
+}
+
+/*:1197*/
+#line 22423 "tex.w"
+;
+/*1199:*/
+#line 22498 "tex.w"
+
+cur_mlist= p;cur_style= display_style;mlist_penalties= false;
+mlist_to_hlist();p= link(temp_head);
+adjust_tail= adjust_head;b= hpack(p,natural);p= list_ptr(b);
+t= adjust_tail;adjust_tail= null;
+w= width(b);z= display_width;s= display_indent;
+if((a==null)||danger)
+{e= 0;q= 0;
+}
+else{e= width(a);q= e+math_quad(text_size);
+}
+if(w+q> z)
+/*1201:*/
+#line 22534 "tex.w"
+
+{if((e!=0)&&((w-total_shrink[normal]+q<=z)||
+(total_shrink[fil]!=0)||(total_shrink[fill]!=0)||
+(total_shrink[filll]!=0)))
+{free_node(b,box_node_size);
+b= hpack(p,z-q,exactly);
+}
+else{e= 0;
+if(w> z)
+{free_node(b,box_node_size);
+b= hpack(p,z,exactly);
+}
+}
+w= width(b);
+}
+
+/*:1201*/
+#line 22511 "tex.w"
+;
+/*1202:*/
+#line 22558 "tex.w"
+
+d= half(z-w);
+if((e> 0)&&(d<2*e))
+{d= half(z-w-e);
+if(p!=null)if(!is_char_node(p))if(type(p)==glue_node)d= 0;
+}
+
+/*:1202*/
+#line 22513 "tex.w"
+;
+/*1203:*/
+#line 22571 "tex.w"
+
+tail_append(new_penalty(pre_display_penalty));
+if((d+s<=pre_display_size)||l)
+{g1= above_display_skip_code;g2= below_display_skip_code;
+}
+else{g1= above_display_short_skip_code;
+g2= below_display_short_skip_code;
+}
+if(l&&(e==0))
+{shift_amount(a)= s;append_to_vlist(a);
+tail_append(new_penalty(inf_penalty));
+}
+else tail_append(new_param_glue(g1))
+
+/*:1203*/
+#line 22514 "tex.w"
+;
+/*1204:*/
+#line 22585 "tex.w"
+
+if(e!=0)
+{r= new_kern(z-w-e-d);
+if(l)
+{link(a)= r;link(r)= b;b= a;d= 0;
+}
+else{link(b)= r;link(r)= a;
+}
+b= hpack(b,natural);
+}
+shift_amount(b)= s+d;append_to_vlist(b)
+
+/*:1204*/
+#line 22515 "tex.w"
+;
+/*1205:*/
+#line 22597 "tex.w"
+
+if((a!=null)&&(e==0)&&!l)
+{tail_append(new_penalty(inf_penalty));
+shift_amount(a)= s+z-width(a);
+append_to_vlist(a);
+g2= 0;
+}
+if(t!=adjust_head)
+{link(tail)= link(adjust_head);tail= t;
+}
+tail_append(new_penalty(post_display_penalty));
+if(g2> 0)tail_append(new_param_glue(g2))
+
+/*:1205*/
+#line 22516 "tex.w"
+;
+resume_after_display()
+
+/*:1199*/
+#line 22424 "tex.w"
+;
+}
+}
+
+/*:1194*//*1200:*/
+#line 22519 "tex.w"
+
+void resume_after_display(void)
+{if(cur_group!=math_shift_group)confusion(/*1742:*/
+#line 26122 "tex.w"
+617
+/*:1742*/
+#line 22521 "tex.w"
+);
+
+unsave();prev_graf= prev_graf+3;
+push_nest();mode= hmode;space_factor= 1000;set_cur_lang;clang= cur_lang;
+prev_graf= (norm_min(left_hyphen_min)*0100+norm_min(right_hyphen_min))
+*0200000+cur_lang;
+/*443:*/
+#line 8804 "tex.w"
+
+{get_x_token();if(cur_cmd!=spacer)back_input();
+}
+
+/*:443*/
+#line 22527 "tex.w"
+;
+if(nest_ptr==1)build_page();
+}
+
+/*:1200*//*1211:*/
+#line 22716 "tex.w"
+
+/*1215:*/
+#line 22781 "tex.w"
+
+void get_r_token(void)
+{
+restart:do{get_token();
+}while(!(cur_tok!=space_token));
+if((cur_cs==0)||(cur_cs> frozen_control_sequence))
+{print_err("Missing control sequence inserted");
+
+help5("Please don't say `\\def cs{...}', say `\\def\\cs{...}'.")
+("I've inserted an inaccessible control sequence so that your")
+("definition will be completed without mixing me up too badly.")
+("You can recover graciously from this error, if you're")
+("careful; see exercise 27.2 in The TeXbook.");
+
+if(cur_cs==0)back_input();
+cur_tok= cs_token_flag+frozen_protection;ins_error();goto restart;
+}
+}
+
+/*:1215*//*1229:*/
+#line 22992 "tex.w"
+
+void trap_zero_glue(void)
+{if((width(cur_val)==0)&&(stretch(cur_val)==0)&&(shrink(cur_val)==0))
+{add_glue_ref(zero_glue);
+delete_glue_ref(cur_val);cur_val= zero_glue;
+}
+}
+
+/*:1229*//*1236:*/
+#line 23072 "tex.w"
+
+void do_register_command(small_number a)
+{
+pointer l,q,r,s;
+uint8_t p;
+q= cur_cmd;
+/*1237:*/
+#line 23101 "tex.w"
+
+{if(q!=register)
+{get_x_token();
+if((cur_cmd>=assign_int)&&(cur_cmd<=assign_mu_glue))
+{l= cur_chr;p= cur_cmd-assign_int;goto found;
+}
+if(cur_cmd!=register)
+{print_err("You can't use `");print_cmd_chr(cur_cmd,cur_chr);
+
+print_str("' after ");print_cmd_chr(q,0);
+help1("I'm forgetting what you said and not changing anything.");
+error();return;
+}
+}
+p= cur_chr;scan_eight_bit_int();
+switch(p){
+case int_val:l= cur_val+count_base;break;
+case dimen_val:l= cur_val+scaled_base;break;
+case glue_val:l= cur_val+skip_base;break;
+case mu_val:l= cur_val+mu_skip_base;
+}
+}
+found:
+
+/*:1237*/
+#line 23078 "tex.w"
+;
+if(q==register)scan_optional_equals();
+else if(scan_keyword(/*1761:*/
+#line 26179 "tex.w"
+636
+/*:1761*/
+#line 23080 "tex.w"
+))do_nothing;
+
+arith_error= false;
+if(q<multiply)/*1238:*/
+#line 23125 "tex.w"
+
+if(p<glue_val)
+{if(p==int_val)scan_int();else scan_normal_dimen;
+if(q==advance)cur_val= cur_val+eqtb[l].i;
+}
+else{scan_glue(p);
+if(q==advance)/*1239:*/
+#line 23134 "tex.w"
+
+{q= new_spec(cur_val);r= equiv(l);
+delete_glue_ref(cur_val);
+width(q)= width(q)+width(r);
+if(stretch(q)==0)stretch_order(q)= normal;
+if(stretch_order(q)==stretch_order(r))stretch(q)= stretch(q)+stretch(r);
+else if((stretch_order(q)<stretch_order(r))&&(stretch(r)!=0))
+{stretch(q)= stretch(r);stretch_order(q)= stretch_order(r);
+}
+if(shrink(q)==0)shrink_order(q)= normal;
+if(shrink_order(q)==shrink_order(r))shrink(q)= shrink(q)+shrink(r);
+else if((shrink_order(q)<shrink_order(r))&&(shrink(r)!=0))
+{shrink(q)= shrink(r);shrink_order(q)= shrink_order(r);
+}
+cur_val= q;
+}
+
+/*:1239*/
+#line 23131 "tex.w"
+;
+}
+
+/*:1238*/
+#line 23083 "tex.w"
+
+else/*1240:*/
+#line 23151 "tex.w"
+
+{scan_int();
+if(p<glue_val)
+if(q==multiply)
+if(p==int_val)cur_val= mult_integers(eqtb[l].i,cur_val);
+else cur_val= nx_plus_y(eqtb[l].i,cur_val,0);
+else cur_val= x_over_n(eqtb[l].i,cur_val);
+else{s= equiv(l);r= new_spec(s);
+if(q==multiply)
+{width(r)= nx_plus_y(width(s),cur_val,0);
+stretch(r)= nx_plus_y(stretch(s),cur_val,0);
+shrink(r)= nx_plus_y(shrink(s),cur_val,0);
+}
+else{width(r)= x_over_n(width(s),cur_val);
+stretch(r)= x_over_n(stretch(s),cur_val);
+shrink(r)= x_over_n(shrink(s),cur_val);
+}
+cur_val= r;
+}
+}
+
+/*:1240*/
+#line 23084 "tex.w"
+;
+if(arith_error)
+{print_err("Arithmetic overflow");
+
+help2("I can't carry out that multiplication or division,")
+("since the result is out of range.");
+if(p>=glue_val)delete_glue_ref(cur_val);
+error();return;
+}
+if(p<glue_val)word_define(l,cur_val);
+else{trap_zero_glue();define(l,glue_ref,cur_val);
+}
+}
+
+/*:1236*//*1243:*/
+#line 23203 "tex.w"
+
+void alter_aux(void)
+{halfword c;
+if(cur_chr!=abs(mode))report_illegal_case();
+else{c= cur_chr;scan_optional_equals();
+if(c==vmode)
+{scan_normal_dimen;prev_depth= cur_val;
+}
+else{scan_int();
+if((cur_val<=0)||(cur_val> 32767))
+{print_err("Bad space factor");
+
+help1("I allow only values in the range 1..32767 here.");
+int_error(cur_val);
+}
+else space_factor= cur_val;
+}
+}
+}
+
+/*:1243*//*1244:*/
+#line 23223 "tex.w"
+
+void alter_prev_graf(void)
+{uint8_t p;
+nest[nest_ptr]= cur_list;p= nest_ptr;
+while(abs(nest[p].mode_field)!=vmode)decr(p);
+scan_optional_equals();scan_int();
+if(cur_val<0)
+{print_err("Bad ");print_esc(/*1554:*/
+#line 25558 "tex.w"
+429
+/*:1554*/
+#line 23230 "tex.w"
+);
+
+help1("I allow only nonnegative values here.");
+int_error(cur_val);
+}
+else{nest[p].pg_field= cur_val;cur_list= nest[nest_ptr];
+}
+}
+
+/*:1244*//*1245:*/
+#line 23239 "tex.w"
+
+void alter_page_so_far(void)
+{uint8_t c;
+c= cur_chr;scan_optional_equals();scan_normal_dimen;
+page_so_far[c]= cur_val;
+}
+
+/*:1245*//*1246:*/
+#line 23246 "tex.w"
+
+void alter_integer(void)
+{uint8_t c;
+c= cur_chr;scan_optional_equals();scan_int();
+if(c==0)dead_cycles= cur_val;
+else insert_penalties= cur_val;
+}
+
+/*:1246*//*1247:*/
+#line 23254 "tex.w"
+
+void alter_box_dimen(void)
+{small_number c;
+eight_bits b;
+c= cur_chr;scan_eight_bit_int();b= cur_val;scan_optional_equals();
+scan_normal_dimen;
+if(box(b)!=null)mem[box(b)+c].sc= cur_val;
+}
+
+/*:1247*//*1257:*/
+#line 23340 "tex.w"
+
+void new_font(small_number a)
+{
+pointer u;
+scaled s;
+int f;
+str_number t;
+uint8_t old_setting;
+str_number flushable_string;
+if(job_name==0)open_log_file();
+
+
+get_r_token();u= cur_cs;
+if(u>=hash_base)t= text(u);
+else if(u>=single_base)
+if(u==null_cs)t= /*1764:*/
+#line 26188 "tex.w"
+639
+/*:1764*/
+#line 23355 "tex.w"
+;else t= u-single_base;
+else{old_setting= selector;selector= new_string;
+print_str("FONT");print(u-active_base);selector= old_setting;
+
+str_room(1);t= make_string();
+}
+define(u,set_font,null_font);scan_optional_equals();scan_file_name();
+/*1258:*/
+#line 23369 "tex.w"
+
+name_in_progress= true;
+if(scan_keyword(/*1765:*/
+#line 26191 "tex.w"
+640
+/*:1765*/
+#line 23371 "tex.w"
+))/*1259:*/
+#line 23386 "tex.w"
+
+{scan_normal_dimen;s= cur_val;
+if((s<=0)||(s>=01000000000))
+{print_err("Improper `at' size (");
+print_scaled(s);print_str("pt), replaced by 10pt");
+
+help2("I can only handle fonts at positive sizes that are")
+("less than 2048pt, so I've changed what you said to 10pt.");
+error();s= 10*unity;
+}
+}
+
+/*:1259*/
+#line 23371 "tex.w"
+
+
+else if(scan_keyword(/*1766:*/
+#line 26194 "tex.w"
+641
+/*:1766*/
+#line 23373 "tex.w"
+))
+
+{scan_int();s= -cur_val;
+if((cur_val<=0)||(cur_val> 32768))
+{print_err("Illegal magnification has been changed to 1000");
+
+help1("The magnification ratio must be between 1 and 32768.");
+int_error(cur_val);s= -1000;
+}
+}
+else s= -1000;
+name_in_progress= false
+
+/*:1258*/
+#line 23362 "tex.w"
+;
+/*1260:*/
+#line 23402 "tex.w"
+
+flushable_string= str_ptr-1;
+for(f= font_base+1;f<=font_ptr;f++)
+if(str_eq_str(font_name[f],cur_name)&&str_eq_str(font_area[f],cur_area))
+{if(cur_name==flushable_string)
+{flush_string;cur_name= font_name[f];
+}
+if(s> 0)
+{if(s==font_size[f])goto common_ending;
+}
+else if(font_size[f]==xn_over_d(font_dsize[f],-s,1000))
+goto common_ending;
+}
+
+/*:1260*/
+#line 23364 "tex.w"
+;
+f= read_font_info(u,cur_name,cur_area,s);
+common_ending:equiv(u)= f;eqtb[font_id_base+f]= eqtb[u];font_id_text(f)= t;
+}
+
+/*:1257*//*1265:*/
+#line 23445 "tex.w"
+
+void new_interaction(void)
+{print_ln();
+interaction= cur_chr;
+/*75:*/
+#line 1788 "tex.w"
+
+if(interaction==batch_mode)selector= no_print;else selector= term_only
+
+/*:75*/
+#line 23449 "tex.w"
+;
+if(log_opened)selector= selector+2;
+}
+
+/*:1265*/
+#line 22717 "tex.w"
+
+void prefixed_command(void)
+{
+small_number a;
+internal_font_number f;
+int j;
+font_index k;
+pointer p,q;
+int n;
+bool e;
+a= 0;
+while(cur_cmd==prefix)
+{if(!odd(a/cur_chr))a= a+cur_chr;
+/*404:*/
+#line 8257 "tex.w"
+
+do{get_x_token();
+}while(!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+/*:404*/
+#line 22730 "tex.w"
+;
+if(cur_cmd<=max_non_prefixed_command)
+/*1212:*/
+#line 22744 "tex.w"
+
+{print_err("You can't use a prefix with `");
+
+print_cmd_chr(cur_cmd,cur_chr);print_char('\'');
+help1("I'll pretend you didn't say \\long or \\outer or \\global.");
+back_error();return;
+}
+
+/*:1212*/
+#line 22732 "tex.w"
+;
+}
+/*1213:*/
+#line 22752 "tex.w"
+
+if((cur_cmd!=def)&&(a%4!=0))
+{print_err("You can't use `");print_esc(/*1743:*/
+#line 26125 "tex.w"
+618
+/*:1743*/
+#line 22754 "tex.w"
+);print_str("' or `");
+print_esc(/*1744:*/
+#line 26128 "tex.w"
+619
+/*:1744*/
+#line 22755 "tex.w"
+);print_str("' with `");
+
+print_cmd_chr(cur_cmd,cur_chr);print_char('\'');
+help1("I'll pretend you didn't say \\long or \\outer here.");
+error();
+}
+
+/*:1213*/
+#line 22734 "tex.w"
+;
+/*1214:*/
+#line 22769 "tex.w"
+
+if(global_defs!=0)
+if(global_defs<0)
+{if(global)a= a-4;
+}
+else{if(!global)a= a+4;
+}
+
+/*:1214*/
+#line 22735 "tex.w"
+;
+switch(cur_cmd){
+/*1217:*/
+#line 22806 "tex.w"
+
+case set_font:define(cur_font_loc,data,cur_chr);break;
+
+/*:1217*//*1218:*/
+#line 22813 "tex.w"
+
+case def:{if(odd(cur_chr)&&!global&&(global_defs>=0))a= a+4;
+e= (cur_chr>=2);get_r_token();p= cur_cs;
+q= scan_toks(true,e);define(p,call+(a%4),def_ref);
+}break;
+
+/*:1218*//*1221:*/
+#line 22830 "tex.w"
+
+case let:{n= cur_chr;
+get_r_token();p= cur_cs;
+if(n==normal)
+{do{get_token();
+}while(!(cur_cmd!=spacer));
+if(cur_tok==other_token+'=')
+{get_token();
+if(cur_cmd==spacer)get_token();
+}
+}
+else{get_token();q= cur_tok;get_token();back_input();
+cur_tok= q;back_input();
+}
+if(cur_cmd>=call)add_token_ref(cur_chr);
+define(p,cur_cmd,cur_chr);
+}break;
+
+/*:1221*//*1224:*/
+#line 22899 "tex.w"
+
+case shorthand_def:{n= cur_chr;get_r_token();p= cur_cs;define(p,relax,256);
+scan_optional_equals();
+switch(n){
+case char_def_code:{scan_char_num();define(p,char_given,cur_val);
+}break;
+case math_char_def_code:{scan_fifteen_bit_int();define(p,math_given,cur_val);
+}break;
+default:{scan_eight_bit_int();
+switch(n){
+case count_def_code:define(p,assign_int,count_base+cur_val);break;
+case dimen_def_code:define(p,assign_dimen,scaled_base+cur_val);break;
+case skip_def_code:define(p,assign_glue,skip_base+cur_val);break;
+case mu_skip_def_code:define(p,assign_mu_glue,mu_skip_base+cur_val);break;
+case toks_def_code:define(p,assign_toks,toks_base+cur_val);
+}
+}
+}
+}break;
+
+/*:1224*//*1225:*/
+#line 22919 "tex.w"
+
+case read_to_cs:{scan_int();n= cur_val;
+if(!scan_keyword(/*1642:*/
+#line 25822 "tex.w"
+517
+/*:1642*/
+#line 22921 "tex.w"
+))
+
+{print_err("Missing `to' inserted");
+
+help2("You should have said `\\read<number> to \\cs'.")
+("I'm going to look for the \\cs now.");error();
+}
+get_r_token();
+p= cur_cs;read_toks(n,p);define(p,call,cur_val);
+}break;
+
+/*:1225*//*1226:*/
+#line 22936 "tex.w"
+
+case toks_register:case assign_toks:{q= cur_cs;
+if(cur_cmd==toks_register)
+{scan_eight_bit_int();p= toks_base+cur_val;
+}
+else p= cur_chr;
+scan_optional_equals();
+/*404:*/
+#line 8257 "tex.w"
+
+do{get_x_token();
+}while(!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+/*:404*/
+#line 22943 "tex.w"
+;
+if(cur_cmd!=left_brace)/*1227:*/
+#line 22960 "tex.w"
+
+{if(cur_cmd==toks_register)
+{scan_eight_bit_int();cur_cmd= assign_toks;cur_chr= toks_base+cur_val;
+}
+if(cur_cmd==assign_toks)
+{q= equiv(cur_chr);
+if(q==null)define(p,undefined_cs,null);
+else{add_token_ref(q);define(p,call,q);
+}
+goto done;
+}
+}
+
+/*:1227*/
+#line 22945 "tex.w"
+;
+back_input();cur_cs= q;q= scan_toks(false,false);
+if(link(def_ref)==null)
+{define(p,undefined_cs,null);free_avail(def_ref);
+}
+else{if(p==output_routine_loc)
+{link(q)= get_avail();q= link(q);
+info(q)= right_brace_token+'}';
+q= get_avail();info(q)= left_brace_token+'{';
+link(q)= link(def_ref);link(def_ref)= q;
+}
+define(p,call,def_ref);
+}
+}break;
+
+/*:1226*//*1228:*/
+#line 22975 "tex.w"
+
+case assign_int:{p= cur_chr;scan_optional_equals();scan_int();
+word_define(p,cur_val);
+}break;
+case assign_dimen:{p= cur_chr;scan_optional_equals();
+scan_normal_dimen;word_define(p,cur_val);
+}break;
+case assign_glue:case assign_mu_glue:{p= cur_chr;n= cur_cmd;scan_optional_equals();
+if(n==assign_mu_glue)scan_glue(mu_val);else scan_glue(glue_val);
+trap_zero_glue();
+define(p,glue_ref,cur_val);
+}break;
+
+/*:1228*//*1232:*/
+#line 23035 "tex.w"
+
+case def_code:{/*1233:*/
+#line 23053 "tex.w"
+
+if(cur_chr==cat_code_base)n= max_char_code;
+else if(cur_chr==math_code_base)n= 0100000;
+else if(cur_chr==sf_code_base)n= 077777;
+else if(cur_chr==del_code_base)n= 077777777;
+else n= 255
+
+/*:1233*/
+#line 23036 "tex.w"
+;
+p= cur_chr;scan_char_num();p= p+cur_val;scan_optional_equals();
+scan_int();
+if(((cur_val<0)&&(p<del_code_base))||(cur_val> n))
+{print_err("Invalid code (");print_int(cur_val);
+
+if(p<del_code_base)print_str("), should be in the range 0..");
+else print_str("), should be at most ");
+print_int(n);
+help1("I'm going to use 0 instead of that illegal code value.");
+error();cur_val= 0;
+}
+if(p<math_code_base)define(p,data,cur_val);
+else if(p<del_code_base)define(p,data,hi(cur_val));
+else word_define(p,cur_val);
+}break;
+
+/*:1232*//*1234:*/
+#line 23060 "tex.w"
+
+case def_family:{p= cur_chr;scan_four_bit_int();p= p+cur_val;
+scan_optional_equals();scan_font_ident();define(p,data,cur_val);
+}break;
+
+/*:1234*//*1235:*/
+#line 23067 "tex.w"
+
+case register:case advance:case multiply:case divide:do_register_command(a);break;
+
+/*:1235*//*1241:*/
+#line 23176 "tex.w"
+
+case set_box:{scan_eight_bit_int();
+if(global)n= 256+cur_val;else n= cur_val;
+scan_optional_equals();
+if(set_box_allowed)scan_box(box_flag+n);
+else{print_err("Improper ");print_esc(/*1558:*/
+#line 25570 "tex.w"
+433
+/*:1558*/
+#line 23181 "tex.w"
+);
+
+help2("Sorry, \\setbox is not allowed after \\halign in a display,")
+("or between \\accent and an accented character.");error();
+}
+}break;
+
+/*:1241*//*1242:*/
+#line 23196 "tex.w"
+
+case set_aux:alter_aux();break;
+case set_prev_graf:alter_prev_graf();break;
+case set_page_dimen:alter_page_so_far();break;
+case set_page_int:alter_integer();break;
+case set_box_dimen:alter_box_dimen();break;
+
+/*:1242*//*1248:*/
+#line 23265 "tex.w"
+
+case set_shape:{scan_optional_equals();scan_int();n= cur_val;
+if(n<=0)p= null;
+else{p= get_node(2*n+1);info(p)= n;
+for(j= 1;j<=n;j++)
+{scan_normal_dimen;
+mem[p+2*j-1].sc= cur_val;
+scan_normal_dimen;
+mem[p+2*j].sc= cur_val;
+}
+}
+define(par_shape_loc,shape_ref,p);
+}break;
+
+/*:1248*//*1252:*/
+#line 23298 "tex.w"
+
+case hyph_data:if(cur_chr==1)
+{
+#ifdef INIT
+new_patterns();goto done;
+#endif
+print_err("Patterns can be loaded only by INITEX");
+
+help0;error();
+do{get_token();}while(!(cur_cmd==right_brace));
+return;
+}
+else{new_hyph_exceptions();goto done;
+}break;
+
+/*:1252*//*1253:*/
+#line 23316 "tex.w"
+
+case assign_font_dimen:{find_font_dimen(true);k= cur_val;
+scan_optional_equals();scan_normal_dimen;font_info[k].sc= cur_val;
+}break;
+case assign_font_int:{n= cur_chr;scan_font_ident();f= cur_val;
+scan_optional_equals();scan_int();
+if(n==0)hyphen_char[f]= cur_val;else skew_char[f]= cur_val;
+}break;
+
+/*:1253*//*1256:*/
+#line 23337 "tex.w"
+
+case def_font:new_font(a);break;
+
+/*:1256*//*1264:*/
+#line 23442 "tex.w"
+
+case set_interaction:new_interaction();break;
+
+/*:1264*/
+#line 22737 "tex.w"
+
+default:confusion(/*1750:*/
+#line 26146 "tex.w"
+625
+/*:1750*/
+#line 22738 "tex.w"
+);
+
+}
+done:/*1269:*/
+#line 23467 "tex.w"
+
+if(after_token!=0)
+{cur_tok= after_token;back_input();after_token= 0;
+}
+
+/*:1269*/
+#line 22741 "tex.w"
+;
+}
+
+/*:1211*//*1270:*/
+#line 23475 "tex.w"
+
+void do_assignments(void)
+{
+loop{/*404:*/
+#line 8257 "tex.w"
+
+do{get_x_token();
+}while(!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+/*:404*/
+#line 23478 "tex.w"
+;
+if(cur_cmd<=max_non_prefixed_command)return;
+set_box_allowed= false;prefixed_command();set_box_allowed= true;
+}
+}
+
+/*:1270*//*1275:*/
+#line 23503 "tex.w"
+
+void open_or_close_in(void)
+{uint8_t c;
+uint8_t n;
+c= cur_chr;scan_four_bit_int();n= cur_val;
+if(read_open[n]!=closed)
+{a_close(&read_file[n]);read_open[n]= closed;
+}
+if(c!=0)
+{scan_optional_equals();scan_file_name();
+if(cur_ext==empty_string)cur_ext= /*1637:*/
+#line 25807 "tex.w"
+512
+/*:1637*/
+#line 23513 "tex.w"
+;
+pack_cur_name;
+if(a_open_in(&read_file[n]))read_open[n]= just_open;
+}
+}
+
+/*:1275*//*1279:*/
+#line 23535 "tex.w"
+
+void issue_message(void)
+{uint8_t old_setting;
+uint8_t c;
+str_number s;
+c= cur_chr;link(garbage)= scan_toks(false,true);
+old_setting= selector;selector= new_string;
+token_show(def_ref);selector= old_setting;
+flush_list(def_ref);
+str_room(1);s= make_string();
+if(c==0)/*1280:*/
+#line 23550 "tex.w"
+
+{if(term_offset+length(s)> max_print_line-2)print_ln();
+else if((term_offset> 0)||(file_offset> 0))print_char(' ');
+slow_print(s);update_terminal;
+}
+
+/*:1280*/
+#line 23545 "tex.w"
+
+else/*1283:*/
+#line 23565 "tex.w"
+
+{print_err("");slow_print(s);
+if(err_help!=null)use_err_help= true;
+else if(long_help_seen)help1("(That was another \\errmessage.)")
+else{if(interaction<error_stop_mode)long_help_seen= true;
+help4("This error message was generated by an \\errmessage")
+("command, so I can't give any explicit help.")
+("Pretend that you're Hercule Poirot: Examine all clues,")
+
+("and deduce the truth by order and method.");
+}
+error();use_err_help= false;
+}
+
+/*:1283*/
+#line 23546 "tex.w"
+;
+flush_string;
+}
+
+/*:1279*//*1288:*/
+#line 23602 "tex.w"
+
+void shift_case(void)
+{pointer b;
+pointer p;
+halfword t;
+eight_bits c;
+b= cur_chr;p= scan_toks(false,false);p= link(def_ref);
+while(p!=null)
+{/*1289:*/
+#line 23621 "tex.w"
+
+t= info(p);
+if(t<cs_token_flag+single_base)
+{c= t%256;
+if(equiv(b+c)!=0)info(p)= t-c+equiv(b+c);
+}
+
+/*:1289*/
+#line 23610 "tex.w"
+;
+p= link(p);
+}
+back_list(link(def_ref));free_avail(def_ref);
+}
+
+/*:1288*//*1293:*/
+#line 23657 "tex.w"
+
+void show_whatever(void)
+{
+pointer p;
+switch(cur_chr){
+case show_lists:{begin_diagnostic();show_activities();
+}break;
+case show_box_code:/*1296:*/
+#line 23707 "tex.w"
+
+{scan_eight_bit_int();begin_diagnostic();
+print_nl("> \\box");print_int(cur_val);print_char('=');
+if(box(cur_val)==null)print_str("void");
+else show_box(box(cur_val));
+}
+
+/*:1296*/
+#line 23664 "tex.w"
+break;
+case show_code:/*1294:*/
+#line 23688 "tex.w"
+
+{get_token();
+if(interaction==error_stop_mode)wake_up_terminal;
+print_nl("> ");
+if(cur_cs!=0)
+{sprint_cs(cur_cs);print_char('=');
+}
+print_meaning();goto common_ending;
+}
+
+/*:1294*/
+#line 23665 "tex.w"
+
+default:/*1297:*/
+#line 23714 "tex.w"
+
+{p= the_toks();
+if(interaction==error_stop_mode)wake_up_terminal;
+print_nl("> ");token_show(temp_head);
+flush_list(link(temp_head));goto common_ending;
+}
+
+/*:1297*/
+#line 23666 "tex.w"
+
+}
+/*1298:*/
+#line 23721 "tex.w"
+
+end_diagnostic(true);print_err("OK");
+
+if(selector==term_and_log)if(tracing_online<=0)
+{selector= term_only;print_str(" (see the transcript file)");
+selector= term_and_log;
+}
+
+/*:1298*/
+#line 23668 "tex.w"
+;
+common_ending:if(interaction<error_stop_mode)
+{help0;decr(error_count);
+}
+else if(tracing_online> 0)
+{
+help3("This isn't an error message; I'm just \\showing something.")
+("Type `I\\show...' to show more (e.g., \\show\\cs,")
+("\\showthe\\count10, \\showbox255, \\showlists).");
+}
+else{
+help5("This isn't an error message; I'm just \\showing something.")
+("Type `I\\show...' to show more (e.g., \\show\\cs,")
+("\\showthe\\count10, \\showbox255, \\showlists).")
+("And type `I\\tracingonline=1\\show...' to show boxes and")
+("lists on your terminal as well as in the transcript file.");
+}
+error();
+}
+
+/*:1293*//*1302:*/
+#line 23755 "tex.w"
+
+#ifdef INIT
+void store_fmt_file(void)
+{
+int j,k,l;
+pointer p,q;
+int x;
+four_quarters w;
+/*1304:*/
+#line 23812 "tex.w"
+
+if(save_ptr!=0)
+{print_err("You can't dump inside a group");
+
+help1("`{...\\dump}' is a no-no.");succumb;
+}
+
+/*:1304*/
+#line 23763 "tex.w"
+;
+/*1328:*/
+#line 24208 "tex.w"
+
+selector= new_string;
+print_str(" (preloaded format=");print(job_name);print_char(' ');
+print_int(year);print_char('.');
+print_int(month);print_char('.');print_int(day);print_char(')');
+if(interaction==batch_mode)selector= log_only;
+else selector= term_and_log;
+str_room(1);
+format_ident= make_string();
+pack_job_name(format_extension);
+while(!w_open_out(&fmt_file))
+prompt_file_name("format file name",format_extension);
+print_nl("Beginning to dump on file ");
+
+slow_print(w_make_name_string(&fmt_file));flush_string;
+print_nl("");slow_print(format_ident)
+
+/*:1328*/
+#line 23765 "tex.w"
+;
+/*1307:*/
+#line 23849 "tex.w"
+
+dump_int(0);
+dump_int(mem_bot);
+dump_int(mem_top);
+dump_int(eqtb_size);
+dump_int(hash_prime);
+dump_int(hyph_size)
+
+/*:1307*/
+#line 23766 "tex.w"
+;
+/*1309:*/
+#line 23882 "tex.w"
+
+dump_int(pool_ptr);
+dump_int(str_ptr);
+for(k= 0;k<=str_ptr;k++)dump_int(str_start[k]);
+k= 0;
+while(k+4<pool_ptr)
+{dump_four_ASCII;k= k+4;
+}
+k= pool_ptr-4;dump_four_ASCII;
+print_ln();print_int(str_ptr);print_str(" strings of total length ");
+print_int(pool_ptr)
+
+/*:1309*/
+#line 23767 "tex.w"
+;
+/*1311:*/
+#line 23917 "tex.w"
+
+sort_avail();var_used= 0;
+dump_int(lo_mem_max);dump_int(rover);
+p= mem_bot;q= rover;x= 0;
+do{for(k= p;k<=q+1;k++)dump_wd(mem[k]);
+x= x+q+2-p;var_used= var_used+q-p;
+p= q+node_size(q);q= rlink(q);
+}while(!(q==rover));
+var_used= var_used+lo_mem_max-p;dyn_used= mem_end+1-hi_mem_min;
+for(k= p;k<=lo_mem_max;k++)dump_wd(mem[k]);
+x= x+lo_mem_max+1-p;
+dump_int(hi_mem_min);dump_int(avail);
+for(k= hi_mem_min;k<=mem_end;k++)dump_wd(mem[k]);
+x= x+mem_end+1-hi_mem_min;
+p= avail;
+while(p!=null)
+{decr(dyn_used);p= link(p);
+}
+dump_int(var_used);dump_int(dyn_used);
+print_ln();print_int(x);
+print_str(" memory locations dumped; current usage is ");
+print_int(var_used);print_char('&');print_int(dyn_used)
+
+/*:1311*/
+#line 23768 "tex.w"
+;
+/*1313:*/
+#line 23962 "tex.w"
+
+/*1315:*/
+#line 23980 "tex.w"
+
+k= active_base;
+do{j= k;
+while(j<int_base-1)
+{if((equiv(j)==equiv(j+1))&&(eq_type(j)==eq_type(j+1))&&
+(eq_level(j)==eq_level(j+1)))goto found1;
+incr(j);
+}
+l= int_base;goto done1;
+found1:incr(j);l= j;
+while(j<int_base-1)
+{if((equiv(j)!=equiv(j+1))||(eq_type(j)!=eq_type(j+1))||
+(eq_level(j)!=eq_level(j+1)))goto done1;
+incr(j);
+}
+done1:dump_int(l-k);
+while(k<l)
+{dump_wd(eqtb[k]);incr(k);
+}
+k= j+1;dump_int(k-l);
+}while(!(k==int_base))
+
+/*:1315*/
+#line 23963 "tex.w"
+;
+/*1316:*/
+#line 24002 "tex.w"
+
+do{j= k;
+while(j<eqtb_size)
+{if(eqtb[j].i==eqtb[j+1].i)goto found2;
+incr(j);
+}
+l= eqtb_size+1;goto done2;
+found2:incr(j);l= j;
+while(j<eqtb_size)
+{if(eqtb[j].i!=eqtb[j+1].i)goto done2;
+incr(j);
+}
+done2:dump_int(l-k);
+while(k<l)
+{dump_wd(eqtb[k]);incr(k);
+}
+k= j+1;dump_int(k-l);
+}while(!(k> eqtb_size))
+
+/*:1316*/
+#line 23964 "tex.w"
+;
+dump_int(par_loc);dump_int(write_loc);
+/*1318:*/
+#line 24038 "tex.w"
+
+dump_int(hash_used);cs_count= frozen_control_sequence-1-hash_used;
+for(p= hash_base;p<=hash_used;p++)if(text(p)!=0)
+{dump_int(p);dump_hh(hash[p]);incr(cs_count);
+}
+for(p= hash_used+1;p<=undefined_control_sequence-1;p++)dump_hh(hash[p]);
+dump_int(cs_count);
+print_ln();print_int(cs_count);print_str(" multiletter control sequences")
+
+/*:1318*/
+#line 23966 "tex.w"
+
+
+/*:1313*/
+#line 23769 "tex.w"
+;
+/*1320:*/
+#line 24054 "tex.w"
+
+dump_int(fmem_ptr);
+for(k= 0;k<=fmem_ptr-1;k++)dump_wd(font_info[k]);
+dump_int(font_ptr);
+for(k= null_font;k<=font_ptr;k++)
+/*1322:*/
+#line 24071 "tex.w"
+
+{dump_qqqq(font_check[k]);
+dump_int(font_size[k]);
+dump_int(font_dsize[k]);
+dump_int(font_params[k]);
+dump_int(hyphen_char[k]);
+dump_int(skew_char[k]);
+dump_int(font_name[k]);
+dump_int(font_area[k]);
+dump_int(font_bc[k]);
+dump_int(font_ec[k]);
+dump_int(char_base[k]);
+dump_int(width_base[k]);
+dump_int(height_base[k]);
+dump_int(depth_base[k]);
+dump_int(italic_base[k]);
+dump_int(lig_kern_base[k]);
+dump_int(kern_base[k]);
+dump_int(exten_base[k]);
+dump_int(param_base[k]);
+dump_int(font_glue[k]);
+dump_int(bchar_label[k]);
+dump_int(font_bchar[k]);
+dump_int(font_false_bchar[k]);
+print_nl("\\font");print_esc(font_id_text(k));print_char('=');
+print_file_name(font_name[k],font_area[k],empty_string);
+if(font_size[k]!=font_dsize[k])
+{print_str(" at ");print_scaled(font_size[k]);print_str("pt");
+}
+}
+
+/*:1322*/
+#line 24059 "tex.w"
+;
+print_ln();print_int(fmem_ptr-7);print_str(" words of font info for ");
+print_int(font_ptr-font_base);print_str(" preloaded font");
+if(font_ptr!=font_base+1)print_char('s')
+
+/*:1320*/
+#line 23770 "tex.w"
+;
+/*1324:*/
+#line 24128 "tex.w"
+
+dump_int(hyph_count);
+for(k= 0;k<=hyph_size;k++)if(hyph_word[k]!=0)
+{dump_int(k);dump_int(hyph_word[k]);dump_int(hyph_list[k]);
+}
+print_ln();print_int(hyph_count);print_str(" hyphenation exception");
+if(hyph_count!=1)print_char('s');
+if(trie_not_ready)init_trie();
+dump_int(trie_max);
+for(k= 0;k<=trie_max;k++)dump_hh(trie[k]);
+dump_int(trie_op_ptr);
+for(k= 1;k<=trie_op_ptr;k++)
+{dump_int(hyf_distance[k]);
+dump_int(hyf_num[k]);
+dump_int(hyf_next[k]);
+}
+print_nl("Hyphenation trie of length ");print_int(trie_max);
+
+print_str(" has ");print_int(trie_op_ptr);print_str(" op");
+if(trie_op_ptr!=1)print_char('s');
+print_str(" out of ");print_int(trie_op_size);
+for(k= 255;k>=0;k--)if(trie_used[k]> min_quarterword)
+{print_nl(" ");print_int(qo(trie_used[k]));
+print_str(" for language ");print_int(k);
+dump_int(k);dump_int(qo(trie_used[k]));
+}
+
+/*:1324*/
+#line 23771 "tex.w"
+;
+/*1326:*/
+#line 24198 "tex.w"
+
+dump_int(interaction);dump_int(format_ident);dump_int(69069);
+tracing_stats= 0
+
+/*:1326*/
+#line 23772 "tex.w"
+;
+/*1329:*/
+#line 24225 "tex.w"
+
+w_close(&fmt_file)
+
+/*:1329*/
+#line 23773 "tex.w"
+;
+}
+#endif
+
+/*:1302*//*1348:*/
+#line 24663 "tex.w"
+
+/*1349:*/
+#line 24684 "tex.w"
+
+void new_whatsit(small_number s,small_number w)
+{pointer p;
+p= get_node(w);type(p)= whatsit_node;subtype(p)= s;
+link(tail)= p;tail= p;
+}
+
+/*:1349*//*1350:*/
+#line 24694 "tex.w"
+
+void new_write_whatsit(small_number w)
+{new_whatsit(cur_chr,w);
+if(w!=write_node_size)scan_four_bit_int();
+else{scan_int();
+if(cur_val<0)cur_val= 17;
+else if(cur_val> 15)cur_val= 16;
+}
+write_stream(tail)= cur_val;
+}
+
+/*:1350*/
+#line 24664 "tex.w"
+
+void do_extension(void)
+{int k;
+pointer p;
+switch(cur_chr){
+case open_node:/*1351:*/
+#line 24705 "tex.w"
+
+{new_write_whatsit(open_node_size);
+scan_optional_equals();scan_file_name();
+open_name(tail)= cur_name;open_area(tail)= cur_area;open_ext(tail)= cur_ext;
+}
+
+/*:1351*/
+#line 24669 "tex.w"
+break;
+case write_node:/*1352:*/
+#line 24715 "tex.w"
+
+{k= cur_cs;new_write_whatsit(write_node_size);
+cur_cs= k;p= scan_toks(false,false);write_tokens(tail)= def_ref;
+}
+
+/*:1352*/
+#line 24670 "tex.w"
+break;
+case close_node:/*1353:*/
+#line 24720 "tex.w"
+
+{new_write_whatsit(write_node_size);write_tokens(tail)= null;
+}
+
+/*:1353*/
+#line 24671 "tex.w"
+break;
+case special_node:/*1354:*/
+#line 24727 "tex.w"
+
+{new_whatsit(special_node,write_node_size);write_stream(tail)= null;
+p= scan_toks(false,true);write_tokens(tail)= def_ref;
+}
+
+/*:1354*/
+#line 24672 "tex.w"
+break;
+case immediate_code:/*1375:*/
+#line 24950 "tex.w"
+
+{get_x_token();
+if((cur_cmd==extension)&&(cur_chr<=close_node))
+{p= tail;do_extension();
+out_what(tail);
+flush_node_list(tail);tail= p;link(p)= null;
+}
+else back_input();
+}
+
+/*:1375*/
+#line 24673 "tex.w"
+break;
+case set_language_code:/*1377:*/
+#line 24978 "tex.w"
+
+if(abs(mode)!=hmode)report_illegal_case();
+else{new_whatsit(language_node,small_node_size);
+scan_int();
+if(cur_val<=0)clang= 0;
+else if(cur_val> 255)clang= 0;
+else clang= cur_val;
+what_lang(tail)= clang;
+what_lhm(tail)= norm_min(left_hyphen_min);
+what_rhm(tail)= norm_min(right_hyphen_min);
+}
+
+/*:1377*/
+#line 24674 "tex.w"
+break;
+default:confusion(/*1788:*/
+#line 26260 "tex.w"
+663
+/*:1788*/
+#line 24675 "tex.w"
+);
+
+}
+}
+
+/*:1348*//*1376:*/
+#line 24964 "tex.w"
+
+void fix_language(void)
+{ASCII_code l;
+if(language<=0)l= 0;
+else if(language> 255)l= 0;
+else l= language;
+if(l!=clang)
+{new_whatsit(language_node,small_node_size);
+what_lang(tail)= l;clang= l;
+what_lhm(tail)= norm_min(left_hyphen_min);
+what_rhm(tail)= norm_min(right_hyphen_min);
+}
+}
+
+/*:1376*/
+#line 20035 "tex.w"
+
+/*1068:*/
+#line 20717 "tex.w"
+
+void handle_right_brace(void)
+{pointer p,q;
+scaled d;
+int f;
+switch(cur_group){
+case simple_group:unsave();break;
+case bottom_level:{print_err("Too many }'s");
+
+help2("You've closed more groups than you opened.")
+("Such booboos are generally harmless, so keep going.");error();
+}break;
+case semi_simple_group:case math_shift_group:case math_left_group:extra_right_brace();break;
+/*1085:*/
+#line 21055 "tex.w"
+
+case hbox_group:package(0);break;
+case adjusted_hbox_group:{adjust_tail= adjust_head;package(0);
+}break;
+case vbox_group:{end_graf();package(0);
+}break;
+case vtop_group:{end_graf();package(vtop_code);
+}break;
+
+/*:1085*//*1100:*/
+#line 21212 "tex.w"
+
+case insert_group:{end_graf();q= split_top_skip;add_glue_ref(q);
+d= split_max_depth;f= floating_penalty;unsave();decr(save_ptr);
+
+p= vpack(link(head),natural);pop_nest();
+if(saved(0)<255)
+{tail_append(get_node(ins_node_size));
+type(tail)= ins_node;subtype(tail)= qi(saved(0));
+height(tail)= height(p)+depth(p);ins_ptr(tail)= list_ptr(p);
+split_top_ptr(tail)= q;depth(tail)= d;float_cost(tail)= f;
+}
+else{tail_append(get_node(small_node_size));
+type(tail)= adjust_node;
+subtype(tail)= 0;
+adjust_ptr(tail)= list_ptr(p);delete_glue_ref(q);
+}
+free_node(p,box_node_size);
+if(nest_ptr==0)build_page();
+}break;
+case output_group:/*1026:*/
+#line 19949 "tex.w"
+
+{if((loc!=null)||
+((token_type!=output_text)&&(token_type!=backed_up)))
+/*1027:*/
+#line 19969 "tex.w"
+
+{print_err("Unbalanced output routine");
+
+help2("Your sneaky output routine has problematic {'s and/or }'s.")
+("I can't handle that very well; good luck.");error();
+do{get_token();
+}while(!(loc==null));
+}
+
+/*:1027*/
+#line 19952 "tex.w"
+;
+end_token_list();
+end_graf();unsave();output_active= false;insert_penalties= 0;
+/*1028:*/
+#line 19978 "tex.w"
+
+if(box(255)!=null)
+{print_err("Output routine didn't use all of ");
+print_esc(/*1437:*/
+#line 25207 "tex.w"
+312
+/*:1437*/
+#line 19981 "tex.w"
+);print_int(255);
+
+help3("Your \\output commands should empty \\box255,")
+("e.g., by saying `\\shipout\\box255'.")
+("Proceed; I'll discard its present contents.");
+box_error(255);
+}
+
+/*:1028*/
+#line 19955 "tex.w"
+;
+if(tail!=head)
+{link(page_tail)= link(head);
+page_tail= tail;
+}
+if(link(page_head)!=null)
+{if(link(contrib_head)==null)contrib_tail= page_tail;
+link(page_tail)= link(contrib_head);
+link(contrib_head)= link(page_head);
+link(page_head)= null;page_tail= page_head;
+}
+pop_nest();build_page();
+}
+
+/*:1026*/
+#line 21231 "tex.w"
+break;
+
+/*:1100*//*1118:*/
+#line 21414 "tex.w"
+
+case disc_group:build_discretionary();break;
+
+/*:1118*//*1132:*/
+#line 21650 "tex.w"
+
+case align_group:{back_input();cur_tok= cs_token_flag+frozen_cr;
+print_err("Missing ");print_esc(/*1670:*/
+#line 25906 "tex.w"
+545
+/*:1670*/
+#line 21652 "tex.w"
+);print_str(" inserted");
+
+help1("I'm guessing that you meant to end an alignment here.");
+ins_error();
+}break;
+
+/*:1132*//*1133:*/
+#line 21658 "tex.w"
+
+case no_align_group:{end_graf();unsave();align_peek();
+}break;
+
+/*:1133*//*1168:*/
+#line 22111 "tex.w"
+
+case vcenter_group:{end_graf();unsave();save_ptr= save_ptr-2;
+p= vpack(link(head),saved(1),saved(0));pop_nest();
+tail_append(new_noad());type(tail)= vcenter_noad;
+math_type(nucleus(tail))= sub_box;info(nucleus(tail))= p;
+}break;
+
+/*:1168*//*1173:*/
+#line 22149 "tex.w"
+
+case math_choice_group:build_choices();break;
+
+/*:1173*//*1186:*/
+#line 22323 "tex.w"
+
+case math_group:{unsave();decr(save_ptr);
+math_type(saved(0))= sub_mlist;p= fin_mlist(null);info(saved(0))= p;
+if(p!=null)if(link(p)==null)
+if(type(p)==ord_noad)
+{if(math_type(subscr(p))==empty)
+if(math_type(supscr(p))==empty)
+{mem[saved(0)].hh= mem[nucleus(p)].hh;
+free_node(p,noad_size);
+}
+}
+else if(type(p)==accent_noad)if(saved(0)==nucleus(tail))
+if(type(tail)==ord_noad)/*1187:*/
+#line 22338 "tex.w"
+
+{q= head;while(link(q)!=tail)q= link(q);
+link(q)= p;free_node(tail,noad_size);tail= p;
+}
+
+/*:1187*/
+#line 22335 "tex.w"
+;
+}break;
+
+/*:1186*/
+#line 20730 "tex.w"
+
+default:confusion(/*1711:*/
+#line 26029 "tex.w"
+586
+/*:1711*/
+#line 20731 "tex.w"
+);
+
+}
+}
+
+/*:1068*/
+#line 20036 "tex.w"
+
+void main_control(void)
+{
+
+
+
+
+int t;
+if(every_job!=null)begin_token_list(every_job,every_job_text);
+big_switch:get_x_token();
+reswitch:/*1031:*/
+#line 20071 "tex.w"
+
+if(interrupt!=0)if(OK_to_interrupt)
+{back_input();check_interrupt;goto big_switch;
+}
+#ifdef DEBUG
+if(panicking)check_mem(false);
+#endif
+if(tracing_commands> 0)show_cur_cmd_chr()
+
+/*:1031*/
+#line 20046 "tex.w"
+;
+switch(abs(mode)+cur_cmd){
+case hmode+letter:case hmode+other_char:case hmode+char_given:goto main_loop;
+case hmode+char_num:{scan_char_num();cur_chr= cur_val;goto main_loop;}
+case hmode+no_boundary:{get_x_token();
+if((cur_cmd==letter)||(cur_cmd==other_char)||(cur_cmd==char_given)||
+(cur_cmd==char_num))cancel_boundary= true;
+goto reswitch;
+}
+case hmode+spacer:if(space_factor==1000)goto append_normal_space;
+else app_space();break;
+case hmode+ex_space:case mmode+ex_space:goto append_normal_space;
+/*1045:*/
+#line 20385 "tex.w"
+
+any_mode(relax):case vmode+spacer:case mmode+spacer:case mmode+no_boundary:do_nothing;
+any_mode(ignore_spaces):{/*406:*/
+#line 8269 "tex.w"
+
+do{get_x_token();
+}while(!(cur_cmd!=spacer))
+
+/*:406*/
+#line 20387 "tex.w"
+;
+goto reswitch;
+}
+case vmode+stop:if(its_all_over())return;break;
+/*1048:*/
+#line 20432 "tex.w"
+
+case vmode+vmove:case hmode+hmove:case mmode+hmove:any_mode(last_item):
+
+/*:1048*//*1098:*/
+#line 21193 "tex.w"
+
+case vmode+vadjust:
+
+/*:1098*//*1111:*/
+#line 21353 "tex.w"
+case vmode+ital_corr:
+
+/*:1111*//*1144:*/
+#line 21749 "tex.w"
+non_math(eq_no):
+
+/*:1144*/
+#line 20391 "tex.w"
+any_mode(mac_param):
+report_illegal_case();break;
+/*1046:*/
+#line 20403 "tex.w"
+
+non_math(sup_mark):non_math(sub_mark):non_math(math_char_num):
+non_math(math_given):non_math(math_comp):non_math(delim_num):
+non_math(left_right):non_math(above):non_math(radical):
+non_math(math_style):non_math(math_choice):non_math(vcenter):
+non_math(non_script):non_math(mkern):non_math(limit_switch):
+non_math(mskip):non_math(math_accent):
+case mmode+endv:case mmode+par_end:case mmode+stop:case mmode+vskip:case mmode+un_vbox:
+case mmode+valign:case mmode+hrule
+
+/*:1046*/
+#line 20393 "tex.w"
+:insert_dollar_sign();break;
+/*1056:*/
+#line 20521 "tex.w"
+
+case vmode+hrule:case hmode+vrule:case mmode+vrule:{tail_append(scan_rule_spec());
+if(abs(mode)==vmode)prev_depth= ignore_depth;
+else if(abs(mode)==hmode)space_factor= 1000;
+}break;
+
+/*:1056*//*1057:*/
+#line 20532 "tex.w"
+
+case vmode+vskip:case hmode+hskip:case mmode+hskip:case mmode+mskip:append_glue();break;
+any_mode(kern):case mmode+mkern:append_kern();break;
+
+/*:1057*//*1063:*/
+#line 20645 "tex.w"
+
+non_math(left_brace):new_save_level(simple_group);break;
+any_mode(begin_group):new_save_level(semi_simple_group);break;
+any_mode(end_group):if(cur_group==semi_simple_group)unsave();
+else off_save();break;
+
+/*:1063*//*1067:*/
+#line 20714 "tex.w"
+
+any_mode(right_brace):handle_right_brace();break;
+
+/*:1067*//*1073:*/
+#line 20858 "tex.w"
+
+case vmode+hmove:case hmode+vmove:case mmode+vmove:{t= cur_chr;
+scan_normal_dimen;
+if(t==0)scan_box(cur_val);else scan_box(-cur_val);
+}break;
+any_mode(leader_ship):scan_box(leader_flag-a_leaders+cur_chr);break;
+any_mode(make_box):begin_box(0);break;
+
+/*:1073*//*1090:*/
+#line 21101 "tex.w"
+
+case vmode+start_par:new_graf(cur_chr> 0);break;
+case vmode+letter:case vmode+other_char:case vmode+char_num:case vmode+char_given:
+case vmode+math_shift:case vmode+un_hbox:case vmode+vrule:
+case vmode+accent:case vmode+discretionary:case vmode+hskip:case vmode+valign:
+case vmode+ex_space:case vmode+no_boundary:
+{back_input();new_graf(true);
+}break;
+
+/*:1090*//*1092:*/
+#line 21130 "tex.w"
+
+case hmode+start_par:case mmode+start_par:indent_in_hmode();break;
+
+/*:1092*//*1094:*/
+#line 21150 "tex.w"
+
+case vmode+par_end:{normal_paragraph();
+if(mode> 0)build_page();
+}break;
+case hmode+par_end:{if(align_state<0)off_save();
+
+end_graf();
+if(mode==vmode)build_page();
+}break;
+case hmode+stop:case hmode+vskip:case hmode+hrule:case hmode+un_vbox:case hmode+halign:head_for_vmode();break;
+
+/*:1094*//*1097:*/
+#line 21189 "tex.w"
+
+any_mode(insert):case hmode+vadjust:case mmode+vadjust:begin_insert_or_adjust();break;
+any_mode(mark):make_mark();break;
+
+/*:1097*//*1102:*/
+#line 21244 "tex.w"
+
+any_mode(break_penalty):append_penalty();break;
+
+/*:1102*//*1104:*/
+#line 21260 "tex.w"
+
+any_mode(remove_item):delete_last();break;
+
+/*:1104*//*1109:*/
+#line 21327 "tex.w"
+
+case vmode+un_vbox:case hmode+un_hbox:case mmode+un_hbox:unpackage();break;
+
+/*:1109*//*1112:*/
+#line 21359 "tex.w"
+
+case hmode+ital_corr:append_italic_correction();break;
+case mmode+ital_corr:tail_append(new_kern(0))break;
+
+/*:1112*//*1116:*/
+#line 21391 "tex.w"
+
+case hmode+discretionary:case mmode+discretionary:append_discretionary();break;
+
+/*:1116*//*1122:*/
+#line 21482 "tex.w"
+
+case hmode+accent:make_accent();break;
+
+/*:1122*//*1126:*/
+#line 21552 "tex.w"
+
+any_mode(car_ret):any_mode(tab_mark):align_error();break;
+any_mode(no_align):no_align_error();break;
+any_mode(omit):omit_error();break;
+
+/*:1126*//*1130:*/
+#line 21619 "tex.w"
+
+case vmode+halign:case hmode+valign:init_align();break;
+case mmode+halign:if(privileged())
+if(cur_group==math_shift_group)init_align();
+else off_save();break;
+case vmode+endv:case hmode+endv:do_endv();break;
+
+/*:1130*//*1134:*/
+#line 21664 "tex.w"
+
+any_mode(end_cs_name):cs_error();break;
+
+/*:1134*//*1137:*/
+#line 21695 "tex.w"
+
+case hmode+math_shift:init_math();break;
+
+/*:1137*//*1140:*/
+#line 21725 "tex.w"
+
+case mmode+eq_no:if(privileged())
+if(cur_group==math_shift_group)start_eq_no();
+else off_save();break;
+
+/*:1140*//*1150:*/
+#line 21863 "tex.w"
+
+case mmode+left_brace:{tail_append(new_noad());
+back_input();scan_math(nucleus(tail));
+}break;
+
+/*:1150*//*1154:*/
+#line 21927 "tex.w"
+
+case mmode+letter:case mmode+other_char:case mmode+char_given:
+set_math_char(ho(math_code(cur_chr)));break;
+case mmode+char_num:{scan_char_num();cur_chr= cur_val;
+set_math_char(ho(math_code(cur_chr)));
+}break;
+case mmode+math_char_num:{scan_fifteen_bit_int();set_math_char(cur_val);
+}break;
+case mmode+math_given:set_math_char(cur_chr);break;
+case mmode+delim_num:{scan_twenty_seven_bit_int();
+set_math_char(cur_val/010000);
+}break;
+
+/*:1154*//*1158:*/
+#line 22011 "tex.w"
+
+case mmode+math_comp:{tail_append(new_noad());
+type(tail)= cur_chr;scan_math(nucleus(tail));
+}break;
+case mmode+limit_switch:math_limit_switch();break;
+
+/*:1158*//*1162:*/
+#line 22063 "tex.w"
+
+case mmode+radical:math_radical();break;
+
+/*:1162*//*1164:*/
+#line 22076 "tex.w"
+
+case mmode+accent:case mmode+math_accent:math_ac();break;
+
+/*:1164*//*1167:*/
+#line 22105 "tex.w"
+
+case mmode+vcenter:{scan_spec(vcenter_group,false);normal_paragraph();
+push_nest();mode= -vmode;prev_depth= ignore_depth;
+if(every_vbox!=null)begin_token_list(every_vbox,every_vbox_text);
+}break;
+
+/*:1167*//*1171:*/
+#line 22133 "tex.w"
+
+case mmode+math_style:tail_append(new_style(cur_chr))break;
+case mmode+non_script:{tail_append(new_glue(zero_glue));
+subtype(tail)= cond_math_glue;
+}break;
+case mmode+math_choice:append_choices();break;
+
+/*:1171*//*1175:*/
+#line 22173 "tex.w"
+
+case mmode+sub_mark:case mmode+sup_mark:sub_sup();break;
+
+/*:1175*//*1180:*/
+#line 22243 "tex.w"
+
+case mmode+above:math_fraction();break;
+
+/*:1180*//*1190:*/
+#line 22358 "tex.w"
+
+case mmode+left_right:math_left_right();break;
+
+/*:1190*//*1193:*/
+#line 22394 "tex.w"
+
+case mmode+math_shift:if(cur_group==math_shift_group)after_math();
+else off_save();break;
+
+/*:1193*/
+#line 20394 "tex.w"
+
+/*1210:*/
+#line 22681 "tex.w"
+
+any_mode(toks_register):
+any_mode(assign_toks):
+any_mode(assign_int):
+any_mode(assign_dimen):
+any_mode(assign_glue):
+any_mode(assign_mu_glue):
+any_mode(assign_font_dimen):
+any_mode(assign_font_int):
+any_mode(set_aux):
+any_mode(set_prev_graf):
+any_mode(set_page_dimen):
+any_mode(set_page_int):
+any_mode(set_box_dimen):
+any_mode(set_shape):
+any_mode(def_code):
+any_mode(def_family):
+any_mode(set_font):
+any_mode(def_font):
+any_mode(register):
+any_mode(advance):
+any_mode(multiply):
+any_mode(divide):
+any_mode(prefix):
+any_mode(let):
+any_mode(shorthand_def):
+any_mode(read_to_cs):
+any_mode(def):
+any_mode(set_box):
+any_mode(hyph_data):
+any_mode(set_interaction):prefixed_command();break;
+
+/*:1210*//*1268:*/
+#line 23463 "tex.w"
+
+any_mode(after_assignment):{get_token();after_token= cur_tok;
+}break;
+
+/*:1268*//*1271:*/
+#line 23484 "tex.w"
+
+any_mode(after_group):{get_token();save_for_after(cur_tok);
+}break;
+
+/*:1271*//*1274:*/
+#line 23500 "tex.w"
+
+any_mode(in_stream):open_or_close_in();break;
+
+/*:1274*//*1276:*/
+#line 23522 "tex.w"
+
+any_mode(message):issue_message();break;
+
+/*:1276*//*1285:*/
+#line 23589 "tex.w"
+
+any_mode(case_shift):shift_case();break;
+
+/*:1285*//*1290:*/
+#line 23631 "tex.w"
+
+any_mode(xray):show_whatever();break;
+
+/*:1290*/
+#line 20395 "tex.w"
+
+/*1347:*/
+#line 24660 "tex.w"
+
+any_mode(extension):do_extension();
+
+/*:1347*/
+#line 20396 "tex.w"
+
+
+/*:1045*/
+#line 20058 "tex.w"
+
+}
+goto big_switch;
+main_loop:/*1034:*/
+#line 20136 "tex.w"
+
+adjust_space_factor;
+main_f= cur_font;
+bchar= font_bchar[main_f];false_bchar= font_false_bchar[main_f];
+if(mode> 0)if(language!=clang)fix_language();
+fast_get_avail(lig_stack);font(lig_stack)= main_f;cur_l= qi(cur_chr);
+character(lig_stack)= cur_l;
+cur_q= tail;
+if(cancel_boundary)
+{cancel_boundary= false;main_k= non_address;
+}
+else main_k= bchar_label[main_f];
+if(main_k==non_address)goto main_loop_move2;
+cur_r= cur_l;cur_l= non_char;
+goto main_lig_loop1;
+
+main_loop_wrapup:/*1035:*/
+#line 20194 "tex.w"
+
+wrapup(rt_hit)
+
+/*:1035*/
+#line 20153 "tex.w"
+;
+main_loop_move:/*1036:*/
+#line 20197 "tex.w"
+
+
+if(lig_stack==null)goto reswitch;
+cur_q= tail;cur_l= character(lig_stack);
+main_loop_move1:if(!is_char_node(lig_stack))goto main_loop_move_lig;
+main_loop_move2:if((cur_chr<font_bc[main_f])||(cur_chr> font_ec[main_f]))
+{char_warning(main_f,cur_chr);free_avail(lig_stack);goto big_switch;
+}
+main_i= char_info(main_f)(cur_l);
+if(!char_exists(main_i))
+{char_warning(main_f,cur_chr);free_avail(lig_stack);goto big_switch;
+}
+link(tail)= lig_stack;tail= lig_stack
+
+/*:1036*/
+#line 20156 "tex.w"
+;
+main_loop_lookahead:/*1038:*/
+#line 20229 "tex.w"
+
+get_next();
+if(cur_cmd==letter)goto main_loop_lookahead1;
+if(cur_cmd==other_char)goto main_loop_lookahead1;
+if(cur_cmd==char_given)goto main_loop_lookahead1;
+x_token();
+if(cur_cmd==letter)goto main_loop_lookahead1;
+if(cur_cmd==other_char)goto main_loop_lookahead1;
+if(cur_cmd==char_given)goto main_loop_lookahead1;
+if(cur_cmd==char_num)
+{scan_char_num();cur_chr= cur_val;goto main_loop_lookahead1;
+}
+if(cur_cmd==no_boundary)bchar= non_char;
+cur_r= bchar;lig_stack= null;goto main_lig_loop;
+main_loop_lookahead1:adjust_space_factor;
+fast_get_avail(lig_stack);font(lig_stack)= main_f;
+cur_r= qi(cur_chr);character(lig_stack)= cur_r;
+if(cur_r==false_bchar)cur_r= non_char
+
+/*:1038*/
+#line 20158 "tex.w"
+;
+main_lig_loop:/*1039:*/
+#line 20258 "tex.w"
+
+if(char_tag(main_i)!=lig_tag)goto main_loop_wrapup;
+if(cur_r==non_char)goto main_loop_wrapup;
+main_k= lig_kern_start(main_f)(main_i);main_j= font_info[main_k].qqqq;
+if(skip_byte(main_j)<=stop_flag)goto main_lig_loop2;
+main_k= lig_kern_restart(main_f)(main_j);
+main_lig_loop1:main_j= font_info[main_k].qqqq;
+main_lig_loop2:if(next_char(main_j)==cur_r)
+if(skip_byte(main_j)<=stop_flag)
+/*1040:*/
+#line 20284 "tex.w"
+
+{if(op_byte(main_j)>=kern_flag)
+{wrapup(rt_hit);
+tail_append(new_kern(char_kern(main_f)(main_j)));goto main_loop_move;
+}
+if(cur_l==non_char)lft_hit= true;
+else if(lig_stack==null)rt_hit= true;
+check_interrupt;
+switch(op_byte(main_j)){
+qi(case 1):qi(case 5):{cur_l= rem_byte(main_j);
+main_i= char_info(main_f)(cur_l);ligature_present= true;
+}break;
+qi(case 2):qi(case 6):{cur_r= rem_byte(main_j);
+if(lig_stack==null)
+{lig_stack= new_lig_item(cur_r);bchar= non_char;
+}
+else if(is_char_node(lig_stack))
+{main_p= lig_stack;lig_stack= new_lig_item(cur_r);
+lig_ptr(lig_stack)= main_p;
+}
+else character(lig_stack)= cur_r;
+}break;
+qi(case 3):{cur_r= rem_byte(main_j);
+main_p= lig_stack;lig_stack= new_lig_item(cur_r);
+link(lig_stack)= main_p;
+}break;
+qi(case 7):qi(case 11):{wrapup(false);
+cur_q= tail;cur_l= rem_byte(main_j);
+main_i= char_info(main_f)(cur_l);ligature_present= true;
+}break;
+default:{cur_l= rem_byte(main_j);ligature_present= true;
+if(lig_stack==null)goto main_loop_wrapup;
+else goto main_loop_move1;
+}
+}
+if(op_byte(main_j)> qi(4))
+if(op_byte(main_j)!=qi(7))goto main_loop_wrapup;
+if(cur_l<non_char)goto main_lig_loop;
+main_k= bchar_label[main_f];goto main_lig_loop1;
+}
+
+/*:1040*/
+#line 20268 "tex.w"
+;
+if(skip_byte(main_j)==qi(0))incr(main_k);
+else{if(skip_byte(main_j)>=stop_flag)goto main_loop_wrapup;
+main_k= main_k+qo(skip_byte(main_j))+1;
+}
+goto main_lig_loop1
+
+/*:1039*/
+#line 20160 "tex.w"
+;
+main_loop_move_lig:/*1037:*/
+#line 20214 "tex.w"
+
+main_p= lig_ptr(lig_stack);
+if(main_p> null)tail_append(main_p);
+temp_ptr= lig_stack;lig_stack= link(temp_ptr);
+free_node(temp_ptr,small_node_size);
+main_i= char_info(main_f)(cur_l);ligature_present= true;
+if(lig_stack==null)
+if(main_p> null)goto main_loop_lookahead;
+else cur_r= bchar;
+else cur_r= character(lig_stack);
+goto main_lig_loop
+
+/*:1037*/
+#line 20162 "tex.w"
+
+
+/*:1034*/
+#line 20062 "tex.w"
+;
+append_normal_space:/*1041:*/
+#line 20336 "tex.w"
+
+if(space_skip==zero_glue)
+{/*1042:*/
+#line 20350 "tex.w"
+
+{main_p= font_glue[cur_font];
+if(main_p==null)
+{main_p= new_spec(zero_glue);main_k= param_base[cur_font]+space_code;
+width(main_p)= font_info[main_k].sc;
+stretch(main_p)= font_info[main_k+1].sc;
+shrink(main_p)= font_info[main_k+2].sc;
+font_glue[cur_font]= main_p;
+}
+}
+
+/*:1042*/
+#line 20338 "tex.w"
+;
+temp_ptr= new_glue(main_p);
+}
+else temp_ptr= new_param_glue(space_skip_code);
+link(tail)= temp_ptr;tail= temp_ptr;
+goto big_switch
+
+/*:1041*/
+#line 20064 "tex.w"
+;
+}
+
+/*:1030*//*1284:*/
+#line 23582 "tex.w"
+void give_err_help(void)
+{token_show(err_help);
+}
+
+/*:1284*//*1303:*/
+#line 23787 "tex.w"
+/*523:*/
+#line 10180 "tex.w"
+
+bool open_fmt_file(void)
+{
+uint16_t j;
+j= loc;
+if(buffer[loc]=='&')
+{incr(loc);j= loc;buffer[last]= ' ';
+while(buffer[j]!=' ')incr(j);
+pack_buffered_name(0,loc,j-1);
+if(w_open_in(&fmt_file))goto found;
+pack_buffered_name(format_area_length,loc,j-1);
+
+if(w_open_in(&fmt_file))goto found;
+wake_up_terminal;
+wterm_ln("Sorry, I can't find that format; will try PLAIN.");
+
+update_terminal;
+}
+
+pack_buffered_name(format_default_length-format_ext_length,1,0);
+if(!w_open_in(&fmt_file))
+{wake_up_terminal;
+wterm_ln("I can't find the PLAIN format file!");
+
+
+return false;
+}
+found:loc= j;return true;
+}
+
+/*:523*/
+#line 23787 "tex.w"
+
+bool load_fmt_file(void)
+{
+int j,k;
+pointer p,q;
+int x;
+four_quarters w;
+/*1308:*/
+#line 23863 "tex.w"
+
+x= fmt_file.d.i;
+if(x!=0)goto bad_fmt;
+undump_int(x);
+if(x!=mem_bot)goto bad_fmt;
+undump_int(x);
+if(x!=mem_top)goto bad_fmt;
+undump_int(x);
+if(x!=eqtb_size)goto bad_fmt;
+undump_int(x);
+if(x!=hash_prime)goto bad_fmt;
+undump_int(x);
+if(x!=hyph_size)goto bad_fmt
+
+/*:1308*/
+#line 23794 "tex.w"
+;
+/*1310:*/
+#line 23899 "tex.w"
+
+undump_size(0)(pool_size)("string pool size")(pool_ptr);
+undump_size(0)(max_strings)("max strings")(str_ptr);
+for(k= 0;k<=str_ptr;k++)undump(0)(pool_ptr)(str_start[k]);
+k= 0;
+while(k+4<pool_ptr)
+{undump_four_ASCII;k= k+4;
+}
+k= pool_ptr-4;undump_four_ASCII;
+init_str_ptr= str_ptr;init_pool_ptr= pool_ptr
+
+/*:1310*/
+#line 23795 "tex.w"
+;
+/*1312:*/
+#line 23940 "tex.w"
+
+undump(lo_mem_stat_max+1000)(hi_mem_stat_min-1)(lo_mem_max);
+undump(lo_mem_stat_max+1)(lo_mem_max)(rover);
+p= mem_bot;q= rover;
+do{for(k= p;k<=q+1;k++)undump_wd(mem[k]);
+p= q+node_size(q);
+if((p> lo_mem_max)||((q>=rlink(q))&&(rlink(q)!=rover)))goto bad_fmt;
+q= rlink(q);
+}while(!(q==rover));
+for(k= p;k<=lo_mem_max;k++)undump_wd(mem[k]);
+if(mem_min<mem_bot-2)
+{p= llink(rover);q= mem_min+1;
+link(mem_min)= null;info(mem_min)= null;
+rlink(p)= q;llink(rover)= q;
+rlink(q)= rover;llink(q)= p;link(q)= empty_flag;
+node_size(q)= mem_bot-q;
+}
+undump(lo_mem_max+1)(hi_mem_stat_min)(hi_mem_min);
+undump(null)(mem_top)(avail);mem_end= mem_top;
+for(k= hi_mem_min;k<=mem_end;k++)undump_wd(mem[k]);
+undump_int(var_used);undump_int(dyn_used)
+
+/*:1312*/
+#line 23796 "tex.w"
+;
+/*1314:*/
+#line 23968 "tex.w"
+
+/*1317:*/
+#line 24021 "tex.w"
+
+k= active_base;
+do{undump_int(x);
+if((x<1)||(k+x> eqtb_size+1))goto bad_fmt;
+for(j= k;j<=k+x-1;j++)undump_wd(eqtb[j]);
+k= k+x;
+undump_int(x);
+if((x<0)||(k+x> eqtb_size+1))goto bad_fmt;
+for(j= k;j<=k+x-1;j++)eqtb[j]= eqtb[k-1];
+k= k+x;
+}while(!(k> eqtb_size))
+
+/*:1317*/
+#line 23969 "tex.w"
+;
+undump(hash_base)(frozen_control_sequence)(par_loc);
+par_token= cs_token_flag+par_loc;
+undump(hash_base)(frozen_control_sequence)(write_loc);
+/*1319:*/
+#line 24047 "tex.w"
+
+undump(hash_base)(frozen_control_sequence)(hash_used);p= hash_base-1;
+do{undump(p+1)(hash_used)(p);undump_hh(hash[p]);
+}while(!(p==hash_used));
+for(p= hash_used+1;p<=undefined_control_sequence-1;p++)undump_hh(hash[p]);
+undump_int(cs_count)
+
+/*:1319*/
+#line 23973 "tex.w"
+
+
+/*:1314*/
+#line 23797 "tex.w"
+;
+/*1321:*/
+#line 24064 "tex.w"
+
+undump_size(7)(font_mem_size)("font mem size")(fmem_ptr);
+for(k= 0;k<=fmem_ptr-1;k++)undump_wd(font_info[k]);
+undump_size(font_base)(font_max)("font max")(font_ptr);
+for(k= null_font;k<=font_ptr;k++)
+/*1323:*/
+#line 24102 "tex.w"
+
+{undump_qqqq(font_check[k]);
+undump_int(font_size[k]);
+undump_int(font_dsize[k]);
+undump(min_halfword)(max_halfword)(font_params[k]);
+undump_int(hyphen_char[k]);
+undump_int(skew_char[k]);
+undump(0)(str_ptr)(font_name[k]);
+undump(0)(str_ptr)(font_area[k]);
+undump(0)(255)(font_bc[k]);
+undump(0)(255)(font_ec[k]);
+undump_int(char_base[k]);
+undump_int(width_base[k]);
+undump_int(height_base[k]);
+undump_int(depth_base[k]);
+undump_int(italic_base[k]);
+undump_int(lig_kern_base[k]);
+undump_int(kern_base[k]);
+undump_int(exten_base[k]);
+undump_int(param_base[k]);
+undump(min_halfword)(lo_mem_max)(font_glue[k]);
+undump(0)(fmem_ptr-1)(bchar_label[k]);
+undump(min_quarterword)(non_char)(font_bchar[k]);
+undump(min_quarterword)(non_char)(font_false_bchar[k]);
+}
+
+/*:1323*/
+#line 24069 "tex.w"
+
+
+/*:1321*/
+#line 23798 "tex.w"
+;
+/*1325:*/
+#line 24157 "tex.w"
+
+undump(0)(hyph_size)(hyph_count);
+for(k= 1;k<=hyph_count;k++)
+{undump(0)(hyph_size)(j);
+undump(0)(str_ptr)(hyph_word[j]);
+undump(min_halfword)(max_halfword)(hyph_list[j]);
+}
+undump_size(0)(trie_size)("trie size")(j);
+#ifdef INIT
+trie_max= j;
+#endif
+for(k= 0;k<=j;k++)undump_hh(trie[k]);
+undump_size(0)(trie_op_size)("trie op size")(j);
+#ifdef INIT
+trie_op_ptr= j;
+#endif
+for(k= 1;k<=j;k++)
+{undump(0)(63)(hyf_distance[k]);
+undump(0)(63)(hyf_num[k]);
+undump(min_quarterword)(max_quarterword)(hyf_next[k]);
+}
+#ifdef INIT
+for(k= 0;k<=255;k++)trie_used[k]= min_quarterword;
+#endif
+
+k= 256;
+while(j> 0)
+{undump(0)(k-1)(k);undump(1)(j)(x);
+#ifdef INIT
+trie_used[k]= qi(x);
+#endif
+
+j= j-x;op_start[k]= qo(j);
+}
+#ifdef INIT
+trie_not_ready= false
+#endif
+
+/*:1325*/
+#line 23799 "tex.w"
+;
+/*1327:*/
+#line 24202 "tex.w"
+
+undump(batch_mode)(error_stop_mode)(interaction);
+undump(0)(str_ptr)(format_ident);
+undump_int(x);
+if((x!=69069)||eof(fmt_file))goto bad_fmt
+
+/*:1327*/
+#line 23800 "tex.w"
+;
+return true;
+bad_fmt:wake_up_terminal;
+wterm_ln("(Fatal format file error; I'm stymied)");
+
+return false;
+}
+
+/*:1303*//*1330:*/
+#line 24235 "tex.w"
+/*1333:*/
+#line 24329 "tex.w"
+
+void close_files_and_terminate(void)
+{int k;
+/*1378:*/
+#line 24990 "tex.w"
+
+for(k= 0;k<=15;k++)if(write_open[k])a_close(&write_file[k])
+
+/*:1378*/
+#line 24332 "tex.w"
+;
+#ifdef STAT
+if(tracing_stats> 0)/*1334:*/
+#line 24351 "tex.w"
+
+if(log_opened)
+{wlog_ln(" ");
+wlog_ln("Here is how much of TeX's memory you used:");
+
+wlog(" %d string",str_ptr-init_str_ptr);
+if(str_ptr!=init_str_ptr+1)wlog("s");
+wlog_ln(" out of %d",max_strings-init_str_ptr);
+wlog_ln(" %d string characters out of %d",pool_ptr-init_pool_ptr,
+pool_size-init_pool_ptr);
+wlog_ln(" %d words of memory out of %d",lo_mem_max-mem_min+mem_end-hi_mem_min+2,
+mem_end+1-mem_min);
+wlog_ln(" %d multiletter control sequences out of %d",cs_count,hash_size);
+wlog(" %d words of font info for %d font",fmem_ptr,font_ptr-font_base);
+if(font_ptr!=font_base+1)wlog("s");
+wlog_ln(", out of %d for %d",font_mem_size,font_max-font_base);
+wlog(" %d hyphenation exception",hyph_count);
+if(hyph_count!=1)wlog("s");
+wlog_ln(" out of %d",hyph_size);
+wlog_ln(" %di,%dn,%dp,%db,%ds stack positions out of %di,%dn,%dp,%db,%ds",
+max_in_stack,max_nest_stack,
+max_param_stack,
+max_buf_stack+1,
+max_save_stack+6,
+stack_size,
+nest_size,
+param_size,
+buf_size,
+save_size);
+}
+
+/*:1334*/
+#line 24334 "tex.w"
+;
+#endif
+wake_up_terminal;/*642:*/
+#line 12800 "tex.w"
+
+while(cur_s> -1)
+{if(cur_s> 0)dvi_out(pop)
+else{dvi_out(eop);incr(total_pages);
+}
+decr(cur_s);
+}
+if(total_pages==0)print_nl("No pages of output.");
+
+else{dvi_out(post);
+dvi_four(last_bop);last_bop= dvi_offset+dvi_ptr-5;
+dvi_four(25400000);dvi_four(473628672);
+prepare_mag();dvi_four(mag);
+dvi_four(max_v);dvi_four(max_h);
+dvi_out(max_push/256);dvi_out(max_push%256);
+dvi_out((total_pages/256)%256);dvi_out(total_pages%256);
+/*643:*/
+#line 12831 "tex.w"
+
+while(font_ptr> font_base)
+{if(font_used[font_ptr])dvi_font_def(font_ptr);
+decr(font_ptr);
+}
+
+/*:643*/
+#line 12816 "tex.w"
+;
+dvi_out(post_post);dvi_four(last_bop);dvi_out(id_byte);
+k= 4+((dvi_buf_size-dvi_ptr)%4);
+while(k> 0)
+{dvi_out(223);decr(k);
+}
+/*599:*/
+#line 11982 "tex.w"
+
+if(dvi_limit==half_buf)write_dvi(half_buf,dvi_buf_size-1);
+if(dvi_ptr> 0)write_dvi(0,dvi_ptr-1)
+
+/*:599*/
+#line 12822 "tex.w"
+;
+print_nl("Output written on ");slow_print(output_file_name);
+
+print_str(" (");print_int(total_pages);print_str(" page");
+if(total_pages!=1)print_char('s');
+print_str(", ");print_int(dvi_offset+dvi_ptr);print_str(" bytes).");
+b_close(&dvi_file);
+}
+
+/*:642*/
+#line 24336 "tex.w"
+;
+if(log_opened)
+{wlog_cr;a_close(&log_file);selector= selector-2;
+if(selector==term_only)
+{print_nl("Transcript written on ");
+
+slow_print(log_name);print_char('.');
+}
+}
+}
+
+/*:1333*//*1335:*/
+#line 24385 "tex.w"
+
+void final_cleanup(void)
+{
+small_number c;
+c= cur_chr;
+if(job_name==0)open_log_file();
+while(input_ptr> 0)
+if(state==token_list)end_token_list();else end_file_reading();
+while(open_parens> 0)
+{print_str(" )");decr(open_parens);
+}
+if(cur_level> level_one)
+{print_nl("(");print_esc(/*1782:*/
+#line 26242 "tex.w"
+657
+/*:1782*/
+#line 24397 "tex.w"
+);
+print_str("inside a group at level ");
+
+print_int(cur_level-level_one);print_char(')');
+}
+while(cond_ptr!=null)
+{print_nl("(");print_esc(/*1782:*/
+#line 26242 "tex.w"
+657
+/*:1782*/
+#line 24403 "tex.w"
+);
+print_str("when ");print_cmd_chr(if_test,cur_if);
+if(if_line!=0)
+{print_str(" on line ");print_int(if_line);
+}
+print_str(" was incomplete)");
+if_line= if_line_field(cond_ptr);
+cur_if= subtype(cond_ptr);temp_ptr= cond_ptr;
+cond_ptr= link(cond_ptr);free_node(temp_ptr,if_node_size);
+}
+if(history!=spotless)
+if(((history==warning_issued)||(interaction<error_stop_mode)))
+if(selector==term_and_log)
+{selector= term_only;
+print_nl("(see the transcript file for additional information)");
+
+selector= term_and_log;
+}
+if(c==1)
+{
+#ifdef INIT
+for(c= top_mark_code;c<=split_bot_mark_code;c++)
+if(cur_mark[c]!=null)delete_token_ref(cur_mark[c]);
+if(last_glue!=max_halfword)delete_glue_ref(last_glue);
+store_fmt_file();return;
+#endif
+print_nl("(\\dump is performed only by INITEX)");return;
+
+}
+}
+
+/*:1335*//*1336:*/
+#line 24434 "tex.w"
+
+#ifdef INIT
+void init_prim(void)
+{no_new_control_sequence= false;
+/*226:*/
+#line 4700 "tex.w"
+
+primitive(/*1405:*/
+#line 25111 "tex.w"
+280
+/*:1405*/
+#line 4701 "tex.w"
+,assign_glue,glue_base+line_skip_code);
+
+primitive(/*1406:*/
+#line 25114 "tex.w"
+281
+/*:1406*/
+#line 4703 "tex.w"
+,assign_glue,glue_base+baseline_skip_code);
+
+primitive(/*1407:*/
+#line 25117 "tex.w"
+282
+/*:1407*/
+#line 4705 "tex.w"
+,assign_glue,glue_base+par_skip_code);
+
+primitive(/*1408:*/
+#line 25120 "tex.w"
+283
+/*:1408*/
+#line 4707 "tex.w"
+,assign_glue,glue_base+above_display_skip_code);
+
+primitive(/*1409:*/
+#line 25123 "tex.w"
+284
+/*:1409*/
+#line 4709 "tex.w"
+,assign_glue,glue_base+below_display_skip_code);
+
+primitive(/*1410:*/
+#line 25126 "tex.w"
+285
+/*:1410*/
+#line 4711 "tex.w"
+,
+assign_glue,glue_base+above_display_short_skip_code);
+
+primitive(/*1411:*/
+#line 25129 "tex.w"
+286
+/*:1411*/
+#line 4714 "tex.w"
+,
+assign_glue,glue_base+below_display_short_skip_code);
+
+primitive(/*1412:*/
+#line 25132 "tex.w"
+287
+/*:1412*/
+#line 4717 "tex.w"
+,assign_glue,glue_base+left_skip_code);
+
+primitive(/*1413:*/
+#line 25135 "tex.w"
+288
+/*:1413*/
+#line 4719 "tex.w"
+,assign_glue,glue_base+right_skip_code);
+
+primitive(/*1414:*/
+#line 25138 "tex.w"
+289
+/*:1414*/
+#line 4721 "tex.w"
+,assign_glue,glue_base+top_skip_code);
+
+primitive(/*1415:*/
+#line 25141 "tex.w"
+290
+/*:1415*/
+#line 4723 "tex.w"
+,assign_glue,glue_base+split_top_skip_code);
+
+primitive(/*1416:*/
+#line 25144 "tex.w"
+291
+/*:1416*/
+#line 4725 "tex.w"
+,assign_glue,glue_base+tab_skip_code);
+
+primitive(/*1417:*/
+#line 25147 "tex.w"
+292
+/*:1417*/
+#line 4727 "tex.w"
+,assign_glue,glue_base+space_skip_code);
+
+primitive(/*1418:*/
+#line 25150 "tex.w"
+293
+/*:1418*/
+#line 4729 "tex.w"
+,assign_glue,glue_base+xspace_skip_code);
+
+primitive(/*1419:*/
+#line 25153 "tex.w"
+294
+/*:1419*/
+#line 4731 "tex.w"
+,assign_glue,glue_base+par_fill_skip_code);
+
+primitive(/*1420:*/
+#line 25156 "tex.w"
+295
+/*:1420*/
+#line 4733 "tex.w"
+,assign_mu_glue,glue_base+thin_mu_skip_code);
+
+primitive(/*1421:*/
+#line 25159 "tex.w"
+296
+/*:1421*/
+#line 4735 "tex.w"
+,assign_mu_glue,glue_base+med_mu_skip_code);
+
+primitive(/*1422:*/
+#line 25162 "tex.w"
+297
+/*:1422*/
+#line 4737 "tex.w"
+,assign_mu_glue,glue_base+thick_mu_skip_code);
+
+
+/*:226*//*230:*/
+#line 4821 "tex.w"
+
+primitive(/*1426:*/
+#line 25174 "tex.w"
+301
+/*:1426*/
+#line 4822 "tex.w"
+,assign_toks,output_routine_loc);
+
+primitive(/*1427:*/
+#line 25177 "tex.w"
+302
+/*:1427*/
+#line 4824 "tex.w"
+,assign_toks,every_par_loc);
+
+primitive(/*1428:*/
+#line 25180 "tex.w"
+303
+/*:1428*/
+#line 4826 "tex.w"
+,assign_toks,every_math_loc);
+
+primitive(/*1429:*/
+#line 25183 "tex.w"
+304
+/*:1429*/
+#line 4828 "tex.w"
+,assign_toks,every_display_loc);
+
+primitive(/*1430:*/
+#line 25186 "tex.w"
+305
+/*:1430*/
+#line 4830 "tex.w"
+,assign_toks,every_hbox_loc);
+
+primitive(/*1431:*/
+#line 25189 "tex.w"
+306
+/*:1431*/
+#line 4832 "tex.w"
+,assign_toks,every_vbox_loc);
+
+primitive(/*1432:*/
+#line 25192 "tex.w"
+307
+/*:1432*/
+#line 4834 "tex.w"
+,assign_toks,every_job_loc);
+
+primitive(/*1433:*/
+#line 25195 "tex.w"
+308
+/*:1433*/
+#line 4836 "tex.w"
+,assign_toks,every_cr_loc);
+
+primitive(/*1434:*/
+#line 25198 "tex.w"
+309
+/*:1434*/
+#line 4838 "tex.w"
+,assign_toks,err_help_loc);
+
+
+/*:230*//*238:*/
+#line 5154 "tex.w"
+
+primitive(/*1446:*/
+#line 25234 "tex.w"
+321
+/*:1446*/
+#line 5155 "tex.w"
+,assign_int,int_base+pretolerance_code);
+
+primitive(/*1447:*/
+#line 25237 "tex.w"
+322
+/*:1447*/
+#line 5157 "tex.w"
+,assign_int,int_base+tolerance_code);
+
+primitive(/*1448:*/
+#line 25240 "tex.w"
+323
+/*:1448*/
+#line 5159 "tex.w"
+,assign_int,int_base+line_penalty_code);
+
+primitive(/*1449:*/
+#line 25243 "tex.w"
+324
+/*:1449*/
+#line 5161 "tex.w"
+,assign_int,int_base+hyphen_penalty_code);
+
+primitive(/*1450:*/
+#line 25246 "tex.w"
+325
+/*:1450*/
+#line 5163 "tex.w"
+,assign_int,int_base+ex_hyphen_penalty_code);
+
+primitive(/*1451:*/
+#line 25249 "tex.w"
+326
+/*:1451*/
+#line 5165 "tex.w"
+,assign_int,int_base+club_penalty_code);
+
+primitive(/*1452:*/
+#line 25252 "tex.w"
+327
+/*:1452*/
+#line 5167 "tex.w"
+,assign_int,int_base+widow_penalty_code);
+
+primitive(/*1453:*/
+#line 25255 "tex.w"
+328
+/*:1453*/
+#line 5169 "tex.w"
+,
+assign_int,int_base+display_widow_penalty_code);
+
+primitive(/*1454:*/
+#line 25258 "tex.w"
+329
+/*:1454*/
+#line 5172 "tex.w"
+,assign_int,int_base+broken_penalty_code);
+
+primitive(/*1455:*/
+#line 25261 "tex.w"
+330
+/*:1455*/
+#line 5174 "tex.w"
+,assign_int,int_base+bin_op_penalty_code);
+
+primitive(/*1456:*/
+#line 25264 "tex.w"
+331
+/*:1456*/
+#line 5176 "tex.w"
+,assign_int,int_base+rel_penalty_code);
+
+primitive(/*1457:*/
+#line 25267 "tex.w"
+332
+/*:1457*/
+#line 5178 "tex.w"
+,assign_int,int_base+pre_display_penalty_code);
+
+primitive(/*1458:*/
+#line 25270 "tex.w"
+333
+/*:1458*/
+#line 5180 "tex.w"
+,assign_int,int_base+post_display_penalty_code);
+
+primitive(/*1459:*/
+#line 25273 "tex.w"
+334
+/*:1459*/
+#line 5182 "tex.w"
+,assign_int,int_base+inter_line_penalty_code);
+
+primitive(/*1460:*/
+#line 25276 "tex.w"
+335
+/*:1460*/
+#line 5184 "tex.w"
+,
+assign_int,int_base+double_hyphen_demerits_code);
+
+primitive(/*1461:*/
+#line 25279 "tex.w"
+336
+/*:1461*/
+#line 5187 "tex.w"
+,
+assign_int,int_base+final_hyphen_demerits_code);
+
+primitive(/*1462:*/
+#line 25282 "tex.w"
+337
+/*:1462*/
+#line 5190 "tex.w"
+,assign_int,int_base+adj_demerits_code);
+
+primitive(/*1463:*/
+#line 25285 "tex.w"
+338
+/*:1463*/
+#line 5192 "tex.w"
+,assign_int,int_base+mag_code);
+
+primitive(/*1464:*/
+#line 25288 "tex.w"
+339
+/*:1464*/
+#line 5194 "tex.w"
+,assign_int,int_base+delimiter_factor_code);
+
+primitive(/*1465:*/
+#line 25291 "tex.w"
+340
+/*:1465*/
+#line 5196 "tex.w"
+,assign_int,int_base+looseness_code);
+
+primitive(/*1466:*/
+#line 25294 "tex.w"
+341
+/*:1466*/
+#line 5198 "tex.w"
+,assign_int,int_base+time_code);
+
+primitive(/*1467:*/
+#line 25297 "tex.w"
+342
+/*:1467*/
+#line 5200 "tex.w"
+,assign_int,int_base+day_code);
+
+primitive(/*1468:*/
+#line 25300 "tex.w"
+343
+/*:1468*/
+#line 5202 "tex.w"
+,assign_int,int_base+month_code);
+
+primitive(/*1469:*/
+#line 25303 "tex.w"
+344
+/*:1469*/
+#line 5204 "tex.w"
+,assign_int,int_base+year_code);
+
+primitive(/*1470:*/
+#line 25306 "tex.w"
+345
+/*:1470*/
+#line 5206 "tex.w"
+,assign_int,int_base+show_box_breadth_code);
+
+primitive(/*1471:*/
+#line 25309 "tex.w"
+346
+/*:1471*/
+#line 5208 "tex.w"
+,assign_int,int_base+show_box_depth_code);
+
+primitive(/*1472:*/
+#line 25312 "tex.w"
+347
+/*:1472*/
+#line 5210 "tex.w"
+,assign_int,int_base+hbadness_code);
+
+primitive(/*1473:*/
+#line 25315 "tex.w"
+348
+/*:1473*/
+#line 5212 "tex.w"
+,assign_int,int_base+vbadness_code);
+
+primitive(/*1474:*/
+#line 25318 "tex.w"
+349
+/*:1474*/
+#line 5214 "tex.w"
+,assign_int,int_base+pausing_code);
+
+primitive(/*1475:*/
+#line 25321 "tex.w"
+350
+/*:1475*/
+#line 5216 "tex.w"
+,assign_int,int_base+tracing_online_code);
+
+primitive(/*1476:*/
+#line 25324 "tex.w"
+351
+/*:1476*/
+#line 5218 "tex.w"
+,assign_int,int_base+tracing_macros_code);
+
+primitive(/*1477:*/
+#line 25327 "tex.w"
+352
+/*:1477*/
+#line 5220 "tex.w"
+,assign_int,int_base+tracing_stats_code);
+
+primitive(/*1478:*/
+#line 25330 "tex.w"
+353
+/*:1478*/
+#line 5222 "tex.w"
+,assign_int,int_base+tracing_paragraphs_code);
+
+primitive(/*1479:*/
+#line 25333 "tex.w"
+354
+/*:1479*/
+#line 5224 "tex.w"
+,assign_int,int_base+tracing_pages_code);
+
+primitive(/*1480:*/
+#line 25336 "tex.w"
+355
+/*:1480*/
+#line 5226 "tex.w"
+,assign_int,int_base+tracing_output_code);
+
+primitive(/*1481:*/
+#line 25339 "tex.w"
+356
+/*:1481*/
+#line 5228 "tex.w"
+,assign_int,int_base+tracing_lost_chars_code);
+
+primitive(/*1482:*/
+#line 25342 "tex.w"
+357
+/*:1482*/
+#line 5230 "tex.w"
+,assign_int,int_base+tracing_commands_code);
+
+primitive(/*1483:*/
+#line 25345 "tex.w"
+358
+/*:1483*/
+#line 5232 "tex.w"
+,assign_int,int_base+tracing_restores_code);
+
+primitive(/*1484:*/
+#line 25348 "tex.w"
+359
+/*:1484*/
+#line 5234 "tex.w"
+,assign_int,int_base+uc_hyph_code);
+
+primitive(/*1485:*/
+#line 25351 "tex.w"
+360
+/*:1485*/
+#line 5236 "tex.w"
+,assign_int,int_base+output_penalty_code);
+
+primitive(/*1486:*/
+#line 25354 "tex.w"
+361
+/*:1486*/
+#line 5238 "tex.w"
+,assign_int,int_base+max_dead_cycles_code);
+
+primitive(/*1487:*/
+#line 25357 "tex.w"
+362
+/*:1487*/
+#line 5240 "tex.w"
+,assign_int,int_base+hang_after_code);
+
+primitive(/*1488:*/
+#line 25360 "tex.w"
+363
+/*:1488*/
+#line 5242 "tex.w"
+,assign_int,int_base+floating_penalty_code);
+
+primitive(/*1489:*/
+#line 25363 "tex.w"
+364
+/*:1489*/
+#line 5244 "tex.w"
+,assign_int,int_base+global_defs_code);
+
+primitive(/*1490:*/
+#line 25366 "tex.w"
+365
+/*:1490*/
+#line 5246 "tex.w"
+,assign_int,int_base+cur_fam_code);
+
+primitive(/*1491:*/
+#line 25369 "tex.w"
+366
+/*:1491*/
+#line 5248 "tex.w"
+,assign_int,int_base+escape_char_code);
+
+primitive(/*1492:*/
+#line 25372 "tex.w"
+367
+/*:1492*/
+#line 5250 "tex.w"
+,assign_int,int_base+default_hyphen_char_code);
+
+primitive(/*1493:*/
+#line 25375 "tex.w"
+368
+/*:1493*/
+#line 5252 "tex.w"
+,assign_int,int_base+default_skew_char_code);
+
+primitive(/*1494:*/
+#line 25378 "tex.w"
+369
+/*:1494*/
+#line 5254 "tex.w"
+,assign_int,int_base+end_line_char_code);
+
+primitive(/*1495:*/
+#line 25381 "tex.w"
+370
+/*:1495*/
+#line 5256 "tex.w"
+,assign_int,int_base+new_line_char_code);
+
+primitive(/*1496:*/
+#line 25384 "tex.w"
+371
+/*:1496*/
+#line 5258 "tex.w"
+,assign_int,int_base+language_code);
+
+primitive(/*1497:*/
+#line 25387 "tex.w"
+372
+/*:1497*/
+#line 5260 "tex.w"
+,assign_int,int_base+left_hyphen_min_code);
+
+primitive(/*1498:*/
+#line 25390 "tex.w"
+373
+/*:1498*/
+#line 5262 "tex.w"
+,assign_int,int_base+right_hyphen_min_code);
+
+primitive(/*1499:*/
+#line 25393 "tex.w"
+374
+/*:1499*/
+#line 5264 "tex.w"
+,assign_int,int_base+holding_inserts_code);
+
+primitive(/*1500:*/
+#line 25396 "tex.w"
+375
+/*:1500*/
+#line 5266 "tex.w"
+,assign_int,int_base+error_context_lines_code);
+
+
+/*:238*//*248:*/
+#line 5419 "tex.w"
+
+primitive(/*1503:*/
+#line 25405 "tex.w"
+378
+/*:1503*/
+#line 5420 "tex.w"
+,assign_dimen,dimen_base+par_indent_code);
+
+primitive(/*1504:*/
+#line 25408 "tex.w"
+379
+/*:1504*/
+#line 5422 "tex.w"
+,assign_dimen,dimen_base+math_surround_code);
+
+primitive(/*1505:*/
+#line 25411 "tex.w"
+380
+/*:1505*/
+#line 5424 "tex.w"
+,assign_dimen,dimen_base+line_skip_limit_code);
+
+primitive(/*1506:*/
+#line 25414 "tex.w"
+381
+/*:1506*/
+#line 5426 "tex.w"
+,assign_dimen,dimen_base+hsize_code);
+
+primitive(/*1507:*/
+#line 25417 "tex.w"
+382
+/*:1507*/
+#line 5428 "tex.w"
+,assign_dimen,dimen_base+vsize_code);
+
+primitive(/*1508:*/
+#line 25420 "tex.w"
+383
+/*:1508*/
+#line 5430 "tex.w"
+,assign_dimen,dimen_base+max_depth_code);
+
+primitive(/*1509:*/
+#line 25423 "tex.w"
+384
+/*:1509*/
+#line 5432 "tex.w"
+,assign_dimen,dimen_base+split_max_depth_code);
+
+primitive(/*1510:*/
+#line 25426 "tex.w"
+385
+/*:1510*/
+#line 5434 "tex.w"
+,assign_dimen,dimen_base+box_max_depth_code);
+
+primitive(/*1511:*/
+#line 25429 "tex.w"
+386
+/*:1511*/
+#line 5436 "tex.w"
+,assign_dimen,dimen_base+hfuzz_code);
+
+primitive(/*1512:*/
+#line 25432 "tex.w"
+387
+/*:1512*/
+#line 5438 "tex.w"
+,assign_dimen,dimen_base+vfuzz_code);
+
+primitive(/*1513:*/
+#line 25435 "tex.w"
+388
+/*:1513*/
+#line 5440 "tex.w"
+,
+assign_dimen,dimen_base+delimiter_shortfall_code);
+
+primitive(/*1514:*/
+#line 25438 "tex.w"
+389
+/*:1514*/
+#line 5443 "tex.w"
+,
+assign_dimen,dimen_base+null_delimiter_space_code);
+
+primitive(/*1515:*/
+#line 25441 "tex.w"
+390
+/*:1515*/
+#line 5446 "tex.w"
+,assign_dimen,dimen_base+script_space_code);
+
+primitive(/*1516:*/
+#line 25444 "tex.w"
+391
+/*:1516*/
+#line 5448 "tex.w"
+,assign_dimen,dimen_base+pre_display_size_code);
+
+primitive(/*1517:*/
+#line 25447 "tex.w"
+392
+/*:1517*/
+#line 5450 "tex.w"
+,assign_dimen,dimen_base+display_width_code);
+
+primitive(/*1518:*/
+#line 25450 "tex.w"
+393
+/*:1518*/
+#line 5452 "tex.w"
+,assign_dimen,dimen_base+display_indent_code);
+
+primitive(/*1519:*/
+#line 25453 "tex.w"
+394
+/*:1519*/
+#line 5454 "tex.w"
+,assign_dimen,dimen_base+overfull_rule_code);
+
+primitive(/*1520:*/
+#line 25456 "tex.w"
+395
+/*:1520*/
+#line 5456 "tex.w"
+,assign_dimen,dimen_base+hang_indent_code);
+
+primitive(/*1521:*/
+#line 25459 "tex.w"
+396
+/*:1521*/
+#line 5458 "tex.w"
+,assign_dimen,dimen_base+h_offset_code);
+
+primitive(/*1522:*/
+#line 25462 "tex.w"
+397
+/*:1522*/
+#line 5460 "tex.w"
+,assign_dimen,dimen_base+v_offset_code);
+
+primitive(/*1523:*/
+#line 25465 "tex.w"
+398
+/*:1523*/
+#line 5462 "tex.w"
+,assign_dimen,dimen_base+emergency_stretch_code);
+
+
+/*:248*//*265:*/
+#line 5701 "tex.w"
+
+primitive(' ',ex_space,0);
+
+primitive('/',ital_corr,0);
+
+primitive(/*1530:*/
+#line 25486 "tex.w"
+405
+/*:1530*/
+#line 5706 "tex.w"
+,accent,0);
+
+primitive(/*1531:*/
+#line 25489 "tex.w"
+406
+/*:1531*/
+#line 5708 "tex.w"
+,advance,0);
+
+primitive(/*1532:*/
+#line 25492 "tex.w"
+407
+/*:1532*/
+#line 5710 "tex.w"
+,after_assignment,0);
+
+primitive(/*1533:*/
+#line 25495 "tex.w"
+408
+/*:1533*/
+#line 5712 "tex.w"
+,after_group,0);
+
+primitive(/*1534:*/
+#line 25498 "tex.w"
+409
+/*:1534*/
+#line 5714 "tex.w"
+,begin_group,0);
+
+primitive(/*1535:*/
+#line 25501 "tex.w"
+410
+/*:1535*/
+#line 5716 "tex.w"
+,char_num,0);
+
+primitive(/*1526:*/
+#line 25474 "tex.w"
+401
+/*:1526*/
+#line 5718 "tex.w"
+,cs_name,0);
+
+primitive(/*1536:*/
+#line 25504 "tex.w"
+411
+/*:1536*/
+#line 5720 "tex.w"
+,delim_num,0);
+
+primitive(/*1537:*/
+#line 25507 "tex.w"
+412
+/*:1537*/
+#line 5722 "tex.w"
+,divide,0);
+
+primitive(/*1527:*/
+#line 25477 "tex.w"
+402
+/*:1527*/
+#line 5724 "tex.w"
+,end_cs_name,0);
+
+primitive(/*1538:*/
+#line 25510 "tex.w"
+413
+/*:1538*/
+#line 5726 "tex.w"
+,end_group,0);
+
+text(frozen_end_group)= /*1538:*/
+#line 25510 "tex.w"
+413
+/*:1538*/
+#line 5728 "tex.w"
+;eqtb[frozen_end_group]= eqtb[cur_val];
+primitive(/*1539:*/
+#line 25513 "tex.w"
+414
+/*:1539*/
+#line 5729 "tex.w"
+,expand_after,0);
+
+primitive(/*1540:*/
+#line 25516 "tex.w"
+415
+/*:1540*/
+#line 5731 "tex.w"
+,def_font,0);
+
+primitive(/*1541:*/
+#line 25519 "tex.w"
+416
+/*:1541*/
+#line 5733 "tex.w"
+,assign_font_dimen,0);
+
+primitive(/*1542:*/
+#line 25522 "tex.w"
+417
+/*:1542*/
+#line 5735 "tex.w"
+,halign,0);
+
+primitive(/*1543:*/
+#line 25525 "tex.w"
+418
+/*:1543*/
+#line 5737 "tex.w"
+,hrule,0);
+
+primitive(/*1544:*/
+#line 25528 "tex.w"
+419
+/*:1544*/
+#line 5739 "tex.w"
+,ignore_spaces,0);
+
+primitive(/*1390:*/
+#line 25066 "tex.w"
+265
+/*:1390*/
+#line 5741 "tex.w"
+,insert,0);
+
+primitive(/*1401:*/
+#line 25099 "tex.w"
+276
+/*:1401*/
+#line 5743 "tex.w"
+,mark,0);
+
+primitive(/*1545:*/
+#line 25531 "tex.w"
+420
+/*:1545*/
+#line 5745 "tex.w"
+,math_accent,0);
+
+primitive(/*1546:*/
+#line 25534 "tex.w"
+421
+/*:1546*/
+#line 5747 "tex.w"
+,math_char_num,0);
+
+primitive(/*1547:*/
+#line 25537 "tex.w"
+422
+/*:1547*/
+#line 5749 "tex.w"
+,math_choice,0);
+
+primitive(/*1548:*/
+#line 25540 "tex.w"
+423
+/*:1548*/
+#line 5751 "tex.w"
+,multiply,0);
+
+primitive(/*1549:*/
+#line 25543 "tex.w"
+424
+/*:1549*/
+#line 5753 "tex.w"
+,no_align,0);
+
+primitive(/*1550:*/
+#line 25546 "tex.w"
+425
+/*:1550*/
+#line 5755 "tex.w"
+,no_boundary,0);
+
+primitive(/*1551:*/
+#line 25549 "tex.w"
+426
+/*:1551*/
+#line 5757 "tex.w"
+,no_expand,0);
+
+primitive(/*1392:*/
+#line 25072 "tex.w"
+267
+/*:1392*/
+#line 5759 "tex.w"
+,non_script,0);
+
+primitive(/*1552:*/
+#line 25552 "tex.w"
+427
+/*:1552*/
+#line 5761 "tex.w"
+,omit,0);
+
+primitive(/*1436:*/
+#line 25204 "tex.w"
+311
+/*:1436*/
+#line 5763 "tex.w"
+,set_shape,0);
+
+primitive(/*1553:*/
+#line 25555 "tex.w"
+428
+/*:1553*/
+#line 5765 "tex.w"
+,break_penalty,0);
+
+primitive(/*1554:*/
+#line 25558 "tex.w"
+429
+/*:1554*/
+#line 5767 "tex.w"
+,set_prev_graf,0);
+
+primitive(/*1555:*/
+#line 25561 "tex.w"
+430
+/*:1555*/
+#line 5769 "tex.w"
+,radical,0);
+
+primitive(/*1556:*/
+#line 25564 "tex.w"
+431
+/*:1556*/
+#line 5771 "tex.w"
+,read_to_cs,0);
+
+primitive(/*1557:*/
+#line 25567 "tex.w"
+432
+/*:1557*/
+#line 5773 "tex.w"
+,relax,256);
+
+text(frozen_relax)= /*1557:*/
+#line 25567 "tex.w"
+432
+/*:1557*/
+#line 5775 "tex.w"
+;eqtb[frozen_relax]= eqtb[cur_val];
+primitive(/*1558:*/
+#line 25570 "tex.w"
+433
+/*:1558*/
+#line 5776 "tex.w"
+,set_box,0);
+
+primitive(/*1559:*/
+#line 25573 "tex.w"
+434
+/*:1559*/
+#line 5778 "tex.w"
+,the,0);
+
+primitive(/*1435:*/
+#line 25201 "tex.w"
+310
+/*:1435*/
+#line 5780 "tex.w"
+,toks_register,0);
+
+primitive(/*1402:*/
+#line 25102 "tex.w"
+277
+/*:1402*/
+#line 5782 "tex.w"
+,vadjust,0);
+
+primitive(/*1560:*/
+#line 25576 "tex.w"
+435
+/*:1560*/
+#line 5784 "tex.w"
+,valign,0);
+
+primitive(/*1561:*/
+#line 25579 "tex.w"
+436
+/*:1561*/
+#line 5786 "tex.w"
+,vcenter,0);
+
+primitive(/*1562:*/
+#line 25582 "tex.w"
+437
+/*:1562*/
+#line 5788 "tex.w"
+,vrule,0);
+
+
+/*:265*//*334:*/
+#line 7198 "tex.w"
+
+primitive(/*1569:*/
+#line 25603 "tex.w"
+444
+/*:1569*/
+#line 7199 "tex.w"
+,par_end,256);
+
+par_loc= cur_val;par_token= cs_token_flag+par_loc;
+
+/*:334*//*376:*/
+#line 7848 "tex.w"
+
+primitive(/*1570:*/
+#line 25606 "tex.w"
+445
+/*:1570*/
+#line 7849 "tex.w"
+,input,0);
+
+primitive(/*1571:*/
+#line 25609 "tex.w"
+446
+/*:1571*/
+#line 7851 "tex.w"
+,input,1);
+
+
+/*:376*//*384:*/
+#line 7933 "tex.w"
+
+primitive(/*1572:*/
+#line 25612 "tex.w"
+447
+/*:1572*/
+#line 7934 "tex.w"
+,top_bot_mark,top_mark_code);
+
+primitive(/*1573:*/
+#line 25615 "tex.w"
+448
+/*:1573*/
+#line 7936 "tex.w"
+,top_bot_mark,first_mark_code);
+
+primitive(/*1574:*/
+#line 25618 "tex.w"
+449
+/*:1574*/
+#line 7938 "tex.w"
+,top_bot_mark,bot_mark_code);
+
+primitive(/*1575:*/
+#line 25621 "tex.w"
+450
+/*:1575*/
+#line 7940 "tex.w"
+,top_bot_mark,split_first_mark_code);
+
+primitive(/*1576:*/
+#line 25624 "tex.w"
+451
+/*:1576*/
+#line 7942 "tex.w"
+,top_bot_mark,split_bot_mark_code);
+
+
+/*:384*//*411:*/
+#line 8378 "tex.w"
+
+primitive(/*1501:*/
+#line 25399 "tex.w"
+376
+/*:1501*/
+#line 8379 "tex.w"
+,register,int_val);
+
+primitive(/*1524:*/
+#line 25468 "tex.w"
+399
+/*:1524*/
+#line 8381 "tex.w"
+,register,dimen_val);
+
+primitive(/*1423:*/
+#line 25165 "tex.w"
+298
+/*:1423*/
+#line 8383 "tex.w"
+,register,glue_val);
+
+primitive(/*1424:*/
+#line 25168 "tex.w"
+299
+/*:1424*/
+#line 8385 "tex.w"
+,register,mu_val);
+
+
+/*:411*//*416:*/
+#line 8472 "tex.w"
+
+primitive(/*1577:*/
+#line 25627 "tex.w"
+452
+/*:1577*/
+#line 8473 "tex.w"
+,set_aux,hmode);
+
+primitive(/*1578:*/
+#line 25630 "tex.w"
+453
+/*:1578*/
+#line 8475 "tex.w"
+,set_aux,vmode);
+
+primitive(/*1579:*/
+#line 25633 "tex.w"
+454
+/*:1579*/
+#line 8477 "tex.w"
+,set_page_int,0);
+
+primitive(/*1580:*/
+#line 25636 "tex.w"
+455
+/*:1580*/
+#line 8479 "tex.w"
+,set_page_int,1);
+
+primitive(/*1581:*/
+#line 25639 "tex.w"
+456
+/*:1581*/
+#line 8481 "tex.w"
+,set_box_dimen,width_offset);
+
+primitive(/*1582:*/
+#line 25642 "tex.w"
+457
+/*:1582*/
+#line 8483 "tex.w"
+,set_box_dimen,height_offset);
+
+primitive(/*1583:*/
+#line 25645 "tex.w"
+458
+/*:1583*/
+#line 8485 "tex.w"
+,set_box_dimen,depth_offset);
+
+primitive(/*1584:*/
+#line 25648 "tex.w"
+459
+/*:1584*/
+#line 8487 "tex.w"
+,last_item,int_val);
+
+primitive(/*1585:*/
+#line 25651 "tex.w"
+460
+/*:1585*/
+#line 8489 "tex.w"
+,last_item,dimen_val);
+
+primitive(/*1586:*/
+#line 25654 "tex.w"
+461
+/*:1586*/
+#line 8491 "tex.w"
+,last_item,glue_val);
+
+primitive(/*1587:*/
+#line 25657 "tex.w"
+462
+/*:1587*/
+#line 8493 "tex.w"
+,last_item,input_line_no_code);
+
+primitive(/*1588:*/
+#line 25660 "tex.w"
+463
+/*:1588*/
+#line 8495 "tex.w"
+,last_item,badness_code);
+
+
+/*:416*//*468:*/
+#line 9273 "tex.w"
+
+primitive(/*1605:*/
+#line 25711 "tex.w"
+480
+/*:1605*/
+#line 9274 "tex.w"
+,convert,number_code);
+
+primitive(/*1606:*/
+#line 25714 "tex.w"
+481
+/*:1606*/
+#line 9276 "tex.w"
+,convert,roman_numeral_code);
+
+primitive(/*1607:*/
+#line 25717 "tex.w"
+482
+/*:1607*/
+#line 9278 "tex.w"
+,convert,string_code);
+
+primitive(/*1608:*/
+#line 25720 "tex.w"
+483
+/*:1608*/
+#line 9280 "tex.w"
+,convert,meaning_code);
+
+primitive(/*1609:*/
+#line 25723 "tex.w"
+484
+/*:1609*/
+#line 9282 "tex.w"
+,convert,font_name_code);
+
+primitive(/*1610:*/
+#line 25726 "tex.w"
+485
+/*:1610*/
+#line 9284 "tex.w"
+,convert,job_name_code);
+
+
+/*:468*//*487:*/
+#line 9589 "tex.w"
+
+primitive(/*1611:*/
+#line 25729 "tex.w"
+486
+/*:1611*/
+#line 9590 "tex.w"
+,if_test,if_char_code);
+
+primitive(/*1612:*/
+#line 25732 "tex.w"
+487
+/*:1612*/
+#line 9592 "tex.w"
+,if_test,if_cat_code);
+
+primitive(/*1613:*/
+#line 25735 "tex.w"
+488
+/*:1613*/
+#line 9594 "tex.w"
+,if_test,if_int_code);
+
+primitive(/*1614:*/
+#line 25738 "tex.w"
+489
+/*:1614*/
+#line 9596 "tex.w"
+,if_test,if_dim_code);
+
+primitive(/*1615:*/
+#line 25741 "tex.w"
+490
+/*:1615*/
+#line 9598 "tex.w"
+,if_test,if_odd_code);
+
+primitive(/*1616:*/
+#line 25744 "tex.w"
+491
+/*:1616*/
+#line 9600 "tex.w"
+,if_test,if_vmode_code);
+
+primitive(/*1617:*/
+#line 25747 "tex.w"
+492
+/*:1617*/
+#line 9602 "tex.w"
+,if_test,if_hmode_code);
+
+primitive(/*1618:*/
+#line 25750 "tex.w"
+493
+/*:1618*/
+#line 9604 "tex.w"
+,if_test,if_mmode_code);
+
+primitive(/*1619:*/
+#line 25753 "tex.w"
+494
+/*:1619*/
+#line 9606 "tex.w"
+,if_test,if_inner_code);
+
+primitive(/*1620:*/
+#line 25756 "tex.w"
+495
+/*:1620*/
+#line 9608 "tex.w"
+,if_test,if_void_code);
+
+primitive(/*1621:*/
+#line 25759 "tex.w"
+496
+/*:1621*/
+#line 9610 "tex.w"
+,if_test,if_hbox_code);
+
+primitive(/*1622:*/
+#line 25762 "tex.w"
+497
+/*:1622*/
+#line 9612 "tex.w"
+,if_test,if_vbox_code);
+
+primitive(/*1623:*/
+#line 25765 "tex.w"
+498
+/*:1623*/
+#line 9614 "tex.w"
+,if_test,ifx_code);
+
+primitive(/*1624:*/
+#line 25768 "tex.w"
+499
+/*:1624*/
+#line 9616 "tex.w"
+,if_test,if_eof_code);
+
+primitive(/*1625:*/
+#line 25771 "tex.w"
+500
+/*:1625*/
+#line 9618 "tex.w"
+,if_test,if_true_code);
+
+primitive(/*1626:*/
+#line 25774 "tex.w"
+501
+/*:1626*/
+#line 9620 "tex.w"
+,if_test,if_false_code);
+
+primitive(/*1627:*/
+#line 25777 "tex.w"
+502
+/*:1627*/
+#line 9622 "tex.w"
+,if_test,if_case_code);
+
+
+/*:487*//*491:*/
+#line 9678 "tex.w"
+
+primitive(/*1628:*/
+#line 25780 "tex.w"
+503
+/*:1628*/
+#line 9679 "tex.w"
+,fi_or_else,fi_code);
+
+text(frozen_fi)= /*1628:*/
+#line 25780 "tex.w"
+503
+/*:1628*/
+#line 9681 "tex.w"
+;eqtb[frozen_fi]= eqtb[cur_val];
+primitive(/*1629:*/
+#line 25783 "tex.w"
+504
+/*:1629*/
+#line 9682 "tex.w"
+,fi_or_else,or_code);
+
+primitive(/*1630:*/
+#line 25786 "tex.w"
+505
+/*:1630*/
+#line 9684 "tex.w"
+,fi_or_else,else_code);
+
+
+/*:491*//*553:*/
+#line 10835 "tex.w"
+
+primitive(/*1639:*/
+#line 25813 "tex.w"
+514
+/*:1639*/
+#line 10836 "tex.w"
+,set_font,null_font);
+
+text(frozen_null_font)= /*1639:*/
+#line 25813 "tex.w"
+514
+/*:1639*/
+#line 10838 "tex.w"
+;eqtb[frozen_null_font]= eqtb[cur_val];
+
+/*:553*//*780:*/
+#line 15416 "tex.w"
+
+primitive(/*1669:*/
+#line 25903 "tex.w"
+544
+/*:1669*/
+#line 15417 "tex.w"
+,tab_mark,span_code);
+
+primitive(/*1670:*/
+#line 25906 "tex.w"
+545
+/*:1670*/
+#line 15419 "tex.w"
+,car_ret,cr_code);
+
+text(frozen_cr)= /*1670:*/
+#line 25906 "tex.w"
+545
+/*:1670*/
+#line 15421 "tex.w"
+;eqtb[frozen_cr]= eqtb[cur_val];
+primitive(/*1671:*/
+#line 25909 "tex.w"
+546
+/*:1671*/
+#line 15422 "tex.w"
+,car_ret,cr_cr_code);
+
+text(frozen_end_template)= /*1672:*/
+#line 25912 "tex.w"
+547
+/*:1672*/
+#line 15424 "tex.w"
+;text(frozen_endv)= /*1672:*/
+#line 25912 "tex.w"
+547
+/*:1672*/
+#line 15424 "tex.w"
+;
+eq_type(frozen_endv)= endv;equiv(frozen_endv)= null_list;
+eq_level(frozen_endv)= level_one;
+eqtb[frozen_end_template]= eqtb[frozen_endv];
+eq_type(frozen_end_template)= end_template;
+
+/*:780*//*983:*/
+#line 19251 "tex.w"
+
+primitive(/*1689:*/
+#line 25963 "tex.w"
+564
+/*:1689*/
+#line 19252 "tex.w"
+,set_page_dimen,0);
+
+primitive(/*1690:*/
+#line 25966 "tex.w"
+565
+/*:1690*/
+#line 19254 "tex.w"
+,set_page_dimen,1);
+
+primitive(/*1691:*/
+#line 25969 "tex.w"
+566
+/*:1691*/
+#line 19256 "tex.w"
+,set_page_dimen,2);
+
+primitive(/*1692:*/
+#line 25972 "tex.w"
+567
+/*:1692*/
+#line 19258 "tex.w"
+,set_page_dimen,3);
+
+primitive(/*1693:*/
+#line 25975 "tex.w"
+568
+/*:1693*/
+#line 19260 "tex.w"
+,set_page_dimen,4);
+
+primitive(/*1694:*/
+#line 25978 "tex.w"
+569
+/*:1694*/
+#line 19262 "tex.w"
+,set_page_dimen,5);
+
+primitive(/*1695:*/
+#line 25981 "tex.w"
+570
+/*:1695*/
+#line 19264 "tex.w"
+,set_page_dimen,6);
+
+primitive(/*1696:*/
+#line 25984 "tex.w"
+571
+/*:1696*/
+#line 19266 "tex.w"
+,set_page_dimen,7);
+
+
+/*:983*//*1052:*/
+#line 20471 "tex.w"
+
+primitive(/*1698:*/
+#line 25990 "tex.w"
+573
+/*:1698*/
+#line 20472 "tex.w"
+,stop,0);
+
+primitive(/*1699:*/
+#line 25993 "tex.w"
+574
+/*:1699*/
+#line 20474 "tex.w"
+,stop,1);
+
+
+/*:1052*//*1058:*/
+#line 20547 "tex.w"
+
+primitive(/*1700:*/
+#line 25996 "tex.w"
+575
+/*:1700*/
+#line 20548 "tex.w"
+,hskip,skip_code);
+
+primitive(/*1701:*/
+#line 25999 "tex.w"
+576
+/*:1701*/
+#line 20550 "tex.w"
+,hskip,fil_code);
+
+primitive(/*1702:*/
+#line 26002 "tex.w"
+577
+/*:1702*/
+#line 20552 "tex.w"
+,hskip,fill_code);
+
+primitive(/*1703:*/
+#line 26005 "tex.w"
+578
+/*:1703*/
+#line 20554 "tex.w"
+,hskip,ss_code);
+
+primitive(/*1704:*/
+#line 26008 "tex.w"
+579
+/*:1704*/
+#line 20556 "tex.w"
+,hskip,fil_neg_code);
+
+primitive(/*1705:*/
+#line 26011 "tex.w"
+580
+/*:1705*/
+#line 20558 "tex.w"
+,vskip,skip_code);
+
+primitive(/*1706:*/
+#line 26014 "tex.w"
+581
+/*:1706*/
+#line 20560 "tex.w"
+,vskip,fil_code);
+
+primitive(/*1707:*/
+#line 26017 "tex.w"
+582
+/*:1707*/
+#line 20562 "tex.w"
+,vskip,fill_code);
+
+primitive(/*1708:*/
+#line 26020 "tex.w"
+583
+/*:1708*/
+#line 20564 "tex.w"
+,vskip,ss_code);
+
+primitive(/*1709:*/
+#line 26023 "tex.w"
+584
+/*:1709*/
+#line 20566 "tex.w"
+,vskip,fil_neg_code);
+
+primitive(/*1393:*/
+#line 25075 "tex.w"
+268
+/*:1393*/
+#line 20568 "tex.w"
+,mskip,mskip_code);
+
+primitive(/*1396:*/
+#line 25084 "tex.w"
+271
+/*:1396*/
+#line 20570 "tex.w"
+,kern,explicit);
+
+primitive(/*1397:*/
+#line 25087 "tex.w"
+272
+/*:1397*/
+#line 20572 "tex.w"
+,mkern,mu_glue);
+
+
+/*:1058*//*1071:*/
+#line 20804 "tex.w"
+
+primitive(/*1712:*/
+#line 26032 "tex.w"
+587
+/*:1712*/
+#line 20805 "tex.w"
+,hmove,1);
+
+primitive(/*1713:*/
+#line 26035 "tex.w"
+588
+/*:1713*/
+#line 20807 "tex.w"
+,hmove,0);
+
+primitive(/*1714:*/
+#line 26038 "tex.w"
+589
+/*:1714*/
+#line 20809 "tex.w"
+,vmove,1);
+
+primitive(/*1715:*/
+#line 26041 "tex.w"
+590
+/*:1715*/
+#line 20811 "tex.w"
+,vmove,0);
+
+
+primitive(/*1437:*/
+#line 25207 "tex.w"
+312
+/*:1437*/
+#line 20814 "tex.w"
+,make_box,box_code);
+
+primitive(/*1716:*/
+#line 26044 "tex.w"
+591
+/*:1716*/
+#line 20816 "tex.w"
+,make_box,copy_code);
+
+primitive(/*1717:*/
+#line 26047 "tex.w"
+592
+/*:1717*/
+#line 20818 "tex.w"
+,make_box,last_box_code);
+
+primitive(/*1687:*/
+#line 25957 "tex.w"
+562
+/*:1687*/
+#line 20820 "tex.w"
+,make_box,vsplit_code);
+
+primitive(/*1718:*/
+#line 26050 "tex.w"
+593
+/*:1718*/
+#line 20822 "tex.w"
+,make_box,vtop_code);
+
+primitive(/*1688:*/
+#line 25960 "tex.w"
+563
+/*:1688*/
+#line 20824 "tex.w"
+,make_box,vtop_code+vmode);
+
+primitive(/*1719:*/
+#line 26053 "tex.w"
+594
+/*:1719*/
+#line 20826 "tex.w"
+,make_box,vtop_code+hmode);
+
+primitive(/*1720:*/
+#line 26056 "tex.w"
+595
+/*:1720*/
+#line 20828 "tex.w"
+,leader_ship,a_leaders-1);
+
+primitive(/*1721:*/
+#line 26059 "tex.w"
+596
+/*:1721*/
+#line 20830 "tex.w"
+,leader_ship,a_leaders);
+
+primitive(/*1722:*/
+#line 26062 "tex.w"
+597
+/*:1722*/
+#line 20832 "tex.w"
+,leader_ship,c_leaders);
+
+primitive(/*1723:*/
+#line 26065 "tex.w"
+598
+/*:1723*/
+#line 20834 "tex.w"
+,leader_ship,x_leaders);
+
+
+/*:1071*//*1088:*/
+#line 21092 "tex.w"
+
+primitive(/*1724:*/
+#line 26068 "tex.w"
+599
+/*:1724*/
+#line 21093 "tex.w"
+,start_par,1);
+
+primitive(/*1725:*/
+#line 26071 "tex.w"
+600
+/*:1725*/
+#line 21095 "tex.w"
+,start_par,0);
+
+
+/*:1088*//*1107:*/
+#line 21300 "tex.w"
+
+primitive(/*1726:*/
+#line 26074 "tex.w"
+601
+/*:1726*/
+#line 21301 "tex.w"
+,remove_item,penalty_node);
+
+primitive(/*1727:*/
+#line 26077 "tex.w"
+602
+/*:1727*/
+#line 21303 "tex.w"
+,remove_item,kern_node);
+
+primitive(/*1728:*/
+#line 26080 "tex.w"
+603
+/*:1728*/
+#line 21305 "tex.w"
+,remove_item,glue_node);
+
+primitive(/*1729:*/
+#line 26083 "tex.w"
+604
+/*:1729*/
+#line 21307 "tex.w"
+,un_hbox,box_code);
+
+primitive(/*1730:*/
+#line 26086 "tex.w"
+605
+/*:1730*/
+#line 21309 "tex.w"
+,un_hbox,copy_code);
+
+primitive(/*1731:*/
+#line 26089 "tex.w"
+606
+/*:1731*/
+#line 21311 "tex.w"
+,un_vbox,box_code);
+
+primitive(/*1732:*/
+#line 26092 "tex.w"
+607
+/*:1732*/
+#line 21313 "tex.w"
+,un_vbox,copy_code);
+
+
+/*:1107*//*1114:*/
+#line 21381 "tex.w"
+
+primitive('-',discretionary,1);
+
+primitive(/*1400:*/
+#line 25096 "tex.w"
+275
+/*:1400*/
+#line 21384 "tex.w"
+,discretionary,0);
+
+
+/*:1114*//*1141:*/
+#line 21730 "tex.w"
+
+primitive(/*1733:*/
+#line 26095 "tex.w"
+608
+/*:1733*/
+#line 21731 "tex.w"
+,eq_no,0);
+
+primitive(/*1734:*/
+#line 26098 "tex.w"
+609
+/*:1734*/
+#line 21733 "tex.w"
+,eq_no,1);
+
+
+/*:1141*//*1156:*/
+#line 21966 "tex.w"
+
+primitive(/*1649:*/
+#line 25843 "tex.w"
+524
+/*:1649*/
+#line 21967 "tex.w"
+,math_comp,ord_noad);
+
+primitive(/*1650:*/
+#line 25846 "tex.w"
+525
+/*:1650*/
+#line 21969 "tex.w"
+,math_comp,op_noad);
+
+primitive(/*1651:*/
+#line 25849 "tex.w"
+526
+/*:1651*/
+#line 21971 "tex.w"
+,math_comp,bin_noad);
+
+primitive(/*1652:*/
+#line 25852 "tex.w"
+527
+/*:1652*/
+#line 21973 "tex.w"
+,math_comp,rel_noad);
+
+primitive(/*1653:*/
+#line 25855 "tex.w"
+528
+/*:1653*/
+#line 21975 "tex.w"
+,math_comp,open_noad);
+
+primitive(/*1654:*/
+#line 25858 "tex.w"
+529
+/*:1654*/
+#line 21977 "tex.w"
+,math_comp,close_noad);
+
+primitive(/*1655:*/
+#line 25861 "tex.w"
+530
+/*:1655*/
+#line 21979 "tex.w"
+,math_comp,punct_noad);
+
+primitive(/*1656:*/
+#line 25864 "tex.w"
+531
+/*:1656*/
+#line 21981 "tex.w"
+,math_comp,inner_noad);
+
+primitive(/*1658:*/
+#line 25870 "tex.w"
+533
+/*:1658*/
+#line 21983 "tex.w"
+,math_comp,under_noad);
+
+primitive(/*1657:*/
+#line 25867 "tex.w"
+532
+/*:1657*/
+#line 21985 "tex.w"
+,math_comp,over_noad);
+
+primitive(/*1735:*/
+#line 26101 "tex.w"
+610
+/*:1735*/
+#line 21987 "tex.w"
+,limit_switch,normal);
+
+primitive(/*1661:*/
+#line 25879 "tex.w"
+536
+/*:1661*/
+#line 21989 "tex.w"
+,limit_switch,limits);
+
+primitive(/*1662:*/
+#line 25882 "tex.w"
+537
+/*:1662*/
+#line 21991 "tex.w"
+,limit_switch,no_limits);
+
+
+/*:1156*//*1169:*/
+#line 22120 "tex.w"
+
+primitive(/*1645:*/
+#line 25831 "tex.w"
+520
+/*:1645*/
+#line 22121 "tex.w"
+,math_style,display_style);
+
+primitive(/*1646:*/
+#line 25834 "tex.w"
+521
+/*:1646*/
+#line 22123 "tex.w"
+,math_style,text_style);
+
+primitive(/*1647:*/
+#line 25837 "tex.w"
+522
+/*:1647*/
+#line 22125 "tex.w"
+,math_style,script_style);
+
+primitive(/*1648:*/
+#line 25840 "tex.w"
+523
+/*:1648*/
+#line 22127 "tex.w"
+,math_style,script_script_style);
+
+
+/*:1169*//*1178:*/
+#line 22219 "tex.w"
+
+primitive(/*1736:*/
+#line 26104 "tex.w"
+611
+/*:1736*/
+#line 22220 "tex.w"
+,above,above_code);
+
+primitive(/*1737:*/
+#line 26107 "tex.w"
+612
+/*:1737*/
+#line 22222 "tex.w"
+,above,over_code);
+
+primitive(/*1738:*/
+#line 26110 "tex.w"
+613
+/*:1738*/
+#line 22224 "tex.w"
+,above,atop_code);
+
+primitive(/*1739:*/
+#line 26113 "tex.w"
+614
+/*:1739*/
+#line 22226 "tex.w"
+,above,delimited_code+above_code);
+
+primitive(/*1740:*/
+#line 26116 "tex.w"
+615
+/*:1740*/
+#line 22228 "tex.w"
+,above,delimited_code+over_code);
+
+primitive(/*1741:*/
+#line 26119 "tex.w"
+616
+/*:1741*/
+#line 22230 "tex.w"
+,above,delimited_code+atop_code);
+
+
+/*:1178*//*1188:*/
+#line 22347 "tex.w"
+
+primitive(/*1659:*/
+#line 25873 "tex.w"
+534
+/*:1659*/
+#line 22348 "tex.w"
+,left_right,left_noad);
+
+primitive(/*1660:*/
+#line 25876 "tex.w"
+535
+/*:1660*/
+#line 22350 "tex.w"
+,left_right,right_noad);
+
+text(frozen_right)= /*1660:*/
+#line 25876 "tex.w"
+535
+/*:1660*/
+#line 22352 "tex.w"
+;eqtb[frozen_right]= eqtb[cur_val];
+
+/*:1188*//*1208:*/
+#line 22651 "tex.w"
+
+primitive(/*1743:*/
+#line 26125 "tex.w"
+618
+/*:1743*/
+#line 22652 "tex.w"
+,prefix,1);
+
+primitive(/*1744:*/
+#line 26128 "tex.w"
+619
+/*:1744*/
+#line 22654 "tex.w"
+,prefix,2);
+
+primitive(/*1745:*/
+#line 26131 "tex.w"
+620
+/*:1745*/
+#line 22656 "tex.w"
+,prefix,4);
+
+primitive(/*1746:*/
+#line 26134 "tex.w"
+621
+/*:1746*/
+#line 22658 "tex.w"
+,def,0);
+
+primitive(/*1747:*/
+#line 26137 "tex.w"
+622
+/*:1747*/
+#line 22660 "tex.w"
+,def,1);
+
+primitive(/*1748:*/
+#line 26140 "tex.w"
+623
+/*:1748*/
+#line 22662 "tex.w"
+,def,2);
+
+primitive(/*1749:*/
+#line 26143 "tex.w"
+624
+/*:1749*/
+#line 22664 "tex.w"
+,def,3);
+
+
+/*:1208*//*1219:*/
+#line 22821 "tex.w"
+
+primitive(/*1752:*/
+#line 26152 "tex.w"
+627
+/*:1752*/
+#line 22822 "tex.w"
+,let,normal);
+
+primitive(/*1753:*/
+#line 26155 "tex.w"
+628
+/*:1753*/
+#line 22824 "tex.w"
+,let,normal+1);
+
+
+/*:1219*//*1222:*/
+#line 22863 "tex.w"
+
+primitive(/*1754:*/
+#line 26158 "tex.w"
+629
+/*:1754*/
+#line 22864 "tex.w"
+,shorthand_def,char_def_code);
+
+primitive(/*1755:*/
+#line 26161 "tex.w"
+630
+/*:1755*/
+#line 22866 "tex.w"
+,shorthand_def,math_char_def_code);
+
+primitive(/*1756:*/
+#line 26164 "tex.w"
+631
+/*:1756*/
+#line 22868 "tex.w"
+,shorthand_def,count_def_code);
+
+primitive(/*1757:*/
+#line 26167 "tex.w"
+632
+/*:1757*/
+#line 22870 "tex.w"
+,shorthand_def,dimen_def_code);
+
+primitive(/*1758:*/
+#line 26170 "tex.w"
+633
+/*:1758*/
+#line 22872 "tex.w"
+,shorthand_def,skip_def_code);
+
+primitive(/*1759:*/
+#line 26173 "tex.w"
+634
+/*:1759*/
+#line 22874 "tex.w"
+,shorthand_def,mu_skip_def_code);
+
+primitive(/*1760:*/
+#line 26176 "tex.w"
+635
+/*:1760*/
+#line 22876 "tex.w"
+,shorthand_def,toks_def_code);
+
+
+/*:1222*//*1230:*/
+#line 23003 "tex.w"
+
+primitive(/*1441:*/
+#line 25219 "tex.w"
+316
+/*:1441*/
+#line 23004 "tex.w"
+,def_code,cat_code_base);
+
+primitive(/*1445:*/
+#line 25231 "tex.w"
+320
+/*:1445*/
+#line 23006 "tex.w"
+,def_code,math_code_base);
+
+primitive(/*1442:*/
+#line 25222 "tex.w"
+317
+/*:1442*/
+#line 23008 "tex.w"
+,def_code,lc_code_base);
+
+primitive(/*1443:*/
+#line 25225 "tex.w"
+318
+/*:1443*/
+#line 23010 "tex.w"
+,def_code,uc_code_base);
+
+primitive(/*1444:*/
+#line 25228 "tex.w"
+319
+/*:1444*/
+#line 23012 "tex.w"
+,def_code,sf_code_base);
+
+primitive(/*1502:*/
+#line 25402 "tex.w"
+377
+/*:1502*/
+#line 23014 "tex.w"
+,def_code,del_code_base);
+
+primitive(/*1438:*/
+#line 25210 "tex.w"
+313
+/*:1438*/
+#line 23016 "tex.w"
+,def_family,math_font_base);
+
+primitive(/*1439:*/
+#line 25213 "tex.w"
+314
+/*:1439*/
+#line 23018 "tex.w"
+,def_family,math_font_base+script_size);
+
+primitive(/*1440:*/
+#line 25216 "tex.w"
+315
+/*:1440*/
+#line 23020 "tex.w"
+,def_family,math_font_base+script_script_size);
+
+
+/*:1230*//*1250:*/
+#line 23288 "tex.w"
+
+primitive(/*1683:*/
+#line 25945 "tex.w"
+558
+/*:1683*/
+#line 23289 "tex.w"
+,hyph_data,0);
+
+primitive(/*1684:*/
+#line 25948 "tex.w"
+559
+/*:1684*/
+#line 23291 "tex.w"
+,hyph_data,1);
+
+
+/*:1250*//*1254:*/
+#line 23325 "tex.w"
+
+primitive(/*1762:*/
+#line 26182 "tex.w"
+637
+/*:1762*/
+#line 23326 "tex.w"
+,assign_font_int,0);
+
+primitive(/*1763:*/
+#line 26185 "tex.w"
+638
+/*:1763*/
+#line 23328 "tex.w"
+,assign_font_int,1);
+
+
+/*:1254*//*1262:*/
+#line 23424 "tex.w"
+
+primitive(/*1383:*/
+#line 25045 "tex.w"
+258
+/*:1383*/
+#line 23425 "tex.w"
+,set_interaction,batch_mode);
+
+primitive(/*1384:*/
+#line 25048 "tex.w"
+259
+/*:1384*/
+#line 23427 "tex.w"
+,set_interaction,nonstop_mode);
+
+primitive(/*1385:*/
+#line 25051 "tex.w"
+260
+/*:1385*/
+#line 23429 "tex.w"
+,set_interaction,scroll_mode);
+
+primitive(/*1767:*/
+#line 26197 "tex.w"
+642
+/*:1767*/
+#line 23431 "tex.w"
+,set_interaction,error_stop_mode);
+
+
+/*:1262*//*1272:*/
+#line 23490 "tex.w"
+
+primitive(/*1768:*/
+#line 26200 "tex.w"
+643
+/*:1768*/
+#line 23491 "tex.w"
+,in_stream,1);
+
+primitive(/*1769:*/
+#line 26203 "tex.w"
+644
+/*:1769*/
+#line 23493 "tex.w"
+,in_stream,0);
+
+
+/*:1272*//*1277:*/
+#line 23525 "tex.w"
+
+primitive(/*1770:*/
+#line 26206 "tex.w"
+645
+/*:1770*/
+#line 23526 "tex.w"
+,message,0);
+
+primitive(/*1771:*/
+#line 26209 "tex.w"
+646
+/*:1771*/
+#line 23528 "tex.w"
+,message,1);
+
+
+/*:1277*//*1286:*/
+#line 23592 "tex.w"
+
+primitive(/*1772:*/
+#line 26212 "tex.w"
+647
+/*:1772*/
+#line 23593 "tex.w"
+,case_shift,lc_code_base);
+
+primitive(/*1773:*/
+#line 26215 "tex.w"
+648
+/*:1773*/
+#line 23595 "tex.w"
+,case_shift,uc_code_base);
+
+
+/*:1286*//*1291:*/
+#line 23639 "tex.w"
+
+primitive(/*1774:*/
+#line 26218 "tex.w"
+649
+/*:1774*/
+#line 23640 "tex.w"
+,xray,show_code);
+
+primitive(/*1775:*/
+#line 26221 "tex.w"
+650
+/*:1775*/
+#line 23642 "tex.w"
+,xray,show_box_code);
+
+primitive(/*1776:*/
+#line 26224 "tex.w"
+651
+/*:1776*/
+#line 23644 "tex.w"
+,xray,show_the_code);
+
+primitive(/*1777:*/
+#line 26227 "tex.w"
+652
+/*:1777*/
+#line 23646 "tex.w"
+,xray,show_lists);
+
+
+/*:1291*//*1344:*/
+#line 24626 "tex.w"
+
+primitive(/*1783:*/
+#line 26245 "tex.w"
+658
+/*:1783*/
+#line 24627 "tex.w"
+,extension,open_node);
+
+primitive(/*1568:*/
+#line 25600 "tex.w"
+443
+/*:1568*/
+#line 24629 "tex.w"
+,extension,write_node);write_loc= cur_val;
+
+primitive(/*1784:*/
+#line 26248 "tex.w"
+659
+/*:1784*/
+#line 24631 "tex.w"
+,extension,close_node);
+
+primitive(/*1785:*/
+#line 26251 "tex.w"
+660
+/*:1785*/
+#line 24633 "tex.w"
+,extension,special_node);
+
+primitive(/*1786:*/
+#line 26254 "tex.w"
+661
+/*:1786*/
+#line 24635 "tex.w"
+,extension,immediate_code);
+
+primitive(/*1787:*/
+#line 26257 "tex.w"
+662
+/*:1787*/
+#line 24637 "tex.w"
+,extension,set_language_code);
+
+
+/*:1344*/
+#line 24438 "tex.w"
+;
+no_new_control_sequence= true;
+}
+#endif
+
+/*:1336*//*1338:*/
+#line 24491 "tex.w"
+
+#ifdef DEBUG
+void debug_help(void)
+{
+int k,l,m,n;
+loop{wake_up_terminal;
+print_nl("debug # (-1 to exit):");update_terminal;
+
+if(fscanf(term_in.f," %d",&m)<1||
+m<0)return;
+else if(m==0)
+{goto breakpoint;
+breakpoint:m= 0;
+}
+else{fscanf(term_in.f," %d",&n);
+switch(m){
+/*1339:*/
+#line 24515 "tex.w"
+
+case 1:print_word(mem[n]);break;
+case 2:print_int(info(n));break;
+case 3:print_int(link(n));break;
+case 4:print_word(eqtb[n]);break;
+case 5:print_word(font_info[n]);break;
+case 6:print_word(save_stack[n]);break;
+case 7:show_box(n);break;
+
+case 8:{breadth_max= 10000;depth_threshold= pool_size-pool_ptr-10;
+show_node_list(n);
+}break;
+case 9:show_token_list(n,null,1000);break;
+case 10:slow_print(n);break;
+case 11:check_mem(n> 0);break;
+case 12:search_mem(n);break;
+case 13:{fscanf(term_in.f," %d",&l);print_cmd_chr(n,l);
+}break;
+case 14:for(k= 0;k<=n;k++)print(buffer[k]);break;
+case 15:{font_in_short_display= null_font;short_display(n);
+}break;
+case 16:panicking= !panicking;break;
+
+/*:1339*/
+#line 24507 "tex.w"
+
+default:print_str("?");
+}
+}
+}
+}
+#endif
+
+/*:1338*/
+#line 24235 "tex.w"
+
+
+/*:1330*//*1332:*/
+#line 24289 "tex.w"
+int main(void){
+history= fatal_error_stop;
+t_open_out;
+if(ready_already==314159)goto start_of_TEX;
+/*14:*/
+#line 473 "tex.w"
+
+bad= 0;
+if((half_error_line<30)||(half_error_line> error_line-15))bad= 1;
+if(max_print_line<60)bad= 2;
+if(dvi_buf_size%8!=0)bad= 3;
+if(mem_bot+1100> mem_top)bad= 4;
+if(hash_prime> hash_size)bad= 5;
+if(max_in_open>=128)bad= 6;
+if(mem_top<256+11)bad= 7;
+
+/*:14*//*111:*/
+#line 2452 "tex.w"
+
+#ifdef INIT
+if((mem_min!=mem_bot)||(mem_max!=mem_top))bad= 10;
+#endif
+
+if((mem_min> mem_bot)||(mem_max<mem_top))bad= 10;
+if((min_quarterword> 0)||(max_quarterword<127))bad= 11;
+if((min_halfword> 0)||(max_halfword<32767))bad= 12;
+if((min_quarterword<min_halfword)||
+(max_quarterword> max_halfword))bad= 13;
+if((mem_min<min_halfword)||(mem_max>=max_halfword)||
+(mem_bot-mem_min> max_halfword+1))bad= 14;
+if((font_base<min_quarterword)||(font_max> max_quarterword))bad= 15;
+if(font_max> font_base+256)bad= 16;
+if((save_size> max_halfword)||(max_strings> max_halfword))bad= 17;
+if(buf_size> max_halfword)bad= 18;
+if(max_quarterword-min_quarterword<255)bad= 19;
+
+/*:111*//*290:*/
+#line 6246 "tex.w"
+
+if(cs_token_flag+undefined_control_sequence> max_halfword)bad= 21;
+
+/*:290*//*521:*/
+#line 10144 "tex.w"
+
+if(format_default_length> file_name_size)bad= 31;
+
+/*:521*//*1249:*/
+#line 23283 "tex.w"
+
+if(2*max_halfword<mem_top-mem_min)bad= 41;
+
+/*:1249*/
+#line 24293 "tex.w"
+
+if(bad> 0)
+{wterm_ln("Ouch---my internal constants have been clobbered!"
+"---case %d",bad);
+
+exit(0);
+}
+initialize();
+#ifdef INIT
+init_prim();
+init_str_ptr= str_ptr;init_pool_ptr= pool_ptr;fix_date_and_time();
+#endif
+ready_already= 314159;
+start_of_TEX:/*55:*/
+#line 1438 "tex.w"
+
+selector= term_only;tally= 0;term_offset= 0;file_offset= 0;
+
+/*:55*//*61:*/
+#line 1588 "tex.w"
+
+wterm("%s",banner);
+if(format_ident==0)wterm_ln(" (no format preloaded)");
+else{slow_print(format_ident);print_ln();
+}
+update_terminal;
+
+/*:61*//*527:*/
+#line 10278 "tex.w"
+
+job_name= 0;name_in_progress= false;log_opened= false;
+
+/*:527*//*533:*/
+#line 10347 "tex.w"
+output_file_name= 0;
+
+/*:533*/
+#line 24306 "tex.w"
+;
+/*1337:*/
+#line 24450 "tex.w"
+
+{/*331:*/
+#line 7153 "tex.w"
+
+{input_ptr= 0;max_in_stack= 0;
+in_open= 0;open_parens= 0;max_buf_stack= 0;
+param_ptr= 0;max_param_stack= 0;
+first= buf_size;do{buffer[first]= 0;decr(first);}while(!(first==0));
+scanner_status= normal;warning_index= null;first= 1;
+state= new_line;start= 1;index= 0;line= 0;name= 0;
+force_eof= false;
+align_state= 1000000;
+if(!init_terminal())exit(0);
+limit= last;first= last+1;
+}
+
+/*:331*/
+#line 24451 "tex.w"
+;
+if((format_ident==0)||(buffer[loc]=='&'))
+{if(format_ident!=0)initialize();
+if(!open_fmt_file())exit(0);
+if(!load_fmt_file())
+{w_close(&fmt_file);exit(0);
+}
+w_close(&fmt_file);
+while((loc<limit)&&(buffer[loc]==' '))incr(loc);
+}
+if(end_line_char_inactive)decr(limit);
+else buffer[limit]= end_line_char;
+fix_date_and_time();
+/*765:*/
+#line 15078 "tex.w"
+
+magic_offset= str_start[math_spacing]-9*ord_noad
+
+/*:765*/
+#line 24464 "tex.w"
+;
+/*75:*/
+#line 1788 "tex.w"
+
+if(interaction==batch_mode)selector= no_print;else selector= term_only
+
+/*:75*/
+#line 24465 "tex.w"
+;
+if((loc<limit)&&(cat_code(buffer[loc])!=escape))start_input();
+
+}
+
+/*:1337*/
+#line 24307 "tex.w"
+;
+history= spotless;
+main_control();
+final_cleanup();
+close_files_and_terminate();
+ready_already= 0;
+return 0;}
+
+/*:1332*/
diff --git a/web/web2w/ctex.idx b/web/web2w/ctex.idx
new file mode 100644
index 0000000000..ac556e8e61
--- /dev/null
+++ b/web/web2w/ctex.idx
@@ -0,0 +1,3851 @@
+\I\.{**}, 37, 534.
+\I\.{*\relax}, 174, 176, 178, 313, 360, 856, 1006, 1355.
+\I\.{->}, 294.
+\I\.{=>}, 363.
+\I\.{???}, 59.
+\I\.{?\relax}, 83.
+\I\.{\AT!}, 856.
+\I\.{\AT!\AT!}, 846.
+\I\.{\_\_SIZEOF\_FLOAT\_\_}, 9.
+\I\.{\_\_VA\_ARGS\_\_}, 56, 668.
+\I\|{a}, \[47], \[102], \[218], \[518], \[519], \[522], \[560], \[597], \[691], \[722], \[738], \[752], \[1123], \[1194], \[1211], \[1236], \[1257].
+\I\.{A <box> was supposed to...}, 1084.
+\I\\{a\_close}, \[28], 51, 329, 485, 486, 1275, 1333, 1374, 1378.
+\I\\{a\_leaders}, \[149], 189, 625, 627, 634, 636, 656, 671, 1071, 1072, 1073, 1078, 1148.
+\I\\{a\_make\_name\_string}, \[524], 534, 537.
+\I\\{a\_open\_in}, \[27], 51, 537, 1275.
+\I\\{a\_open\_out}, \[27], 534, 1374.
+\I\\{A\_token}, \[445].
+\I\\{abort}, \[560], 563, 564, 565, 568, 569, 570, 571, 573, 575.
+\I\\{above}, \[208], 1046, 1178, 1179, 1180.
+\I\9{above_}{\.{\\above} primitive}, \[1178].
+\I\\{above\_code}, \[1178], 1179, 1182, 1183.
+\I\\{above\_display\_short\_skip}, \[224], 814.
+\I\9{above_display_short_skip_}{\.{\\abovedisplayshortskip} primitive}, \[226].
+\I\\{above\_display\_short\_skip\_code}, \[224], 225, 226, 1203.
+\I\\{above\_display\_skip}, \[224], 814.
+\I\9{above_display_skip_}{\.{\\abovedisplayskip} primitive}, \[226].
+\I\\{above\_display\_skip\_code}, \[224], 225, 226, 1203, 1206.
+\I\9{above_with_delims_}{\.{\\abovewithdelims} primitive}, \[1178].
+\I\\{abs}, 66, 186, 211, 218, 219, 418, 422, 448, 501, 610, 663, 675, 718, 737, 757, 758, 759, 831, 836, 849, 859, 944, 948, 1029, 1030, 1056, 1076, 1078, 1080, 1083, 1093, 1110, 1120, 1127, 1149, 1243, 1244, 1377.
+\I\\{absorbing}, \[305], 306, 339, 473.
+\I\\{acc\_kern}, \[155], 191, 1125.
+\I\\{accent}, \[208], 265, 266, 1090, 1122, 1164, 1165.
+\I\9{accent_}{\.{\\accent} primitive}, \[265].
+\I\\{accent\_chr}, \[687], 696, 738, 1165.
+\I\\{accent\_noad}, \[687], 690, 696, 698, 733, 761, 1165, 1186.
+\I\\{accent\_noad\_size}, \[687], 698, 761, 1165.
+\I\\{act\_width}, \[866], 867, 868, 869, 871.
+\I{action procedure}, \[1029].
+\I\\{active}, \[162], 819, 829, 843, 854, 860, 861, 863, 864, 865, 873, 874, 875.
+\I\\{active\_base}, 220, \[222], 252, 253, 255, 262, 263, 353, 442, 506, 1152, 1257, 1289, 1315, 1317.
+\I\\{active\_char}, \[207], 344, 506.
+\I\\{active\_height}, \[970], 975, 976.
+\I\\{active\_node\_size}, \[819], 845, 860, 864, 865.
+\I\\{active\_width}, \[823], 824, 829, 843, 861, 864, 866, 868, 970.
+\I\\{active\_width0}, \[823].
+\I\\{actual\_looseness}, \[872], 873, 875.
+\I\\{add\_delims\_to}, \[347].
+\I\\{add\_glue\_ref}, \[203], 206, 430, 802, 881, 996, 1100, 1229.
+\I\\{add\_token\_ref}, \[203], 206, 323, 979, 1012, 1016, 1221, 1227, 1357.
+\I\\{additional}, \[644], 645, 657, 672.
+\I\\{adj\_demerits}, \[236], 836, 859.
+\I\9{adj_demerits_}{\.{\\adjdemerits} primitive}, \[238].
+\I\\{adj\_demerits\_code}, \[236], 237, 238.
+\I\\{adjust}, \[576].
+\I\\{adjust\_head}, \[162], 888, 889, 1076, 1085, 1199, 1205.
+\I\\{adjust\_node}, \[142], 148, 175, 183, 202, 206, 647, 651, 655, 730, 761, 866, 899, 1100.
+\I\\{adjust\_ptr}, \[142], 197, 202, 206, 655, 1100.
+\I\\{adjust\_space\_factor}, \[1034], 1038.
+\I\\{adjust\_tail}, \[647], 648, 649, 651, 655, 796, 888, 889, 1076, 1085, 1199.
+\I\\{adjusted\_hbox\_group}, \[269], 1062, 1083, 1085.
+\I\\{adv\_past}, \[1362], 1363.
+\I\\{advance}, \[209], 265, 266, 1210, 1235, 1236, 1238.
+\I\9{advance_}{\.{\\advance} primitive}, \[265].
+\I\\{advance\_major\_tail}, \[914], 917.
+\I\\{after}, \[147], 866, 1196.
+\I\\{after\_assignment}, \[208], 265, 266, 1268.
+\I\9{after_assignment_}{\.{\\afterassignment} primitive}, \[265].
+\I\\{after\_group}, \[208], 265, 266, 1271.
+\I\9{after_group_}{\.{\\aftergroup} primitive}, \[265].
+\I\\{after\_math}, 1193, \[1194].
+\I\\{after\_token}, \[1266], 1267, 1268, 1269.
+\I\\{aire}, \[560], 561, 563, 576.
+\I\\{align\_error}, 1126, \[1127].
+\I\\{align\_group}, \[269], 768, 774, 791, 800, 1131, 1132.
+\I\\{align\_head}, \[162], 770, 777.
+\I\\{align\_peek}, 773, \[774], \[785], 799, 1048, 1133.
+\I\\{align\_ptr}, \[770], 771, 772.
+\I\\{align\_stack\_node\_size}, \[770], 772.
+\I\\{align\_state}, 88, \[309], 324, 325, 331, 339, 342, 347, 357, 394, 395, 396, 403, 442, 475, 482, 483, 486, 770, 771, 772, 774, 777, 783, 784, 785, 788, 789, 791, 1069, 1094, 1126, 1127.
+\I\\{aligning}, \[305], 306, 339, 777, 789.
+\I{alignment of rules with characters}, 589.
+\I\\{alpha}, \[560], 571, 572.
+\I\&{alpha\_file}, \[25], 27, 28, 31, 32, 50, 54, 304, 480, 524, 1342.
+\I\\{alpha\_token}, \[438], 440.
+\I\\{alter\_aux}, 1242, \[1243].
+\I\\{alter\_box\_dimen}, 1242, \[1247].
+\I\\{alter\_integer}, 1242, \[1246].
+\I\\{alter\_page\_so\_far}, 1242, \[1245].
+\I\\{alter\_prev\_graf}, 1242, \[1244].
+\I\.{Ambiguous...}, 1183.
+\I{Amble, Ole}, 925.
+\I\.{AmSTeX}, 1331.
+\I\\{any\_mode}, \[1045], \[1048], \[1057], \[1063], \[1067], \[1073], \[1097], \[1102], \[1104], \[1126], \[1134], \[1210], \[1268], \[1271], \[1274], \[1276], \[1285], \[1290], \[1347].
+\I\\{any\_state\_plus}, \[344], \[345], \[347].
+\I\\{app\_lc\_hex}, \[48].
+\I\\{app\_space}, 1030, \[1043].
+\I\\{append\_char}, \[42], 48, 52, 58, 180, 195, 260, 516, 524, 692, 695, 939.
+\I\\{append\_charnode\_to\_t}, \[908], 911.
+\I\\{append\_choices}, 1171, \[1172].
+\I\\{append\_discretionary}, 1116, \[1117].
+\I\\{append\_glue}, 1057, \[1060], 1078.
+\I\\{append\_italic\_correction}, 1112, \[1113].
+\I\\{append\_kern}, 1057, \[1061].
+\I\\{append\_normal\_space}, \[1030].
+\I\\{append\_penalty}, 1102, \[1103].
+\I\\{append\_to\_name}, \[519], 522.
+\I\\{append\_to\_vlist}, \[679], 799, 888, 1076, 1203, 1204, 1205.
+\I\\{area\_delimiter}, \[513], 515, 516, 517.
+\I\.{Argument of \\x has...}, 395.
+\I\\{arith\_error}, \[104], 105, 106, 107, 448, 453, 460, 1236.
+\I\.{Arithmetic overflow}, 1236.
+\I\\{array}, \[304].
+\I\\{artificial\_demerits}, \[830], 851, 854, 855, 856.
+\I{ASCII code}, 17, 503.
+\I\&{ASCII\_code}, \[18], 19, 20, 29, 30, 31, 38, 42, 54, 58, 60, 82, 292, 341, 389, 516, 519, 520, 522, \[534], 692, 892, 912, 943, 953, 959, 960, 1376.
+\I\\{assign\_dimen}, \[209], 248, 249, 413, 1210, 1224, 1228.
+\I\\{assign\_font\_dimen}, \[209], 265, 266, 413, 1210, 1253.
+\I\\{assign\_font\_int}, \[209], 413, 1210, 1253, 1254, 1255.
+\I\\{assign\_glue}, \[209], 226, 227, 413, 782, 1210, 1224, 1228.
+\I\\{assign\_int}, \[209], 238, 239, 413, 1210, 1222, 1224, 1228, 1237.
+\I\\{assign\_mu\_glue}, \[209], 226, 227, 413, 1210, 1222, 1224, 1228, 1237.
+\I\\{assign\_toks}, \[209], 230, 231, 233, 323, 413, 415, 1210, 1224, 1226, 1227.
+\I\.{at}, 1258.
+\I\9{atop_}{\.{\\atop} primitive}, \[1178].
+\I\\{atop\_code}, \[1178], 1179, 1182.
+\I\9{atop_with_delims_}{\.{\\atopwithdelims} primitive}, \[1178].
+\I\\{attach\_fraction}, \[453], 454, 456.
+\I\\{attach\_sign}, \[448], 449, 455.
+\I\\{auto\_breaking}, \[862], 863, 866, 868.
+\I\\{aux}, 212, \[213], 216, 800, 812.
+\I\\{aux\_field}, \[212], 213, 218, 775.
+\I\\{aux\_save}, \[800], 812, 1206.
+\I\\{avail}, \[118], 120, 121, 122, 123, 164, 168, 1311, 1312.
+\I\.{AVAIL list clobbered...}, 168.
+\I\\{awful\_bad}, \[833], 834, 835, 836, 854, 874, 970, 974, 975, 987, 1005, 1006, 1007.
+\I\\{axis\_height}, \[700], 706, 736, 746, 747, 749, 762.
+\I\|{b}, \[464], \[465], \[470], \[498], \[522], \[560], \[597], \[679], \[705], \[706], \[709], \[711], \[715], \[830], \[970], \[994], \[1198], \[1247], \[1288].
+\I\\{b\_close}, \[28], 560, 642.
+\I\\{b\_make\_name\_string}, \[524], 531.
+\I\\{b\_open\_in}, \[27], 563.
+\I\\{b\_open\_out}, \[27], 531.
+\I\\{back\_error}, \[327], 373, 396, 403, 415, 442, 446, 476, 479, 503, 577, 783, 1078, 1084, 1161, 1197, 1207, 1212.
+\I\\{back\_input}, \[281], \[325], 326, 327, 368, 369, 372, 375, 379, 395, 405, 407, 415, 443, 444, 448, 452, 455, 461, 525, 788, 1031, 1047, 1054, 1064, 1090, 1095, 1124, 1127, 1132, 1138, 1150, 1152, 1153, 1215, 1221, 1226, 1269, 1375.
+\I\\{back\_list}, \[323], 325, 337, 407, 1288.
+\I\\{backed\_up}, \[307], 311, 312, 314, 323, 324, 325, 1026.
+\I\\{background}, \[823], 824, 827, 837, 863, 864.
+\I\\{background0}, \[823].
+\I\\{backup\_backup}, \[366].
+\I\\{backup\_head}, \[162], 366, 407.
+\I\.{BAD}, 293, 294.
+\I\\{bad}, \[13], 14, 111, 290, 521, 1249, 1332.
+\I\.{Bad \\patterns}, 961.
+\I\.{Bad \\prevgraf}, 1244.
+\I\.{Bad character code}, 434.
+\I\.{Bad delimiter code}, 437.
+\I\.{Bad flag...}, 170.
+\I\.{Bad link...}, 182.
+\I\.{Bad mathchar}, 436.
+\I\.{Bad number}, 435.
+\I\.{Bad register code}, 433.
+\I\.{Bad space factor}, 1243.
+\I\\{bad\_fmt}, \[1303], 1306, 1308, 1312, 1317, 1327.
+\I\\{bad\_pool}, \[51], 52, 53.
+\I\\{bad\_tfm}, \[560].
+\I\\{badness}, \[108], 660, 667, 674, 678, 828, 852, 853, 975, 1007.
+\I\9{badness_}{\.{\\badness} primitive}, \[416].
+\I\\{badness\_code}, \[416], 424.
+\I\\{banner}, \[2], 61, 536, 1299.
+\I\\{base\_line}, \[619], 623, 624, 628.
+\I\\{base\_ptr}, 84, 85, \[310], 311, 312, 313, 1131.
+\I\\{baseline\_skip}, \[224], 247, 679.
+\I\9{baseline_skip_}{\.{\\baselineskip} primitive}, \[226].
+\I\\{baseline\_skip\_code}, 149, \[224], 225, 226, 679.
+\I\\{batch\_mode}, \[73], 75, 86, 90, 92, 93, 535, 1262, 1263, 1327, 1328.
+\I\9{batch_mode_}{\.{\\batchmode} primitive}, \[1262].
+\I\\{bc}, 540, 541, 543, 545, \[560], 565, 566, 570, 576.
+\I\\{bch\_label}, \[560], 573, 576.
+\I\\{bchar}, \[560], 573, 576, \[901], 903, 905, \[906], 908, 911, 913, 916, 917, \[1032], 1034, 1037, 1038, 1040.
+\I\\{bchar\_label}, \[549], 552, 576, 909, 916, 1034, 1040, 1322, 1323.
+\I\\{bchar\_label0}, \[549].
+\I\\{before}, \[147], 192, 1196.
+\I\\{begin\_box}, 1073, \[1079], 1084.
+\I\\{begin\_diagnostic}, 76, \[245], 284, 299, 323, 400, 401, 502, 509, 581, 638, 641, 663, 675, 863, 987, 992, 1006, 1011, 1121, 1293, 1296.
+\I\\{begin\_file\_reading}, \[78], 87, \[328], 483, 537.
+\I\\{begin\_group}, \[208], 265, 266, 1063.
+\I\9{begin_group_}{\.{\\begingroup} primitive}, \[265].
+\I\\{begin\_insert\_or\_adjust}, 1097, \[1099].
+\I\\{begin\_name}, 512, \[515], 525, 526, 530.
+\I\\{begin\_pseudoprint}, \[316], 318, 319.
+\I\\{begin\_token\_list}, \[323], 359, 386, 390, 774, 788, 789, 799, 1025, 1030, 1083, 1091, 1139, 1145, 1167, 1371.
+\I\.{Beginning to dump...}, 1328.
+\I\\{below\_display\_short\_skip}, \[224].
+\I\9{below_display_short_skip_}{\.{\\belowdisplayshortskip} primitive}, \[226].
+\I\\{below\_display\_short\_skip\_code}, \[224], 225, 226, 1203.
+\I\\{below\_display\_skip}, \[224].
+\I\9{below_display_skip_}{\.{\\belowdisplayskip} primitive}, \[226].
+\I\\{below\_display\_skip\_code}, \[224], 225, 226, 1203, 1206.
+\I\\{best\_bet}, \[872], 874, 875, 877, 878.
+\I\\{best\_height\_plus\_depth}, \[971], 974, 1010, 1011.
+\I\\{best\_ins\_ptr}, \[981], 1005, 1009, 1018, 1020, 1021.
+\I\\{best\_line}, \[872], 874, 875, 877, 890.
+\I\\{best\_page\_break}, \[980], 1005, 1013, 1014.
+\I\\{best\_pl\_line}, \[833], 845, 855.
+\I\\{best\_pl\_line0}, \[833].
+\I\\{best\_place}, \[833], 845, 855, \[970], 974, 980.
+\I\\{best\_place0}, \[833].
+\I\\{best\_size}, \[980], 1005, 1017.
+\I\\{beta}, \[560], 571, 572.
+\I\\{big\_op\_spacing1}, \[701], 751.
+\I\\{big\_op\_spacing2}, \[701], 751.
+\I\\{big\_op\_spacing3}, \[701], 751.
+\I\\{big\_op\_spacing4}, \[701], 751.
+\I\\{big\_op\_spacing5}, \[701], 751.
+\I\\{big\_switch}, 209, 236, 994, 1029, \[1030], 1031, 1036, 1041.
+\I{BigEndian order}, \[540].
+\I\\{billion}, \[625].
+\I\\{bin\_noad}, \[682], 690, 696, 698, 728, 729, 761, 1156, 1157.
+\I\\{bin\_op\_penalty}, \[236], 761.
+\I\9{bin_op_penalty_}{\.{\\binoppenalty} primitive}, \[238].
+\I\\{bin\_op\_penalty\_code}, \[236], 237, 238.
+\I\\{blank\_line}, \[245].
+\I\\{bop}, 583, 585, \[586], 588, 590, 592, 638, 640.
+\I{Bosshard, Hans Rudolf}, 458.
+\I\\{bot}, \[546].
+\I\\{bot\_mark}, \[382], 383, 1012, 1016.
+\I\9{bot_mark_}{\.{\\botmark} primitive}, \[384].
+\I\\{bot\_mark\_code}, \[382], 384, 385.
+\I\\{bottom\_level}, \[269], 272, 281, 1064, 1068.
+\I\\{bottom\_line}, \[311].
+\I{bowels}, 592.
+\I\\{box}, \[230], 232, 420, 505, 977, 992, 993, 1009, 1015, 1017, 1018, 1021, 1023, 1028, 1079, 1110, 1247, 1296.
+\I\9{box_}{\.{\\box} primitive}, \[1071].
+\I\\{box\_base}, \[230], 232, 233, 255, 1077.
+\I\\{box\_code}, \[1071], 1072, 1079, 1107.
+\I\\{box\_context}, \[1075], 1076, 1077, 1078, \[1079], 1083, \[1084].
+\I\\{box\_end}, \[1075], 1079, 1084, 1086.
+\I\\{box\_error}, \[992], 993, 1015, 1028.
+\I\\{box\_flag}, \[1071], 1075, 1077, 1083, 1241.
+\I\\{box\_max\_depth}, \[247], 1086.
+\I\9{box_max_depth_}{\.{\\boxmaxdepth} primitive}, \[248].
+\I\\{box\_max\_depth\_code}, \[247], 248.
+\I\\{box\_node\_size}, \[135], 136, 202, 206, 649, 668, 715, 727, 751, 756, 977, 1021, 1100, 1110, 1201.
+\I\\{box\_ref}, \[210], 232, 275, 1077.
+\I\\{box\_there}, \[980], 987, 1000, 1001.
+\I\9{box255}{\.{\\box255 is not void}}, 1015.
+\I\.{bp}, 458.
+\I{brain}, 1029.
+\I\\{breadth\_max}, \[181], 182, \[198], 233, \[236], 1339.
+\I\\{break\_node}, \[819], 845, 855, 856, 864, 877, 878.
+\I\\{break\_penalty}, \[208], 265, 266, 1102.
+\I\\{break\_type}, \[829], 837, 845, 846, 859.
+\I\\{break\_width}, \[823], 824, 837, 838, 840, 841, 842, 843, 844, 879.
+\I\\{break\_width0}, \[823].
+\I\\{breakpoint}, \[1338].
+\I\\{broken\_ins}, \[981], 986, 1010, 1021.
+\I\\{broken\_penalty}, \[236], 890.
+\I\9{broken_penalty_}{\.{\\brokenpenalty} primitive}, \[238].
+\I\\{broken\_penalty\_code}, \[236], 237, 238.
+\I\\{broken\_ptr}, \[981], 1010, 1021.
+\I\\{buf\_size}, \[11], 30, 31, 35, 111, 328, 331, 374, 1334.
+\I\\{buffer}, \[30], 31, 36, 37, 45, 71, 83, 87, 88, 259, 260, 261, 264, 302, 303, 315, 318, 331, 341, 343, 352, 354, 355, 356, 360, 362, 363, 366, 374, 483, 484, 522, 523, 529, 530, 534, 538, 1337, 1339.
+\I\.{Buffer size exceeded}, 35.
+\I\\{build\_choices}, 1173, \[1174].
+\I\\{build\_discretionary}, 1118, \[1119].
+\I\\{build\_page}, \[800], 812, 988, \[994], 1026, 1054, 1060, 1076, 1091, 1094, 1100, 1103, 1145, 1200.
+\I\.{by}, 1236.
+\I\\{bypass\_eoln}, \[31].
+\I\&{byte\_file}, \[25], 27, 28, 524, 532, 539.
+\I\\{b0}, 110, \[113], 114, 133, 221, 268, 545, 546, 550, 554, 556, 564, 602, 683, 685, 921, 958, 1309, 1310.
+\I\\{b1}, 110, \[113], 114, 133, 221, 268, 545, 546, 554, 556, 564, 602, 683, 685, 921, 958, 1309, 1310.
+\I\\{b2}, 110, \[113], 114, 545, 546, 554, 556, 564, 602, 683, 685, 1309, 1310.
+\I\\{b3}, 110, \[113], 114, 545, 546, 556, 564, 602, 683, 685, 1309, 1310.
+\I\|{c}, \[47], \[63], \[82], \[144], \[264], \[274], \[292], \[341], \[470], \[516], \[519], \[522], \[560], \[581], \[582], \[592], \[645], \[692], \[694], \[706], \[709], \[711], \[712], \[738], \[749], \[893], \[912], \[953], \[959], \[960], \[994], %
+\[1012], \[1086], \[1110], \[1117], \[1136], \[1151], \[1155], \[1181], \[1243], \[1245], \[1246], \[1247], \[1275], \[1279], \[1288], \[1335].
+\I\\{c\_leaders}, \[149], 190, 627, 636, 1071, 1072.
+\I\9{c_leaders_}{\.{\\cleaders} primitive}, \[1071].
+\I\\{c\_loc}, \[912], 916.
+\I\\{call}, \[210], 223, 275, 296, 366, 380, 387, 395, 396, 507, 1218, 1221, 1225, 1226, 1227, 1295.
+\I\\{cancel\_boundary}, 1030, \[1032], 1033, 1034.
+\I\.{cannot \\read}, 484.
+\I\\{car\_ret}, \[207], 232, 342, 347, 777, 780, 781, 783, 784, 785, 788, 1126.
+\I\\{carriage\_return}, \[22], 49, 207, 232, 240, 363.
+\I\\{case\_shift}, \[208], 1285, 1286, 1287.
+\I\\{cat}, \[341], 354, 355, 356.
+\I\\{cat\_code}, \[230], 232, 236, 262, 341, 343, 354, 355, 356, 1337.
+\I\9{cat_code_}{\.{\\catcode} primitive}, \[1230].
+\I\\{cat\_code\_base}, \[230], 232, 233, 235, 1230, 1231, 1233.
+\I\\{cc}, \[341], 352, 355.
+\I\.{cc}, 458.
+\I\\{change\_if\_limit}, \[497], 498, 509.
+\I\9{char_}{\.{\\char} primitive}, \[265].
+\I\\{char\_base}, \[550], 552, 554, 566, 570, 576, 1322, 1323.
+\I\\{char\_base0}, \[550].
+\I\\{char\_box}, \[709], 710, 711, 738.
+\I\9{char_def_}{\.{\\chardef} primitive}, \[1222].
+\I\\{char\_def\_code}, \[1222], 1223, 1224.
+\I\\{char\_depth}, \[554], 654, 708, 709, 712.
+\I\\{char\_depth\_end}, \[554].
+\I\\{char\_exists}, \[554], 573, 576, 582, 708, 722, 738, 740, 749, 755, 1036.
+\I\\{char\_given}, \[208], 413, 935, 1030, 1038, 1090, 1124, 1151, 1154, 1222, 1223, 1224.
+\I\\{char\_height}, \[554], 654, 708, 709, 712, 1125.
+\I\\{char\_height\_end}, \[554].
+\I\\{char\_info}, 543, 550, \[554], 555, 557, 570, 573, 576, 582, 620, 654, 708, 709, 712, 714, 715, 722, 724, 738, 740, 749, 841, 842, 866, 867, 870, 871, 909, 1036, 1037, 1039, 1040, 1113, 1123, 1125, 1147.
+\I\\{char\_info\_end}, \[554].
+\I\\{char\_info\_word}, 541, \[543], 544.
+\I\\{char\_italic}, \[554], 709, 714, 749, 755, 1113.
+\I\\{char\_italic\_end}, \[554].
+\I\\{char\_kern}, \[557], 741, 753, 909, 1040.
+\I\\{char\_kern\_end}, \[557].
+\I\\{char\_node}, \[134], 143, 145, 162, 176, 548, 592, 620, 649, 752, 881, 907, 1029, 1113, 1138.
+\I\\{char\_num}, \[208], 265, 266, 935, 1030, 1038, 1090, 1124, 1151, 1154.
+\I\\{char\_tag}, \[554], 570, 708, 710, 740, 741, 749, 752, 909, 1039.
+\I\\{char\_warning}, \[581], 582, 722, 1036.
+\I\\{char\_width}, \[554], 620, 654, 709, 714, 715, 740, 841, 842, 866, 867, 870, 871, 1123, 1125, 1147.
+\I\\{char\_width\_end}, \[554].
+\I\\{character}, \[134], 143, 144, 174, 176, 206, 582, 620, 654, 681, 682, 683, 687, 691, 709, 715, 722, 724, 749, 752, 753, 841, 842, 866, 867, 870, 871, 896, 897, 898, 903, 907, 908, 910, 911, 1032, 1034, 1035, 1036, 1037, 1038, 1040, 1113, 1123, 1125,
+1147, 1151, 1155, 1165.
+\I{character set dependencies}, 23, 49.
+\I{check sum}, 53, 542, 588.
+\I\\{check\_byte\_range}, \[570], 573.
+\I\\{check\_dimensions}, \[727], 733, 754.
+\I\\{check\_existence}, \[573], 574.
+\I\\{check\_full\_save\_stack}, \[273], 274, 276, 280.
+\I\\{check\_interrupt}, \[96], 324, 343, 753, 911, 1031, 1040.
+\I\\{check\_mem}, 165, \[167], 1031, 1339.
+\I\\{check\_outer\_validity}, \[336], 351, 353, 354, 357, 362, 375.
+\I\\{check\_shrinkage}, \[825], 827, 868.
+\I{Chinese characters}, 134, 585.
+\I\\{choice\_node}, 688, \[689], 690, 698, 730.
+\I\\{choose\_mlist}, \[731].
+\I\\{chr}, \[9], 19, 20, 23, 24, 1222.
+\I\\{chr\_cmd}, \[298], 781.
+\I\\{chr\_code}, 227, 231, 239, 249, \[298], 377, 385, 411, 412, 413, 417, 469, 488, 492, 781, 984, 1053, 1059, 1071, 1072, 1089, 1108, 1115, 1143, 1157, 1170, 1179, 1189, 1209, 1220, 1223, 1231, 1251, 1255, 1261, 1263, 1273, 1278, 1287, 1289, 1292, 1346.
+\I\\{clang}, 212, \[213], 812, 1034, 1091, 1200, 1376, 1377.
+\I\\{clean\_box}, \[720], 734, 735, 737, 738, 742, 744, 749, 750, 757, 758, 759.
+\I\\{clear\_for\_error\_prompt}, \[78], 83, \[330], 346.
+\I\\{clear\_terminal}, \[34], 330, 529.
+\I\.{CLOBBERED}, 293.
+\I\\{clobbered}, \[167], 168, 169.
+\I\\{close}, 28, \[56].
+\I\\{close\_files\_and\_terminate}, \[78], 81, 1332, \[1333].
+\I\9{close_in_}{\.{\\closein} primitive}, \[1272].
+\I\\{close\_noad}, \[682], 690, 696, 698, 728, 761, 762, 1156, 1157.
+\I\\{close\_node}, \[1341], 1344, 1346, 1348, 1356, 1357, 1358, 1373, 1374, 1375.
+\I\9{close_out_}{\.{\\closeout} primitive}, \[1344].
+\I\\{closed}, \[480], 481, 483, 485, 486, 501, 1275.
+\I\\{clr}, \[737], \[743], 745, 746, \[756], 757, 758, 759.
+\I\\{club\_penalty}, \[236], 890.
+\I\9{club_penalty_}{\.{\\clubpenalty} primitive}, \[238].
+\I\\{club\_penalty\_code}, \[236], 237, 238.
+\I\.{cm}, 458.
+\I\\{cmd}, \[298], 1222, 1289.
+\I\\{co\_backup}, \[366].
+\I\\{combine\_two\_deltas}, \[860].
+\I\\{comment}, \[207], 232, 347.
+\I\\{common\_ending}, 15, \[498], 500, 509, \[649], 660, 666, 667, \[668], 674, 677, 678, \[903], \[1257], 1260, \[1293], 1294, 1297.
+\I\.{Completed box...}, 638.
+\I\\{compress\_trie}, \[949], 952.
+\I\\{cond\_math\_glue}, \[149], 189, 732, 1171.
+\I\\{cond\_ptr}, \[489], 490, 495, 496, 497, 498, 500, 509, 1335.
+\I\\{conditional}, \[366], 367, \[498].
+\I\\{confusion}, \[95], 202, 206, 281, 497, 630, 669, 728, 736, 754, 761, 766, 791, 798, 800, 841, 842, 866, 870, 871, 877, 968, 973, 1000, 1068, 1185, 1200, 1211, 1348, 1357, 1358, 1373.
+\I\\{continental\_point\_token}, \[438], 448.
+\I\\{contrib\_head}, \[162], 215, 218, 988, 994, 995, 998, 999, 1001, 1017, 1023, 1026.
+\I\\{contrib\_tail}, \[995], 1017, 1023, 1026.
+\I\\{contribute}, \[997], 1000, 1002, 1008, 1364.
+\I\\{conv\_toks}, \[366], 367, \[470].
+\I{conventions for representing stacks}, 300.
+\I\\{convert}, \[210], 366, 367, 468, 469, 470.
+\I\\{convert\_to\_break\_width}, \[843].
+\I\9{copy_}{\.{\\copy} primitive}, \[1071].
+\I\\{copy\_code}, \[1071], 1072, 1079, 1107, 1108, 1110.
+\I\\{copy\_node\_list}, 161, 203, \[204], 206, 1079, 1110.
+\I\\{copy\_to\_cur\_active}, \[829], 861.
+\I\\{count}, \[236], 427, 638, 640, 986, 1008, 1009, 1010.
+\I\9{count_}{\.{\\count} primitive}, \[411].
+\I\\{count\_base}, \[236], 239, 242, 1224, 1237.
+\I\9{count_def_}{\.{\\countdef} primitive}, \[1222].
+\I\\{count\_def\_code}, \[1222], 1223, 1224.
+\I\9{cr_}{\.{\\cr} primitive}, \[780].
+\I\\{cr\_code}, \[780], 781, 789, 791, 792.
+\I\9{cr_cr_}{\.{\\crcr} primitive}, \[780].
+\I\\{cr\_cr\_code}, \[780], 785, 789.
+\I\\{cramped}, \[688], 702.
+\I\\{cramped\_style}, \[702], 734, 737, 738.
+\I\\{cs\_count}, \[256], 258, 260, 1318, 1319, 1334.
+\I\\{cs\_error}, 1134, \[1135].
+\I\\{cs\_name}, \[210], 265, 266, 366, 367.
+\I\9{cs_name_}{\.{\\csname} primitive}, \[265].
+\I\\{cs\_token\_flag}, \[289], 290, 293, 334, 336, 337, 339, 357, 358, 365, 369, 372, 375, 379, 380, 381, 442, 466, 506, 780, 1065, 1132, 1215, 1289, 1314, 1371.
+\I\\{cur\_active\_width}, \[823], 824, 829, 832, 837, 843, 844, 851, 852, 853, 860.
+\I\\{cur\_active\_width0}, \[823].
+\I\\{cur\_align}, \[770], 771, 772, 777, 778, 779, 783, 786, 788, 789, 791, 792, 795, 796, 798.
+\I\\{cur\_area}, \[512], 517, 528, 529, 537, 1257, 1260, 1351, 1374.
+\I\\{cur\_boundary}, 270, \[271], 272, 274, 282.
+\I\\{cur\_box}, \[1074], 1075, 1076, 1077, 1078, \[1079], \[1080], 1081, 1082, 1084, 1086, 1087.
+\I\\{cur\_break}, \[821], 845, 879, 880, 881.
+\I\\{cur\_c}, 722, 723, \[724], 738, 749, 752, 753, 755.
+\I\\{cur\_chr}, 88, 296, \[297], 299, 332, 337, 341, 343, 348, 349, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 364, 365, 378, 380, 381, 386, 387, 389, 403, 407, 413, 424, 428, 442, 470, 472, 474, 476, 479, 483, 494, 495, 498, 500, 506, 507, 508,
+509, 510, 525, 577, 782, 785, 789, 935, 937, 962, 1030, 1034, 1036, 1038, 1049, 1058, 1060, 1061, 1066, 1073, 1079, 1083, 1090, 1093, 1105, 1106, 1110, 1117, 1124, 1128, 1140, 1142, 1151, 1152, 1154, 1155, 1158, 1159, 1160, 1171, 1181, 1191, 1211, 1212,
+1213, 1217, 1218, 1221, 1224, 1226, 1227, 1228, 1232, 1233, 1234, 1237, 1243, 1245, 1246, 1247, 1252, 1253, 1265, 1275, 1279, 1288, 1293, 1335, 1348, 1350, 1375.
+\I\\{cur\_cmd}, 88, 211, 296, \[297], 299, 332, 337, 341, 342, 343, 344, 348, 349, 351, 353, 354, 357, 358, 360, 364, 365, 366, 367, 368, 372, 380, 381, 386, 387, 403, 404, 406, 407, 413, 415, 428, 440, 442, 443, 444, 448, 452, 455, 461, 463, 474, 476,
+477, 478, 479, 483, 494, 506, 507, 525, 577, 777, 782, 783, 784, 785, 788, 789, 935, 961, 1029, 1030, 1038, 1049, 1066, 1078, 1079, 1084, 1095, 1099, 1124, 1128, 1138, 1151, 1152, 1160, 1165, 1176, 1177, 1197, 1206, 1211, 1212, 1213, 1221, 1226, 1227,
+1228, 1236, 1237, 1252, 1270, 1375.
+\I\\{cur\_cs}, \[297], 332, 333, 336, 337, 338, 341, 351, 353, 354, 356, 357, 358, 365, 372, 374, 379, 380, 381, 389, 391, 407, 472, 473, 507, 774, 1152, 1215, 1218, 1221, 1224, 1225, 1226, 1257, 1294, 1352, 1371.
+\I\\{cur\_ext}, \[512], 517, 528, 529, 537, 1275, 1351, 1374.
+\I\\{cur\_f}, 722, \[724], 738, 741, 749, 752, 753, 755.
+\I\\{cur\_fam}, \[236], 1151, 1155, 1165.
+\I\\{cur\_fam\_code}, \[236], 237, 238, 1139, 1145.
+\I\\{cur\_file}, \[304], 329, 362, 537, 538.
+\I\\{cur\_font}, \[230], 232, 558, 559, 577, 1032, 1034, 1042, 1044, 1117, 1123, 1124, 1146.
+\I\\{cur\_font\_loc}, \[230], 232, 233, 234, 1217.
+\I\\{cur\_g}, \[619], 625, \[629], 634.
+\I\\{cur\_glue}, \[619], 625, \[629], 634.
+\I\\{cur\_group}, 270, \[271], 272, 274, 281, 282, 800, 1062, 1063, 1064, 1065, 1067, 1068, 1069, 1130, 1131, 1140, 1142, 1191, 1192, 1193, 1194, 1200.
+\I\\{cur\_h}, \[616], 617, 618, 619, 620, 622, 623, 626, 627, 628, 629, 632, 637.
+\I\\{cur\_head}, \[770], 771, 772, 786, 799.
+\I\\{cur\_height}, \[970], 972, 973, 974, 975, 976.
+\I\\{cur\_i}, 722, 723, \[724], 738, 741, 749, 752, 753, 755.
+\I\\{cur\_if}, 336, \[489], 490, 495, 496, 1335.
+\I\\{cur\_indent}, \[877], 889.
+\I\\{cur\_input}, 35, 36, 87, \[301], 302, 311, 321, 322, 534, 1131.
+\I\\{cur\_l}, \[907], 908, 909, 910, 911, 1032, 1034, 1035, 1036, 1037, 1039, 1040.
+\I\\{cur\_lang}, 891, \[892], 923, 924, 930, 934, 939, 944, 963, 1091, 1200, 1362.
+\I\\{cur\_length}, \[41], 180, 182, 260, 516, 524, 617, 692, 1368.
+\I\\{cur\_level}, 270, \[271], 272, 274, 277, 278, 280, 281, 1304, 1335.
+\I\\{cur\_line}, \[877], 889, 890.
+\I\\{cur\_list}, \[213], 216, 217, 218, 422, 1244.
+\I\\{cur\_loop}, \[770], 771, 772, 777, 783, 792, 793, 794.
+\I\\{cur\_mark}, 296, \[382], 386, 1335.
+\I\\{cur\_mark0}, \[382].
+\I\\{cur\_mlist}, \[719], 720, 726, 754, 1194, 1196, 1199.
+\I\\{cur\_mu}, 703, \[719], 730, 732, 766.
+\I\\{cur\_name}, \[512], 517, 528, 529, 537, 1257, 1258, 1260, 1351, 1374.
+\I\\{cur\_order}, 366, 439, \[447], 448, 454, 462.
+\I\\{cur\_p}, 823, \[828], 829, 830, 833, 837, 839, 840, 845, 851, 853, 855, 856, 857, 858, 859, 860, 862, 863, 865, 866, 867, 868, 869, 872, 877, 878, 879, 880, 881, 894, 903, 1362.
+\I\\{cur\_q}, \[907], 908, 910, 911, 1034, 1035, 1036, 1037, 1040.
+\I\\{cur\_r}, \[907], 908, 909, 910, 911, 1032, 1034, 1037, 1038, 1039, 1040.
+\I\\{cur\_rh}, \[906], 908, 909, 910.
+\I\\{cur\_s}, 593, \[616], 619, 629, 640, 642.
+\I\\{cur\_size}, 700, 701, 703, \[719], 722, 723, 732, 736, 737, 744, 746, 747, 748, 749, 757, 758, 759, 762.
+\I\\{cur\_span}, \[770], 771, 772, 787, 796, 798.
+\I\\{cur\_style}, 703, \[719], 720, 726, 730, 731, 734, 735, 737, 738, 742, 744, 745, 746, 748, 749, 750, 754, 756, 757, 758, 759, 760, 763, 766, 1194, 1196, 1199.
+\I\\{cur\_tail}, \[770], 771, 772, 786, 796, 799.
+\I\\{cur\_tok}, 88, 281, \[297], 325, 326, 327, 336, 364, 365, 366, 368, 369, 372, 375, 379, 380, 381, 392, 393, 394, 395, 397, 399, 403, 405, 407, 440, 441, 442, 444, 445, 448, 452, 474, 476, 477, 479, 483, 494, 503, 506, 783, 784, 1038, 1047, 1095,
+1127, 1128, 1132, 1215, 1221, 1268, 1269, 1271, 1371, 1372.
+\I\\{cur\_v}, \[616], 618, 619, 623, 624, 628, 629, 631, 632, 633, 635, 636, 637, 640.
+\I\\{cur\_val}, 264, 265, 334, 366, \[410], 413, 414, 415, 419, 420, 421, 423, 424, 425, 426, 427, 429, 430, 431, 433, 434, 435, 436, 437, 438, 439, 440, 442, 444, 445, 447, 448, 450, 451, 453, 455, 457, 458, 460, 461, 462, 463, 465, 466, 472, 482, 491,
+501, 503, 504, 505, 509, 553, 577, 578, 579, 580, 645, 780, 782, 935, 1030, 1038, 1060, 1061, 1073, 1079, 1082, 1099, 1103, 1110, 1123, 1124, 1151, 1154, \[1160], \[1161], 1165, 1182, 1188, 1224, 1225, 1226, 1227, 1228, 1229, 1232, 1234, 1236, 1237,
+1238, 1239, 1240, 1241, 1243, 1244, 1245, 1246, 1247, 1248, 1253, 1258, 1259, 1275, 1296, 1344, 1350, 1377.
+\I\\{cur\_val\_level}, 366, \[410], 413, 419, 420, 421, 423, 424, 427, 429, 430, 439, 449, 451, 455, 461, 465, 466.
+\I\\{cur\_width}, \[877], 889.
+\I{current page}, 980.
+\I\\{current\_character\_being\_worked\_on}, \[570].
+\I\\{cv\_backup}, \[366].
+\I\\{cvl\_backup}, \[366].
+\I\|{d}, \[25], \[107], \[113], \[176], \[177], \[259], \[341], \[440], \[560], \[649], \[668], \[679], \[706], \[830], \[944], \[970], \[1068], \[1086], \[1138], \[1198].
+\I\\{d\_fixed}, \[608], 609.
+\I\\{danger}, \[1194], \[1195], 1199.
+\I\\{data}, \[210], 232, 1217, 1232, 1234.
+\I{data structure assumptions}, \[161], 164, 204, 816, 968, 981, 1289.
+\I\\{day}, \[236], 241, 536, 617, 1328.
+\I\9{day_}{\.{\\day} primitive}, \[238].
+\I\\{day\_code}, \[236], 237, 238.
+\I\.{dd}, 458.
+\I\\{deactivate}, \[851], 854.
+\I\\{dead\_cycles}, 419, \[592], 593, 638, 1012, 1024, 1025, 1054, 1242, 1246.
+\I\9{dead_cycles_}{\.{\\deadcycles} primitive}, \[416].
+\I\.{DEBUG}, \[78], \[84], \[114], \[117], \[165], \[166], \[167], \[172], \[1031], \[1338].
+\I\\{debug}, 7.
+\I\.{debug \#}, 1338.
+\I\\{debug\_help}, \[78], 84, 93, \[1338].
+\I{debugging}, 7, 84, 96, 114, 165, 182, 1031, 1338.
+\I\\{decent\_fit}, \[817], 834, 852, 853, 864.
+\I\\{decr}, \[16], 42, 44, 64, 71, 86, 88, 89, 90, 92, 102, 117, 120, 175, 177, 200, 201, 205, 217, 245, 260, 281, 282, 311, 322, 324, 325, 329, 331, 347, 356, 357, 360, 362, 394, 399, 422, 429, 442, 477, 483, 494, 509, 534, 538, 568, 576, 601, 619, 629,
+638, 642, 643, 716, 717, 803, 808, 840, 858, 869, 883, 915, 916, 930, 931, 940, 944, 948, 965, 1060, 1100, 1120, 1127, 1131, 1174, 1186, 1194, 1244, 1293, 1311, 1335, 1337.
+\I\\{decr\_dyn\_used}, \[117], 121, 123.
+\I\\{def}, \[209], 1208, 1209, 1210, 1213, 1218.
+\I\9{def_}{\.{\\def} primitive}, \[1208].
+\I\\{def\_code}, \[209], 413, 1210, 1230, 1231, 1232.
+\I\\{def\_family}, \[209], 413, 577, 1210, 1230, 1231, 1234.
+\I\\{def\_font}, \[209], 265, 266, 413, 577, 1210, 1256.
+\I\\{def\_ref}, \[305], 306, 473, 482, 960, 1101, 1218, 1226, 1279, 1288, 1352, 1354, 1370.
+\I\\{default\_code}, \[683], 697, 743, 1182.
+\I\\{default\_hyphen\_char}, \[236], 576.
+\I\9{default_hyphen_char_}{\.{\\defaulthyphenchar} primitive}, \[238].
+\I\\{default\_hyphen\_char\_code}, \[236], 237, 238.
+\I\\{default\_rule}, \[463].
+\I\\{default\_rule\_thickness}, 683, \[701], 734, 735, 737, 743, 745, 759.
+\I\\{default\_skew\_char}, \[236], 576.
+\I\9{default_skew_char_}{\.{\\defaultskewchar} primitive}, \[238].
+\I\\{default\_skew\_char\_code}, \[236], 237, 238.
+\I{defecation}, 597.
+\I\&{define}, \[1214].
+\I\\{defining}, \[305], 306, 339, 473, 482.
+\I\\{del\_code}, \[236], 240, 1160.
+\I\9{del_code_}{\.{\\delcode} primitive}, \[1230].
+\I\\{del\_code\_base}, \[236], 240, 242, 1230, 1232, 1233.
+\I\\{delete\_glue\_ref}, \[201], 202, 275, 451, 465, 578, 732, 802, 816, 826, 881, 976, 996, 1004, 1017, 1022, 1100, 1229, 1236, 1239, 1335.
+\I\\{delete\_last}, 1104, \[1105].
+\I\\{delete\_q}, \[760], 763.
+\I\\{delete\_token\_ref}, \[200], 202, 275, 324, 977, 979, 1012, 1016, 1335, 1358.
+\I\\{deletions\_allowed}, \[76], 77, 84, 85, 98, 336, 346.
+\I\\{delim\_num}, \[207], 265, 266, 1046, 1151, 1154, 1160.
+\I\\{delimited\_code}, \[1178], 1179, 1182, 1183.
+\I\\{delimiter}, \[687], 696, 762, 1191.
+\I\9{delimiter_}{\.{\\delimiter} primitive}, \[265].
+\I\\{delimiter\_factor}, \[236], 762.
+\I\9{delimiter_factor_}{\.{\\delimiterfactor} primitive}, \[238].
+\I\\{delimiter\_factor\_code}, \[236], 237, 238.
+\I\\{delimiter\_shortfall}, \[247], 762.
+\I\9{delimiter_shortfall_}{\.{\\delimitershortfall} primitive}, \[248].
+\I\\{delimiter\_shortfall\_code}, \[247], 248.
+\I\\{delim1}, \[700], 748.
+\I\\{delim2}, \[700], 748.
+\I\\{delta}, \[103], \[726], 728, 733, \[735], \[736], \[737], \[738], 742, \[743], 745, 746, 747, 748, \[749], 750, 754, 755, \[756], 759, \[762], \[994], 1008, 1010, \[1123], 1125.
+\I\\{delta\_node}, \[822], 830, 832, 843, 844, 860, 861, 865, 874, 875.
+\I\\{delta\_node\_size}, \[822], 843, 844, 860, 861, 865.
+\I\\{delta1}, \[743], 746, \[762].
+\I\\{delta2}, \[743], 746, \[762].
+\I\\{den}, 585, \[587], 590.
+\I\\{denom}, \[450], 458.
+\I\\{denom\_style}, \[702], 744.
+\I\\{denominator}, \[683], 690, 697, 698, 744, 1181, 1185.
+\I\\{denom1}, \[700], 744.
+\I\\{denom2}, \[700], 744.
+\I\\{deplorable}, \[974], 1005.
+\I\.{depth}, 463.
+\I\\{depth}, \[135], 136, 138, 139, 140, 184, 187, 188, 463, 554, 622, 624, 626, 631, 632, 635, 641, 649, 653, 656, 668, 670, 679, 688, 704, 706, 709, 713, 727, 730, 731, 735, 736, 737, 745, 746, 747, 749, 750, 751, 756, 758, 759, 768, 769, 801, 806,
+810, 973, 1002, 1009, 1010, 1021, 1087, 1100.
+\I\\{depth\_base}, \[550], 552, 554, 566, 571, 1322, 1323.
+\I\\{depth\_base0}, \[550].
+\I\\{depth\_index}, \[543], 554.
+\I\\{depth\_offset}, \[135], 416, 769, 1247.
+\I\\{depth\_threshold}, \[181], 182, \[198], 233, \[236], 692, 1339.
+\I\\{dig}, \[54], 64, 65, 67, 102, 452.
+\I\\{digit\_sensed}, \[960], 961, 962.
+\I\\{dimen}, \[247], 427, 1008, 1010.
+\I\9{dimen_}{\.{\\dimen} primitive}, \[411].
+\I\\{dimen\_base}, 220, \[236], 247, 248, 249, 250, 251, 252, 1070, 1145.
+\I\9{dimen_def_}{\.{\\dimendef} primitive}, \[1222].
+\I\\{dimen\_def\_code}, \[1222], 1223, 1224.
+\I\\{dimen\_par}, \[247].
+\I\\{dimen\_pars}, \[247].
+\I\\{dimen\_val}, \[410], 411, 412, 413, 415, 416, 417, 418, 420, 421, 424, 425, 427, 428, 429, 449, 455, 465, 1237.
+\I\.{Dimension too large}, 460.
+\I{dirty \PASCAL}, \[3], 114, 172, 182, 186, 285, 812, 1331.
+\I\\{disc\_break}, \[877], 880, \[881], \[882], 890.
+\I\\{disc\_group}, \[269], 1117, 1118, 1119.
+\I\\{disc\_node}, \[145], 148, 175, 183, 202, 206, 730, 761, 817, 819, 829, 856, 858, 866, 881, 914, 1081, 1105.
+\I\\{disc\_width}, \[839], 840, 869, 870.
+\I\\{discretionary}, \[208], 1090, 1114, 1115, 1116.
+\I\.{Discretionary list is too long}, 1120.
+\I\9{discretionary_}{\.{\\discretionary} primitive}, \[1114].
+\I\.{Display math...with \$\$}, 1197.
+\I\\{display\_indent}, \[247], 800, 1138, 1145, 1199.
+\I\9{display_indent_}{\.{\\displayindent} primitive}, \[248].
+\I\\{display\_indent\_code}, \[247], 248, 1145.
+\I\9{display_limits_}{\.{\\displaylimits} primitive}, \[1156].
+\I\\{display\_mlist}, \[689], 695, 698, 731, 1174.
+\I\\{display\_style}, \[688], 694, 731, 1169, 1199.
+\I\9{display_style_}{\.{\\displaystyle} primitive}, \[1169].
+\I\\{display\_widow\_penalty}, \[236], 1145.
+\I\9{display_widow_penalty_}{\.{\\displaywidowpenalty} primitive}, \[238].
+\I\\{display\_widow\_penalty\_code}, \[236], 237, 238.
+\I\\{display\_width}, \[247], 1138, 1145, 1199.
+\I\9{display_width_}{\.{\\displaywidth} primitive}, \[248].
+\I\\{display\_width\_code}, \[247], 248, 1145.
+\I\\{divide}, \[209], 265, 266, 1210, 1235, 1236.
+\I\9{divide_}{\.{\\divide} primitive}, \[265].
+\I\\{do\_all\_six}, \[823], 829, 832, 837, 843, 844, 860, 861, 864, 970, 987.
+\I\\{do\_assignments}, \[800], 1123, 1206, \[1270].
+\I\\{do\_endv}, 1130, \[1131].
+\I\\{do\_extension}, 1347, \[1348], 1375.
+\I\\{do\_nothing}, \[16], 34, 57, 58, 78, 84, 175, 202, 275, 344, 357, 538, 569, 609, 611, 612, 622, 631, 651, 669, 692, 728, 733, 761, 837, 866, 899, 1045, 1236, 1359, 1360, 1373.
+\I\\{do\_register\_command}, 1235, \[1236].
+\I\\{doing\_leaders}, \[592], 593, 628, 637, 1374.
+\I\\{done}, 15, \[53], \[202], \[282], \[311], \[380], \[397], \[445], \[453], 458, \[474], 476, \[483], \[494], \[525], \[530], \[537], \[560], 567, 576, \[615], \[640], 641, 698, \[740], \[760], 761, \[777], \[837], \[863], 873, \[881], \[909], 911, %
+\[931], \[961], \[970], 974, \[979], \[997], 998, 1005, \[1081], \[1121], \[1146], \[1211], 1227, 1252, 1358.
+\I\\{done\_with\_noad}, \[727], 728, 733, 754.
+\I\\{done\_with\_node}, \[727], 730, 731, 754.
+\I\\{done1}, \[168], \[399], \[452], \[474], \[741], \[783], \[852], \[879], \[894], 896, 899, \[965], \[997], 1000, \[1315].
+\I\\{done2}, \[169], \[458], 459, \[478], \[784], \[896], \[1316].
+\I\\{done3}, \[897], 898.
+\I\\{done4}, \[899].
+\I\\{done5}, \[866], 869.
+\I\\{done6}, \[15].
+\I\\{dont\_expand}, \[210], 258, 357, 369.
+\I$\dotdot$, 23, 38, 49, 64, 79, 87, 110, 220, 236, 259, 304, 315, 355, 464, 522, 523, 541, 594, 597, 764, 819, 822, 852, 892, 912, 919, 920, 963, 1237, 1341.
+\I\.{Double subscript}, 1177.
+\I\.{Double superscript}, 1177.
+\I\\{double\_hyphen\_demerits}, \[236], 859.
+\I\9{double_hyphen_demerits_}{\.{\\doublehyphendemerits} primitive}, \[238].
+\I\\{double\_hyphen\_demerits\_code}, \[236], 237, 238.
+\I\.{Doubly free location...}, 169.
+\I\\{down\_ptr}, \[605], 606, 607, 615.
+\I\\{downdate\_width}, \[860].
+\I\\{down1}, 585, \[586], 607, 609, 610, 613, 614, 616.
+\I\\{down2}, \[585], 594, 610.
+\I\\{down3}, \[585], 610.
+\I\\{down4}, \[585], 610.
+\I\9{dp_}{\.{\\dp} primitive}, \[416].
+\I{dry rot}, 95.
+\I\9{dump_}{\.{\\dump...only by INITEX}}, 1335.
+\I\9{dump_}{\.{\\dump} primitive}, \[1052].
+\I\\{dump\_four\_ASCII}, \[1309].
+\I\\{dump\_hh}, \[1305], 1318, 1324.
+\I\\{dump\_int}, \[1305], 1307, 1309, 1311, 1313, 1315, 1316, 1318, 1320, 1322, 1324, 1326.
+\I\\{dump\_qqqq}, \[1305], 1309, 1322.
+\I\\{dump\_wd}, \[1305], 1311, 1315, 1316, 1320.
+\I\.{Duplicate pattern}, 963.
+\I\\{dvi\_buf}, 594, \[595], 597, 598, 607, 613, 614.
+\I\\{dvi\_buf\_size}, \[11], 14, 594, 595, 596, 598, 599, 607, 613, 614, 642.
+\I\\{dvi\_f}, \[616], 617, 620, 621.
+\I\\{dvi\_file}, 531, \[532], 592, 595, 597, 642.
+\I\9{DVI_files}{\.{DVI} files}, 583.
+\I\\{dvi\_font\_def}, \[602], 621, 643.
+\I\\{dvi\_four}, \[600], 602, 610, 617, 624, 633, 640, 642, 1368.
+\I\\{dvi\_gone}, 594, \[595], 596, 598, 612.
+\I\\{dvi\_h}, \[616], 617, 619, 620, 623, 624, 628, 629, 632, 637.
+\I\&{dvi\_index}, \[594], 595, 597.
+\I\\{dvi\_limit}, 594, \[595], 596, 598, 599.
+\I\\{dvi\_offset}, 594, \[595], 596, 598, 601, 605, 607, 613, 614, 619, 629, 640, 642.
+\I\\{dvi\_out}, \[598], 600, 601, 602, 603, 609, 610, 617, 619, 620, 621, 624, 629, 633, 640, 642, 1368.
+\I\\{dvi\_pop}, \[601], 619, 629.
+\I\\{dvi\_ptr}, 594, \[595], 596, 598, 599, 601, 607, 619, 629, 640, 642.
+\I\\{dvi\_swap}, \[598].
+\I\\{dvi\_v}, \[616], 617, 619, 623, 628, 629, 632, 637.
+\I\\{dyn\_used}, \[117], 164, 639, 1311, 1312.
+\I\|{e}, \[277], \[279], \[518], \[519], \[529], \[1198], \[1199], \[1201], \[1211].
+\I\\{easy\_line}, 819, 835, \[847], 848, 850.
+\I\\{ec}, 540, 541, 543, 545, \[560], 565, 566, 570, 576.
+\I\9{edef_}{\.{\\edef} primitive}, \[1208].
+\I\\{edge}, \[619], 623, 626, \[629], 635.
+\I\&{eight\_bits}, \[25], 64, 112, 297, 549, 560, 581, 582, 595, 607, 649, 706, 709, 712, 977, 992, 993, 1079, 1247, 1288.
+\I\\{eject\_penalty}, \[157], 829, 831, 851, 859, 873, 970, 972, 974, 1005, 1010, 1011.
+\I\9{else_}{\.{\\else} primitive}, \[491].
+\I\\{else\_code}, \[489], 491, 498.
+\I\.{em}, 455.
+\I\.{Emergency stop}, 93.
+\I\\{emergency\_stretch}, \[247], 828, 863.
+\I\9{emergency_stretch_}{\.{\\emergencystretch} primitive}, \[248].
+\I\\{emergency\_stretch\_code}, \[247], 248.
+\I\\{empty}, \[16], 421, 681, 685, 687, 692, 722, 723, 738, 749, 751, 752, 754, 755, 756, 980, 986, 987, 991, 1001, 1008, 1176, 1177, 1186.
+\I{empty line at end of file}, 486, 538.
+\I\\{empty\_field}, \[684], 685, 686, 742, 1163, 1165, 1181.
+\I\\{empty\_flag}, \[124], 126, 130, 150, 164, 1312.
+\I\\{empty\_string}, 190, 512, 517, 528, 529, 537, 552, 561, 563, 1275, 1322, 1374, \[1395].
+\I\\{end}, 15, \[389], 396, 398, \[649], 657, 658, 664, \[668], 672, 673, 676, \[829], 831, 835.
+\I\.{End of file on the terminal}, 37, 71.
+\I\9{end_}{\.{(\\end occurred...)}}, 1335.
+\I\9{end_}{\.{\\end} primitive}, \[1052].
+\I\\{end\_cs\_name}, \[208], 265, 266, 372, 1134.
+\I\9{end_cs_name_}{\.{\\endcsname} primitive}, \[265].
+\I\\{end\_diagnostic}, \[245], 284, 299, 323, 400, 401, 502, 509, 581, 638, 641, 663, 675, 863, 987, 992, 1006, 1011, 1121, 1298.
+\I\\{end\_file\_reading}, \[329], 330, 360, 362, 483, 537, 1335.
+\I\\{end\_graf}, 1026, 1085, 1094, \[1096], 1100, 1131, 1133, 1168.
+\I\\{end\_group}, \[208], 265, 266, 1063.
+\I\9{end_group_}{\.{\\endgroup} primitive}, \[265].
+\I\9{end_input_}{\.{\\endinput} primitive}, \[376].
+\I\\{end\_line\_char}, 87, \[236], 240, 303, 318, 332, 360, 362, 483, 534, 538, 1337.
+\I\9{end_line_char_}{\.{\\endlinechar} primitive}, \[238].
+\I\\{end\_line\_char\_code}, \[236], 237, 238.
+\I\\{end\_line\_char\_inactive}, \[360], 362, 483, 538, 1337.
+\I\\{end\_match}, \[207], 289, 291, 294, 391, 392, 394.
+\I\\{end\_match\_token}, \[289], 389, 391, 392, 393, 394, 474, 476, 482.
+\I\\{end\_name}, 512, \[517], 525, 530.
+\I\\{end\_of\_TEX}, 81.
+\I\\{end\_span}, \[162], 768, 779, 793, 797, 801, 803.
+\I\\{end\_template}, \[210], 366, 375, 380, 780, 1295.
+\I\\{end\_template\_token}, \[780], 784, 790.
+\I\\{end\_token\_list}, \[324], 325, 357, 390, 1026, 1335, 1371.
+\I\\{end\_write}, \[222], 1369, 1371.
+\I\9{end_write_}{\.{\\endwrite}}, 1369.
+\I\\{end\_write\_token}, \[1371], 1372.
+\I\\{endv}, \[207], 298, 375, 380, 768, 780, 782, 791, 1046, 1130, 1131.
+\I\\{ensure\_vbox}, \[993], 1009, 1018.
+\I\\{eof}, 26, 31, 52, \[56], 564, 575, 1327.
+\I\\{eoln}, 31, 52, \[56].
+\I\\{eop}, 583, 585, \[586], 588, 640, 642.
+\I\\{eq\_define}, \[277], 278, 279, 372, 782, 1070, 1077, 1214.
+\I\\{eq\_destroy}, \[275], 277, 279, 283.
+\I\\{eq\_level}, \[221], 222, 228, 232, 236, 253, 264, 277, 279, 283, 780, 977, 1315, 1369.
+\I\\{eq\_level\_field}, \[221].
+\I\\{eq\_no}, \[208], 1140, 1141, 1143, 1144.
+\I\9{eq_no_}{\.{\\eqno} primitive}, \[1141].
+\I\\{eq\_save}, \[276], 277, 278.
+\I\\{eq\_type}, 210, \[221], 222, 223, 228, 232, 253, 258, 264, 265, 267, 277, 279, 351, 353, 354, 357, 358, 372, 389, 391, 780, 1152, 1315, 1369.
+\I\\{eq\_type\_field}, \[221], 275.
+\I\\{eq\_word\_define}, \[278], 279, 1070, 1139, 1145, 1214.
+\I\\{eqtb}, 115, 163, 220, 221, 222, 223, 224, 228, 230, 232, 236, 240, 242, 247, 250, 251, 252, \[253], 255, 262, 264, 265, 266, 267, 268, 270, 272, 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 285, 286, 289, 291, 297, 298, 305, 307, 332, 333, 354,
+389, 413, 414, 473, 491, 548, 553, 780, 814, 1188, 1208, 1222, 1238, 1240, 1253, 1257, 1315, 1316, 1317, 1339, 1345.
+\I\\{eqtb\_size}, 220, \[247], 250, 252, 253, 254, 1307, 1308, 1316, 1317.
+\I\\{eqtb0}, \[253].
+\I\\{equiv}, \[221], 222, 223, 224, 228, 229, 230, 232, 233, 234, 235, 253, 255, 264, 265, 267, 275, 277, 279, 351, 353, 354, 357, 358, 413, 414, 415, 508, 577, 780, 1152, 1227, 1239, 1240, 1257, 1289, 1315, 1369.
+\I\\{equiv\_field}, \[221], 275, 285.
+\I\\{err\_help}, 79, \[230], 1283, 1284.
+\I\9{err_help_}{\.{\\errhelp} primitive}, \[230].
+\I\\{err\_help\_loc}, \[230].
+\I\9{err_message_}{\.{\\errmessage} primitive}, \[1277].
+\I\\{error\_context\_lines}, \[236], 311.
+\I\9{error_context_lines_}{\.{\\errorcontextlines} primitive}, \[238].
+\I\\{error\_context\_lines\_code}, \[236], 237, 238.
+\I\\{error\_count}, \[76], 77, 82, 86, 1096, 1293.
+\I\\{error\_line}, \[11], 14, 54, 58, 306, 311, 315, 316, 317.
+\I\\{error\_message\_issued}, \[76], 82, 95.
+\I\\{error\_stop\_mode}, 72, \[73], 74, 82, 93, 98, 1262, 1283, 1293, 1294, 1297, 1327, 1335.
+\I\9{error_stop_mode_}{\.{\\errorstopmode} primitive}, \[1262].
+\I\\{erstat}, \[27], \[56].
+\I\\{escape}, \[207], 232, 344, 1337.
+\I\\{escape\_char}, \[236], 240, 243.
+\I\9{escape_char_}{\.{\\escapechar} primitive}, \[238].
+\I\\{escape\_char\_code}, \[236], 237, 238.
+\I\.{etc}, 182.
+\I\.{ETC}, 292.
+\I\\{every\_cr}, \[230], 774, 799.
+\I\9{every_cr_}{\.{\\everycr} primitive}, \[230].
+\I\\{every\_cr\_loc}, \[230], 231.
+\I\\{every\_cr\_text}, \[307], 314, 774, 799.
+\I\\{every\_display}, \[230], 1145.
+\I\9{every_display_}{\.{\\everydisplay} primitive}, \[230].
+\I\\{every\_display\_loc}, \[230], 231.
+\I\\{every\_display\_text}, \[307], 314, 1145.
+\I\\{every\_hbox}, \[230], 1083.
+\I\9{every_hbox_}{\.{\\everyhbox} primitive}, \[230].
+\I\\{every\_hbox\_loc}, \[230], 231.
+\I\\{every\_hbox\_text}, \[307], 314, 1083.
+\I\\{every\_job}, \[230], 1030.
+\I\9{every_job_}{\.{\\everyjob} primitive}, \[230].
+\I\\{every\_job\_loc}, \[230], 231.
+\I\\{every\_job\_text}, \[307], 314, 1030.
+\I\\{every\_math}, \[230], 1139.
+\I\9{every_math_}{\.{\\everymath} primitive}, \[230].
+\I\\{every\_math\_loc}, \[230], 231.
+\I\\{every\_math\_text}, \[307], 314, 1139.
+\I\\{every\_par}, \[230], 1091.
+\I\9{every_par_}{\.{\\everypar} primitive}, \[230].
+\I\\{every\_par\_loc}, \[230], 231, 307, 1226.
+\I\\{every\_par\_text}, \[307], 314, 1091.
+\I\\{every\_vbox}, \[230], 1083, 1167.
+\I\9{every_vbox_}{\.{\\everyvbox} primitive}, \[230].
+\I\\{every\_vbox\_loc}, \[230], 231.
+\I\\{every\_vbox\_text}, \[307], 314, 1083, 1167.
+\I\.{ex}, 455.
+\I\\{ex\_hyphen\_penalty}, 145, \[236], 869.
+\I\9{ex_hyphen_penalty_}{\.{\\exhyphenpenalty} primitive}, \[238].
+\I\\{ex\_hyphen\_penalty\_code}, \[236], 237, 238.
+\I\\{ex\_space}, \[208], 265, 266, 1030, 1090.
+\I\\{exactly}, \[644], 645, 715, 889, 977, 1017, 1062, 1201.
+\I\\{exit}, 35, 81, 331, 1332, 1337.
+\I\\{expand}, 358, \[366], 368, 371, 380, 381, 439, 467, 478, 498, 510, 782.
+\I\\{expand\_after}, \[210], 265, 266, 366, 367.
+\I\9{expand_after_}{\.{\\expandafter} primitive}, \[265].
+\I\&{explicit}, \[155].
+\I\\{ext\_bot}, \[546], 713, 714.
+\I\\{ext\_delimiter}, \[513], 515, 516, 517.
+\I\\{ext\_mid}, \[546], 713, 714.
+\I\\{ext\_rep}, \[546], 713, 714.
+\I\\{ext\_tag}, \[544], 569, 708, 710.
+\I\\{ext\_top}, \[546], 713, 714.
+\I\\{exten}, \[544].
+\I\\{exten\_base}, \[550], 552, 566, 573, 574, 576, 713, 1322, 1323.
+\I\\{exten\_base0}, \[550].
+\I\\{extensible\_recipe}, 541, \[546].
+\I\\{extension}, \[208], 1344, 1346, 1347, 1375.
+\I{extensions to \TeX}, 2, 146, 1340.
+\I\.{Extra \\else}, 510.
+\I\.{Extra \\endcsname}, 1135.
+\I\.{Extra \\fi}, 510.
+\I\.{Extra \\or}, 500, 510.
+\I\.{Extra \\right.}, 1192.
+\I\.{Extra \}, or forgotten x}, 1069.
+\I\.{Extra alignment tab...}, 792.
+\I\.{Extra x}, 1066.
+\I\\{extra\_info}, \[769], 788, 789, 791, 792.
+\I\\{extra\_right\_brace}, 1068, \[1069].
+\I\\{extra\_space}, 547, \[558], 1044.
+\I\\{extra\_space\_code}, \[547], 558.
+\I{eyes and mouth}, 332.
+\I\|{f}, \[25], \[27], \[28], \[31], \[113], \[144], \[448], \[524], \[560], \[577], \[578], \[581], \[582], \[592], \[602], \[649], \[706], \[709], \[711], \[712], \[715], \[716], \[717], \[738], \[830], \[862], \[1068], \[1113], \[1123], \[1138], %
+\[1211], \[1257].
+\I\\{false}, 27, 31, 37, 45, 46, 47, 51, 76, 80, 88, 89, 98, 106, 107, 166, 167, 168, 169, 264, 284, 299, 311, 323, 327, 331, 336, 346, 361, 362, 365, 374, 400, 401, 407, 425, 440, 441, 445, 447, 448, 449, 455, 460, 461, 462, 465, 485, 501, 502, 505,
+507, 509, 512, 516, 523, 525, 527, 538, 551, 563, 581, 593, 706, 720, 722, 754, 774, 791, 826, 828, 837, 851, 854, 863, 881, 903, 906, 910, 911, 951, 954, 960, 961, 962, 963, 966, 987, 990, 1006, 1011, 1020, 1026, 1031, 1033, 1034, 1035, 1040, 1051,
+1054, 1061, 1101, 1167, 1182, 1183, 1191, 1192, 1194, 1199, 1226, 1236, 1258, 1270, 1279, 1282, 1283, 1288, 1303, 1325, 1336, 1342, 1343, 1352, 1354, 1371, 1374.
+\I\\{false\_bchar}, \[1032], 1034, 1038.
+\I\\{fam}, \[681], 682, 683, 687, 691, 722, 723, 752, 753, 1151, 1155, 1165.
+\I\9{fam_}{\.{\\fam} primitive}, \[238].
+\I\\{fam\_fnt}, \[230], 700, 701, 707, 722, 1195.
+\I\\{fam\_in\_range}, \[1151], 1155, 1165.
+\I\\{fast\_delete\_glue\_ref}, \[201], 202.
+\I\\{fast\_get\_avail}, \[122], 371, 1034, 1038.
+\I\\{fast\_store\_new\_token}, \[371], 399, 464, 466.
+\I\.{Fatal format file error}, 1303.
+\I\\{fatal\_error}, 71, \[93], 324, 360, 484, 529, 535, 782, 789, 791, 1131.
+\I\\{fatal\_error\_stop}, \[76], 77, 82, 93, 1332.
+\I\\{fbyte}, \[564], 568, 571, 575.
+\I\\{fclose}, 56.
+\I\\{feof}, 56.
+\I{Ferguson, Michael John}, 2.
+\I\\{ferror}, 56.
+\I\\{fetch}, \[722], 724, 738, 741, 749, 752, 755.
+\I\\{fewest\_demerits}, \[872], 874, 875.
+\I\\{fflush}, 34.
+\I\\{fget}, \[564], 565, 568, 571, 575.
+\I\9{fi_}{\.{\\fi} primitive}, \[491].
+\I\\{fi\_code}, \[489], 491, 492, 494, 498, 500, 509, 510.
+\I\\{fi\_or\_else}, \[210], 366, 367, 489, 491, 492, 494, 510.
+\I\.{fil}, 454.
+\I\\{fil}, 135, \[150], 164, 177, 454, 650, 659, 665, 1201.
+\I\\{fil\_code}, \[1058], 1059, 1060.
+\I\\{fil\_glue}, \[162], 164, 1060.
+\I\\{fil\_neg\_code}, \[1058], 1060.
+\I\\{fil\_neg\_glue}, \[162], 164, 1060.
+\I\\{file}, 56.
+\I\.{File ended while scanning...}, 338.
+\I\.{File ended within \\read}, 486.
+\I\\{file\_name\_size}, \[11], 26, 51, 519, 521, 522.
+\I\\{file\_offset}, \[54], 55, 57, 58, 62, 537, 638, 1280.
+\I\\{file\_opened}, \[560], 561, 563.
+\I\\{fill}, 135, \[150], 164, 650, 659, 665, 1201.
+\I\\{fill\_code}, \[1058], 1059, 1060.
+\I\\{fill\_glue}, \[162], 164, 1054, 1060.
+\I\\{filll}, 135, \[150], 177, 454, 646, 650, 659, 665, 1201.
+\I\\{fin\_align}, 773, 785, \[800], 1131.
+\I\\{fin\_col}, 773, \[791], 1131.
+\I\\{fin\_mlist}, 1174, \[1184], 1186, 1191, 1194.
+\I\\{fin\_row}, 773, \[799], 1131.
+\I\\{fin\_rule}, \[622], 626, \[631], 635.
+\I\\{final\_cleanup}, 1332, \[1335].
+\I\\{final\_hyphen\_demerits}, \[236], 859.
+\I\9{final_hyphen_demerits_}{\.{\\finalhyphendemerits} primitive}, \[238].
+\I\\{final\_hyphen\_demerits\_code}, \[236], 237, 238.
+\I\\{final\_pass}, \[828], 854, 863, 873.
+\I\\{final\_widow\_penalty}, 814, \[815], 876, \[877], 890.
+\I\\{find\_font\_dimen}, 425, \[578], 1042, 1253.
+\I{fingers}, 511.
+\I\\{finite\_shrink}, 825, \[826].
+\I\\{fire\_up}, 1005, \[1012].
+\I\\{firm\_up\_the\_line}, \[340], 362, \[363], 538.
+\I\\{first}, \[30], 31, 35, 36, 37, 71, 83, 87, 88, 328, 329, 331, 355, 360, 362, 363, 374, 483, 530, 538.
+\I\\{first\_child}, \[960], 963, 964.
+\I\\{first\_count}, \[54], 315, 316, 317.
+\I\\{first\_fit}, \[953], 957, 966.
+\I\\{first\_indent}, \[847], 849, 889.
+\I\\{first\_mark}, \[382], 383, 1012, 1016.
+\I\9{first_mark_}{\.{\\firstmark} primitive}, \[384].
+\I\\{first\_mark\_code}, \[382], 384, 385.
+\I\\{first\_text\_char}, \[19], 24.
+\I\\{first\_width}, \[847], 849, 850, 889.
+\I\\{fit\_class}, \[830], 836, 845, 846, 852, 853, 855, 859.
+\I\\{fitness}, \[819], 845, 859, 864.
+\I\\{fix\_date\_and\_time}, \[241], 1332, 1337.
+\I\\{fix\_language}, 1034, \[1376].
+\I\\{fix\_word}, \[541], 542, 547, 548, 571.
+\I\&{float}, \[109].
+\I\\{float\_constant}, \[109], 186, 619, 625, 629, 1123, 1125.
+\I\\{float\_cost}, \[140], 188, 1008, 1100.
+\I\\{floating\_penalty}, 140, \[236], 1068, 1100.
+\I\9{floating_penalty_}{\.{\\floatingpenalty} primitive}, \[238].
+\I\\{floating\_penalty\_code}, \[236], 237, 238.
+\I\&{float32\_t}, \[9], 109.
+\I\\{flush\_char}, \[42], 180, 195, 692, 695.
+\I\\{flush\_list}, \[123], 200, 324, 372, 396, 407, 801, 903, 960, 1279, 1297, 1370.
+\I\\{flush\_math}, \[718], 776, 1195.
+\I\\{flush\_node\_list}, 199, \[202], 275, 639, 698, 718, 731, 732, 742, 800, 816, 879, 883, 903, 918, 968, 992, 999, 1078, 1105, 1120, 1121, 1375.
+\I\\{flush\_string}, \[44], 264, 537, 1260, 1279, 1328.
+\I\\{flushable\_string}, \[1257], 1260.
+\I\\{fmem\_ptr}, 425, \[549], 552, 566, 569, 570, 576, 578, 579, 580, 1320, 1321, 1323, 1334.
+\I\\{fmt\_file}, 523, \[1305], 1306, 1308, 1327, 1328, 1329, 1337.
+\I\\{fnt\_def1}, 585, \[586], 602.
+\I\\{fnt\_def2}, \[585].
+\I\\{fnt\_def3}, \[585].
+\I\\{fnt\_def4}, \[585].
+\I\\{fnt\_num\_0}, 585, \[586], 621.
+\I\\{fnt1}, 585, \[586], 621.
+\I\\{fnt2}, \[585].
+\I\\{fnt3}, \[585].
+\I\\{fnt4}, \[585].
+\I\\{font}, \[134], 143, 144, 174, 176, 193, 206, 267, 548, 582, 620, 654, 681, 709, 715, 724, 841, 842, 866, 867, 870, 871, 896, 897, 898, 903, 908, 911, 1034, 1038, 1113, 1147.
+\I{font metric files}, 539.
+\I{font parameters}, 700, 701.
+\I\.{Font x has only...}, 579.
+\I\.{Font x=xx not loadable...}, 561.
+\I\.{Font x=xx not loaded...}, 567.
+\I\9{font_}{\.{\\font} primitive}, \[265].
+\I\\{font\_area}, \[549], 552, 576, 602, 603, 1260, 1322, 1323.
+\I\\{font\_area0}, \[549].
+\I\\{font\_base}, 11, \[12], 111, 134, 174, 176, 222, 232, 549, 550, 551, 602, 621, 643, 1260, 1320, 1321, 1334.
+\I\\{font\_bc}, \[549], 552, 576, 582, 708, 722, 1036, 1322, 1323.
+\I\\{font\_bchar}, \[549], 552, 576, 897, 898, 915, 1032, 1034, 1322, 1323.
+\I\\{font\_bchar0}, \[549].
+\I\\{font\_bc0}, \[549].
+\I\\{font\_check}, \[549], 568, 602, 1322, 1323.
+\I\\{font\_check0}, \[549].
+\I\9{font_dimen_}{\.{\\fontdimen} primitive}, \[265].
+\I\\{font\_dsize}, 472, \[549], 552, 568, 602, 1260, 1261, 1322, 1323.
+\I\\{font\_dsize0}, \[549].
+\I\\{font\_ec}, \[549], 552, 576, 582, 708, 722, 1036, 1322, 1323.
+\I\\{font\_ec0}, \[549].
+\I\\{font\_false\_bchar}, \[549], 552, 576, 1032, 1034, 1322, 1323.
+\I\\{font\_false\_bchar0}, \[549].
+\I\\{font\_glue}, \[549], 552, 576, 578, 1042, 1322, 1323.
+\I\\{font\_glue0}, \[549].
+\I\\{font\_id\_base}, \[222], 234, 256, 415, 548, 1257.
+\I\\{font\_id\_text}, 234, \[256], 267, 579, 1257, 1322.
+\I\\{font\_in\_short\_display}, \[173], 174, 193, 663, 864, 1339.
+\I\&{font\_index}, \[548], 549, 560, 906, 1032, 1211.
+\I\\{font\_info}, 11, 425, 548, \[549], 550, 552, 554, 557, 558, 560, 566, 569, 571, 573, 574, 575, 578, 580, 700, 701, 713, 741, 752, 909, 1032, 1039, 1042, 1211, 1253, 1320, 1321, 1339.
+\I\\{font\_max}, \[11], 111, 174, 176, 549, 550, 551, 566, 1321, 1334.
+\I\\{font\_mem\_size}, \[11], 549, 566, 580, 1321, 1334.
+\I\\{font\_name}, 472, \[549], 552, 576, 581, 602, 603, 1260, 1261, 1322, 1323.
+\I\9{font_name_}{\.{\\fontname} primitive}, \[468].
+\I\\{font\_name\_code}, \[468], 469, 471, 472.
+\I\\{font\_name0}, \[549].
+\I\\{font\_params}, \[549], 552, 576, 578, 579, 580, 1195, 1322, 1323.
+\I\\{font\_params0}, \[549].
+\I\\{font\_ptr}, \[549], 552, 566, 576, 578, 643, 1260, 1320, 1321, 1334.
+\I\\{font\_size}, 472, \[549], 552, 568, 602, 1260, 1261, 1322, 1323.
+\I\\{font\_size0}, \[549].
+\I\\{font\_used}, \[549], 551, 621, 643.
+\I\\{font\_used0}, \[549].
+\I\.{FONTx}, 1257.
+\I\\{fopen}, 56.
+\I\.{for accent}, 191.
+\I\.{Forbidden control sequence...}, 338.
+\I\\{force\_eof}, 331, \[361], 362, 378.
+\I\\{format}, 56.
+\I\\{format\_area\_length}, \[520], 523.
+\I\\{format\_default\_length}, \[520], 521, 522, 523.
+\I\\{format\_ext\_length}, \[520], 522, 523.
+\I\\{format\_extension}, 528, 1328, \[1633].
+\I\\{format\_extension\_str}, \[520].
+\I\\{format\_ident}, 35, 61, 536, \[1299], 1300, 1301, 1326, 1327, 1328, 1337.
+\I\\{forward}, 78, 409, 693.
+\I\\{found}, 15, \[125], 128, 129, \[259], \[354], 356, \[392], 394, \[455], \[473], 475, 477, \[523], \[607], 609, 612, 613, 614, \[645], \[706], 708, \[720], \[923], 931, \[941], \[953], 955, \[1146], 1147, 1148, \[1237].
+\I\\{found1}, \[902], \[1315].
+\I\\{found2}, \[903], \[1316].
+\I\&{four\_choices}, \[113].
+\I\&{four\_quarters}, \[113], 548, 549, 554, 555, 560, 649, 683, 684, 706, 709, 712, 724, 738, 749, 906, 1032, 1123, 1302, 1303.
+\I\\{fprintf}, 56.
+\I\\{fraction\_noad}, \[683], 687, 690, 698, 733, 761, 1178, 1181.
+\I\\{fraction\_noad\_size}, \[683], 698, 761, 1181.
+\I\\{fraction\_rule}, \[704], 705, 735, 747.
+\I\\{fread}, 56.
+\I\\{free\_avail}, \[121], 202, 204, 217, 400, 452, 772, 915, 1036, 1226, 1288.
+\I\\{free\_node}, \[130], 201, 202, 275, 496, 615, 655, 698, 715, 721, 727, 751, 753, 756, 760, 772, 803, 860, 861, 865, 903, 910, 977, 1019, 1021, 1022, 1037, 1100, 1110, 1186, 1187, 1201, 1335, 1358.
+\I\\{freeze\_page\_specs}, \[987], 1001, 1008.
+\I\\{frozen\_control\_sequence}, \[222], 258, 1215, 1314, 1318, 1319.
+\I\\{frozen\_cr}, \[222], 339, 780, 1132.
+\I\\{frozen\_dont\_expand}, \[222], 258, 369.
+\I\\{frozen\_end\_group}, \[222], 265, 1065.
+\I\\{frozen\_end\_template}, \[222], 375, 780.
+\I\\{frozen\_endv}, \[222], 375, 380, 780.
+\I\\{frozen\_fi}, \[222], 336, 491.
+\I\\{frozen\_null\_font}, \[222], 553.
+\I\\{frozen\_protection}, \[222], 1215, 1216.
+\I\\{frozen\_relax}, \[222], 265, 379.
+\I\\{frozen\_right}, \[222], 1065, 1188.
+\I\\{fscanf}, 1338, 1339.
+\I{Fuchs, David Raymond}, 2, 583, 591.
+\I\9{future_let_}{\.{\\futurelet} primitive}, \[1219].
+\I\\{fwrite}, 56.
+\I\|{g}, \[47], \[182], \[560], \[592], \[649], \[668], \[706], \[716].
+\I\\{g\_order}, \[619], 625, \[629], 634.
+\I\\{g\_sign}, \[619], 625, \[629], 634.
+\I\\{garbage}, \[162], 467, 470, 960, 1183, 1192, 1279.
+\I\9{gdef_}{\.{\\gdef} primitive}, \[1208].
+\I\\{geq\_define}, \[279], 782, 1077, 1214.
+\I\\{geq\_word\_define}, \[279], 288, 1013, 1214.
+\I\\{get}, 26, 29, 31, 33, \[56], 485, 538, 564, 1306.
+\I\\{get\_avail}, \[120], 122, 204, 205, 216, 325, 337, 339, 369, 371, 372, 452, 473, 482, 582, 709, 772, 783, 784, 794, 908, 911, 938, 1064, 1065, 1226, 1371.
+\I\\{get\_cur\_chr}, \[343], 344, 346, 350.
+\I\\{get\_next}, 76, 297, 332, 336, 340, \[341], 357, 360, 364, 365, 366, 369, 380, 381, 387, 389, 478, 494, 507, 644, 1038, 1126.
+\I\\{get\_node}, \[125], 131, 136, 139, 144, 145, 147, 151, 152, 153, 156, 158, 206, 495, 607, 649, 668, 686, 688, 689, 716, 772, 798, 843, 844, 845, 864, 914, 1009, 1100, 1101, 1163, 1165, 1181, 1248, 1249, 1349, 1357.
+\I\\{get\_preamble\_token}, \[782], 783, 784.
+\I\\{get\_r\_token}, \[1215], 1218, 1221, 1224, 1225, 1257.
+\I\\{get\_strings\_started}, \[47].
+\I\\{get\_token}, 76, \[78], 88, 364, \[365], 368, 369, 392, 399, 442, 452, 471, 473, 474, 476, 477, 479, 483, 782, 1027, 1138, 1215, 1221, 1252, 1268, 1271, 1294, 1371, 1372.
+\I\\{get\_x\_token}, 364, \[366], 372, \[380], 381, 402, 404, 406, 407, 443, 444, 445, 452, 465, 479, 506, 525, 780, 935, 961, 1029, 1030, 1138, 1197, 1237, 1375.
+\I\\{get\_x\_token\_or\_active\_char}, \[506].
+\I\\{give\_err\_help}, \[78], 89, 90, \[1284].
+\I\\{global}, \[1214], 1218, 1241.
+\I{global definitions}, 221, 279, 283.
+\I\9{global_}{\.{\\global} primitive}, \[1208].
+\I\\{global\_defs}, \[236], 782, 1214, 1218.
+\I\9{global_defs_}{\.{\\globaldefs} primitive}, \[238].
+\I\\{global\_defs\_code}, \[236], 237, 238.
+\I\\{glue\_base}, 220, \[222], 224, 226, 227, 228, 229, 252, 782.
+\I\\{glue\_node}, \[149], 152, 153, 175, 183, 202, 206, 424, 622, 631, 651, 669, 730, 732, 761, 816, 817, 837, 856, 862, 866, 879, 881, 899, 903, 968, 972, 973, 988, 996, 997, 1000, 1106, 1107, 1108, 1147, 1202.
+\I\\{glue\_offset}, \[135], 159, 186.
+\I\&{glue\_ord}, \[150], 447, 619, 629, 649, 668, 791.
+\I\\{glue\_order}, \[135], 136, 159, 185, 186, 619, 629, 657, 658, 664, 672, 673, 676, 769, 796, 801, 807, 809, 810, 811, 1148.
+\I\\{glue\_par}, \[224], 766.
+\I\\{glue\_pars}, \[224].
+\I\\{glue\_ptr}, \[149], 152, 153, 175, 189, 190, 202, 206, 424, 625, 634, 656, 671, 679, 732, 786, 793, 795, 802, 803, 809, 816, 838, 868, 881, 969, 976, 996, 1001, 1004, 1148.
+\I\&{glue\_ratio}, \[109], 110, 113, 135, 186.
+\I\\{glue\_ref}, \[210], 228, 275, 782, 1228, 1236.
+\I\\{glue\_ref\_count}, \[150], 151, 152, 153, 154, 164, 201, 203, 228, 766, 1043, 1060.
+\I\\{glue\_set}, \[135], 136, 159, 186, 625, 634, 657, 658, 664, 672, 673, 676, 807, 809, 810, 811, 1148.
+\I\\{glue\_shrink}, \[159], 185, 796, 799, 801, 810, 811.
+\I\\{glue\_sign}, \[135], 136, 159, 185, 186, 619, 629, 657, 658, 664, 672, 673, 676, 769, 796, 801, 807, 809, 810, 811, 1148.
+\I\\{glue\_spec\_size}, \[150], 151, 162, 164, 201, 716.
+\I\\{glue\_stretch}, \[159], 185, 796, 799, 801, 810, 811.
+\I\\{glue\_temp}, \[619], 625, \[629], 634.
+\I\\{glue\_val}, \[410], 411, 412, 413, 416, 417, 424, 427, 429, 430, 451, 461, 465, 782, 1060, 1228, 1236, 1237, 1238, 1240.
+\I\.{goal height}, 986, 987.
+\I\&{goto}, \[35], \[81].
+\I\\{gr}, 110, \[113], 114, 135.
+\I\&{group\_code}, \[269], 271, 274, 645, 1136.
+\I{Guibas, Leonidas Ioannis}, 2.
+\I\\{g1}, \[1198], 1203.
+\I\\{g2}, \[1198], 1203, 1205.
+\I\|{h}, \[204], \[259], \[649], \[668], \[738], \[929], \[934], \[948], \[953], \[966], \[970], \[977], \[994], \[1086], \[1091], \[1123].
+\I\\{h\_offset}, \[247], 617, 641.
+\I\9{h_offset_}{\.{\\hoffset} primitive}, \[248].
+\I\\{h\_offset\_code}, \[247], 248.
+\I\\{ha}, \[892], 896, 900, 903, 912.
+\I\\{half}, \[100], 706, 736, 737, 738, 745, 746, 749, 750, 1202.
+\I\\{half\_buf}, 594, \[595], 596, 598, 599.
+\I\\{half\_error\_line}, \[11], 14, 311, 315, 316, 317.
+\I\&{halfword}, 108, 110, \[113], 115, 130, 264, 277, 279, 280, 281, 297, 298, 300, 333, 341, 366, 389, 413, 464, 473, 549, 560, 577, 681, 791, 800, 821, 829, 830, 833, 847, 872, 877, 892, 901, 906, 907, 1032, 1079, 1243, 1266, 1288.
+\I\\{halign}, \[208], 265, 266, 1094, 1130.
+\I\9{halign_}{\.{\\halign} primitive}, \[265].
+\I\\{handle\_right\_brace}, 1067, \[1068].
+\I\\{hang\_after}, \[236], 240, 847, 849, 1070, 1149.
+\I\9{hang_after_}{\.{\\hangafter} primitive}, \[238].
+\I\\{hang\_after\_code}, \[236], 237, 238, 1070.
+\I\\{hang\_indent}, \[247], 847, 848, 849, 1070, 1149.
+\I\9{hang_indent_}{\.{\\hangindent} primitive}, \[248].
+\I\\{hang\_indent\_code}, \[247], 248, 1070.
+\I{hanging indentation}, 847.
+\I\\{hash}, 234, \[256], 257, 259, 260, 1318, 1319.
+\I\\{hash\_base}, 220, \[222], 256, 257, 259, 262, 263, 1257, 1314, 1318, 1319.
+\I\\{hash\_brace}, \[473], 476.
+\I\\{hash\_is\_full}, \[256], 260.
+\I\\{hash\_prime}, \[12], 14, 259, 261, 1307, 1308.
+\I\\{hash\_size}, \[12], 14, 222, 260, 261, 1334.
+\I\\{hash\_used}, \[256], 258, 260, 1318, 1319.
+\I\\{hash0}, \[256].
+\I\\{have}, 9.
+\I\\{hb}, \[892], 897, 898, 900, 903.
+\I\\{hbadness}, \[236], 660, 666, 667.
+\I\9{hbadness_}{\.{\\hbadness} primitive}, \[238].
+\I\\{hbadness\_code}, \[236], 237, 238.
+\I\9{hbox_}{\.{\\hbox} primitive}, \[1071].
+\I\\{hbox\_group}, \[269], 274, 1083, 1085.
+\I\\{hc}, \[892], 893, 897, 898, 900, 901, 919, 920, 923, 930, 931, 934, 937, 939, 960, 962, 963, 965.
+\I\\{hchar}, 905, \[906], 908, 909.
+\I\\{hd}, \[649], 654, \[706], 708, \[709], \[712].
+\I\\{head}, 212, \[213], 215, 216, 217, 424, 718, 776, 796, 799, 805, 812, 814, 816, 1026, 1054, 1080, 1081, 1086, 1091, 1096, 1100, 1105, 1113, 1119, 1121, 1145, 1159, 1168, 1176, 1181, 1184, 1185, 1187, 1191.
+\I\\{head\_field}, \[212], 213, 218.
+\I\\{head\_for\_vmode}, 1094, \[1095].
+\I\\{header}, 542.
+\I{Hedrick, Charles Locke}, 3.
+\I\\{height}, \[135], 136, 138, 139, 140, 184, 187, 188, 463, 554, 622, 624, 626, 629, 631, 632, 635, 637, 640, 641, 649, 653, 656, 670, 672, 679, 704, 706, 709, 711, 713, 727, 730, 735, 736, 737, 738, 739, 742, 745, 746, 747, 749, 750, 751, 756, 757,
+759, 768, 769, 796, 801, 804, 806, 807, 809, 810, 811, 969, 973, \[981], 986, 1001, 1002, 1008, 1009, 1010, 1021, 1087, 1100.
+\I\.{height}, 463.
+\I\\{height\_base}, \[550], 552, 554, 566, 571, 1322, 1323.
+\I\\{height\_base0}, \[550].
+\I\\{height\_depth}, \[554], 654, 708, 709, 712, 1125.
+\I\\{height\_index}, \[543], 554.
+\I\\{height\_offset}, \[135], 416, 417, 769, 1247.
+\I\\{height\_plus\_depth}, \[712], 714.
+\I\.{held over for next output}, 986.
+\I\\{help\_line}, \[79], 89, 90, 336, 1106.
+\I\\{help\_ptr}, \[79], 80, 89, 90.
+\I\\{help0}, \[79], 1252, 1293.
+\I\\{help1}, \[79], 93, 95, 288, 408, 428, 454, 476, 486, 500, 503, 510, 960, 961, 962, 963, 1066, 1080, 1099, 1121, 1132, 1135, 1159, 1177, 1192, 1212, 1213, 1232, 1237, 1243, 1244, 1258, 1283, 1304.
+\I\\{help2}, 72, \[79], 88, 89, 94, 95, 288, 346, 373, 433, 434, 435, 436, 437, 442, 445, 460, 475, 476, 577, 579, 641, 936, 937, 978, 1015, 1027, 1047, 1068, 1080, 1082, 1095, 1106, 1120, 1129, 1166, 1197, 1207, 1225, 1236, 1241, 1259, 1372.
+\I\\{help3}, 72, \[79], 98, 336, 396, 415, 446, 479, 776, 783, 784, 792, 993, 1009, 1024, 1028, 1078, 1084, 1110, 1127, 1183, 1195, 1293.
+\I\\{help4}, \[79], 89, 338, 398, 403, 418, 456, 567, 723, 976, 1004, 1050, 1283.
+\I\\{help5}, \[79], 370, 561, 826, 1064, 1069, 1128, 1215, 1293.
+\I\\{help6}, \[79], 395, 459, 1128, 1161.
+\I\.{Here is how much...}, 1334.
+\I\\{hex\_to\_cur\_chr}, \[352], 355.
+\I\\{hex\_token}, \[438], 444.
+\I\\{hf}, \[892], 896, 897, 898, 903, 908, 909, 910, 911, 915, 916.
+\I\9{hfil_}{\.{\\hfil} primitive}, \[1058].
+\I\9{hfil_neg_}{\.{\\hfilneg} primitive}, \[1058].
+\I\9{hfill_}{\.{\\hfill} primitive}, \[1058].
+\I\\{hfuzz}, \[247], 666.
+\I\9{hfuzz_}{\.{\\hfuzz} primitive}, \[248].
+\I\\{hfuzz\_code}, \[247], 248.
+\I\\{hh}, 110, \[113], 114, 118, 133, 182, 213, 219, 221, 268, 686, 742, 1163, 1165, 1181, 1186, 1305, 1306.
+\I\\{hi}, \[112], 232, 1232.
+\I\\{hi\_mem\_min}, \[116], 118, 120, 125, 126, 134, 164, 165, 167, 168, 171, 172, 176, 293, 639, 1311, 1312, 1334.
+\I\\{hi\_mem\_stat\_min}, \[162], 164, 1312.
+\I\\{hi\_mem\_stat\_usage}, \[162], 164.
+\I\\{history}, \[76], 77, 82, 93, 95, 245, 1332, 1335.
+\I\\{hlist\_node}, \[135], 136, 137, 138, 148, 159, 175, 183, 184, 202, 206, 505, 618, 619, 622, 631, 644, 649, 651, 669, 681, 807, 810, 814, 841, 842, 866, 870, 871, 968, 973, 993, 1000, 1074, 1080, 1087, 1110, 1147, 1203.
+\I\\{hlist\_out}, 592, 615, 616, 618, \[619], 620, 623, 628, 629, 632, 637, 638, 640, 693, 1373.
+\I\\{hlp1}, \[79].
+\I\\{hlp2}, \[79].
+\I\\{hlp3}, \[79].
+\I\\{hlp4}, \[79].
+\I\\{hlp5}, \[79].
+\I\\{hlp6}, \[79].
+\I\\{hmode}, \[211], 218, 416, 501, 786, 787, 796, 799, 1030, 1045, 1046, 1048, 1056, 1057, 1071, 1073, 1076, 1079, 1083, 1086, 1091, 1092, 1093, 1094, 1096, 1097, 1109, 1110, 1112, 1116, 1117, 1119, 1122, 1130, 1137, 1200, 1243, 1377.
+\I\\{hmove}, \[208], 1048, 1071, 1072, 1073.
+\I\\{hn}, \[892], 897, 898, 899, 902, 912, 913, 915, 916, 917, 919, 923, 930, 931.
+\I\\{ho}, \[112], 235, 414, 1151, 1154.
+\I\\{hold\_head}, \[162], 306, 779, 783, 784, 794, 808, 905, 906, 913, 914, 915, 916, 917, 1014, 1017.
+\I\\{holding\_inserts}, \[236], 1014.
+\I\9{holding_inserts_}{\.{\\holdinginserts} primitive}, \[238].
+\I\\{holding\_inserts\_code}, \[236], 237, 238.
+\I\\{hpack}, 162, 236, 644, 645, 646, 647, \[649], 661, 709, 715, 720, 727, 737, 748, 754, 756, 796, 799, 804, 806, 889, 1062, 1086, 1125, 1194, 1199, 1201, 1204.
+\I\\{hrule}, \[208], 265, 266, 463, 1046, 1056, 1084, 1094, 1095.
+\I\9{hrule_}{\.{\\hrule} primitive}, \[265].
+\I\\{hsize}, \[247], 847, 848, 849, 1054, 1149.
+\I\9{hsize_}{\.{\\hsize} primitive}, \[248].
+\I\\{hsize\_code}, \[247], 248.
+\I\\{hskip}, \[208], 1057, 1058, 1059, 1078, 1090.
+\I\9{hskip_}{\.{\\hskip} primitive}, \[1058].
+\I\9{hss_}{\.{\\hss} primitive}, \[1058].
+\I\9{ht_}{\.{\\ht} primitive}, \[416].
+\I\\{hu}, \[892], 893, 897, 898, 901, 903, 905, 907, 908, 910, 911, 912, 915, 916.
+\I\.{Huge page...}, 641.
+\I\\{hyf}, \[900], 902, 905, 908, 909, 913, 914, 919, 920, 923, 924, 932, 960, 961, 962, 963, 965.
+\I\\{hyf\_bchar}, \[892], 897, 898, 903.
+\I\\{hyf\_char}, \[892], 896, 913, 915.
+\I\\{hyf\_distance}, 920, \[921], 922, 924, 943, 944, 945, 1324, 1325.
+\I\\{hyf\_distance0}, \[921].
+\I\\{hyf\_next}, 920, \[921], 924, 943, 944, 945, 1324, 1325.
+\I\\{hyf\_next0}, \[921].
+\I\\{hyf\_node}, \[912], 915.
+\I\\{hyf\_num}, 920, \[921], 924, 943, 944, 945, 1324, 1325.
+\I\\{hyf\_num0}, \[921].
+\I\\{hyph\_count}, \[926], 928, 940, 1324, 1325, 1334.
+\I\\{hyph\_data}, \[209], 1210, 1250, 1251, 1252.
+\I\\{hyph\_list}, \[926], 928, 929, 932, 933, 934, 940, 941, 1324, 1325.
+\I\&{hyph\_pointer}, \[925], 926, 927, 929, 934.
+\I\\{hyph\_size}, \[12], 926, 928, 930, 933, 939, 940, 1307, 1308, 1324, 1325, 1334.
+\I\\{hyph\_word}, \[926], 928, 929, 931, 934, 940, 941, 1324, 1325.
+\I\\{hyphen\_char}, 426, \[549], 552, 576, 891, 896, 1035, 1117, 1253, 1322, 1323.
+\I\9{hyphen_char_}{\.{\\hyphenchar} primitive}, \[1254].
+\I\\{hyphen\_char0}, \[549].
+\I\\{hyphen\_passed}, \[905], 906, 909, 913, 914.
+\I\\{hyphen\_penalty}, 145, \[236], 869.
+\I\9{hyphen_penalty_}{\.{\\hyphenpenalty} primitive}, \[238].
+\I\\{hyphen\_penalty\_code}, \[236], 237, 238.
+\I\\{hyphenate}, 894, \[895].
+\I\\{hyphenated}, \[819], 820, 829, 846, 859, 869, 873.
+\I\.{Hyphenation trie...}, 1324.
+\I\9{hyphenation_}{\.{\\hyphenation} primitive}, \[1250].
+\I\|{i}, \[19], \[113], \[315], \[587], \[649], \[738], \[749], \[901], \[1123].
+\I\.{I can't find file x}, 529.
+\I\.{I can't find PLAIN...}, 523.
+\I\.{I can't go on...}, 95.
+\I\.{I can't read TEX.POOL}, 51.
+\I\.{I can't write on file x}, 529.
+\I\\{id\_byte}, \[587], 617, 642.
+\I\\{id\_lookup}, \[259], 264, 356, 374.
+\I\\{ident\_val}, \[410], 415, 465, 466.
+\I\9{if_case_}{\.{\\ifcase} primitive}, \[487].
+\I\\{if\_case\_code}, \[487], 488, 501.
+\I\\{if\_cat\_code}, \[487], 488, 501.
+\I\9{if_cat_code_}{\.{\\ifcat} primitive}, \[487].
+\I\9{if_char_}{\.{\\if} primitive}, \[487].
+\I\\{if\_char\_code}, \[487], 501, 506.
+\I\\{if\_code}, \[489], 495, 510.
+\I\9{if_dim_}{\.{\\ifdim} primitive}, \[487].
+\I\\{if\_dim\_code}, \[487], 488, 501.
+\I\9{if_eof_}{\.{\\ifeof} primitive}, \[487].
+\I\\{if\_eof\_code}, \[487], 488, 501.
+\I\9{if_false_}{\.{\\iffalse} primitive}, \[487].
+\I\\{if\_false\_code}, \[487], 488, 501.
+\I\9{if_hbox_}{\.{\\ifhbox} primitive}, \[487].
+\I\\{if\_hbox\_code}, \[487], 488, 501, 505.
+\I\9{if_hmode_}{\.{\\ifhmode} primitive}, \[487].
+\I\\{if\_hmode\_code}, \[487], 488, 501.
+\I\9{if_inner_}{\.{\\ifinner} primitive}, \[487].
+\I\\{if\_inner\_code}, \[487], 488, 501.
+\I\9{if_int_}{\.{\\ifnum} primitive}, \[487].
+\I\\{if\_int\_code}, \[487], 488, 501, 503.
+\I\\{if\_limit}, \[489], 490, 495, 496, 497, 498, 510.
+\I\\{if\_line}, \[489], 490, 495, 496, 1335.
+\I\\{if\_line\_field}, \[489], 495, 496, 1335.
+\I\9{if_mmode_}{\.{\\ifmmode} primitive}, \[487].
+\I\\{if\_mmode\_code}, \[487], 488, 501.
+\I\\{if\_node\_size}, \[489], 495, 496, 1335.
+\I\9{if_odd_}{\.{\\ifodd} primitive}, \[487].
+\I\\{if\_odd\_code}, \[487], 488, 501.
+\I\\{if\_test}, \[210], 336, 366, 367, 487, 488, 494, 498, 503, 1335.
+\I\9{if_true_}{\.{\\iftrue} primitive}, \[487].
+\I\\{if\_true\_code}, \[487], 488, 501.
+\I\9{if_vbox_}{\.{\\ifvbox} primitive}, \[487].
+\I\\{if\_vbox\_code}, \[487], 488, 501.
+\I\9{if_vmode_}{\.{\\ifvmode} primitive}, \[487].
+\I\\{if\_vmode\_code}, \[487], 488, 501.
+\I\9{if_void_}{\.{\\ifvoid} primitive}, \[487].
+\I\\{if\_void\_code}, \[487], 488, 501, 505.
+\I\9{ifx_}{\.{\\ifx} primitive}, \[487].
+\I\\{ifx\_code}, \[487], 488, 501.
+\I\\{ignore}, \[207], 232, 332, 345.
+\I\\{ignore\_depth}, \[212], 215, 219, 679, 787, 1025, 1056, 1083, 1099, 1167.
+\I\\{ignore\_spaces}, \[208], 265, 266, 1045.
+\I\9{ignore_spaces_}{\.{\\ignorespaces} primitive}, \[265].
+\I\.{Illegal magnification...}, 288, 1258.
+\I\.{Illegal math \\disc...}, 1120.
+\I\.{Illegal parameter number...}, 479.
+\I\.{Illegal unit of measure}, 454, 456, 459.
+\I\9{immediate_}{\.{\\immediate} primitive}, \[1344].
+\I\\{immediate\_code}, \[1344], 1346, 1348.
+\I\.{IMPOSSIBLE}, 262.
+\I\.{Improper \\halign...}, 776.
+\I\.{Improper \\hyphenation...}, 936.
+\I\.{Improper \\prevdepth}, 418.
+\I\.{Improper \\setbox}, 1241.
+\I\.{Improper \\spacefactor}, 418.
+\I\.{Improper `at' size...}, 1259.
+\I\.{Improper alphabetic constant}, 442.
+\I\.{Improper discretionary list}, 1121.
+\I$\in$, 49.
+\I\.{in}, 458.
+\I\\{in\_open}, \[304], 328, 329, 331.
+\I\&{in\_state\_record}, \[300], 301.
+\I\\{in\_stream}, \[208], 1272, 1273, 1274.
+\I\.{Incompatible glue units}, 408.
+\I\.{Incompatible list...}, 1110.
+\I\.{Incompatible magnification}, 288.
+\I\\{incompleat\_noad}, 212, \[213], 718, 776, 1136, 1178, 1181, 1182, 1184, 1185.
+\I\.{Incomplete \\if...}, 336.
+\I\\{incr}, \[16], 31, 37, 42, 43, 45, 46, 53, 58, 59, 60, 65, 67, 70, 71, 82, 90, 98, 117, 120, 152, 153, 170, 182, 203, 216, 260, 274, 276, 280, 294, 311, 312, 321, 325, 328, 343, 347, 352, 354, 355, 356, 357, 360, 362, 374, 392, 395, 397, 399, 400,
+403, 407, 442, 452, 454, 464, 475, 476, 477, 494, 517, 519, 523, 530, 537, 580, 598, 619, 629, 640, 642, 645, 714, 798, 845, 877, 897, 898, 910, 911, 914, 915, 923, 930, 931, 937, 939, 940, 941, 944, 954, 956, 962, 963, 964, 986, 1022, 1025, 1035, 1039,
+1069, 1099, 1117, 1119, 1121, 1127, 1142, 1153, 1172, 1174, 1315, 1316, 1318, 1337.
+\I\\{incr\_dyn\_used}, \[117], 120, 122.
+\I\9{indent_}{\.{\\indent} primitive}, \[1088].
+\I\\{indent\_in\_hmode}, 1092, \[1093].
+\I\\{indented}, \[1091].
+\I\\{index}, 300, \[302], 303, 304, 307, 328, 329, 331.
+\I\\{index\_field}, \[300], 302, 1131.
+\I\\{inf}, 447, \[448], 453.
+\I\\{inf\_bad}, \[108], 157, 851, 852, 853, 856, 863, 974, 1005, 1017.
+\I\\{inf\_penalty}, \[157], 761, 767, 816, 829, 831, 974, 1005, 1013, 1203, 1205.
+\I\.{Infinite glue shrinkage...}, 826, 976, 1004, 1009.
+\I\\{infinity}, \[445].
+\I\\{info}, \[118], 124, 126, 140, 164, 172, 200, 233, 275, 291, 293, 325, 337, 339, 357, 358, 369, 371, 374, 389, 391, 392, 393, 394, 397, 400, 423, 452, 466, 508, 605, 608, 609, 610, 611, 612, 613, 614, 615, 681, 689, 692, 693, 698, 720, 734, 735, 736,
+737, 738, 742, 749, 754, 768, 769, 772, 779, 783, 784, 790, 793, 794, 797, 798, 801, 803, 821, 847, 848, 925, 932, 938, 981, 1065, 1076, 1093, 1149, 1151, 1168, 1181, 1185, 1186, 1191, 1226, 1248, 1249, 1289, 1312, 1339, 1341, 1371.
+\I\\{init}, 8.
+\I\.{INIT}, \[8], \[47], \[50], \[111], \[131], \[264], \[891], \[942], \[943], \[947], \[950], \[1252], \[1302], \[1325], \[1332], \[1335], \[1336].
+\I\\{init\_align}, 773, \[774], 1130.
+\I\\{init\_col}, 773, 785, \[788], 791.
+\I\\{init\_cur\_lang}, 816, 891, \[892].
+\I\\{init\_l\_hyf}, 816, 891, \[892].
+\I\\{init\_lft}, \[900], 903, 905, 908.
+\I\\{init\_lig}, \[900], 903, 905, 908.
+\I\\{init\_list}, \[900], 903, 905, 908.
+\I\\{init\_math}, 1137, \[1138].
+\I\\{init\_pool\_ptr}, \[39], 42, 1310, 1332, 1334.
+\I\\{init\_prim}, 1332, \[1336].
+\I\\{init\_r\_hyf}, 816, 891, \[892].
+\I\\{init\_row}, 773, 785, \[786].
+\I\\{init\_span}, 773, 786, \[787], 791.
+\I\\{init\_str\_ptr}, \[39], 43, 517, 1310, 1332, 1334.
+\I\\{init\_terminal}, \[37], 331.
+\I\\{init\_trie}, 891, \[966], 1324.
+\I\.{INITEX}, 8, 11, 12, 47, 50, 116, 1299, 1331.
+\I\\{initialize}, \[4], 1332, 1337.
+\I{inner loop}, 31, 112, 120, 121, 122, 123, 125, 127, 128, 130, 202, 324, 325, 341, 342, 343, 357, 365, 380, 399, 407, 554, 597, 611, 620, 651, 654, 655, 832, 835, 851, 852, 867, 1030, 1034, 1035, 1036, 1039, 1041.
+\I\\{inner\_noad}, \[682], 683, 690, 696, 698, 733, 761, 764, 1156, 1157, 1191.
+\I\\{input}, \[210], 366, 367, 376, 377.
+\I\9{input_}{\.{\\input} primitive}, \[376].
+\I\\{input\_file}, \[304].
+\I\\{input\_file0}, \[304].
+\I\9{input_line_no_}{\.{\\inputlineno} primitive}, \[416].
+\I\\{input\_line\_no\_code}, \[416], 417, 424.
+\I\\{input\_ln}, 30, \[31], 37, 58, 71, 362, 485, 486, 538.
+\I\\{input\_ptr}, \[301], 311, 312, 321, 322, 330, 331, 360, 534, 1131, 1335.
+\I\\{input\_stack}, 84, \[301], 311, 321, 322, 534, 1131.
+\I\\{ins\_disc}, \[1032], 1033, 1035.
+\I\\{ins\_error}, \[327], 336, 395, 1047, 1127, 1132, 1215.
+\I\\{ins\_list}, \[323], 339, 467, 470, 1064, 1371.
+\I\\{ins\_node}, \[140], 148, 175, 183, 202, 206, 647, 651, 730, 761, 866, 899, 968, 973, 981, 986, 1000, 1014, 1100.
+\I\\{ins\_node\_size}, \[140], 202, 206, 1022, 1100.
+\I\\{ins\_ptr}, \[140], 188, 202, 206, 1010, 1020, 1021, 1100.
+\I\\{ins\_the\_toks}, \[366], 367, \[467].
+\I\\{insert}, \[208], 265, 266, 1097.
+\I\.{insert>}, 87.
+\I\9{insert_}{\.{\\insert} primitive}, \[265].
+\I\\{insert\_dollar\_sign}, 1045, \[1047].
+\I\\{insert\_group}, \[269], 1068, 1099, 1100.
+\I\\{insert\_penalties}, 419, \[982], 990, 1005, 1008, 1010, 1014, 1022, 1026, 1242, 1246.
+\I\9{insert_penalties_}{\.{\\insertpenalties} primitive}, \[416].
+\I\\{insert\_relax}, 378, \[379], 510.
+\I\\{insert\_token}, \[268], 280, 282.
+\I\\{inserted}, \[307], 314, 323, 324, 327, 379, 1095.
+\I\\{inserting}, \[981], 1009.
+\I\.{Insertions can only...}, 993.
+\I\\{inserts\_only}, \[980], 987, 1008.
+\I\\{int\_base}, 220, \[230], 232, 236, 238, 239, 240, 242, 252, 253, 254, 268, 283, 288, 1013, 1070, 1139, 1145, 1315.
+\I\\{int\_error}, \[91], 288, 433, 434, 435, 436, 437, 1243, 1244, 1258.
+\I\\{int\_par}, \[236].
+\I\\{int\_pars}, \[236].
+\I\\{int\_val}, \[410], 411, 412, 413, 414, 416, 417, 418, 419, 422, 423, 424, 426, 427, 428, 429, 439, 440, 449, 461, 465, 1237, 1238, 1240.
+\I\\{inter\_line\_penalty}, \[236], 890.
+\I\9{inter_line_penalty_}{\.{\\interlinepenalty} primitive}, \[238].
+\I\\{inter\_line\_penalty\_code}, \[236], 237, 238.
+\I\\{interaction}, 71, 72, \[73], 74, 75, 82, 84, 86, 90, 92, 93, 98, 360, 363, 484, 529, 1265, 1283, 1293, 1294, 1297, 1326, 1327, 1328, 1335.
+\I\&{internal\_font\_number}, \[548], 549, 560, 577, 578, 581, 582, 602, 616, 649, 706, 709, 711, 712, 715, 724, 738, 830, 862, 892, 1032, 1113, 1123, 1138, 1211.
+\I\\{interrupt}, \[96], 97, 98, 1031.
+\I\.{Interruption}, 98.
+\I\.{interwoven alignment preambles...}, 324, 782, 789, 791, 1131.
+\I\\{int16\_t}, 212, 213, 218, 944.
+\I\&{int8\_t}, 76.
+\I\.{Invalid code}, 1232.
+\I\\{invalid\_char}, \[207], 232, 344.
+\I\\{invalid\_code}, \[22], 24, 232.
+\I\\{is\_char\_node}, \[134], 174, 183, 202, 205, 424, 620, 630, 651, 669, 715, 720, 721, 756, 805, 816, 837, 841, 842, 866, 867, 868, 870, 871, 879, 896, 897, 899, 903, 1036, 1040, 1080, 1081, 1105, 1113, 1121, 1147, 1202.
+\I\\{is\_empty}, \[124], 127, 169, 170.
+\I\\{is\_free}, \[165], 167, 168, 169, 170, 171.
+\I\\{is\_free0}, \[165].
+\I\\{is\_hex}, \[352], 355.
+\I\\{is\_running}, \[138], 176, 624, 633, 806.
+\I\\{issue\_message}, 1276, \[1279].
+\I\\{ital\_corr}, \[208], 265, 266, 1111, 1112.
+\I{italic correction}, \[543].
+\I\\{italic\_base}, \[550], 552, 554, 566, 571, 1322, 1323.
+\I\\{italic\_base0}, \[550].
+\I\\{italic\_index}, \[543].
+\I\\{its\_all\_over}, 1045, \[1054], 1335.
+\I\|{j}, \[45], \[46], \[59], \[60], \[69], \[70], \[259], \[264], \[315], \[366], \[519], \[522], \[523], \[638], \[893], \[901], \[906], \[934], \[966], \[1211], \[1302], \[1303], \[1370], \[1373].
+\I{Japanese characters}, 134, 585.
+\I{Jensen, Kathleen}, 10.
+\I\.{job aborted}, 360.
+\I\.{job aborted, file error...}, 529.
+\I\\{job\_name}, 92, 471, 472, \[526], 527, 528, 531, 534, 537, 1257, 1328, 1335.
+\I\9{job_name_}{\.{\\jobname} primitive}, \[468].
+\I\\{job\_name\_code}, \[468], 471, 472.
+\I\\{jump\_out}, \[81], 82, 84, 93.
+\I\\{just\_box}, \[814], 888, 889, 1146, 1148.
+\I\\{just\_open}, \[480], 483, 1275.
+\I\|{k}, \[45], \[46], \[47], \[51], \[64], \[65], \[67], \[69], \[71], \[102], \[163], \[259], \[264], \[341], \[363], \[407], \[450], \[464], \[519], \[522], \[524], \[529], \[534], \[560], \[587], \[597], \[602], \[607], \[638], \[705], \[906], %
+\[929], \[934], \[960], \[966], \[1079], \[1211], \[1302], \[1303], \[1333], \[1338], \[1348], \[1368].
+\I\\{kern}, \[208], 545, 1057, 1058, 1059.
+\I\9{kern_}{\.{\\kern} primitive}, \[1058].
+\I\\{kern\_base}, \[550], 552, 557, 566, 573, 576, 1322, 1323.
+\I\\{kern\_base\_offset}, \[557], 566, 573.
+\I\\{kern\_base0}, \[550].
+\I\\{kern\_break}, \[866].
+\I\\{kern\_flag}, \[545], 741, 753, 909, 1040.
+\I\\{kern\_node}, \[155], 156, 183, 202, 206, 424, 622, 631, 651, 669, 721, 730, 732, 761, 837, 841, 842, 856, 866, 868, 870, 871, 879, 881, 896, 897, 899, 968, 972, 973, 976, 996, 997, 1000, 1004, 1106, 1107, 1108, 1121, 1147.
+\I\\{kk}, \[450], 452.
+\I{Knuth, Donald Ervin}, 2, 86, 693, 813, 891, 925, 997, 1154, 1371.
+\I\|{l}, \[47], \[259], \[264], \[276], \[281], \[292], \[315], \[494], \[497], \[534], \[601], \[615], \[668], \[830], \[901], \[944], \[953], \[960], \[963], \[965], \[1138], \[1194], \[1236], \[1302], \[1338], \[1376].
+\I\\{l\_hyf}, 891, \[892], 894, 899, 902, 923, 1362.
+\I\\{label1}, \[610].
+\I\\{label2}, \[610].
+\I\\{language}, \[236], 934, 1034, 1376.
+\I\9{language_}{\.{\\language} primitive}, \[238].
+\I\\{language\_code}, \[236], 237, 238.
+\I\\{language\_node}, \[1341], 1356, 1357, 1358, 1362, 1373, 1376, 1377.
+\I\\{large\_attempt}, \[706].
+\I\\{large\_char}, \[683], 691, 697, 706, 1160.
+\I\\{large\_fam}, \[683], 691, 697, 706, 1160.
+\I\\{last}, \[30], 31, 35, 36, 37, 71, 83, 87, 88, 331, 360, 363, 483, 523, 530.
+\I\\{last\_active}, \[819], 820, 832, 835, 844, 854, 860, 861, 863, 864, 865, 873, 874, 875.
+\I\\{last\_badness}, 424, \[646], 648, 649, 660, 664, 667, 668, 674, 676, 678.
+\I\\{last\_bop}, \[592], 593, 640, 642.
+\I\9{last_box_}{\.{\\lastbox} primitive}, \[1071].
+\I\\{last\_box\_code}, \[1071], 1072, 1079.
+\I\\{last\_glue}, 424, \[982], 991, 996, 1017, 1106, 1335.
+\I\\{last\_ins\_ptr}, \[981], 1005, 1008, 1018, 1020.
+\I\\{last\_item}, \[208], 413, 416, 417, 1048.
+\I\\{last\_kern}, 424, \[982], 991, 996.
+\I\9{last_kern_}{\.{\\lastkern} primitive}, \[416].
+\I\\{last\_nonblank}, \[31].
+\I\\{last\_penalty}, 424, \[982], 991, 996.
+\I\9{last_penalty_}{\.{\\lastpenalty} primitive}, \[416].
+\I\9{last_skip_}{\.{\\lastskip} primitive}, \[416].
+\I\\{last\_special\_line}, \[847], 848, 849, 850, 889.
+\I\\{last\_text\_char}, \[19], 24.
+\I\\{lc\_code}, \[230], 232, 891, 896, 897, 898, 937, 962.
+\I\9{lc_code_}{\.{\\lccode} primitive}, \[1230].
+\I\\{lc\_code\_base}, \[230], 235, 1230, 1231, 1286, 1287, 1288.
+\I\\{leader\_box}, \[619], 626, 628, \[629], 635, 637.
+\I\\{leader\_flag}, \[1071], 1073, 1078, 1084.
+\I\\{leader\_ht}, \[629], 635, 636, 637.
+\I\\{leader\_ptr}, \[149], 152, 153, 190, 202, 206, 626, 635, 656, 671, 816, 1078.
+\I\\{leader\_ship}, \[208], 1071, 1072, 1073.
+\I\\{leader\_wd}, \[619], 626, 627, 628.
+\I{leaders}, 1374.
+\I\.{Leaders not followed by...}, 1078.
+\I\9{leaders_}{\.{\\leaders} primitive}, \[1071].
+\I\\{least\_cost}, \[970], 974, 980.
+\I\\{least\_page\_cost}, \[980], 987, 1005, 1006.
+\I\9{left_}{\.{\\left} primitive}, \[1188].
+\I\\{left\_brace}, \[207], 289, 294, 298, 347, 357, 403, 473, 476, 777, 1063, 1150, 1226.
+\I\\{left\_brace\_limit}, \[289], 325, 392, 394, 399.
+\I\\{left\_brace\_token}, \[289], 403, 1127, 1226, 1371.
+\I\\{left\_delimiter}, \[683], 696, 697, 737, 748, 1163, 1181, 1182.
+\I\\{left\_edge}, \[619], 627, \[629], 632, 637.
+\I\\{left\_hyphen\_min}, \[236], 1091, 1200, 1376, 1377.
+\I\9{left_hyphen_min_}{\.{\\lefthyphenmin} primitive}, \[238].
+\I\\{left\_hyphen\_min\_code}, \[236], 237, 238.
+\I\\{left\_noad}, \[687], 690, 696, 698, 725, 728, 733, 760, 761, 762, 1185, 1188, 1189, 1191.
+\I\\{left\_right}, \[208], 1046, 1188, 1189, 1190.
+\I\\{left\_skip}, \[224], 827, 880, 887.
+\I\9{left_skip_}{\.{\\leftskip} primitive}, \[226].
+\I\\{left\_skip\_code}, \[224], 225, 226, 887.
+\I\\{length}, \[40], 46, 259, 537, 602, 931, 941, 1280.
+\I{length of lines}, 847.
+\I\9{leq_no_}{\.{\\leqno} primitive}, \[1141].
+\I\\{let}, \[209], 1210, 1219, 1220, 1221.
+\I\9{let_}{\.{\\let} primitive}, \[1219].
+\I\\{letter}, \[207], 232, 262, 289, 291, 294, 298, 347, 354, 356, 935, 961, 1029, 1030, 1038, 1090, 1124, 1151, 1154, 1160.
+\I\\{letter\_token}, \[289], 445.
+\I\\{level}, 410, \[413], 415, 418, 428, \[461].
+\I\\{level\_boundary}, \[268], 270, 274, 282.
+\I\\{level\_one}, \[221], 228, 232, 254, 264, 272, 277, 278, 279, 280, 281, 283, 780, 1304, 1335, 1369.
+\I\\{level\_zero}, \[221], 222, 272, 276, 280.
+\I\\{lf}, 540, \[560], 565, 566, 575, 576.
+\I\\{lft\_hit}, 906, \[907], 908, 910, 911, 1033, 1035, 1040.
+\I\\{lh}, 110, \[113], 114, 118, 213, 219, 256, 540, 541, \[560], 565, 566, 568, 685, 950.
+\I{Liang, Franklin Mark}, 2, 919.
+\I\\{lig\_char}, \[143], 144, 193, 206, 652, 841, 842, 866, 870, 871, 898, 903, 1113.
+\I\\{lig\_kern}, 544, 545, 549.
+\I\\{lig\_kern\_base}, \[550], 552, 557, 566, 571, 573, 576, 1322, 1323.
+\I\\{lig\_kern\_base0}, \[550].
+\I\\{lig\_kern\_command}, 541, \[545].
+\I\\{lig\_kern\_restart}, \[557], 741, 752, 909, 1039.
+\I\\{lig\_kern\_restart\_end}, \[557].
+\I\\{lig\_kern\_start}, \[557], 741, 752, 909, 1039.
+\I\\{lig\_ptr}, \[143], 144, 175, 193, 202, 206, 896, 898, 903, 907, 910, 911, 1037, 1040.
+\I\\{lig\_stack}, \[907], 908, 910, 911, 1032, 1034, 1035, 1036, 1037, 1038, 1040.
+\I\\{lig\_tag}, \[544], 569, 741, 752, 909, 1039.
+\I\\{lig\_trick}, \[162], 652.
+\I\\{ligature\_node}, \[143], 144, 148, 175, 183, 202, 206, 622, 651, 752, 841, 842, 866, 870, 871, 896, 897, 899, 903, 1113, 1121, 1147.
+\I\\{ligature\_present}, 906, \[907], 908, 910, 911, 1033, 1035, 1037, 1040.
+\I\\{limit}, 300, \[302], 303, 307, 318, 328, 330, 331, 343, 348, 350, 351, 352, 354, 355, 356, 360, 362, 363, 483, 537, 538, 1337.
+\I\.{Limit controls must follow...}, 1159.
+\I\\{limit\_field}, 35, 87, \[300], 302, 534.
+\I\\{limit\_switch}, \[208], 1046, 1156, 1157, 1158.
+\I\\{limits}, \[682], 696, 733, 749, 1156, 1157.
+\I\9{limits_}{\.{\\limits} primitive}, \[1156].
+\I\\{line}, 84, 216, \[304], 313, 328, 329, 331, 362, 424, 494, 495, 538, 663, 675, 1025.
+\I\\{line\_break}, 162, 814, \[815], 828, 839, 848, 862, 863, 866, 876, 894, 934, 967, 970, 982, 1096, 1145.
+\I\\{line\_diff}, \[872], 875.
+\I\\{line\_number}, \[819], 820, 833, 835, 845, 846, 850, 864, 872, 874, 875.
+\I\\{line\_penalty}, \[236], 859.
+\I\9{line_penalty_}{\.{\\linepenalty} primitive}, \[238].
+\I\\{line\_penalty\_code}, \[236], 237, 238.
+\I\\{line\_skip}, \[224], 247.
+\I\9{line_skip_}{\.{\\lineskip} primitive}, \[226].
+\I\\{line\_skip\_code}, 149, 152, \[224], 225, 226, 679.
+\I\\{line\_skip\_limit}, \[247], 679.
+\I\9{line_skip_limit_}{\.{\\lineskiplimit} primitive}, \[248].
+\I\\{line\_skip\_limit\_code}, \[247], 248.
+\I\\{line\_stack}, \[304], 328, 329.
+\I\\{line\_stack0}, \[304].
+\I\\{line\_width}, \[830], 850, 851.
+\I\\{link}, \[118], 120, 121, 122, 123, 124, 125, 126, 130, 133, 134, 135, 140, 143, 150, 164, 168, 172, 174, 175, 176, 182, 202, 204, 212, 214, 218, 223, 233, 292, 295, 306, 319, 323, 339, 357, 358, 366, 369, 371, 374, 389, 390, 391, 394, 396, 397, 400,
+407, 452, 464, 466, 467, 470, 478, 489, 495, 496, 497, 508, 605, 607, 609, 611, 615, 620, 622, 630, 649, 651, 652, 654, 655, 666, 669, 679, 681, 689, 705, 711, 715, 718, 719, 720, 721, 727, 731, 732, 735, 737, 738, 739, 747, 748, 751, 752, 753, 754, 755,
+756, 759, 760, 761, 766, 767, 770, 772, 778, 779, 783, 784, 786, 790, 791, 793, 794, 795, 796, 797, 798, 799, 801, 802, 803, 804, 805, 806, 807, 808, 809, 812, 814, 816, 819, 821, 822, 829, 830, 837, 840, 843, 844, 845, 854, 857, 858, 860, 861, 862, 863,
+864, 865, 866, 867, 869, 873, 874, 875, 877, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 890, 894, 896, 897, 898, 899, 903, 905, 906, 907, 908, 910, 911, 913, 914, 915, 916, 917, 918, 932, 938, 960, 968, 969, 970, 973, 979, 980, 981, 986, 988, 991,
+994, 998, 999, 1000, 1001, 1005, 1008, 1009, 1014, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1026, 1035, 1036, 1037, 1040, 1041, 1043, 1064, 1065, 1076, 1081, 1086, 1091, 1100, 1101, 1105, 1110, 1119, 1120, 1121, 1123, 1125, 1146, 1155, 1168, 1181, 1184,
+1185, 1186, 1187, 1191, 1194, 1196, 1199, 1204, 1205, 1206, 1226, 1279, 1288, 1297, 1311, 1312, 1335, 1339, 1341, 1349, 1368, 1371, 1375.
+\I\\{list\_offset}, \[135], 649, 769, 1018.
+\I\\{list\_ptr}, \[135], 136, 184, 202, 206, 619, 623, 629, 632, 658, 663, 664, 668, 673, 676, 709, 711, 715, 721, 739, 747, 751, 807, 977, 979, 1021, 1087, 1100, 1110, 1146, 1199.
+\I\&{list\_state\_record}, \[212], 213.
+\I\\{list\_tag}, \[544], 569, 570, 708, 740, 749.
+\I\\{ll}, \[953], 956.
+\I\\{llink}, \[124], 126, 127, 129, 130, 131, 145, 149, 164, 169, 772, 819, 821, 1312.
+\I\\{lo\_mem\_max}, \[116], 120, 125, 126, 164, 165, 167, 169, 170, 171, 172, 178, 639, 1311, 1312, 1323, 1334.
+\I\\{lo\_mem\_stat\_max}, \[162], 164, 1312.
+\I\\{load\_fmt\_file}, \[1303], 1337.
+\I\\{loc}, \[36], 37, 87, 300, 302, 303, 307, 312, 314, 318, 319, 323, 325, 328, 330, 331, 343, 348, 350, 351, 352, 354, 356, 357, 358, 360, 362, 369, 390, 483, 523, 537, 538, 1026, 1027, 1337.
+\I\\{loc\_field}, 35, 36, \[300], 302, 1131.
+\I\\{local\_base}, 220, \[224], 228, 230, 252.
+\I\\{location}, \[605], 607, 612, 613, 614, 615.
+\I\\{log\_file}, \[54], 56, 75, 534, 1333.
+\I\\{log\_name}, \[532], 534, 1333.
+\I\\{log\_only}, \[54], 57, 58, 62, 75, 98, 360, 534, 1328, 1370.
+\I\\{log\_opened}, 92, 93, \[526], 527, 534, 535, 1265, 1333, 1334.
+\I\9{long_}{\.{\\long} primitive}, \[1208].
+\I\\{long\_call}, \[210], 275, 366, 387, 389, 392, 399, 1295.
+\I\\{long\_help\_seen}, \[1281], 1282, 1283.
+\I\\{long\_outer\_call}, \[210], 275, 366, 387, 389, 1295.
+\I\\{long\_state}, 339, \[387], 391, 392, 395, 396, 399.
+\I\&{loop}, 15, \[16], 37, 53, 69, 83, 259, 282, 311, 397, 399, 445, 452, 474, 477, 478, 483, 494, 497, 500, 525, 530, 537, 706, 740, 741, 752, 777, 783, 784, 829, 863, 879, 896, 897, 899, 909, 930, 935, 944, 948, 953, 961, 965, 970, 979, 1270, 1338.
+\I\.{Loose \\hbox...}, 660.
+\I\.{Loose \\vbox...}, 674.
+\I\\{loose\_fit}, \[817], 834, 852.
+\I\\{looseness}, \[236], 848, 873, 875, 1070.
+\I\9{looseness_}{\.{\\looseness} primitive}, \[238].
+\I\\{looseness\_code}, \[236], 237, 238, 1070.
+\I\9{lower_}{\.{\\lower} primitive}, \[1071].
+\I\9{lowercase_}{\.{\\lowercase} primitive}, \[1286].
+\I\\{lq}, \[592], 627, 636.
+\I\\{lr}, \[592], 627, 636.
+\I\\{lx}, \[619], 626, 627, 628, \[629], 635, 636, 637.
+\I\|{m}, \[47], \[65], \[158], \[211], \[218], \[292], \[315], \[389], \[413], \[440], \[482], \[498], \[577], \[649], \[668], \[706], \[716], \[717], \[1079], \[1105], \[1194], \[1338].
+\I\\{mac\_param}, \[207], 291, 294, 298, 347, 474, 477, 479, 783, 784, 1045.
+\I\\{macro}, \[307], 314, 319, 323, 324, 390.
+\I\\{macro\_call}, 291, 366, 380, 382, 387, 388, \[389], 391.
+\I\\{macro\_def}, \[473], 477.
+\I\\{mag}, \[236], 240, 288, 457, 585, \[587], 588, 590, 617, 642.
+\I\9{mag_}{\.{\\mag} primitive}, \[238].
+\I\\{mag\_code}, \[236], 237, 238, 288.
+\I\\{mag\_set}, \[286], 287, 288.
+\I\\{magic\_offset}, \[764], 765, 766.
+\I\\{main}, \[1332].
+\I\\{main\_control}, 1029, \[1030], 1032, 1040, 1041, 1052, 1054, 1055, 1056, 1057, 1126, 1134, 1208, 1290, 1332, 1337, 1344, 1347.
+\I\\{main\_f}, \[1032], 1034, 1035, 1036, 1037, 1038, 1039, 1040.
+\I\\{main\_i}, \[1032], 1036, 1037, 1039, 1040.
+\I\\{main\_j}, \[1032], 1039, 1040.
+\I\\{main\_k}, \[1032], 1034, 1039, 1040, 1042.
+\I\\{main\_lig\_loop}, \[1034], 1037, 1038, 1040.
+\I\\{main\_lig\_loop1}, 1034, \[1039], 1040.
+\I\\{main\_lig\_loop2}, \[1039].
+\I\\{main\_loop}, \[1030].
+\I\\{main\_loop\_lookahead}, \[1034], 1036, 1037.
+\I\\{main\_loop\_lookahead1}, \[1038].
+\I\\{main\_loop\_move}, \[1034], 1040.
+\I\\{main\_loop\_move\_lig}, \[1034], 1036, 1037.
+\I\\{main\_loop\_move1}, \[1036], 1040.
+\I\\{main\_loop\_move2}, 1034, \[1036].
+\I\\{main\_loop\_wrapup}, \[1034], 1039, 1040.
+\I\\{main\_p}, \[1032], 1035, 1037, 1040, 1041, 1042, 1043, 1044.
+\I\\{main\_s}, \[1032], 1034.
+\I\\{major\_tail}, \[912], 914, 917, 918.
+\I\\{make\_accent}, 1122, \[1123].
+\I\\{make\_box}, \[208], 1071, 1072, 1073, 1079, 1084.
+\I\\{make\_fraction}, 733, 734, \[743].
+\I\\{make\_left\_right}, 761, \[762].
+\I\\{make\_mark}, 1097, \[1101].
+\I\\{make\_math\_accent}, 733, \[738].
+\I\\{make\_name\_string}, \[524].
+\I\\{make\_op}, 733, \[749].
+\I\\{make\_ord}, 733, \[752].
+\I\\{make\_over}, 733, \[734].
+\I\\{make\_radical}, 733, 734, \[737].
+\I\\{make\_scripts}, 754, \[756].
+\I\\{make\_string}, \[43], 48, 52, 260, 517, 524, 939, 1257, 1279, 1328, 1333.
+\I\\{make\_under}, 733, \[735].
+\I\\{make\_vcenter}, 733, \[736].
+\I\\{mark}, \[208], 265, 266, 1097.
+\I\9{mark_}{\.{\\mark} primitive}, \[265].
+\I\\{mark\_node}, \[141], 148, 175, 183, 202, 206, 647, 651, 730, 761, 866, 899, 968, 973, 979, 1000, 1014, 1101.
+\I\\{mark\_ptr}, \[141], 142, 196, 202, 206, 979, 1016, 1101.
+\I\\{mark\_text}, \[307], 314, 323, 386.
+\I{mastication}, 341.
+\I\\{match}, \[207], 289, 291, 292, 294, 391, 392.
+\I\\{match\_chr}, \[292], 294, \[389], 391, 400.
+\I\\{match\_token}, \[289], 391, 392, 393, 394, 476.
+\I\\{matching}, \[305], 306, 339, 391.
+\I\.{Math formula deleted...}, 1195.
+\I\\{math\_ac}, 1164, \[1165].
+\I\\{math\_accent}, \[208], 265, 266, 1046, 1164.
+\I\9{math_accent_}{\.{\\mathaccent} primitive}, \[265].
+\I\9{math_bin_}{\.{\\mathbin} primitive}, \[1156].
+\I\\{math\_char}, \[681], 692, 720, 722, 724, 738, 741, 749, 752, 753, 754, 1151, 1155, 1165.
+\I\9{math_char_}{\.{\\mathchar} primitive}, \[265].
+\I\9{math_char_def_}{\.{\\mathchardef} primitive}, \[1222].
+\I\\{math\_char\_def\_code}, \[1222], 1223, 1224.
+\I\\{math\_char\_num}, \[208], 265, 266, 1046, 1151, 1154.
+\I\\{math\_choice}, \[208], 265, 266, 1046, 1171.
+\I\9{math_choice_}{\.{\\mathchoice} primitive}, \[265].
+\I\\{math\_choice\_group}, \[269], 1172, 1173, 1174.
+\I\9{math_close_}{\.{\\mathclose} primitive}, \[1156].
+\I\\{math\_code}, \[230], 232, 236, 414, 1151, 1154.
+\I\9{math_code_}{\.{\\mathcode} primitive}, \[1230].
+\I\\{math\_code\_base}, \[230], 235, 414, 1230, 1231, 1232, 1233.
+\I\\{math\_comp}, \[208], 1046, 1156, 1157, 1158.
+\I\\{math\_font\_base}, \[230], 232, 234, 1230, 1231.
+\I\\{math\_fraction}, 1180, \[1181].
+\I\\{math\_given}, \[208], 413, 1046, 1151, 1154, 1222, 1223, 1224.
+\I\\{math\_glue}, \[716], 732, 766.
+\I\\{math\_group}, \[269], 1136, 1150, 1153, 1186.
+\I\9{math_inner_}{\.{\\mathinner} primitive}, \[1156].
+\I\\{math\_kern}, \[717], 730.
+\I\\{math\_left\_group}, \[269], 1065, 1068, 1069, 1150, 1191.
+\I\\{math\_left\_right}, 1190, \[1191].
+\I\\{math\_limit\_switch}, 1158, \[1159].
+\I\\{math\_node}, \[147], 148, 175, 183, 202, 206, 622, 651, 817, 837, 866, 879, 881, 1147.
+\I\9{math_op_}{\.{\\mathop} primitive}, \[1156].
+\I\9{math_open_}{\.{\\mathopen} primitive}, \[1156].
+\I\9{math_ord_}{\.{\\mathord} primitive}, \[1156].
+\I\9{math_punct_}{\.{\\mathpunct} primitive}, \[1156].
+\I\\{math\_quad}, \[700], 703, 1199.
+\I\\{math\_radical}, 1162, \[1163].
+\I\9{math_rel_}{\.{\\mathrel} primitive}, \[1156].
+\I\\{math\_shift}, \[207], 289, 294, 298, 347, 1090, 1137, 1138, 1193, 1197, 1206.
+\I\\{math\_shift\_group}, \[269], 1065, 1068, 1069, 1130, 1139, 1140, 1142, 1145, 1192, 1193, 1194, 1200.
+\I\\{math\_shift\_token}, \[289], 1047, 1065.
+\I\\{math\_spacing}, 765, \[1667].
+\I\\{math\_spacing\_str}, \[764].
+\I\\{math\_style}, \[208], 1046, 1169, 1170, 1171.
+\I\\{math\_surround}, \[247], 1196.
+\I\9{math_surround_}{\.{\\mathsurround} primitive}, \[248].
+\I\\{math\_surround\_code}, \[247], 248.
+\I\\{math\_text\_char}, \[681], 752, 753, 754, 755.
+\I\\{math\_type}, \[681], 683, 687, 692, 698, 720, 722, 723, 734, 735, 737, 738, 741, 742, 749, 751, 752, 753, 754, 755, 756, 1076, 1093, 1151, 1155, 1165, 1168, 1176, 1181, 1185, 1186, 1191.
+\I\\{math\_x\_height}, \[700], 737, 757, 758, 759.
+\I\\{mathex}, \[701].
+\I\\{mathsy}, \[700].
+\I\\{mathsy\_end}, \[700].
+\I\\{max\_answer}, \[105].
+\I\\{max\_buf\_stack}, \[30], 31, 331, 374, 1334.
+\I\\{max\_char\_code}, \[207], 303, 344, 1233.
+\I\\{max\_command}, \[209], 210, 211, 219, 358, 366, 368, 380, 381, 478, 782.
+\I\\{max\_d}, \[726], 727, 730, 760, 761, \[762].
+\I\\{max\_dead\_cycles}, \[236], 240, 1012.
+\I\9{max_dead_cycles_}{\.{\\maxdeadcycles} primitive}, \[238].
+\I\\{max\_dead\_cycles\_code}, \[236], 237, 238.
+\I\\{max\_depth}, \[247], 980, 987.
+\I\9{max_depth_}{\.{\\maxdepth} primitive}, \[248].
+\I\\{max\_depth\_code}, \[247], 248.
+\I\\{max\_dimen}, \[421], 460, 641, 668, 1010, 1017, 1145, 1146, 1148.
+\I\\{max\_group\_code}, \[269].
+\I\\{max\_h}, \[592], 593, 641, 642, \[726], 727, 730, 760, 761, \[762].
+\I\\{max\_halfword}, 11, 14, \[110], 111, 124, 125, 126, 131, 132, 289, 290, 424, 820, 848, 850, 982, 991, 996, 1017, 1106, 1249, 1323, 1325, 1335.
+\I\\{max\_in\_open}, \[11], 14, 304, 328.
+\I\\{max\_in\_stack}, \[301], 321, 331, 1334.
+\I\\{max\_internal}, \[209], 413, 440, 448, 455, 461.
+\I\\{max\_nest\_stack}, \[213], 215, 216, 1334.
+\I\\{max\_non\_prefixed\_command}, \[208], 1211, 1270.
+\I\\{max\_param\_stack}, \[308], 331, 390, 1334.
+\I\\{max\_print\_line}, \[11], 14, 58, 61, 72, 176, 537, 638, 1280.
+\I\\{max\_push}, \[592], 593, 619, 629, 642.
+\I\\{max\_quarterword}, 11, \[110], 111, 274, 797, 798, 944, 1120, 1325.
+\I\\{max\_save\_stack}, \[271], 272, 273, 1334.
+\I\\{max\_selector}, \[54].
+\I\\{max\_strings}, \[11], 39, 43, 111, 517, 524, 1310, 1334.
+\I\\{max\_v}, \[592], 593, 641, 642.
+\I\9{meaning_}{\.{\\meaning} primitive}, \[468].
+\I\\{meaning\_code}, \[468], 469, 471, 472.
+\I\\{med\_mu\_skip}, \[224].
+\I\9{med_mu_skip_}{\.{\\medmuskip} primitive}, \[226].
+\I\\{med\_mu\_skip\_code}, \[224], 225, 226, 766.
+\I\\{mem}, 11, 12, 115, \[116], 118, 124, 126, 131, 133, 134, 135, 140, 141, 150, 151, 157, 159, 162, 163, 164, 165, 167, 172, 182, 186, 203, 205, 206, 221, 224, 275, 291, 387, 420, 489, 605, 652, 680, 681, 683, 686, 687, 720, 725, 742, 753, 769, 770,
+772, 797, 816, 818, 819, 822, 823, 832, 843, 844, 847, 848, 850, 860, 861, 889, 925, 1149, 1151, 1160, 1163, 1165, 1181, 1186, 1247, 1248, 1311, 1312, 1339.
+\I\\{mem\_bot}, 11, \[12], 14, 111, 116, 125, 126, 162, 164, 1307, 1308, 1311, 1312.
+\I\\{mem\_end}, 116, \[118], 120, 164, 165, 167, 168, 171, 172, 174, 176, 182, 293, 1311, 1312, 1334.
+\I\\{mem\_max}, \[11], 12, 14, 110, 111, 116, 120, 124, 125, 165, 166.
+\I\\{mem\_min}, \[11], 12, 111, 116, 120, 125, 165, 166, 167, 169, 170, 171, 172, 174, 178, 182, 1249, 1312, 1334.
+\I\\{mem\_top}, 11, \[12], 14, 111, 116, 162, 164, 1249, 1307, 1308, 1312.
+\I\.{Memory usage...}, 639.
+\I\&{memory\_word}, 110, \[113], 114, 116, 182, 212, 218, 221, 253, 268, 271, 275, 548, 549, 800, 1305.
+\I\\{mem0}, \[116].
+\I\\{message}, \[208], 1276, 1277, 1278.
+\I\9{message_}{\.{\\message} primitive}, \[1277].
+\I\9{METAFONT}{\MF}, 589.
+\I\\{mid}, \[546].
+\I\\{mid\_line}, 87, \[303], 328, 344, 347, 352, 353, 354.
+\I\\{min\_halfword}, 11, \[110], 111, 112, 115, 230, 1027, 1323, 1325.
+\I\\{min\_internal}, \[208], 413, 440, 448, 455, 461.
+\I\\{min\_quarterword}, 12, \[110], 111, 112, 134, 136, 140, 185, 221, 274, 550, 554, 556, 557, 566, 576, 649, 668, 685, 697, 707, 713, 714, 796, 801, 803, 808, 920, 923, 924, 943, 944, 945, 946, 958, 963, 964, 965, 1323, 1324, 1325.
+\I\\{minimal\_demerits}, \[833], 834, 836, 845, 855.
+\I\\{minimal\_demerits0}, \[833].
+\I\\{minimum\_demerits}, \[833], 834, 835, 836, 854, 855.
+\I\\{minor\_tail}, \[912], 915, 916.
+\I\.{minus}, 462.
+\I\.{Misplaced \&}, 1128.
+\I\.{Misplaced \\cr}, 1128.
+\I\.{Misplaced \\noalign}, 1129.
+\I\.{Misplaced \\omit}, 1129.
+\I\.{Misplaced \\span}, 1128.
+\I\.{Missing = inserted}, 503.
+\I\.{Missing \# inserted...}, 783.
+\I\.{Missing \$ inserted}, 1047, 1065.
+\I\.{Missing \\cr inserted}, 1132.
+\I\.{Missing \\endcsname...}, 373.
+\I\.{Missing \\endgroup inserted}, 1065.
+\I\.{Missing \\right\hbox{.} inserted}, 1065.
+\I\.{Missing \{ inserted}, 403, 475, 1127.
+\I\.{Missing \} inserted}, 1065, 1127.
+\I\.{Missing `to' inserted}, 1082.
+\I\.{Missing `to'...}, 1225.
+\I\.{Missing {\$\$} inserted}, 1207.
+\I\.{Missing character}, 581.
+\I\.{Missing control...}, 1215.
+\I\.{Missing delimiter...}, 1161.
+\I\.{Missing font identifier}, 577.
+\I\.{Missing number...}, 415, 446.
+\I\\{mkern}, \[208], 1046, 1057, 1058, 1059.
+\I\9{mkern_}{\.{\\mkern} primitive}, \[1058].
+\I\\{ml\_field}, \[212], 213, 218.
+\I\\{mlist}, \[726], 760.
+\I\\{mlist\_penalties}, \[719], 720, 726, 754, 1194, 1196, 1199.
+\I\\{mlist\_to\_hlist}, 693, 719, \[720], 725, \[726], 734, 754, 760, 1194, 1196, 1199.
+\I\.{mm}, 458.
+\I\\{mmode}, \[211], 501, 718, 775, 776, 800, 812, 1030, 1045, 1046, 1048, 1056, 1057, 1073, 1080, 1092, 1097, 1109, 1110, 1112, 1116, 1120, 1130, 1136, 1140, 1145, 1150, 1154, 1158, 1162, 1164, 1167, 1171, 1175, 1180, 1190, 1193, 1194.
+\I\\{mode}, 56, 211, 212, \[213], 215, 216, 299, 418, 422, 424, 501, 718, 775, 776, 785, 786, 787, 796, 799, 804, 807, 808, 809, 812, 1025, 1029, 1030, 1034, 1035, 1049, 1051, 1056, 1076, 1078, 1080, 1083, 1086, 1091, 1093, 1094, 1095, 1096, 1099, 1103,
+1105, 1110, 1117, 1119, 1120, 1136, 1138, 1145, 1167, 1194, 1196, 1200, 1243, 1370, 1371, 1377.
+\I\\{mode\_field}, \[212], 213, 218, 422, 800, 1244.
+\I\\{mode\_line}, 212, \[213], 215, 216, 304, 804, 815, 1025.
+\I\\{month}, \[236], 241, 536, 617, 1328.
+\I\9{month_}{\.{\\month} primitive}, \[238].
+\I\\{month\_code}, \[236], 237, 238.
+\I\\{months}, \[534], 536.
+\I\\{more\_name}, 512, \[516], 525, 530.
+\I\9{move_left_}{\.{\\moveleft} primitive}, \[1071].
+\I\\{move\_past}, \[622], 625, \[631], 634.
+\I\9{move_right_}{\.{\\moveright} primitive}, \[1071].
+\I\\{movement}, \[607], 609, 616.
+\I\\{movement\_node\_size}, \[605], 607, 615.
+\I\\{mskip}, \[208], 1046, 1057, 1058, 1059.
+\I\9{mskip_}{\.{\\mskip} primitive}, \[1058].
+\I\\{mskip\_code}, \[1058], 1060.
+\I\\{mstate}, \[607], 611, 612.
+\I\\{mu}, 447, \[448], 449, 453, 455, \[461], 462.
+\I\.{mu}, 456.
+\I\\{mu\_error}, \[408], 429, 449, 455, 461.
+\I\\{mu\_glue}, \[149], 155, 191, 424, 717, 732, 1058, 1060, 1061.
+\I\\{mu\_mult}, \[716], 717.
+\I\\{mu\_skip}, \[224], 427.
+\I\9{mu_skip_}{\.{\\muskip} primitive}, \[411].
+\I\\{mu\_skip\_base}, \[224], 227, 229, 1224, 1237.
+\I\9{mu_skip_def_}{\.{\\muskipdef} primitive}, \[1222].
+\I\\{mu\_skip\_def\_code}, \[1222], 1223, 1224.
+\I\\{mu\_val}, \[410], 411, 413, 424, 427, 429, 430, 449, 451, 455, 461, 465, 1060, 1228, 1237.
+\I\\{mult\_and\_add}, \[105].
+\I\\{mult\_integers}, \[105], 1240.
+\I\\{multiply}, \[209], 265, 266, 1210, 1235, 1236, 1240.
+\I\9{multiply_}{\.{\\multiply} primitive}, \[265].
+\I\\{must}, 9.
+\I\.{Must increase the x}, 1303.
+\I\|{n}, \[47], \[65], \[66], \[67], \[69], \[91], \[94], \[105], \[106], \[107], \[152], \[154], \[174], \[182], \[225], \[237], \[247], \[252], \[292], \[315], \[389], \[482], \[498], \[518], \[519], \[522], \[578], \[706], \[716], \[717], \[791], %
+\[800], \[906], \[934], \[944], \[977], \[992], \[993], \[994], \[1012], \[1079], \[1119], \[1138], \[1211], \[1275], \[1338].
+\I\\{name}, 56, 300, \[302], 303, 304, 307, 311, 313, 314, 323, 328, 329, 331, 337, 360, 390, 483, 537.
+\I\\{name\_field}, 84, \[300], 302.
+\I\\{name\_in\_progress}, 378, 525, \[526], 527, 1258.
+\I\\{name\_length}, \[26], 51, 519, 522, 524.
+\I\\{name\_of\_file}, \[26], 27, 51, 519, 522, 524, 529.
+\I\\{name\_of\_file0}, \[26].
+\I\\{natural}, \[644], 705, 715, 720, 727, 735, 737, 738, 748, 754, 756, 759, 796, 799, 806, 977, 1021, 1100, 1125, 1194, 1199, 1204.
+\I\\{nd}, 540, 541, \[560], 565, 566, 569.
+\I\\{ne}, 540, 541, \[560], 565, 566, 569.
+\I\\{negate}, \[16], 65, 103, 105, 106, 107, 430, 431, 440, 448, 461, 775.
+\I\\{negative}, \[106], \[413], 430, \[440], 441, \[448], \[461].
+\I\\{nest}, 212, \[213], 216, 217, 218, 219, 413, 422, 775, 800, 995, 1244.
+\I\\{nest\_ptr}, \[213], 215, 216, 217, 218, 422, 775, 800, 995, 1017, 1023, 1091, 1100, 1145, 1200, 1244.
+\I\\{nest\_size}, \[11], 213, 216, 1334.
+\I\\{new\_character}, \[582], 755, 915, 1117, 1123, 1124.
+\I\\{new\_choice}, \[689], 1172.
+\I\\{new\_delta\_from\_break\_width}, \[844].
+\I\\{new\_delta\_to\_break\_width}, \[843].
+\I\\{new\_disc}, \[145], 1035, 1117.
+\I\\{new\_font}, 1256, \[1257].
+\I\\{new\_glue}, \[153], 154, 715, 766, 786, 793, 795, 809, 1041, 1043, 1054, 1060, 1171.
+\I\\{new\_graf}, 1090, \[1091].
+\I\\{new\_hlist}, \[725], 727, 743, 748, 749, 750, 754, 756, 762, 767.
+\I\\{new\_hyph\_exceptions}, \[934], 1252.
+\I\\{new\_interaction}, 1264, \[1265].
+\I\\{new\_kern}, \[156], 705, 715, 735, 738, 739, 747, 751, 753, 755, 759, 910, 1040, 1061, 1112, 1113, 1125, 1204.
+\I\\{new\_lig\_item}, \[144], 911, 1040.
+\I\\{new\_ligature}, \[144], 910, 1035.
+\I\\{new\_line}, \[303], 331, 343, 344, 345, 347, 483, 537.
+\I\\{new\_line\_char}, 59, \[236], 244.
+\I\9{new_line_char_}{\.{\\newlinechar} primitive}, \[238].
+\I\\{new\_line\_char\_code}, \[236], 237, 238.
+\I\\{new\_math}, \[147], 1196.
+\I\\{new\_noad}, \[686], 720, 742, 753, 1076, 1093, 1150, 1155, 1158, 1168, 1177, 1191.
+\I\\{new\_null\_box}, \[136], 706, 709, 713, 720, 747, 750, 779, 793, 809, 1018, 1054, 1091, 1093.
+\I\\{new\_param\_glue}, \[152], 154, 679, 778, 816, 886, 887, 1041, 1043, 1091, 1203, 1205, 1206.
+\I\\{new\_patterns}, \[960], 1252.
+\I\\{new\_penalty}, \[158], 767, 816, 890, 1054, 1103, 1203, 1205, 1206.
+\I\\{new\_rule}, \[139], 463, 666, 704.
+\I\\{new\_save\_level}, \[274], 645, 774, 785, 791, 1025, 1063, 1099, 1117, 1119, 1136.
+\I\\{new\_skip\_param}, \[154], 679, 969, 1001.
+\I\\{new\_spec}, \[151], 154, 430, 462, 826, 976, 1004, 1042, 1043, 1239, 1240.
+\I\\{new\_string}, \[54], 57, 58, 465, 470, 617, 1257, 1279, 1328, 1368.
+\I\\{new\_style}, \[688], 1171.
+\I\\{new\_trie\_op}, 943, \[944], 945, 965.
+\I\\{new\_whatsit}, \[1349], 1350, 1354, 1376, 1377.
+\I\\{new\_write\_whatsit}, \[1350], 1351, 1352, 1353.
+\I\\{next}, \[256], 257, 259, 260.
+\I\\{next\_break}, \[877], 878.
+\I\\{next\_char}, \[545], 741, 753, 909, 1039.
+\I\\{next\_p}, \[622], 626, \[630], 631, 633, 635.
+\I\\{nh}, 540, 541, \[560], 565, 566, 569.
+\I\\{ni}, 540, 541, \[560], 565, 566, 569.
+\I\\{nk}, 540, 541, \[560], 565, 566, 573.
+\I\\{nl}, \[59], 540, 541, 545, \[560], 565, 566, 569, 573, 576.
+\I\\{nn}, \[311], 312.
+\I\.{No pages of output}, 642.
+\I\\{no\_align}, \[208], 265, 266, 785, 1126.
+\I\9{no_align_}{\.{\\noalign} primitive}, \[265].
+\I\\{no\_align\_error}, 1126, \[1129].
+\I\\{no\_align\_group}, \[269], 768, 785, 1133.
+\I\\{no\_boundary}, \[208], 265, 266, 1030, 1038, 1045, 1090.
+\I\9{no_boundary_}{\.{\\noboundary} primitive}, \[265].
+\I\\{no\_break\_yet}, \[829], 836, 837.
+\I\\{no\_expand}, \[210], 265, 266, 366, 367.
+\I\9{no_expand_}{\.{\\noexpand} primitive}, \[265].
+\I\\{no\_expand\_flag}, \[358], 506.
+\I\9{no_indent_}{\.{\\noindent} primitive}, \[1088].
+\I\\{no\_limits}, \[682], 1156, 1157.
+\I\9{no_limits_}{\.{\\nolimits} primitive}, \[1156].
+\I\\{no\_new\_control\_sequence}, \[256], 257, 259, 264, 365, 374, 1336.
+\I\\{no\_print}, \[54], 57, 58, 75, 98.
+\I\\{no\_shrink\_error\_yet}, \[825], 826, 827.
+\I\\{no\_tag}, \[544], 569.
+\I\\{noad\_size}, \[681], 686, 698, 753, 761, 1186, 1187.
+\I\\{node\_list\_display}, \[180], 184, 188, 190, 195, 197.
+\I\\{node\_r\_stays\_active}, \[830], 851, 854.
+\I\\{node\_size}, \[124], 126, 127, 128, 130, 164, 169, 1311, 1312.
+\I\\{nom}, \[560], 561, 563, 576.
+\I\\{non\_address}, \[549], 552, 576, 909, 916, 1034.
+\I\\{non\_char}, \[549], 552, 576, 897, 898, 901, 908, 909, 910, 911, 915, 916, 917, 1032, 1034, 1035, 1038, 1039, 1040, 1323.
+\I\\{non\_discardable}, \[148], 879.
+\I\\{non\_math}, \[1046], \[1063], \[1144].
+\I\\{non\_script}, \[208], 265, 266, 1046, 1171.
+\I\9{non_script_}{\.{\\nonscript} primitive}, \[265], \[732].
+\I\\{none\_seen}, \[611], 612.
+\I\.{NONEXISTENT}, 262.
+\I\.{Nonletter}, 962.
+\I\\{nonnegative\_integer}, 69, 101, 107.
+\I\\{nonstop\_mode}, \[73], 86, 360, 363, 484, 1262, 1263.
+\I\9{nonstop_mode_}{\.{\\nonstopmode} primitive}, \[1262].
+\I\\{nop}, 583, 585, \[586], 588, 590.
+\I\\{norm\_min}, \[1091], 1200, 1376, 1377.
+\I\\{normal}, \[135], 136, 149, 150, 153, 155, 156, 164, 177, 186, 189, 191, 305, 331, 336, 369, 439, 448, 471, 473, 480, 482, 485, 489, 490, 507, 625, 634, 646, 650, 657, 658, 659, 660, 664, 665, 666, 667, 672, 673, 674, 676, 677, 678, 682, 686, 696,
+716, 732, 749, 777, 801, 810, 811, 825, 826, 896, 897, 899, 976, 988, 1004, 1009, 1156, 1163, 1165, 1181, 1201, 1219, 1220, 1221, 1239.
+\I\\{normal\_paragraph}, \[774], 785, 787, 1025, \[1070], 1083, 1094, 1096, 1099, 1167.
+\I\\{normalize\_selector}, \[78], \[92], 93, 94, 95, 863.
+\I\.{Not a letter}, 937.
+\I\\{not\_found}, 15, \[45], \[46], \[455], \[570], \[611], 612, \[930], 931, \[941], \[953], 955, \[972], 973, \[1146], 1365.
+\I\.{notexpanded:}, 258.
+\I\\{np}, 540, 541, \[560], 565, 566, 575, 576.
+\I\\{nucleus}, \[681], 682, 683, 686, 687, 690, 696, 698, 720, 725, 734, 735, 736, 737, 738, 741, 742, 749, 750, 752, 753, 754, 755, 1076, 1093, 1150, 1151, 1155, 1158, 1163, 1165, 1168, 1186, 1191.
+\I\\{null}, \[115], 116, 118, 120, 122, 123, 125, 126, 135, 136, 144, 145, 149, 150, 151, 152, 153, 154, 164, 168, 169, 175, 176, 182, 200, 201, 202, 204, 210, 212, 218, 219, 222, 223, 232, 233, 275, 292, 295, 306, 307, 312, 314, 325, 331, 357, 358, 371,
+374, 382, 383, 386, 390, 391, 392, 397, 400, 407, 410, 420, 423, 452, 464, 466, 473, 478, 482, 489, 490, 497, 505, 508, 549, 552, 576, 578, 582, 606, 611, 615, 619, 623, 629, 632, 648, 649, 651, 655, 658, 664, 666, 668, 673, 676, 681, 685, 689, 692, 715,
+718, 719, 720, 721, 726, 731, 732, 752, 754, 755, 756, 760, 761, 766, 767, 771, 774, 776, 777, 783, 784, 789, 790, 791, 792, 794, 796, 797, 799, 801, 804, 805, 806, 807, 812, 821, 829, 837, 840, 846, 847, 848, 850, 856, 857, 858, 859, 863, 864, 865, 867,
+869, 872, 877, 878, 879, 881, 882, 883, 884, 885, 887, 888, 889, 894, 896, 898, 903, 906, 907, 908, 910, 911, 913, 914, 915, 916, 917, 918, 928, 932, 935, 968, 969, 970, 972, 973, 977, 978, 979, 981, 991, 992, 993, 994, 998, 999, 1000, 1009, 1010, 1011,
+1012, 1014, 1015, 1016, 1017, 1018, 1020, 1021, 1022, 1023, 1026, 1027, 1028, 1030, 1032, 1035, 1036, 1037, 1038, 1040, 1042, 1043, 1070, 1074, 1075, 1076, 1079, 1080, 1081, 1083, 1087, 1091, 1105, 1110, 1121, 1123, 1124, 1131, 1136, 1139, 1145, 1146,
+1149, 1167, 1174, 1176, 1181, 1184, 1185, 1186, 1194, 1196, 1199, 1202, 1205, 1206, 1226, 1227, 1247, 1248, 1283, 1288, 1296, 1311, 1312, 1335, 1339, 1353, 1354, 1368, 1369, 1375.
+\I{null delimiter}, 240, 1065.
+\I\\{null\_character}, \[555], 556, 722, 723.
+\I\\{null\_code}, \[22], 232.
+\I\\{null\_cs}, \[222], 262, 263, 354, 374, 1257.
+\I\\{null\_delimiter}, \[684], 685, 1181.
+\I\\{null\_delimiter\_space}, \[247], 706.
+\I\9{null_delimiter_space_}{\.{\\nulldelimiterspace} primitive}, \[248].
+\I\\{null\_delimiter\_space\_code}, \[247], 248.
+\I\\{null\_flag}, \[138], 139, 463, 653, 779, 793, 801.
+\I\\{null\_font}, \[232], 552, 553, 560, 577, 617, 663, 706, 707, 722, 864, 1257, 1320, 1321, 1339.
+\I\9{null_font_}{\.{\\nullfont} primitive}, \[553].
+\I\\{null\_list}, 14, \[162], 380, 780.
+\I\\{num}, \[450], 458, 585, \[587], 590.
+\I\\{num\_style}, \[702], 744.
+\I\.{Number too big}, 445.
+\I\9{number_}{\.{\\number} primitive}, \[468].
+\I\\{number\_code}, \[468], 469, 471, 472.
+\I\\{numerator}, \[683], 690, 697, 698, 744, 1181, 1185.
+\I\\{num1}, \[700], 744.
+\I\\{num2}, \[700], 744.
+\I\\{num3}, \[700], 744.
+\I\\{nw}, 540, 541, \[560], 565, 566, 569.
+\I\\{nx\_plus\_y}, \[105], 455, 716, 1240.
+\I\|{o}, \[264], \[607], \[649], \[668], \[791], \[800].
+\I\\{octal\_token}, \[438], 444.
+\I\\{odd}, \[9], 62, 100, 193, 504, 758, 898, 902, 908, 909, 913, 914, 1211, 1218.
+\I\\{off\_save}, 1063, \[1064], 1094, 1095, 1130, 1131, 1140, 1192, 1193.
+\I\.{OK}, 1298.
+\I\\{OK\_so\_far}, \[440], 445.
+\I\\{OK\_to\_interrupt}, 88, \[96], 97, 98, 327, 1031.
+\I\\{old\_l}, \[829], 835, 850.
+\I\\{old\_mode}, \[1370], 1371.
+\I\\{old\_rover}, \[131].
+\I\\{old\_setting}, 245, \[246], \[311], 312, \[465], \[470], \[534], 617, \[638], \[1257], \[1279], \[1368], \[1370].
+\I\\{omit}, \[208], 265, 266, 788, 789, 1126.
+\I\9{omit_}{\.{\\omit} primitive}, \[265].
+\I\\{omit\_error}, 1126, \[1129].
+\I\\{omit\_template}, \[162], 789, 790.
+\I\.{Only one \# is allowed...}, 784.
+\I\\{op\_byte}, \[545], 557, 741, 753, 909, 911, 1040.
+\I\\{op\_noad}, \[682], 690, 696, 698, 726, 728, 733, 749, 761, 1156, 1157, 1159.
+\I\\{op\_start}, 920, \[921], 924, 945, 1325.
+\I\\{open\_area}, \[1341], 1351, 1356, 1374.
+\I\\{open\_ext}, \[1341], 1351, 1356, 1374.
+\I\\{open\_fmt\_file}, \[523], 1337.
+\I\9{open_in_}{\.{\\openin} primitive}, \[1272].
+\I\\{open\_log\_file}, \[78], 92, 360, 471, 531, \[534], 535, 537, 1257, 1335.
+\I\\{open\_name}, \[1341], 1351, 1356, 1374.
+\I\\{open\_noad}, \[682], 690, 696, 698, 728, 733, 761, 762, 1156, 1157.
+\I\\{open\_node}, \[1341], 1344, 1346, 1348, 1356, 1357, 1358, 1373.
+\I\\{open\_node\_size}, \[1341], 1351, 1357, 1358.
+\I\\{open\_or\_close\_in}, 1274, \[1275].
+\I\9{open_out_}{\.{\\openout} primitive}, \[1344].
+\I\\{open\_parens}, \[304], 331, 362, 537, 1335.
+\I\9{or_}{\.{\\or} primitive}, \[491].
+\I\\{or\_code}, \[489], 491, 492, 500, 509.
+\I\\{ord}, \[9], 20.
+\I\\{ord\_noad}, 681, \[682], 686, 687, 690, 696, 698, 728, 729, 733, 752, 753, 761, 764, 765, 1075, 1155, 1156, 1157, 1186.
+\I\\{order}, \[177].
+\I{oriental characters}, 134, 585.
+\I\\{other\_A\_token}, \[445].
+\I\\{other\_char}, \[207], 232, 289, 291, 294, 298, 347, 445, 464, 525, 935, 961, 1030, 1038, 1090, 1124, 1151, 1154, 1160.
+\I\\{other\_token}, \[289], 405, 438, 441, 445, 464, 503, 1065, 1221.
+\I\.{Ouch...clobbered}, 1332.
+\I\\{out\_param}, \[207], 289, 291, 294, 357.
+\I\\{out\_param\_token}, \[289], 479.
+\I\\{out\_what}, 1366, 1367, \[1373], 1375.
+\I\9{outer_}{\.{\\outer} primitive}, \[1208].
+\I\\{outer\_call}, \[210], 275, 339, 351, 353, 354, 357, 366, 387, 391, 396, 780, 1152, 1295, 1369.
+\I\\{outer\_doing\_leaders}, \[619], 628, \[629], 637.
+\I\\{output}, 4.
+\I\.{Output loop...}, 1024.
+\I\.{Output routine didn't use...}, 1028.
+\I\.{Output written on x}, 642.
+\I\9{output_}{\.{\\output} primitive}, \[230].
+\I\\{output\_active}, 421, 663, 675, 986, \[989], 990, 994, 1005, 1025, 1026.
+\I\\{output\_file\_name}, 531, \[532], 533, 642.
+\I\\{output\_group}, \[269], 1025, 1100.
+\I\\{output\_penalty}, \[236].
+\I\9{output_penalty_}{\.{\\outputpenalty} primitive}, \[238].
+\I\\{output\_penalty\_code}, \[236], 237, 238, 1013.
+\I\\{output\_routine}, \[230], 1012, 1025.
+\I\\{output\_routine\_loc}, \[230], 231, 232, 307, 323, 1226.
+\I\\{output\_text}, \[307], 314, 323, 1025, 1026.
+\I\9{over_}{\.{\\over} primitive}, \[1178].
+\I\\{over\_code}, \[1178], 1179, 1182.
+\I\\{over\_noad}, \[687], 690, 696, 698, 733, 761, 1156.
+\I\9{over_with_delims_}{\.{\\overwithdelims} primitive}, \[1178].
+\I\\{overbar}, \[705], 734, 737.
+\I\\{overflow}, 35, 42, 43, \[94], 120, 125, 216, 260, 273, 274, 321, 328, 374, 390, 517, 580, 940, 944, 954, 964, 1333.
+\I{overflow in arithmetic}, 9, 104.
+\I\.{Overfull \\hbox...}, 666.
+\I\.{Overfull \\vbox...}, 677.
+\I{overfull boxes}, 854.
+\I\\{overfull\_rule}, \[247], 666, 800, 804.
+\I\9{overfull_rule_}{\.{\\overfullrule} primitive}, \[248].
+\I\\{overfull\_rule\_code}, \[247], 248.
+\I\9{overline_}{\.{\\overline} primitive}, \[1156].
+\I\|{p}, \[120], \[123], \[125], \[130], \[131], \[136], \[139], \[144], \[145], \[147], \[151], \[152], \[153], \[154], \[156], \[158], \[167], \[172], \[174], \[176], \[178], \[182], \[198], \[200], \[201], \[202], \[204], \[218], \[259], \[262], %
+\[263], \[276], \[277], \[278], \[279], \[281], \[284], \[292], \[295], \[306], \[315], \[323], \[325], \[336], \[366], \[389], \[407], \[413], \[450], \[464], \[465], \[473], \[482], \[497], \[498], \[582], \[607], \[615], \[619], \[629], \[638], %
+\[649], \[668], \[679], \[686], \[688], \[689], \[691], \[692], \[704], \[705], \[709], \[711], \[715], \[716], \[717], \[720], \[726], \[735], \[738], \[743], \[749], \[752], \[756], \[772], \[774], \[787], \[791], \[799], \[800], \[826], \[906], %
+\[934], \[948], \[949], \[953], \[957], \[959], \[960], \[966], \[968], \[969], \[970], \[977], \[993], \[994], \[1012], \[1064], \[1068], \[1075], \[1079], \[1086], \[1093], \[1101], \[1105], \[1110], \[1113], \[1119], \[1123], \[1125], \[1138], %
+\[1151], \[1155], \[1160], \[1174], \[1176], \[1184], \[1191], \[1194], \[1211], \[1236], \[1244], \[1288], \[1293], \[1302], \[1303], \[1348], \[1349], \[1355], \[1368], \[1370], \[1373].
+\I\\{pack\_begin\_line}, \[661], 662, 663, 675, 804, 815.
+\I\\{pack\_buffered\_name}, \[522], 523.
+\I\\{pack\_cur\_name}, \[528], 529, 537, 1275, 1374.
+\I\\{pack\_file\_name}, \[519], 528, 537, 563.
+\I\\{pack\_job\_name}, \[528], 531, 534, 1328.
+\I\\{pack\_lig}, \[1035].
+\I\\{package}, 1085, \[1086].
+\I\&{packed\_ASCII\_code}, \[38], 39, 947.
+\I\\{page}, \[304].
+\I\\{page\_contents}, 421, \[980], 986, 987, 991, 1000, 1001, 1008.
+\I\\{page\_depth}, \[982], 987, 991, 1002, 1003, 1004, 1008, 1010.
+\I\9{page_depth_}{\.{\\pagedepth} primitive}, \[983].
+\I\9{page_fil_stretch_}{\.{\\pagefilstretch} primitive}, \[983].
+\I\9{page_fill_stretch_}{\.{\\pagefillstretch} primitive}, \[983].
+\I\9{page_filll_stretch_}{\.{\\pagefilllstretch} primitive}, \[983].
+\I\\{page\_goal}, 980, \[982], 986, 987, 1005, 1006, 1007, 1008, 1009, 1010.
+\I\9{page_goal_}{\.{\\pagegoal} primitive}, \[983].
+\I\\{page\_head}, \[162], 215, 980, 986, 988, 991, 1014, 1017, 1023, 1026, 1054.
+\I\\{page\_ins\_head}, \[162], 981, 986, 1005, 1008, 1018, 1019, 1020.
+\I\\{page\_ins\_node\_size}, \[981], 1009, 1019.
+\I\\{page\_loc}, \[638], 640.
+\I\\{page\_max\_depth}, \[980], 982, 987, 991, 1003, 1017.
+\I\\{page\_shrink}, \[982], 985, 1004, 1007, 1008, 1009.
+\I\9{page_shrink_}{\.{\\pageshrink} primitive}, \[983].
+\I\\{page\_so\_far}, 421, \[982], 985, 987, 1004, 1007, 1009, 1245.
+\I\\{page\_stack}, \[304].
+\I\9{page_stretch_}{\.{\\pagestretch} primitive}, \[983].
+\I\\{page\_tail}, 215, \[980], 986, 991, 998, 1000, 1017, 1023, 1026, 1054.
+\I\\{page\_total}, \[982], 985, 1002, 1003, 1004, 1007, 1008, 1010.
+\I\9{page_total_}{\.{\\pagetotal} primitive}, \[983].
+\I\\{panicking}, \[165], 166, 1031, 1339.
+\I\9{par_}{\.{\\par} primitive}, \[334].
+\I\\{par\_end}, \[207], 334, 335, 1046, 1094.
+\I\\{par\_fill\_skip}, \[224], 816.
+\I\9{par_fill_skip_}{\.{\\parfillskip} primitive}, \[226].
+\I\\{par\_fill\_skip\_code}, \[224], 225, 226, 816.
+\I\\{par\_indent}, \[247], 1091, 1093.
+\I\9{par_indent_}{\.{\\parindent} primitive}, \[248].
+\I\\{par\_indent\_code}, \[247], 248.
+\I\\{par\_loc}, \[333], 334, 351, 1313, 1314.
+\I\9{par_shape_}{\.{\\parshape} primitive}, \[265].
+\I\\{par\_shape\_loc}, \[230], 232, 233, 1070, 1248.
+\I\\{par\_shape\_ptr}, \[230], 232, 233, 423, 814, 847, 848, 850, 889, 1070, 1149, 1249.
+\I\\{par\_skip}, \[224], 1091.
+\I\9{par_skip_}{\.{\\parskip} primitive}, \[226].
+\I\\{par\_skip\_code}, \[224], 225, 226, 1091.
+\I\\{par\_token}, \[333], 334, 339, 392, 395, 399, 1095, 1314.
+\I\.{Paragraph ended before...}, 396.
+\I\\{param}, 542, 547, \[558].
+\I\\{param\_base}, \[550], 552, 558, 566, 574, 575, 576, 578, 580, 700, 701, 1042, 1322, 1323.
+\I\\{param\_base0}, \[550].
+\I\\{param\_end}, \[558].
+\I\\{param\_ptr}, \[308], 323, 324, 331, 390.
+\I\\{param\_size}, \[11], 308, 390, 1334.
+\I\\{param\_stack}, 307, \[308], 324, 359, 388, 389, 390.
+\I\\{param\_start}, \[307], 323, 324, 359.
+\I\\{parameter}, \[307], 314, 359.
+\I{parameters for symbols}, 700, 701.
+\I\.{Parameters...consecutively}, 476.
+\I\9{PASCAL H}{\ph}, \[3], 4, 9, 10, 27, 28, 33, 34.
+\I\9{PASCAL}{\PASCAL}, 1, 10, 693, 764.
+\I\\{pass\_number}, \[821], 845, 864.
+\I\\{pass\_text}, \[366], \[494], 500, 509, 510.
+\I\\{passive}, \[821], 845, 846, 864, 865.
+\I\\{passive\_node\_size}, \[821], 845, 865.
+\I\.{Patterns can be...}, 1252.
+\I\9{patterns_}{\.{\\patterns} primitive}, \[1250].
+\I\\{pause\_for\_instructions}, 96, \[98].
+\I\\{pausing}, \[236], 363.
+\I\9{pausing_}{\.{\\pausing} primitive}, \[238].
+\I\\{pausing\_code}, \[236], 237, 238.
+\I\.{pc}, 458.
+\I\\{pen}, \[726], 761, 767, \[877], 890.
+\I{penalties}, 1102.
+\I\\{penalties}, \[726], 767.
+\I\\{penalty}, \[157], 158, 194, 424, 816, 866, 973, 996, 1000, 1010, 1011, 1013.
+\I\9{penalty_}{\.{\\penalty} primitive}, \[265].
+\I\\{penalty\_node}, \[157], 158, 183, 202, 206, 424, 730, 761, 767, 816, 817, 837, 856, 866, 879, 899, 968, 973, 996, 1000, 1010, 1011, 1013, 1107.
+\I\\{pg\_field}, \[212], 213, 218, 219, 422, 1244.
+\I\\{pi}, \[829], 831, 851, 856, 859, \[970], 972, 973, 974, \[994], 1000, 1005, 1006.
+\I\.{plain}, 520, 523, 1331.
+\I{Plass, Michael Frederick}, 2, 813.
+\I\.{Please type...}, 360, 529.
+\I\.{Please use \\mathaccent...}, 1166.
+\I\.{PLtoTF}, 561.
+\I\.{plus}, 462.
+\I\\{point\_token}, \[438], 440, 448, 452.
+\I\&{pointer}, \[115], 116, 118, 120, 123, 124, 125, 130, 131, 136, 139, 144, 145, 147, 151, 152, 153, 154, 156, 158, 165, 167, 172, 198, 200, 201, 202, 204, 212, 218, 252, 256, 259, 263, 275, 276, 277, 278, 279, 281, 284, 295, 297, 305, 306, 308, 323,
+325, 333, 336, 366, 382, 388, 389, 407, 450, 461, 463, 464, 465, 473, 482, 489, 497, 498, 549, 560, 582, 592, 605, 607, 615, 619, 629, 638, 647, 649, 668, 679, 686, 688, 689, 691, 692, 704, 705, 706, 709, 711, 715, 716, 717, 719, 720, 722, 726, 734, 735,
+736, 737, 738, 743, 749, 752, 756, 762, 770, 772, 774, 787, 791, 799, 800, 814, 821, 826, 828, 829, 830, 833, 862, 872, 877, 892, 900, 901, 906, 907, 912, 926, 934, 968, 970, 977, 980, 982, 993, 994, 1012, 1032, 1043, 1064, 1068, 1074, 1075, 1079, 1086,
+1093, 1101, 1105, 1110, 1113, 1119, 1123, 1138, 1151, 1155, 1160, 1174, 1176, 1184, 1191, 1194, 1198, 1211, 1236, 1257, 1288, 1293, 1302, 1303, 1345, 1348, 1349, 1355, 1368, 1370, 1373.
+\I{Poirot, Hercule}, 1283.
+\I\\{pool\_file}, 47, \[50], 51, 52, 53.
+\I\\{pool\_name}, \[11], 51.
+\I\&{pool\_pointer}, \[38], 39, 45, 46, 59, 60, 69, 70, 264, 407, 464, 465, 470, 513, 929, 934.
+\I\\{pool\_ptr}, 38, \[39], 41, 42, 43, 44, 47, 52, 58, 70, 198, 260, 464, 465, 470, 516, 524, 617, 1309, 1310, 1332, 1334, 1339, 1368.
+\I\\{pool\_size}, \[11], 39, 42, 52, 58, 198, 524, 1310, 1334, 1339, 1368.
+\I\\{pop}, 584, 585, \[586], 590, 601, 608, 642.
+\I\\{pop\_alignment}, \[772], 800.
+\I\\{pop\_input}, \[322], 324, 329.
+\I\\{pop\_lig\_stack}, \[910], 911.
+\I\\{pop\_nest}, \[217], 796, 799, 812, 816, 1026, 1086, 1096, 1100, 1119, 1145, 1168, 1184, 1206.
+\I\\{positive}, \[107].
+\I\\{post}, 583, 585, \[586], 590, 591, 642.
+\I\\{post\_break}, \[145], 175, 195, 202, 206, 840, 858, 882, 884, 916, 1119.
+\I\\{post\_disc\_break}, \[877], 881, 884.
+\I\\{post\_display\_penalty}, \[236], 1205, 1206.
+\I\9{post_display_penalty_}{\.{\\postdisplaypenalty} primitive}, \[238].
+\I\\{post\_display\_penalty\_code}, \[236], 237, 238.
+\I\\{post\_line\_break}, 876, \[877].
+\I\\{post\_post}, 585, \[586], 590, 591, 642.
+\I\\{pre}, 583, 585, \[586], 617.
+\I\\{pre\_break}, \[145], 175, 195, 202, 206, 858, 869, 882, 885, 915, 1117, 1119.
+\I\\{pre\_display\_penalty}, \[236], 1203, 1206.
+\I\9{pre_display_penalty_}{\.{\\predisplaypenalty} primitive}, \[238].
+\I\\{pre\_display\_penalty\_code}, \[236], 237, 238.
+\I\\{pre\_display\_size}, \[247], 1138, 1145, 1148, 1203.
+\I\9{pre_display_size_}{\.{\\predisplaysize} primitive}, \[248].
+\I\\{pre\_display\_size\_code}, \[247], 248, 1145.
+\I{preamble}, 768, 774.
+\I\\{preamble}, \[770], 771, 772, 777, 786, 801, 804.
+\I{preamble of \.{DVI} file}, 617.
+\I\\{precedes\_break}, \[148], 868, 973, 1000.
+\I\\{prefix}, \[209], 1208, 1209, 1210, 1211.
+\I\\{prefixed\_command}, 1210, \[1211], 1270.
+\I\\{prepare\_mag}, \[288], 457, 617, 642, 1333.
+\I\\{pretolerance}, \[236], 828, 863.
+\I\9{pretolerance_}{\.{\\pretolerance} primitive}, \[238].
+\I\\{pretolerance\_code}, \[236], 237, 238.
+\I\\{prev\_break}, \[821], 845, 846, 877, 878.
+\I\\{prev\_depth}, 212, \[213], 215, 418, 679, 775, 786, 787, 1025, 1056, 1083, 1099, 1167, 1206, 1242, 1243.
+\I\9{prev_depth_}{\.{\\prevdepth} primitive}, \[416].
+\I\\{prev\_dp}, \[970], 972, 973, 974, 976.
+\I\\{prev\_graf}, 212, \[213], 215, 216, 422, 814, 816, 864, 877, 890, 1091, 1149, 1200, 1242.
+\I\9{prev_graf_}{\.{\\prevgraf} primitive}, \[265].
+\I\\{prev\_p}, \[862], 863, 866, 867, 868, 869, \[968], 969, \[970], 973, \[1012], 1014, 1017, 1022.
+\I\\{prev\_prev\_r}, \[830], 832, 843, 844, 860.
+\I\\{prev\_r}, \[829], 830, 832, 843, 844, 845, 851, 854, 860.
+\I\\{prev\_s}, \[862], 894, 896.
+\I\\{primitive}, 226, 230, 238, 248, \[264], 265, 266, 298, 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, 1331,
+1332, 1344.
+\I\\{print}, 54, \[59], 60, 62, 63, 68, 70, 71, 95, 177, 178, 262, 263, 284, 294, 318, 363, 400, 472, 534, 1257, 1328, 1334, 1339.
+\I\\{print\_ASCII}, \[68], 174, 176, 298, 581, 691, 723.
+\I\\{print\_char}, \[58], 59, 60, 64, 65, 66, 67, 69, 70, 82, 91, 94, 95, 103, 114, 171, 172, 174, 175, 176, 177, 178, 184, 186, 187, 188, 189, 190, 191, 193, 218, 219, 223, 229, 233, 234, 235, 242, 251, 252, 255, 262, 284, 285, 294, 296, 299, 306, 313,
+317, 362, 472, 509, 536, 537, 561, 581, 617, 638, 639, 642, 691, 723, 846, 856, 933, 1006, 1011, 1065, 1069, 1212, 1213, 1280, 1294, 1296, 1311, 1320, 1322, 1324, 1328, 1333, 1335, 1340, 1355, 1356.
+\I\\{print\_cmd\_chr}, 223, 233, 266, 296, \[298], 299, 323, 336, 418, 428, 503, 510, 1049, 1066, 1128, 1212, 1213, 1237, 1335, 1339.
+\I\\{print\_cs}, \[262], 293, 314, 401.
+\I\\{print\_current\_string}, \[70], 182, 692.
+\I\\{print\_delimiter}, \[691], 696, 697.
+\I\\{print\_err}, 72, \[73], 93, 94, 95, 98, 288, 336, 338, 346, 370, 373, 395, 396, 398, 403, 408, 415, 418, 428, 433, 434, 435, 436, 437, 442, 445, 446, 454, 456, 459, 460, 475, 476, 479, 486, 500, 503, 510, 529, 561, 577, 579, 641, 723, 776, 783, 784,
+792, 826, 936, 937, 960, 961, 962, 963, 976, 978, 993, 1004, 1009, 1015, 1024, 1027, 1028, 1047, 1049, 1064, 1066, 1068, 1069, 1078, 1082, 1084, 1095, 1099, 1110, 1120, 1121, 1127, 1128, 1129, 1132, 1135, 1159, 1161, 1166, 1177, 1183, 1192, 1195, 1197,
+1207, 1212, 1213, 1215, 1225, 1232, 1236, 1237, 1241, 1243, 1244, 1252, 1258, 1259, 1283, 1298, 1304, 1372.
+\I\\{print\_esc}, \[63], 86, 176, 184, 187, 188, 189, 190, 191, 192, 194, 195, 196, 197, 225, 227, 229, 231, 233, 234, 235, 237, 239, 242, 247, 249, 251, 262, 263, 266, 267, 292, 293, 294, 323, 335, 373, 377, 385, 412, 417, 428, 469, 486, 488, 492, 500,
+579, 691, 694, 695, 696, 697, 699, 776, 781, 792, 856, 936, 960, 961, 978, 984, 986, 1009, 1015, 1028, 1053, 1059, 1065, 1069, 1072, 1089, 1095, 1099, 1108, 1115, 1120, 1129, 1132, 1135, 1143, 1157, 1166, 1179, 1189, 1192, 1209, 1213, 1220, 1223, 1231,
+1241, 1244, 1251, 1255, 1263, 1273, 1278, 1287, 1292, 1295, 1322, 1335, 1346, 1355, 1356.
+\I\\{print\_fam\_and\_char}, \[691], 692, 696.
+\I\\{print\_file\_name}, \[518], 529, 561, 1322, 1356.
+\I\\{print\_font\_and\_char}, \[176], 183, 193.
+\I\\{print\_glue}, \[177], 178, 185, 186.
+\I\\{print\_hex}, \[67], 691, 1223.
+\I\\{print\_int}, \[65], 84, 91, 94, 103, 114, 168, 169, 170, 171, 172, 185, 188, 194, 195, 218, 219, 227, 229, 231, 233, 234, 235, 239, 242, 249, 251, 255, 285, 288, 313, 336, 400, 465, 472, 509, 536, 561, 579, 617, 638, 639, 642, 660, 663, 667, 674,
+675, 678, 691, 723, 846, 856, 933, 986, 1006, 1009, 1011, 1024, 1028, 1099, 1232, 1296, 1309, 1311, 1318, 1320, 1324, 1328, 1335, 1339, 1355, 1356.
+\I\\{print\_length\_param}, \[247], 249, 251.
+\I\\{print\_ln}, \[57], 58, 59, 61, 62, 71, 86, 89, 90, 114, 182, 198, 218, 236, 245, 296, 306, 314, 317, 330, 360, 363, 401, 484, 534, 537, 638, 639, 660, 663, 666, 667, 674, 675, 677, 678, 692, 986, 1265, 1280, 1309, 1311, 1318, 1320, 1324, 1340, 1370.
+\I\\{print\_locs}, \[167].
+\I\\{print\_mark}, \[176], 196, 1356.
+\I\\{print\_meaning}, \[296], 472, 1294.
+\I\\{print\_mode}, \[211], 218, 299, 1049.
+\I\\{print\_nl}, \[62], 73, 82, 84, 85, 90, 168, 169, 170, 171, 172, 218, 219, 245, 255, 285, 288, 299, 306, 311, 313, 314, 323, 360, 400, 529, 534, 581, 638, 639, 641, 642, 660, 666, 667, 674, 677, 678, 846, 856, 857, 863, 933, 986, 987, 992, 1006,
+1011, 1121, 1294, 1296, 1297, 1322, 1324, 1328, 1333, 1335, 1338, 1370.
+\I\\{print\_param}, \[237], 239, 242.
+\I\\{print\_plus}, \[985].
+\I\\{print\_plus\_end}, \[985].
+\I\\{print\_roman\_int}, \[69], 472.
+\I\\{print\_rule\_dimen}, \[176], 187.
+\I\\{print\_scaled}, \[103], 114, 176, 177, 178, 184, 188, 191, 192, 219, 251, 465, 472, 561, 666, 677, 697, 985, 986, 987, 1006, 1011, 1259, 1261, 1322.
+\I\\{print\_size}, \[699], 723, 1231.
+\I\\{print\_skip\_param}, 189, \[225], 227, 229.
+\I\\{print\_spec}, \[178], 188, 189, 190, 229, 465.
+\I\\{print\_str}, \[59], 62, 71, 73, 84, 85, 86, 89, 91, 94, 175, 177, 178, 182, 183, 184, 185, 186, 187, 188, 190, 191, 192, 193, 195, 211, 218, 219, 225, 233, 234, 237, 247, 251, 288, 294, 298, 299, 306, 317, 323, 336, 338, 339, 373, 395, 396, 398,
+400, 428, 454, 456, 459, 465, 472, 502, 509, 529, 536, 561, 567, 579, 581, 617, 638, 639, 642, 660, 663, 666, 674, 675, 677, 692, 694, 697, 723, 776, 846, 856, 936, 978, 985, 986, 987, 1006, 1011, 1015, 1024, 1049, 1064, 1095, 1132, 1166, 1213, 1232,
+1237, 1257, 1259, 1261, 1295, 1296, 1298, 1309, 1311, 1318, 1320, 1322, 1324, 1328, 1335, 1338, 1346, 1356.
+\I\\{print\_style}, 690, \[694], 1170.
+\I\\{print\_subsidiary\_data}, \[692], 696, 697.
+\I\\{print\_the\_digs}, \[64], 65, 67.
+\I\\{print\_totals}, \[218], \[985], 986, 1006.
+\I\\{print\_two}, \[66], 536, 617.
+\I\\{print\_word}, \[114], 1339.
+\I\\{print\_write\_whatsit}, \[1355], 1356.
+\I\\{printed\_node}, \[821], \[856], \[857], 858, 864.
+\I\\{privileged}, \[1051], 1054, 1130, 1140.
+\I\\{prompt\_file\_name}, \[529], 531, 535, 537, 1328, 1374.
+\I\\{prompt\_input}, \[71], 83, 87, 360, 363, 484, 529.
+\I\\{prune\_movements}, \[615], 619, 629.
+\I\\{prune\_page\_top}, \[968], 977, 1021.
+\I\\{pseudo}, \[54], 57, 58, 59, 316.
+\I\\{pstack}, \[388], 390, 396, 400.
+\I\.{pt}, 453.
+\I\\{punct\_noad}, \[682], 690, 696, 698, 728, 752, 761, 1156, 1157.
+\I\\{push}, 584, 585, \[586], 590, 592, 601, 608, 616, 619, 629.
+\I\\{push\_alignment}, \[772], 774.
+\I\\{push\_input}, \[321], 323, 325, 328.
+\I\\{push\_math}, \[1136], 1139, 1145, 1153, 1172, 1174, 1191.
+\I\\{push\_nest}, \[216], 774, 786, 787, 1025, 1083, 1091, 1099, 1117, 1119, 1136, 1167, 1200.
+\I\\{put}, 26, 29, \[56], 1305.
+\I\\{put\_rule}, 585, \[586], 633.
+\I\\{put1}, \[585].
+\I\\{put2}, \[585].
+\I\\{put3}, \[585].
+\I\\{put4}, \[585].
+\I\|{q}, \[123], \[125], \[130], \[131], \[144], \[151], \[152], \[153], \[167], \[172], \[202], \[204], \[218], \[275], \[292], \[315], \[336], \[366], \[389], \[407], \[450], \[461], \[463], \[464], \[465], \[473], \[482], \[497], \[498], \[607], %
+\[649], \[705], \[706], \[709], \[712], \[720], \[726], \[734], \[735], \[736], \[737], \[738], \[743], \[749], \[752], \[756], \[762], \[791], \[800], \[826], \[830], \[862], \[877], \[901], \[906], \[934], \[948], \[953], \[957], \[959], \[960], %
+\[968], \[970], \[977], \[994], \[1012], \[1043], \[1068], \[1079], \[1093], \[1105], \[1119], \[1123], \[1124], \[1138], \[1184], \[1198], \[1211], \[1236], \[1302], \[1303], \[1370].
+\I\\{qi}, \[112], 545, 549, 564, 570, 573, 576, 582, 620, \[753], 907, 908, \[911], 913, 923, 958, 959, 981, 1008, 1009, 1034, 1035, 1038, 1039, \[1040], 1100, 1151, 1155, 1160, 1165, 1309, 1325.
+\I\\{qo}, \[112], 159, 174, 176, 185, 188, 554, 570, 576, 602, 620, 691, 708, 722, 723, 741, 752, 755, 896, 897, 898, 903, 909, 923, 945, 981, 986, 1008, 1018, 1021, 1039, 1310, 1324, 1325.
+\I\\{qqqq}, 110, \[113], 114, 550, 554, 569, 573, 574, 683, 713, 741, 752, 909, 1039, 1181, 1305, 1306.
+\I\\{quad}, 547, \[558], 1146.
+\I\\{quad\_code}, \[547], 558.
+\I\&{quarterword}, 110, \[113], 144, 253, 264, 271, 276, 277, 279, 281, 298, 300, 323, 592, 681, 706, 709, 711, 712, 724, 738, 749, 877, 921, 943, 944, 947, 960, 1061.
+\I\\{qw}, \[560], 564, 570, 573, 576.
+\I\|{r}, \[108], \[123], \[125], \[131], \[204], \[218], \[366], \[389], \[465], \[482], \[498], \[649], \[668], \[706], \[720], \[726], \[752], \[791], \[800], \[829], \[862], \[877], \[901], \[953], \[966], \[970], \[994], \[1012], \[1123], \[1160], %
+\[1198], \[1236], \[1370].
+\I\\{r\_count}, \[912], 914, 918.
+\I\\{r\_hyf}, 891, \[892], 894, 899, 902, 923, 1362.
+\I\\{r\_type}, \[726], 727, 728, 729, 760, 766, 767.
+\I\\{radical}, \[208], 265, 266, 1046, 1162.
+\I\9{radical_}{\.{\\radical} primitive}, \[265].
+\I\\{radical\_noad}, \[683], 690, 696, 698, 733, 761, 1163.
+\I\\{radical\_noad\_size}, \[683], 698, 761, 1163.
+\I\\{radix}, 366, \[438], 439, 440, 444, 445, 448.
+\I\\{radix\_backup}, \[366].
+\I\9{raise_}{\.{\\raise} primitive}, \[1071].
+\I{Ramshaw, Lyle Harold}, 539.
+\I\\{rbrace\_ptr}, \[389], 399, 400.
+\I\\{read}, 52, 53, \[56].
+\I\9{read_}{\.{\\read} primitive}, \[265].
+\I\\{read\_file}, \[480], 485, 486, 1275.
+\I\\{read\_font\_info}, \[560], 564, 1040, 1257.
+\I\\{read\_ln}, 52, \[56].
+\I\\{read\_open}, \[480], 481, 483, 485, 486, 501, 1275.
+\I\\{read\_sixteen}, \[564], 565, 568.
+\I\\{read\_to\_cs}, \[209], 265, 266, 1210, 1225.
+\I\\{read\_toks}, 303, \[482], 1225.
+\I\\{ready\_already}, \[1331], 1332.
+\I{real addition}, 1125.
+\I{real division}, 658, 664, 673, 676, 810, 811, 1123, 1125.
+\I{real multiplication}, 114, 186, 625, 634, 809, 1125.
+\I\\{rebox}, \[715], 744, 750.
+\I\\{reconstitute}, 905, \[906], 913, 915, 916, 917, 1032.
+\I{recursion}, 76, 78, 173, 180, 198, 202, 203, 366, 402, 407, 498, 526, 592, 618, 692, 719, 720, 725, 754, 949, 957, 959, 1333, 1375.
+\I\\{ref\_count}, \[389], 390, 401.
+\I{reference counts}, 150, 200, 201, 203, 275, 291, 307.
+\I\&{register}, \[209].
+\I\\{rel\_noad}, \[682], 690, 696, 698, 728, 761, 767, 1156, 1157.
+\I\\{rel\_penalty}, \[236], 682, 761.
+\I\9{rel_penalty_}{\.{\\relpenalty} primitive}, \[238].
+\I\\{rel\_penalty\_code}, \[236], 237, 238.
+\I\\{relax}, \[207], 265, 266, 358, 372, 404, 506, 1045, 1224.
+\I\9{relax_}{\.{\\relax} primitive}, \[265].
+\I\\{rem}, \[104], 106, 107, 457, 458, \[543], 544, 545, 716, 717.
+\I\\{rem\_byte}, \[545], 554, 557, 570, 708, 713, 740, 749, 753, 911, 1040.
+\I\\{remove\_item}, \[208], 1104, 1107, 1108.
+\I\\{rep}, \[546].
+\I\\{replace\_count}, \[145], 175, 195, 840, 858, 869, 882, 883, 918, 1081, 1105, 1120.
+\I\\{report\_illegal\_case}, 1045, \[1050], 1051, 1243, 1377.
+\I\\{reset}, 26, 27, \[56].
+\I\\{reset\_OK}, \[27].
+\I\\{restart}, 15, \[125], 126, \[341], 346, 357, 359, 360, 362, \[380], \[752], 753, \[782], \[785], 789, \[1151], \[1215].
+\I\\{restore\_old\_value}, \[268], 276, 282.
+\I\\{restore\_trace}, 283, \[284].
+\I\\{restore\_zero}, \[268], 276, 278.
+\I\\{result}, \[45], \[46].
+\I\\{resume}, 15, \[83], 84, 88, 89, \[392], 393, 394, 395, 397, \[708], \[784], \[829], 832, 851, \[896], \[906], 909, 910, 911, \[994], 1001.
+\I\\{resume\_after\_display}, \[800], 1199, \[1200], 1206.
+\I\\{reswitch}, 15, \[343], 352, \[463], \[620], \[651], 652, \[728], \[935], 1029, \[1030], 1036, 1045, \[1147], \[1151].
+\I\\{rewrite}, 26, 27, \[56].
+\I\\{rewrite\_OK}, \[27].
+\I\\{rh}, 110, \[113], 114, 118, 213, 219, 221, 234, 256, 268, 685, 921, 958.
+\I\9{right_}{\.{\\right} primitive}, \[1188].
+\I\\{right\_brace}, \[207], 289, 294, 298, 347, 357, 389, 442, 474, 477, 785, 935, 961, 1067, 1252.
+\I\\{right\_brace\_limit}, \[289], 325, 392, 399, 400, 474, 477.
+\I\\{right\_brace\_token}, \[289], 339, 1065, 1127, 1226, 1371.
+\I\\{right\_delimiter}, \[683], 697, 748, 1181, 1182.
+\I\\{right\_hyphen\_min}, \[236], 1091, 1200, 1376, 1377.
+\I\9{right_hyphen_min_}{\.{\\righthyphenmin} primitive}, \[238].
+\I\\{right\_hyphen\_min\_code}, \[236], 237, 238.
+\I\\{right\_noad}, \[687], 690, 696, 698, 725, 728, 760, 761, 762, 1184, 1188, 1191.
+\I\\{right\_ptr}, \[605], 606, 607, 615.
+\I\\{right\_skip}, \[224], 827, 880, 881.
+\I\9{right_skip_}{\.{\\rightskip} primitive}, \[226].
+\I\\{right\_skip\_code}, \[224], 225, 226, 881, 886.
+\I\\{right1}, 585, \[586], 607, 610, 616.
+\I\\{right2}, 585, 610.
+\I\\{right3}, 585, 610.
+\I\\{right4}, 585, 610.
+\I\\{rlink}, \[124], 125, 126, 127, 129, 130, 131, 132, 145, 149, 164, 169, 772, 819, 821, 1311, 1312.
+\I\9{roman_numeral_}{\.{\\romannumeral} primitive}, \[468].
+\I\\{roman\_numeral\_code}, \[468], 469, 471, 472.
+\I\\{round}, 3, 114, 186, 625, 634, 809, 1125.
+\I\\{round\_decimals}, \[102], 103, 452.
+\I\\{rover}, \[124], 125, 126, 127, 128, 129, 130, 131, 132, 164, 169, 1311, 1312.
+\I\\{rt\_hit}, 906, \[907], 910, 911, 1033, 1035, 1040.
+\I\\{rule\_dp}, \[592], 622, 624, 626, 631, 633, 635.
+\I\\{rule\_ht}, \[592], 622, 624, 626, 631, 633, 634, 635, 636.
+\I\\{rule\_node}, \[138], 139, 148, 175, 183, 202, 206, 622, 626, 631, 635, 651, 653, 669, 670, 730, 761, 805, 841, 842, 866, 870, 871, 968, 973, 1000, 1074, 1087, 1121, 1147.
+\I\\{rule\_node\_size}, \[138], 139, 202, 206.
+\I\\{rule\_save}, \[800], 804.
+\I\\{rule\_wd}, \[592], 622, 624, 625, 626, 627, 631, 633, 635.
+\I{rules aligning with characters}, 589.
+\I\\{runaway}, 120, \[306], 338, 396, 486.
+\I\.{Runaway...}, 306.
+\I\|{s}, \[45], \[46], \[58], \[59], \[60], \[62], \[63], \[93], \[94], \[95], \[103], \[108], \[125], \[130], \[147], \[177], \[178], \[264], \[284], \[389], \[407], \[473], \[482], \[528], \[529], \[560], \[638], \[645], \[649], \[668], \[688], \[699],
+\[706], \[720], \[726], \[738], \[791], \[800], \[830], \[862], \[877], \[901], \[934], \[966], \[987], \[1012], \[1060], \[1061], \[1123], \[1138], \[1198], \[1236], \[1257], \[1279], \[1349], \[1355].
+\I\\{save\_cond\_ptr}, \[498], 500, 509.
+\I\\{save\_cs\_ptr}, \[774], 777.
+\I\\{save\_cur\_val}, \[450], 455.
+\I\\{save\_for\_after}, \[280], 1271.
+\I\\{save\_h}, \[619], 623, 627, 628, \[629], 632, 637.
+\I\\{save\_index}, \[268], 274, 276, 280, 282.
+\I\\{save\_level}, \[268], 269, 274, 276, 280, 282.
+\I\\{save\_link}, \[830], 857.
+\I\\{save\_loc}, \[619], \[629].
+\I\\{save\_ptr}, 268, \[271], 272, 273, 274, 276, 280, 282, 283, 285, 645, 804, 1086, 1099, 1100, 1117, 1120, 1142, 1153, 1168, 1172, 1174, 1186, 1194, 1304.
+\I\\{save\_scanner\_status}, \[366], 369, \[389], \[470], 471, \[494], \[498], 507.
+\I\\{save\_size}, \[11], 111, 271, 273, 1334.
+\I\\{save\_split\_top\_skip}, \[1012], 1014.
+\I\\{save\_stack}, 203, 268, 270, \[271], 273, 274, 275, 276, 277, 281, 282, 283, 285, 300, 372, 489, 645, 768, 1062, 1071, 1131, 1140, 1150, 1153, 1339.
+\I\\{save\_style}, \[720], \[726], 754.
+\I\\{save\_type}, \[268], 274, 276, 280, 282.
+\I\\{save\_v}, \[619], 623, 628, \[629], 632, 636, 637.
+\I\\{save\_vbadness}, \[1012], 1017.
+\I\\{save\_vfuzz}, \[1012], 1017.
+\I\\{save\_warning\_index}, \[389].
+\I\\{saved}, \[274], 645, 804, 1083, 1086, 1099, 1100, 1117, 1119, 1142, 1153, 1168, 1172, 1174, 1186, 1194.
+\I\\{sc}, 110, \[113], 114, 135, 150, 159, 164, 213, 219, 247, 250, 251, 413, 420, 425, 550, 552, 554, 557, 558, 571, 573, 575, 580, 700, 701, 775, 822, 823, 832, 843, 844, 848, 850, 860, 861, 889, 1042, 1149, 1206, 1247, 1248, 1253.
+\I\&{scaled}, \[101], 102, 103, 104, 105, 106, 107, 108, 110, 113, 147, 150, 156, 176, 177, 447, 448, 450, 453, 548, 549, 560, 584, 592, 607, 616, 619, 629, 646, 649, 668, 679, 704, 705, 706, 712, 715, 716, 717, 719, 726, 735, 736, 737, 738, 743, 749,
+756, 762, 791, 800, 823, 830, 839, 847, 877, 906, 970, 971, 977, 980, 982, 994, 1012, 1068, 1086, 1123, 1138, 1198, 1257.
+\I\.{scaled}, 1258.
+\I\\{scaled\_base}, \[247], 249, 251, 1224, 1237.
+\I\\{scan\_box}, 1073, \[1084], 1241.
+\I\\{scan\_char\_num}, 414, \[434], 935, 1030, 1038, 1123, 1124, 1151, 1154, 1224, 1232.
+\I\\{scan\_delimiter}, \[1160], 1163, 1182, 1183, 1191, 1192.
+\I\\{scan\_dimen}, 410, 440, 447, \[448], 461, 462, 1061.
+\I\\{scan\_eight\_bit\_int}, 415, 420, 427, \[433], 505, 1079, 1082, 1099, 1110, 1224, 1226, 1227, 1237, 1241, 1247, 1296.
+\I\\{scan\_fifteen\_bit\_int}, \[436], 1151, 1154, 1165, 1224.
+\I\\{scan\_file\_name}, 265, 334, \[525], 526, 537, 1257, 1275, 1351.
+\I\\{scan\_font\_ident}, 415, 426, 471, \[577], 578, 1234, 1253.
+\I\\{scan\_four\_bit\_int}, \[435], 501, 577, 1234, 1275, 1350.
+\I\\{scan\_glue}, 410, \[461], 782, 1060, 1228, 1238.
+\I\\{scan\_int}, \[409], 410, 432, 433, 434, 435, 436, 437, 438, \[440], 447, 448, 461, 471, 503, 504, 509, 578, 1103, 1225, 1228, 1232, 1238, 1240, 1243, 1244, 1246, 1248, 1253, 1258, 1350, 1377.
+\I\\{scan\_keyword}, 162, \[407], 453, 454, 455, 456, 458, 462, 463, 645, 1082, 1225, 1236, 1258.
+\I\\{scan\_left\_brace}, \[403], 473, 645, 785, 934, 960, 1025, 1099, 1117, 1119, 1153, 1172, 1174.
+\I\\{scan\_math}, 1150, \[1151], 1158, 1163, 1165, 1176.
+\I\\{scan\_normal\_dimen}, \[448], 463, 503, 645, 1073, 1082, 1182, 1183, 1228, 1238, 1243, 1245, 1247, 1248, 1253, 1259.
+\I\\{scan\_optional\_equals}, \[405], 782, 1224, 1226, 1228, 1232, 1234, 1236, 1241, 1243, 1244, 1245, 1246, 1247, 1248, 1253, 1257, 1275, 1351.
+\I\\{scan\_rule\_spec}, \[463], 1056, 1084.
+\I\\{scan\_something\_internal}, 409, 410, \[413], 432, 440, 449, 451, 455, 461, 465.
+\I\\{scan\_spec}, \[645], 768, 774, 1071, 1083, 1167.
+\I\\{scan\_toks}, 291, 464, \[473], 960, 1101, 1218, 1226, 1279, 1288, 1352, 1354, 1371.
+\I\\{scan\_twenty\_seven\_bit\_int}, \[437], 1151, 1154, 1160.
+\I\\{scanned\_result}, \[413], 414, 415, 418, 422, 425, 426, 428.
+\I\\{scanned\_result\_end}, \[413].
+\I\\{scanner\_status}, \[305], 306, 331, 336, 339, 366, 369, 389, 391, 470, 471, 473, 482, 494, 498, 507, 777, 789.
+\I\9{script_font_}{\.{\\scriptfont} primitive}, \[1230].
+\I\\{script\_mlist}, \[689], 695, 698, 731, 1174.
+\I\9{script_script_font_}{\.{\\scriptscriptfont} primitive}, \[1230].
+\I\\{script\_script\_mlist}, \[689], 695, 698, 731, 1174.
+\I\\{script\_script\_size}, \[699], 756, 1195, 1230.
+\I\\{script\_script\_style}, \[688], 694, 731, 1169.
+\I\9{script_script_style_}{\.{\\scriptscriptstyle} primitive}, \[1169].
+\I\\{script\_size}, \[699], 756, 1195, 1230.
+\I\\{script\_space}, \[247], 757, 758, 759.
+\I\9{script_space_}{\.{\\scriptspace} primitive}, \[248].
+\I\\{script\_space\_code}, \[247], 248.
+\I\\{script\_style}, \[688], 694, 702, 703, 731, 756, 762, 766, 1169.
+\I\9{script_style_}{\.{\\scriptstyle} primitive}, \[1169].
+\I\\{scripts\_allowed}, \[687], 1176.
+\I\\{scroll\_mode}, 71, \[73], 84, 86, 93, 529, 1262, 1263, 1281.
+\I\9{scroll_mode_}{\.{\\scrollmode} primitive}, \[1262].
+\I\\{search\_mem}, 165, \[172], 255, 1339.
+\I\\{second\_indent}, \[847], 848, 849, 889.
+\I\\{second\_pass}, \[828], 863, 866.
+\I\\{second\_width}, \[847], 848, 849, 850, 889.
+\I{Sedgewick, Robert}, 2.
+\I\.{see the transcript file...}, 1335.
+\I\\{selector}, \[54], 55, 57, 58, 59, 62, 71, 75, 86, 90, 92, 98, 245, 311, 312, 316, 360, 465, 470, 534, 535, 617, 638, 1257, 1265, 1279, 1298, 1328, 1333, 1335, 1368, 1370.
+\I\\{semi\_simple\_group}, \[269], 1063, 1065, 1068, 1069.
+\I\\{serial}, \[821], 845, 846, 856.
+\I\\{set}, 1208.
+\I\\{set\_aux}, \[209], 413, 416, 417, 418, 1210, 1242.
+\I\\{set\_box}, \[209], 265, 266, 1210, 1241.
+\I\9{set_box_}{\.{\\setbox} primitive}, \[265].
+\I\\{set\_box\_allowed}, \[76], 77, 1241, 1270.
+\I\\{set\_box\_dimen}, \[209], 413, 416, 417, 1210, 1242.
+\I\\{set\_break\_width\_to\_background}, \[837].
+\I\\{set\_char\_0}, 585, \[586], 620.
+\I\\{set\_conversion}, \[458].
+\I\\{set\_conversion\_end}, \[458].
+\I\\{set\_cur\_lang}, \[934], 960, 1091, 1200.
+\I\\{set\_cur\_r}, \[908], 910, 911.
+\I\\{set\_font}, \[209], 413, 553, 577, 1210, 1217, 1257, 1261.
+\I\\{set\_glue\_ratio\_one}, \[109], 664, 676, 810, 811.
+\I\\{set\_glue\_ratio\_zero}, \[109], 136, 657, 658, 664, 672, 673, 676, 810, 811.
+\I\\{set\_height\_zero}, \[970].
+\I\\{set\_interaction}, \[209], 1210, 1262, 1263, 1264.
+\I\9{set_language_}{\.{\\setlanguage} primitive}, \[1344].
+\I\\{set\_language\_code}, \[1344], 1346, 1348.
+\I\\{set\_math\_char}, 1154, \[1155].
+\I\\{set\_page\_dimen}, \[209], 413, 982, 983, 984, 1210, 1242.
+\I\\{set\_page\_int}, \[209], 413, 416, 417, 1210, 1242.
+\I\\{set\_page\_so\_far\_zero}, \[987].
+\I\\{set\_prev\_graf}, \[209], 265, 266, 413, 1210, 1242.
+\I\\{set\_rule}, 583, 585, \[586], 624.
+\I\\{set\_shape}, \[209], 265, 266, 413, 1210, 1248.
+\I\\{set\_trick\_count}, \[316], 317, 318, 320.
+\I\\{set1}, 585, \[586], 620.
+\I\\{set2}, \[585].
+\I\\{set3}, \[585].
+\I\\{set4}, \[585].
+\I\\{sf\_code}, \[230], 232, 1034.
+\I\9{sf_code_}{\.{\\sfcode} primitive}, \[1230].
+\I\\{sf\_code\_base}, \[230], 235, 1230, 1231, 1233.
+\I\\{shape\_ref}, \[210], 232, 275, 1070, 1248.
+\I\\{shift\_amount}, \[135], 136, 159, 184, 623, 628, 632, 637, 649, 653, 668, 670, 681, 706, 720, 737, 738, 749, 750, 756, 757, 759, 799, 806, 807, 808, 889, 1076, 1081, 1125, 1146, 1203, 1204, 1205.
+\I\\{shift\_case}, 1285, \[1288].
+\I\\{shift\_down}, \[743], 744, 745, 746, 747, \[749], 751, \[756], 757, 759.
+\I\\{shift\_up}, \[743], 744, 745, 746, 747, \[749], 751, \[756], 758, 759.
+\I\\{ship\_out}, 211, 592, \[638], 644, 1023, 1075.
+\I\9{ship_out_}{\.{\\shipout} primitive}, \[1071].
+\I\\{ship\_out\_flag}, \[1071], 1075.
+\I\\{short\_display}, 173, \[174], 175, 193, 663, 857, 1339.
+\I\\{short\_real}, 109, 110.
+\I\\{shortcut}, 447, \[448].
+\I\\{shortfall}, \[830], 851, 852, 853.
+\I\\{shorthand\_def}, \[209], 1210, 1222, 1223, 1224.
+\I\9{show_}{\.{\\show} primitive}, \[1291].
+\I\\{show\_activities}, \[218], 1293.
+\I\\{show\_box}, 180, 182, \[198], 218, 219, 236, 638, 641, 663, 675, 986, 992, 1121, 1296, 1339.
+\I\9{show_box_}{\.{\\showbox} primitive}, \[1291].
+\I\\{show\_box\_breadth}, \[236], 1339.
+\I\9{show_box_breadth_}{\.{\\showboxbreadth} primitive}, \[238].
+\I\\{show\_box\_breadth\_code}, \[236], 237, 238.
+\I\\{show\_box\_code}, \[1291], 1292, 1293.
+\I\\{show\_box\_depth}, \[236], 1339.
+\I\9{show_box_depth_}{\.{\\showboxdepth} primitive}, \[238].
+\I\\{show\_box\_depth\_code}, \[236], 237, 238.
+\I\\{show\_code}, \[1291], 1293.
+\I\\{show\_context}, 54, \[78], 82, 88, 310, \[311], 318, 529, 535, 537.
+\I\\{show\_cur\_cmd\_chr}, \[299], 367, 1031.
+\I\\{show\_eqtb}, \[252], 284.
+\I\\{show\_info}, \[692], \[693].
+\I\\{show\_lists}, \[1291], 1292, 1293.
+\I\9{show_lists_}{\.{\\showlists} primitive}, \[1291].
+\I\\{show\_node\_list}, 173, 176, 180, 181, \[182], 195, 198, 233, 690, 692, 693, 695, 1339.
+\I\9{show_the_}{\.{\\showthe} primitive}, \[1291].
+\I\\{show\_the\_code}, \[1291], 1292.
+\I\\{show\_token\_list}, 176, 223, 233, \[292], 295, 306, 319, 320, 400, 1339, 1368.
+\I\\{show\_whatever}, 1290, \[1293].
+\I\\{shown\_mode}, \[213], 215, 299.
+\I\\{shrink}, \[150], 151, 164, 178, 431, 462, 625, 634, 656, 671, 716, 809, 825, 827, 838, 868, 976, 1004, 1009, 1042, 1044, 1148, 1229, 1239, 1240.
+\I\\{shrink\_order}, \[150], 164, 178, 462, 625, 634, 656, 671, 716, 809, 825, 826, 976, 1004, 1009, 1148, 1239.
+\I\\{shrinking}, \[135], 186, 664, 676, 809, 810, 811, 1148.
+\I\\{si}, \[38], 42, 69, 951, 964, 1310.
+\I\\{simple\_group}, \[269], 1063, 1068.
+\I{Single-character primitives}, \[267].
+\I\9{Single-character primitives -}{\quad\.{\\-}}, \[1114].
+\I\9{Single-character primitives /}{\quad\.{\\/}}, \[265].
+\I\9{Single-character primitives /}{\quad\.{\\\ }}, \[265].
+\I\\{single\_base}, \[222], 262, 263, 264, 354, 374, 442, 1257, 1289.
+\I\\{size}, 9.
+\I\\{skew\_char}, 426, \[549], 552, 576, 741, 1253, 1322, 1323.
+\I\9{skew_char_}{\.{\\skewchar} primitive}, \[1254].
+\I\\{skew\_char0}, \[549].
+\I\\{skip}, \[224], 427, 1009.
+\I\9{skip_}{\.{\\skip} primitive}, \[411].
+\I\\{skip\_base}, \[224], 227, 229, 1224, 1237.
+\I\\{skip\_blanks}, \[303], 344, 345, 347, 349, 354.
+\I\\{skip\_byte}, \[545], 557, 741, 752, 753, 909, 1039.
+\I\\{skip\_code}, \[1058], 1059, 1060.
+\I\9{skip_def_}{\.{\\skipdef} primitive}, \[1222].
+\I\\{skip\_def\_code}, \[1222], 1223, 1224.
+\I\\{skip\_line}, 336, \[493], 494.
+\I\\{skipping}, \[305], 306, 336, 494.
+\I\\{slant}, 547, \[558], 575, 1123, 1125.
+\I\\{slant\_code}, \[547], 558.
+\I\\{slow\_print}, \[60], 61, 63, 84, 518, 536, 537, 581, 642, 1261, 1280, 1283, 1328, 1333, 1339.
+\I\\{small\_char}, \[683], 691, 697, 706, 1160.
+\I\\{small\_fam}, \[683], 691, 697, 706, 1160.
+\I\\{small\_node\_size}, \[141], 144, 145, 147, 152, 153, 156, 158, 202, 206, 655, 721, 903, 910, 914, 1037, 1100, 1101, 1357, 1358, 1376, 1377.
+\I\&{small\_number}, \[101], 102, 147, 152, 154, 264, 366, 389, 413, 438, 440, 461, 470, 482, 489, 494, 497, 498, 522, 607, 649, 668, 688, 706, 719, 720, 726, 756, 762, 829, 892, 893, 905, 906, 921, 934, 944, 960, 970, 987, 1060, 1086, 1091, 1176, 1181,
+1191, 1198, 1211, 1236, 1247, 1257, 1325, 1335, 1349, 1350, 1370, 1373.
+\I\\{so}, \[38], 45, 59, 60, 69, 70, 264, 407, 464, 519, 603, 617, 766, 931, 953, 955, 956, 959, 963, 1309, 1368.
+\I\.{Sorry, I can't find...}, 523.
+\I\\{sort\_avail}, \[131], 1311.
+\I{sp}, 104, 587.
+\I\.{sp}, 458.
+\I\\{space}, 547, \[558], 752, 755, 1042.
+\I\\{space\_code}, \[547], 558, 578, 1042.
+\I\\{space\_factor}, 212, \[213], 418, 786, 787, 799, 1030, 1034, 1043, 1044, 1056, 1076, 1083, 1091, 1093, 1117, 1119, 1123, 1196, 1200, 1242, 1243.
+\I\9{space_factor_}{\.{\\spacefactor} primitive}, \[416].
+\I\\{space\_shrink}, 547, \[558], 1042.
+\I\\{space\_shrink\_code}, \[547], 558, 578.
+\I\\{space\_skip}, \[224], 1041, 1043.
+\I\9{space_skip_}{\.{\\spaceskip} primitive}, \[226].
+\I\\{space\_skip\_code}, \[224], 225, 226, 1041.
+\I\\{space\_stretch}, 547, \[558], 1042.
+\I\\{space\_stretch\_code}, \[547], 558.
+\I\\{space\_token}, \[289], 393, 464, 1215.
+\I\\{spacer}, \[207], 208, 232, 289, 291, 294, 298, 303, 337, 345, 347, 348, 349, 354, 404, 406, 407, 443, 444, 452, 464, 783, 935, 961, 1030, 1045, 1221.
+\I\9{span_}{\.{\\span} primitive}, \[780].
+\I\\{span\_code}, \[780], 781, 782, 789, 791.
+\I\\{span\_count}, 136, \[159], 185, 796, 801, 808.
+\I\\{span\_node\_size}, \[797], 798, 803.
+\I\\{spec\_code}, \[645].
+\I\9{special_}{\.{\\special} primitive}, \[1344].
+\I\\{special\_node}, \[1341], 1344, 1346, 1348, 1354, 1356, 1357, 1358, 1373.
+\I\\{special\_out}, \[1368], 1373.
+\I\.{split}, 1011.
+\I\\{split\_bot\_mark}, \[382], 383, 977, 979.
+\I\9{split_bot_mark_}{\.{\\splitbotmark} primitive}, \[384].
+\I\\{split\_bot\_mark\_code}, \[382], 384, 385, 1335.
+\I\\{split\_first\_mark}, \[382], 383, 977, 979.
+\I\9{split_first_mark_}{\.{\\splitfirstmark} primitive}, \[384].
+\I\\{split\_first\_mark\_code}, \[382], 384, 385.
+\I\\{split\_max\_depth}, 140, \[247], 977, 1068, 1100.
+\I\9{split_max_depth_}{\.{\\splitmaxdepth} primitive}, \[248].
+\I\\{split\_max\_depth\_code}, \[247], 248.
+\I\\{split\_top\_ptr}, \[140], 188, 202, 206, 1021, 1022, 1100.
+\I\\{split\_top\_skip}, 140, \[224], 968, 977, 1012, 1014, 1021, 1100.
+\I\9{split_top_skip_}{\.{\\splittopskip} primitive}, \[226].
+\I\\{split\_top\_skip\_code}, \[224], 225, 226, 969.
+\I\\{split\_up}, \[981], 986, 1008, 1010, 1020, 1021.
+\I\\{spotless}, \[76], 77, 245, 1332, 1335.
+\I\.{spread}, 645.
+\I\\{sprint\_cs}, 223, \[263], 338, 395, 396, 398, 472, 479, 484, 561, 1294.
+\I{square roots}, 737.
+\I\\{ss\_code}, \[1058], 1059, 1060.
+\I\\{ss\_glue}, \[162], 164, 715, 1060.
+\I{stack conventions}, 300.
+\I\\{stack\_into\_box}, \[711], 713.
+\I\\{stack\_size}, \[11], 301, 321, 1334.
+\I\\{start}, 300, \[302], 303, 307, 318, 319, 323, 324, 325, 328, 329, 331, 360, 362, 363, 369, 483, 538.
+\I\\{start\_cs}, \[354], 355.
+\I\\{start\_eq\_no}, 1140, \[1142].
+\I\\{start\_field}, \[300], 302.
+\I\\{start\_font\_error\_message}, \[561], 567.
+\I\\{start\_here}, 5, \[1332].
+\I\\{start\_input}, \[366], 376, 378, \[537], 1337.
+\I\\{start\_of\_TEX}, \[1332].
+\I\\{start\_par}, \[208], 1088, 1089, 1090, 1092.
+\I\\{stat}, 7.
+\I\.{STAT}, \[117], \[125], \[130], \[252], \[260], \[283], \[284], \[639], \[829], \[830], \[845], \[855], \[863], \[987], \[1005], \[1010], \[1333].
+\I\\{state}, 87, 300, \[302], 303, 307, 311, 312, 323, 325, 328, 330, 331, 337, 341, 343, \[344], 346, 347, 349, \[352], \[353], \[354], 390, 483, 537, 1335.
+\I\\{state\_field}, \[300], 302, 1131.
+\I\\{stdin}, 33.
+\I\\{stdout}, 33.
+\I{stomach}, 402.
+\I\\{stop}, \[207], 1045, 1046, 1052, 1053, 1054, 1094.
+\I\\{stop\_flag}, \[545], 557, 741, 752, 753, 909, 1039.
+\I\\{store\_background}, \[864].
+\I\\{store\_break\_width}, \[843].
+\I\\{store\_fmt\_file}, \[1302], 1335.
+\I\\{store\_four\_quarters}, \[564], 568, 569, 573, 574.
+\I\\{store\_new\_token}, \[371], 372, 393, 397, 399, 407, 464, 466, 473, 474, 476, 477, 482, 483.
+\I\\{store\_scaled}, \[571], 573, 575.
+\I\\{str\_eq\_buf}, \[45], 259.
+\I\\{str\_eq\_str}, \[46], 1260.
+\I\&{str\_number}, \[38], 39, 43, 45, 46, 47, 63, 95, 177, 178, 264, 284, 407, 512, 519, 524, 526, 528, 529, 532, 549, 560, 926, 929, 934, 1257, 1279, 1299, 1355.
+\I\\{str\_pool}, 38, \[39], 42, 43, 45, 46, 47, 59, 60, 69, 70, 256, 260, 264, 303, 407, 464, 519, 602, 603, 617, 638, 764, 766, 929, 931, 934, 941, 1309, 1310, 1334, 1368.
+\I\\{str\_ptr}, 38, \[39], 41, 43, 44, 47, 59, 60, 70, 260, 262, 517, 524, 537, 617, 1260, 1309, 1310, 1323, 1325, 1327, 1332, 1334, 1368.
+\I\\{str\_room}, \[42], 180, 260, 464, 516, 524, 939, 1257, 1279, 1328, 1333, 1368.
+\I\\{str\_start}, 38, \[39], 40, 41, 43, 44, 45, 46, 47, 59, 60, 69, 70, 256, 260, 264, 407, 517, 519, 603, 617, 765, 929, 931, 934, 941, 1309, 1310, 1368.
+\I\\{str\_start\_end}, 1795.
+\I\\{str\_start\_0\_255}, \[1380], 1794.
+\I\\{str\_start\_256}, 1794, 1795.
+\I\\{str\_start\_257}, 1794, 1795.
+\I\\{str\_start\_258}, 1794, 1795.
+\I\\{str\_start\_259}, 1794, 1795.
+\I\\{str\_start\_260}, 1794, 1795.
+\I\\{str\_start\_261}, 1794, 1795.
+\I\\{str\_start\_262}, 1794, 1795.
+\I\\{str\_start\_263}, 1794, 1795.
+\I\\{str\_start\_264}, 1794, 1795.
+\I\\{str\_start\_265}, 1794, 1795.
+\I\\{str\_start\_266}, 1794, 1795.
+\I\\{str\_start\_267}, 1794, 1795.
+\I\\{str\_start\_268}, 1794, 1795.
+\I\\{str\_start\_269}, 1794, 1795.
+\I\\{str\_start\_270}, 1794, 1795.
+\I\\{str\_start\_271}, 1794, 1795.
+\I\\{str\_start\_272}, 1794, 1795.
+\I\\{str\_start\_273}, 1794, 1795.
+\I\\{str\_start\_274}, 1794, 1795.
+\I\\{str\_start\_275}, 1794, 1795.
+\I\\{str\_start\_276}, 1794, 1795.
+\I\\{str\_start\_277}, 1794, 1795.
+\I\\{str\_start\_278}, 1794, 1795.
+\I\\{str\_start\_279}, 1794, 1795.
+\I\\{str\_start\_280}, 1794, 1795.
+\I\\{str\_start\_281}, 1794, 1795.
+\I\\{str\_start\_282}, 1794, 1795.
+\I\\{str\_start\_283}, 1794, 1795.
+\I\\{str\_start\_284}, 1794, 1795.
+\I\\{str\_start\_285}, 1794, 1795.
+\I\\{str\_start\_286}, 1794, 1795.
+\I\\{str\_start\_287}, 1794, 1795.
+\I\\{str\_start\_288}, 1794, 1795.
+\I\\{str\_start\_289}, 1794, 1795.
+\I\\{str\_start\_290}, 1794, 1795.
+\I\\{str\_start\_291}, 1794, 1795.
+\I\\{str\_start\_292}, 1794, 1795.
+\I\\{str\_start\_293}, 1794, 1795.
+\I\\{str\_start\_294}, 1794, 1795.
+\I\\{str\_start\_295}, 1794, 1795.
+\I\\{str\_start\_296}, 1794, 1795.
+\I\\{str\_start\_297}, 1794, 1795.
+\I\\{str\_start\_298}, 1794, 1795.
+\I\\{str\_start\_299}, 1794, 1795.
+\I\\{str\_start\_300}, 1794, 1795.
+\I\\{str\_start\_301}, 1794, 1795.
+\I\\{str\_start\_302}, 1794, 1795.
+\I\\{str\_start\_303}, 1794, 1795.
+\I\\{str\_start\_304}, 1794, 1795.
+\I\\{str\_start\_305}, 1794, 1795.
+\I\\{str\_start\_306}, 1794, 1795.
+\I\\{str\_start\_307}, 1794, 1795.
+\I\\{str\_start\_308}, 1794, 1795.
+\I\\{str\_start\_309}, 1794, 1795.
+\I\\{str\_start\_310}, 1794, 1795.
+\I\\{str\_start\_311}, 1794, 1795.
+\I\\{str\_start\_312}, 1794, 1795.
+\I\\{str\_start\_313}, 1794, 1795.
+\I\\{str\_start\_314}, 1794, 1795.
+\I\\{str\_start\_315}, 1794, 1795.
+\I\\{str\_start\_316}, 1794, 1795.
+\I\\{str\_start\_317}, 1794, 1795.
+\I\\{str\_start\_318}, 1794, 1795.
+\I\\{str\_start\_319}, 1794, 1795.
+\I\\{str\_start\_320}, 1794, 1795.
+\I\\{str\_start\_321}, 1794, 1795.
+\I\\{str\_start\_322}, 1794, 1795.
+\I\\{str\_start\_323}, 1794, 1795.
+\I\\{str\_start\_324}, 1794, 1795.
+\I\\{str\_start\_325}, 1794, 1795.
+\I\\{str\_start\_326}, 1794, 1795.
+\I\\{str\_start\_327}, 1794, 1795.
+\I\\{str\_start\_328}, 1794, 1795.
+\I\\{str\_start\_329}, 1794, 1795.
+\I\\{str\_start\_330}, 1794, 1795.
+\I\\{str\_start\_331}, 1794, 1795.
+\I\\{str\_start\_332}, 1794, 1795.
+\I\\{str\_start\_333}, 1794, 1795.
+\I\\{str\_start\_334}, 1794, 1795.
+\I\\{str\_start\_335}, 1794, 1795.
+\I\\{str\_start\_336}, 1794, 1795.
+\I\\{str\_start\_337}, 1794, 1795.
+\I\\{str\_start\_338}, 1794, 1795.
+\I\\{str\_start\_339}, 1794, 1795.
+\I\\{str\_start\_340}, 1794, 1795.
+\I\\{str\_start\_341}, 1794, 1795.
+\I\\{str\_start\_342}, 1794, 1795.
+\I\\{str\_start\_343}, 1794, 1795.
+\I\\{str\_start\_344}, 1794, 1795.
+\I\\{str\_start\_345}, 1794, 1795.
+\I\\{str\_start\_346}, 1794, 1795.
+\I\\{str\_start\_347}, 1794, 1795.
+\I\\{str\_start\_348}, 1794, 1795.
+\I\\{str\_start\_349}, 1794, 1795.
+\I\\{str\_start\_350}, 1794, 1795.
+\I\\{str\_start\_351}, 1794, 1795.
+\I\\{str\_start\_352}, 1794, 1795.
+\I\\{str\_start\_353}, 1794, 1795.
+\I\\{str\_start\_354}, 1794, 1795.
+\I\\{str\_start\_355}, 1794, 1795.
+\I\\{str\_start\_356}, 1794, 1795.
+\I\\{str\_start\_357}, 1794, 1795.
+\I\\{str\_start\_358}, 1794, 1795.
+\I\\{str\_start\_359}, 1794, 1795.
+\I\\{str\_start\_360}, 1794, 1795.
+\I\\{str\_start\_361}, 1794, 1795.
+\I\\{str\_start\_362}, 1794, 1795.
+\I\\{str\_start\_363}, 1794, 1795.
+\I\\{str\_start\_364}, 1794, 1795.
+\I\\{str\_start\_365}, 1794, 1795.
+\I\\{str\_start\_366}, 1794, 1795.
+\I\\{str\_start\_367}, 1794, 1795.
+\I\\{str\_start\_368}, 1794, 1795.
+\I\\{str\_start\_369}, 1794, 1795.
+\I\\{str\_start\_370}, 1794, 1795.
+\I\\{str\_start\_371}, 1794, 1795.
+\I\\{str\_start\_372}, 1794, 1795.
+\I\\{str\_start\_373}, 1794, 1795.
+\I\\{str\_start\_374}, 1794, 1795.
+\I\\{str\_start\_375}, 1794, 1795.
+\I\\{str\_start\_376}, 1794, 1795.
+\I\\{str\_start\_377}, 1794, 1795.
+\I\\{str\_start\_378}, 1794, 1795.
+\I\\{str\_start\_379}, 1794, 1795.
+\I\\{str\_start\_380}, 1794, 1795.
+\I\\{str\_start\_381}, 1794, 1795.
+\I\\{str\_start\_382}, 1794, 1795.
+\I\\{str\_start\_383}, 1794, 1795.
+\I\\{str\_start\_384}, 1794, 1795.
+\I\\{str\_start\_385}, 1794, 1795.
+\I\\{str\_start\_386}, 1794, 1795.
+\I\\{str\_start\_387}, 1794, 1795.
+\I\\{str\_start\_388}, 1794, 1795.
+\I\\{str\_start\_389}, 1794, 1795.
+\I\\{str\_start\_390}, 1794, 1795.
+\I\\{str\_start\_391}, 1794, 1795.
+\I\\{str\_start\_392}, 1794, 1795.
+\I\\{str\_start\_393}, 1794, 1795.
+\I\\{str\_start\_394}, 1794, 1795.
+\I\\{str\_start\_395}, 1794, 1795.
+\I\\{str\_start\_396}, 1794, 1795.
+\I\\{str\_start\_397}, 1794, 1795.
+\I\\{str\_start\_398}, 1794, 1795.
+\I\\{str\_start\_399}, 1794, 1795.
+\I\\{str\_start\_400}, 1794, 1795.
+\I\\{str\_start\_401}, 1794, 1795.
+\I\\{str\_start\_402}, 1794, 1795.
+\I\\{str\_start\_403}, 1794, 1795.
+\I\\{str\_start\_404}, 1794, 1795.
+\I\\{str\_start\_405}, 1794, 1795.
+\I\\{str\_start\_406}, 1794, 1795.
+\I\\{str\_start\_407}, 1794, 1795.
+\I\\{str\_start\_408}, 1794, 1795.
+\I\\{str\_start\_409}, 1794, 1795.
+\I\\{str\_start\_410}, 1794, 1795.
+\I\\{str\_start\_411}, 1794, 1795.
+\I\\{str\_start\_412}, 1794, 1795.
+\I\\{str\_start\_413}, 1794, 1795.
+\I\\{str\_start\_414}, 1794, 1795.
+\I\\{str\_start\_415}, 1794, 1795.
+\I\\{str\_start\_416}, 1794, 1795.
+\I\\{str\_start\_417}, 1794, 1795.
+\I\\{str\_start\_418}, 1794, 1795.
+\I\\{str\_start\_419}, 1794, 1795.
+\I\\{str\_start\_420}, 1794, 1795.
+\I\\{str\_start\_421}, 1794, 1795.
+\I\\{str\_start\_422}, 1794, 1795.
+\I\\{str\_start\_423}, 1794, 1795.
+\I\\{str\_start\_424}, 1794, 1795.
+\I\\{str\_start\_425}, 1794, 1795.
+\I\\{str\_start\_426}, 1794, 1795.
+\I\\{str\_start\_427}, 1794, 1795.
+\I\\{str\_start\_428}, 1794, 1795.
+\I\\{str\_start\_429}, 1794, 1795.
+\I\\{str\_start\_430}, 1794, 1795.
+\I\\{str\_start\_431}, 1794, 1795.
+\I\\{str\_start\_432}, 1794, 1795.
+\I\\{str\_start\_433}, 1794, 1795.
+\I\\{str\_start\_434}, 1794, 1795.
+\I\\{str\_start\_435}, 1794, 1795.
+\I\\{str\_start\_436}, 1794, 1795.
+\I\\{str\_start\_437}, 1794, 1795.
+\I\\{str\_start\_438}, 1794, 1795.
+\I\\{str\_start\_439}, 1794, 1795.
+\I\\{str\_start\_440}, 1794, 1795.
+\I\\{str\_start\_441}, 1794, 1795.
+\I\\{str\_start\_442}, 1794, 1795.
+\I\\{str\_start\_443}, 1794, 1795.
+\I\\{str\_start\_444}, 1794, 1795.
+\I\\{str\_start\_445}, 1794, 1795.
+\I\\{str\_start\_446}, 1794, 1795.
+\I\\{str\_start\_447}, 1794, 1795.
+\I\\{str\_start\_448}, 1794, 1795.
+\I\\{str\_start\_449}, 1794, 1795.
+\I\\{str\_start\_450}, 1794, 1795.
+\I\\{str\_start\_451}, 1794, 1795.
+\I\\{str\_start\_452}, 1794, 1795.
+\I\\{str\_start\_453}, 1794, 1795.
+\I\\{str\_start\_454}, 1794, 1795.
+\I\\{str\_start\_455}, 1794, 1795.
+\I\\{str\_start\_456}, 1794, 1795.
+\I\\{str\_start\_457}, 1794, 1795.
+\I\\{str\_start\_458}, 1794, 1795.
+\I\\{str\_start\_459}, 1794, 1795.
+\I\\{str\_start\_460}, 1794, 1795.
+\I\\{str\_start\_461}, 1794, 1795.
+\I\\{str\_start\_462}, 1794, 1795.
+\I\\{str\_start\_463}, 1794, 1795.
+\I\\{str\_start\_464}, 1794, 1795.
+\I\\{str\_start\_465}, 1794, 1795.
+\I\\{str\_start\_466}, 1794, 1795.
+\I\\{str\_start\_467}, 1794, 1795.
+\I\\{str\_start\_468}, 1794, 1795.
+\I\\{str\_start\_469}, 1794, 1795.
+\I\\{str\_start\_470}, 1794, 1795.
+\I\\{str\_start\_471}, 1794, 1795.
+\I\\{str\_start\_472}, 1794, 1795.
+\I\\{str\_start\_473}, 1794, 1795.
+\I\\{str\_start\_474}, 1794, 1795.
+\I\\{str\_start\_475}, 1794, 1795.
+\I\\{str\_start\_476}, 1794, 1795.
+\I\\{str\_start\_477}, 1794, 1795.
+\I\\{str\_start\_478}, 1794, 1795.
+\I\\{str\_start\_479}, 1794, 1795.
+\I\\{str\_start\_480}, 1794, 1795.
+\I\\{str\_start\_481}, 1794, 1795.
+\I\\{str\_start\_482}, 1794, 1795.
+\I\\{str\_start\_483}, 1794, 1795.
+\I\\{str\_start\_484}, 1794, 1795.
+\I\\{str\_start\_485}, 1794, 1795.
+\I\\{str\_start\_486}, 1794, 1795.
+\I\\{str\_start\_487}, 1794, 1795.
+\I\\{str\_start\_488}, 1794, 1795.
+\I\\{str\_start\_489}, 1794, 1795.
+\I\\{str\_start\_490}, 1794, 1795.
+\I\\{str\_start\_491}, 1794, 1795.
+\I\\{str\_start\_492}, 1794, 1795.
+\I\\{str\_start\_493}, 1794, 1795.
+\I\\{str\_start\_494}, 1794, 1795.
+\I\\{str\_start\_495}, 1794, 1795.
+\I\\{str\_start\_496}, 1794, 1795.
+\I\\{str\_start\_497}, 1794, 1795.
+\I\\{str\_start\_498}, 1794, 1795.
+\I\\{str\_start\_499}, 1794, 1795.
+\I\\{str\_start\_500}, 1794, 1795.
+\I\\{str\_start\_501}, 1794, 1795.
+\I\\{str\_start\_502}, 1794, 1795.
+\I\\{str\_start\_503}, 1794, 1795.
+\I\\{str\_start\_504}, 1794, 1795.
+\I\\{str\_start\_505}, 1794, 1795.
+\I\\{str\_start\_506}, 1794, 1795.
+\I\\{str\_start\_507}, 1794, 1795.
+\I\\{str\_start\_508}, 1794, 1795.
+\I\\{str\_start\_509}, 1794, 1795.
+\I\\{str\_start\_510}, 1794, 1795.
+\I\\{str\_start\_511}, 1794, 1795.
+\I\\{str\_start\_512}, 1794, 1795.
+\I\\{str\_start\_513}, 1794, 1795.
+\I\\{str\_start\_514}, 1794, 1795.
+\I\\{str\_start\_515}, 1794, 1795.
+\I\\{str\_start\_516}, 1794, 1795.
+\I\\{str\_start\_517}, 1794, 1795.
+\I\\{str\_start\_518}, 1794, 1795.
+\I\\{str\_start\_519}, 1794, 1795.
+\I\\{str\_start\_520}, 1794, 1795.
+\I\\{str\_start\_521}, 1794, 1795.
+\I\\{str\_start\_522}, 1794, 1795.
+\I\\{str\_start\_523}, 1794, 1795.
+\I\\{str\_start\_524}, 1794, 1795.
+\I\\{str\_start\_525}, 1794, 1795.
+\I\\{str\_start\_526}, 1794, 1795.
+\I\\{str\_start\_527}, 1794, 1795.
+\I\\{str\_start\_528}, 1794, 1795.
+\I\\{str\_start\_529}, 1794, 1795.
+\I\\{str\_start\_530}, 1794, 1795.
+\I\\{str\_start\_531}, 1794, 1795.
+\I\\{str\_start\_532}, 1794, 1795.
+\I\\{str\_start\_533}, 1794, 1795.
+\I\\{str\_start\_534}, 1794, 1795.
+\I\\{str\_start\_535}, 1794, 1795.
+\I\\{str\_start\_536}, 1794, 1795.
+\I\\{str\_start\_537}, 1794, 1795.
+\I\\{str\_start\_538}, 1794, 1795.
+\I\\{str\_start\_539}, 1794, 1795.
+\I\\{str\_start\_540}, 1794, 1795.
+\I\\{str\_start\_541}, 1794, 1795.
+\I\\{str\_start\_542}, 1794, 1795.
+\I\\{str\_start\_543}, 1794, 1795.
+\I\\{str\_start\_544}, 1794, 1795.
+\I\\{str\_start\_545}, 1794, 1795.
+\I\\{str\_start\_546}, 1794, 1795.
+\I\\{str\_start\_547}, 1794, 1795.
+\I\\{str\_start\_548}, 1794, 1795.
+\I\\{str\_start\_549}, 1794, 1795.
+\I\\{str\_start\_550}, 1794, 1795.
+\I\\{str\_start\_551}, 1794, 1795.
+\I\\{str\_start\_552}, 1794, 1795.
+\I\\{str\_start\_553}, 1794, 1795.
+\I\\{str\_start\_554}, 1794, 1795.
+\I\\{str\_start\_555}, 1794, 1795.
+\I\\{str\_start\_556}, 1794, 1795.
+\I\\{str\_start\_557}, 1794, 1795.
+\I\\{str\_start\_558}, 1794, 1795.
+\I\\{str\_start\_559}, 1794, 1795.
+\I\\{str\_start\_560}, 1794, 1795.
+\I\\{str\_start\_561}, 1794, 1795.
+\I\\{str\_start\_562}, 1794, 1795.
+\I\\{str\_start\_563}, 1794, 1795.
+\I\\{str\_start\_564}, 1794, 1795.
+\I\\{str\_start\_565}, 1794, 1795.
+\I\\{str\_start\_566}, 1794, 1795.
+\I\\{str\_start\_567}, 1794, 1795.
+\I\\{str\_start\_568}, 1794, 1795.
+\I\\{str\_start\_569}, 1794, 1795.
+\I\\{str\_start\_570}, 1794, 1795.
+\I\\{str\_start\_571}, 1794, 1795.
+\I\\{str\_start\_572}, 1794, 1795.
+\I\\{str\_start\_573}, 1794, 1795.
+\I\\{str\_start\_574}, 1794, 1795.
+\I\\{str\_start\_575}, 1794, 1795.
+\I\\{str\_start\_576}, 1794, 1795.
+\I\\{str\_start\_577}, 1794, 1795.
+\I\\{str\_start\_578}, 1794, 1795.
+\I\\{str\_start\_579}, 1794, 1795.
+\I\\{str\_start\_580}, 1794, 1795.
+\I\\{str\_start\_581}, 1794, 1795.
+\I\\{str\_start\_582}, 1794, 1795.
+\I\\{str\_start\_583}, 1794, 1795.
+\I\\{str\_start\_584}, 1794, 1795.
+\I\\{str\_start\_585}, 1794, 1795.
+\I\\{str\_start\_586}, 1794, 1795.
+\I\\{str\_start\_587}, 1794, 1795.
+\I\\{str\_start\_588}, 1794, 1795.
+\I\\{str\_start\_589}, 1794, 1795.
+\I\\{str\_start\_590}, 1794, 1795.
+\I\\{str\_start\_591}, 1794, 1795.
+\I\\{str\_start\_592}, 1794, 1795.
+\I\\{str\_start\_593}, 1794, 1795.
+\I\\{str\_start\_594}, 1794, 1795.
+\I\\{str\_start\_595}, 1794, 1795.
+\I\\{str\_start\_596}, 1794, 1795.
+\I\\{str\_start\_597}, 1794, 1795.
+\I\\{str\_start\_598}, 1794, 1795.
+\I\\{str\_start\_599}, 1794, 1795.
+\I\\{str\_start\_600}, 1794, 1795.
+\I\\{str\_start\_601}, 1794, 1795.
+\I\\{str\_start\_602}, 1794, 1795.
+\I\\{str\_start\_603}, 1794, 1795.
+\I\\{str\_start\_604}, 1794, 1795.
+\I\\{str\_start\_605}, 1794, 1795.
+\I\\{str\_start\_606}, 1794, 1795.
+\I\\{str\_start\_607}, 1794, 1795.
+\I\\{str\_start\_608}, 1794, 1795.
+\I\\{str\_start\_609}, 1794, 1795.
+\I\\{str\_start\_610}, 1794, 1795.
+\I\\{str\_start\_611}, 1794, 1795.
+\I\\{str\_start\_612}, 1794, 1795.
+\I\\{str\_start\_613}, 1794, 1795.
+\I\\{str\_start\_614}, 1794, 1795.
+\I\\{str\_start\_615}, 1794, 1795.
+\I\\{str\_start\_616}, 1794, 1795.
+\I\\{str\_start\_617}, 1794, 1795.
+\I\\{str\_start\_618}, 1794, 1795.
+\I\\{str\_start\_619}, 1794, 1795.
+\I\\{str\_start\_620}, 1794, 1795.
+\I\\{str\_start\_621}, 1794, 1795.
+\I\\{str\_start\_622}, 1794, 1795.
+\I\\{str\_start\_623}, 1794, 1795.
+\I\\{str\_start\_624}, 1794, 1795.
+\I\\{str\_start\_625}, 1794, 1795.
+\I\\{str\_start\_626}, 1794, 1795.
+\I\\{str\_start\_627}, 1794, 1795.
+\I\\{str\_start\_628}, 1794, 1795.
+\I\\{str\_start\_629}, 1794, 1795.
+\I\\{str\_start\_630}, 1794, 1795.
+\I\\{str\_start\_631}, 1794, 1795.
+\I\\{str\_start\_632}, 1794, 1795.
+\I\\{str\_start\_633}, 1794, 1795.
+\I\\{str\_start\_634}, 1794, 1795.
+\I\\{str\_start\_635}, 1794, 1795.
+\I\\{str\_start\_636}, 1794, 1795.
+\I\\{str\_start\_637}, 1794, 1795.
+\I\\{str\_start\_638}, 1794, 1795.
+\I\\{str\_start\_639}, 1794, 1795.
+\I\\{str\_start\_640}, 1794, 1795.
+\I\\{str\_start\_641}, 1794, 1795.
+\I\\{str\_start\_642}, 1794, 1795.
+\I\\{str\_start\_643}, 1794, 1795.
+\I\\{str\_start\_644}, 1794, 1795.
+\I\\{str\_start\_645}, 1794, 1795.
+\I\\{str\_start\_646}, 1794, 1795.
+\I\\{str\_start\_647}, 1794, 1795.
+\I\\{str\_start\_648}, 1794, 1795.
+\I\\{str\_start\_649}, 1794, 1795.
+\I\\{str\_start\_650}, 1794, 1795.
+\I\\{str\_start\_651}, 1794, 1795.
+\I\\{str\_start\_652}, 1794, 1795.
+\I\\{str\_start\_653}, 1794, 1795.
+\I\\{str\_start\_654}, 1794, 1795.
+\I\\{str\_start\_655}, 1794, 1795.
+\I\\{str\_start\_656}, 1794, 1795.
+\I\\{str\_start\_657}, 1794, 1795.
+\I\\{str\_start\_658}, 1794, 1795.
+\I\\{str\_start\_659}, 1794, 1795.
+\I\\{str\_start\_660}, 1794, 1795.
+\I\\{str\_start\_661}, 1794, 1795.
+\I\\{str\_start\_662}, 1794, 1795.
+\I\\{str\_start\_663}, 1794, 1795.
+\I\\{str\_start\_664}, 1794, 1795.
+\I\\{str\_start\_665}, 1794, 1795.
+\I\\{str\_start\_666}, 1794, 1795.
+\I\\{str\_start\_667}, 1794, 1795.
+\I\\{str\_start\_668}, 1794, 1795, 1796.
+\I\&{str\_starts}, \[1795].
+\I\\{str\_toks}, \[464], 465, 470.
+\I\\{str\_0\_255}, \[1380], 1793, 1795.
+\I\\{str\_256}, \[1381], 1793, 1795.
+\I\\{str\_257}, \[1382], 1793, 1795.
+\I\\{str\_258}, \[1383], 1793, 1795.
+\I\\{str\_259}, \[1384], 1793, 1795.
+\I\\{str\_260}, \[1385], 1793, 1795.
+\I\\{str\_261}, \[1386], 1793, 1795.
+\I\\{str\_262}, \[1387], 1793, 1795.
+\I\\{str\_263}, \[1388], 1793, 1795.
+\I\\{str\_264}, \[1389], 1793, 1795.
+\I\\{str\_265}, \[1390], 1793, 1795.
+\I\\{str\_266}, \[1391], 1793, 1795.
+\I\\{str\_267}, \[1392], 1793, 1795.
+\I\\{str\_268}, \[1393], 1793, 1795.
+\I\\{str\_269}, \[1394], 1793, 1795.
+\I\\{str\_270}, \[1395], 1793, 1795.
+\I\\{str\_271}, \[1396], 1793, 1795.
+\I\\{str\_272}, \[1397], 1793, 1795.
+\I\\{str\_273}, \[1398], 1793, 1795.
+\I\\{str\_274}, \[1399], 1793, 1795.
+\I\\{str\_275}, \[1400], 1793, 1795.
+\I\\{str\_276}, \[1401], 1793, 1795.
+\I\\{str\_277}, \[1402], 1793, 1795.
+\I\\{str\_278}, \[1403], 1793, 1795.
+\I\\{str\_279}, \[1404], 1793, 1795.
+\I\\{str\_280}, \[1405], 1793, 1795.
+\I\\{str\_281}, \[1406], 1793, 1795.
+\I\\{str\_282}, \[1407], 1793, 1795.
+\I\\{str\_283}, \[1408], 1793, 1795.
+\I\\{str\_284}, \[1409], 1793, 1795.
+\I\\{str\_285}, \[1410], 1793, 1795.
+\I\\{str\_286}, \[1411], 1793, 1795.
+\I\\{str\_287}, \[1412], 1793, 1795.
+\I\\{str\_288}, \[1413], 1793, 1795.
+\I\\{str\_289}, \[1414], 1793, 1795.
+\I\\{str\_290}, \[1415], 1793, 1795.
+\I\\{str\_291}, \[1416], 1793, 1795.
+\I\\{str\_292}, \[1417], 1793, 1795.
+\I\\{str\_293}, \[1418], 1793, 1795.
+\I\\{str\_294}, \[1419], 1793, 1795.
+\I\\{str\_295}, \[1420], 1793, 1795.
+\I\\{str\_296}, \[1421], 1793, 1795.
+\I\\{str\_297}, \[1422], 1793, 1795.
+\I\\{str\_298}, \[1423], 1793, 1795.
+\I\\{str\_299}, \[1424], 1793, 1795.
+\I\\{str\_300}, \[1425], 1793, 1795.
+\I\\{str\_301}, \[1426], 1793, 1795.
+\I\\{str\_302}, \[1427], 1793, 1795.
+\I\\{str\_303}, \[1428], 1793, 1795.
+\I\\{str\_304}, \[1429], 1793, 1795.
+\I\\{str\_305}, \[1430], 1793, 1795.
+\I\\{str\_306}, \[1431], 1793, 1795.
+\I\\{str\_307}, \[1432], 1793, 1795.
+\I\\{str\_308}, \[1433], 1793, 1795.
+\I\\{str\_309}, \[1434], 1793, 1795.
+\I\\{str\_310}, \[1435], 1793, 1795.
+\I\\{str\_311}, \[1436], 1793, 1795.
+\I\\{str\_312}, \[1437], 1793, 1795.
+\I\\{str\_313}, \[1438], 1793, 1795.
+\I\\{str\_314}, \[1439], 1793, 1795.
+\I\\{str\_315}, \[1440], 1793, 1795.
+\I\\{str\_316}, \[1441], 1793, 1795.
+\I\\{str\_317}, \[1442], 1793, 1795.
+\I\\{str\_318}, \[1443], 1793, 1795.
+\I\\{str\_319}, \[1444], 1793, 1795.
+\I\\{str\_320}, \[1445], 1793, 1795.
+\I\\{str\_321}, \[1446], 1793, 1795.
+\I\\{str\_322}, \[1447], 1793, 1795.
+\I\\{str\_323}, \[1448], 1793, 1795.
+\I\\{str\_324}, \[1449], 1793, 1795.
+\I\\{str\_325}, \[1450], 1793, 1795.
+\I\\{str\_326}, \[1451], 1793, 1795.
+\I\\{str\_327}, \[1452], 1793, 1795.
+\I\\{str\_328}, \[1453], 1793, 1795.
+\I\\{str\_329}, \[1454], 1793, 1795.
+\I\\{str\_330}, \[1455], 1793, 1795.
+\I\\{str\_331}, \[1456], 1793, 1795.
+\I\\{str\_332}, \[1457], 1793, 1795.
+\I\\{str\_333}, \[1458], 1793, 1795.
+\I\\{str\_334}, \[1459], 1793, 1795.
+\I\\{str\_335}, \[1460], 1793, 1795.
+\I\\{str\_336}, \[1461], 1793, 1795.
+\I\\{str\_337}, \[1462], 1793, 1795.
+\I\\{str\_338}, \[1463], 1793, 1795.
+\I\\{str\_339}, \[1464], 1793, 1795.
+\I\\{str\_340}, \[1465], 1793, 1795.
+\I\\{str\_341}, \[1466], 1793, 1795.
+\I\\{str\_342}, \[1467], 1793, 1795.
+\I\\{str\_343}, \[1468], 1793, 1795.
+\I\\{str\_344}, \[1469], 1793, 1795.
+\I\\{str\_345}, \[1470], 1793, 1795.
+\I\\{str\_346}, \[1471], 1793, 1795.
+\I\\{str\_347}, \[1472], 1793, 1795.
+\I\\{str\_348}, \[1473], 1793, 1795.
+\I\\{str\_349}, \[1474], 1793, 1795.
+\I\\{str\_350}, \[1475], 1793, 1795.
+\I\\{str\_351}, \[1476], 1793, 1795.
+\I\\{str\_352}, \[1477], 1793, 1795.
+\I\\{str\_353}, \[1478], 1793, 1795.
+\I\\{str\_354}, \[1479], 1793, 1795.
+\I\\{str\_355}, \[1480], 1793, 1795.
+\I\\{str\_356}, \[1481], 1793, 1795.
+\I\\{str\_357}, \[1482], 1793, 1795.
+\I\\{str\_358}, \[1483], 1793, 1795.
+\I\\{str\_359}, \[1484], 1793, 1795.
+\I\\{str\_360}, \[1485], 1793, 1795.
+\I\\{str\_361}, \[1486], 1793, 1795.
+\I\\{str\_362}, \[1487], 1793, 1795.
+\I\\{str\_363}, \[1488], 1793, 1795.
+\I\\{str\_364}, \[1489], 1793, 1795.
+\I\\{str\_365}, \[1490], 1793, 1795.
+\I\\{str\_366}, \[1491], 1793, 1795.
+\I\\{str\_367}, \[1492], 1793, 1795.
+\I\\{str\_368}, \[1493], 1793, 1795.
+\I\\{str\_369}, \[1494], 1793, 1795.
+\I\\{str\_370}, \[1495], 1793, 1795.
+\I\\{str\_371}, \[1496], 1793, 1795.
+\I\\{str\_372}, \[1497], 1793, 1795.
+\I\\{str\_373}, \[1498], 1793, 1795.
+\I\\{str\_374}, \[1499], 1793, 1795.
+\I\\{str\_375}, \[1500], 1793, 1795.
+\I\\{str\_376}, \[1501], 1793, 1795.
+\I\\{str\_377}, \[1502], 1793, 1795.
+\I\\{str\_378}, \[1503], 1793, 1795.
+\I\\{str\_379}, \[1504], 1793, 1795.
+\I\\{str\_380}, \[1505], 1793, 1795.
+\I\\{str\_381}, \[1506], 1793, 1795.
+\I\\{str\_382}, \[1507], 1793, 1795.
+\I\\{str\_383}, \[1508], 1793, 1795.
+\I\\{str\_384}, \[1509], 1793, 1795.
+\I\\{str\_385}, \[1510], 1793, 1795.
+\I\\{str\_386}, \[1511], 1793, 1795.
+\I\\{str\_387}, \[1512], 1793, 1795.
+\I\\{str\_388}, \[1513], 1793, 1795.
+\I\\{str\_389}, \[1514], 1793, 1795.
+\I\\{str\_390}, \[1515], 1793, 1795.
+\I\\{str\_391}, \[1516], 1793, 1795.
+\I\\{str\_392}, \[1517], 1793, 1795.
+\I\\{str\_393}, \[1518], 1793, 1795.
+\I\\{str\_394}, \[1519], 1793, 1795.
+\I\\{str\_395}, \[1520], 1793, 1795.
+\I\\{str\_396}, \[1521], 1793, 1795.
+\I\\{str\_397}, \[1522], 1793, 1795.
+\I\\{str\_398}, \[1523], 1793, 1795.
+\I\\{str\_399}, \[1524], 1793, 1795.
+\I\\{str\_400}, \[1525], 1793, 1795.
+\I\\{str\_401}, \[1526], 1793, 1795.
+\I\\{str\_402}, \[1527], 1793, 1795.
+\I\\{str\_403}, \[1528], 1793, 1795.
+\I\\{str\_404}, \[1529], 1793, 1795.
+\I\\{str\_405}, \[1530], 1793, 1795.
+\I\\{str\_406}, \[1531], 1793, 1795.
+\I\\{str\_407}, \[1532], 1793, 1795.
+\I\\{str\_408}, \[1533], 1793, 1795.
+\I\\{str\_409}, \[1534], 1793, 1795.
+\I\\{str\_410}, \[1535], 1793, 1795.
+\I\\{str\_411}, \[1536], 1793, 1795.
+\I\\{str\_412}, \[1537], 1793, 1795.
+\I\\{str\_413}, \[1538], 1793, 1795.
+\I\\{str\_414}, \[1539], 1793, 1795.
+\I\\{str\_415}, \[1540], 1793, 1795.
+\I\\{str\_416}, \[1541], 1793, 1795.
+\I\\{str\_417}, \[1542], 1793, 1795.
+\I\\{str\_418}, \[1543], 1793, 1795.
+\I\\{str\_419}, \[1544], 1793, 1795.
+\I\\{str\_420}, \[1545], 1793, 1795.
+\I\\{str\_421}, \[1546], 1793, 1795.
+\I\\{str\_422}, \[1547], 1793, 1795.
+\I\\{str\_423}, \[1548], 1793, 1795.
+\I\\{str\_424}, \[1549], 1793, 1795.
+\I\\{str\_425}, \[1550], 1793, 1795.
+\I\\{str\_426}, \[1551], 1793, 1795.
+\I\\{str\_427}, \[1552], 1793, 1795.
+\I\\{str\_428}, \[1553], 1793, 1795.
+\I\\{str\_429}, \[1554], 1793, 1795.
+\I\\{str\_430}, \[1555], 1793, 1795.
+\I\\{str\_431}, \[1556], 1793, 1795.
+\I\\{str\_432}, \[1557], 1793, 1795.
+\I\\{str\_433}, \[1558], 1793, 1795.
+\I\\{str\_434}, \[1559], 1793, 1795.
+\I\\{str\_435}, \[1560], 1793, 1795.
+\I\\{str\_436}, \[1561], 1793, 1795.
+\I\\{str\_437}, \[1562], 1793, 1795.
+\I\\{str\_438}, \[1563], 1793, 1795.
+\I\\{str\_439}, \[1564], 1793, 1795.
+\I\\{str\_440}, \[1565], 1793, 1795.
+\I\\{str\_441}, \[1566], 1793, 1795.
+\I\\{str\_442}, \[1567], 1793, 1795.
+\I\\{str\_443}, \[1568], 1793, 1795.
+\I\\{str\_444}, \[1569], 1793, 1795.
+\I\\{str\_445}, \[1570], 1793, 1795.
+\I\\{str\_446}, \[1571], 1793, 1795.
+\I\\{str\_447}, \[1572], 1793, 1795.
+\I\\{str\_448}, \[1573], 1793, 1795.
+\I\\{str\_449}, \[1574], 1793, 1795.
+\I\\{str\_450}, \[1575], 1793, 1795.
+\I\\{str\_451}, \[1576], 1793, 1795.
+\I\\{str\_452}, \[1577], 1793, 1795.
+\I\\{str\_453}, \[1578], 1793, 1795.
+\I\\{str\_454}, \[1579], 1793, 1795.
+\I\\{str\_455}, \[1580], 1793, 1795.
+\I\\{str\_456}, \[1581], 1793, 1795.
+\I\\{str\_457}, \[1582], 1793, 1795.
+\I\\{str\_458}, \[1583], 1793, 1795.
+\I\\{str\_459}, \[1584], 1793, 1795.
+\I\\{str\_460}, \[1585], 1793, 1795.
+\I\\{str\_461}, \[1586], 1793, 1795.
+\I\\{str\_462}, \[1587], 1793, 1795.
+\I\\{str\_463}, \[1588], 1793, 1795.
+\I\\{str\_464}, \[1589], 1793, 1795.
+\I\\{str\_465}, \[1590], 1793, 1795.
+\I\\{str\_466}, \[1591], 1793, 1795.
+\I\\{str\_467}, \[1592], 1793, 1795.
+\I\\{str\_468}, \[1593], 1793, 1795.
+\I\\{str\_469}, \[1594], 1793, 1795.
+\I\\{str\_470}, \[1595], 1793, 1795.
+\I\\{str\_471}, \[1596], 1793, 1795.
+\I\\{str\_472}, \[1597], 1793, 1795.
+\I\\{str\_473}, \[1598], 1793, 1795.
+\I\\{str\_474}, \[1599], 1793, 1795.
+\I\\{str\_475}, \[1600], 1793, 1795.
+\I\\{str\_476}, \[1601], 1793, 1795.
+\I\\{str\_477}, \[1602], 1793, 1795.
+\I\\{str\_478}, \[1603], 1793, 1795.
+\I\\{str\_479}, \[1604], 1793, 1795.
+\I\\{str\_480}, \[1605], 1793, 1795.
+\I\\{str\_481}, \[1606], 1793, 1795.
+\I\\{str\_482}, \[1607], 1793, 1795.
+\I\\{str\_483}, \[1608], 1793, 1795.
+\I\\{str\_484}, \[1609], 1793, 1795.
+\I\\{str\_485}, \[1610], 1793, 1795.
+\I\\{str\_486}, \[1611], 1793, 1795.
+\I\\{str\_487}, \[1612], 1793, 1795.
+\I\\{str\_488}, \[1613], 1793, 1795.
+\I\\{str\_489}, \[1614], 1793, 1795.
+\I\\{str\_490}, \[1615], 1793, 1795.
+\I\\{str\_491}, \[1616], 1793, 1795.
+\I\\{str\_492}, \[1617], 1793, 1795.
+\I\\{str\_493}, \[1618], 1793, 1795.
+\I\\{str\_494}, \[1619], 1793, 1795.
+\I\\{str\_495}, \[1620], 1793, 1795.
+\I\\{str\_496}, \[1621], 1793, 1795.
+\I\\{str\_497}, \[1622], 1793, 1795.
+\I\\{str\_498}, \[1623], 1793, 1795.
+\I\\{str\_499}, \[1624], 1793, 1795.
+\I\\{str\_500}, \[1625], 1793, 1795.
+\I\\{str\_501}, \[1626], 1793, 1795.
+\I\\{str\_502}, \[1627], 1793, 1795.
+\I\\{str\_503}, \[1628], 1793, 1795.
+\I\\{str\_504}, \[1629], 1793, 1795.
+\I\\{str\_505}, \[1630], 1793, 1795.
+\I\\{str\_506}, \[1631], 1793, 1795.
+\I\\{str\_507}, \[1632], 1793, 1795.
+\I\\{str\_508}, \[1633], 1793, 1795.
+\I\\{str\_509}, \[1634], 1793, 1795.
+\I\\{str\_510}, \[1635], 1793, 1795.
+\I\\{str\_511}, \[1636], 1793, 1795.
+\I\\{str\_512}, \[1637], 1793, 1795.
+\I\\{str\_513}, \[1638], 1793, 1795.
+\I\\{str\_514}, \[1639], 1793, 1795.
+\I\\{str\_515}, \[1640], 1793, 1795.
+\I\\{str\_516}, \[1641], 1793, 1795.
+\I\\{str\_517}, \[1642], 1793, 1795.
+\I\\{str\_518}, \[1643], 1793, 1795.
+\I\\{str\_519}, \[1644], 1793, 1795.
+\I\\{str\_520}, \[1645], 1793, 1795.
+\I\\{str\_521}, \[1646], 1793, 1795.
+\I\\{str\_522}, \[1647], 1793, 1795.
+\I\\{str\_523}, \[1648], 1793, 1795.
+\I\\{str\_524}, \[1649], 1793, 1795.
+\I\\{str\_525}, \[1650], 1793, 1795.
+\I\\{str\_526}, \[1651], 1793, 1795.
+\I\\{str\_527}, \[1652], 1793, 1795.
+\I\\{str\_528}, \[1653], 1793, 1795.
+\I\\{str\_529}, \[1654], 1793, 1795.
+\I\\{str\_530}, \[1655], 1793, 1795.
+\I\\{str\_531}, \[1656], 1793, 1795.
+\I\\{str\_532}, \[1657], 1793, 1795.
+\I\\{str\_533}, \[1658], 1793, 1795.
+\I\\{str\_534}, \[1659], 1793, 1795.
+\I\\{str\_535}, \[1660], 1793, 1795.
+\I\\{str\_536}, \[1661], 1793, 1795.
+\I\\{str\_537}, \[1662], 1793, 1795.
+\I\\{str\_538}, \[1663], 1793, 1795.
+\I\\{str\_539}, \[1664], 1793, 1795.
+\I\\{str\_540}, \[1665], 1793, 1795.
+\I\\{str\_541}, \[1666], 1793, 1795.
+\I\\{str\_542}, \[1667], 1793, 1795.
+\I\\{str\_543}, \[1668], 1793, 1795.
+\I\\{str\_544}, \[1669], 1793, 1795.
+\I\\{str\_545}, \[1670], 1793, 1795.
+\I\\{str\_546}, \[1671], 1793, 1795.
+\I\\{str\_547}, \[1672], 1793, 1795.
+\I\\{str\_548}, \[1673], 1793, 1795.
+\I\\{str\_549}, \[1674], 1793, 1795.
+\I\\{str\_550}, \[1675], 1793, 1795.
+\I\\{str\_551}, \[1676], 1793, 1795.
+\I\\{str\_552}, \[1677], 1793, 1795.
+\I\\{str\_553}, \[1678], 1793, 1795.
+\I\\{str\_554}, \[1679], 1793, 1795.
+\I\\{str\_555}, \[1680], 1793, 1795.
+\I\\{str\_556}, \[1681], 1793, 1795.
+\I\\{str\_557}, \[1682], 1793, 1795.
+\I\\{str\_558}, \[1683], 1793, 1795.
+\I\\{str\_559}, \[1684], 1793, 1795.
+\I\\{str\_560}, \[1685], 1793, 1795.
+\I\\{str\_561}, \[1686], 1793, 1795.
+\I\\{str\_562}, \[1687], 1793, 1795.
+\I\\{str\_563}, \[1688], 1793, 1795.
+\I\\{str\_564}, \[1689], 1793, 1795.
+\I\\{str\_565}, \[1690], 1793, 1795.
+\I\\{str\_566}, \[1691], 1793, 1795.
+\I\\{str\_567}, \[1692], 1793, 1795.
+\I\\{str\_568}, \[1693], 1793, 1795.
+\I\\{str\_569}, \[1694], 1793, 1795.
+\I\\{str\_570}, \[1695], 1793, 1795.
+\I\\{str\_571}, \[1696], 1793, 1795.
+\I\\{str\_572}, \[1697], 1793, 1795.
+\I\\{str\_573}, \[1698], 1793, 1795.
+\I\\{str\_574}, \[1699], 1793, 1795.
+\I\\{str\_575}, \[1700], 1793, 1795.
+\I\\{str\_576}, \[1701], 1793, 1795.
+\I\\{str\_577}, \[1702], 1793, 1795.
+\I\\{str\_578}, \[1703], 1793, 1795.
+\I\\{str\_579}, \[1704], 1793, 1795.
+\I\\{str\_580}, \[1705], 1793, 1795.
+\I\\{str\_581}, \[1706], 1793, 1795.
+\I\\{str\_582}, \[1707], 1793, 1795.
+\I\\{str\_583}, \[1708], 1793, 1795.
+\I\\{str\_584}, \[1709], 1793, 1795.
+\I\\{str\_585}, \[1710], 1793, 1795.
+\I\\{str\_586}, \[1711], 1793, 1795.
+\I\\{str\_587}, \[1712], 1793, 1795.
+\I\\{str\_588}, \[1713], 1793, 1795.
+\I\\{str\_589}, \[1714], 1793, 1795.
+\I\\{str\_590}, \[1715], 1793, 1795.
+\I\\{str\_591}, \[1716], 1793, 1795.
+\I\\{str\_592}, \[1717], 1793, 1795.
+\I\\{str\_593}, \[1718], 1793, 1795.
+\I\\{str\_594}, \[1719], 1793, 1795.
+\I\\{str\_595}, \[1720], 1793, 1795.
+\I\\{str\_596}, \[1721], 1793, 1795.
+\I\\{str\_597}, \[1722], 1793, 1795.
+\I\\{str\_598}, \[1723], 1793, 1795.
+\I\\{str\_599}, \[1724], 1793, 1795.
+\I\\{str\_600}, \[1725], 1793, 1795.
+\I\\{str\_601}, \[1726], 1793, 1795.
+\I\\{str\_602}, \[1727], 1793, 1795.
+\I\\{str\_603}, \[1728], 1793, 1795.
+\I\\{str\_604}, \[1729], 1793, 1795.
+\I\\{str\_605}, \[1730], 1793, 1795.
+\I\\{str\_606}, \[1731], 1793, 1795.
+\I\\{str\_607}, \[1732], 1793, 1795.
+\I\\{str\_608}, \[1733], 1793, 1795.
+\I\\{str\_609}, \[1734], 1793, 1795.
+\I\\{str\_610}, \[1735], 1793, 1795.
+\I\\{str\_611}, \[1736], 1793, 1795.
+\I\\{str\_612}, \[1737], 1793, 1795.
+\I\\{str\_613}, \[1738], 1793, 1795.
+\I\\{str\_614}, \[1739], 1793, 1795.
+\I\\{str\_615}, \[1740], 1793, 1795.
+\I\\{str\_616}, \[1741], 1793, 1795.
+\I\\{str\_617}, \[1742], 1793, 1795.
+\I\\{str\_618}, \[1743], 1793, 1795.
+\I\\{str\_619}, \[1744], 1793, 1795.
+\I\\{str\_620}, \[1745], 1793, 1795.
+\I\\{str\_621}, \[1746], 1793, 1795.
+\I\\{str\_622}, \[1747], 1793, 1795.
+\I\\{str\_623}, \[1748], 1793, 1795.
+\I\\{str\_624}, \[1749], 1793, 1795.
+\I\\{str\_625}, \[1750], 1793, 1795.
+\I\\{str\_626}, \[1751], 1793, 1795.
+\I\\{str\_627}, \[1752], 1793, 1795.
+\I\\{str\_628}, \[1753], 1793, 1795.
+\I\\{str\_629}, \[1754], 1793, 1795.
+\I\\{str\_630}, \[1755], 1793, 1795.
+\I\\{str\_631}, \[1756], 1793, 1795.
+\I\\{str\_632}, \[1757], 1793, 1795.
+\I\\{str\_633}, \[1758], 1793, 1795.
+\I\\{str\_634}, \[1759], 1793, 1795.
+\I\\{str\_635}, \[1760], 1793, 1795.
+\I\\{str\_636}, \[1761], 1793, 1795.
+\I\\{str\_637}, \[1762], 1793, 1795.
+\I\\{str\_638}, \[1763], 1793, 1795.
+\I\\{str\_639}, \[1764], 1793, 1795.
+\I\\{str\_640}, \[1765], 1793, 1795.
+\I\\{str\_641}, \[1766], 1793, 1795.
+\I\\{str\_642}, \[1767], 1793, 1795.
+\I\\{str\_643}, \[1768], 1793, 1795.
+\I\\{str\_644}, \[1769], 1793, 1795.
+\I\\{str\_645}, \[1770], 1793, 1795.
+\I\\{str\_646}, \[1771], 1793, 1795.
+\I\\{str\_647}, \[1772], 1793, 1795.
+\I\\{str\_648}, \[1773], 1793, 1795.
+\I\\{str\_649}, \[1774], 1793, 1795.
+\I\\{str\_650}, \[1775], 1793, 1795.
+\I\\{str\_651}, \[1776], 1793, 1795.
+\I\\{str\_652}, \[1777], 1793, 1795.
+\I\\{str\_653}, \[1778], 1793, 1795.
+\I\\{str\_654}, \[1779], 1793, 1795.
+\I\\{str\_655}, \[1780], 1793, 1795.
+\I\\{str\_656}, \[1781], 1793, 1795.
+\I\\{str\_657}, \[1782], 1793, 1795.
+\I\\{str\_658}, \[1783], 1793, 1795.
+\I\\{str\_659}, \[1784], 1793, 1795.
+\I\\{str\_660}, \[1785], 1793, 1795.
+\I\\{str\_661}, \[1786], 1793, 1795.
+\I\\{str\_662}, \[1787], 1793, 1795.
+\I\\{str\_663}, \[1788], 1793, 1795.
+\I\\{str\_664}, \[1789], 1793, 1795.
+\I\\{str\_665}, \[1790], 1793, 1795.
+\I\\{str\_666}, \[1791], 1793, 1795.
+\I\\{str\_667}, \[1792], 1793, 1795.
+\I\\{strcmp}, 529.
+\I\\{stretch}, \[150], 151, 164, 178, 431, 462, 625, 634, 656, 671, 716, 809, 827, 838, 868, 976, 1004, 1009, 1042, 1044, 1148, 1229, 1239, 1240.
+\I\\{stretch\_order}, \[150], 164, 178, 462, 625, 634, 656, 671, 716, 809, 827, 838, 868, 976, 1004, 1009, 1148, 1239.
+\I\\{stretching}, \[135], 625, 634, 658, 673, 809, 810, 811, 1148.
+\I{string pool}, 47, 1308.
+\I\9{string_}{\.{\\string} primitive}, \[468].
+\I\\{string\_code}, \[468], 469, 471, 472.
+\I\\{string\_vacancies}, \[11], 52.
+\I\\{style}, \[726], 760, 761, \[762].
+\I\\{style\_node}, 160, \[688], 690, 698, 730, 731, 761, 1169.
+\I\\{style\_node\_size}, \[688], 689, 698, 763.
+\I\\{sub\_box}, \[681], 687, 692, 698, 720, 734, 735, 737, 738, 749, 754, 1076, 1093, 1168.
+\I\\{sub\_drop}, \[700], 756.
+\I\\{sub\_mark}, \[207], 294, 298, 347, 1046, 1175.
+\I\\{sub\_mlist}, \[681], 683, 692, 720, 742, 754, 1181, 1185, 1186, 1191.
+\I\\{sub\_style}, \[702], 750, 757, 759.
+\I\\{sub\_sup}, 1175, \[1176].
+\I\\{subscr}, \[681], 683, 686, 687, 690, 696, 698, 738, 742, 749, 750, 751, 752, 753, 754, 755, 756, 757, 759, 1151, 1163, 1165, 1175, 1176, 1177, 1186.
+\I{subscripts}, 754, 1175.
+\I\\{subtype}, \[133], 134, 135, 136, 139, 140, 143, 144, 145, 146, 147, 149, 150, 152, 153, 154, 155, 156, 158, 159, 188, 189, 190, 191, 192, 193, 424, 489, 495, 496, 625, 627, 634, 636, 649, 656, 668, 671, 681, 682, 686, 688, 689, 690, 696, 717, 730,
+731, 732, 733, 749, 763, 766, 768, 786, 795, 809, 819, 820, 822, 837, 843, 844, 866, 868, 879, 881, 896, 897, 898, 899, 903, 910, 981, 986, 988, 1008, 1009, 1018, 1020, 1021, 1035, 1060, 1061, 1078, 1100, 1101, 1113, 1125, 1148, 1159, 1163, 1165, 1171,
+1181, 1335, 1341, 1349, 1356, 1357, 1358, 1362, 1373, 1374.
+\I\\{sub1}, \[700], 757.
+\I\\{sub2}, \[700], 759.
+\I\\{succumb}, \[93], 94, 95, 1304.
+\I\\{sup\_drop}, \[700], 756.
+\I\\{sup\_mark}, \[207], 294, 298, 344, 355, 1046, 1175, 1176, 1177.
+\I\\{sup\_style}, \[702], 750, 758.
+\I{superscripts}, 754, 1175.
+\I\\{supscr}, \[681], 683, 686, 687, 690, 696, 698, 738, 742, 750, 751, 752, 753, 754, 756, 758, 1151, 1163, 1165, 1175, 1176, 1177, 1186.
+\I\\{sup1}, \[700], 758.
+\I\\{sup2}, \[700], 758.
+\I\\{sup3}, \[700], 758.
+\I\\{sw}, \[560], 571, 575.
+\I\\{synch\_h}, \[616], 620, 624, 628, 633, 637, 1368.
+\I\\{synch\_v}, \[616], 620, 624, 628, 632, 633, 637, 1368.
+\I{system dependencies}, 2, \[3], 4, 9, 10, 11, 12, 19, 21, 23, 26, 27, 28, 32, 33, 34, 35, 37, 38, 49, 56, 59, 72, 81, 84, 96, 109, 110, 112, 113, 161, 186, 241, 304, 313, 328, 485, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 522, 524, 538, 557,
+564, 591, 595, 597, 798, 1331, 1332, 1333, 1338, 1340, 1379.
+\I\\{s1}, \[82], 88.
+\I\\{s2}, \[82], 88.
+\I\\{s3}, \[82], 88.
+\I\\{s4}, \[82], 88.
+\I\|{t}, \[46], \[107], \[108], \[125], \[218], \[277], \[279], \[280], \[281], \[323], \[341], \[366], \[389], \[464], \[473], \[704], \[705], \[726], \[756], \[800], \[830], \[877], \[906], \[934], \[966], \[970], \[1030], \[1123], \[1176], \[1191], %
+\[1198], \[1257], \[1288].
+\I\\{t\_open\_in}, \[33], 37.
+\I\\{t\_open\_out}, \[33], 1332.
+\I\\{tab\_mark}, \[207], 289, 294, 342, 347, 780, 781, 782, 783, 784, 788, 1126.
+\I\\{tab\_skip}, \[224].
+\I\9{tab_skip_}{\.{\\tabskip} primitive}, \[226].
+\I\\{tab\_skip\_code}, \[224], 225, 226, 778, 782, 786, 795, 809.
+\I\\{tab\_token}, \[289], 1128.
+\I\\{tag}, \[543], 544, 554.
+\I\\{tail}, 212, \[213], 214, 215, 216, 424, 679, 718, 776, 786, 795, 796, 799, 812, 816, 888, 890, 995, 1017, 1023, 1026, 1034, 1035, 1036, 1037, 1040, 1041, 1043, 1054, 1060, 1061, 1076, 1078, 1080, 1081, 1091, 1096, 1100, 1101, 1105, 1110, 1113, 1117,
+1119, 1120, 1123, 1125, 1145, 1150, 1155, 1158, 1159, 1163, 1165, 1168, 1171, 1174, 1176, 1177, 1181, 1184, 1186, 1187, 1191, 1196, 1205, 1206, 1349, 1350, 1351, 1352, 1353, 1354, 1375, 1376, 1377.
+\I\\{tail\_append}, \[214], 786, 795, 816, 1035, 1037, 1040, 1054, 1056, 1060, 1061, 1091, 1093, 1100, 1103, 1112, 1113, 1117, 1150, 1158, 1163, 1165, 1168, 1171, 1172, 1177, 1191, 1196, 1203, 1205, 1206.
+\I\\{tail\_field}, \[212], 213, 995.
+\I\\{tally}, \[54], 55, 57, 58, 292, 312, 315, 316, 317.
+\I\\{tats}, 7, 117.
+\I\\{temp\_head}, \[162], 306, 391, 396, 400, 464, 466, 467, 470, 478, 719, 720, 754, 760, 816, 862, 863, 864, 877, 879, 880, 881, 887, 968, 1064, 1065, 1194, 1196, 1199, 1297.
+\I\\{temp\_ptr}, \[115], 154, 618, 619, 623, 628, 629, 632, 637, 640, 679, 692, 693, 969, 1001, 1021, 1037, 1041, 1335.
+\I\\{term\_and\_log}, \[54], 57, 58, 71, 75, 92, 245, 534, 1298, 1328, 1335, 1370.
+\I\\{term\_in}, \[32], 33, 34, 36, 37, 71, 1338, 1339.
+\I\\{term\_input}, \[71], \[78].
+\I\\{term\_offset}, \[54], 55, 57, 58, 61, 62, 71, 537, 638, 1280.
+\I\\{term\_only}, \[54], 55, 57, 58, 71, 75, 92, 535, 1298, 1333, 1335.
+\I\\{term\_out}, \[32], 33, 34, 35, 36, 37, 51, 56.
+\I\\{terminal\_input}, \[304], 313, 328, 330, 360.
+\I\\{test\_char}, \[906], 909.
+\I\.{TeX capacity exceeded ...}, 94.
+\I\9{TeX capacity exceeded buffer size}{\quad buffer size}, 35, 328, 374.
+\I\9{TeX capacity exceeded exception dictionary}{\quad exception dictionary}, 940.
+\I\9{TeX capacity exceeded font memory}{\quad font memory}, 580.
+\I\9{TeX capacity exceeded grouping levels}{\quad grouping levels}, 274.
+\I\9{TeX capacity exceeded hash size}{\quad hash size}, 260.
+\I\9{TeX capacity exceeded input stack size}{\quad input stack size}, 321.
+\I\9{TeX capacity exceeded main memory size}{\quad main memory size}, 120, 125.
+\I\9{TeX capacity exceeded number of strings}{\quad number of strings}, 43, 517.
+\I\9{TeX capacity exceeded parameter stack size}{\quad parameter stack size}, 390.
+\I\9{TeX capacity exceeded pattern memory}{\quad pattern memory}, 954, 964.
+\I\9{TeX capacity exceeded pool size}{\quad pool size}, 42.
+\I\9{TeX capacity exceeded save size}{\quad save size}, 273.
+\I\9{TeX capacity exceeded semantic nest size}{\quad semantic nest size}, 216.
+\I\9{TeX capacity exceeded text input levels}{\quad text input levels}, 328.
+\I\.{TEX.POOL check sum...}, 53.
+\I\.{TEX.POOL doesn't match}, 53.
+\I\.{TEX.POOL has no check sum}, 52.
+\I\.{TEX.POOL line doesn't...}, 52.
+\I\\{TEX\_area}, 514, 537, \[1631].
+\I\\{TEX\_font\_area}, 514, 563, \[1632].
+\I\\{TEX\_format\_default}, \[520], 522.
+\I\9{TeXbook}{\sl The \TeX book}, 1, 23, 49, 108, 207, 415, 446, 456, 459, 683, 688, 764, 1215, 1331.
+\I\.{TeXfonts}, 514.
+\I\.{TeXformats}, 11, 520.
+\I\.{TeXinputs}, 514.
+\I\.{texput}, 35, 534, 1257.
+\I\\{text}, \[256], 257, 258, 259, 260, 262, 263, 264, 265, 491, 553, 780, 1188, 1216, 1257, 1318, 1369.
+\I\.{Text line contains...}, 346.
+\I\\{text\_char}, \[19], 25.
+\I\9{text_font_}{\.{\\textfont} primitive}, \[1230].
+\I\\{text\_mlist}, \[689], 695, 698, 731, 1174.
+\I\\{text\_size}, \[699], 703, 732, 762, 1195, 1199.
+\I\\{text\_style}, \[688], 694, 703, 731, 737, 744, 745, 746, 748, 749, 758, 762, 1169, 1194, 1196.
+\I\9{text_style_}{\.{\\textstyle} primitive}, \[1169].
+\I\9{TeX82}{\TeX82}, \[1], 99.
+\I\9{TFM files}{\.{TFM} files}, 539.
+\I\\{tfm\_file}, \[539], 560, 563, 564, 575.
+\I\.{TFtoPL}, 561.
+\I\.{That makes 100 errors...}, 82.
+\I\\{the}, \[210], 265, 266, 366, 367, 478.
+\I\.{The following...deleted}, 641, 992, 1121.
+\I\9{the_}{\.{\\the} primitive}, \[265].
+\I\\{the\_toks}, \[465], 467, 478, 1297.
+\I\\{thick\_mu\_skip}, \[224].
+\I\9{thick_mu_skip_}{\.{\\thickmuskip} primitive}, \[226].
+\I\\{thick\_mu\_skip\_code}, \[224], 225, 226, 766.
+\I\\{thickness}, \[683], 697, 725, 743, 744, 746, 747, 1182.
+\I\\{thin\_mu\_skip}, \[224].
+\I\9{thin_mu_skip_}{\.{\\thinmuskip} primitive}, \[226].
+\I\\{thin\_mu\_skip\_code}, \[224], 225, 226, 229, 766.
+\I\.{This can't happen}, 95.
+\I\9{this can't happen align}{\quad align}, 800.
+\I\9{this can't happen copying}{\quad copying}, 206.
+\I\9{this can't happen curlevel}{\quad curlevel}, 281.
+\I\9{this can't happen disc1}{\quad disc1}, 841.
+\I\9{this can't happen disc2}{\quad disc2}, 842.
+\I\9{this can't happen disc3}{\quad disc3}, 870.
+\I\9{this can't happen disc4}{\quad disc4}, 871.
+\I\9{this can't happen display}{\quad display}, 1200.
+\I\9{this can't happen endv}{\quad endv}, 791.
+\I\9{this can't happen ext1}{\quad ext1}, 1348.
+\I\9{this can't happen ext2}{\quad ext2}, 1357.
+\I\9{this can't happen ext3}{\quad ext3}, 1358.
+\I\9{this can't happen ext4}{\quad ext4}, 1373.
+\I\9{this can't happen flushing}{\quad flushing}, 202.
+\I\9{this can't happen if}{\quad if}, 497.
+\I\9{this can't happen line breaking}{\quad line breaking}, 877.
+\I\9{this can't happen mlist1}{\quad mlist1}, 728.
+\I\9{this can't happen mlist2}{\quad mlist2}, 754.
+\I\9{this can't happen mlist3}{\quad mlist3}, 761.
+\I\9{this can't happen mlist4}{\quad mlist4}, 766.
+\I\9{this can't happen page}{\quad page}, 1000.
+\I\9{this can't happen paragraph}{\quad paragraph}, 866.
+\I\9{this can't happen prefix}{\quad prefix}, 1211.
+\I\9{this can't happen pruning}{\quad pruning}, 968.
+\I\9{this can't happen right}{\quad right}, 1185.
+\I\9{this can't happen rightbrace}{\quad rightbrace}, 1068.
+\I\9{this can't happen vcenter}{\quad vcenter}, 736.
+\I\9{this can't happen vertbreak}{\quad vertbreak}, 973.
+\I\9{this can't happen vlistout}{\quad vlistout}, 630.
+\I\9{this can't happen vpack}{\quad vpack}, 669.
+\I\9{this can't happen 256 spans}{\quad 256 spans}, 798.
+\I\\{this\_box}, \[619], 624, 625, \[629], 633, 634.
+\I\\{this\_if}, \[498], 501, 503, 505, 506.
+\I\\{three\_codes}, \[645].
+\I\\{threshold}, \[828], 851, 854, 863.
+\I\.{Tight \\hbox...}, 667.
+\I\.{Tight \\vbox...}, 678.
+\I\\{tight\_fit}, \[817], 819, 833, 834, 836, 853.
+\I\\{time}, \[236], 241, 536, 617.
+\I\9{time_}{\.{\\time} primitive}, \[238].
+\I\\{time\_code}, \[236], 237, 238.
+\I\\{tini}, 8.
+\I\&{to}, 823.
+\I\.{to}, 645, 1082, 1225.
+\I\\{tok\_val}, \[410], 415, 418, 428, 465.
+\I{token}, 289.
+\I\\{token\_list}, \[307], 311, 312, 323, 325, 330, 337, 341, 346, 390, 1131, 1335.
+\I\\{token\_ref\_count}, \[200], 203, 291, 473, 482, 979.
+\I\\{token\_show}, \[295], 296, 323, 401, 1279, 1284, 1297, 1370.
+\I\\{token\_type}, \[307], 311, 312, 314, 319, 323, 324, 325, 327, 379, 390, 1026, 1095.
+\I\\{toks}, \[230].
+\I\9{toks_}{\.{\\toks} primitive}, \[265].
+\I\\{toks\_base}, \[230], 231, 232, 233, 415, 1224, 1226, 1227.
+\I\9{toks_def_}{\.{\\toksdef} primitive}, \[1222].
+\I\\{toks\_def\_code}, \[1222], 1224.
+\I\\{toks\_register}, \[209], 265, 266, 413, 415, 1210, 1226, 1227.
+\I\\{tolerance}, \[236], 240, 828, 863.
+\I\9{tolerance_}{\.{\\tolerance} primitive}, \[238].
+\I\\{tolerance\_code}, \[236], 237, 238.
+\I\.{Too many \}'s}, 1068.
+\I\\{too\_small}, \[1303], 1306.
+\I\\{top}, \[546].
+\I\\{top\_bot\_mark}, \[210], 296, 366, 367, 384, 385, 386.
+\I\\{top\_edge}, \[629], 636.
+\I\\{top\_mark}, \[382], 383, 1012.
+\I\9{top_mark_}{\.{\\topmark} primitive}, \[384].
+\I\\{top\_mark\_code}, \[382], 384, 386, 1335.
+\I\\{top\_skip}, \[224].
+\I\9{top_skip_}{\.{\\topskip} primitive}, \[226].
+\I\\{top\_skip\_code}, \[224], 225, 226, 1001.
+\I\\{total\_demerits}, \[819], 845, 846, 855, 864, 874, 875.
+\I\9{total_height}{\.{total height}}, 986.
+\I\\{total\_mathex\_params}, \[701], 1195.
+\I\\{total\_mathsy\_params}, \[700], 1195.
+\I\\{total\_pages}, \[592], 593, 617, 640, 642.
+\I\\{total\_shrink}, \[646], 650, 656, 664, 665, 666, 667, 671, 676, 677, 678, 796, 1201.
+\I\\{total\_shrink0}, \[646].
+\I\\{total\_stretch}, \[646], 650, 656, 658, 659, 660, 671, 673, 674, 796.
+\I\\{total\_stretch0}, \[646].
+\I{Trabb Pardo, Luis Isidoro}, 2.
+\I\\{tracing\_commands}, \[236], 367, 498, 509, 1031.
+\I\9{tracing_commands_}{\.{\\tracingcommands} primitive}, \[238].
+\I\\{tracing\_commands\_code}, \[236], 237, 238.
+\I\\{tracing\_lost\_chars}, \[236], 581.
+\I\9{tracing_lost_chars_}{\.{\\tracinglostchars} primitive}, \[238].
+\I\\{tracing\_lost\_chars\_code}, \[236], 237, 238.
+\I\\{tracing\_macros}, \[236], 323, 389, 400.
+\I\9{tracing_macros_}{\.{\\tracingmacros} primitive}, \[238].
+\I\\{tracing\_macros\_code}, \[236], 237, 238.
+\I\\{tracing\_online}, \[236], 245, 1293, 1298.
+\I\9{tracing_online_}{\.{\\tracingonline} primitive}, \[238].
+\I\\{tracing\_online\_code}, \[236], 237, 238.
+\I\\{tracing\_output}, \[236], 638, 641.
+\I\9{tracing_output_}{\.{\\tracingoutput} primitive}, \[238].
+\I\\{tracing\_output\_code}, \[236], 237, 238.
+\I\\{tracing\_pages}, \[236], 987, 1005, 1010.
+\I\9{tracing_pages_}{\.{\\tracingpages} primitive}, \[238].
+\I\\{tracing\_pages\_code}, \[236], 237, 238.
+\I\\{tracing\_paragraphs}, \[236], 845, 855, 863.
+\I\9{tracing_paragraphs_}{\.{\\tracingparagraphs} primitive}, \[238].
+\I\\{tracing\_paragraphs\_code}, \[236], 237, 238.
+\I\\{tracing\_restores}, \[236], 283.
+\I\9{tracing_restores_}{\.{\\tracingrestores} primitive}, \[238].
+\I\\{tracing\_restores\_code}, \[236], 237, 238.
+\I\\{tracing\_stats}, 117, \[236], 639, 1326, 1333.
+\I\9{tracing_stats_}{\.{\\tracingstats} primitive}, \[238].
+\I\\{tracing\_stats\_code}, \[236], 237, 238.
+\I\.{Transcript written...}, 1333.
+\I\\{trap\_zero\_glue}, 1228, \[1229], 1236.
+\I\\{trick\_buf}, \[54], 58, 315, 317.
+\I\\{trick\_count}, \[54], 58, 315, 316, 317.
+\I{Trickey, Howard Wellington}, 2.
+\I\\{trie}, 920, \[921], 922, 950, 952, 953, 954, 958, 959, 966, 1324, 1325.
+\I\\{trie\_back}, \[950], 954, 956.
+\I\\{trie\_c}, \[947], 948, 951, 953, 955, 956, 959, 963, 964.
+\I\\{trie\_char}, 920, \[921], 923, 958, 959.
+\I\\{trie\_fix}, 958, \[959].
+\I\\{trie\_hash}, \[947], 948, 949, 950, 952.
+\I\\{trie\_l}, \[947], 948, 949, 957, 959, 960, 963, 964.
+\I\\{trie\_link}, 920, \[921], 923, 950, 952, 953, 954, 955, 956, 958, 959.
+\I\\{trie\_max}, \[950], 952, 954, 958, 1324, 1325.
+\I\\{trie\_min}, \[950], 952, 953, 956.
+\I\\{trie\_node}, \[948], 949.
+\I\\{trie\_not\_ready}, 891, \[950], 951, 960, 966, 1324, 1325.
+\I\\{trie\_o}, \[947], 948, 959, 963, 964.
+\I\\{trie\_op}, 920, \[921], 923, 924, 943, 958, 959.
+\I\\{trie\_op\_hash}, \[943], 944, 945, 946, 948, 952.
+\I\\{trie\_op\_hash0}, \[943].
+\I\\{trie\_op\_lang}, \[943], 944, 945, 952.
+\I\\{trie\_op\_lang0}, \[943].
+\I\\{trie\_op\_ptr}, \[943], 944, 945, 946, 1324, 1325.
+\I\\{trie\_op\_size}, \[11], 921, 943, 944, 946, 1324, 1325.
+\I\\{trie\_op\_val}, \[943], 944, 945, 952.
+\I\\{trie\_op\_val0}, \[943].
+\I\\{trie\_pack}, \[957], 966.
+\I\&{trie\_pointer}, \[920], 922, 947, 948, 949, 950, 953, 957, 959, 960, 966.
+\I\\{trie\_ptr}, \[947], 951, 952, 964.
+\I\\{trie\_r}, \[947], 948, 949, 955, 956, 957, 959, 963, 964.
+\I\\{trie\_ref}, \[950], 952, 953, 956, 957, 959.
+\I\\{trie\_root}, \[947], 949, 951, 952, 958, 966.
+\I\\{trie\_size}, \[11], 921, 947, 948, 950, 952, 954, 964, 1325.
+\I\\{trie\_taken}, \[950], 952, 953, 954, 956.
+\I\\{trie\_taken0}, \[950].
+\I\\{trie\_used}, \[943], 944, 945, 946, 1324, 1325.
+\I\\{true}, 16, 31, 37, 45, 46, 49, 51, 53, 71, 77, 88, 97, 98, 104, 105, 106, 107, 168, 169, 256, 257, 259, 311, 327, 328, 336, 346, 361, 362, 365, 374, 378, 407, 413, 430, 440, 444, 447, 453, 461, 462, 486, 501, 508, 512, 516, 523, 525, 534, 563, 578,
+592, 621, 628, 637, 638, 641, 663, 675, 706, 719, 791, 827, 828, 829, 851, 854, 863, 880, 882, 884, 903, 905, 910, 911, 951, 956, 962, 963, 992, 1020, 1021, 1025, 1030, 1035, 1037, 1040, 1051, 1054, 1083, 1090, 1101, 1121, 1163, 1194, 1195, 1218, 1253,
+1258, 1270, 1279, 1283, 1298, 1303, 1336, 1342, 1354, 1371, 1374.
+\I\.{true}, 453.
+\I\\{try\_break}, 828, \[829], 839, 851, 858, 862, 866, 868, 869, 873, 879.
+\I\\{two}, \[101], 102.
+\I\&{two\_choices}, \[113].
+\I\&{two\_halves}, \[113], 118, 124, 172, 221, 256, 684, 921, 966.
+\I\\{type}, 4, \[9], \[133], 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 152, 153, 155, 156, 157, 158, 159, 160, 175, 183, 184, 202, 206, 424, 489, 495, 496, 497, 505, 622, 623, 626, 628, 631, 632, 635, 637, 640,
+649, 651, 653, 655, 668, 669, 670, 680, 681, 682, 683, 686, 687, 688, 689, 696, 698, 713, 715, 720, 721, 726, 727, 728, 729, 731, 732, 736, 747, 750, 752, 761, 762, 767, 768, 796, 799, 801, 805, 807, 809, 810, 811, 816, 819, 820, 822, 830, 832, 837, 841,
+842, 843, 844, 845, 856, 858, 859, 860, 861, 862, 864, 865, 866, 868, 870, 871, 874, 875, 879, 881, 896, 897, 899, 903, 914, 968, 970, 972, 973, 976, 978, 979, 981, 986, 988, 993, 996, 997, 1000, 1004, 1008, 1009, 1010, 1011, 1013, 1014, 1021, 1074,
+1080, 1081, 1087, 1100, 1101, 1105, 1110, 1113, 1121, 1147, 1155, 1158, 1159, 1163, 1165, 1168, 1181, 1185, 1186, 1191, 1202, 1203, 1341, 1349.
+\I\.{Type <return> to proceed...}, 85.
+\I\|{u}, \[69], \[107], \[389], \[560], \[706], \[791], \[800], \[929], \[934], \[944], \[1257].
+\I\\{u\_part}, 768, \[769], 779, 788, 794, 801.
+\I\\{u\_template}, \[307], 314, 324, 788.
+\I\\{uc\_code}, \[230], 232, 407.
+\I\9{uc_code_}{\.{\\uccode} primitive}, \[1230].
+\I\\{uc\_code\_base}, \[230], 235, 1230, 1231, 1286, 1288.
+\I\\{uc\_hyph}, \[236], 891, 896.
+\I\9{uc_hyph_}{\.{\\uchyph} primitive}, \[238].
+\I\\{uc\_hyph\_code}, \[236], 237, 238.
+\I\&{uint16\_t}, 30, 31, 38, 113, 271, 315, 341, 366, 523, 529, 534, 548, 549, 560, 594, 892, 920, 921, 925, 943, 944, 953.
+\I\&{uint32\_t}, \[101], 450.
+\I\&{uint8\_t}, 18, 20, 25, 26, 38, 47, 54, 65, 67, 73, 76, 79, 101, 113, 150, 204, 213, 246, 269, 301, 304, 305, 308, 310, 311, 315, 341, 387, 410, 413, 465, 470, 480, 489, 498, 534, 548, 560, 619, 629, 638, 645, 830, 893, 900, 912, 934, 960, 980, 994,
+1012, 1110, 1236, 1244, 1245, 1246, 1257, 1275, 1279, 1368, 1370.
+\I\\{un\_hbox}, \[208], 1090, 1107, 1108, 1109.
+\I\9{un_hbox_}{\.{\\unhbox} primitive}, \[1107].
+\I\9{un_hcopy_}{\.{\\unhcopy} primitive}, \[1107].
+\I\9{un_kern_}{\.{\\unkern} primitive}, \[1107].
+\I\9{un_penalty_}{\.{\\unpenalty} primitive}, \[1107].
+\I\9{un_skip_}{\.{\\unskip} primitive}, \[1107].
+\I\\{un\_vbox}, \[208], 1046, 1094, 1107, 1108, 1109.
+\I\9{un_vbox_}{\.{\\unvbox} primitive}, \[1107].
+\I\9{un_vcopy_}{\.{\\unvcopy} primitive}, \[1107].
+\I\\{unbalance}, \[389], 391, 396, 399, \[473], 477.
+\I\.{Unbalanced output routine}, 1027.
+\I\.{Unbalanced write...}, 1372.
+\I\.{Undefined control sequence}, 370.
+\I\\{undefined\_control\_sequence}, \[222], 232, 256, 257, 259, 262, 268, 282, 290, 1318, 1319.
+\I\\{undefined\_cs}, \[210], 222, 366, 372, 1226, 1227, 1295.
+\I\\{under\_noad}, \[687], 690, 696, 698, 733, 761, 1156, 1157.
+\I\.{Underfull \\hbox...}, 660.
+\I\.{Underfull \\vbox...}, 674.
+\I\9{underline_}{\.{\\underline} primitive}, \[1156].
+\I\\{undump}, \[1306], 1310, 1312, 1314, 1319, 1323, 1325, 1327.
+\I\\{undump\_end}, \[1306].
+\I\\{undump\_end\_end}, \[1306].
+\I\\{undump\_four\_ASCII}, \[1310].
+\I\\{undump\_hh}, \[1306], 1319, 1325.
+\I\\{undump\_int}, \[1306], 1308, 1312, 1317, 1319, 1323, 1327.
+\I\\{undump\_qqqq}, \[1306], 1310, 1323.
+\I\\{undump\_size}, \[1306], 1310, 1321, 1325.
+\I\\{undump\_size\_end}, \[1306].
+\I\\{undump\_size\_end\_end}, \[1306].
+\I\\{undump\_wd}, \[1306], 1312, 1317, 1321.
+\I\\{unfloat}, \[109], 658, 664, 673, 676, 810, 811.
+\I\\{unhyphenated}, \[819], 829, 837, 864, 866, 868.
+\I\\{unity}, \[101], 103, 114, 164, 186, 453, 568, 1259.
+\I\\{unpackage}, 1109, \[1110].
+\I\\{unsave}, \[281], 283, 791, 800, 1026, 1063, 1068, 1086, 1100, 1119, 1133, 1168, 1174, 1186, 1191, 1194, 1196, 1200.
+\I\\{unset\_node}, 136, \[159], 175, 183, 184, 202, 206, 651, 669, 682, 688, 689, 768, 796, 799, 801, 805.
+\I\\{update\_active}, \[861].
+\I\\{update\_heights}, \[972], 973, \[997], 1000.
+\I\\{update\_terminal}, \[34], 37, 61, 71, 86, 362, 523, 537, 638, 1280, 1338.
+\I\\{update\_width}, \[832], 860.
+\I\9{uppercase_}{\.{\\uppercase} primitive}, \[1286].
+\I\.{Use of x doesn't match...}, 398.
+\I\\{use\_err\_help}, \[79], 80, 89, 90, 1283.
+\I\|{v}, \[69], \[107], \[389], \[450], \[706], \[715], \[736], \[743], \[749], \[800], \[830], \[922], \[934], \[944], \[960], \[977], \[1138], \[1146], \[1147], \[1148].
+\I\\{v\_offset}, \[247], 640, 641.
+\I\9{v_offset_}{\.{\\voffset} primitive}, \[248].
+\I\\{v\_offset\_code}, \[247], 248.
+\I\\{v\_part}, 768, \[769], 779, 789, 794, 801.
+\I\\{v\_template}, \[307], 314, 325, 390, 789, 1131.
+\I\\{vacuous}, \[440], 444, 445.
+\I\\{vadjust}, \[208], 265, 266, 1097, 1098, 1099, 1100.
+\I\9{vadjust_}{\.{\\vadjust} primitive}, \[265].
+\I\\{valign}, \[208], 265, 266, 1046, 1090, 1130.
+\I\9{valign_}{\.{\\valign} primitive}, \[265].
+\I\\{var\_code}, \[232], 1151, 1155, 1165.
+\I\\{var\_delimiter}, \[706], 737, 748, 762.
+\I\\{var\_used}, \[117], 125, 130, 164, 639, 1311, 1312.
+\I\\{vbadness}, \[236], 674, 677, 678, 1012, 1017.
+\I\9{vbadness_}{\.{\\vbadness} primitive}, \[238].
+\I\\{vbadness\_code}, \[236], 237, 238.
+\I\9{vbox_}{\.{\\vbox} primitive}, \[1071].
+\I\\{vbox\_group}, \[269], 1083, 1085.
+\I\\{vcenter}, \[208], 265, 266, 1046, 1167.
+\I\9{vcenter_}{\.{\\vcenter} primitive}, \[265].
+\I\\{vcenter\_group}, \[269], 1167, 1168.
+\I\\{vcenter\_noad}, \[687], 690, 696, 698, 733, 761, 1168.
+\I\\{vert\_break}, \[970], 971, 976, 977, 980, 982, 1010.
+\I\\{very\_loose\_fit}, \[817], 819, 833, 834, 836, 852.
+\I\\{vet\_glue}, \[625], 634.
+\I\9{vfil_}{\.{\\vfil} primitive}, \[1058].
+\I\9{vfil_neg_}{\.{\\vfilneg} primitive}, \[1058].
+\I\9{vfill_}{\.{\\vfill} primitive}, \[1058].
+\I\\{vfuzz}, \[247], 677, 1012, 1017.
+\I\9{vfuzz_}{\.{\\vfuzz} primitive}, \[248].
+\I\\{vfuzz\_code}, \[247], 248.
+\I\.{VIRTEX}, 1331.
+\I{virtual memory}, 126.
+\I{Vitter, Jeffrey Scott}, 261.
+\I\\{vlist\_node}, \[137], 148, 159, 175, 183, 184, 202, 206, 505, 618, 622, 623, 628, 629, 631, 632, 637, 640, 644, 651, 668, 669, 681, 713, 715, 720, 736, 747, 750, 807, 809, 811, 841, 842, 866, 870, 871, 968, 973, 978, 1000, 1074, 1080, 1087, 1110,
+1147.
+\I\\{vlist\_out}, 592, 615, 616, \[618], 619, 623, 628, \[629], 632, 637, 638, 640, 693, 1373.
+\I\\{vmode}, \[211], 215, 416, 417, 418, 422, 424, 501, 775, 785, 786, 804, 807, 808, 809, 812, 1025, 1029, 1045, 1046, 1048, 1056, 1057, 1071, 1072, 1073, 1076, 1078, 1079, 1080, 1083, 1090, 1091, 1094, 1098, 1099, 1103, 1105, 1109, 1110, 1111, 1130,
+1167, 1243, 1244.
+\I\\{vmove}, \[208], 1048, 1071, 1072, 1073.
+\I\\{vpack}, 236, 644, 645, 646, \[668], 705, 735, 738, 759, 799, 804, 977, 1021, 1100, 1168.
+\I\\{vpackage}, \[668], 796, 977, 1017, 1086.
+\I\\{vrule}, \[208], 265, 266, 463, 1056, 1084, 1090.
+\I\9{vrule_}{\.{\\vrule} primitive}, \[265].
+\I\\{vsize}, \[247], 980, 987.
+\I\9{vsize_}{\.{\\vsize} primitive}, \[248].
+\I\\{vsize\_code}, \[247], 248.
+\I\\{vskip}, \[208], 1046, 1057, 1058, 1059, 1078, 1094.
+\I\9{vskip_}{\.{\\vskip} primitive}, \[1058].
+\I\\{vsplit}, 967, \[977], 980, 1082.
+\I\9{vsplit_}{\.{\\vsplit needs a \\vbox}}, 978.
+\I\9{vsplit_}{\.{\\vsplit} primitive}, \[1071].
+\I\\{vsplit\_code}, \[1071], 1072, 1079.
+\I\9{vss_}{\.{\\vss} primitive}, \[1058].
+\I\9{vtop_}{\.{\\vtop} primitive}, \[1071].
+\I\\{vtop\_code}, \[1071], 1072, 1083, 1085, 1086.
+\I\\{vtop\_group}, \[269], 1083, 1085.
+\I\|{w}, \[114], \[147], \[156], \[275], \[278], \[279], \[607], \[649], \[668], \[706], \[715], \[738], \[791], \[800], \[906], \[994], \[1123], \[1138], \[1145], \[1146], \[1198], \[1302], \[1303], \[1349], \[1350].
+\I\\{w\_close}, \[28], 1329, 1337.
+\I\\{w\_make\_name\_string}, \[524], 1328.
+\I\\{w\_open\_in}, \[27], 523.
+\I\\{w\_open\_out}, \[27], 1328.
+\I\\{wait}, \[1012], \[1020], \[1021], 1022.
+\I\\{wake\_up\_terminal}, \[34], 37, 51, 71, 73, 363, 484, 523, 529, 1294, 1297, 1303, 1333, 1338.
+\I\\{warning\_index}, \[305], 331, 338, 389, 390, 395, 396, 398, 401, 473, 479, 482, 774, 777.
+\I\\{warning\_issued}, \[76], 245, 1335.
+\I\\{was\_free}, \[165], 167, 171.
+\I\\{was\_free0}, \[165].
+\I\\{was\_hi\_min}, \[165], 166, 167, 171.
+\I\\{was\_lo\_max}, \[165], 166, 167, 171.
+\I\\{was\_mem\_end}, \[165], 166, 167, 171.
+\I\9{wd_}{\.{\\wd} primitive}, \[416].
+\I\.{WEB}, 1, 4, 38, 40, 50, 1308.
+\I\\{what\_lang}, \[1341], 1356, 1362, 1376, 1377.
+\I\\{what\_lhm}, \[1341], 1356, 1362, 1376, 1377.
+\I\\{what\_rhm}, \[1341], 1356, 1362, 1376, 1377.
+\I\\{whatsit\_node}, \[146], 148, 175, 183, 202, 206, 622, 631, 651, 669, 730, 761, 866, 896, 899, 968, 973, 1000, 1147, 1341, 1349.
+\I\\{widow\_penalty}, \[236], 1096.
+\I\9{widow_penalty_}{\.{\\widowpenalty} primitive}, \[238].
+\I\\{widow\_penalty\_code}, \[236], 237, 238.
+\I\.{width}, 463.
+\I\\{width}, \[135], 136, 138, 139, 147, 150, 151, 155, 156, 178, 184, 187, 191, 192, 424, 429, 431, 451, 462, 463, 554, 605, 607, 611, 622, 623, 625, 626, 631, 633, 634, 635, 641, 651, 653, 656, 657, 666, 668, 669, 670, 671, 679, 683, 688, 706, 709,
+714, 715, 716, 717, 731, 738, 744, 747, 749, 750, 757, 758, 759, 768, 779, 793, 796, 797, 798, 801, 802, 803, 804, 806, 807, 808, 809, 810, 811, 827, 837, 838, 841, 842, 866, 868, 870, 871, 881, 969, 976, 996, 1001, 1004, 1009, 1042, 1044, 1054, 1091,
+1093, 1147, 1148, 1199, 1201, 1205, 1229, 1239, 1240.
+\I\\{width\_base}, \[550], 552, 554, 566, 569, 571, 576, 1322, 1323.
+\I\\{width\_base0}, \[550].
+\I\\{width\_index}, \[543], 550.
+\I\\{width\_offset}, \[135], 416, 417, 1247.
+\I{Wirth, Niklaus}, 10.
+\I\\{wlog}, \[56], 58, 536, 1334.
+\I\\{wlog\_cr}, \[56], 57, 58, 1333.
+\I\\{wlog\_ln}, \[56], 1334.
+\I\\{word\_define}, \[1214], 1228, 1232, 1236.
+\I\&{word\_file}, 25, 27, 28, \[113], 524, 1305.
+\I\\{words}, \[204], 205, 206, 1357.
+\I\\{wrap\_lig}, \[910], 911.
+\I\\{wrapup}, \[1035], 1040.
+\I\\{write}, 37, \[56], 58, 597.
+\I\9{write_}{\.{\\write} primitive}, \[1344].
+\I\\{write\_dvi}, \[597], 598, 599.
+\I\\{write\_file}, 57, 58, \[1342], 1374, 1378.
+\I\\{write\_ln}, 35, 37, 51, \[56], 57.
+\I\\{write\_loc}, 1313, 1314, 1344, \[1345], 1371.
+\I\\{write\_node}, \[1341], 1344, 1346, 1348, 1356, 1357, 1358, 1373, 1374.
+\I\\{write\_node\_size}, \[1341], 1350, 1352, 1353, 1354, 1357, 1358.
+\I\\{write\_open}, \[1342], 1343, 1370, 1374, 1378.
+\I\\{write\_out}, \[1370], 1374.
+\I\\{write\_stream}, \[1341], 1350, 1354, 1355, 1370, 1374.
+\I\\{write\_text}, \[307], 314, 323, 1340, 1371.
+\I\\{write\_tokens}, \[1341], 1352, 1353, 1354, 1356, 1357, 1358, 1368, 1371.
+\I\\{writing}, \[578].
+\I\\{wterm}, \[56], 58, 61.
+\I\\{wterm\_cr}, \[56], 57, 58.
+\I\\{wterm\_ln}, \[56], 61, 523, 1303, 1332.
+\I{Wyatt, Douglas Kirk}, 2.
+\I\\{w0}, 585, \[586], 604, 609.
+\I\\{w1}, 585, \[586], 607.
+\I\\{w2}, \[585].
+\I\\{w3}, \[585].
+\I\\{w4}, \[585].
+\I\|{X}, \[347].
+\I\|{x}, \[100], \[105], \[106], \[107], \[587], \[600], \[649], \[668], \[706], \[720], \[726], \[735], \[737], \[738], \[743], \[749], \[756], \[1123], \[1302], \[1303].
+\I\\{x\_height}, 547, \[558], 559, 738, 1123.
+\I\\{x\_height\_code}, \[547], 558.
+\I\\{x\_leaders}, \[149], 190, 627, 1071, 1072.
+\I\9{x_leaders_}{\.{\\xleaders} primitive}, \[1071].
+\I\\{x\_over\_n}, \[106], 703, 716, 717, 986, 1008, 1009, 1010, 1240.
+\I\\{x\_token}, 364, \[381], 478, 1038, 1152.
+\I\\{xchr}, \[20], 21, 23, 24, 38, 49, 58, 519.
+\I\9{xdef_}{\.{\\xdef} primitive}, \[1208].
+\I\\{xeq\_level}, \[253], 254, 268, 278, 279, 283, 1304.
+\I\\{xeq\_level0}, \[253].
+\I\\{xn\_over\_d}, \[107], 455, 457, 458, 568, 716, 1044, 1260.
+\I\\{xord}, \[20], 24, 31, 52, 53, 522, 524.
+\I\\{xpand}, \[473], 477, 479.
+\I\\{xray}, \[208], 1290, 1291, 1292.
+\I\\{xspace\_skip}, \[224], 1043.
+\I\9{xspace_skip_}{\.{\\xspaceskip} primitive}, \[226].
+\I\\{xspace\_skip\_code}, \[224], 225, 226, 1043.
+\I\\{xxx1}, 585, \[586], 1368.
+\I\\{xxx2}, \[585].
+\I\\{xxx3}, \[585].
+\I\\{xxx4}, 585, \[586], 1368.
+\I\\{x0}, 585, \[586], 604, 609.
+\I\\{x1}, 585, \[586], 607.
+\I\\{x2}, \[585].
+\I\\{x3}, \[585].
+\I\\{x4}, \[585].
+\I\|{y}, \[105], \[706], \[726], \[735], \[737], \[738], \[743], \[749], \[756].
+\I\\{y\_here}, \[608], 609, 611, 612, 613.
+\I\\{y\_OK}, \[608], 609, 612.
+\I\\{y\_seen}, \[611], 612.
+\I\\{year}, \[236], 241, 536, 617, 1328.
+\I\9{year_}{\.{\\year} primitive}, \[238].
+\I\\{year\_code}, \[236], 237, 238.
+\I\.{You already have nine...}, 476.
+\I\.{You can't \\insert255}, 1099.
+\I\.{You can't dump...}, 1304.
+\I\.{You can't use \\hrule...}, 1095.
+\I\.{You can't use \\long...}, 1213.
+\I\.{You can't use a prefix with x}, 1212.
+\I\.{You can't use x after ...}, 428, 1237.
+\I\.{You can't use x in y mode}, 1049.
+\I\.{You have to increase POOLSIZE}, 52.
+\I\.{You want to edit file x}, 84.
+\I\\{you\_cant}, \[1049], 1050, 1080, 1106.
+\I\\{yz\_OK}, \[608], 609, 610, 612.
+\I\\{y0}, 585, \[586], 594, 604, 609.
+\I\\{y1}, 585, \[586], 607, 613.
+\I\\{y2}, \[585], 594.
+\I\\{y3}, \[585].
+\I\\{y4}, \[585].
+\I\|{z}, \[560], \[706], \[726], \[743], \[749], \[756], \[922], \[927], \[953], \[959], \[1198].
+\I\\{z\_here}, \[608], 609, 611, 612, 614.
+\I\\{z\_OK}, \[608], 609, 612.
+\I\\{z\_seen}, \[611], 612.
+\I{Zabala Salelles, Ignacio Andr\'es}, 2.
+\I\\{zero\_glue}, \[162], 175, 224, 228, 424, 462, 732, 802, 887, 1041, 1042, 1043, 1171, 1229.
+\I\\{zero\_token}, \[445], 452, 473, 476, 479.
+\I\\{z0}, 585, \[586], 604, 609.
+\I\\{z1}, 585, \[586], 607, 614.
+\I\\{z2}, \[585].
+\I\\{z3}, \[585].
+\I\\{z4}, \[585].
diff --git a/web/web2w/ctex.patch b/web/web2w/ctex.patch
new file mode 100644
index 0000000000..15957aede9
--- /dev/null
+++ b/web/web2w/ctex.patch
@@ -0,0 +1,907 @@
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+--- hint.w 2017-07-28 10:40:38.023223082 +0200
++++ tex.w 2017-07-28 10:43:49.801661332 +0200
+@@ -73,11 +73,6 @@
+ \def\(#1){} % this is used to make section names sort themselves better
+ \def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
+
+-\outer\def\N#1. \[#2]#3.{\MN#1.\vfil\eject % begin starred section
+- \def\rhead{PART #2:\uppercase{#3}} % define running headline
+- \message{*\modno} % progress report
+- \edef\next{\write\cont{\Z{\?#2]#3}{\modno}{\the\pageno}}}\next
+- \ifon\startsection{\bf\ignorespaces#3.\quad}\ignorespaces}
+ \let\?=\relax % we want to be able to \write a \?
+
+ \def\title{\TeX82}
+@@ -90,6 +85,22 @@
+ \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
++@s dotdot TeX
+ @* Introduction.
+ This is \TeX, a document compiler intended to produce typesetting of high
+ quality.
+@@ -188,7 +199,7 @@
+ known as `\TeX' [cf.~Stanford Computer Science report CS1027,
+ November 1984].
+
+-@d banner "This is TeX, Version 3.14159265" /*printed when \TeX\ starts*/
++@d banner "This is TeX, Version 3.14159265 (HINT)" /*printed when \TeX\ starts*/
+
+ @ Different \PASCAL s have slightly different conventions, and the present
+ @!@:PASCAL H}{\ph@>
+@@ -318,12 +329,33 @@
+ @^system dependencies@>
+ @^overflow in arithmetic@>
+
++@s int8_t int
++@s uint8_t int
++@s uint16_t int
++@s halfword int
++@s in TeX
++@s line normal
++@s to do
++
+ @<Compiler directives@>=
+-/*@&$C-,A+,D-*/ /*no range check, catch arithmetic overflow, no debug overhead*/
+-#ifdef @!DEBUG
+-/*@&$C+,D+*/
++#include <stdint.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <math.h>
++
++#define odd(X) ((X)&1)
++#define chr(X) ((unsigned char)(X))
++#define ord(X) ((int)(X))
++
++#if __SIZEOF_FLOAT__==4
++typedef float float32_t;
++#else
++#error float type must have size 4
+ #endif
+- /*but turn everything on when debugging*/
++
++@h
+
+ @ This \TeX\ implementation conforms to the rules of the {\sl Pascal User
+ @:PASCAL}{\PASCAL@>
+@@ -757,7 +789,7 @@
+ @^system dependencies@>
+
+ @<Glob...@>=
+-uint8_t @!name_of_file0[file_name_size], *const @!name_of_file = @!name_of_file0-1;@;@/
++uint8_t @!name_of_file0[file_name_size+1]={0}, *const @!name_of_file = @!name_of_file0-1;@;@/
+ /*on some systems this may be a \&{record} variable*/
+ uint8_t @!name_length;@/ /*this many characters are actually
+ relevant in |name_of_file| (the rest are blank)*/
+@@ -790,32 +822,32 @@
+
+ @p bool a_open_in(alpha_file *f)
+ /*open a text file for input*/
+-{@+reset((*f), name_of_file,"/O");return reset_OK((*f));
++{@+reset((*f), name_of_file,"r");return reset_OK((*f));
+ }
+ @#
+ bool a_open_out(alpha_file *f)
+ /*open a text file for output*/
+-{@+rewrite((*f), name_of_file,"/O");return rewrite_OK((*f));
++{@+rewrite((*f), name_of_file,"w");return rewrite_OK((*f));
+ }
+ @#
+ bool b_open_in(byte_file *f)
+ /*open a binary file for input*/
+-{@+reset((*f), name_of_file,"/O");return reset_OK((*f));
++{@+reset((*f), name_of_file,"rb");return reset_OK((*f));
+ }
+ @#
+ bool b_open_out(byte_file *f)
+ /*open a binary file for output*/
+-{@+rewrite((*f), name_of_file,"/O");return rewrite_OK((*f));
++{@+rewrite((*f), name_of_file,"wb");return rewrite_OK((*f));
+ }
+ @#
+ bool w_open_in(word_file *f)
+ /*open a word file for input*/
+-{@+reset((*f), name_of_file,"/O");return reset_OK((*f));
++{@+reset((*f), name_of_file,"rb");return reset_OK((*f));
+ }
+ @#
+ bool w_open_out(word_file *f)
+ /*open a word file for output*/
+-{@+rewrite((*f), name_of_file,"/O");return rewrite_OK((*f));
++{@+rewrite((*f), name_of_file,"wb");return rewrite_OK((*f));
+ }
+
+ @ Files can be closed with the \ph\ routine `|close(f)|', which
+@@ -938,8 +970,8 @@
+ @:PASCAL H}{\ph@>
+ @^system dependencies@>
+
+-@d t_open_in reset(term_in,"TTY:","/O/I") /*open the terminal for text input*/
+-@d t_open_out rewrite(term_out,"TTY:","/O") /*open the terminal for text output*/
++@d t_open_in term_in.f=stdin /*open the terminal for text input*/
++@d t_open_out term_out.f=stdout /*open the terminal for text output*/
+
+ @ Sometimes it is necessary to synchronize the input/output mixture that
+ happens on the user's terminal, and three system-dependent
+@@ -956,8 +988,8 @@
+ @:PASCAL H}{\ph@>
+ @^system dependencies@>
+
+-@d update_terminal break(term_out) /*empty the terminal output buffer*/
+-@d clear_terminal break_in(term_in, true) /*clear the terminal input buffer*/
++@d update_terminal fflush(term_out.f) /*empty the terminal output buffer*/
++@d clear_terminal fflush(term_in.f) /*clear the terminal input buffer*/
+ @d wake_up_terminal do_nothing /*cancel the user's cancellation of output*/
+
+ @ We need a special routine to read the first line of \TeX\ input from
+@@ -1103,10 +1135,11 @@
+ typedef uint8_t packed_ASCII_code; /*elements of |str_pool| array*/
+
+ @ @<Glob...@>=
+-packed_ASCII_code @!str_pool[pool_size+1]; /*the characters*/
+-pool_pointer @!str_start[max_strings+1]; /*the starting pointers*/
+-pool_pointer @!pool_ptr; /*first unused position in |str_pool|*/
+-str_number @!str_ptr; /*number of the current string being created*/
++@<prepare for string pool initialization@>@;
++packed_ASCII_code @!str_pool[pool_size+1]= @<|str_pool| initialization@>; /*the characters*/
++pool_pointer @!str_start[max_strings+1]= {@<|str_start| initialization@>}; /*the starting pointers*/
++pool_pointer @!pool_ptr=@<|pool_ptr| initialization@>; /*first unused position in |str_pool|*/
++str_number @!str_ptr=@<|str_ptr| initialization@>; /*number of the current string being created*/
+ pool_pointer @!init_pool_ptr; /*the starting value of |pool_ptr|*/
+ str_number @!init_str_ptr; /*the starting value of |str_ptr|*/
+
+@@ -1231,11 +1264,11 @@
+
+ @<Make the first 256...@>=
+ for (k=0; k<=255; k++)
+- {@+if ((@<Character |k| cannot be printed@>))
+- {@+append_char('^');append_char('^');
++ { if (@[@<Character |k| cannot be printed@>@])
++ { append_char('^');append_char('^');
+ if (k < 0100) append_char(k+0100)@;
+ else if (k < 0200) append_char(k-0100)@;
+- else{@+app_lc_hex(k/16);app_lc_hex(k%16);
++ else{ app_lc_hex(k/16);app_lc_hex(k%16);
+ }
+ }
+ else append_char(k);
+@@ -1289,7 +1322,7 @@
+ a_close(&pool_file);return false;
+ }
+ @<Read the other strings...@>=
+-name_of_file=pool_name; /*we needn't set |name_length|*/
++{@+int k;@+for(k=1; k<=file_name_size;k++)name_of_file[k]=pool_name[k-1];@+} /*we needn't set |name_length|*/
+ if (a_open_in(&pool_file))
+ {@+c=false;
+ @/do@+{@<Read one string, but return |false| if the string memory space is getting
+@@ -1303,7 +1336,7 @@
+ @ @<Read one string...@>=
+ {@+if (eof(pool_file)) bad_pool("! TEX.POOL has no check sum.");
+ @.TEX.POOL has no check sum@>
+-read(pool_file, m, n); /*read two digits of string length*/
++read(pool_file, m);@+read(pool_file, n); /*read two digits of string length*/
+ if (m== '*' ) @<Check the pool check sum@>@;
+ else{@+if ((xord[m] < '0')||(xord[m] > '9')||@|
+ (xord[n] < '0')||(xord[n] > '9'))
+@@ -1411,12 +1444,30 @@
+ by changing |wterm|, |wterm_ln|, and |wterm_cr| in this section.
+ @^system dependencies@>
+
+-@d wterm(X) write(term_out, X)
+-@d wterm_ln(...) write_ln(term_out,__VA_ARGS__)
+-@d wterm_cr write_ln(term_out)
+-@d wlog(...) write(log_file,__VA_ARGS__)
+-@d wlog_ln(...) write_ln(log_file,__VA_ARGS__)
+-@d wlog_cr write_ln(log_file)
++@<Compiler directives@>=
++#define put(file) @[fwrite(&((file).d),sizeof((file).d),1,(file).f)@]
++#define get(file) @[fread(&((file).d),sizeof((file).d),1,(file).f)@]
++
++#define reset(file,name,mode) @[((file).f=fopen((char *)(name)+1,mode),\
++ (file).f!=NULL?get(file):0)@]
++#define rewrite(file,name,mode) @[((file).f=fopen((char *)(name)+1,mode))@]
++#define close(file) @[fclose((file).f)@]
++#define eof(file) @[feof((file).f)@]
++#define eoln(file) @[((file).d=='\n'||eof(file))@]
++#define erstat(file) @[((file).f==NULL?-1:ferror((file).f))@]
++
++#define read(file,x) @[((x)=(file).d,get(file))@]
++#define read_ln(file) @[do get(file); while (!eoln(file))@]
++
++#define write(file, format,...) @[fprintf(file.f,format,## __VA_ARGS__)@]
++#define write_ln(file,...) @[write(file,__VA_ARGS__"\n")@]
++
++#define wterm(format,...) @[write(term_out,format, ## __VA_ARGS__)@]
++#define wterm_ln(format,...) @[wterm(format "\n", ## __VA_ARGS__)@]
++#define wterm_cr @[write(term_out,"\n")@]
++#define wlog(format, ...) @[write(log_file,format, ## __VA_ARGS__)@]
++#define wlog_ln(format, ...) @[wlog(format "\n", ## __VA_ARGS__)@]
++#define wlog_cr @[write(log_file,"\n")@]
+
+ @ To end a line of text output, we call |print_ln|.
+
+@@ -1447,7 +1498,7 @@
+ {@+print_ln();return;
+ }
+ switch (selector) {
+-case term_and_log: {@+wterm(xchr[s]);wlog(xchr[s]);
++case term_and_log: {@+wterm("%c",xchr[s]);wlog("%c",xchr[s]);
+ incr(term_offset);incr(file_offset);
+ if (term_offset==max_print_line)
+ {@+wterm_cr;term_offset=0;
+@@ -1456,17 +1507,17 @@
+ {@+wlog_cr;file_offset=0;
+ }
+ } @+break;
+-case log_only: {@+wlog(xchr[s]);incr(file_offset);
++case log_only: {@+wlog("%c",xchr[s]);incr(file_offset);
+ if (file_offset==max_print_line) print_ln();
+ } @+break;
+-case term_only: {@+wterm(xchr[s]);incr(term_offset);
++case term_only: {@+wterm("%c",xchr[s]);incr(term_offset);
+ if (term_offset==max_print_line) print_ln();
+ } @+break;
+ case no_print: do_nothing;@+break;
+ case pseudo: if (tally < trick_count) trick_buf[tally%error_line]=s;@+break;
+ case new_string: {@+if (pool_ptr < pool_size) append_char(s);
+ } @+break; /*we drop characters if the string space is full*/
+-default:write(write_file[selector], xchr[s]);
++default:write(write_file[selector],"%c", xchr[s]);
+ } @/
+ incr(tally);
+ }
+@@ -1509,6 +1560,10 @@
+ }
+ }
+
++void print_str(char *s) /* the simple version */
++{while (*s!=0) print_char(*s++);@+
++}
++
+ @ 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:
+@@ -1531,7 +1586,7 @@
+ character positions.
+
+ @<Initialize the output...@>=
+-wterm(banner);
++wterm("%s",banner);
+ if (format_ident==0) wterm_ln(" (no format preloaded)");
+ else{@+slow_print(format_ident);print_ln();
+ }
+@@ -1541,10 +1596,10 @@
+ string appears at the beginning of a new line.
+
+ @<Basic print...@>=
+-void print_nl(str_number @!s) /*prints string |s| at beginning of line*/
++void print_nl(char *@!s) /*prints string |s| at beginning of line*/
+ {@+if (((term_offset > 0)&&(odd(selector)))||@|
+ ((file_offset > 0)&&(selector >= log_only))) print_ln();
+-print(s);
++print_str(s);
+ }
+
+ @ The procedure |print_esc| prints a string that is preceded by
+@@ -1681,10 +1736,10 @@
+ @* Reporting errors.
+ When something anomalous is detected, \TeX\ typically does something like this:
+ $$\vbox{\halign{#\hfil\cr
+-|print_err(@[@<|"Something anomalous has been detected"|@>@]);|\cr
+-|help3(@[@<|"This is the first line of my offer to help."|@>@])|\cr
+-|(@[@<|"This is the second line. I'm trying to"|@>@])|\cr
+-|(@[@<|"explain the best way for you to proceed."|@>@]);|\cr
++|print_err("Something anomalous has been detected");|\cr
++|help3("This is the first line of my offer to help.")|\cr
++|("This is the second line. I'm trying to")|\cr
++|("explain the best way for you to proceed.");|\cr
+ |error;|\cr}}$$
+ A two-line help message would be given using |help2|, etc.; these informal
+ helps should use simple vocabulary that complements the words used in the
+@@ -1788,10 +1843,10 @@
+ void close_files_and_terminate(void);@/
+ void clear_for_error_prompt(void);@/
+ void give_err_help(void);@/
+-@t\4\hskip-\fontdimen2\font@>@;
+ #ifdef @!DEBUG
+-@+void debug_help(void)
+- ;@;
++void debug_help(void);
++#else
++#define debug_help() do_nothing
+ #endif
+
+ @ Individual lines of help are recorded in the array |help_line|, which
+@@ -1813,7 +1868,7 @@
+ @d help6 @+{@+help_ptr=6;hlp6 /*use this with six help lines*/
+
+ @<Glob...@>=
+-str_number @!help_line[6]; /*helps for the next |error|*/
++char *@!help_line[6]; /*helps for the next |error|*/
+ uint8_t @!help_ptr; /*the number of help lines present*/
+ bool @!use_err_help; /*should the |err_help| list be shown?*/
+
+@@ -1832,7 +1887,7 @@
+
+ @<Error hand...@>=
+ void jump_out(void)
+-{@+goto end_of_TEX;
++{@+ close_files_and_terminate(); exit(0);
+ }
+
+ @ Here now is the general |error| routine.
+@@ -1972,7 +2027,7 @@
+ else{@+if (help_ptr==0)
+ help2("Sorry, I don't know how to help in this situation.")@/
+ @t\kern1em@>("Maybe you should try asking a human?");
+- @/do@+{decr(help_ptr);print(help_line[help_ptr]);print_ln();
++ @/do@+{decr(help_ptr);print_str(help_line[help_ptr]);print_ln();
+ }@+ while (!(help_ptr==0));
+ }
+ help4("Sorry, I already gave what help I could...")@/
+@@ -2017,16 +2072,12 @@
+ @d succumb {@+if (interaction==error_stop_mode)
+ interaction=scroll_mode; /*no more interaction*/
+ if (log_opened) error();
+-
+-#ifdef @!DEBUG
+-if (interaction > batch_mode) debug_help();
+-#endif
+-@;@/
++ if (interaction > batch_mode) debug_help();
+ history=fatal_error_stop;jump_out(); /*irrecoverable error*/
+ }
+
+ @<Error hand...@>=
+-void fatal_error(str_number @!s) /*prints |s|, and that's it*/
++void fatal_error(char *@!s) /*prints |s|, and that's it*/
+ {@+normalize_selector();@/
+ print_err("Emergency stop");help1(s);succumb;
+ @.Emergency stop@>
+@@ -2035,11 +2086,11 @@
+ @ Here is the most dreaded error message.
+
+ @<Error hand...@>=
+-void overflow(str_number @!s, int @!n) /*stop due to finiteness*/
++void overflow(char *@!s, int @!n) /*stop due to finiteness*/
+ {@+normalize_selector();
+ print_err("TeX capacity exceeded, sorry [");
+ @.TeX capacity exceeded ...@>
+-print(s);print_char('=');print_int(n);print_char(']');
++print_str(s);print_char('=');print_int(n);print_char(']');
+ help2("If you really absolutely need more capacity,")@/
+ ("you can ask a wizard to enlarge me.");
+ succumb;
+@@ -2202,7 +2253,7 @@
+ The present implementation of \TeX\ does not check for overflow when
+ @^overflow in arithmetic@>
+ dimensions are added or subtracted. This could be done by inserting a
+-few dozen tests of the form `\ignorespaces|if (x >= 010000000000)
++few dozen tests of the form `\ignorespaces|if (x >= 010000000000)@/
+ @t\\{report\_overflow}@>|', but the chance of overflow is so remote that
+ such tests do not seem worthwhile.
+
+@@ -2332,12 +2383,12 @@
+
+ @d set_glue_ratio_zero(X) X=0.0 /*store the representation of zero ratio*/
+ @d set_glue_ratio_one(X) X=1.0 /*store the representation of unit ratio*/
+-@d float(X) X /*convert from |glue_ratio| to type |double|*/
+-@d unfloat(X) X /*convert from |double| to type |glue_ratio|*/
+-@d float_constant(X) X.0 /*convert |int| constant to |double|*/
++@d float(X) ((double)(X)) /*convert from |glue_ratio| to type |double|*/
++@d unfloat(X) ((glue_ratio)(X)) /*convert from |double| to type |glue_ratio|*/
++@d float_constant(X) ((double)(X)) /*convert |int| constant to |double|*/
+
+ @<Types...@>=
+-typedef double glue_ratio; /*one-word representation of a glue expansion factor*/
++typedef float32_t @!glue_ratio; /*one-word representation of a glue expansion factor*/
+
+ @* Packed data.
+ In order to make efficient use of storage space, \TeX\ bases its major data
+@@ -2500,6 +2551,7 @@
+ value represents a null pointer. \TeX\ does not assume that |mem[null]| exists.
+
+ @d pointer halfword /*a flag or a location in |mem| or |eqtb|*/
++@s pointer int
+ @d null min_halfword /*the null pointer*/
+
+ @<Glob...@>=
+@@ -2549,7 +2601,14 @@
+
+ @<Glob...@>=
+ int @!var_used, @!dyn_used; /*how much memory is in use*/
+-
++#ifdef @!DEBUG
++#define incr_dyn_used @[incr(dyn_used)@]
++#define decr_dyn_used @[decr(dyn_used)@]
++#else
++#define incr_dyn_used
++#define decr_dyn_used
++#endif
++
+ @ 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
+@@ -2599,10 +2658,7 @@
+ }
+ }
+ link(p)=null; /*provide an oft-desired initialization of the new node*/
+-#ifdef @!STAT
+-incr(dyn_used);
+-#endif
+-@; /*maintain statistics*/
++incr_dyn_used; /*maintain statistics*/
+ return p;
+ }
+
+@@ -2612,10 +2668,7 @@
+
+ @d free_avail(X) /*single-word node liberation*/
+ {@+link(X)=avail;avail=X;
+-
+-#ifdef @!STAT
+-decr(dyn_used);
+-#endif
++ decr_dyn_used;
+ }
+
+ @ There's also a |fast_get_avail| routine, which saves the procedure-call
+@@ -2627,10 +2680,7 @@
+ {@+X=avail; /*avoid |get_avail| if possible, to save time*/
+ if (X==null) X=get_avail();
+ else{@+avail=link(X);link(X)=null;
+-
+-#ifdef @!STAT
+-incr(dyn_used);
+-#endif
++ incr_dyn_used;
+ }
+ }
+
+@@ -2644,9 +2694,7 @@
+ if (p!=null)
+ {@+r=p;
+ @/do@+{q=r;r=link(r);
+-#ifdef @!STAT
+-decr(dyn_used);
+-#endif
++ decr_dyn_used;
+ }@+ while (!(r==null)); /*now |q| is the last node on the list*/
+ link(q)=avail;avail=p;
+ }
+@@ -8168,7 +8216,7 @@
+ else pstack[n]=link(temp_head);
+ incr(n);
+ if (tracing_macros > 0)
+- {@+begin_diagnostic();print_nl(match_chr);print_int(n);
++ {@+begin_diagnostic();print_nl("");print(match_chr);print_int(n);
+ print_str("<-");show_token_list(pstack[n-1], null, 1000);
+ end_diagnostic(false);
+ }
+@@ -9997,10 +10045,7 @@
+ |TEX_font_area|. These system area names will, of course, vary from place
+ to place.
+ @^system dependencies@>
+-
+-@d TEX_area TEX_area
+ @.TeXinputs@>
+-@d TEX_font_area TEX_font_area
+ @.TeXfonts@>
+
+ @ Here now is the first of the system-dependent routines for file name scanning.
+@@ -10076,7 +10121,7 @@
+ for (j=str_start[n]; j<=str_start[n+1]-1; j++) append_to_name(so(str_pool[j]));
+ for (j=str_start[e]; j<=str_start[e+1]-1; j++) append_to_name(so(str_pool[j]));
+ if (k <= file_name_size) name_length=k;@+else name_length=file_name_size;
+-for (k=name_length+1; k<=file_name_size; k++) name_of_file[k]= ' ' ;
++name_of_file[name_length+1]=0;
+ }
+
+ @ A messier routine is also needed, since format file names must be scanned
+@@ -10088,13 +10133,10 @@
+ @d format_default_length 20 /*length of the |TEX_format_default| string*/
+ @d format_area_length 11 /*length of its area part*/
+ @d format_ext_length 4 /*length of its `\.{.fmt}' part*/
+-@d format_extension format_extension /*the extension, as a \.{WEB} constant*/
++@d format_extension_str ".fmt" /*the extension, as a \.{WEB} constant*/
+
+ @<Glob...@>=
+-uint8_t @!TEX_format_default0[format_default_length], *const @!TEX_format_default = @!TEX_format_default0-1;
+-
+-@ @<Set init...@>=
+-TEX_format_default="TeXformats:plain.fmt";
++ASCII_code @!TEX_format_default[1+format_default_length+1]=" TeXformats/plain.fmt";
+ @.TeXformats@>
+ @.plain@>
+ @^system dependencies@>
+@@ -10125,7 +10167,7 @@
+ for (j=format_default_length-format_ext_length+1; j<=format_default_length; j++)
+ append_to_name(xord[TEX_format_default[j]]);
+ if (k <= file_name_size) name_length=k;@+else name_length=file_name_size;
+-for (k=name_length+1; k<=file_name_size; k++) name_of_file[k]= ' ' ;
++name_of_file[name_length+1]=0;
+ }
+
+ @ Here is the only place we use |pack_buffered_name|. This part of the program
+@@ -10149,7 +10191,7 @@
+ /*now try the system format file area*/
+ if (w_open_in(&fmt_file)) goto found;
+ wake_up_terminal;
+- wterm_ln("Sorry, I can't find that format;"," will try PLAIN.");
++ wterm_ln("Sorry, I can't find that format; will try PLAIN.");
+ @.Sorry, I can't find...@>
+ update_terminal;
+ }
+@@ -10255,17 +10297,17 @@
+ variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are
+ ready for another attempt at file opening.
+
+-@p void prompt_file_name(str_number @!s, str_number @!e)
++@p void prompt_file_name(char *@!s, str_number @!e)
+ {@+
+ uint16_t k; /*index into |buffer|*/
+ if (interaction==scroll_mode) wake_up_terminal;
+-if (s==@[@<|"input file name"|@>@]) print_err("I can't find file `")@;
++if (strcmp(s,"input file name")==0) print_err("I can't find file `")@;
+ @.I can't find file x@>
+ else print_err("I can't write on file `");
+ @.I can't write on file x@>
+ print_file_name(cur_name, cur_area, cur_ext);print_str("'.");
+ if (e==@[@<|".tex"|@>@]) show_context();
+-print_nl("Please type another ");print(s);
++print_nl("Please type another ");print_str(s);
+ @.Please type...@>
+ if (interaction < scroll_mode)
+ fatal_error("*** (job aborted, file error in nonstop mode)");
+@@ -10286,9 +10328,10 @@
+ }
+
+ @ Here's an example of how these conventions are used. Whenever it is time to
+-ship out a box of stuff, we shall use the macro |ensure_dvi_open|.
++ship out a box of stuff, we shall use |@<ensure dvi open@>|.
+
+-@d ensure_dvi_open if (output_file_name==0)
++@<ensure dvi open@>=
++if (output_file_name==0)
+ {@+if (job_name==0) open_log_file();
+ pack_job_name(@[@<|".dvi"|@>@]);
+ while (!b_open_out(&dvi_file))
+@@ -10296,7 +10339,7 @@
+ output_file_name=b_make_name_string(&dvi_file);
+ }
+
+-@<Glob...@>=
++@ @<Glob...@>=
+ byte_file @!dvi_file; /*the device-independent output goes here*/
+ str_number @!output_file_name; /*full name of the output file*/
+ str_number @!log_name; /*full name of the log file*/
+@@ -10310,7 +10353,7 @@
+ {@+uint8_t old_setting; /*previous |selector| setting*/
+ int @!k; /*index into |months| and |buffer|*/
+ uint16_t @!l; /*end of first input line*/
+-uint8_t @!months0[36], *const @!months = @!months0-1; /*abbreviations of month names*/
++@!ASCII_code @!months[]=" JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; /*abbreviations of month names*/
+ old_setting=selector;
+ if (job_name==0) job_name=@[@<|"texput"|@>@];
+ @.texput@>
+@@ -10349,11 +10392,10 @@
+ }
+
+ @ @<Print the banner...@>=
+-{@+wlog(banner);
++{@+wlog("%s",banner);
+ slow_print(format_ident);print_str(" ");
+ print_int(day);print_char(' ');
+-months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
+-for (k=3*month-2; k<=3*month; k++) wlog(months[k]);
++for (k=3*month-2; k<=3*month; k++) wlog("%c",months[k]);
+ print_char(' ');print_int(year);print_char(' ');
+ print_two(time/60);print_char(':');print_two(time%60);
+ }
+@@ -10453,7 +10495,8 @@
+ @ The rest of the \.{TFM} file may be regarded as a sequence of ten data
+ arrays having the informal specification
+ $$\def\arr$[#1]#2${\&{array} $[#1]$ \&{of} #2}
+-\vbox{\halign{\hfil\\{#}&$\,:\,$\arr#\hfil\cr
++\def\PB#1{\arr#1}
++\vbox{\halign{\hfil\\{#}&$\,:\,$#\hfil\cr
+ header&|[0 dotdot lh-1]@t\\{stuff}@>|\cr
+ char\_info&|[bc dotdot ec]char_info_word|\cr
+ width&|[0 dotdot nw-1]fix_word|\cr
+@@ -11913,7 +11956,7 @@
+
+ @p void write_dvi(dvi_index @!a, dvi_index @!b)
+ {@+int k;
+-for (k=a; k<=b; k++) write(dvi_file, dvi_buf[k]);
++for (k=a; k<=b; k++) write(dvi_file, "%c", dvi_buf[k]);
+ }
+
+ @ To put a byte in the buffer without paying the cost of invoking a procedure
+@@ -12279,7 +12322,7 @@
+
+ @ @<Initialize variables as |ship_out| begins@>=
+ dvi_h=0;dvi_v=0;cur_h=h_offset;dvi_f=null_font;
+-ensure_dvi_open;
++@<ensure dvi open@>;
+ if (total_pages==0)
+ {@+dvi_out(pre);dvi_out(id_byte); /*output the preamble*/
+ @^preamble of \.{DVI} file@>
+@@ -13135,10 +13178,11 @@
+ computed by the normal rules; if it exceeds this limit, the reference
+ point is simply moved down until the limiting depth is attained.
+
+-@d vpack(...) vpackage(__VA_ARGS__, max_dimen) /*special case of unconstrained depth*/
+-
+ @p
+- pointer vpackage(pointer @!p, scaled @!h, small_number @!m, scaled @!l)
++#define vpack(...) @[vpackage(__VA_ARGS__, max_dimen)@]
++ /*special case of unconstrained depth*/
++
++pointer vpackage(pointer @!p, scaled @!h, small_number @!m, scaled @!l)
+ {@+
+ pointer r; /*the box node that will be returned*/
+ scaled @!w, @!d, @!x; /*width, depth, and natural height*/
+@@ -15023,9 +15067,9 @@
+ the program would not have been so strange.
+ @:PASCAL}{\PASCAL@>
+
+-@d math_spacing @;@/
++@d math_spacing_str @;@/
+ @t\hskip-35pt@>
+-math_spacing
++"math_spacing"
+ @t$ \hskip-35pt$@>
+
+ @<Glob...@>=
+@@ -16337,7 +16381,7 @@
+ should no longer be active; then |goto continue| if a line from |r| to |cur_p| is
+ infeasible, otherwise record a new feasible break@>;
+ }
+-end:
++end: ;
+ #ifdef @!STAT
+ @<Update the value of |printed_node| for symbolic displays@>;
+ #endif
+@@ -16358,7 +16402,9 @@
+ halfword @!b; /*badness of test line*/
+ int @!d; /*demerits of test line*/
+ bool @!artificial_demerits; /*has |d| been forced to zero?*/
++#ifdef @!STAT
+ pointer @!save_link; /*temporarily holds value of |link(cur_p)|*/
++#endif
+ scaled @!shortfall; /*used in badness calculations*/
+
+ @ @<Make sure that |pi| is in the proper range@>=
+@@ -17790,7 +17836,7 @@
+ ligature and a |lig_ptr| field that points to a |char_node| or is |null|.
+ We have
+ $$|cur_r|=\cases{|character(lig_stack)|,&if |lig_stack > null|;\cr
+- |qi(hu[j+1])|,&if |lig_stack==null| and |j < n|;\cr
++ \hbox{|qi(hu[j+1])|},&if |lig_stack==null| and |j < n|;\cr
+ bchar,&if |lig_stack==null| and |j==n|.\cr}$$
+
+ @<Glob...@>=
+@@ -23733,7 +23779,7 @@
+ incompatible with the present \TeX\ table sizes, etc.
+
+ @d too_small(X) {@+wake_up_terminal;
+- wterm_ln("---! Must increase the ", X);
++ wterm_ln("---! Must increase the %s", X);
+ @.Must increase the x@>
+ goto bad_fmt;
+ }
+@@ -24246,14 +24292,13 @@
+ if (ready_already==314159) goto start_of_TEX;
+ @<Check the ``constant'' values...@>@;
+ if (bad > 0)
+- {@+wterm_ln("Ouch---my internal constants have been clobbered!",
+- "---case ", bad: 1);
++ {@+wterm_ln("Ouch---my internal constants have been clobbered!"
++ "---case %d", bad);
+ @.Ouch...clobbered@>
+ exit(0);
+ }
+ initialize(); /*set global variables to their starting values*/
+ #ifdef @!INIT
+-if (!get_strings_started()) exit(0);
+ init_prim(); /*call |primitive| for each primitive*/
+ init_str_ptr=str_ptr;init_pool_ptr=pool_ptr;fix_date_and_time();
+ #endif
+@@ -24263,7 +24308,7 @@
+ history=spotless; /*ready to go!*/
+ main_control(); /*come to life*/
+ final_cleanup(); /*prepare for death*/
+-end_of_TEX: close_files_and_terminate();
++close_files_and_terminate();
+ ready_already=0;
+ return 0; }
+
+@@ -24305,34 +24350,33 @@
+
+ @<Output statistics...@>=
+ if (log_opened)
+- {@+wlog_ln( ' ' );
+- wlog_ln("Here is how much of TeX's memory"," you used:");
++ {@+wlog_ln(" ");
++ wlog_ln("Here is how much of TeX's memory you used:");
+ @.Here is how much...@>
+- wlog( ' ' , str_ptr-init_str_ptr: 1," string");
+- if (str_ptr!=init_str_ptr+1) wlog( 's' );
+- wlog_ln(" out of ", max_strings-init_str_ptr: 1);@/
+- wlog_ln( ' ' , pool_ptr-init_pool_ptr: 1," string characters out of ",
+- pool_size-init_pool_ptr: 1);@/
+- wlog_ln( ' ' , lo_mem_max-mem_min+mem_end-hi_mem_min+2: 1,@|
+- " words of memory out of ", mem_end+1-mem_min: 1);@/
+- wlog_ln( ' ' , cs_count: 1," multiletter control sequences out of ",
+- hash_size: 1);@/
+- wlog( ' ' , fmem_ptr: 1," words of font info for ",
+- font_ptr-font_base: 1," font");
+- if (font_ptr!=font_base+1) wlog( 's' );
+- wlog_ln(", out of ", font_mem_size: 1," for ", font_max-font_base: 1);@/
+- wlog( ' ' , hyph_count: 1," hyphenation exception");
+- if (hyph_count!=1) wlog( 's' );
+- wlog_ln(" out of ", hyph_size: 1);@/
+- wlog_ln( ' ' , max_in_stack: 1,"i,", max_nest_stack: 1,"n,",@|
+- max_param_stack: 1,"p,",@|
+- max_buf_stack+1: 1,"b,",@|
+- max_save_stack+6: 1,"s stack positions out of ",@|
+- stack_size: 1,"i,",
+- nest_size: 1,"n,",
+- param_size: 1,"p,",
+- buf_size: 1,"b,",
+- save_size: 1, 's' );
++ wlog(" %d string", str_ptr-init_str_ptr);
++ if (str_ptr!=init_str_ptr+1) wlog( "s" );
++ wlog_ln( " out of %d", max_strings-init_str_ptr);@/
++ wlog_ln( " %d string characters out of %d", pool_ptr-init_pool_ptr,
++ pool_size-init_pool_ptr);@/
++ wlog_ln(" %d words of memory out of %d", lo_mem_max-mem_min+mem_end-hi_mem_min+2,@|
++ mem_end+1-mem_min);@/
++ wlog_ln(" %d multiletter control sequences out of %d", cs_count, hash_size);@/
++ wlog(" %d words of font info for %d font", fmem_ptr, font_ptr-font_base);
++ if (font_ptr!=font_base+1) wlog("s");
++ wlog_ln( ", out of %d for %d", font_mem_size, font_max-font_base);@/
++ wlog(" %d hyphenation exception", hyph_count);
++ if (hyph_count!=1) wlog("s");
++ wlog_ln( " out of %d", hyph_size);@/
++ wlog_ln(" %di,%dn,%dp,%db,%ds stack positions out of %di,%dn,%dp,%db,%ds",
++ max_in_stack, max_nest_stack,@|
++ max_param_stack,@|
++ max_buf_stack+1,@|
++ max_save_stack+6,@|
++ stack_size,
++ nest_size,
++ param_size,
++ buf_size,
++ save_size );
+ }
+
+ @ We get to the |final_cleanup| routine when \.{\\end} or \.{\\dump} has
+@@ -24452,13 +24496,13 @@
+ loop{@+wake_up_terminal;
+ print_nl("debug # (-1 to exit):");update_terminal;
+ @.debug \#@>
+- read(term_in, m);
+- if (m < 0) return;
++ if (fscanf(term_in.f," %d",&m)<1 ||
++ m < 0) return;
+ else if (m==0)
+ {@+goto breakpoint; /*go to every label at least once*/
+ breakpoint: m=0;/*'BREAKPOINT'*/
+ }
+- else{@+read(term_in, n);
++ else{@+fscanf(term_in.f," %d",&n);
+ switch (m) {
+ @t\4@>@<Numbered cases for |debug_help|@>@;
+ default:print_str("?");
+@@ -24484,7 +24528,7 @@
+ case 10: slow_print(n);@+break;
+ case 11: check_mem(n > 0);@+break; /*check wellformedness; print new busy locations if |n > 0|*/
+ case 12: search_mem(n);@+break; /*look for pointers to |n|*/
+-case 13: {@+read(term_in, l);print_cmd_chr(n, l);
++case 13: {@+fscanf(term_in.f," %d",&l);print_cmd_chr(n, l);
+ } @+break;
+ case 14: for (k=0; k<=n; k++) print(buffer[k]);@+break;
+ case 15: {@+font_in_short_display=null_font;short_display(n);
+@@ -24619,8 +24663,8 @@
+ @ @<Declare act...@>=
+ @t\4@>@<Declare procedures needed in |do_extension|@>@;
+ void do_extension(void)
+-{@+int i, @!j, @!k; /*all-purpose integers*/
+-pointer @!p, @!q, @!r; /*all-purpose pointers*/
++{@+int @!k; /*all-purpose integer*/
++pointer @!p; /*all-purpose pointer*/
+ switch (cur_chr) {
+ case open_node: @<Implement \.{\\openout}@>@;@+break;
+ case write_node: @<Implement \.{\\write}@>@;@+break;
+@@ -24957,22 +25001,6 @@
+ itself will get a new section number.
+ @^system dependencies@>
+
+-@* 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.
+-
+ @ Appendix: Replacement of the string pool file.
+ @d str_0_255 "^^@@^^A^^B^^C^^D^^E^^F^^G^^H^^I^^J^^K^^L^^M^^N^^O"@/
+ "^^P^^Q^^R^^S^^T^^U^^V^^W^^X^^Y^^Z^^[^^\\^^]^^^^^_"@/
+@@ -25757,10 +25785,10 @@
+ @d str_505 "else"
+ @<|"else"|@>=@+505
+ @
+-@d str_506 "TeXinputs:"
++@d str_506 "TeXinputs/"
+ @d TEX_area 506
+ @
+-@d str_507 "TeXfonts:"
++@d str_507 "TeXfonts/"
+ @d TEX_font_area 507
+ @
+ @d str_508 ".fmt"
+@@ -26827,3 +26855,19 @@
+ @ @<|pool_ptr| initialization@>= str_start_668
+
+ @ @<|str_ptr| initialization@>= 668
++
++@* 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.
diff --git a/web/web2w/ctex.scn b/web/web2w/ctex.scn
new file mode 100644
index 0000000000..7d97dc470f
--- /dev/null
+++ b/web/web2w/ctex.scn
@@ -0,0 +1,2129 @@
+\I\X445:Accumulate the constant until \\{cur\_tok} is not a suitable digit\X
+\U444.
+\I\X871:Add the width of node \|s to \\{act\_width}\X
+\U869.
+\I\X842:Add the width of node \|s to \\{break\_width}\X
+\U840.
+\I\X870:Add the width of node \|s to \\{disc\_width}\X
+\U869.
+\I\X457:Adjust \(f)for the magnification ratio\X
+\U453.
+\I\X1214:Adjust \(f)for the setting of \.{\\globaldefs}\X
+\U1211.
+\I\X746:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of a fraction line\X
+\U743.
+\I\X745:Adjust \(s)\\{shift\_up} and \\{shift\_down} for the case of no fraction line\X
+\U743.
+\I\X867:Advance \(c)\\{cur\_p} to the node following the present string of characters\X
+\U866.
+\I\X1362:Advance \(p)past a whatsit node in the \(l)\\{line\_break} loop\X
+\U866.
+\I\X1363:Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop\X
+\U896.
+\I\X394:Advance \(r)\|r; \&{goto} \\{found} if the parameter delimiter has been fully matched, otherwise \&{goto} \&{continue}\X
+\U392.
+\I\X129:Allocate entire node \|p and \&{goto} \\{found}\X
+\U127.
+\I\X128:Allocate from the top of node \|p and \&{goto} \\{found}\X
+\U127.
+\I\X1106:Apologize for inability to do the operation now, unless \.{\\unskip} follows non-glue\X
+\U1105.
+\I\X567:Apologize for not loading the font, \&{goto} \\{done}\X
+\U566.
+\I\X910:Append a ligature and/or kern to the translation; \&{goto} \&{continue} if the stack of inserted ligatures is nonempty\X
+\U906.
+\I\X1078:Append a new leader node that uses \\{cur\_box}\X
+\U1075.
+\I\X962:Append a new letter or a hyphen level\X
+\U961.
+\I\X937:Append a new letter or hyphen\X
+\U935.
+\I\X1041:Append a normal inter-word space to the current list, then \&{goto} \\{big\_switch}\X
+\U1030.
+\I\X890:Append a penalty node, if a nonzero penalty is appropriate\X
+\U880.
+\I\X1008:Append an insertion to the current page and \&{goto} \\{contribute}\X
+\U1000.
+\I\X767:Append any \\{new\_hlist} entries for \|q, and any appropriate penalties\X
+\U760.
+\I\X1076:Append box \\{cur\_box} to the current list, shifted by \\{box\_context}\X
+\U1075.
+\I\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
+\U1030.
+\I\X917:Append characters of \\{hu} [ \|j $\MRL{{.}{.}}$ ] to \\{major\_tail}, advancing~\|j\X
+\U916.
+\I\X766:Append inter-element spacing based on \\{r\_type} and \|t\X
+\U760.
+\I\X809:Append tabskip glue and an empty box to list \|u, and update \|s and \|t as the prototype nodes are passed\X
+\U808.
+\I\X1125:Append the accent with appropriate kerns, then set \|p: $\K$ \|q\X
+\U1123.
+\I\X778:Append the current tabskip glue to the preamble list\X
+\U777.
+\I\X1204:Append the display and perhaps also the equation number\X
+\U1199.
+\I\X1205:Append the glue or equation number following the display\X
+\U1199.
+\I\X1203:Append the glue or equation number preceding the display\X
+\U1199.
+\I\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
+\U880.
+\I\X938:Append the value \|n to list \|p\X
+\U937.
+\I\X236:Assign the values \\{depth\_threshold}: $\K$ \\{show\_box\_depth} and \\{breadth\_max}: $\K$ \\{show\_box\_breadth}\X
+\U198.
+\I\X1217, 1218, 1221, 1224, 1225, 1226, 1228, 1232, 1234, 1235, 1241, 1242, 1248, 1252, 1253, 1256, 1264:Assignments\X
+\U1211.
+\I\X1120:Attach list \|p to the current list, and record its length; then finish up and \&{return}\X
+\U1119.
+\I\X751:Attach the limits to \|y and adjust \\{height}(\|v), \\{depth}(\|v) to account for their presence\X
+\U750.
+\I\X337:Back up an outer control sequence so that it can be reread\X
+\U336.
+\I\X57, 58, 59, 60, 62, 63, 64, 65, 262, 263, 518, 699, 1355:Basic printing procedures\X
+\U4.
+\I\X1017:Break the current page at node \|p, put it in box~255, and put the remaining nodes on the contribution list\X
+\U1014.
+\I\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
+\U815.
+\I\X1149:Calculate the length, \|l, and the shift amount, \|s, of the display lines\X
+\U1145.
+\I\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
+\U1145.
+\I\X889:Call the packaging subroutine, setting \\{just\_box} to the justified box\X
+\U880.
+\I\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
+\U863.
+\I\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
+\U909.
+\I\X206:Case statement to copy different types and set \\{words} to the number of initial words not yet copied\X
+\U205.
+\I\X733:Cases for noads that can follow a \\{bin\_noad}\X
+\U728.
+\I\X730:Cases for nodes that can appear in an mlist, after which we \&{goto} \\{done\_with\_node}\X
+\U728.
+\I\X698:Cases of \\{flush\_node\_list} that arise in mlists only\X
+\U202.
+\I\X1085, 1100, 1118, 1132, 1133, 1168, 1173, 1186:Cases of \\{handle\_right\_brace} where a \\{right\_brace} triggers a delayed action\X
+\U1068.
+\I\X1347:Cases of \\{main\_control} that are for extensions to \TeX\X
+\U1045.
+\I\X1045:Cases of \\{main\_control} that are not part of the inner loop\X
+\U1030.
+\I\X1056, 1057, 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, 1193:Cases of \\{main\_control} that build boxes and lists\X
+\U1045.
+\I\X1210, 1268, 1271, 1274, 1276, 1285, 1290:Cases of \\{main\_control} that don't depend on \\{mode}\X
+\U1045.
+\I\X227, 231, 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, 1346:Cases of \\{print\_cmd%
+\_chr} for symbolic printing of primitives\X
+\U298.
+\I\X690:Cases of \\{show\_node\_list} that arise in mlists only\X
+\U183.
+\I\X345:Cases where character is ignored\X
+\U344.
+\I\X613:Change buffered instruction to \|y or \|w and \&{goto} \\{found}\X
+\U612.
+\I\X614:Change buffered instruction to \|z or \|x and \&{goto} \\{found}\X
+\U612.
+\I\X775:Change current mode to ${-}\\{vmode}$ for \.{\\halign}, ${-}\\{hmode}$ for \.{\\valign}\X
+\U774.
+\I\X882:Change discretionary to compulsory and set \\{disc\_break}: $\K$ \\{true}\X
+\U881.
+\I\X621:Change font \\{dvi\_f} to \|f\X
+\U620.
+\I\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
+\U343.
+\I\X1289:Change the case of the token in \|p, if a change is appropriate\X
+\U1288.
+\I\X763:Change the current style and \&{goto} \\{delete\_q}\X
+\U761.
+\I\X86:Change the interaction level and \&{return}\X
+\U84.
+\I\X731:Change this node to a style node followed by the correct choice, then \&{goto} \\{done\_with\_node}\X
+\U730.
+\I\X49:Character \|k cannot be printed\X
+\U48.
+\I\X244:Character \|s is the current new-line character\X
+\Us58\ET59.
+\I\X170:Check flags of unavailable nodes\X
+\U167.
+\I\X570:Check for charlist cycle\X
+\U569.
+\I\X776:Check for improper alignment in displayed math\X
+\U774.
+\I\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
+\U972.
+\I\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
+\U997.
+\I\X168:Check single-word \\{avail} list\X
+\U167.
+\I\X1197:Check that another \.\$ follows\X
+\Us1194\ET1206.
+\I\X1195:Check that the necessary fonts for math symbols are present; if not, flush the current math lists and set \\{danger}: $\K$ \\{true}\X
+\U1194.
+\I\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
+\U894.
+\I\X14, 111, 290, 521, 1249:Check the ``constant'' values for consistency\X
+\U1332.
+\I\X53:Check the pool check sum\X
+\U52.
+\I\X169:Check variable-size \\{avail} list\X
+\U167.
+\I\X865:Clean up the memory by removing the break nodes\X
+\Us815\ET863.
+\I\X650:Clear dimensions to zero\X
+\Us649\ET668.
+\I\X282:Clear off top level from \\{save\_stack}\X
+\U281.
+\I\X1329:Close the format file\X
+\U1302.
+\I\X451:Coerce glue to a dimension\X
+\Us449\ET455.
+\I\X9, 56:Compiler directives\X
+\U4.
+\I\X723:Complain about an undefined family and set \\{cur\_i} null\X
+\U722.
+\I\X370:Complain about an undefined macro\X
+\U367.
+\I\X373:Complain about missing \.{\\endcsname}\X
+\U372.
+\I\X459:Complain about unknown unit and \&{goto} \\{done2}\X
+\U458.
+\I\X428:Complain that \.{\\the} can't do this; give zero result\X
+\U413.
+\I\X1166:Complain that the user should have said \.{\\mathaccent}\X
+\U1165.
+\I\X1185:Compleat the incompleat noad\X
+\U1184.
+\I\X1298:Complete a potentially long \.{\\show} command\X
+\U1293.
+\I\X1240:Compute result of \\{multiply} or \\{divide}, put it in \\{cur\_val}\X
+\U1236.
+\I\X1238:Compute result of \&{register} or \\{advance}, put it in \\{cur\_val}\X
+\U1236.
+\I\X741:Compute the amount of skew\X
+\U738.
+\I\X1007:Compute the badness, \|b, of the current page, using \\{awful\_bad} if the box is too full\X
+\U1005.
+\I\X975:Compute the badness, \|b, using \\{awful\_bad} if the box is too full\X
+\U974.
+\I\X859:Compute the demerits, \|d, from \|r to \\{cur\_p}\X
+\U855.
+\I\X840:Compute the discretionary \\{break\_width} values\X
+\U837.
+\I\X261:Compute the hash code \|h\X
+\U259.
+\I\X765:Compute the magic offset\X
+\U1337.
+\I\X714:Compute the minimum suitable height, \|w, and the corresponding number of extension steps, \|n; also set \\{width}(\|b)\X
+\U713.
+\I\X850:Compute the new line width\X
+\U835.
+\I\X1237:Compute the register location \|l and its type \|p; but \&{return} if invalid\X
+\U1236.
+\I\X1239:Compute the sum of two glue specs\X
+\U1238.
+\I\X965:Compute the trie op code, \|v, and set \|l: $\K$ \T{0}\X
+\U963.
+\I\X837:Compute the values of \\{break\_width}\X
+\U836.
+\I\X612:Consider a node with matching width; \&{goto} \\{found} if it's a hit\X
+\U611.
+\I\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
+\U829.
+\I\X11:Constants in the outer block\X
+\U4.
+\I\X750:Construct a box with limits above and below it, skewed by \\{delta}\X
+\U749.
+\I\X759:Construct a sub/superscript combination box \|x, with the superscript offset by \\{delta}\X
+\U756.
+\I\X757:Construct a subscript box \|x when there is no superscript\X
+\U756.
+\I\X758:Construct a superscript box \|x\X
+\U756.
+\I\X747:Construct a vlist box for the fraction, according to \\{shift\_up} and \\{shift\_down}\X
+\U743.
+\I\X713:Construct an extensible character in a new box \|b, using recipe \\{rem\_byte}(\|q) and font \|f\X
+\U710.
+\I\X399:Contribute an entire group to the current parameter\X
+\U392.
+\I\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
+\U392.
+\I\X729:Convert \(a)a final \\{bin\_noad} to an \\{ord\_noad}\X
+\Us726\ET728.
+\I\X429:Convert \(c)\\{cur\_val} to a lower level\X
+\U413.
+\I\X732:Convert \(m)math glue to ordinary glue\X
+\U730.
+\I\X754:Convert \(n)\\{nucleus}(\|q) to an hlist and attach the sub/superscripts\X
+\U728.
+\I\X795:Copy the tabskip glue between columns\X
+\U791.
+\I\X794:Copy the templates from node \\{cur\_loop} into node \|p\X
+\U793.
+\I\X466:Copy the token list\X
+\U465.
+\I\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
+\U754.
+\I\X1124:Create a character node \|q for the next character, but set \|q: $\K$ \\{null} if problems arise\X
+\U1123.
+\I\X462:Create a new glue specification whose width is \\{cur\_val}; scan for its stretch and shrink components\X
+\U461.
+\I\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
+\U1008.
+\I\X864:Create an active breakpoint representing the beginning of the paragraph\X
+\U863.
+\I\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
+\U913.
+\I\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
+\U743.
+\I\X836:Create new active nodes for the best feasible breaks just found\X
+\U835.
+\I\X1328:Create the \\{format\_ident}, open the format file, and inform the user that dumping has begun\X
+\U1302.
+\I\X224:Current \\{mem} equivalent of glue parameter number \|n\X
+\Us152\ET154.
+\I\X860:Deactivate node \|r\X
+\U851.
+\I\X1043, 1047, 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, 1376:Declare action procedures for use by \\{main\_control}\X
+\U1030.
+\I\X734, 735, 736, 737, 738, 743, 749, 752, 756, 762:Declare math construction procedures\X
+\U726.
+\I\X944, 948, 949, 953, 957, 959, 960, 966:Declare procedures for preprocessing hyphenation patterns\X
+\U942.
+\I\X691, 692, 694:Declare procedures needed for displaying the elements of mlists\X
+\U179.
+\I\X1349, 1350:Declare procedures needed in \\{do\_extension}\X
+\U1348.
+\I\X1368, 1370, 1373:Declare procedures needed in \\{hlist\_out}, \\{vlist\_out}\X
+\U619.
+\I\X577, 578:Declare procedures that scan font-related stuff\X
+\U409.
+\I\X433, 434, 435, 436, 437:Declare procedures that scan restricted classes of integers\X
+\U409.
+\I\X826, 829, 877, 895, 942:Declare subprocedures for \\{line\_break}\X
+\U815.
+\I\X1215, 1229, 1236, 1243, 1244, 1245, 1246, 1247, 1257, 1265:Declare subprocedures for \\{prefixed\_command}\X
+\U1211.
+\I\X709, 711, 712:Declare subprocedures for \\{var\_delimiter}\X
+\U706.
+\I\X1184:Declare the function called \\{fin\_mlist}\X
+\U1174.
+\I\X523:Declare the function called \\{open\_fmt\_file}\X
+\U1303.
+\I\X906:Declare the function called \\{reconstitute}\X
+\U895.
+\I\X785:Declare the procedure called \\{align\_peek}\X
+\U800.
+\I\X1012:Declare the procedure called \\{fire\_up}\X
+\U994.
+\I\X782:Declare the procedure called \\{get\_preamble\_token}\X
+\U774.
+\I\X1068:Declare the procedure called \\{handle\_right\_brace}\X
+\U1030.
+\I\X787:Declare the procedure called \\{init\_span}\X
+\U786.
+\I\X379:Declare the procedure called \\{insert\_relax}\X
+\U366.
+\I\X389:Declare the procedure called \\{macro\_call}\X
+\U366.
+\I\X298:Declare the procedure called \\{print\_cmd\_chr}\X
+\U252.
+\I\X225:Declare the procedure called \\{print\_skip\_param}\X
+\U179.
+\I\X284:Declare the procedure called \\{restore\_trace}\X
+\U281.
+\I\X306:Declare the procedure called \\{runaway}\X
+\U119.
+\I\X292:Declare the procedure called \\{show\_token\_list}\X
+\U119.
+\I\X346:Decry the invalid character and \&{goto} \\{restart}\X
+\U344.
+\I\X88:Delete \(c)$\|c-\.{"0"}$ tokens and \&{goto} \&{continue}\X
+\U84.
+\I\X1019:Delete \(t)the page-insertion nodes\X
+\U1014.
+\I\X883:Destroy the \|t nodes following \|q, and make \|r point to the following node\X
+\U882.
+\I\X664:Determine horizontal glue shrink setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X
+\U657.
+\I\X658:Determine horizontal glue stretch setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X
+\U657.
+\I\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
+\U1199.
+\I\X665:Determine the shrink order\X
+\Us664, 676\ETs796.
+\I\X659:Determine the stretch order\X
+\Us658, 673\ETs796.
+\I\X672:Determine the value of \\{height}(\|r) and the appropriate glue setting; then \&{return} or \&{goto} \\{common\_ending}\X
+\U668.
+\I\X657:Determine the value of \\{width}(\|r) and the appropriate glue setting; then \&{return} or \&{goto} \\{common\_ending}\X
+\U649.
+\I\X676:Determine vertical glue shrink setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X
+\U672.
+\I\X673:Determine vertical glue stretch setting, then \&{return} or \hbox{\&{goto} \\{common\_ending}}\X
+\U672.
+\I\X1212:Discard erroneous prefixes and \&{return}\X
+\U1211.
+\I\X1213:Discard the prefixes \.{\\long} and \.{\\outer} if they are irrelevant\X
+\U1211.
+\I\X978:Dispense with trivial cases of void or bad boxes\X
+\U977.
+\I\X197:Display adjustment \|p\X
+\U183.
+\I\X184:Display box \|p\X
+\U183.
+\I\X695:Display choice node \|p\X
+\U690.
+\I\X195:Display discretionary \|p\X
+\U183.
+\I\X697:Display fraction noad \|p\X
+\U690.
+\I\X189:Display glue \|p\X
+\U183.
+\I\X188:Display insertion \|p\X
+\U183.
+\I\X191:Display kern \|p\X
+\U183.
+\I\X190:Display leaders \|p\X
+\U189.
+\I\X193:Display ligature \|p\X
+\U183.
+\I\X196:Display mark \|p\X
+\U183.
+\I\X192:Display math node \|p\X
+\U183.
+\I\X183:Display node \|p\X
+\U182.
+\I\X696:Display normal noad \|p\X
+\U690.
+\I\X194:Display penalty \|p\X
+\U183.
+\I\X187:Display rule \|p\X
+\U183.
+\I\X185:Display special fields of the unset node \|p\X
+\U184.
+\I\X312:Display the current context\X
+\U311.
+\I\X1011:Display the insertion split cost\X
+\U1010.
+\I\X1006:Display the page break cost\X
+\U1005.
+\I\X294:Display the token $(\|m,\|c)$\X
+\U293.
+\I\X502:Display the value of \|b\X
+\U498.
+\I\X186:Display the value of \\{glue\_set}(\|p)\X
+\U184.
+\I\X1356:Display the whatsit node \|p\X
+\U183.
+\I\X293:Display token \|p, and \&{return} if there are problems\X
+\U292.
+\I\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
+\U727.
+\I\X1040:Do ligature or kern command, returning to \\{main\_lig\_loop} or \\{main\_loop\_wrapup} or \\{main\_loop\_move}\X
+\U1039.
+\I\X320:Do magic computation\X
+\U292.
+\I\X1374:Do some work that has been queued up for \.{\\write}\X
+\U1373.
+\I\X1066:Drop current token and complain that it was unmatched\X
+\U1064.
+\I\X1326:Dump a couple more things and the closing check word\X
+\U1302.
+\I\X1307:Dump constants for consistency check\X
+\U1302.
+\I\X1315:Dump regions 1 to 4 of \\{eqtb}\X
+\U1313.
+\I\X1316:Dump regions 5 and 6 of \\{eqtb}\X
+\U1313.
+\I\X1322:Dump the array info for internal font number \|k\X
+\U1320.
+\I\X1311:Dump the dynamic memory\X
+\U1302.
+\I\X1320:Dump the font information\X
+\U1302.
+\I\X1318:Dump the hash table\X
+\U1313.
+\I\X1324:Dump the hyphenation tables\X
+\U1302.
+\I\X1309:Dump the string pool\X
+\U1302.
+\I\X1313:Dump the table of equivalents\X
+\U1302.
+\I\X1022:Either append the insertion node \|p after node \|q, and remove it from the current page, or delete \\{node}(\|p)\X
+\U1020.
+\I\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
+\U1014.
+\I\X501:Either process \.{\\ifcase} or set \|b to the value of a boolean condition\X
+\U498.
+\I\X599:Empty the last bytes out of \\{dvi\_buf}\X
+\U642.
+\I\X1028:Ensure that box 255 is empty after output\X
+\U1026.
+\I\X1015:Ensure that box 255 is empty before output\X
+\U1014.
+\I\X954:Ensure that $\\{trie\_max}\G\|h+\T{256}$\X
+\U953.
+\I\X939:Enter a hyphenation exception\X
+\U935.
+\I\X961:Enter all of the patterns into a linked trie, until coming to a right brace\X
+\U960.
+\I\X935:Enter as many hyphenation exceptions as are listed, until coming to a right brace; then \&{return}\X
+\U934.
+\I\X349:Enter \\{skip\_blanks} state, emit a space\X
+\U347.
+\I\X78, 81, 82, 93, 94, 95:Error handling procedures\X
+\U4.
+\I\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
+\U649.
+\I\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
+\U668.
+\I\X367:Expand a nonmacro\X
+\U366.
+\I\X1371:Expand macros in the token list and make \\{link}(\\{def\_ref}) point to the result\X
+\U1370.
+\I\X478:Expand the next part of the input\X
+\U477.
+\I\X368:Expand the token after the next token\X
+\U367.
+\I\X1024:Explain that too many dead cycles have occurred in a row\X
+\U1012.
+\I\X446:Express astonishment that no number was here\X
+\U444.
+\I\X1128:Express consternation over the fact that no alignment is in progress\X
+\U1127.
+\I\X475:Express shock at the missing left brace; \&{goto} \\{found}\X
+\U474.
+\I\X390:Feed the macro body and its parameters to the scanner\X
+\U389.
+\I\X420:Fetch a box dimension\X
+\U413.
+\I\X414:Fetch a character code from some table\X
+\U413.
+\I\X425:Fetch a font dimension\X
+\U413.
+\I\X426:Fetch a font integer\X
+\U413.
+\I\X427:Fetch a register\X
+\U413.
+\I\X415:Fetch a token list or font identifier, provided that $\\{level}\K\\{tok\_val}$\X
+\U413.
+\I\X449:Fetch an internal dimension and \&{goto} \\{attach\_sign}, or fetch an internal integer\X
+\U448.
+\I\X424:Fetch an item in the current node, if appropriate\X
+\U413.
+\I\X421:Fetch something on the \\{page\_so\_far}\X
+\U413.
+\I\X419:Fetch the \\{dead\_cycles} or the \\{insert\_penalties}\X
+\U413.
+\I\X423:Fetch the \\{par\_shape} size\X
+\U413.
+\I\X422:Fetch the \\{prev\_graf}\X
+\U413.
+\I\X418:Fetch the \\{space\_factor} or the \\{prev\_depth}\X
+\U413.
+\I\X874:Find an active node with fewest demerits\X
+\U873.
+\I\X923:Find hyphen locations for the word in \\{hc}, or \&{return}\X
+\U895.
+\I\X863:Find optimal breakpoints\X
+\U815.
+\I\X875:Find the best active node for the desired looseness\X
+\U873.
+\I\X1010:Find the best way to split the insertion, and change \\{type}(\|r) to \\{split\_up}\X
+\U1008.
+\I\X1042:Find the glue specification, \\{main\_p}, for text spaces in the current font\X
+\Us1041\ET1043.
+\I\X1206:Finish an alignment in a display\X
+\U812.
+\I\X1199:Finish displayed math\X
+\U1194.
+\I\X663:Finish issuing a diagnostic message for an overfull or underfull hbox\X
+\U649.
+\I\X675:Finish issuing a diagnostic message for an overfull or underfull vbox\X
+\U668.
+\I\X351:Finish line, emit a \.{\\par}\X
+\U347.
+\I\X348:Finish line, emit a space\X
+\U347.
+\I\X350:Finish line, \&{goto} \&{switch}\X
+\U347.
+\I\X1196:Finish math in text\X
+\U1194.
+\I\X642:Finish the \.{DVI} file\X
+\U1333.
+\I\X1378:Finish the extensions\X
+\U1333.
+\I\X1025:Fire up the user's output routine and \&{return}\X
+\U1012.
+\I\X430:Fix the reference count, if any, and negate \\{cur\_val} if \\{negative}\X
+\U413.
+\I\X639:Flush the box from memory, showing statistics if requested\X
+\U638.
+\I\X1048, 1098, 1111, 1144:Forbidden cases detected in \\{main\_control}\X
+\U1045.
+\I\X610:Generate a \\{down} or \\{right} command for \|w and \&{return}\X
+\U607.
+\I\X609:Generate a \\{y0} or \\{z0} command in order to reuse a previous appearance of~\|w\X
+\U607.
+\I\X952:Get ready to compress the trie\X
+\U966.
+\I\X816, 827, 834, 848:Get ready to start line breaking\X
+\U815.
+\I\X1337:Get the first line of input and prepare to start\X
+\U1332.
+\I\X406:Get the next non-blank non-call token\X
+\Us405, 441, 455, 503, 525, 577, 785, 791\ETs1045.
+\I\X404:Get the next non-blank non-relax non-call token\X
+\Us403, 1078, 1084, 1151, 1160, 1211, 1226\ETs1270.
+\I\X441:Get the next non-blank non-sign token; set \\{negative} appropriately\X
+\Us440, 448\ETs461.
+\I\X358:Get the next token, suppressing expansion\X
+\U357.
+\I\X83:Get user's advice and \&{return}\X
+\U82.
+\I\X1031:Give diagnostic information, if requested\X
+\U1030.
+\I\X936:Give improper \.{\\hyphenation} error\X
+\U935.
+\I\X13, 20, 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, 1345:Global variables\X
+\U4.
+\I\X1145:Go into display math mode\X
+\U1138.
+\I\X1139:Go into ordinary math mode\X
+\Us1138\ET1142.
+\I\X801:Go through the preamble list, determining the column widths and changing the alignrecords to dummy unset boxes\X
+\U800.
+\I\X126:Grow more variable-size memory and \&{goto} \\{restart}\X
+\U125.
+\I\X347:Handle situations involving spaces, braces, changes of state\X
+\U344.
+\I\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
+\U829.
+\I\X955:If all characters of the family fit relative to \|h, then \&{goto} \\{found},\30\ otherwise \&{goto} \\{not\_found}\X
+\U953.
+\I\X342:If an alignment entry has just ended, take appropriate action\X
+\U341.
+\I\X355:If an expanded code is present, reduce it and \&{goto} \\{start\_cs}\X
+\Us354\ET356.
+\I\X1304:If dumping is not allowed, abort\X
+\U1302.
+\I\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
+\U752.
+\I\X902:If no hyphens were found, \&{return}\X
+\U895.
+\I\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
+\U866.
+\I\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
+\U970.
+\I\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
+\U760.
+\I\X832:If node \|r is of type \\{delta\_node}, update \\{cur\_active\_width}, set \\{prev\_r} and \\{prev\_prev\_r}, then \&{goto} \&{continue}\X
+\U829.
+\I\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
+\U1079.
+\I\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
+\U997.
+\I\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
+\U1034.
+\I\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
+\U474.
+\I\X792:If the preamble list has been traversed, check that the row has ended\X
+\U791.
+\I\X1227:If the right-hand side is a token parameter or token register, finish the assignment and \&{goto} \\{done}\X
+\U1226.
+\I\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
+\U930.
+\I\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
+\U940.
+\I\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
+\U906.
+\I\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
+\U1034.
+\I\X1260:If this font has already been loaded, set \|f to the internal font number and \&{goto} \\{common\_ending}\X
+\U1257.
+\I\X352:If this \\{sup\_mark} starts an expanded character like~\.{\^\^A} or~\.{\^\^df}, then \&{goto} \\{reswitch}, otherwise set \\{state}: $\K$ \\{mid\_line}\X
+\U344.
+\I\X1183:Ignore the fraction operation and complain about this ambiguous case\X
+\U1181.
+\I\X1353:Implement \.{\\closeout}\X
+\U1348.
+\I\X1375:Implement \.{\\immediate}\X
+\U1348.
+\I\X1351:Implement \.{\\openout}\X
+\U1348.
+\I\X1377:Implement \.{\\setlanguage}\X
+\U1348.
+\I\X1354:Implement \.{\\special}\X
+\U1348.
+\I\X1352:Implement \.{\\write}\X
+\U1348.
+\I\X1359:Incorporate a whatsit node into a vbox\X
+\U669.
+\I\X1360:Incorporate a whatsit node into an hbox\X
+\U651.
+\I\X653:Incorporate box dimensions into the dimensions of the hbox that will contain~it\X
+\U651.
+\I\X670:Incorporate box dimensions into the dimensions of the vbox that will contain~it\X
+\U669.
+\I\X654:Incorporate character dimensions into the dimensions of the hbox that will contain~it, then move to the next node\X
+\U651.
+\I\X656:Incorporate glue into the horizontal totals\X
+\U651.
+\I\X671:Incorporate glue into the vertical totals\X
+\U669.
+\I\X580:Increase the number of parameters in the last font\X
+\U578.
+\I\X891:Initialize for hyphenating a paragraph\X
+\U863.
+\I\X164, 222, 228, 232, 240, 250, 258, 552, 946, 951, 1216, 1301, 1369:Initialize table entries (done by \.{INITEX} only)\X
+\U8.
+\I\X1001:Initialize the current page, insert the \.{\\topskip} glue ahead of \|p, and \&{goto} \&{continue}\X
+\U1000.
+\I\X331:Initialize the input routines\X
+\U1337.
+\I\X55, 61, 527, 533:Initialize the output routines\X
+\U1332.
+\I\X75:Initialize the print \\{selector} based on \\{interaction}\X
+\Us1265\ET1337.
+\I\X790, 797, 820, 981, 988:Initialize the special list heads and constant nodes\X
+\U164.
+\I\X617:Initialize variables as \\{ship\_out} begins\X
+\U640.
+\I\X8:Initialize whatever \TeX\ might access\X
+\U4.
+\I\X378:Initiate or terminate input from a file\X
+\U367.
+\I\X1083:Initiate the construction of an hbox or vbox, then \&{return}\X
+\U1079.
+\I\X483:Input and store tokens from the next line of the file\X
+\U482.
+\I\X484:Input for \.{\\read} from the terminal\X
+\U483.
+\I\X343:Input from external file, \&{goto} \\{restart} if no input found\X
+\U341.
+\I\X357:Input from token list, \&{goto} \\{restart} if end of list or if a parameter needs to be expanded\X
+\U341.
+\I\X485:Input the first line of \\{read\_file}[\|m]\X
+\U483.
+\I\X486:Input the next line of \\{read\_file}[\|m]\X
+\U483.
+\I\X843:Insert a delta node to prepare for breaks at \\{cur\_p}\X
+\U836.
+\I\X844:Insert a delta node to prepare for the next active node\X
+\U836.
+\I\X1177:Insert a dummy noad to be sub/superscripted\X
+\U1176.
+\I\X845:Insert a new active node from \\{best\_place}[\\{fit\_class}] to \\{cur\_p}\X
+\U836.
+\I\X260:Insert a new control sequence after \|p, then make \|p point to it\X
+\U259.
+\I\X963:Insert a new pattern into the linked trie\X
+\U961.
+\I\X964:Insert a new trie node between \|q and \|p, and make \|p point to it\X
+\U963.
+\I\X375:Insert a token containing \\{frozen\_endv}\X
+\U366.
+\I\X1269:Insert a token saved by \.{\\afterassignment}, if any\X
+\U1211.
+\I\X969:Insert glue for \\{split\_top\_skip} and set~\|p: $\K$ \\{null}\X
+\U968.
+\I\X932:Insert hyphens as specified in \\{hyph\_list}[\|h]\X
+\U931.
+\I\X359:Insert macro parameter and \&{goto} \\{restart}\X
+\U357.
+\I\X386:Insert the \(a)appropriate mark text into the scanner\X
+\U367.
+\I\X812:Insert the \(c)current list into its environment\X
+\U800.
+\I\X940:Insert the \(p)pair $(\|s,\|p)$ into the exception table\X
+\U939.
+\I\X789:Insert the \(v)\<v_j> template and \&{goto} \\{restart}\X
+\U342.
+\I\X326:Insert token \|p into \TeX's input\X
+\U282.
+\I\X84:Interpret code \|c and \&{return} if done\X
+\U83.
+\I\X87:Introduce new material from the terminal and \&{return}\X
+\U84.
+\I\X579:Issue an error message if $\\{cur\_val}\K\\{fmem\_ptr}$\X
+\U578.
+\I\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
+\U877.
+\I\X6:Labels in the outer block\X
+\U4.
+\I\X1333, 1335, 1336, 1338:Last-minute procedures\X
+\U1330.
+\I\X793:Lengthen the preamble periodically\X
+\U792.
+\I\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
+\U626.
+\I\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
+\U635.
+\I\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
+\U1146.
+\I\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
+\U1147.
+\I\X1361:Let \|d be the width of the whatsit \|p\X
+\U1147.
+\I\X1233:Let \|n be the largest legal code value, based on \\{cur\_chr}\X
+\U1232.
+\I\X998:Link node \|p into the current page and \&{goto} \\{done}\X
+\U997.
+\I\X450:Local variables for dimension calculations\X
+\U448.
+\I\X1198:Local variables for finishing a displayed formula\X
+\U1194.
+\I\X315:Local variables for formatting calculations\X
+\U311.
+\I\X901, 912, 922, 929:Local variables for hyphenation\X
+\U895.
+\I\X19, 163, 927:Local variables for initialization\X
+\U4.
+\I\X862, 893:Local variables for line breaking\X
+\U815.
+\I\X1038:Look ahead for another character, or leave \\{lig\_stack} empty if there's none there\X
+\U1034.
+\I\X979:Look at all the marks in nodes before the break, and set the final link to \\{null} at the break\X
+\U977.
+\I\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
+\U707.
+\I\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
+\U607.
+\I\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
+\U706.
+\I\X479:Look for parameter number or \.{\#\#}\X
+\U477.
+\I\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
+\U923.
+\I\X374:Look up the characters of list \|r in the hash table, and set \\{cur\_cs}\X
+\U372.
+\I\X205:Make a copy of node \|p in node \|r\X
+\U204.
+\I\X1035:Make a ligature node, if \\{ligature\_present}; insert a null discretionary, if appropriate\X
+\U1034.
+\I\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
+\U206.
+\I\X760:Make a second pass over the mlist, removing all noads and inserting the proper spacing and penalties\X
+\U726.
+\I\X576:Make final adjustments and \&{goto} \\{done}\X
+\U562.
+\I\X652:Make node \|p look like a \\{char\_node} and \&{goto} \\{reswitch}\X
+\Us622, 651\ETs1147.
+\I\X1003:Make sure that \\{page\_max\_depth} is not exceeded\X
+\U997.
+\I\X831:Make sure that \\{pi} is in the proper range\X
+\U829.
+\I\X995:Make the contribution list empty by setting its tail to \\{contrib\_head}\X
+\U994.
+\I\X48:Make the first 256 strings\X
+\U47.
+\I\X739:Make the height of box \|y equal to \|h\X
+\U738.
+\I\X806:Make the running dimensions in rule \|q extend to the boundaries of the alignment\X
+\U805.
+\I\X811:Make the unset node \|r into a \\{vlist\_node} of height \|w, setting the glue as if the height were \|t\X
+\U808.
+\I\X810:Make the unset node \|r into an \\{hlist\_node} of width \|w, setting the glue as if the width were \|t\X
+\U808.
+\I\X710:Make variable \|b point to a box for $(\|f,\|c)$\X
+\U706.
+\I\X372:Manufacture a control sequence name\X
+\U367.
+\I\X1046:Math-only cases in non-math modes, or vice versa\X
+\U1045.
+\I\X803:Merge the widths in the span nodes of \|q with those of \|p, destroying the span nodes of \|q\X
+\U801.
+\I\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
+\U880.
+\I\X1044:Modify the glue specification in \\{main\_p} according to the space factor\X
+\U1043.
+\I\X634:Move down or output leaders\X
+\U631.
+\I\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
+\U994.
+\I\X918:Move pointer \|s to the end of the current list, and set \\{replace\_count}(\|r) appropriately\X
+\U914.
+\I\X625:Move right or output leaders\X
+\U622.
+\I\X898:Move the characters of a ligature node to \\{hu} and \\{hc}; but \&{goto} \\{done3} if they are not all letters\X
+\U897.
+\I\X1037:Move the cursor past a pseudo-ligature, then \&{goto} \\{main\_loop\_lookahead} or \\{main\_lig\_loop}\X
+\U1034.
+\I\X958:Move the data into \\{trie}\X
+\U966.
+\I\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
+\U343.
+\I\X431:Negate all three glue components of \\{cur\_val}\X
+\U430.
+\I\X802:Nullify \\{width}(\|q) and the tabskip glue following this column\X
+\U801.
+\I\X1339:Numbered cases for \\{debug\_help}\X
+\U1338.
+\I\X563:Open \\{tfm\_file} for input\X
+\U562.
+\I\X830:Other local variables for \\{try\_break}\X
+\U829.
+\I\X632:Output a box in a vlist\X
+\U631.
+\I\X623:Output a box in an hlist\X
+\U622.
+\I\X628:Output a leader box at \\{cur\_h}, then advance \\{cur\_h} by $\\{leader\_wd}+\\{lx}$\X
+\U626.
+\I\X637:Output a leader box at \\{cur\_v}, then advance \\{cur\_v} by $\\{leader\_ht}+\\{lx}$\X
+\U635.
+\I\X633:Output a rule in a vlist, \&{goto} \\{next\_p}\X
+\U631.
+\I\X624:Output a rule in an hlist\X
+\U622.
+\I\X635:Output leaders in a vlist, \&{goto} \\{fin\_rule} if a rule or to \\{next\_p} if done\X
+\U634.
+\I\X626:Output leaders in an hlist, \&{goto} \\{fin\_rule} if a rule or to \\{next\_p} if done\X
+\U625.
+\I\X620:Output node \|p for \\{hlist\_out} and move to the next node, maintaining the condition $\\{cur\_v}\K\\{base\_line}$\X
+\U619.
+\I\X630:Output node \|p for \\{vlist\_out} and move to the next node, maintaining the condition $\\{cur\_h}\K\\{left\_edge}$\X
+\U629.
+\I\X1334:Output statistics about this job\X
+\U1333.
+\I\X643:Output the font definitions for all fonts that were used\X
+\U642.
+\I\X603:Output the font name whose internal number is \|f\X
+\U602.
+\I\X622:Output the non-\\{char\_node} \|p for \\{hlist\_out} and move to the next node\X
+\U620.
+\I\X631:Output the non-\\{char\_node} \|p for \\{vlist\_out}\X
+\U630.
+\I\X1366:Output the whatsit node \|p in a vlist\X
+\U631.
+\I\X1367:Output the whatsit node \|p in an hlist\X
+\U622.
+\I\X956:Pack the family into \\{trie} relative to \|h\X
+\U953.
+\I\X796:Package an unset box for the current column and record its width\X
+\U791.
+\I\X804:Package the preamble list, to determine the actual tabskip glue amounts, and let \|p point to this prototype box\X
+\U800.
+\I\X1023:Perform the default output routine\X
+\U1012.
+\I\X1207:Pontificate about improper alignment in display\X
+\U1206.
+\I\X496:Pop the condition stack\X
+\Us498, 500, 509\ETs510.
+\I\X1018:Prepare all the boxes involved in insertions to act as queues\X
+\U1014.
+\I\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
+\U851.
+\I\X1065:Prepare to insert a token that matches \\{cur\_group}, and print what it is\X
+\U1064.
+\I\X1002:Prepare to move a box or rule node to the current page, then \&{goto} \\{contribute}\X
+\U1000.
+\I\X1364:Prepare to move whatsit \|p to the current page, then \&{goto} \\{contribute}\X
+\U1000.
+\I\X175:Print a short indication of the contents of node \|p\X
+\U174.
+\I\X846:Print a symbolic description of the new break node\X
+\U845.
+\I\X856:Print a symbolic description of this feasible break\X
+\U855.
+\I\X339:Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `\.{text}', and insert tokens that should lead to recovery\X
+\U338.
+\I\X313:Print location of current line\X
+\U312.
+\I\X171:Print newly busy locations\X
+\U167.
+\I\X1283:Print string \|s as an error message\X
+\U1279.
+\I\X1280:Print string \|s on the terminal\X
+\U1279.
+\I\X536:Print the banner line, including the date and time\X
+\U534.
+\I\X267:Print the font identifier for \\{font}(\|p)\X
+\Us174\ET176.
+\I\X89:Print the help information and \&{goto} \&{continue}\X
+\U84.
+\I\X857:Print the list between \\{printed\_node} and \\{cur\_p}, then set \\{printed\_node}: $\K$ \\{cur\_p}\X
+\U856.
+\I\X85:Print the menu of available options\X
+\U84.
+\I\X472:Print the result of command \|c\X
+\U470.
+\I\X317:Print two lines using the tricky pseudoprinted information\X
+\U312.
+\I\X314:Print type of token list\X
+\U312.
+\I\X353:Process an active-character control sequence and set \\{state}: $\K$ \\{mid\_line}\X
+\U344.
+\I\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
+\U726.
+\I\X1365:Process whatsit \|p in \\{vert\_break} loop, \&{goto} \\{not\_found}\X
+\U973.
+\I\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
+\U1119.
+\I\X879:Prune unwanted nodes at the beginning of the next line\X
+\U877.
+\I\X318:Pseudoprint the line\X
+\U312.
+\I\X319:Pseudoprint the token list\X
+\U312.
+\I\X495:Push the condition stack\X
+\U498.
+\I\X226, 230, 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, 1344:Put each of \TeX's primitives
+into the hash table\X
+\U1336.
+\I\X90:Put help message on the transcript file\X
+\U82.
+\I\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
+\U914.
+\I\X915:Put the \(c)characters $\\{hu}[\|l\MRL{{.}{.}}\|i]$ and a hyphen into \\{pre\_break}(\|r)\X
+\U914.
+\I\X748:Put the \(f)fraction into a box with its delimiters, and make \\{new\_hlist}(\|q) point to it\X
+\U743.
+\I\X887:Put the \(l)\.{\\leftskip} glue at the left and detach this line\X
+\U880.
+\I\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
+\U1012.
+\I\X1259:Put the \(p)(positive) `at' size into \|s\X
+\U1258.
+\I\X886:Put the \(r)\.{\\rightskip} glue after node \|q\X
+\U881.
+\I\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
+\U560.
+\I\X571:Read box dimensions\X
+\U562.
+\I\X569:Read character data\X
+\U562.
+\I\X574:Read extensible character recipes\X
+\U562.
+\I\X575:Read font parameters\X
+\U562.
+\I\X573:Read ligature/kern program\X
+\U562.
+\I\X362:Read next line of file into \\{buffer}, or \&{goto} \\{restart} if the file has ended\X
+\U360.
+\I\X52:Read one string, but return \\{false} if the string memory space is getting too tight for comfort\X
+\U51.
+\I\X538:Read the first line of the new file\X
+\U537.
+\I\X51:Read the other strings from the \.{TEX.POOL} file and return \\{true}, or give an error message and return \\{false}\X
+\U47.
+\I\X568:Read the {\.{TFM}} header\X
+\U562.
+\I\X565:Read the {\.{TFM}} size fields\X
+\U562.
+\I\X1087:Readjust the height and depth of \\{cur\_box}, for \.{\\vtop}\X
+\U1086.
+\I\X913:Reconstitute nodes for the hyphenated word, inserting discretionary hyphens\X
+\U903.
+\I\X855:Record a new feasible break\X
+\U851.
+\I\X1027:Recover from an unbalanced output routine\X
+\U1026.
+\I\X1372:Recover from an unbalanced write command\X
+\U1371.
+\I\X999:Recycle node \|p\X
+\U997.
+\I\X1081:Remove the last box, unless it's part of a discretionary\X
+\U1080.
+\I\X903:Replace nodes $\\{ha}\MRL{{.}{.}}\\{hb}$ by a sequence of nodes that includes the discretionary hyphens\X
+\U895.
+\I\X1187:Replace the tail of the list by \|p\X
+\U1186.
+\I\X572:Replace \|z by $\|z^\prime$ and compute $\alpha,\beta$\X
+\U571.
+\I\X396:Report a runaway argument and abort\X
+\Us392\ET399.
+\I\X667:Report a tight hbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X
+\U664.
+\I\X678:Report a tight vbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X
+\U676.
+\I\X395:Report an extra right brace and \&{goto} \&{continue}\X
+\U392.
+\I\X398:Report an improper use of the macro and abort\X
+\U397.
+\I\X666:Report an overfull hbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X
+\U664.
+\I\X677:Report an overfull vbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X
+\U676.
+\I\X660:Report an underfull hbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X
+\U658.
+\I\X674:Report an underfull vbox and \&{goto} \\{common\_ending}, if this box is sufficiently bad\X
+\U673.
+\I\X35:Report overflow of the input buffer, and abort\X
+\U31.
+\I\X1161:Report that an invalid delimiter code is being changed to null; set~\\{cur\_val}: $\K$ \T{0}\X
+\U1160.
+\I\X561:Report that the font won't be loaded\X
+\U560.
+\I\X460:Report that this dimension is out of range\X
+\U448.
+\I\X1026:Resume the page builder after an output routine has come to an end\X
+\U1100.
+\I\X878:Reverse the links of the relevant passive nodes, setting \\{cur\_p} to the first breakpoint\X
+\U877.
+\I\X354:Scan a control sequence and set \\{state}: $\K$ \\{skip\_blanks} or \\{mid\_line}\X
+\U344.
+\I\X444:Scan a numeric constant\X
+\U440.
+\I\X392:Scan a parameter until its delimiter string has been found; or, if $\|s\K\\{null}$, simply scan the delimiter string\X
+\U391.
+\I\X1153:Scan a subformula enclosed in braces and \&{return}\X
+\U1151.
+\I\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
+\U354.
+\I\X442:Scan an alphabetic character code into \\{cur\_val}\X
+\U440.
+\I\X443:Scan an optional space\X
+\Us442, 448, 455\ETs1200.
+\I\X477:Scan and build the body of the token list; \&{goto} \\{found} when finished\X
+\U473.
+\I\X474:Scan and build the parameter part of the macro definition\X
+\U473.
+\I\X452:Scan decimal fraction\X
+\U448.
+\I\X530:Scan file name in the buffer\X
+\U529.
+\I\X458:Scan for \(a)all other units and adjust \\{cur\_val} and \|f accordingly; \&{goto} \\{done} in the case of scaled points\X
+\U453.
+\I\X454:Scan for \(f)\.{fil} units; \&{goto} \\{attach\_fraction} if found\X
+\U453.
+\I\X456:Scan for \(m)\.{mu} units and \&{goto} \\{attach\_fraction}\X
+\U453.
+\I\X455:Scan for \(u)units that are internal dimensions; \&{goto} \\{attach\_sign} with \\{cur\_val} set if found\X
+\U453.
+\I\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
+\U777.
+\I\X471:Scan the argument for command \|c\X
+\U470.
+\I\X1258:Scan the font size specification\X
+\U1257.
+\I\X391:Scan the parameters and make \\{link}(\|r) point to the macro body; but \&{return} if an illegal \.{\\par} is detected\X
+\U389.
+\I\X777:Scan the preamble and record it in the \\{preamble} list\X
+\U774.
+\I\X783:Scan the template \<u_j>, putting the resulting token list in \\{hold\_head}\X
+\U779.
+\I\X784:Scan the template \<v_j>, putting the resulting token list in \\{hold\_head}\X
+\U779.
+\I\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
+\U448.
+\I\X255:Search \\{eqtb} for equivalents equal to \|p\X
+\U172.
+\I\X933:Search \\{hyph\_list} for pointers to \|p\X
+\U172.
+\I\X285:Search \\{save\_stack} for equivalents that point to \|p\X
+\U172.
+\I\X509:Select the appropriate case and \&{return} or \&{goto} \\{common\_ending}\X
+\U501.
+\I\X21, 23, 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, 1343:Set initial values of key variables\X
+\U8.
+\I\X849:Set line length parameters in preparation for hanging indentation\X
+\U848.
+\I\X805:Set the glue in all the unset boxes of the current list\X
+\U800.
+\I\X808:Set the glue in node \|r and change it from an unset node\X
+\U807.
+\I\X807:Set the unset box \|q and the unset boxes in it\X
+\U805.
+\I\X853:Set the value of \|b to the badness for shrinking the line, and compute the corresponding \\{fit\_class}\X
+\U851.
+\I\X852:Set the value of \|b to the badness for stretching the line, and compute the corresponding \\{fit\_class}\X
+\U851.
+\I\X1013:Set the value of \\{output\_penalty}\X
+\U1012.
+\I\X908:Set up data structures with the cursor following position \|j\X
+\U906.
+\I\X703:Set up the values of \\{cur\_size} and \\{cur\_mu}, based on \\{cur\_style}\X
+\Us720, 726, 730, 754, 760\ETs763.
+\I\X243:Set variable \|c to the current escape character\X
+\U63.
+\I\X640:Ship box \|p out\X
+\U638.
+\I\X223:Show equivalent \|n, in region 1 or 2\X
+\U252.
+\I\X229:Show equivalent \|n, in region 3\X
+\U252.
+\I\X233:Show equivalent \|n, in region 4\X
+\U252.
+\I\X242:Show equivalent \|n, in region 5\X
+\U252.
+\I\X251:Show equivalent \|n, in region 6\X
+\U252.
+\I\X219:Show the auxiliary field, \|a\X
+\U218.
+\I\X1296:Show the current contents of a box\X
+\U1293.
+\I\X1294:Show the current meaning of a token, then \&{goto} \\{common\_ending}\X
+\U1293.
+\I\X1297:Show the current value of some parameter or register, then \&{goto} \\{common\_ending}\X
+\U1293.
+\I\X234:Show the font identifier in \\{eqtb}[\|n]\X
+\U233.
+\I\X235:Show the halfword code in \\{eqtb}[\|n]\X
+\U233.
+\I\X986:Show the status of the current page\X
+\U218.
+\I\X401:Show the text of the macro being expanded\X
+\U389.
+\I\X721:Simplify a trivial box\X
+\U720.
+\I\X500:Skip to \.{\\else} or \.{\\fi}, then \&{goto} \\{common\_ending}\X
+\U498.
+\I\X896:Skip to node \\{ha}, or \&{goto} \\{done1} if no hyphenation should be attempted\X
+\U894.
+\I\X897:Skip to node \\{hb}, putting letters into \\{hu} and \\{hc}\X
+\U894.
+\I\X132:Sort \(p)\|p into the list starting at \\{rover} and advance \|p to \\{rlink}(\|p)\X
+\U131.
+\I\X945:Sort \(t)the hyphenation op tables into proper order\X
+\U952.
+\I\X1082:Split off part of a vertical box, make \\{cur\_box} point to it\X
+\U1079.
+\I\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
+\U1199.
+\I\X991:Start a new current page\X
+\Us215\ET1017.
+\I\X1077:Store \(c)\\{cur\_box} in a box register\X
+\U1075.
+\I\X924:Store \(m)maximum values in the \\{hyf} table\X
+\U923.
+\I\X283:Store \(s)\\{save\_stack}[\\{save\_ptr}] in \\{eqtb}[\|p], unless \\{eqtb}[\|p] holds a global value\X
+\U282.
+\I\X393:Store the current token, but \&{goto} \&{continue} if it is a blank space that would become an undelimited parameter\X
+\U392.
+\I\X838:Subtract glue from \\{break\_width}\X
+\U837.
+\I\X841:Subtract the width of node \|v from \\{break\_width}\X
+\U840.
+\I\X369:Suppress expansion of the next token\X
+\U367.
+\I\X742:Swap the subscript and superscript into box \|x\X
+\U738.
+\I\X740:Switch to a larger accent if available and appropriate\X
+\U738.
+\I\X338:Tell the user what has run away and try to recover\X
+\U336.
+\I\X510:Terminate the current conditional and skip to \.{\\fi}\X
+\U367.
+\I\X505:Test box register status\X
+\U501.
+\I\X504:Test if an integer is odd\X
+\U501.
+\I\X506:Test if two characters match\X
+\U501.
+\I\X508:Test if two macro texts match\X
+\U507.
+\I\X507:Test if two tokens match\X
+\U501.
+\I\X503:Test relation between integers or dimensions\X
+\U501.
+\I\X558:The em width for \\{cur\_font}\X
+\U455.
+\I\X559:The x-height for \\{cur\_font}\X
+\U455.
+\I\X400:Tidy up the parameter just scanned, and tuck it away\X
+\U392.
+\I\X655:Transfer node \|p to the adjustment list\X
+\U651.
+\I\X884:Transplant the post-break list\X
+\U882.
+\I\X885:Transplant the pre-break list\X
+\U882.
+\I\X1152:Treat \\{cur\_chr} as an active character\X
+\Us1151\ET1155.
+\I\X873:Try the final line break at the end of the paragraph, and \&{goto} \\{done} if the desired breakpoints have been found\X
+\U863.
+\I\X127:Try to allocate within node \|p and its physical successors, and \&{goto} \\{found} if allocation was possible\X
+\U125.
+\I\X869:Try to break after a discretionary fragment, then \&{goto} \\{done5}\X
+\U866.
+\I\X535:Try to get a different log file name\X
+\U534.
+\I\X894:Try to hyphenate the following word\X
+\U866.
+\I\X1192:Try to recover from mismatched \.{\\right}\X
+\U1191.
+\I\X18, 25, 38, 101, 109, 113, 150, 212, 269, 300, 548, 594, 920, 925:Types in the outer block\X
+\U4.
+\I\X1327:Undump a couple more things and the closing check word\X
+\U1303.
+\I\X1308:Undump constants for consistency check\X
+\U1303.
+\I\X1317:Undump regions 1 to 6 of \\{eqtb}\X
+\U1314.
+\I\X1323:Undump the array info for internal font number \|k\X
+\U1321.
+\I\X1312:Undump the dynamic memory\X
+\U1303.
+\I\X1321:Undump the font information\X
+\U1303.
+\I\X1319:Undump the hash table\X
+\U1314.
+\I\X1325:Undump the hyphenation tables\X
+\U1303.
+\I\X1310:Undump the string pool\X
+\U1303.
+\I\X1314:Undump the table of equivalents\X
+\U1303.
+\I\X861:Update the active widths, since the first active node has been deleted\X
+\U860.
+\I\X976:Update the current height and depth measurements with respect to a glue or kern node~\|p\X
+\U972.
+\I\X1004:Update the current page measurements with respect to the glue or kern specified by node~\|p\X
+\U997.
+\I\X858:Update the value of \\{printed\_node} for symbolic displays\X
+\U829.
+\I\X1016:Update the values of \\{first\_mark} and \\{bot\_mark}\X
+\U1014.
+\I\X996:Update the values of \\{last\_glue}, \\{last\_penalty}, and \\{last\_kern}\X
+\U994.
+\I\X641:Update the values of \\{max\_h} and \\{max\_v}; but if the page is too large, \&{goto} \\{done}\X
+\U640.
+\I\X798:Update width entry for spanned columns\X
+\U796.
+\I\X1182:Use code \|c to distinguish between generalized fractions\X
+\U1181.
+\I\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
+\U972.
+\I\X566:Use size fields to allocate font information\X
+\U562.
+\I\X1358:Wipe out the whatsit node \|p and \&{goto} \\{done}\X
+\U202.
+\I\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
+\U1020.
+\I\X531:ensure dvi open\X
+\Q531.
+\U617.
+\I\X1795:prepare for string pool initialization\X
+\U39.
+\I\X1781:\.{"\ (INITEX)"}\X
+\U1301.
+\I\X1635:\.{".dvi"}\X
+\Q528.
+\U531.
+\I\X1634:\.{".log"}\X
+\Q528.
+\Us534\ET535.
+\I\X1637:\.{".tex"}\X
+\Us529, 537, 1275\ETs1374.
+\I\X1640:\.{".tfm"}\X
+\U563.
+\I\X1674:\.{"256\ spans"}\X
+\U798.
+\I\X1381:\.{"???"}\X
+\U59.
+\I\X1567:\.{"BAD."}\X
+\Us293\ET294.
+\I\X1386:\.{"CLOBBERED."}\X
+\Us176\ET293.
+\I\X1566:\.{"ETC."}\X
+\U292.
+\I\X1764:\.{"FONT"}\X
+\U1257.
+\I\X1528:\.{"IMPOSSIBLE."}\X
+\U262.
+\I\X1529:\.{"NONEXISTENT."}\X
+\U262.
+\I\X1736:\.{"above"}\X
+\Us1178\ET1179.
+\I\X1410:\.{"abovedisplayshortsk}\)\.{ip"}\X
+\Us225\ET226.
+\I\X1408:\.{"abovedisplayskip"}\X
+\Us225\ET226.
+\I\X1739:\.{"abovewithdelims"}\X
+\Us1178\ET1179.
+\I\X1530:\.{"accent"}\X
+\Us265, 266\ETs696.
+\I\X1462:\.{"adjdemerits"}\X
+\Us237\ET238.
+\I\X1531:\.{"advance"}\X
+\Us265\ET266.
+\I\X1532:\.{"afterassignment"}\X
+\Us265\ET266.
+\I\X1533:\.{"aftergroup"}\X
+\Us265\ET266.
+\I\X1676:\.{"align0"}\X
+\U800.
+\I\X1675:\.{"align1"}\X
+\U800.
+\I\X1765:\.{"at"}\X
+\U1258.
+\I\X1738:\.{"atop"}\X
+\Us1178\ET1179.
+\I\X1741:\.{"atopwithdelims"}\X
+\Us1178\ET1179.
+\I\X1588:\.{"badness"}\X
+\Us416\ET417.
+\I\X1406:\.{"baselineskip"}\X
+\Us225\ET226.
+\I\X1383:\.{"batchmode"}\X
+\Us86, 1262\ETs1263.
+\I\X1534:\.{"begingroup"}\X
+\Us265\ET266.
+\I\X1411:\.{"belowdisplayshortsk}\)\.{ip"}\X
+\Us225\ET226.
+\I\X1409:\.{"belowdisplayskip"}\X
+\Us225\ET226.
+\I\X1455:\.{"binoppenalty"}\X
+\Us237\ET238.
+\I\X1574:\.{"botmark"}\X
+\Us384\ET385.
+\I\X1437:\.{"box"}\X
+\Us233, 1015, 1028, 1071\ETs1072.
+\I\X1510:\.{"boxmaxdepth"}\X
+\Us247\ET248.
+\I\X1596:\.{"bp"}\X
+\U458.
+\I\X1454:\.{"brokenpenalty"}\X
+\Us237\ET238.
+\I\X1761:\.{"by"}\X
+\U1236.
+\I\X1441:\.{"catcode"}\X
+\Us235, 1230\ETs1231.
+\I\X1598:\.{"cc"}\X
+\U458.
+\I\X1535:\.{"char"}\X
+\Us265, 266\ETs1223.
+\I\X1754:\.{"chardef"}\X
+\Us1222\ET1223.
+\I\X1722:\.{"cleaders"}\X
+\Us1071\ET1072.
+\I\X1769:\.{"closein"}\X
+\Us1272\ET1273.
+\I\X1784:\.{"closeout"}\X
+\Us1344, 1346\ETs1356.
+\I\X1451:\.{"clubpenalty"}\X
+\Us237\ET238.
+\I\X1594:\.{"cm"}\X
+\U458.
+\I\X1716:\.{"copy"}\X
+\Us1071\ET1072.
+\I\X1404:\.{"copying"}\X
+\U206.
+\I\X1501:\.{"count"}\X
+\Us239, 242, 411\ETs412.
+\I\X1756:\.{"countdef"}\X
+\Us1222\ET1223.
+\I\X1670:\.{"cr"}\X
+\Us780, 781, 792\ETs1132.
+\I\X1671:\.{"crcr"}\X
+\Us780\ET781.
+\I\X1526:\.{"csname"}\X
+\Us262, 263, 265\ETs266.
+\I\X1563:\.{"curlevel"}\X
+\U281.
+\I\X1467:\.{"day"}\X
+\Us237\ET238.
+\I\X1597:\.{"dd"}\X
+\U458.
+\I\X1579:\.{"deadcycles"}\X
+\Us416\ET417.
+\I\X1746:\.{"def"}\X
+\Us1208\ET1209.
+\I\X1492:\.{"defaulthyphenchar"}\X
+\Us237\ET238.
+\I\X1493:\.{"defaultskewchar"}\X
+\Us237\ET238.
+\I\X1502:\.{"delcode"}\X
+\Us242, 1230\ETs1231.
+\I\X1536:\.{"delimiter"}\X
+\Us265\ET266.
+\I\X1464:\.{"delimiterfactor"}\X
+\Us237\ET238.
+\I\X1513:\.{"delimitershortfall"}\X
+\Us247\ET248.
+\I\X1604:\.{"depth"}\X
+\U463.
+\I\X1524:\.{"dimen"}\X
+\Us249, 251, 411\ETs412.
+\I\X1757:\.{"dimendef"}\X
+\Us1222\ET1223.
+\I\X1677:\.{"disc1"}\X
+\U841.
+\I\X1678:\.{"disc2"}\X
+\U842.
+\I\X1680:\.{"disc3"}\X
+\U870.
+\I\X1681:\.{"disc4"}\X
+\U871.
+\I\X1400:\.{"discretionary"}\X
+\Us195, 856, 1114, 1115\ETs1120.
+\I\X1742:\.{"display"}\X
+\U1200.
+\I\X1518:\.{"displayindent"}\X
+\Us247\ET248.
+\I\X1735:\.{"displaylimits"}\X
+\Us1156\ET1157.
+\I\X1645:\.{"displaystyle"}\X
+\Us694\ET1169.
+\I\X1453:\.{"displaywidowpenalty}\)\.{"}\X
+\Us237\ET238.
+\I\X1517:\.{"displaywidth"}\X
+\Us247\ET248.
+\I\X1537:\.{"divide"}\X
+\Us265\ET266.
+\I\X1460:\.{"doublehyphendemerit}\)\.{s"}\X
+\Us237\ET238.
+\I\X1583:\.{"dp"}\X
+\Us416\ET417.
+\I\X1699:\.{"dump"}\X
+\Us1052\ET1053.
+\I\X1748:\.{"edef"}\X
+\Us1208\ET1209.
+\I\X1630:\.{"else"}\X
+\Us491\ET492.
+\I\X1590:\.{"em"}\X
+\U455.
+\I\X1523:\.{"emergencystretch"}\X
+\Us247\ET248.
+\I\X1782:\.{"end\ occurred\ "}\X
+\U1335.
+\I\X1698:\.{"end"}\X
+\Us1052\ET1053.
+\I\X1527:\.{"endcsname"}\X
+\Us262, 263, 265, 266, 373\ETs1135.
+\I\X1538:\.{"endgroup"}\X
+\Us265, 266, 1065\ETs1069.
+\I\X1571:\.{"endinput"}\X
+\Us376\ET377.
+\I\X1494:\.{"endlinechar"}\X
+\Us237\ET238.
+\I\X1672:\.{"endtemplate"}\X
+\U780.
+\I\X1673:\.{"endv"}\X
+\U791.
+\I\X1791:\.{"endwrite"}\X
+\U1369.
+\I\X1733:\.{"eqno"}\X
+\Us1141\ET1143.
+\I\X1434:\.{"errhelp"}\X
+\Us230\ET231.
+\I\X1771:\.{"errmessage"}\X
+\Us1277\ET1278.
+\I\X1500:\.{"errorcontextlines"}\X
+\Us237\ET238.
+\I\X1767:\.{"errorstopmode"}\X
+\Us1262\ET1263.
+\I\X1491:\.{"escapechar"}\X
+\Us237\ET238.
+\I\X1433:\.{"everycr"}\X
+\Us230\ET231.
+\I\X1429:\.{"everydisplay"}\X
+\Us230\ET231.
+\I\X1430:\.{"everyhbox"}\X
+\Us230\ET231.
+\I\X1432:\.{"everyjob"}\X
+\Us230\ET231.
+\I\X1428:\.{"everymath"}\X
+\Us230\ET231.
+\I\X1427:\.{"everypar"}\X
+\Us230\ET231.
+\I\X1431:\.{"everyvbox"}\X
+\Us230\ET231.
+\I\X1591:\.{"ex"}\X
+\U455.
+\I\X1450:\.{"exhyphenpenalty"}\X
+\Us237\ET238.
+\I\X1539:\.{"expandafter"}\X
+\Us265\ET266.
+\I\X1788:\.{"ext1"}\X
+\U1348.
+\I\X1789:\.{"ext2"}\X
+\U1357.
+\I\X1790:\.{"ext3"}\X
+\U1358.
+\I\X1792:\.{"ext4"}\X
+\U1373.
+\I\X1490:\.{"fam"}\X
+\Us237, 238\ETs691.
+\I\X1628:\.{"fi"}\X
+\Us491\ET492.
+\I\X1387:\.{"fil"}\X
+\U454.
+\I\X1461:\.{"finalhyphendemerits}\)\.{"}\X
+\Us237\ET238.
+\I\X1573:\.{"firstmark"}\X
+\Us384\ET385.
+\I\X1488:\.{"floatingpenalty"}\X
+\Us237\ET238.
+\I\X1403:\.{"flushing"}\X
+\U202.
+\I\X1540:\.{"font"}\X
+\Us265\ET266.
+\I\X1541:\.{"fontdimen"}\X
+\Us265\ET266.
+\I\X1609:\.{"fontname"}\X
+\Us468\ET469.
+\I\X1663:\.{"fraction,\ thickness}\)\.{\ "}\X
+\U697.
+\I\X1753:\.{"futurelet"}\X
+\Us1219\ET1220.
+\I\X1747:\.{"gdef"}\X
+\Us1208\ET1209.
+\I\X1745:\.{"global"}\X
+\Us1208\ET1209.
+\I\X1489:\.{"globaldefs"}\X
+\Us237\ET238.
+\I\X1391:\.{"glue"}\X
+\U189.
+\I\X1542:\.{"halign"}\X
+\Us265, 266\ETs776.
+\I\X1487:\.{"hangafter"}\X
+\Us237\ET238.
+\I\X1520:\.{"hangindent"}\X
+\Us247\ET248.
+\I\X1472:\.{"hbadness"}\X
+\Us237\ET238.
+\I\X1719:\.{"hbox"}\X
+\Us1071\ET1072.
+\I\X1603:\.{"height"}\X
+\U463.
+\I\X1701:\.{"hfil"}\X
+\Us1058\ET1059.
+\I\X1702:\.{"hfill"}\X
+\Us1058\ET1059.
+\I\X1704:\.{"hfilneg"}\X
+\Us1058\ET1059.
+\I\X1511:\.{"hfuzz"}\X
+\Us247\ET248.
+\I\X1521:\.{"hoffset"}\X
+\Us247\ET248.
+\I\X1499:\.{"holdinginserts"}\X
+\Us237\ET238.
+\I\X1543:\.{"hrule"}\X
+\Us265, 266\ETs1095.
+\I\X1506:\.{"hsize"}\X
+\Us247\ET248.
+\I\X1700:\.{"hskip"}\X
+\Us1058\ET1059.
+\I\X1703:\.{"hss"}\X
+\Us1058\ET1059.
+\I\X1582:\.{"ht"}\X
+\Us416\ET417.
+\I\X1683:\.{"hyphenation"}\X
+\Us936, 1250\ETs1251.
+\I\X1762:\.{"hyphenchar"}\X
+\Us1254\ET1255.
+\I\X1449:\.{"hyphenpenalty"}\X
+\Us237\ET238.
+\I\X1611:\.{"if"}\X
+\Us487, 488\ETs497.
+\I\X1627:\.{"ifcase"}\X
+\Us487\ET488.
+\I\X1612:\.{"ifcat"}\X
+\Us487\ET488.
+\I\X1614:\.{"ifdim"}\X
+\Us487\ET488.
+\I\X1624:\.{"ifeof"}\X
+\Us487\ET488.
+\I\X1626:\.{"iffalse"}\X
+\Us487\ET488.
+\I\X1621:\.{"ifhbox"}\X
+\Us487\ET488.
+\I\X1617:\.{"ifhmode"}\X
+\Us487\ET488.
+\I\X1619:\.{"ifinner"}\X
+\Us487\ET488.
+\I\X1618:\.{"ifmmode"}\X
+\Us487\ET488.
+\I\X1613:\.{"ifnum"}\X
+\Us487\ET488.
+\I\X1615:\.{"ifodd"}\X
+\Us487\ET488.
+\I\X1625:\.{"iftrue"}\X
+\Us487\ET488.
+\I\X1622:\.{"ifvbox"}\X
+\Us487\ET488.
+\I\X1616:\.{"ifvmode"}\X
+\Us487\ET488.
+\I\X1620:\.{"ifvoid"}\X
+\Us487\ET488.
+\I\X1623:\.{"ifx"}\X
+\Us487\ET488.
+\I\X1544:\.{"ignorespaces"}\X
+\Us265\ET266.
+\I\X1786:\.{"immediate"}\X
+\Us1344\ET1346.
+\I\X1592:\.{"in"}\X
+\U458.
+\I\X1751:\.{"inaccessible"}\X
+\U1216.
+\I\X1724:\.{"indent"}\X
+\Us1088\ET1089.
+\I\X1636:\.{"input\ file\ name"}\X
+\I\X1570:\.{"input"}\X
+\Us376\ET377.
+\I\X1587:\.{"inputlineno"}\X
+\Us416\ET417.
+\I\X1390:\.{"insert"}\X
+\Us188, 265, 266, 986\ETs1099.
+\I\X1580:\.{"insertpenalties"}\X
+\Us416\ET417.
+\I\X1459:\.{"interlinepenalty"}\X
+\Us237\ET238.
+\I\X1610:\.{"jobname"}\X
+\Us468\ET469.
+\I\X1396:\.{"kern"}\X
+\Us191, 856, 1058\ETs1059.
+\I\X1496:\.{"language"}\X
+\Us237\ET238.
+\I\X1717:\.{"lastbox"}\X
+\Us1071\ET1072.
+\I\X1585:\.{"lastkern"}\X
+\Us416\ET417.
+\I\X1584:\.{"lastpenalty"}\X
+\Us416\ET417.
+\I\X1586:\.{"lastskip"}\X
+\Us416\ET417.
+\I\X1442:\.{"lccode"}\X
+\Us235, 1230\ETs1231.
+\I\X1721:\.{"leaders"}\X
+\Us1071\ET1072.
+\I\X1659:\.{"left"}\X
+\Us696, 1188\ETs1189.
+\I\X1497:\.{"lefthyphenmin"}\X
+\Us237\ET238.
+\I\X1412:\.{"leftskip"}\X
+\Us225\ET226.
+\I\X1734:\.{"leqno"}\X
+\Us1141\ET1143.
+\I\X1752:\.{"let"}\X
+\Us1219\ET1220.
+\I\X1661:\.{"limits"}\X
+\Us696, 1156\ETs1157.
+\I\X1682:\.{"line\ breaking"}\X
+\U877.
+\I\X1448:\.{"linepenalty"}\X
+\Us237\ET238.
+\I\X1405:\.{"lineskip"}\X
+\Us225\ET226.
+\I\X1505:\.{"lineskiplimit"}\X
+\Us247\ET248.
+\I\X1778:\.{"long\ macro"}\X
+\U1295.
+\I\X1743:\.{"long"}\X
+\Us1208, 1209, 1213\ETs1295.
+\I\X1465:\.{"looseness"}\X
+\Us237\ET238.
+\I\X1715:\.{"lower"}\X
+\Us1071\ET1072.
+\I\X1772:\.{"lowercase"}\X
+\Us1286\ET1287.
+\I\X1382:\.{"m2d5c2l5x2v5i"}\X
+\U69.
+\I\X1463:\.{"mag"}\X
+\Us237\ET238.
+\I\X1401:\.{"mark"}\X
+\Us196, 265, 266\ETs323.
+\I\X1398:\.{"math"}\X
+\Us192\ET856.
+\I\X1545:\.{"mathaccent"}\X
+\Us265, 266\ETs1166.
+\I\X1651:\.{"mathbin"}\X
+\Us696, 1156\ETs1157.
+\I\X1546:\.{"mathchar"}\X
+\Us265, 266\ETs1223.
+\I\X1755:\.{"mathchardef"}\X
+\Us1222\ET1223.
+\I\X1547:\.{"mathchoice"}\X
+\Us265, 266\ETs695.
+\I\X1654:\.{"mathclose"}\X
+\Us696, 1156\ETs1157.
+\I\X1445:\.{"mathcode"}\X
+\Us235, 1230\ETs1231.
+\I\X1656:\.{"mathinner"}\X
+\Us696, 1156\ETs1157.
+\I\X1650:\.{"mathop"}\X
+\Us696, 1156\ETs1157.
+\I\X1653:\.{"mathopen"}\X
+\Us696, 1156\ETs1157.
+\I\X1649:\.{"mathord"}\X
+\Us696, 1156\ETs1157.
+\I\X1655:\.{"mathpunct"}\X
+\Us696, 1156\ETs1157.
+\I\X1652:\.{"mathrel"}\X
+\Us696, 1156\ETs1157.
+\I\X1504:\.{"mathsurround"}\X
+\Us247\ET248.
+\I\X1486:\.{"maxdeadcycles"}\X
+\Us237\ET238.
+\I\X1508:\.{"maxdepth"}\X
+\Us247\ET248.
+\I\X1608:\.{"meaning"}\X
+\Us468\ET469.
+\I\X1421:\.{"medmuskip"}\X
+\Us225\ET226.
+\I\X1770:\.{"message"}\X
+\Us1277\ET1278.
+\I\X1601:\.{"minus"}\X
+\U462.
+\I\X1397:\.{"mkern"}\X
+\Us191, 1058\ETs1059.
+\I\X1664:\.{"mlist1"}\X
+\U728.
+\I\X1665:\.{"mlist2"}\X
+\U754.
+\I\X1666:\.{"mlist3"}\X
+\U761.
+\I\X1668:\.{"mlist4"}\X
+\U766.
+\I\X1595:\.{"mm"}\X
+\U458.
+\I\X1468:\.{"month"}\X
+\Us237\ET238.
+\I\X1712:\.{"moveleft"}\X
+\Us1071\ET1072.
+\I\X1713:\.{"moveright"}\X
+\Us1071\ET1072.
+\I\X1393:\.{"mskip"}\X
+\Us189, 1058\ETs1059.
+\I\X1394:\.{"mu"}\X
+\Us189, 229, 456\ETs465.
+\I\X1548:\.{"multiply"}\X
+\Us265\ET266.
+\I\X1424:\.{"muskip"}\X
+\Us227, 229, 411\ETs412.
+\I\X1759:\.{"muskipdef"}\X
+\Us1222\ET1223.
+\I\X1495:\.{"newlinechar"}\X
+\Us237\ET238.
+\I\X1549:\.{"noalign"}\X
+\Us265, 266\ETs1129.
+\I\X1550:\.{"noboundary"}\X
+\Us265\ET266.
+\I\X1551:\.{"noexpand"}\X
+\Us265\ET266.
+\I\X1725:\.{"noindent"}\X
+\Us1088\ET1089.
+\I\X1662:\.{"nolimits"}\X
+\Us696, 1156\ETs1157.
+\I\X1392:\.{"nonscript"}\X
+\Us189, 265\ETs266.
+\I\X1384:\.{"nonstopmode"}\X
+\Us86, 1262\ETs1263.
+\I\X1525:\.{"notexpanded:"}\X
+\U258.
+\I\X1514:\.{"nulldelimiterspace"}\X
+\Us247\ET248.
+\I\X1639:\.{"nullfont"}\X
+\Us552\ET553.
+\I\X1605:\.{"number"}\X
+\Us468\ET469.
+\I\X1552:\.{"omit"}\X
+\Us265, 266\ETs1129.
+\I\X1768:\.{"openin"}\X
+\Us1272\ET1273.
+\I\X1783:\.{"openout"}\X
+\Us1344, 1346\ETs1356.
+\I\X1629:\.{"or"}\X
+\Us491, 492\ETs500.
+\I\X1780:\.{"outer\ endtemplate"}\X
+\U1295.
+\I\X1779:\.{"outer\ macro"}\X
+\U1295.
+\I\X1744:\.{"outer"}\X
+\Us1208, 1209\ETs1213.
+\I\X1426:\.{"output"}\X
+\Us230\ET231.
+\I\X1485:\.{"outputpenalty"}\X
+\Us237\ET238.
+\I\X1737:\.{"over"}\X
+\Us1178\ET1179.
+\I\X1519:\.{"overfullrule"}\X
+\Us247\ET248.
+\I\X1657:\.{"overline"}\X
+\Us696, 1156\ETs1157.
+\I\X1740:\.{"overwithdelims"}\X
+\Us1178\ET1179.
+\I\X1697:\.{"page"}\X
+\U1000.
+\I\X1696:\.{"pagedepth"}\X
+\Us983\ET984.
+\I\X1694:\.{"pagefilllstretch"}\X
+\Us983\ET984.
+\I\X1693:\.{"pagefillstretch"}\X
+\Us983\ET984.
+\I\X1692:\.{"pagefilstretch"}\X
+\Us983\ET984.
+\I\X1689:\.{"pagegoal"}\X
+\Us983\ET984.
+\I\X1695:\.{"pageshrink"}\X
+\Us983\ET984.
+\I\X1691:\.{"pagestretch"}\X
+\Us983\ET984.
+\I\X1690:\.{"pagetotal"}\X
+\Us983\ET984.
+\I\X1569:\.{"par"}\X
+\Us334, 335\ETs856.
+\I\X1679:\.{"paragraph"}\X
+\U866.
+\I\X1419:\.{"parfillskip"}\X
+\Us225\ET226.
+\I\X1503:\.{"parindent"}\X
+\Us247\ET248.
+\I\X1436:\.{"parshape"}\X
+\Us233, 265\ETs266.
+\I\X1407:\.{"parskip"}\X
+\Us225\ET226.
+\I\X1684:\.{"patterns"}\X
+\Us960, 961, 1250\ETs1251.
+\I\X1474:\.{"pausing"}\X
+\Us237\ET238.
+\I\X1593:\.{"pc"}\X
+\U458.
+\I\X1399:\.{"penalty\ "}\X
+\U194.
+\I\X1553:\.{"penalty"}\X
+\Us265, 266\ETs856.
+\I\X1600:\.{"plus"}\X
+\U462.
+\I\X1458:\.{"postdisplaypenalty"}\X
+\Us237\ET238.
+\I\X1457:\.{"predisplaypenalty"}\X
+\Us237\ET238.
+\I\X1516:\.{"predisplaysize"}\X
+\Us247\ET248.
+\I\X1750:\.{"prefix"}\X
+\U1211.
+\I\X1446:\.{"pretolerance"}\X
+\Us237\ET238.
+\I\X1578:\.{"prevdepth"}\X
+\Us416\ET417.
+\I\X1554:\.{"prevgraf"}\X
+\Us265, 266\ETs1244.
+\I\X1685:\.{"pruning"}\X
+\U968.
+\I\X1425:\.{"pt"}\X
+\Us229, 453\ETs465.
+\I\X1555:\.{"radical"}\X
+\Q267.
+\Us265, 266\ETs696.
+\I\X1714:\.{"raise"}\X
+\Us1071\ET1072.
+\I\X1556:\.{"read"}\X
+\Us265, 266\ETs486.
+\I\X1557:\.{"relax"}\X
+\Us265\ET266.
+\I\X1456:\.{"relpenalty"}\X
+\Us237\ET238.
+\I\X1565:\.{"restoring"}\X
+\U283.
+\I\X1564:\.{"retaining"}\X
+\U283.
+\I\X1660:\.{"right"}\X
+\Us696, 1069, 1185, 1188, 1189\ETs1192.
+\I\X1710:\.{"right."}\X
+\U1065.
+\I\X1711:\.{"rightbrace"}\X
+\U1068.
+\I\X1498:\.{"righthyphenmin"}\X
+\Us237\ET238.
+\I\X1413:\.{"rightskip"}\X
+\Us225\ET226.
+\I\X1606:\.{"romannumeral"}\X
+\Us468\ET469.
+\I\X1389:\.{"rule("}\X
+\U187.
+\I\X1766:\.{"scaled"}\X
+\U1258.
+\I\X1439:\.{"scriptfont"}\X
+\Us234, 699\ETs1230.
+\I\X1440:\.{"scriptscriptfont"}\X
+\Us234, 699\ETs1230.
+\I\X1648:\.{"scriptscriptstyle"}\X
+\Us694\ET1169.
+\I\X1515:\.{"scriptspace"}\X
+\Us247\ET248.
+\I\X1647:\.{"scriptstyle"}\X
+\Us694\ET1169.
+\I\X1385:\.{"scrollmode"}\X
+\Us86, 1262\ETs1263.
+\I\X1558:\.{"setbox"}\X
+\Us265, 266\ETs1241.
+\I\X1787:\.{"setlanguage"}\X
+\Us1344, 1346\ETs1356.
+\I\X1444:\.{"sfcode"}\X
+\Us235, 1230\ETs1231.
+\I\X1720:\.{"shipout"}\X
+\Us1071\ET1072.
+\I\X1774:\.{"show"}\X
+\Us1291\ET1292.
+\I\X1775:\.{"showbox"}\X
+\Us1291\ET1292.
+\I\X1470:\.{"showboxbreadth"}\X
+\Us237\ET238.
+\I\X1471:\.{"showboxdepth"}\X
+\Us237\ET238.
+\I\X1777:\.{"showlists"}\X
+\Us1291\ET1292.
+\I\X1776:\.{"showthe"}\X
+\Us1291\ET1292.
+\I\X1763:\.{"skewchar"}\X
+\Us1254\ET1255.
+\I\X1423:\.{"skip"}\X
+\Us227, 229, 411, 412\ETs1009.
+\I\X1758:\.{"skipdef"}\X
+\Us1222\ET1223.
+\I\X1599:\.{"sp"}\X
+\U458.
+\I\X1577:\.{"spacefactor"}\X
+\Us416\ET417.
+\I\X1417:\.{"spaceskip"}\X
+\Us225\ET226.
+\I\X1669:\.{"span"}\X
+\Us780\ET781.
+\I\X1785:\.{"special"}\X
+\Us1344, 1346\ETs1356.
+\I\X1576:\.{"splitbotmark"}\X
+\Us384\ET385.
+\I\X1575:\.{"splitfirstmark"}\X
+\Us384\ET385.
+\I\X1509:\.{"splitmaxdepth"}\X
+\Us247\ET248.
+\I\X1415:\.{"splittopskip"}\X
+\Us225\ET226.
+\I\X1643:\.{"spread"}\X
+\U645.
+\I\X1607:\.{"string"}\X
+\Us468\ET469.
+\I\X1416:\.{"tabskip"}\X
+\Us225\ET226.
+\I\X1638:\.{"texput"}\X
+\U534.
+\I\X1438:\.{"textfont"}\X
+\Us234, 699\ETs1230.
+\I\X1646:\.{"textstyle"}\X
+\Us694\ET1169.
+\I\X1559:\.{"the"}\X
+\Us265, 266\ETs428.
+\I\X1422:\.{"thickmuskip"}\X
+\Us225\ET226.
+\I\X1420:\.{"thinmuskip"}\X
+\Us225\ET226.
+\I\X1466:\.{"time"}\X
+\Us237\ET238.
+\I\X1642:\.{"to"}\X
+\Us645, 1082\ETs1225.
+\I\X1435:\.{"toks"}\X
+\Us231, 233, 265\ETs266.
+\I\X1760:\.{"toksdef"}\X
+\Us1222\ET1223.
+\I\X1447:\.{"tolerance"}\X
+\Us237\ET238.
+\I\X1572:\.{"topmark"}\X
+\Us384\ET385.
+\I\X1414:\.{"topskip"}\X
+\Us225\ET226.
+\I\X1482:\.{"tracingcommands"}\X
+\Us237\ET238.
+\I\X1481:\.{"tracinglostchars"}\X
+\Us237\ET238.
+\I\X1476:\.{"tracingmacros"}\X
+\Us237\ET238.
+\I\X1475:\.{"tracingonline"}\X
+\Us237\ET238.
+\I\X1480:\.{"tracingoutput"}\X
+\Us237\ET238.
+\I\X1479:\.{"tracingpages"}\X
+\Us237\ET238.
+\I\X1478:\.{"tracingparagraphs"}\X
+\Us237\ET238.
+\I\X1483:\.{"tracingrestores"}\X
+\Us237\ET238.
+\I\X1477:\.{"tracingstats"}\X
+\Us237\ET238.
+\I\X1589:\.{"true"}\X
+\U453.
+\I\X1443:\.{"uccode"}\X
+\Us235, 1230\ETs1231.
+\I\X1484:\.{"uchyph"}\X
+\Us237\ET238.
+\I\X1658:\.{"underline"}\X
+\Us696, 1156\ETs1157.
+\I\X1729:\.{"unhbox"}\X
+\Us1107\ET1108.
+\I\X1730:\.{"unhcopy"}\X
+\Us1107\ET1108.
+\I\X1727:\.{"unkern"}\X
+\Us1107\ET1108.
+\I\X1726:\.{"unpenalty"}\X
+\Us1107\ET1108.
+\I\X1388:\.{"unset"}\X
+\U184.
+\I\X1728:\.{"unskip"}\X
+\Us1107\ET1108.
+\I\X1731:\.{"unvbox"}\X
+\Us1107\ET1108.
+\I\X1732:\.{"unvcopy"}\X
+\Us1107\ET1108.
+\I\X1773:\.{"uppercase"}\X
+\Us1286\ET1287.
+\I\X1402:\.{"vadjust"}\X
+\Us197, 265\ETs266.
+\I\X1560:\.{"valign"}\X
+\Us265\ET266.
+\I\X1473:\.{"vbadness"}\X
+\Us237\ET238.
+\I\X1688:\.{"vbox"}\X
+\Us978, 1071\ETs1072.
+\I\X1561:\.{"vcenter"}\X
+\Us265, 266, 696\ETs736.
+\I\X1686:\.{"vertbreak"}\X
+\U973.
+\I\X1706:\.{"vfil"}\X
+\Us1058\ET1059.
+\I\X1707:\.{"vfill"}\X
+\Us1058\ET1059.
+\I\X1709:\.{"vfilneg"}\X
+\Us1058\ET1059.
+\I\X1512:\.{"vfuzz"}\X
+\Us247\ET248.
+\I\X1641:\.{"vlistout"}\X
+\U630.
+\I\X1522:\.{"voffset"}\X
+\Us247\ET248.
+\I\X1644:\.{"vpack"}\X
+\U669.
+\I\X1562:\.{"vrule"}\X
+\Us265\ET266.
+\I\X1507:\.{"vsize"}\X
+\Us247\ET248.
+\I\X1705:\.{"vskip"}\X
+\Us1058\ET1059.
+\I\X1687:\.{"vsplit"}\X
+\Us978, 1071\ETs1072.
+\I\X1708:\.{"vss"}\X
+\Us1058\ET1059.
+\I\X1718:\.{"vtop"}\X
+\Us1071\ET1072.
+\I\X1581:\.{"wd"}\X
+\Us416\ET417.
+\I\X1452:\.{"widowpenalty"}\X
+\Us237\ET238.
+\I\X1602:\.{"width"}\X
+\U463.
+\I\X1568:\.{"write"}\X
+\Us323, 1344, 1346\ETs1356.
+\I\X1749:\.{"xdef"}\X
+\Us1208\ET1209.
+\I\X1723:\.{"xleaders"}\X
+\Us1071\ET1072.
+\I\X1418:\.{"xspaceskip"}\X
+\Us225\ET226.
+\I\X1469:\.{"year"}\X
+\Us237\ET238.
+\I\X1796:\\{pool\_ptr} initialization\X
+\U39.
+\I\X1793:\\{str\_pool} initialization\X
+\U39.
+\I\X1797:\\{str\_ptr} initialization\X
+\U39.
+\I\X1794:\\{str\_start} initialization\X
+\U39.
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
diff --git a/web/web2w/ctex.w b/web/web2w/ctex.w
new file mode 100644
index 0000000000..a8e204c94f
--- /dev/null
+++ b/web/web2w/ctex.w
@@ -0,0 +1,26873 @@
+% 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
+@s dotdot TeX
+@* Introduction.
+This is \TeX, a document compiler intended to produce typesetting of high
+quality.
+The \PASCAL\ program that follows is the definition of \TeX82, a standard
+@:PASCAL}{\PASCAL@>
+@!@:TeX82}{\TeX82@>
+version of \TeX\ that is designed to be highly portable so that identical output
+will be obtainable on a great variety of computers.
+
+The main purpose of the following program is to explain the algorithms of \TeX\
+as clearly as possible. As a result, the program will not necessarily be very
+efficient when a particular \PASCAL\ compiler has translated it into a
+particular machine language. However, the program has been written so that it
+can be tuned to run efficiently in a wide variety of operating environments
+by making comparatively few changes. Such flexibility is possible because
+the documentation that follows is written in the \.{WEB} language, which is
+at a higher level than \PASCAL; the preprocessing step that converts \.{WEB}
+to \PASCAL\ is able to introduce most of the necessary refinements.
+Semi-automatic translation to other languages is also feasible, because the
+program below does not make extensive use of features that are peculiar to
+\PASCAL.
+
+A large piece of software like \TeX\ has inherent complexity that cannot
+be reduced below a certain level of difficulty, although each individual
+part is fairly simple by itself. The \.{WEB} language is intended to make
+the algorithms as readable as possible, by reflecting the way the
+individual program pieces fit together and by providing the
+cross-references that connect different parts. Detailed comments about
+what is going on, and about why things were done in certain ways, have
+been liberally sprinkled throughout the program. These comments explain
+features of the implementation, but they rarely attempt to explain the
+\TeX\ language itself, since the reader is supposed to be familiar with
+{\sl The \TeX book}.
+@.WEB@>
+@:TeXbook}{\sl The \TeX book@>
+
+@ The present implementation has a long ancestry, beginning in the summer
+of~1977, when Michael~F. Plass and Frank~M. Liang designed and coded
+a prototype
+@^Plass, Michael Frederick@>
+@^Liang, Franklin Mark@>
+@^Knuth, Donald Ervin@>
+based on some specifications that the author had made in May of that year.
+This original proto\TeX\ included macro definitions and elementary
+manipulations on boxes and glue, but it did not have line-breaking,
+page-breaking, mathematical formulas, alignment routines, error recovery,
+or the present semantic nest; furthermore,
+it used character lists instead of token lists, so that a control sequence
+like \.{\\halign} was represented by a list of seven characters. A
+complete version of \TeX\ was designed and coded by the author in late
+1977 and early 1978; that program, like its prototype, was written in the
+{\mc SAIL} language, for which an excellent debugging system was
+available. Preliminary plans to convert the {\mc SAIL} code into a form
+somewhat like the present ``web'' were developed by Luis Trabb~Pardo and
+@^Trabb Pardo, Luis Isidoro@>
+the author at the beginning of 1979, and a complete implementation was
+created by Ignacio~A. Zabala in 1979 and 1980. The \TeX82 program, which
+@^Zabala Salelles, Ignacio Andr\'es@>
+was written by the author during the latter part of 1981 and the early
+part of 1982, also incorporates ideas from the 1979 implementation of
+@^Guibas, Leonidas Ioannis@>
+@^Sedgewick, Robert@>
+@^Wyatt, Douglas Kirk@>
+\TeX\ in {\mc MESA} that was written by Leonidas Guibas, Robert Sedgewick,
+and Douglas Wyatt at the Xerox Palo Alto Research Center. Several hundred
+refinements were introduced into \TeX82 based on the experiences gained with
+the original implementations, so that essentially every part of the system
+has been substantially improved. After the appearance of ``Version 0'' in
+September 1982, this program benefited greatly from the comments of
+many other people, notably David~R. Fuchs and Howard~W. Trickey.
+A final revision in September 1989 extended the input character set to
+eight-bit codes and introduced the ability to hyphenate words from
+different languages, based on some ideas of Michael~J. Ferguson.
+@^Fuchs, David Raymond@>
+@^Trickey, Howard Wellington@>
+@^Ferguson, Michael John@>
+
+No doubt there still is plenty of room for improvement, but the author
+is firmly committed to keeping \TeX82 ``frozen'' from now on; stability
+and reliability are to be its main virtues.
+
+On the other hand, the \.{WEB} description can be extended without changing
+the core of \TeX82 itself, and the program has been designed so that such
+extensions are not extremely difficult to make.
+The |banner| string defined here should be changed whenever \TeX\
+undergoes any modifications, so that it will be clear which version of
+\TeX\ might be the guilty party when a problem arises.
+@^extensions to \TeX@>
+@^system dependencies@>
+
+If this program is changed, the resulting system should not be called
+`\TeX'; the official name `\TeX' by itself is reserved
+for software systems that are fully compatible with each other.
+A special test suite called the ``\.{TRIP} test'' is available for
+helping to determine whether a particular implementation deserves to be
+known as `\TeX' [cf.~Stanford Computer Science report CS1027,
+November 1984].
+
+@d banner "This is TeX, Version 3.14159265 (HINT)" /*printed when \TeX\ starts*/
+
+@ Different \PASCAL s have slightly different conventions, and the present
+@!@:PASCAL H}{\ph@>
+program expresses \TeX\ in terms of the \PASCAL\ that was
+available to the author in 1982. Constructions that apply to
+this particular compiler, which we shall call \ph, should help the
+reader see how to make an appropriate interface for other systems
+if necessary. (\ph\ is Charles Hedrick's modification of a compiler
+@^Hedrick, Charles Locke@>
+for the DECsystem-10 that was originally developed at the University of
+Hamburg; cf.\ {\sl SOFTWARE---Practice \AM\ Experience \bf6} (1976),
+29--42. The \TeX\ program below is intended to be adaptable, without
+extensive changes, to most other versions of \PASCAL, so it does not fully
+use the admirable features of \ph. Indeed, a conscious effort has been
+made here to avoid using several idiosyncratic features of standard
+\PASCAL\ itself, so that most of the code can be translated mechanically
+into other high-level languages. For example, the `\&{with}' and `\\{new}'
+features are not used, nor are pointer types, set types, or enumerated
+scalar types; there are no `\&{var}' parameters, except in the case of files;
+there are no tag fields on variant records; there are no assignments
+|double=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.
+@!@^system dependencies@>
+@!@^dirty \PASCAL@>
+
+Incidentally, \PASCAL's standard |round| function can be problematical,
+because it disagrees with the IEEE floating-point standard.
+Many implementors have
+therefore chosen to substitute their own home-grown rounding procedure.
+
+@ The program begins with a normal \PASCAL\ program heading, whose
+components will be filled in later, using the conventions of \.{WEB}.
+@.WEB@>
+For example, the portion of the program called `\X\glob:Global
+variables\X' below will be replaced by a sequence of variable declarations
+that starts in $\section\glob$ of this documentation. In this way, we are able
+to define each individual global variable when we are prepared to
+understand what it means; we do not have to define all of the globals at
+once. Cross references in $\section\glob$, where it says ``See also
+sections \gglob, \dots,'' also make it possible to look at the set of
+all global variables, if desired. Similar remarks apply to the other
+portions of the program heading.
+
+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.
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+
+@f type true /*but `|type|' will not be treated as a reserved word*/
+
+@p@t\4@>@<Compiler directives@>@;
+ /*all file names are defined dynamically*/
+@<Labels in the outer block@>@;
+@<Constants in the outer block@>@;
+@<Types in the outer block@>@;
+@<Global variables@>@;
+@#
+void initialize(void) /*this procedure gets things started properly*/
+ {@+@<Local variables for initialization@>@;
+ @<Initialize whatever \TeX\ might access@>;
+ } @#
+@t\4@>@<Basic printing procedures@>@;
+@t\4@>@<Error handling procedures@>@;
+
+@ The overall \TeX\ program begins with the heading just shown, after which
+comes a bunch of procedure declarations and function declarations.
+Finally we will get to the main program, which begins with the
+comment `|start_here|'. If you want to skip down to the
+main program now, you can look up `|start_here|' in the index.
+But the author suggests that the best way to understand this program
+is to follow pretty much the order of \TeX's components as they appear in the
+\.{WEB} description you are now reading, since the present ordering is
+intended to combine the advantages of the ``bottom up'' and ``top down''
+approaches to the problem of understanding a somewhat complicated system.
+
+@ Three labels must be declared in the main program, so we give them
+symbolic names.
+
+@<Labels in the out...@>=
+@t\hskip-2pt@>@t\hskip-2pt@>@,
+ /*key control points*/
+
+@ 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}.
+@^debugging@>
+
+@ This program has two important variations: (1) There is a long and slow
+version called \.{INITEX}, which does the extra calculations needed to
+@.INITEX@>
+initialize \TeX's internal tables; and (2)~there is a shorter and faster
+production version, which cuts the initialization to a bare minimum.
+Parts of the program that are needed in (1) but not in (2) are delimited by
+the codewords `$|init|\ldots|tini|$'.
+
+@<Initialize whatever...@>=
+@<Set initial values of key variables@>@;
+#ifdef @!INIT
+@<Initialize table entries (done by \.{INITEX} only)@>@;
+#endif
+
+@ If the first character of a \PASCAL\ comment is a dollar sign,
+\ph\ treats the comment as a list of ``compiler directives'' that will
+affect the translation of this program into machine language. The
+directives shown below specify full checking and inclusion of the \PASCAL\
+debugger when \TeX\ is being debugged, but they cause range checking and other
+redundant code to be eliminated when the production system is being generated.
+Arithmetic overflow will be detected in all cases.
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+@^overflow in arithmetic@>
+
+@s int8_t int
+@s uint8_t int
+@s uint16_t int
+@s halfword int
+@s in TeX
+@s line normal
+@s to do
+
+@<Compiler directives@>=
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#define odd(X) ((X)&1)
+#define chr(X) ((unsigned char)(X))
+#define ord(X) ((int)(X))
+
+#if __SIZEOF_FLOAT__==4
+typedef float float32_t;
+#else
+#error float type must have size 4
+#endif
+
+@h
+
+@ This \TeX\ implementation conforms to the rules of the {\sl Pascal User
+@:PASCAL}{\PASCAL@>
+@^system dependencies@>
+Manual} published by Jensen and Wirth in 1975, except where system-dependent
+@^Wirth, Niklaus@>
+@^Jensen, Kathleen@>
+code is necessary to make a useful system program, and except in another
+respect where such conformity would unnecessarily obscure the meaning
+and clutter up the code: We assume that |case| statements may include a
+default case that applies if no matching label is found. Thus, we shall use
+constructions like
+$$\vbox{\halign{\ignorespaces#\hfil\cr
+|case x|\cr
+1: $\langle\,$code for $x=1\,\rangle$;\cr
+3: $\langle\,$code for $x=3\,\rangle$;\cr
+|default:| $\langle\,$code for |x!=1| and |x!=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!)
+@:PASCAL H}{\ph@>
+
+@ The following parameters can be changed at compile time to extend or
+reduce \TeX's capacity. They may have different values in \.{INITEX} and
+in production versions of \TeX.
+@.INITEX@>
+@^system dependencies@>
+
+@<Constants...@>=
+enum {@+@!mem_max=30000@+}; /*greatest index in \TeX's internal |mem| array;
+ must be strictly less than |max_halfword|;
+ must be equal to |mem_top| in \.{INITEX}, otherwise | >= mem_top|*/
+enum {@+@!mem_min=0@+}; /*smallest index in \TeX's internal |mem| array;
+ must be |min_halfword| or more;
+ must be equal to |mem_bot| in \.{INITEX}, otherwise | <= mem_bot|*/
+enum {@+@!buf_size=500@+}; /*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|*/
+enum {@+@!error_line=72@+}; /*width of context lines on terminal error messages*/
+enum {@+@!half_error_line=42@+}; /*width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|*/
+enum {@+@!max_print_line=79@+}; /*width of longest text lines output; should be at least 60*/
+enum {@+@!stack_size=200@+}; /*maximum number of simultaneous input sources*/
+enum {@+@!max_in_open=6@+}; /*maximum number of input files and error insertions that
+ can be going on simultaneously*/
+enum {@+@!font_max=75@+}; /*maximum internal font number; must not exceed |max_quarterword|
+ and must be at most |font_base+256|*/
+enum {@+@!font_mem_size=20000@+}; /*number of words of |font_info| for all fonts*/
+enum {@+@!param_size=60@+}; /*maximum number of simultaneous macro parameters*/
+enum {@+@!nest_size=40@+}; /*maximum number of semantic levels simultaneously active*/
+enum {@+@!max_strings=3000@+}; /*maximum number of strings; must not exceed |max_halfword|*/
+enum {@+@!string_vacancies=8000@+}; /*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*/
+enum {@+@!pool_size=32000@+}; /*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*/
+enum {@+@!save_size=600@+}; /*space for saving values outside of current group; must be
+ at most |max_halfword|*/
+enum {@+@!trie_size=8000@+}; /*space for hyphenation patterns; should be larger for
+ \.{INITEX} than it is in production versions of \TeX*/
+enum {@+@!trie_op_size=500@+}; /*space for ``opcodes'' in the hyphenation patterns*/
+enum {@+@!dvi_buf_size=800@+}; /*size of the output buffer; must be a multiple of 8*/
+enum {@+@!file_name_size=40@+}; /*file names shouldn't be longer than this*/
+const char *@!pool_name="TeXformats:TEX.POOL ";
+ /*string of length |file_name_size|; tells where the string pool appears*/
+@.TeXformats@>
+
+@ Like the preceding parameters, the following quantities can be changed
+at compile time to extend or reduce \TeX's capacity. But if they are changed,
+it is necessary to rerun the initialization program \.{INITEX}
+@.INITEX@>
+to generate new tables for the production \TeX\ program.
+One can't simply make helter-skelter changes to the following constants,
+since certain rather complex initialization
+numbers are computed from them. They are defined here using
+\.{WEB} macros, instead of being put into \PASCAL's || list, in order to
+emphasize this distinction.
+
+@d mem_bot 0 /*smallest index in the |mem| array dumped by \.{INITEX};
+ must not be less than |mem_min|*/
+@d mem_top 30000 /*largest index in the |mem| array dumped by \.{INITEX};
+ must be substantially larger than |mem_bot|
+ and not greater than |mem_max|*/
+@d font_base 0 /*smallest internal font number; must not be less
+ than |min_quarterword|*/
+@d hash_size 2100 /*maximum number of control sequences; it should be at most
+ about |(mem_max-mem_min)/(double)10|*/
+@d hash_prime 1777 /*a prime number equal to about 85\pct! of |hash_size|*/
+@d hyph_size 307 /*another prime; the number of \.{\\hyphenation} exceptions*/
+@^system dependencies@>
+
+@ In case somebody has inadvertently made bad settings of the ``constants,''
+\TeX\ checks them using a global variable called |bad|.
+
+This is the first of many sections of \TeX\ where global variables are
+defined.
+
+@<Glob...@>=
+int @!bad; /*is some ``constant'' wrong?*/
+
+@ Later on we will say `\ignorespaces|if (mem_max >= max_halfword) bad=14|',
+or something similar. (We can't do that until |max_halfword| has been defined.)
+
+@<Check the ``constant'' values for consistency@>=
+bad=0;
+if ((half_error_line < 30)||(half_error_line > error_line-15)) bad=1;
+if (max_print_line < 60) bad=2;
+if (dvi_buf_size%8!=0) bad=3;
+if (mem_bot+1100 > mem_top) bad=4;
+if (hash_prime > hash_size) bad=5;
+if (max_in_open >= 128) bad=6;
+if (mem_top < 256+11) bad=7; /*we will want |null_list > 255|*/
+
+@ Labels are given symbolic names by the following definitions, so that
+occasional |goto| statements will be meaningful. We insert the label
+`|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.
+
+@d done6 36 /*for exiting the sixth loop in a block*/
+@ Here are some macros for common programming idioms.
+
+@d incr(X) X=X+1 /*increase a variable by unity*/
+@d decr(X) X=X-1 /*decrease a variable by unity*/
+@d negate(X) X=-X /*change the sign of a variable*/
+@d loop @+while (true) @+ /*repeat over and over until a |goto| happens*/
+@f loop else
+ /*\.{WEB}'s |else| acts like `\ignorespaces|while true do|\unskip'*/
+@d do_nothing /*empty statement*/
+@d empty 0 /*symbolic name for a null constant*/
+
+@* 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.
+@^ASCII code@>
+
+\TeX's internal code also defines the value of constants
+that begin with a reverse apostrophe; and it provides an index to the
+\.{\\catcode}, \.{\\mathcode}, \.{\\uccode}, \.{\\lccode}, and \.{\\delcode}
+tables.
+
+@ Characters of text that have been converted to \TeX's internal form
+are said to be of type |ASCII_code|, which is a subrange of the integers.
+
+@<Types...@>=
+typedef uint8_t ASCII_code; /*eight-bit numbers*/
+
+@ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
+character sets were common, so it did not make provision for lowercase
+letters. Nowadays, of course, we need to deal with both capital and small
+letters in a convenient way, especially in a program for typesetting;
+so the present specification of \TeX\ has been written under the assumption
+that the \PASCAL\ compiler and run-time system permit the use of text files
+with more than 64 distinguishable characters. More precisely, we assume that
+the character set contains at least the letters and symbols associated
+with ASCII codes 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.
+@^system dependencies@>
+
+@d text_char unsigned char /*the data type of characters in text files*/
+@d first_text_char 0 /*ordinal number of the smallest element of |text_char|*/
+@d last_text_char 255 /*ordinal number of the largest element of |text_char|*/
+
+@<Local variables for init...@>=
+int @!i;
+
+@ The \TeX\ processor converts between ASCII code and
+the user's external character set by means of arrays |xord| and |xchr|
+that are analogous to \PASCAL's |ord| and |chr| functions.
+
+@<Glob...@>=
+ASCII_code @!xord[256];
+ /*specifies conversion of input characters*/
+uint8_t @!xchr[256];
+ /*specifies conversion of output characters*/
+
+@ Since we are assuming that our \PASCAL\ system is able to read and
+write the visible characters of standard ASCII (although not
+necessarily using the ASCII codes to represent them), the following
+assignment statements initialize the standard part of the |xchr| array
+properly, without needing any system-dependent changes. On the other
+hand, it is possible to implement \TeX\ with less complete character
+sets, and in such cases it will be necessary to change something here.
+@^system dependencies@>
+
+@<Set init...@>=
+xchr[040]= ' ' ;
+xchr[041]= '!' ;
+xchr[042]= '"' ;
+xchr[043]= '#' ;
+xchr[044]= '$' ;
+xchr[045]= '%' ;
+xchr[046]= '&' ;
+xchr[047]= '\'' ;@/
+xchr[050]= '(' ;
+xchr[051]= ')' ;
+xchr[052]= '*' ;
+xchr[053]= '+' ;
+xchr[054]= ',' ;
+xchr[055]= '-' ;
+xchr[056]= '.' ;
+xchr[057]= '/' ;@/
+xchr[060]= '0' ;
+xchr[061]= '1' ;
+xchr[062]= '2' ;
+xchr[063]= '3' ;
+xchr[064]= '4' ;
+xchr[065]= '5' ;
+xchr[066]= '6' ;
+xchr[067]= '7' ;@/
+xchr[070]= '8' ;
+xchr[071]= '9' ;
+xchr[072]= ':' ;
+xchr[073]= ';' ;
+xchr[074]= '<' ;
+xchr[075]= '=' ;
+xchr[076]= '>' ;
+xchr[077]= '?' ;@/
+xchr[0100]= '@@' ;
+xchr[0101]= 'A' ;
+xchr[0102]= 'B' ;
+xchr[0103]= 'C' ;
+xchr[0104]= 'D' ;
+xchr[0105]= 'E' ;
+xchr[0106]= 'F' ;
+xchr[0107]= 'G' ;@/
+xchr[0110]= 'H' ;
+xchr[0111]= 'I' ;
+xchr[0112]= 'J' ;
+xchr[0113]= 'K' ;
+xchr[0114]= 'L' ;
+xchr[0115]= 'M' ;
+xchr[0116]= 'N' ;
+xchr[0117]= 'O' ;@/
+xchr[0120]= 'P' ;
+xchr[0121]= 'Q' ;
+xchr[0122]= 'R' ;
+xchr[0123]= 'S' ;
+xchr[0124]= 'T' ;
+xchr[0125]= 'U' ;
+xchr[0126]= 'V' ;
+xchr[0127]= 'W' ;@/
+xchr[0130]= 'X' ;
+xchr[0131]= 'Y' ;
+xchr[0132]= 'Z' ;
+xchr[0133]= '[' ;
+xchr[0134]= '\\' ;
+xchr[0135]= ']' ;
+xchr[0136]= '^' ;
+xchr[0137]= '_' ;@/
+xchr[0140]= '`' ;
+xchr[0141]= 'a' ;
+xchr[0142]= 'b' ;
+xchr[0143]= 'c' ;
+xchr[0144]= 'd' ;
+xchr[0145]= 'e' ;
+xchr[0146]= 'f' ;
+xchr[0147]= 'g' ;@/
+xchr[0150]= 'h' ;
+xchr[0151]= 'i' ;
+xchr[0152]= 'j' ;
+xchr[0153]= 'k' ;
+xchr[0154]= 'l' ;
+xchr[0155]= 'm' ;
+xchr[0156]= 'n' ;
+xchr[0157]= 'o' ;@/
+xchr[0160]= 'p' ;
+xchr[0161]= 'q' ;
+xchr[0162]= 'r' ;
+xchr[0163]= 's' ;
+xchr[0164]= 't' ;
+xchr[0165]= 'u' ;
+xchr[0166]= 'v' ;
+xchr[0167]= 'w' ;@/
+xchr[0170]= 'x' ;
+xchr[0171]= 'y' ;
+xchr[0172]= 'z' ;
+xchr[0173]= '{' ;
+xchr[0174]= '|' ;
+xchr[0175]= '}' ;
+xchr[0176]= '~' ;@/
+
+@ Some of the ASCII codes without visible characters have been given symbolic
+names in this program because they are used with a special meaning.
+
+@d null_code 00 /*ASCII code that might disappear*/
+@d carriage_return 015 /*ASCII code used at end of line*/
+@d invalid_code 0177 /*ASCII code that many systems prohibit in text files*/
+
+@ The ASCII code is ``standard'' only to a certain extent, since many
+computer installations have found it advantageous to have ready access
+to more than 94 printing characters. Appendix~C of {\sl The \TeX book\/}
+gives a complete specification of the intended correspondence between
+characters and \TeX's internal representation.
+@:TeXbook}{\sl The \TeX book@>
+
+If \TeX\ is being used
+on a garden-variety \PASCAL\ for which only standard ASCII
+codes will appear in the input and output files, it doesn't really matter
+what codes are specified in |xchr[0 dotdot 037]|, 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)|.
+@^character set dependencies@>
+@^system dependencies@>
+
+@<Set init...@>=
+for (i=0; i<=037; i++) xchr[i]= ' ' ;
+for (i=0177; i<=0377; i++) xchr[i]= ' ' ;
+
+@ The following system-independent code makes the |xord| array contain a
+suitable inverse to the information in |xchr|. Note that if |xchr[i]==xchr[j]|
+where |i < j < 0177|, 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.
+
+@<Set init...@>=
+for (i=first_text_char; i<=last_text_char; i++) xord[chr(i)]=invalid_code;
+for (i=0200; i<=0377; i++) xord[xchr[i]]=i;
+for (i=0; i<=0176; i++) xord[xchr[i]]=i;
+
+@* Input and output.
+The bane of portability is the fact that different operating systems treat
+input and output quite differently, perhaps because computer scientists
+have not given sufficient attention to this problem. People have felt somehow
+that input and output are not part of ``real'' programming. Well, it is true
+that some kinds of programming are more fun than others. With existing
+input/output conventions being so diverse and so messy, the only sources of
+joy in such parts of the code are the rare occasions when one can find a
+way to make the program a little less bad than it might have been. We have
+two choices, either to attack I/O now and get it over with, or to postpone
+I/O until near the end. Neither prospect is very attractive, so let's
+get it over with.
+
+The basic operations we need to do are (1)~inputting and outputting of
+text, to or from a file or the user's terminal; (2)~inputting and
+outputting of eight-bit bytes, to or from a file; (3)~instructing the
+operating system to initiate (``open'') or to terminate (``close'') input or
+output from a specified file; (4)~testing whether the end of an input
+file has been reached.
+
+\TeX\ needs to deal with two kinds of files.
+We shall use the term |alpha_file| for a file that contains textual data,
+and the term |byte_file| for a file that contains eight-bit binary information.
+These two types turn out to be the same on many computers, but
+sometimes there is a significant distinction, so we shall be careful to
+distinguish between them. Standard protocols for transferring
+such files from computer to computer, via high-speed networks, are
+now becoming available to more and more communities of users.
+
+The program actually makes use also of a third kind of file, called a
+|word_file|, when dumping and reloading base information for its own
+initialization. We shall define a word file later; but it will be possible
+for us to specify simple operations on word files before they are defined.
+
+@<Types...@>=
+typedef uint8_t eight_bits; /*unsigned one-byte quantity*/
+typedef struct {@+FILE *f;@+text_char@,d;@+} alpha_file; /*files that contain textual data*/
+typedef struct {@+FILE *f;@+eight_bits@,d;@+} byte_file; /*files that contain binary data*/
+
+@ Most of what we need to do with respect to input and output can be handled
+by the I/O facilities that are standard in \PASCAL, i.e., the routines
+called |get|, |put|, |eof|, and so on. But
+standard \PASCAL\ does not allow file variables to be associated with file
+names that are determined at run time, so it cannot be used to implement
+\TeX; some sort of extension to \PASCAL's ordinary |reset| and |rewrite|
+is crucial for our purposes. We shall assume that |name_of_file| is a variable
+of an appropriate type such that the \PASCAL\ run-time system being used to
+implement \TeX\ can open a file whose external name is specified by
+|name_of_file|.
+@^system dependencies@>
+
+@<Glob...@>=
+uint8_t @!name_of_file0[file_name_size+1]={0}, *const @!name_of_file = @!name_of_file0-1;@;@/
+ /*on some systems this may be a \&{record} variable*/
+uint8_t @!name_length;@/ /*this many characters are actually
+ relevant in |name_of_file| (the rest are blank)*/
+
+@ 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,@t\\{name}@>,"/O")|&for input;\cr
+|rewrite(f,@t\\{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)!=0| after an unsuccessful |reset| or |rewrite|. This allows
+\TeX\ to undertake appropriate corrective action.
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+
+\TeX's file-opening procedures return |false| if no file identified by
+|name_of_file| could be opened.
+
+@d reset_OK(X) erstat(X)==0
+@d rewrite_OK(X) erstat(X)==0
+
+@p bool a_open_in(alpha_file *f)
+ /*open a text file for input*/
+{@+reset((*f), name_of_file,"r");return reset_OK((*f));
+}
+@#
+bool a_open_out(alpha_file *f)
+ /*open a text file for output*/
+{@+rewrite((*f), name_of_file,"w");return rewrite_OK((*f));
+}
+@#
+bool b_open_in(byte_file *f)
+ /*open a binary file for input*/
+{@+reset((*f), name_of_file,"rb");return reset_OK((*f));
+}
+@#
+bool b_open_out(byte_file *f)
+ /*open a binary file for output*/
+{@+rewrite((*f), name_of_file,"wb");return rewrite_OK((*f));
+}
+@#
+bool w_open_in(word_file *f)
+ /*open a word file for input*/
+{@+reset((*f), name_of_file,"rb");return reset_OK((*f));
+}
+@#
+bool w_open_out(word_file *f)
+ /*open a word file for output*/
+{@+rewrite((*f), name_of_file,"wb");return rewrite_OK((*f));
+}
+
+@ Files can be closed with the \ph\ routine `|close(f)|', which
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+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.
+
+@p void a_close(alpha_file *f) /*close a text file*/
+{@+close((*f));
+}
+@#
+void b_close(byte_file *f) /*close a binary file*/
+{@+close((*f));
+}
+@#
+void w_close(word_file *f) /*close a word file*/
+{@+close((*f));
+}
+
+@ Binary input and output are done with \PASCAL's ordinary |get| and |put|
+procedures, so we don't have to make any other special arrangements for
+binary~I/O. Text output is also easy to do with standard \PASCAL\ routines.
+The treatment of text input is more difficult, however, because
+of the necessary translation to |ASCII_code| values.
+\TeX's conventions should be efficient, and they should
+blend nicely with the user's operating environment.
+
+@ Input from text files is read one line at a time, using a routine called
+|input_ln|. This function is defined in terms of global variables called
+|buffer|, |first|, and |last| that will be described in detail later; for
+now, it suffices for us to know that |buffer| is an array of |ASCII_code|
+values, and that |first| and |last| are indices into this array
+representing the beginning and ending of a line of text.
+
+@<Glob...@>=
+ASCII_code @!buffer[buf_size+1]; /*lines of characters being read*/
+uint16_t @!first; /*the first unused position in |buffer|*/
+uint16_t @!last; /*end of the line just input to |buffer|*/
+uint16_t @!max_buf_stack; /*largest index used in |buffer|*/
+
+@ The |input_ln| function brings the next line of input from the specified
+file into available positions of the buffer array and returns the value
+|true|, unless the file has already been entirely read, in which case it
+returns |false| and sets |last=first|. In general, the |ASCII_code|
+numbers that represent the next line of the file are input into
+|buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the
+global variable |last| is set equal to |first| plus the length of the
+line. Trailing blanks are removed from the line; thus, either |last==first|
+(in which case the line was entirely blank) or |buffer[last-1]!=' '|.
+
+An overflow error is given, however, if the normal actions of |input_ln|
+would make |last >= buf_size|; this is done so that other parts of \TeX\
+can safely look at the contents of |buffer[last+1]| without overstepping
+the bounds of the |buffer| array. Upon entry to |input_ln|, the condition
+|first < buf_size| will always hold, so that there is always room for an
+``empty'' line.
+
+The variable |max_buf_stack|, which is used to keep track of how large
+the |buf_size| parameter must be to accommodate the present job, is
+also kept up to date by |input_ln|.
+
+If the |bypass_eoln| parameter is |true|, |input_ln| will do a |get|
+before looking at the first character of the line; this skips over
+an |eoln| that was in |f.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.
+@^inner loop@>
+
+@p bool input_ln(alpha_file *f, bool @!bypass_eoln)
+ /*inputs the next line or returns |false|*/
+{@+uint16_t last_nonblank; /*|last| with trailing blanks removed*/
+if (bypass_eoln) if (!eof((*f))) get((*f));
+ /*input the first character of the line into |f.d|*/
+last=first; /*cf.\ Matthew 19\thinspace:\thinspace30*/
+if (eof((*f))) return false;
+else{@+last_nonblank=first;
+ while (!eoln((*f)))
+ {@+if (last >= max_buf_stack)
+ {@+max_buf_stack=last+1;
+ if (max_buf_stack==buf_size)
+ @<Report overflow of the input buffer, and abort@>;
+ }
+ buffer[last]=xord[(*f).d];get((*f));incr(last);
+ if (buffer[last-1]!=' ') last_nonblank=last;
+ }
+ last=last_nonblank;return true;
+ }
+}
+
+@ The user's terminal acts essentially like other files of text, except
+that it is used both for input and for output. When the terminal is
+considered an input file, the file variable is called |term_in|, and when it
+is considered an output file the file variable is |term_out|.
+@^system dependencies@>
+
+@<Glob...@>=
+alpha_file @!term_in; /*the terminal as an input file*/
+alpha_file @!term_out; /*the terminal as an output file*/
+
+@ Here is how to open the terminal files
+in \ph. The `\.{/I}' switch suppresses the first |get|.
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+
+@d t_open_in term_in.f=stdin /*open the terminal for text input*/
+@d t_open_out term_out.f=stdout /*open the terminal for text output*/
+
+@ Sometimes it is necessary to synchronize the input/output mixture that
+happens on the user's terminal, and three system-dependent
+procedures are used for this
+purpose. The first of these, |update_terminal|, is called when we want
+to make sure that everything we have output to the terminal so far has
+actually left the computer's internal buffers and been sent.
+The second, |clear_terminal|, is called when we wish to cancel any
+input that the user may have typed ahead (since we are about to
+issue an unexpected error message). The third, |wake_up_terminal|,
+is supposed to revive the terminal if the user has disabled it by
+some instruction to the operating system. The following macros show how
+these operations can be specified in \ph:
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+
+@d update_terminal fflush(term_out.f) /*empty the terminal output buffer*/
+@d clear_terminal fflush(term_in.f) /*clear the terminal input buffer*/
+@d wake_up_terminal do_nothing /*cancel the user's cancellation of output*/
+
+@ We need a special routine to read the first line of \TeX\ input from
+the user's terminal. This line is different because it is read before we
+have opened the transcript file; there is sort of a ``chicken and
+egg'' problem here. If the user types `\.{\\input paper}' on the first
+line, or if some macro invoked by that line does such an \.{\\input},
+the transcript file will be named `\.{paper.log}'; but if no \.{\\input}
+commands are performed during the first line of terminal input, the transcript
+file will acquire its default name `\.{texput.log}'. (The transcript file
+will not contain error messages generated by the first line before the
+first \.{\\input} command.)
+@.texput@>
+
+The first line is even more special if we are lucky enough to have an operating
+system that treats \TeX\ differently from a run-of-the-mill \PASCAL\ object
+program. It's nice to let the user start running a \TeX\ job by typing
+a command line like `\.{tex paper}'; in such a case, \TeX\ will operate
+as if the first line of input were `\.{paper}', i.e., the first line will
+consist of the remainder of the command line, after the part that invoked
+\TeX.
+
+The first line is special also because it may be read before \TeX\ has
+input a format file. In such cases, normal error messages cannot yet
+be given. The following code uses concepts that will be explained later.
+(If the \PASCAL\ compiler does not support non-local |@!goto|\unskip, the
+@^system dependencies@>
+statement `|goto exit(0)|' should be replaced by something that
+quietly terminates the program.)
+
+@<Report overflow of the input buffer, and abort@>=
+if (format_ident==0)
+ {@+write_ln(term_out,"Buffer size exceeded!");exit(0);
+@.Buffer size exceeded@>
+ }
+else{@+cur_input.loc_field=first;cur_input.limit_field=last-1;
+ overflow("buffer size", buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+ }
+
+@ Different systems have different ways to get started. But regardless of
+what conventions are adopted, the routine that initializes the terminal
+should satisfy the following specifications:
+
+\yskip\textindent{1)}It should open file |term_in| for input from the
+ terminal. (The file |term_out| will already be open for output to the
+ terminal.)
+
+\textindent{2)}If the user has given a command line, this line should be
+ considered the first line of terminal input. Otherwise the
+ user should be prompted with `\.{**}', and the first line of input
+ should be whatever is typed in response.
+
+\textindent{3)}The first line of input, which might or might not be a
+ command line, should appear in locations |first| to |last-1| of the
+ |buffer| array.
+
+\textindent{4)}The global variable |loc| should be set so that the
+ character to be read next by \TeX\ is in |buffer[loc]|. This
+ character should not be blank, and we should have |loc < last|.
+
+\yskip\noindent(It may be necessary to prompt the user several times
+before a non-blank line comes in. The prompt is `\.{**}' instead of the
+later `\.*' because the meaning is slightly different: `\.{\\input}' need
+not be typed immediately after~`\.{**}'.)
+
+@d loc cur_input.loc_field /*location of first unread character in |buffer|*/
+
+@ The following program does the required initialization
+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.
+@^system dependencies@>
+
+@p bool init_terminal(void) /*gets the terminal input started*/
+{@+
+t_open_in;
+loop@+{@+wake_up_terminal;write(term_out,"**");update_terminal;
+@.**@>
+ if (!input_ln(&term_in, true)) /*this shouldn't happen*/
+ {@+write_ln(term_out);
+ write(term_out,"! End of file on the terminal... why?");
+@.End of file on the terminal@>
+ return false;
+ }
+ loc=first;
+ while ((loc < last)&&(buffer[loc]==' ')) incr(loc);
+ if (loc < last)
+ {@+return true;
+ /*return unless the line was all blank*/
+ }
+ write_ln(term_out,"Please type the name of your input file.");
+ }
+}
+
+@* String handling.
+Control sequence names and diagnostic messages are variable-length strings
+of eight-bit characters. Since \PASCAL\ does not have a well-developed string
+mechanism, \TeX\ does all of its string processing by homegrown methods.
+
+Elaborate facilities for dynamic strings are not needed, so all of the
+necessary operations can be handled with a simple data structure.
+The array |str_pool| contains all of the (eight-bit) ASCII codes in all
+of the strings, and the array |str_start| contains indices of the starting
+points of each string. Strings are referred to by integer numbers, so that
+string number |s| comprises the characters |str_pool[j]| for
+|str_start[s] <= j < str_start[s+1]|. Additional integer variables
+|pool_ptr| and |str_ptr| indicate the number of entries used so far
+in |str_pool| and |str_start|, respectively; locations
+|str_pool[pool_ptr]| and |str_start[str_ptr]| are
+ready for the next string to be allocated.
+
+String numbers 0 to 255 are reserved for strings that correspond to single
+ASCII characters. This is in accordance with the conventions of \.{WEB},
+@.WEB@>
+which converts single-character strings into the ASCII code number of the
+single character involved, while it converts other strings into integers
+and builds a string pool file. Thus, when the string constant \.{"."} appears
+in the program below, \.{WEB} converts it into the integer 46, which is the
+ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"}
+into some integer greater than~255. String number 46 will presumably be the
+single character `\..'; but some ASCII codes have no standard visible
+representation, and \TeX\ sometimes needs to be able to print an arbitrary
+ASCII character, so the first 256 strings are used to specify exactly what
+should be printed for each of the 256 possibilities.
+
+Elements of the |str_pool| array must be ASCII codes that can actually
+be printed; i.e., they must have an |xchr| equivalent in the local
+character set. (This restriction applies only to preloaded strings,
+not to those generated dynamically by the user.)
+
+Some \PASCAL\ compilers won't pack integers into a single byte unless the
+integers lie in the range |-128 dotdot 127|. To accommodate such systems
+we access the string pool only via macros that can easily be redefined.
+@^system dependencies@>
+
+@d si(X) X /*convert from |ASCII_code| to |packed_ASCII_code|*/
+@d so(X) X /*convert from |packed_ASCII_code| to |ASCII_code|*/
+
+@<Types...@>=
+typedef uint16_t pool_pointer; /*for variables that point into |str_pool|*/
+typedef uint16_t str_number; /*for variables that point into |str_start|*/
+typedef uint8_t packed_ASCII_code; /*elements of |str_pool| array*/
+
+@ @<Glob...@>=
+@<prepare for string pool initialization@>@;
+packed_ASCII_code @!str_pool[pool_size+1]= @<|str_pool| initialization@>; /*the characters*/
+pool_pointer @!str_start[max_strings+1]= {@<|str_start| initialization@>}; /*the starting pointers*/
+pool_pointer @!pool_ptr=@<|pool_ptr| initialization@>; /*first unused position in |str_pool|*/
+str_number @!str_ptr=@<|str_ptr| initialization@>; /*number of the current string being created*/
+pool_pointer @!init_pool_ptr; /*the starting value of |pool_ptr|*/
+str_number @!init_str_ptr; /*the starting value of |str_ptr|*/
+
+@ Several of the elementary string operations are performed using \.{WEB}
+macros instead of \PASCAL\ procedures, because many of the
+operations are done quite frequently and we want to avoid the
+overhead of procedure calls. For example, here is
+a simple macro that computes the length of a string.
+@.WEB@>
+
+@d length(X) (str_start[X+1]-str_start[X]) /*the number of characters
+ in string number \#*/
+
+@ The length of the current string is called |cur_length|:
+
+@d cur_length (pool_ptr-str_start[str_ptr])
+
+@ Strings are created by appending character codes to |str_pool|.
+The |append_char| macro, defined here, does not check to see if the
+value of |pool_ptr| has gotten too high; this test is supposed to be
+made before |append_char| is used. There is also a |flush_char|
+macro, which erases the last character appended.
+
+To test if there is room to append |l| more characters to |str_pool|,
+we shall write |str_room(l)|, which aborts \TeX\ and gives an
+apologetic error message if there isn't enough room.
+
+@d append_char(X) /*put |ASCII_code| \# at the end of |str_pool|*/
+{@+str_pool[pool_ptr]=si(X);incr(pool_ptr);
+}
+@d flush_char decr(pool_ptr) /*forget the last character in the pool*/
+@d str_room(X) /*make sure that the pool hasn't overflowed*/
+ {@+if (pool_ptr+X > pool_size)
+ overflow("pool size", pool_size-init_pool_ptr);
+@:TeX capacity exceeded pool size}{\quad pool size@>
+ }
+
+@ Once a sequence of characters has been appended to |str_pool|, it
+officially becomes a string when the function |make_string| is called.
+This function returns the identification number of the new string as its
+value.
+
+@p str_number make_string(void) /*current string enters the pool*/
+{@+if (str_ptr==max_strings)
+ overflow("number of strings", max_strings-init_str_ptr);
+@:TeX capacity exceeded number of strings}{\quad number of strings@>
+incr(str_ptr);str_start[str_ptr]=pool_ptr;
+return str_ptr-1;
+}
+
+@ To destroy the most recently made string, we say |flush_string|.
+
+@d flush_string {@+decr(str_ptr);pool_ptr=str_start[str_ptr];
+ }
+
+@ The following subroutine compares string |s| with another string of the
+same length that appears in |buffer| starting at position |k|;
+the result is |true| if and only if the strings are equal.
+Empirical tests indicate that |str_eq_buf| is used in such a way that
+it tends to return |true| about 80 percent of the time.
+
+@p bool str_eq_buf(str_number @!s, int @!k)
+ /*test equality of strings*/
+{@+ /*loop exit*/
+pool_pointer j; /*running index*/
+bool @!result; /*result of comparison*/
+j=str_start[s];
+while (j < str_start[s+1])
+ {@+if (so(str_pool[j])!=buffer[k])
+ {@+result=false;goto not_found;
+ }
+ incr(j);incr(k);
+ }
+result=true;
+not_found: return result;
+}
+
+@ Here is a similar routine, but it compares two strings in the string pool,
+and it does not assume that they have the same length.
+
+@p bool str_eq_str(str_number @!s, str_number @!t)
+ /*test equality of strings*/
+{@+ /*loop exit*/
+pool_pointer j, @!k; /*running indices*/
+bool @!result; /*result of comparison*/
+result=false;
+if (length(s)!=length(t)) goto not_found;
+j=str_start[s];k=str_start[t];
+while (j < str_start[s+1])
+ {@+if (str_pool[j]!=str_pool[k]) goto not_found;
+ incr(j);incr(k);
+ }
+result=true;
+not_found: return result;
+}
+
+@ The initial values of |str_pool|, |str_start|, |pool_ptr|,
+and |str_ptr| are computed by the \.{INITEX} program, based in part
+on the information that \.{WEB} has output while processing \TeX.
+@.INITEX@>
+@^string pool@>
+
+@p
+#ifdef @!INIT
+bool get_strings_started(void) /*initializes the string pool,
+ but returns |false| if something goes wrong*/
+{@+
+int k, @!l; /*small indices or counters*/
+uint8_t @!m, @!n; /*characters input from |pool_file|*/
+str_number @!g; /*garbage*/
+int @!a; /*accumulator for check sum*/
+bool @!c; /*check sum has been checked*/
+pool_ptr=0;str_ptr=0;str_start[0]=0;
+@<Make the first 256 strings@>;
+@<Read the other strings from the \.{TEX.POOL} file and return |true|, or give an
+error message and return |false|@>;
+}
+#endif
+
+@ @d app_lc_hex(X) l=X;
+ if (l < 10) append_char(l+'0')@;@+else append_char(l-10+'a')
+
+@<Make the first 256...@>=
+for (k=0; k<=255; k++)
+ { if (@[@<Character |k| cannot be printed@>@])
+ { append_char('^');append_char('^');
+ if (k < 0100) append_char(k+0100)@;
+ else if (k < 0200) append_char(k-0100)@;
+ else{ app_lc_hex(k/16);app_lc_hex(k%16);
+ }
+ }
+ else append_char(k);
+ g=make_string();
+ }
+
+@ 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[032]==@t\.{\'^^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[0, 010 dotdot 012, 014, 015, 033, 0177 dotdot 0377]|'.
+If character |k| cannot be printed, and |k < 0200|, then character |k+0100| or
+|k-0100| must be printable; moreover, ASCII codes |[041 dotdot 046,
+060 dotdot 071, 0136, 0141 dotdot 0146, 0160 dotdot 0171]| must be printable.
+Thus, at least 81 printable characters are needed.
+@:TeXbook}{\sl The \TeX book@>
+@^character set dependencies@>
+@^system dependencies@>
+
+@<Character |k| cannot be printed@>=
+ (k < ' ')||(k > '~')
+
+@ When the \.{WEB} system program called \.{TANGLE} processes the \.{TEX.WEB}
+description that you are now reading, it outputs the \PASCAL\ program
+\.{TEX.PAS} and also a string pool file called \.{TEX.POOL}. The \.{INITEX}
+@.WEB@>@.INITEX@>
+program reads the latter file, where each string appears as a two-digit decimal
+length followed by the string itself, and the information is recorded in
+\TeX's string memory.
+
+@<Glob...@>=
+#ifdef @!INIT
+alpha_file @!pool_file; /*the string-pool file output by \.{TANGLE}*/
+#endif
+
+@ @d bad_pool(X) {@+wake_up_terminal;write_ln(term_out, X);
+ a_close(&pool_file);return false;
+ }
+@<Read the other strings...@>=
+{@+int k;@+for(k=1; k<=file_name_size;k++)name_of_file[k]=pool_name[k-1];@+} /*we needn't set |name_length|*/
+if (a_open_in(&pool_file))
+ {@+c=false;
+ @/do@+{@<Read one string, but return |false| if the string memory space is getting
+too tight for comfort@>;
+ }@+ while (!(c));
+ a_close(&pool_file);return true;
+ }
+else bad_pool("! I can't read TEX.POOL.")
+@.I can't read TEX.POOL@>
+
+@ @<Read one string...@>=
+{@+if (eof(pool_file)) bad_pool("! TEX.POOL has no check sum.");
+@.TEX.POOL has no check sum@>
+read(pool_file, m);@+read(pool_file, n); /*read two digits of string length*/
+if (m== '*' ) @<Check the pool check sum@>@;
+else{@+if ((xord[m] < '0')||(xord[m] > '9')||@|
+ (xord[n] < '0')||(xord[n] > '9'))
+ bad_pool("! TEX.POOL line doesn't begin with two digits.");
+@.TEX.POOL line doesn't...@>
+ l=xord[m]*10+xord[n]-'0'*11; /*compute the length*/
+ if (pool_ptr+l+string_vacancies > pool_size)
+ bad_pool("! You have to increase POOLSIZE.");
+@.You have to increase POOLSIZE@>
+ for (k=1; k<=l; k++)
+ {@+if (eoln(pool_file)) m= ' ' ;@+else read(pool_file, m);
+ append_char(xord[m]);
+ }
+ read_ln(pool_file);g=make_string();
+ }
+}
+
+@ The \.{WEB} operation \.{@@\$} denotes the value that should be at the
+end of this \.{TEX.POOL} file; any other value means that the wrong pool
+file has been loaded.
+@^check sum@>
+
+@<Check the pool check sum@>=
+{@+a=0;k=1;
+loop@+{@+if ((xord[n] < '0')||(xord[n] > '9'))
+ bad_pool("! TEX.POOL check sum doesn't have nine digits.");
+@.TEX.POOL check sum...@>
+ a=10*a+xord[n]-'0';
+ if (k==9) goto done;
+ incr(k);read(pool_file, n);
+ }
+done: if (a!=0) bad_pool("! TEX.POOL doesn't match; TANGLE me again.");
+@.TEX.POOL doesn't match@>
+c=true;
+}
+
+@* On-line and off-line printing.
+Messages that are sent to a user's terminal and to the transcript-log file
+are produced by several `|print|' procedures. These procedures will
+direct their output to a variety of places, based on the setting of
+the global variable |selector|, which has the following possible
+values:
+
+\yskip
+\hang |term_and_log|, the normal setting, prints on the terminal and on the
+ transcript file.
+
+\hang |log_only|, prints only on the transcript file.
+
+\hang |term_only|, prints only on the terminal.
+
+\hang |no_print|, doesn't print at all. This is used only in rare cases
+ before the transcript file is open.
+
+\hang |pseudo|, puts output into a cyclic buffer that is used
+ by the |show_context| routine; when we get to that routine we shall discuss
+ the reasoning behind this curious mode.
+
+\hang |new_string|, appends the output to the current string in the
+ string pool.
+
+\hang 0 to 15, prints on one of the sixteen files for \.{\\write} output.
+
+\yskip
+\noindent The symbolic names `|term_and_log|', etc., have been assigned
+numeric codes that satisfy the convenient relations |no_print+1==term_only|,
+|no_print+2==log_only|, |term_only+2==log_only+1==term_and_log|.
+
+Three additional global variables, |tally| and |term_offset| and
+|file_offset|, record the number of characters that have been printed
+since they were most recently cleared to zero. We use |tally| to record
+the length of (possibly very long) stretches of printing; |term_offset|
+and |file_offset|, on the other hand, keep track of how many characters
+have appeared so far on the current line that has been output to the
+terminal or to the transcript file, respectively.
+
+@d no_print 16 /*|selector| setting that makes data disappear*/
+@d term_only 17 /*printing is destined for the terminal only*/
+@d log_only 18 /*printing is destined for the transcript file only*/
+@d term_and_log 19 /*normal |selector| setting*/
+@d pseudo 20 /*special |selector| setting for |show_context|*/
+@d new_string 21 /*printing is deflected to the string pool*/
+@d max_selector 21 /*highest selector setting*/
+
+@<Glob...@>=
+alpha_file @!log_file; /*transcript of \TeX\ session*/
+uint8_t @!selector; /*where to print a message*/
+uint8_t @!dig[23]; /*digits in a number being output*/
+int @!tally; /*the number of characters recently printed*/
+uint8_t @!term_offset;
+ /*the number of characters on the current terminal line*/
+uint8_t @!file_offset;
+ /*the number of characters on the current file line*/
+ASCII_code @!trick_buf[error_line+1]; /*circular buffer for
+ pseudoprinting*/
+int @!trick_count; /*threshold for pseudoprinting, explained later*/
+int @!first_count; /*another variable for pseudoprinting*/
+
+@ @<Initialize the output routines@>=
+selector=term_only;tally=0;term_offset=0;file_offset=0;
+
+@ Macro abbreviations for output to the terminal and to the log file are
+defined here for convenience. Some systems need special conventions
+for terminal output, and it is possible to adhere to those conventions
+by changing |wterm|, |wterm_ln|, and |wterm_cr| in this section.
+@^system dependencies@>
+
+@<Compiler directives@>=
+#define put(file) @[fwrite(&((file).d),sizeof((file).d),1,(file).f)@]
+#define get(file) @[fread(&((file).d),sizeof((file).d),1,(file).f)@]
+
+#define reset(file,name,mode) @[((file).f=fopen((char *)(name)+1,mode),\
+ (file).f!=NULL?get(file):0)@]
+#define rewrite(file,name,mode) @[((file).f=fopen((char *)(name)+1,mode))@]
+#define close(file) @[fclose((file).f)@]
+#define eof(file) @[feof((file).f)@]
+#define eoln(file) @[((file).d=='\n'||eof(file))@]
+#define erstat(file) @[((file).f==NULL?-1:ferror((file).f))@]
+
+#define read(file,x) @[((x)=(file).d,get(file))@]
+#define read_ln(file) @[do get(file); while (!eoln(file))@]
+
+#define write(file, format,...) @[fprintf(file.f,format,## __VA_ARGS__)@]
+#define write_ln(file,...) @[write(file,__VA_ARGS__"\n")@]
+
+#define wterm(format,...) @[write(term_out,format, ## __VA_ARGS__)@]
+#define wterm_ln(format,...) @[wterm(format "\n", ## __VA_ARGS__)@]
+#define wterm_cr @[write(term_out,"\n")@]
+#define wlog(format, ...) @[write(log_file,format, ## __VA_ARGS__)@]
+#define wlog_ln(format, ...) @[wlog(format "\n", ## __VA_ARGS__)@]
+#define wlog_cr @[write(log_file,"\n")@]
+
+@ To end a line of text output, we call |print_ln|.
+
+@<Basic print...@>=
+void print_ln(void) /*prints an end-of-line*/
+{@+switch (selector) {
+case term_and_log: {@+wterm_cr;wlog_cr;
+ term_offset=0;file_offset=0;
+ } @+break;
+case log_only: {@+wlog_cr;file_offset=0;
+ } @+break;
+case term_only: {@+wterm_cr;term_offset=0;
+ } @+break;
+case no_print: case pseudo: case new_string: do_nothing;@+break;
+default:write_ln(write_file[selector]);
+} @/
+} /*|tally| is not affected*/
+
+@ The |print_char| procedure sends one character to the desired destination,
+using the |xchr| array to map it into an external character compatible with
+|input_ln|. All printing comes through |print_ln| or |print_char|.
+
+@<Basic printing...@>=
+void print_char(ASCII_code @!s) /*prints a single character*/
+{@+
+if (@<Character |s| is the current new-line character@>)
+ if (selector < pseudo)
+ {@+print_ln();return;
+ }
+switch (selector) {
+case term_and_log: {@+wterm("%c",xchr[s]);wlog("%c",xchr[s]);
+ incr(term_offset);incr(file_offset);
+ if (term_offset==max_print_line)
+ {@+wterm_cr;term_offset=0;
+ }
+ if (file_offset==max_print_line)
+ {@+wlog_cr;file_offset=0;
+ }
+ } @+break;
+case log_only: {@+wlog("%c",xchr[s]);incr(file_offset);
+ if (file_offset==max_print_line) print_ln();
+ } @+break;
+case term_only: {@+wterm("%c",xchr[s]);incr(term_offset);
+ if (term_offset==max_print_line) print_ln();
+ } @+break;
+case no_print: do_nothing;@+break;
+case pseudo: if (tally < trick_count) trick_buf[tally%error_line]=s;@+break;
+case new_string: {@+if (pool_ptr < pool_size) append_char(s);
+ } @+break; /*we drop characters if the string space is full*/
+default:write(write_file[selector],"%c", xchr[s]);
+} @/
+incr(tally);
+}
+
+@ An entire string is output by calling |print|. Note that if we are outputting
+the single standard ASCII character \.c, we could call |print('c')|, since
+|'c'==99| is the number of a single-character string, as explained above. But
+|print_char('c')| is quicker, so \TeX\ goes directly to the |print_char|
+routine when it knows that this is safe. (The present implementation
+assumes that it is always safe to print a visible ASCII character.)
+@^system dependencies@>
+
+@<Basic print...@>=
+void print(int @!s) /*prints string |s|*/
+{@+
+pool_pointer j; /*current character code position*/
+int @!nl; /*new-line character to restore*/
+if (s >= str_ptr) s=@[@<|"???"|@>@]; /*this can't happen*/
+@.???@>
+else if (s < 256)
+ if (s < 0) s=@[@<|"???"|@>@]; /*can't happen*/
+ else{@+if (selector > pseudo)
+ {@+print_char(s);return; /*internal strings are not expanded*/
+ }
+ if ((@<Character |s| is the current new-line character@>))
+ if (selector < pseudo)
+ {@+print_ln();return;
+ }
+ nl=new_line_char;new_line_char=-1;
+ /*temporarily disable new-line character*/
+ j=str_start[s];
+ while (j < str_start[s+1])
+ {@+print_char(so(str_pool[j]));incr(j);
+ }
+ new_line_char=nl;return;
+ }
+j=str_start[s];
+while (j < str_start[s+1])
+ {@+print_char(so(str_pool[j]));incr(j);
+ }
+}
+
+void print_str(char *s) /* the simple version */
+{while (*s!=0) print_char(*s++);@+
+}
+
+@ Control sequence names, file names, and strings constructed with
+\.{\\string} might contain |ASCII_code| values that can't
+be printed using |print_char|. Therefore we use |slow_print| for them:
+
+@<Basic print...@>=
+void slow_print(int @!s) /*prints string |s|*/
+{@+pool_pointer j; /*current character code position*/
+if ((s >= str_ptr)||(s < 256)) print(s);
+else{@+j=str_start[s];
+ while (j < str_start[s+1])
+ {@+print(so(str_pool[j]));incr(j);
+ }
+ }
+}
+
+@ Here is the very first thing that \TeX\ prints: a headline that identifies
+the version number and format package. The |term_offset| variable is temporarily
+incorrect, but the discrepancy is not serious since we assume that the banner
+and format identifier together will occupy at most |max_print_line|
+character positions.
+
+@<Initialize the output...@>=
+wterm("%s",banner);
+if (format_ident==0) wterm_ln(" (no format preloaded)");
+else{@+slow_print(format_ident);print_ln();
+ }
+update_terminal;
+
+@ The procedure |print_nl| is like |print|, but it makes sure that the
+string appears at the beginning of a new line.
+
+@<Basic print...@>=
+void print_nl(char *@!s) /*prints string |s| at beginning of line*/
+{@+if (((term_offset > 0)&&(odd(selector)))||@|
+ ((file_offset > 0)&&(selector >= log_only))) print_ln();
+print_str(s);
+}
+
+@ The procedure |print_esc| prints a string that is preceded by
+the user's escape character (which is usually a backslash).
+
+@<Basic print...@>=
+void print_esc(str_number @!s) /*prints escape character, then |s|*/
+{@+int c; /*the escape character code*/
+@<Set variable |c| to the current escape character@>;
+if (c >= 0) if (c < 256) print(c);
+slow_print(s);
+}
+
+@ An array of digits in the range |0 dotdot 15| is printed by |print_the_digs|.
+
+@<Basic print...@>=
+void print_the_digs(eight_bits @!k)
+ /*prints |dig[k-1]|$\,\ldots\,$|dig[0]|*/
+{@+while (k > 0)
+ {@+decr(k);
+ if (dig[k] < 10) print_char('0'+dig[k]);
+ else print_char('A'-10+dig[k]);
+ }
+}
+
+@ The following procedure, which prints out the decimal representation of a
+given integer |n|, has been written carefully so that it works properly
+if |n==0| or if |(-n)| would cause overflow. It does not apply |%| or |/|
+to negative arguments, since such operations are not implemented consistently
+by all \PASCAL\ compilers.
+
+@<Basic print...@>=
+void print_int(int @!n) /*prints an integer in decimal form*/
+{@+uint8_t k; /*index to current digit; we assume that $|n|<10^{23}$*/
+int @!m; /*used to negate |n| in possibly dangerous cases*/
+k=0;
+if (n < 0)
+ {@+print_char('-');
+ if (n > -100000000) negate(n);
+ else{@+m=-1-n;n=m/10;m=(m%10)+1;k=1;
+ if (m < 10) dig[0]=m;
+ else{@+dig[0]=0;incr(n);
+ }
+ }
+ }
+@/do@+{dig[k]=n%10;n=n/10;incr(k);
+}@+ while (!(n==0));
+print_the_digs(k);
+}
+
+@ Here is a trivial procedure to print two digits; it is usually called with
+a parameter in the range |0 <= n <= 99|.
+
+@p void print_two(int @!n) /*prints two least significant digits*/
+{@+n=abs(n)%100;print_char('0'+(n/10));
+print_char('0'+(n%10));
+}
+
+@ Hexadecimal printing of nonnegative integers is accomplished by |print_hex|.
+
+@p void print_hex(int @!n)
+ /*prints a positive integer in hexadecimal form*/
+{@+uint8_t k; /*index to current digit; we assume that $0\L n<16^{22}$*/
+k=0;print_char('"');
+@/do@+{dig[k]=n%16;n=n/16;incr(k);
+}@+ while (!(n==0));
+print_the_digs(k);
+}
+
+@ Old versions of \TeX\ needed a procedure called |print_ASCII| whose function
+is now subsumed by |print|. We retain the old name here as a possible aid to
+future software arch\ae ologists.
+
+@d print_ASCII print
+
+@ Roman numerals are produced by the |print_roman_int| routine. Readers
+who like puzzles might enjoy trying to figure out how this tricky code
+works; therefore no explanation will be given. Notice that 1990 yields
+\.{mcmxc}, not \.{mxm}.
+
+@p void print_roman_int(int @!n)
+{@+
+pool_pointer j, @!k; /*mysterious indices into |str_pool|*/
+nonnegative_integer @!u, @!v; /*mysterious numbers*/
+j=str_start[@[@<|"m2d5c2l5x2v5i"|@>@]];v=1000;
+loop@+{@+while (n >= v)
+ {@+print_char(so(str_pool[j]));n=n-v;
+ }
+ if (n <= 0) return; /*nonpositive input produces no output*/
+ k=j+2;u=v/(so(str_pool[k-1])-'0');
+ if (str_pool[k-1]==si('2'))
+ {@+k=k+2;u=u/(so(str_pool[k-1])-'0');
+ }
+ if (n+u >= v)
+ {@+print_char(so(str_pool[k]));n=n+u;
+ }
+ else{@+j=j+2;v=v/(so(str_pool[j-1])-'0');
+ }
+ }
+}
+
+@ The |print| subroutine will not print a string that is still being
+created. The following procedure will.
+
+@p void print_current_string(void) /*prints a yet-unmade string*/
+{@+pool_pointer j; /*points to current character code*/
+j=str_start[str_ptr];
+while (j < pool_ptr)
+ {@+print_char(so(str_pool[j]));incr(j);
+ }
+}
+
+@ Here is a procedure that asks the user to type a line of input,
+assuming that the |selector| setting is either |term_only| or |term_and_log|.
+The input is placed into locations |first| through |last-1| of the
+|buffer| array, and echoed on the transcript file if appropriate.
+
+This procedure is never called when |interaction < scroll_mode|.
+
+@d prompt_input(X) {@+wake_up_terminal;print_str(X);term_input();
+ } /*prints a string and gets a line of input*/
+
+@p void term_input(void) /*gets a line from the terminal*/
+{@+int k; /*index into |buffer|*/
+update_terminal; /*now the user sees the prompt for sure*/
+if (!input_ln(&term_in, true)) fatal_error("End of file on the terminal!");
+@.End of file on the terminal@>
+term_offset=0; /*the user's line ended with \<\rm return>*/
+decr(selector); /*prepare to echo the input*/
+if (last!=first) for (k=first; k<=last-1; k++) print(buffer[k]);
+print_ln();incr(selector); /*restore previous status*/
+}
+
+@* Reporting errors.
+When something anomalous is detected, \TeX\ typically does something like this:
+$$\vbox{\halign{#\hfil\cr
+|print_err("Something anomalous has been detected");|\cr
+|help3("This is the first line of my offer to help.")|\cr
+|("This is the second line. I'm trying to")|\cr
+|("explain the best way for you to proceed.");|\cr
+|error;|\cr}}$$
+A two-line help message would be given using |help2|, etc.; these informal
+helps should use simple vocabulary that complements the words used in the
+official error message that was printed. (Outside the U.S.A., the help
+messages should preferably be translated into the local vernacular. Each
+line of help is at most 60 characters long, in the present implementation,
+so that |max_print_line| will not be exceeded.)
+
+The |print_err| procedure supplies a `\.!' before the official message,
+and makes sure that the terminal is awake if a stop is going to occur.
+The |error| procedure supplies a `\..' after the official message, then it
+shows the location of the error; and if |interaction==error_stop_mode|,
+it also enters into a dialog with the user, during which time the help
+message may be printed.
+@^system dependencies@>
+
+@ The global variable |interaction| has four settings, representing increasing
+amounts of user interaction:
+
+@d batch_mode 0 /*omits all stops and omits terminal output*/
+@d nonstop_mode 1 /*omits all stops*/
+@d scroll_mode 2 /*omits error stops*/
+@d error_stop_mode 3 /*stops at every opportunity to interact*/
+@d print_err(X) {@+if (interaction==error_stop_mode) wake_up_terminal;
+ print_nl("! ");print_str(X);
+ }
+
+@<Glob...@>=
+uint8_t @!interaction; /*current level of interaction*/
+
+@ @<Set init...@>=interaction=error_stop_mode;
+
+@ \TeX\ is careful not to call |error| when the print |selector| setting
+might be unusual. The only possible values of |selector| at the time of
+error messages are
+
+\yskip\hang|no_print| (when |interaction==batch_mode|
+ and |log_file| not yet open);
+
+\hang|term_only| (when |interaction > batch_mode| and |log_file| not yet open);
+
+\hang|log_only| (when |interaction==batch_mode| and |log_file| is open);
+
+\hang|term_and_log| (when |interaction > batch_mode| and |log_file| is open).
+
+@<Initialize the print |selector| based on |interaction|@>=
+if (interaction==batch_mode) selector=no_print;@+else selector=term_only
+
+@ A global variable |deletions_allowed| is set |false| if the |get_next|
+routine is active when |error| is called; this ensures that |get_next|
+and related routines like |get_token| will never be called recursively.
+A similar interlock is provided by |set_box_allowed|.
+@^recursion@>
+
+The global variable |history| records the worst level of error that
+has been detected. It has four possible values: |spotless|, |warning_issued|,
+|error_message_issued|, and |fatal_error_stop|.
+
+Another global variable, |error_count|, is increased by one when an
+|error| occurs without an interactive dialog, and it is reset to zero at
+the end of every paragraph. If |error_count| reaches 100, \TeX\ decides
+that there is no point in continuing further.
+
+@d spotless 0 /*|history| value when nothing has been amiss yet*/
+@d warning_issued 1 /*|history| value when |begin_diagnostic| has been called*/
+@d error_message_issued 2 /*|history| value when |error| has been called*/
+@d fatal_error_stop 3 /*|history| value when termination was premature*/
+
+@<Glob...@>=
+bool @!deletions_allowed; /*is it safe for |error| to call |get_token|?*/
+bool @!set_box_allowed; /*is it safe to do a \.{\\setbox} assignment?*/
+uint8_t @!history; /*has the source input been clean so far?*/
+int8_t @!error_count; /*the number of scrolled errors since the
+ last paragraph ended*/
+
+@ The value of |history| is initially |fatal_error_stop|, but it will
+be changed to |spotless| if \TeX\ survives the initialization process.
+
+@<Set init...@>=
+deletions_allowed=true;set_box_allowed=true;
+error_count=0; /*|history| is initialized elsewhere*/
+
+@ Since errors can be detected almost anywhere in \TeX, we want to declare the
+error procedures near the beginning of the program. But the error procedures
+in turn use some other procedures, which need to be declared |forward|
+before we get to |error| itself.
+
+It is possible for |error| to be called recursively if some error arises
+when |get_token| is being used to delete a token, and/or if some fatal error
+occurs while \TeX\ is trying to fix a non-fatal one. But such recursion
+@^recursion@>
+is never more than two levels deep.
+
+@<Error handling...@>=
+void normalize_selector(void);@/
+void get_token(void);@/
+void term_input(void);@/
+void show_context(void);@/
+void begin_file_reading(void);@/
+void open_log_file(void);@/
+void close_files_and_terminate(void);@/
+void clear_for_error_prompt(void);@/
+void give_err_help(void);@/
+#ifdef @!DEBUG
+void debug_help(void);
+#else
+#define debug_help() do_nothing
+#endif
+
+@ Individual lines of help are recorded in the array |help_line|, which
+contains entries in positions |0 dotdot(help_ptr-1)|. They should be printed
+in reverse order, i.e., with |help_line[0]| appearing last.
+
+@d hlp1(X) help_line[0]=X;@+}
+@d hlp2(X) help_line[1]=X;hlp1
+@d hlp3(X) help_line[2]=X;hlp2
+@d hlp4(X) help_line[3]=X;hlp3
+@d hlp5(X) help_line[4]=X;hlp4
+@d hlp6(X) help_line[5]=X;hlp5
+@d help0 help_ptr=0 /*sometimes there might be no help*/
+@d help1 @+{@+help_ptr=1;hlp1 /*use this with one help line*/
+@d help2 @+{@+help_ptr=2;hlp2 /*use this with two help lines*/
+@d help3 @+{@+help_ptr=3;hlp3 /*use this with three help lines*/
+@d help4 @+{@+help_ptr=4;hlp4 /*use this with four help lines*/
+@d help5 @+{@+help_ptr=5;hlp5 /*use this with five help lines*/
+@d help6 @+{@+help_ptr=6;hlp6 /*use this with six help lines*/
+
+@<Glob...@>=
+char *@!help_line[6]; /*helps for the next |error|*/
+uint8_t @!help_ptr; /*the number of help lines present*/
+bool @!use_err_help; /*should the |err_help| list be shown?*/
+
+@ @<Set init...@>=
+help_ptr=0;use_err_help=false;
+
+@ The |jump_out| procedure just cuts across all active procedure levels and
+goes to |end_of_TEX|. This is the only nontrivial |@!goto| statement in the
+whole program. It is used when there is no recovery from a particular error.
+
+Some \PASCAL\ compilers do not implement non-local |goto| statements.
+@^system dependencies@>
+In such cases the body of |jump_out| should simply be
+`|close_files_and_terminate|;\thinspace' followed by a call on some system
+procedure that quietly terminates the program.
+
+@<Error hand...@>=
+void jump_out(void)
+{@+ close_files_and_terminate(); exit(0);
+}
+
+@ Here now is the general |error| routine.
+
+@<Error hand...@>=
+void error(void) /*completes the job of error reporting*/
+{@+
+ASCII_code c; /*what the user types*/
+int @!s1, @!s2, @!s3, @!s4;
+ /*used to save global variables when deleting tokens*/
+if (history < error_message_issued) history=error_message_issued;
+print_char('.');show_context();
+if (interaction==error_stop_mode) @<Get user's advice and |return|@>;
+incr(error_count);
+if (error_count==100)
+ {@+print_nl("(That makes 100 errors; please try again.)");
+@.That makes 100 errors...@>
+ history=fatal_error_stop;jump_out();
+ }
+@<Put help message on the transcript file@>;
+}
+
+@ @<Get user's advice...@>=
+loop@+{@+resume: clear_for_error_prompt();prompt_input("? ");
+@.?\relax@>
+ if (last==first) return;
+ c=buffer[first];
+ if (c >= 'a') c=c+'A'-'a'; /*convert to uppercase*/
+ @<Interpret code |c| and |return| if done@>;
+ }
+
+@ 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.
+@^system dependencies@>
+
+There is a secret `\.D' option available when the debugging routines haven't
+been commented~out.
+@^debugging@>
+
+@<Interpret code |c| and |return| if done@>=
+switch (c) {
+case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (deletions_allowed)
+ @<Delete \(c)|c-"0"| tokens and |goto continue|@>@;@+break;
+@t\4\4@>@;
+#ifdef @!DEBUG
+case 'D': {@+debug_help();goto resume;@+}
+#endif
+case 'E': if (base_ptr > 0)
+ {@+print_nl("You want to edit file ");
+@.You want to edit file x@>
+ slow_print(input_stack[base_ptr].name_field);
+ print_str(" at line ");print_int(line);
+ interaction=scroll_mode;jump_out();
+ } @+break;
+case 'H': @<Print the help information and |goto continue|@>@;
+case 'I': @<Introduce new material from the terminal and |return|@>@;
+case 'Q': case 'R': case 'S': @<Change the interaction level and |return|@>@;
+case 'X': {@+interaction=scroll_mode;jump_out();
+ } @+break;
+default:do_nothing;
+} @/
+@<Print the menu of available options@>@;
+
+@ @<Print the menu...@>=
+{@+print_str("Type <return> to proceed, S to scroll future error messages,");@/
+@.Type <return> to proceed...@>
+print_nl("R to run without stopping, Q to run quietly,");@/
+print_nl("I to insert something, ");
+if (base_ptr > 0) print_str("E to edit your file,");
+if (deletions_allowed)
+ print_nl("1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
+print_nl("H for help, X to quit.");
+}
+
+@ Here the author of \TeX\ apologizes for making use of the numerical
+relation between |'Q'|, |'R'|, |'S'|, and the desired interaction settings
+|batch_mode|, |nonstop_mode|, |scroll_mode|.
+@^Knuth, Donald Ervin@>
+
+@<Change the interaction...@>=
+{@+error_count=0;interaction=batch_mode+c-'Q';
+print_str("OK, entering ");
+switch (c) {
+case 'Q': {@+print_esc(@[@<|"batchmode"|@>@]);decr(selector);
+ } @+break;
+case 'R': print_esc(@[@<|"nonstopmode"|@>@]);@+break;
+case 'S': print_esc(@[@<|"scrollmode"|@>@]);
+} /*there are no other cases*/
+print_str("...");print_ln();update_terminal;return;
+}
+
+@ When the following code is executed, |buffer[(first+1)dotdot(last-1)]| may
+contain the material inserted by the user; otherwise another prompt will
+be given. In order to understand this part of the program fully, you need
+to be familiar with \TeX's input stacks.
+
+@<Introduce new material...@>=
+{@+begin_file_reading(); /*enter a new syntactic level for terminal input*/
+ /*now |state==mid_line|, so an initial blank space will count as a blank*/
+if (last > first+1)
+ {@+loc=first+1;buffer[first]=' ';
+ }
+else{@+prompt_input("insert>");loc=first;
+@.insert>@>
+ }
+first=last;
+cur_input.limit_field=last-1; /*no |end_line_char| ends this line*/
+return;
+}
+
+@ We allow deletion of up to 99 tokens at a time.
+
+@<Delete \(c)|c-"0"| tokens...@>=
+{@+s1=cur_tok;s2=cur_cmd;s3=cur_chr;s4=align_state;
+align_state=1000000;OK_to_interrupt=false;
+if ((last > first+1)&&(buffer[first+1] >= '0')&&(buffer[first+1] <= '9'))
+ c=c*10+buffer[first+1]-'0'*11;
+else c=c-'0';
+while (c > 0)
+ {@+get_token(); /*one-level recursive call of |error| is possible*/
+ decr(c);
+ }
+cur_tok=s1;cur_cmd=s2;cur_chr=s3;align_state=s4;OK_to_interrupt=true;
+help2("I have just deleted some text, as you asked.")@/
+("You can now delete more, or insert, or whatever.");
+show_context();goto resume;
+}
+
+@ @<Print the help info...@>=
+{@+if (use_err_help)
+ {@+give_err_help();use_err_help=false;
+ }
+else{@+if (help_ptr==0)
+ help2("Sorry, I don't know how to help in this situation.")@/
+ @t\kern1em@>("Maybe you should try asking a human?");
+ @/do@+{decr(help_ptr);print_str(help_line[help_ptr]);print_ln();
+ }@+ while (!(help_ptr==0));
+ }
+help4("Sorry, I already gave what help I could...")@/
+ ("Maybe you should try asking a human?")@/
+ ("An error might have occurred before I noticed any problems.")@/
+ ("``If all else fails, read the instructions.'");@/
+goto resume;
+}
+
+@ @<Put help message on the transcript file@>=
+if (interaction > batch_mode) decr(selector); /*avoid terminal output*/
+if (use_err_help)
+ {@+print_ln();give_err_help();
+ }
+else while (help_ptr > 0)
+ {@+decr(help_ptr);print_nl(help_line[help_ptr]);
+ }
+print_ln();
+if (interaction > batch_mode) incr(selector); /*re-enable terminal output*/
+print_ln()
+
+@ A dozen or so error messages end with a parenthesized integer, so we
+save a teeny bit of program space by declaring the following procedure:
+
+@p void int_error(int @!n)
+{@+print_str(" (");print_int(n);print_char(')');error();
+}
+
+@ In anomalous cases, the print selector might be in an unknown state;
+the following subroutine is called to fix things just enough to keep
+running a bit longer.
+
+@p void normalize_selector(void)
+{@+if (log_opened) selector=term_and_log;
+else selector=term_only;
+if (job_name==0) open_log_file();
+if (interaction==batch_mode) decr(selector);
+}
+
+@ The following procedure prints \TeX's last words before dying.
+
+@d succumb {@+if (interaction==error_stop_mode)
+ interaction=scroll_mode; /*no more interaction*/
+ if (log_opened) error();
+ if (interaction > batch_mode) debug_help();
+ history=fatal_error_stop;jump_out(); /*irrecoverable error*/
+ }
+
+@<Error hand...@>=
+void fatal_error(char *@!s) /*prints |s|, and that's it*/
+{@+normalize_selector();@/
+print_err("Emergency stop");help1(s);succumb;
+@.Emergency stop@>
+}
+
+@ Here is the most dreaded error message.
+
+@<Error hand...@>=
+void overflow(char *@!s, int @!n) /*stop due to finiteness*/
+{@+normalize_selector();
+print_err("TeX capacity exceeded, sorry [");
+@.TeX capacity exceeded ...@>
+print_str(s);print_char('=');print_int(n);print_char(']');
+help2("If you really absolutely need more capacity,")@/
+ ("you can ask a wizard to enlarge me.");
+succumb;
+}
+
+@ The program might sometime run completely amok, at which point there is
+no choice but to stop. If no previous error has been detected, that's bad
+news; a message is printed that is really intended for the \TeX\
+maintenance person instead of the user (unless the user has been
+particularly diabolical). The index entries for `this can't happen' may
+help to pinpoint the problem.
+@^dry rot@>
+
+@<Error hand...@>=
+void confusion(str_number @!s)
+ /*consistency check violated; |s| tells where*/
+{@+normalize_selector();
+if (history < error_message_issued)
+ {@+print_err("This can't happen (");print(s);print_char(')');
+@.This can't happen@>
+ help1("I'm broken. Please show this to someone who can fix can fix");
+ }
+else{@+print_err("I can't go on meeting you like this");
+@.I can't go on...@>
+ help2("One of your faux pas seems to have wounded me deeply...")@/
+ ("in fact, I'm barely conscious. Please fix it and try again.");
+ }
+succumb;
+}
+
+@ Users occasionally want to interrupt \TeX\ while it's running.
+If the \PASCAL\ runtime system allows this, one can implement
+a routine that sets the global variable |interrupt| to some nonzero value
+when such an interrupt is signalled. Otherwise there is probably at least
+a way to make |interrupt| nonzero using the \PASCAL\ debugger.
+@^system dependencies@>
+@^debugging@>
+
+@d check_interrupt {@+if (interrupt!=0) pause_for_instructions();
+ }
+
+@<Global...@>=
+int @!interrupt; /*should \TeX\ pause for instructions?*/
+bool @!OK_to_interrupt; /*should interrupts be observed?*/
+
+@ @<Set init...@>=
+interrupt=0;OK_to_interrupt=true;
+
+@ When an interrupt has been detected, the program goes into its
+highest interaction level and lets the user have nearly the full flexibility of
+the |error| routine. \TeX\ checks for interrupts only at times when it is
+safe to do this.
+
+@p void pause_for_instructions(void)
+{@+if (OK_to_interrupt)
+ {@+interaction=error_stop_mode;
+ if ((selector==log_only)||(selector==no_print))
+ incr(selector);
+ print_err("Interruption");
+@.Interruption@>
+ help3("You rang?")@/
+ ("Try to insert some instructions for me (e.g.,`I\\showlists'),")@/
+ ("unless you just want to quit by typing `X'.");
+ deletions_allowed=false;error();deletions_allowed=true;
+ interrupt=0;
+ }
+}
+
+@* Arithmetic with scaled dimensions.
+The principal computations performed by \TeX\ are done entirely in terms of
+integers less than $2^{31}$ in magnitude; and divisions are done only when both
+dividend and divisor are nonnegative. Thus, the arithmetic specified in this
+program can be carried out in exactly the same way on a wide variety of
+computers, including some small ones. Why? Because the arithmetic
+calculations need to be spelled out precisely in order to guarantee that
+\TeX\ will produce identical output on different machines. If some
+quantities were rounded differently in different implementations, we would
+find that line breaks and even page breaks might occur in different places.
+Hence the arithmetic of \TeX\ has been designed with care, and systems that
+claim to be implementations of \TeX82 should follow precisely the
+@:TeX82}{\TeX82@>
+calculations as they appear in the present program.
+
+(Actually there are three places where \TeX\ uses |/| 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 |%| as well as for |/|.)
+
+@ Here is a routine that calculates half of an integer, using an
+unambiguous convention with respect to signed odd numbers.
+
+@p int half(int @!x)
+{@+if (odd(x)) return(x+1)/2;
+else return x/2;
+}
+
+@ Fixed-point arithmetic is done on {\sl scaled integers\/} that are multiples
+of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit
+positions from the right end of a binary computer word.
+
+@d unity 0200000 /*$2^{16}$, represents 1.00000*/
+@d two 0400000 /*$2^{17}$, represents 2.00000*/
+
+@<Types...@>=
+typedef int scaled; /*this type is used for scaled integers*/
+typedef uint32_t nonnegative_integer; /*$0\L x<2^{31}$*/
+typedef uint8_t small_number; /*this type is self-explanatory*/
+
+@ The following function is used to create a scaled integer from a given decimal
+fraction $(.d_0d_1\ldots d_{k-1})$, where |0 <= k <= 17|. The digit $d_i$ is
+given in |dig[i]|, and the calculation produces a correctly rounded result.
+
+@p scaled round_decimals(small_number @!k)
+ /*converts a decimal fraction*/
+{@+int a; /*the accumulator*/
+a=0;
+while (k > 0)
+ {@+decr(k);a=(a+dig[k]*two)/10;
+ }
+return(a+1)/2;
+}
+
+@ Conversely, here is a procedure analogous to |print_int|. If the output
+of this procedure is subsequently read by \TeX\ and converted by the
+|round_decimals| routine above, it turns out that the original value will
+be reproduced exactly; the ``simplest'' such decimal number is output,
+but there is always at least one digit following the decimal point.
+
+The invariant relation in the \&{repeat} loop is that a sequence of
+decimal digits yet to be printed will yield the original number if and only if
+they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$.
+We can stop if and only if $f=0$ satisfies this condition; the loop will
+terminate before $s$ can possibly become zero.
+
+@p void print_scaled(scaled @!s) /*prints scaled real, rounded to five
+ digits*/
+{@+scaled delta; /*amount of allowable inaccuracy*/
+if (s < 0)
+ {@+print_char('-');negate(s); /*print the sign, if negative*/
+ }
+print_int(s/unity); /*print the integer part*/
+print_char('.');
+s=10*(s%unity)+5;delta=10;
+@/do@+{if (delta > unity) s=s+0100000-50000; /*round the last digit*/
+print_char('0'+(s/unity));s=10*(s%unity);delta=delta*10;
+}@+ while (!(s <= delta));
+}
+
+@ Physical sizes that a \TeX\ user specifies for portions of documents are
+represented internally as scaled points. Thus, if we define an `sp' (scaled
+@^sp@>
+point) as a unit equal to $2^{-16}$ printer's points, every dimension
+inside of \TeX\ is an integer number of sp. There are exactly
+4,736,286.72 sp per inch. Users are not allowed to specify dimensions
+larger than $2^{30}-1$ sp, which is a distance of about 18.892 feet (5.7583
+meters); two such quantities can be added without overflow on a 32-bit
+computer.
+
+The present implementation of \TeX\ does not check for overflow when
+@^overflow in arithmetic@>
+dimensions are added or subtracted. This could be done by inserting a
+few dozen tests of the form `\ignorespaces|if (x >= 010000000000)@/
+@t\\{report\_overflow}@>|', but the chance of overflow is so remote that
+such tests do not seem worthwhile.
+
+\TeX\ needs to do only a few arithmetic operations on scaled quantities,
+other than addition and subtraction, and the following subroutines do most of
+the work. A single computation might use several subroutine calls, and it is
+desirable to avoid producing multiple error messages in case of arithmetic
+overflow; so the routines set the global variable |arith_error| to |true|
+instead of reporting errors directly to the user. Another global variable,
+|rem|, holds the remainder after a division.
+
+@<Glob...@>=
+bool @!arith_error; /*has arithmetic overflow occurred recently?*/
+scaled @!rem; /*amount subtracted to get an exact division*/
+
+@ The first arithmetical subroutine we need computes $nx+y$, where |x|
+and~|y| are |scaled| and |n| is an integer. We will also use it to
+multiply integers.
+
+@d nx_plus_y(X, Y, Z) mult_and_add(X, Y, Z, 07777777777)
+@d mult_integers(X, Y) mult_and_add(X, Y, 0, 017777777777)
+
+@p scaled mult_and_add(int @!n, scaled @!x, scaled @!y, scaled @!max_answer)
+{@+if (n < 0)
+ {@+negate(x);negate(n);
+ }
+if (n==0) return y;
+else if (((x <= (max_answer-y)/n)&&(-x <= (max_answer+y)/n)))
+ return n*x+y;
+else{@+arith_error=true;return 0;
+ }
+}
+
+@ We also need to divide scaled dimensions by integers.
+
+@p scaled x_over_n(scaled @!x, int @!n)
+{@+bool negative; /*should |rem| be negated?*/
+scaled x_over_n; negative=false;
+if (n==0)
+ {@+arith_error=true;x_over_n=0;rem=x;
+ }
+else{@+if (n < 0)
+ {@+negate(x);negate(n);negative=true;
+ }
+ if (x >= 0)
+ {@+x_over_n=x/n;rem=x%n;
+ }
+ else{@+x_over_n=-((-x)/n);rem=-((-x)%n);
+ }
+ }
+if (negative) negate(rem);
+return x_over_n;}
+
+@ Then comes the multiplication of a scaled number by a fraction |n/(double)d|,
+where |n| and |d| are nonnegative integers | <= @t$2^{16}$@>| and |d| is
+positive. It would be too dangerous to multiply by~|n| and then divide
+by~|d|, in separate operations, since overflow might well occur; and it
+would be too inaccurate to divide by |d| and then multiply by |n|. Hence
+this subroutine simulates 1.5-precision arithmetic.
+
+@p scaled xn_over_d(scaled @!x, int @!n, int @!d)
+{@+bool positive; /*was |x >= 0|?*/
+nonnegative_integer @!t, @!u, @!v; /*intermediate quantities*/
+scaled xn_over_d; if (x >= 0) positive=true;
+else{@+negate(x);positive=false;
+ }
+t=(x%0100000)*n;
+u=(x/0100000)*n+(t/0100000);
+v=(u%d)*0100000+(t%0100000);
+if (u/d >= 0100000) arith_error=true;
+else u=0100000*(u/d)+(v/d);
+if (positive)
+ {@+xn_over_d=u;rem=v%d;
+ }
+else{@+xn_over_d=-u;rem=-(v%d);
+ }
+return xn_over_d;}
+
+@ The next subroutine is used to compute the ``badness'' of glue, when a
+total~|t| is supposed to be made from amounts that sum to~|s|. According
+to {\sl The \TeX book}, the badness of this situation is $100(t/s)^3$;
+however, badness is simply a heuristic, so we need not squeeze out the
+last drop of accuracy when computing it. All we really want is an
+approximation that has similar properties.
+@:TeXbook}{\sl The \TeX book@>
+
+The actual method used to compute the badness is easier to read from the
+program than to describe in words. It produces an integer value that is a
+reasonably close approximation to $100(t/s)^3$, and all implementations
+of \TeX\ should use precisely this method. Any badness of $2^{13}$ or more is
+treated as infinitely bad, and represented by 10000.
+
+It is not difficult to prove that $$\hbox{|badness(t+1, s) >= badness(t, s)
+ >= badness(t, s+1)|}.$$ The badness function defined here is capable of
+computing at most 1095 distinct values, but that is plenty.
+
+@d inf_bad 10000 /*infinitely bad value*/
+
+@p halfword badness(scaled @!t, scaled @!s) /*compute badness, given |t >= 0|*/
+{@+int r; /*approximation to $\alpha t/s$, where $\alpha^3\approx
+ 100\cdot2^{18}$*/
+if (t==0) return 0;
+else if (s <= 0) return inf_bad;
+else{@+if (t <= 7230584) r=(t*297)/s; /*$297^3=99.94\times2^{18}$*/
+ else if (s >= 1663497) r=t/(s/297);
+ else r=t;
+ if (r > 1290) return inf_bad; /*$1290^3<2^{31}<1291^3$*/
+ else return(r*r*r+0400000)/01000000;
+ } /*that was $r^3/2^{18}$, rounded to the nearest integer*/
+}
+
+@ 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.)
+@^system dependencies@>
+
+@d set_glue_ratio_zero(X) X=0.0 /*store the representation of zero ratio*/
+@d set_glue_ratio_one(X) X=1.0 /*store the representation of unit ratio*/
+@d float(X) ((double)(X)) /*convert from |glue_ratio| to type |double|*/
+@d unfloat(X) ((glue_ratio)(X)) /*convert from |double| to type |glue_ratio|*/
+@d float_constant(X) ((double)(X)) /*convert |int| constant to |double|*/
+
+@<Types...@>=
+typedef float32_t @!glue_ratio; /*one-word representation of a glue expansion factor*/
+
+@* 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.
+@^system dependencies@>
+But it doesn't hurt to have more bits; for example, with enough 36-bit
+words you might be able to have |mem_max| as large as 262142, which is
+eight times as much memory as anybody had during the first four years of
+\TeX's existence.
+
+N.B.: Valuable memory space will be dreadfully wasted unless \TeX\ is compiled
+by a \PASCAL\ that packs all of the |memory_word| variants into
+the space of a single integer. This means, for example, that |glue_ratio|
+words should be |short_real| instead of |double| on some computers. Some
+\PASCAL\ compilers will pack an integer whose subrange is `|0 dotdot 255|' into
+an eight-bit field, but others insist on allocating space for an additional
+sign bit; on such systems you can get 256 values into a quarterword only
+if the subrange is `|-128 dotdot 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==min_halfword==0|,
+so one should try to achieve this unless it causes a severe problem.
+The values defined here are recommended for most 32-bit computers.
+
+@d min_quarterword 0 /*smallest allowable value in a |quarterword|*/
+@d max_quarterword 255 /*largest allowable value in a |quarterword|*/
+@d min_halfword 0 /*smallest allowable value in a |halfword|*/
+@d max_halfword 65535 /*largest allowable value in a |halfword|*/
+
+@ Here are the inequalities that the quarterword and halfword values
+must satisfy (or rather, the inequalities that they mustn't satisfy):
+
+@<Check the ``constant''...@>=
+#ifdef @!INIT
+if ((mem_min!=mem_bot)||(mem_max!=mem_top)) bad=10;
+#endif
+@;@/
+if ((mem_min > mem_bot)||(mem_max < mem_top)) bad=10;
+if ((min_quarterword > 0)||(max_quarterword < 127)) bad=11;
+if ((min_halfword > 0)||(max_halfword < 32767)) bad=12;
+if ((min_quarterword < min_halfword)||@|
+ (max_quarterword > max_halfword)) bad=13;
+if ((mem_min < min_halfword)||(mem_max >= max_halfword)||@|
+ (mem_bot-mem_min > max_halfword+1)) bad=14;
+if ((font_base < min_quarterword)||(font_max > max_quarterword)) bad=15;
+if (font_max > font_base+256) bad=16;
+if ((save_size > max_halfword)||(max_strings > max_halfword)) bad=17;
+if (buf_size > max_halfword) bad=18;
+if (max_quarterword-min_quarterword < 255) bad=19;
+
+@ The operation of adding or subtracting |min_quarterword| occurs quite
+frequently in \TeX, so it is convenient to abbreviate this operation
+by using the macros |qi| and |qo| for input and output to and from
+quarterword format.
+
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `|x+0|' and `|x-0|', if these
+macros are simplified in the obvious way when |min_quarterword==0|.
+@^inner loop@>@^system dependencies@>
+
+@d qi(X) X+min_quarterword
+ /*to put an |eight_bits| item into a quarterword*/
+@d qo(X) X-min_quarterword
+ /*to take an |eight_bits| item out of a quarterword*/
+@d hi(X) X+min_halfword
+ /*to put a sixteen-bit item into a halfword*/
+@d ho(X) X-min_halfword
+ /*to take a sixteen-bit item from a halfword*/
+
+@ The reader should study the following definitions closely:
+@^system dependencies@>
+
+@d sc i /*|scaled| data is equivalent to |int|*/
+
+@<Types...@>=
+typedef uint8_t quarterword; /*1/4 of a word*/
+typedef uint16_t halfword; /*1/2 of a word*/
+typedef uint8_t two_choices; /*used when there are two variants in a record*/
+typedef uint8_t four_choices; /*used when there are four variants in a record*/
+typedef struct { @;@/
+ halfword @!rh;
+ union {
+ halfword @!lh;
+ struct { quarterword @!b0;quarterword @!b1;} ;
+ };} two_halves;
+typedef struct { @;@/
+ quarterword @!b0;
+ quarterword @!b1;
+ quarterword @!b2;
+ quarterword @!b3;
+ } four_quarters;
+typedef struct { @;@/
+ union {
+ int @!i;
+ glue_ratio @!gr;
+ two_halves @!hh;
+ four_quarters @!qqqq;
+ };} memory_word;
+typedef struct {@+FILE *f;@+memory_word@,d;@+} word_file;
+
+@ When debugging, we may want to print a |memory_word| without knowing
+what type it is; so we print it in all modes.
+@^dirty \PASCAL@>@^debugging@>
+
+@p
+#ifdef @!DEBUG
+void print_word(memory_word @!w)
+ /*prints |w| in all ways*/
+{@+print_int(w.i);print_char(' ');@/
+print_scaled(w.sc);print_char(' ');@/
+print_scaled(round(unity*float(w.gr)));print_ln();@/
+@^real multiplication@>
+print_int(w.hh.lh);print_char('=');print_int(w.hh.b0);print_char(':');
+print_int(w.hh.b1);print_char(';');print_int(w.hh.rh);print_char(' ');@/
+print_int(w.qqqq.b0);print_char(':');print_int(w.qqqq.b1);print_char(':');
+print_int(w.qqqq.b2);print_char(':');print_int(w.qqqq.b3);
+}
+#endif
+
+@* Dynamic memory allocation.
+The \TeX\ system does nearly all of its own memory allocation, so that it
+can readily be transported into environments that do not have automatic
+facilities for strings, garbage collection, etc., and so that it can be in
+control of what error messages the user receives. The dynamic storage
+requirements of \TeX\ are handled by providing a large array |mem| in
+which consecutive blocks of words are used as nodes by the \TeX\ routines.
+
+Pointer variables are indices into this array, or into another array
+called |eqtb| that will be explained later. A pointer variable might
+also be a special flag that lies outside the bounds of |mem|, so we
+allow pointers to assume any |halfword| value. The minimum halfword
+value represents a null pointer. \TeX\ does not assume that |mem[null]| exists.
+
+@d pointer halfword /*a flag or a location in |mem| or |eqtb|*/
+@s pointer int
+@d null min_halfword /*the null pointer*/
+
+@<Glob...@>=
+pointer @!temp_ptr; /*a pointer variable for occasional emergency use*/
+
+@ The |mem| array is divided into two regions that are allocated separately,
+but the dividing line between these two regions is not fixed; they grow
+together until finding their ``natural'' size in a particular job.
+Locations less than or equal to |lo_mem_max| are used for storing
+variable-length records consisting of two or more words each. This region
+is maintained using an algorithm similar to the one described in exercise
+2.5--19 of {\sl The Art of Computer Programming}. However, no size field
+appears in the allocated nodes; the program is responsible for knowing the
+relevant size when a node is freed. Locations greater than or equal to
+|hi_mem_min| are used for storing one-word records; a conventional
+\.{AVAIL} stack is used for allocation in this region.
+
+Locations of |mem| between |mem_bot| and |mem_top| may be dumped as part
+of preloaded format files, by the \.{INITEX} preprocessor.
+@.INITEX@>
+Production versions of \TeX\ may extend the memory at both ends in order to
+provide more space; locations between |mem_min| and |mem_bot| are always
+used for variable-size nodes, and locations between |mem_top| and |mem_max|
+are always used for single-word nodes.
+
+The key pointers that govern |mem| allocation have a prescribed order:
+$$\advance\thickmuskip-2mu
+\hbox{|null <= mem_min <= mem_bot < lo_mem_max <
+ hi_mem_min < mem_top <= mem_end <= mem_max|.}$$
+
+Empirical tests show that the present implementation of \TeX\ tends to
+spend about 9\pct! of its running time allocating nodes, and about 6\pct!
+deallocating them after their use.
+
+@<Glob...@>=
+memory_word @!mem0[mem_max-mem_min+1], *const @!mem = @!mem0-mem_min; /*the big dynamic storage area*/
+pointer @!lo_mem_max; /*the largest location of variable-size memory in use*/
+pointer @!hi_mem_min; /*the smallest location of one-word memory in use*/
+
+@ In order to study the memory requirements of particular applications, it
+is possible to prepare a version of \TeX\ that keeps track of current and
+maximum memory usage. When code between the delimiters |
+#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.
+
+@<Glob...@>=
+int @!var_used, @!dyn_used; /*how much memory is in use*/
+#ifdef @!DEBUG
+#define incr_dyn_used @[incr(dyn_used)@]
+#define decr_dyn_used @[decr(dyn_used)@]
+#else
+#define incr_dyn_used
+#define decr_dyn_used
+#endif
+
+@ Let's consider the one-word memory region first, since it's the
+simplest. The pointer variable |mem_end| holds the highest-numbered location
+of |mem| that has ever been used. The free locations of |mem| that
+occur between |hi_mem_min| and |mem_end|, inclusive, are of type
+|two_halves|, and we write |info(p)| and |link(p)| for the |lh|
+and |rh| fields of |mem[p]| when it is of this type. The single-word
+free locations form a linked list
+$$|avail|,\;\hbox{|link(avail)|},\;\hbox{|link(link(avail))|},\;\ldots$$
+terminated by |null|.
+
+@d link(X) mem[X].hh.rh /*the |link| field of a memory word*/
+@d info(X) mem[X].hh.lh /*the |info| field of a memory word*/
+
+@<Glob...@>=
+pointer @!avail; /*head of the list of available one-word nodes*/
+pointer @!mem_end; /*the last one-word node used in |mem|*/
+
+@ If memory is exhausted, it might mean that the user has forgotten
+a right brace. We will define some procedures later that try to help
+pinpoint the trouble.
+
+@p@<Declare the procedure called |show_token_list|@>@;
+@<Declare the procedure called |runaway|@>@;
+
+@ The function |get_avail| returns a pointer to a new one-word node whose
+|link| field is null. However, \TeX\ will halt if there is no more room left.
+@^inner loop@>
+
+If the available-space list is empty, i.e., if |avail==null|,
+we try first to increase |mem_end|. If that cannot be done, i.e., if
+|mem_end==mem_max|, we try to decrease |hi_mem_min|. If that cannot be
+done, i.e., if |hi_mem_min==lo_mem_max+1|, we have to quit.
+
+@p pointer get_avail(void) /*single-word node allocation*/
+{@+pointer p; /*the new node being got*/
+p=avail; /*get top location in the |avail| stack*/
+if (p!=null) avail=link(avail); /*and pop it off*/
+else if (mem_end < mem_max) /*or go into virgin territory*/
+ {@+incr(mem_end);p=mem_end;
+ }
+else{@+decr(hi_mem_min);p=hi_mem_min;
+ if (hi_mem_min <= lo_mem_max)
+ {@+runaway(); /*if memory is exhausted, display possible runaway text*/
+ overflow("main memory size", mem_max+1-mem_min);
+ /*quit; all one-word nodes are busy*/
+@:TeX capacity exceeded main memory size}{\quad main memory size@>
+ }
+ }
+link(p)=null; /*provide an oft-desired initialization of the new node*/
+incr_dyn_used; /*maintain statistics*/
+return p;
+}
+
+@ Conversely, a one-word node is recycled by calling |free_avail|.
+This routine is part of \TeX's ``inner loop,'' so we want it to be fast.
+@^inner loop@>
+
+@d free_avail(X) /*single-word node liberation*/
+ {@+link(X)=avail;avail=X;
+ decr_dyn_used;
+ }
+
+@ There's also a |fast_get_avail| routine, which saves the procedure-call
+overhead at the expense of extra programming. This routine is used in
+the places that would otherwise account for the most calls of |get_avail|.
+@^inner loop@>
+
+@d fast_get_avail(X) @t@>@;@/
+ {@+X=avail; /*avoid |get_avail| if possible, to save time*/
+ if (X==null) X=get_avail();
+ else{@+avail=link(X);link(X)=null;
+ incr_dyn_used;
+ }
+ }
+
+@ The procedure |flush_list(p)| frees an entire linked list of
+one-word nodes that starts at position |p|.
+@^inner loop@>
+
+@p void flush_list(pointer @!p) /*makes list of single-word nodes
+ available*/
+{@+pointer @!q, @!r; /*list traversers*/
+if (p!=null)
+ {@+r=p;
+ @/do@+{q=r;r=link(r);
+ decr_dyn_used;
+ }@+ while (!(r==null)); /*now |q| is the last node on the list*/
+ link(q)=avail;avail=p;
+ }
+}
+
+@ The available-space list that keeps track of the variable-size portion
+of |mem| is a nonempty, doubly-linked circular list of empty nodes,
+pointed to by the roving pointer |rover|.
+
+Each empty node has size 2 or more; the first word contains the special
+value |max_halfword| in its |link| field and the size in its |info| field;
+the second word contains the two pointers for double linking.
+
+Each nonempty node also has size 2 or more. Its first word is of type
+|two_halves|\kern-1pt, and its |link| field is never equal to |max_halfword|.
+Otherwise there is complete flexibility with respect to the contents
+of its other fields and its other words.
+
+(We require |mem_max < max_halfword| because terrible things can happen
+when |max_halfword| appears in the |link| field of a nonempty node.)
+
+@d empty_flag max_halfword /*the |link| of an empty variable-size node*/
+@d is_empty(X) (link(X)==empty_flag) /*tests for empty node*/
+@d node_size info /*the size field in empty variable-size nodes*/
+@d llink(X) info(X+1) /*left link in doubly-linked list of empty nodes*/
+@d rlink(X) link(X+1) /*right link in doubly-linked list of empty nodes*/
+
+@<Glob...@>=
+pointer @!rover; /*points to some node in the list of empties*/
+
+@ A call to |get_node| with argument |s| returns a pointer to a new node
+of size~|s|, which must be 2~or more. The |link| field of the first word
+of this new node is set to null. An overflow stop occurs if no suitable
+space exists.
+
+If |get_node| is called with $s=2^{30}$, it simply merges adjacent free
+areas and returns the value |max_halfword|.
+
+@p pointer get_node(int @!s) /*variable-size node allocation*/
+{@+
+pointer p; /*the node currently under inspection*/
+pointer @!q; /*the node physically after node |p|*/
+int @!r; /*the newly allocated node, or a candidate for this honor*/
+int @!t; /*temporary register*/
+restart: p=rover; /*start at some free node in the ring*/
+@/do@+{@<Try to allocate within node |p| and its physical successors, and |goto found|
+if allocation was possible@>;
+@^inner loop@>
+p=rlink(p); /*move to the next node in the ring*/
+}@+ while (!(p==rover)); /*repeat until the whole list has been traversed*/
+if (s==010000000000)
+ {@+return max_halfword;
+ }
+if (lo_mem_max+2 < hi_mem_min) if (lo_mem_max+2 <= mem_bot+max_halfword)
+ @<Grow more variable-size memory and |goto restart|@>;
+overflow("main memory size", mem_max+1-mem_min);
+ /*sorry, nothing satisfactory is left*/
+@:TeX capacity exceeded main memory size}{\quad main memory size@>
+found: link(r)=null; /*this node is now nonempty*/
+#ifdef @!STAT
+var_used=var_used+s; /*maintain usage statistics*/
+#endif
+@;@/
+return r;
+}
+
+@ The lower part of |mem| grows by 1000 words at a time, unless
+we are very close to going under. When it grows, we simply link
+a new node into the available-space list. This method of controlled
+growth helps to keep the |mem| usage consecutive when \TeX\ is
+implemented on ``virtual memory'' systems.
+@^virtual memory@>
+
+@<Grow more variable-size memory and |goto restart|@>=
+{@+if (hi_mem_min-lo_mem_max >= 1998) t=lo_mem_max+1000;
+else t=lo_mem_max+1+(hi_mem_min-lo_mem_max)/2;
+ /*|lo_mem_max+2 <= t < hi_mem_min|*/
+p=llink(rover);q=lo_mem_max;rlink(p)=q;llink(rover)=q;@/
+if (t > mem_bot+max_halfword) t=mem_bot+max_halfword;
+rlink(q)=rover;llink(q)=p;link(q)=empty_flag;node_size(q)=t-lo_mem_max;@/
+lo_mem_max=t;link(lo_mem_max)=null;info(lo_mem_max)=null;
+rover=q;goto restart;
+}
+
+@ Empirical tests show that the routine in this section performs a
+node-merging operation about 0.75 times per allocation, on the average,
+after which it finds that |r > p+1| about 95\pct! of the time.
+
+@<Try to allocate...@>=
+q=p+node_size(p); /*find the physical successor*/
+@^inner loop@>
+while (is_empty(q)) /*merge node |p| with node |q|*/
+ {@+t=rlink(q);
+ if (q==rover) rover=t;
+ llink(t)=llink(q);rlink(llink(q))=t;@/
+ q=q+node_size(q);
+ }
+r=q-s;
+if (r > p+1) @<Allocate from the top of node |p| and |goto found|@>;
+if (r==p) if (rlink(p)!=p)
+ @<Allocate entire node |p| and |goto found|@>;
+node_size(p)=q-p /*reset the size in case it grew*/
+
+@ @<Allocate from the top...@>=
+{@+node_size(p)=r-p; /*store the remaining size*/
+@^inner loop@>
+rover=p; /*start searching here next time*/
+goto found;
+}
+
+@ Here we delete node |p| from the ring, and let |rover| rove around.
+
+@<Allocate entire...@>=
+{@+rover=rlink(p);t=llink(p);
+llink(rover)=t;rlink(t)=rover;
+goto found;
+}
+
+@ Conversely, when some variable-size node |p| of size |s| is no longer needed,
+the operation |free_node(p, s)| will make its words available, by inserting
+|p| as a new empty node just before where |rover| now points.
+@^inner loop@>
+
+@p void free_node(pointer @!p, halfword @!s) /*variable-size node
+ liberation*/
+{@+pointer q; /*|llink(rover)|*/
+node_size(p)=s;link(p)=empty_flag;
+q=llink(rover);llink(p)=q;rlink(p)=rover; /*set both links*/
+llink(rover)=p;rlink(q)=p; /*insert |p| into the ring*/
+#ifdef @!STAT
+var_used=var_used-s;
+#endif
+@; /*maintain statistics*/
+}
+
+@ Just before \.{INITEX} writes out the memory, it sorts the doubly linked
+available space list. The list is probably very short at such times, so a
+simple insertion sort is used. The smallest available location will be
+pointed to by |rover|, the next-smallest by |rlink(rover)|, etc.
+
+@p
+#ifdef @!INIT
+void sort_avail(void) /*sorts the available variable-size nodes
+ by location*/
+{@+pointer p, @!q, @!r; /*indices into |mem|*/
+pointer @!old_rover; /*initial |rover| setting*/
+p=get_node(010000000000); /*merge adjacent free areas*/
+p=rlink(rover);rlink(rover)=max_halfword;old_rover=rover;
+while (p!=old_rover) @<Sort \(p)|p| into the list starting at |rover| and advance
+|p| to |rlink(p)|@>;
+p=rover;
+while (rlink(p)!=max_halfword)
+ {@+llink(rlink(p))=p;p=rlink(p);
+ }
+rlink(p)=rover;llink(rover)=p;
+}
+#endif
+
+@ The following |while | loop is guaranteed to
+terminate, since the list that starts at
+|rover| ends with |max_halfword| during the sorting procedure.
+
+@<Sort \(p)|p|...@>=
+if (p < rover)
+ {@+q=p;p=rlink(q);rlink(q)=rover;rover=q;
+ }
+else{@+q=rover;
+ while (rlink(q) < p) q=rlink(q);
+ r=rlink(p);rlink(p)=rlink(q);rlink(q)=p;p=r;
+ }
+
+@* Data structures for boxes and their friends.
+From the computer's standpoint, \TeX's chief mission is to create
+horizontal and vertical lists. We shall now investigate how the elements
+of these lists are represented internally as nodes in the dynamic memory.
+
+A horizontal or vertical list is linked together by |link| fields in
+the first word of each node. Individual nodes represent boxes, glue,
+penalties, or special things like discretionary hyphens; because of this
+variety, some nodes are longer than others, and we must distinguish different
+kinds of nodes. We do this by putting a `|type|' field in the first word,
+together with the link and an optional `|subtype|'.
+
+@d type(X) mem[X].hh.b0 /*identifies what kind of node this is*/
+@d subtype(X) mem[X].hh.b1 /*secondary identification in some cases*/
+
+@ A |@!char_node|, which represents a single character, is the most important
+kind of node because it accounts for the vast majority of all boxes.
+Special precautions are therefore taken to ensure that a |char_node| does
+not take up much memory space. Every such node is one word long, and in fact
+it is identifiable by this property, since other kinds of nodes have at least
+two words, and they appear in |mem| locations less than |hi_mem_min|.
+This makes it possible to omit the |type| field in a |char_node|, leaving
+us room for two bytes that identify a |font| and a |character| within
+that font.
+
+Note that the format of a |char_node| allows for up to 256 different
+fonts and up to 256 characters per font; but most implementations will
+probably limit the total number of fonts to fewer than 75 per job,
+and most fonts will stick to characters whose codes are
+less than 128 (since higher codes
+are more difficult to access on most keyboards).
+
+Extensions of \TeX\ intended for oriental languages will need even more
+than $256\times256$ possible characters, when we consider different sizes
+@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
+and styles of type. It is suggested that Chinese and Japanese fonts be
+handled by representing such characters in two consecutive |char_node|
+entries: The first of these has |font==font_base|, and its |link| points
+to the second;
+the second identifies the font and the character dimensions.
+The saving feature about oriental characters is that most of them have
+the same box dimensions. The |character| field of the first |char_node|
+is a ``\\{charext}'' that distinguishes between graphic symbols whose
+dimensions are identical for typesetting purposes. (See the \MF\ manual.)
+Such an extension of \TeX\ would not be difficult; further details are
+left to the reader.
+
+In order to make sure that the |character| code fits in a quarterword,
+\TeX\ adds the quantity |min_quarterword| to the actual code.
+
+Character nodes appear only in horizontal lists, never in vertical lists.
+
+@d is_char_node(X) (X >= hi_mem_min)
+ /*does the argument point to a |char_node|?*/
+@d font type /*the font code in a |char_node|*/
+@d character subtype /*the character code in a |char_node|*/
+
+@ An |hlist_node| stands for a box that was made from a horizontal list.
+Each |hlist_node| is seven words long, and contains the following fields
+(in addition to the mandatory |type| and |link|, which we shall not
+mention explicitly when discussing the other node types): The |height| and
+|width| and |depth| are scaled integers denoting the dimensions of the
+box. There is also a |shift_amount| field, a scaled integer indicating
+how much this box should be lowered (if it appears in a horizontal list),
+or how much it should be moved to the right (if it appears in a vertical
+list). There is a |list_ptr| field, which points to the beginning of the
+list from which this box was fabricated; if |list_ptr| is |null|, the box
+is empty. Finally, there are three fields that represent the setting of
+the glue: |glue_set(p)| is a word of type |glue_ratio| that represents
+the proportionality constant for glue setting; |glue_sign(p)| is
+|stretching| or |shrinking| or |normal| depending on whether or not the
+glue should stretch or shrink or remain rigid; and |glue_order(p)|
+specifies the order of infinity to which glue setting applies (|normal|,
+|fil|, |fill|, or |filll|). The |subtype| field is not used.
+
+@d hlist_node 0 /*|type| of hlist nodes*/
+@d box_node_size 7 /*number of words to allocate for a box node*/
+@d width_offset 1 /*position of |width| field in a box node*/
+@d depth_offset 2 /*position of |depth| field in a box node*/
+@d height_offset 3 /*position of |height| field in a box node*/
+@d width(X) mem[X+width_offset].sc /*width of the box, in sp*/
+@d depth(X) mem[X+depth_offset].sc /*depth of the box, in sp*/
+@d height(X) mem[X+height_offset].sc /*height of the box, in sp*/
+@d shift_amount(X) mem[X+4].sc /*repositioning distance, in sp*/
+@d list_offset 5 /*position of |list_ptr| field in a box node*/
+@d list_ptr(X) link(X+list_offset) /*beginning of the list inside the box*/
+@d glue_order(X) subtype(X+list_offset) /*applicable order of infinity*/
+@d glue_sign(X) type(X+list_offset) /*stretching or shrinking*/
+@d normal 0 /*the most common case when several cases are named*/
+@d stretching 1 /*glue setting applies to the stretch components*/
+@d shrinking 2 /*glue setting applies to the shrink components*/
+@d glue_offset 6 /*position of |glue_set| in a box node*/
+@d glue_set(X) mem[X+glue_offset].gr
+ /*a word of type |glue_ratio| for glue setting*/
+
+@ The |new_null_box| function returns a pointer to an |hlist_node| in
+which all subfields have the values corresponding to `\.{\\hbox\{\}}'.
+The |subtype| field is set to |min_quarterword|, since that's the desired
+|span_count| value if this |hlist_node| is changed to an |unset_node|.
+
+@p pointer new_null_box(void) /*creates a new box node*/
+{@+pointer p; /*the new node*/
+p=get_node(box_node_size);type(p)=hlist_node;
+subtype(p)=min_quarterword;
+width(p)=0;depth(p)=0;height(p)=0;shift_amount(p)=0;list_ptr(p)=null;
+glue_sign(p)=normal;glue_order(p)=normal;set_glue_ratio_zero(glue_set(p));
+return p;
+}
+
+@ A |vlist_node| is like an |hlist_node| in all respects except that it
+contains a vertical list.
+
+@d vlist_node 1 /*|type| of vlist nodes*/
+
+@ A |rule_node| stands for a solid black rectangle; it has |width|,
+|depth|, and |height| fields just as in an |hlist_node|. However, if
+any of these dimensions is $-2^{30}$, the actual value will be determined
+by running the rule up to the boundary of the innermost enclosing box.
+This is called a ``running dimension.'' The |width| is never running in
+an hlist; the |height| and |depth| are never running in a~vlist.
+
+@d rule_node 2 /*|type| of rule nodes*/
+@d rule_node_size 4 /*number of words to allocate for a rule node*/
+@d null_flag -010000000000 /*$-2^{30}$, signifies a missing item*/
+@d is_running(X) (X==null_flag) /*tests for a running dimension*/
+
+@ A new rule node is delivered by the |new_rule| function. It
+makes all the dimensions ``running,'' so you have to change the
+ones that are not allowed to run.
+
+@p pointer new_rule(void)
+{@+pointer p; /*the new node*/
+p=get_node(rule_node_size);type(p)=rule_node;
+subtype(p)=0; /*the |subtype| is not used*/
+width(p)=null_flag;depth(p)=null_flag;height(p)=null_flag;
+return p;
+}
+
+@ Insertions are represented by |ins_node| records, where the |subtype|
+indicates the corresponding box number. For example, `\.{\\insert 250}'
+leads to an |ins_node| whose |subtype| is |250+min_quarterword|.
+The |height| field of an |ins_node| is slightly misnamed; it actually holds
+the natural height plus depth of the vertical list being inserted.
+The |depth| field holds the |split_max_depth| to be used in case this
+insertion is split, and the |split_top_ptr| points to the corresponding
+|split_top_skip|. The |float_cost| field holds the |floating_penalty| that
+will be used if this insertion floats to a subsequent page after a
+split insertion of the same class. There is one more field, the
+|ins_ptr|, which points to the beginning of the vlist for the insertion.
+
+@d ins_node 3 /*|type| of insertion nodes*/
+@d ins_node_size 5 /*number of words to allocate for an insertion*/
+@d float_cost(X) mem[X+1].i /*the |floating_penalty| to be used*/
+@d ins_ptr(X) info(X+4) /*the vertical list to be inserted*/
+@d split_top_ptr(X) link(X+4) /*the |split_top_skip| to be used*/
+
+@ A |mark_node| has a |mark_ptr| field that points to the reference count
+of a token list that contains the user's \.{\\mark} text.
+This field occupies a full word instead of a halfword, because
+there's nothing to put in the other halfword; it is easier in \PASCAL\ to
+use the full word than to risk leaving garbage in the unused half.
+
+@d mark_node 4 /*|type| of a mark node*/
+@d small_node_size 2 /*number of words to allocate for most node types*/
+@d mark_ptr(X) mem[X+1].i /*head of the token list for a mark*/
+
+@ An |adjust_node|, which occurs only in horizontal lists,
+specifies material that will be moved out into the surrounding
+vertical list; i.e., it is used to implement \TeX's `\.{\\vadjust}'
+operation. The |adjust_ptr| field points to the vlist containing this
+material.
+
+@d adjust_node 5 /*|type| of an adjust node*/
+@d adjust_ptr mark_ptr /*vertical list to be moved out of horizontal list*/
+
+@ A |ligature_node|, which occurs only in horizontal lists, specifies
+a character that was fabricated from the interaction of two or more
+actual characters. The second word of the node, which is called the
+|lig_char| word, contains |font| and |character| fields just as in a
+|char_node|. The characters that generated the ligature have not been
+forgotten, since they are needed for diagnostic messages and for
+hyphenation; the |lig_ptr| field points to a linked list of character
+nodes for all original characters that have been deleted. (This list
+might be empty if the characters that generated the ligature were
+retained in other nodes.)
+
+The |subtype| field is 0, plus 2 and/or 1 if the original source of the
+ligature included implicit left and/or right boundaries.
+
+@d ligature_node 6 /*|type| of a ligature node*/
+@d lig_char(X) X+1 /*the word where the ligature is to be found*/
+@d lig_ptr(X) link(lig_char(X)) /*the list of characters*/
+
+@ The |new_ligature| function creates a ligature node having given
+contents of the |font|, |character|, and |lig_ptr| fields. We also have
+a |new_lig_item| function, which returns a two-word node having a given
+|character| field. Such nodes are used for temporary processing as ligatures
+are being created.
+
+@p pointer new_ligature(quarterword @!f, quarterword @!c, pointer @!q)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=ligature_node;
+font(lig_char(p))=f;character(lig_char(p))=c;lig_ptr(p)=q;
+subtype(p)=0;return p;
+}
+@#
+pointer new_lig_item(quarterword @!c)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);character(p)=c;lig_ptr(p)=null;
+return p;
+}
+
+@ A |disc_node|, which occurs only in horizontal lists, specifies a
+``dis\-cretion\-ary'' line break. If such a break occurs at node |p|, the text
+that starts at |pre_break(p)| will precede the break, the text that starts at
+|post_break(p)| will follow the break, and text that appears in the next
+|replace_count(p)| nodes will be ignored. For example, an ordinary
+discretionary hyphen, indicated by `\.{\\-}', yields a |disc_node| with
+|pre_break| pointing to a |char_node| containing a hyphen, |post_break==null|,
+and |replace_count==0|. All three of the discretionary texts must be
+lists that consist entirely of character, kern, box, rule, and ligature nodes.
+
+If |pre_break(p)==null|, the |ex_hyphen_penalty| will be charged for this
+break. Otherwise the |hyphen_penalty| will be charged. The texts will
+actually be substituted into the list by the line-breaking algorithm if it
+decides to make the break, and the discretionary node will disappear at
+that time; thus, the output routine sees only discretionaries that were
+not chosen.
+
+@d disc_node 7 /*|type| of a discretionary node*/
+@d replace_count subtype /*how many subsequent nodes to replace*/
+@d pre_break llink /*text that precedes a discretionary break*/
+@d post_break rlink /*text that follows a discretionary break*/
+
+@p pointer new_disc(void) /*creates an empty |disc_node|*/
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=disc_node;
+replace_count(p)=0;pre_break(p)=null;post_break(p)=null;
+return p;
+}
+
+@ A |whatsit_node| is a wild card reserved for extensions to \TeX. The
+|subtype| field in its first word says what `\\{whatsit}' it is, and
+implicitly determines the node size (which must be 2 or more) and the
+format of the remaining words. When a |whatsit_node| is encountered
+in a list, special actions are invoked; knowledgeable people who are
+careful not to mess up the rest of \TeX\ are able to make \TeX\ do new
+things by adding code at the end of the program. For example, there
+might be a `\TeX nicolor' extension to specify different colors of ink,
+@^extensions to \TeX@>
+and the whatsit node might contain the desired parameters.
+
+The present implementation of \TeX\ treats the features associated with
+`\.{\\write}' and `\.{\\special}' as if they were extensions, in order to
+illustrate how such routines might be coded. We shall defer further
+discussion of extensions until the end of this program.
+
+@d whatsit_node 8 /*|type| of special extension nodes*/
+
+@ A |math_node|, which occurs only in horizontal lists, appears before and
+after mathematical formulas. The |subtype| field is |before| before the
+formula and |after| after it. There is a |width| field, which represents
+the amount of surrounding space inserted by \.{\\mathsurround}.
+
+@d math_node 9 /*|type| of a math node*/
+@d before 0 /*|subtype| for math node that introduces a formula*/
+@d after 1 /*|subtype| for math node that winds up a formula*/
+
+@p pointer new_math(scaled @!w, small_number @!s)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=math_node;
+subtype(p)=s;width(p)=w;return p;
+}
+
+@ \TeX\ makes use of the fact that |hlist_node|, |vlist_node|,
+|rule_node|, |ins_node|, |mark_node|, |adjust_node|, |ligature_node|,
+|disc_node|, |whatsit_node|, and |math_node| are at the low end of the
+type codes, by permitting a break at glue in a list if and only if the
+|type| of the previous node is less than |math_node|. Furthermore, a
+node is discarded after a break if its type is |math_node| or~more.
+
+@d precedes_break(X) (type(X) < math_node)
+@d non_discardable(X) (type(X) < math_node)
+
+@ A |glue_node| represents glue in a list. However, it is really only
+a pointer to a separate glue specification, since \TeX\ makes use of the
+fact that many essentially identical nodes of glue are usually present.
+If |p| points to a |glue_node|, |glue_ptr(p)| points to
+another packet of words that specify the stretch and shrink components, etc.
+
+Glue nodes also serve to represent leaders; the |subtype| is used to
+distinguish between ordinary glue (which is called |normal|) and the three
+kinds of leaders (which are called |a_leaders|, |c_leaders|, and |x_leaders|).
+The |leader_ptr| field points to a rule node or to a box node containing the
+leaders; it is set to |null| in ordinary glue nodes.
+
+Many kinds of glue are computed from \TeX's ``skip'' parameters, and
+it is helpful to know which parameter has led to a particular glue node.
+Therefore the |subtype| is set to indicate the source of glue, whenever
+it originated as a parameter. We will be defining symbolic names for the
+parameter numbers later (e.g., |line_skip_code==0|, |baseline_skip_code==1|,
+etc.); it suffices for now to say that the |subtype| of parametric glue
+will be the same as the parameter number, plus~one.
+
+In math formulas there are two more possibilities for the |subtype| in a
+glue node: |mu_glue| denotes an \.{\\mskip} (where the units are scaled \.{mu}
+instead of scaled \.{pt}); and |cond_math_glue| denotes the `\.{\\nonscript}'
+feature that cancels the glue node immediately following if it appears
+in a subscript.
+
+@d glue_node 10 /*|type| of node that points to a glue specification*/
+@d cond_math_glue 98 /*special |subtype| to suppress glue in the next node*/
+@d mu_glue 99 /*|subtype| for math glue*/
+@d a_leaders 100 /*|subtype| for aligned leaders*/
+@d c_leaders 101 /*|subtype| for centered leaders*/
+@d x_leaders 102 /*|subtype| for expanded leaders*/
+@d glue_ptr llink /*pointer to a glue specification*/
+@d leader_ptr rlink /*pointer to box or rule node for leaders*/
+
+@ A glue specification has a halfword reference count in its first word,
+@^reference counts@>
+representing |null| plus the number of glue nodes that point to it (less one).
+Note that the reference count appears in the same position as
+the |link| field in list nodes; this is the field that is initialized
+to |null| when a node is allocated, and it is also the field that is flagged
+by |empty_flag| in empty nodes.
+
+Glue specifications also contain three |scaled| fields, for the |width|,
+|stretch|, and |shrink| dimensions. Finally, there are two one-byte
+fields called |stretch_order| and |shrink_order|; these contain the
+orders of infinity (|normal|, |fil|, |fill|, or |filll|)
+corresponding to the stretch and shrink values.
+
+@d glue_spec_size 4 /*number of words to allocate for a glue specification*/
+@d glue_ref_count(X) link(X) /*reference count of a glue specification*/
+@d stretch(X) mem[X+2].sc /*the stretchability of this glob of glue*/
+@d shrink(X) mem[X+3].sc /*the shrinkability of this glob of glue*/
+@d stretch_order type /*order of infinity for stretching*/
+@d shrink_order subtype /*order of infinity for shrinking*/
+@d fil 1 /*first-order infinity*/
+@d fill 2 /*second-order infinity*/
+@d filll 3 /*third-order infinity*/
+
+@<Types...@>=
+typedef uint8_t glue_ord; /*infinity to the 0, 1, 2, or 3 power*/
+
+@ Here is a function that returns a pointer to a copy of a glue spec.
+The reference count in the copy is |null|, because there is assumed
+to be exactly one reference to the new specification.
+
+@p pointer new_spec(pointer @!p) /*duplicates a glue specification*/
+{@+pointer q; /*the new spec*/
+q=get_node(glue_spec_size);@/
+mem[q]=mem[p];glue_ref_count(q)=null;@/
+width(q)=width(p);stretch(q)=stretch(p);shrink(q)=shrink(p);
+return q;
+}
+
+@ And here's a function that creates a glue node for a given parameter
+identified by its code number; for example,
+|new_param_glue(line_skip_code)| returns a pointer to a glue node for the
+current \.{\\lineskip}.
+
+@p pointer new_param_glue(small_number @!n)
+{@+pointer p; /*the new node*/
+pointer @!q; /*the glue specification*/
+p=get_node(small_node_size);type(p)=glue_node;subtype(p)=n+1;
+leader_ptr(p)=null;@/
+q=@<Current |mem| equivalent of glue parameter number |n|@>@t@>;
+glue_ptr(p)=q;incr(glue_ref_count(q));
+return p;
+}
+
+@ Glue nodes that are more or less anonymous are created by |new_glue|,
+whose argument points to a glue specification.
+
+@p pointer new_glue(pointer @!q)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=glue_node;subtype(p)=normal;
+leader_ptr(p)=null;glue_ptr(p)=q;incr(glue_ref_count(q));
+return p;
+}
+
+@ Still another subroutine is needed: This one is sort of a combination
+of |new_param_glue| and |new_glue|. It creates a glue node for one of
+the current glue parameters, but it makes a fresh copy of the glue
+specification, since that specification will probably be subject to change,
+while the parameter will stay put. The global variable |temp_ptr| is
+set to the address of the new spec.
+
+@p pointer new_skip_param(small_number @!n)
+{@+pointer p; /*the new node*/
+temp_ptr=new_spec(@<Current |mem| equivalent of glue parameter...@>);
+p=new_glue(temp_ptr);glue_ref_count(temp_ptr)=null;subtype(p)=n+1;
+return p;
+}
+
+@ A |kern_node| has a |width| field to specify a (normally negative)
+amount of spacing. This spacing correction appears in horizontal lists
+between letters like A and V when the font designer said that it looks
+better to move them closer together or further apart. A kern node can
+also appear in a vertical list, when its `|width|' denotes additional
+spacing in the vertical direction. The |subtype| is either |normal| (for
+kerns inserted from font information or math mode calculations) or |explicit|
+(for kerns inserted from \.{\\kern} and \.{\\/} commands) or |acc_kern|
+(for kerns inserted from non-math accents) or |mu_glue| (for kerns
+inserted from \.{\\mkern} specifications in math formulas).
+
+@d kern_node 11 /*|type| of a kern node*/
+@d explicit 1 /*|subtype| of kern nodes from \.{\\kern} and \.{\\/}*/
+@d acc_kern 2 /*|subtype| of kern nodes from accents*/
+
+@ The |new_kern| function creates a kern node having a given width.
+
+@p pointer new_kern(scaled @!w)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=kern_node;
+subtype(p)=normal;
+width(p)=w;
+return p;
+}
+
+@ A |penalty_node| specifies the penalty associated with line or page
+breaking, in its |penalty| field. This field is a fullword integer, but
+the full range of integer values is not used: Any penalty | >= 10000| is
+treated as infinity, and no break will be allowed for such high values.
+Similarly, any penalty | <= -10000| is treated as negative infinity, and a
+break will be forced.
+
+@d penalty_node 12 /*|type| of a penalty node*/
+@d inf_penalty inf_bad /*``infinite'' penalty value*/
+@d eject_penalty (-inf_penalty) /*``negatively infinite'' penalty value*/
+@d penalty(X) mem[X+1].i /*the added cost of breaking a list here*/
+
+@ Anyone who has been reading the last few sections of the program will
+be able to guess what comes next.
+
+@p pointer new_penalty(int @!m)
+{@+pointer p; /*the new node*/
+p=get_node(small_node_size);type(p)=penalty_node;
+subtype(p)=0; /*the |subtype| is not used*/
+penalty(p)=m;return p;
+}
+
+@ You might think that we have introduced enough node types by now. Well,
+almost, but there is one more: An |unset_node| has nearly the same format
+as an |hlist_node| or |vlist_node|; it is used for entries in \.{\\halign}
+or \.{\\valign} that are not yet in their final form, since the box
+dimensions are their ``natural'' sizes before any glue adjustment has been
+made. The |glue_set| word is not present; instead, we have a |glue_stretch|
+field, which contains the total stretch of order |glue_order| that is
+present in the hlist or vlist being boxed.
+Similarly, the |shift_amount| field is replaced by a |glue_shrink| field,
+containing the total shrink of order |glue_sign| that is present.
+The |subtype| field is called |span_count|; an unset box typically
+contains the data for |qo(span_count)+1| columns.
+Unset nodes will be changed to box nodes when alignment is completed.
+
+@d unset_node 13 /*|type| for an unset node*/
+@d glue_stretch(X) mem[X+glue_offset].sc /*total stretch in an unset node*/
+@d glue_shrink shift_amount /*total shrink in an unset node*/
+@d span_count subtype /*indicates the number of spanned columns*/
+
+@ In fact, there are still more types coming. When we get to math formula
+processing we will see that a |style_node| has |type==14|; and a number
+of larger type codes will also be defined, for use in math mode only.
+
+@ Warning: If any changes are made to these data structure layouts, such as
+changing any of the node sizes or even reordering the words of nodes,
+the |copy_node_list| procedure and the memory initialization code
+below may have to be changed. Such potentially dangerous parts of the
+program are listed in the index under `data structure assumptions'.
+@!@^data structure assumptions@>
+However, other references to the nodes are made symbolically in terms of
+the \.{WEB} macro definitions above, so that format changes will leave
+\TeX's other algorithms intact.
+@^system dependencies@>
+
+@* Memory layout.
+Some areas of |mem| are dedicated to fixed usage, since static allocation is
+more efficient than dynamic allocation when we can get away with it. For
+example, locations |mem_bot| to |mem_bot+3| are always used to store the
+specification for glue that is `\.{0pt plus 0pt minus 0pt}'. The
+following macro definitions accomplish the static allocation by giving
+symbolic names to the fixed positions. Static variable-size nodes appear
+in locations |mem_bot| through |lo_mem_stat_max|, and static single-word nodes
+appear in locations |hi_mem_stat_min| through |mem_top|, inclusive. It is
+harmless to let |lig_trick| and |garbage| share the same location of |mem|.
+
+@d zero_glue mem_bot /*specification for \.{0pt plus 0pt minus 0pt}*/
+@d fil_glue zero_glue+glue_spec_size /*\.{0pt plus 1fil minus 0pt}*/
+@d fill_glue fil_glue+glue_spec_size /*\.{0pt plus 1fill minus 0pt}*/
+@d ss_glue fill_glue+glue_spec_size /*\.{0pt plus 1fil minus 1fil}*/
+@d fil_neg_glue ss_glue+glue_spec_size /*\.{0pt plus -1fil minus 0pt}*/
+@d lo_mem_stat_max fil_neg_glue+glue_spec_size-1 /*largest statically
+ allocated word in the variable-size |mem|*/
+@#
+@d page_ins_head mem_top /*list of insertion data for current page*/
+@d contrib_head mem_top-1 /*vlist of items not yet on current page*/
+@d page_head mem_top-2 /*vlist for current page*/
+@d temp_head mem_top-3 /*head of a temporary list of some kind*/
+@d hold_head mem_top-4 /*head of a temporary list of another kind*/
+@d adjust_head mem_top-5 /*head of adjustment list returned by |hpack|*/
+@d active mem_top-7 /*head of active list in |line_break|, needs two words*/
+@d align_head mem_top-8 /*head of preamble list for alignments*/
+@d end_span mem_top-9 /*tail of spanned-width lists*/
+@d omit_template mem_top-10 /*a constant token list*/
+@d null_list mem_top-11 /*permanently empty list*/
+@d lig_trick mem_top-12 /*a ligature masquerading as a |char_node|*/
+@d garbage mem_top-12 /*used for scrap information*/
+@d backup_head mem_top-13 /*head of token list built by |scan_keyword|*/
+@d hi_mem_stat_min mem_top-13 /*smallest statically allocated word in
+ the one-word |mem|*/
+@d hi_mem_stat_usage 14 /*the number of one-word nodes always present*/
+
+@ The following code gets |mem| off to a good start, when \TeX\ is
+initializing itself the slow~way.
+
+@<Local variables for init...@>=
+int @!k; /*index into |mem|, |eqtb|, etc.*/
+
+@ @<Initialize table entries...@>=
+for (k=mem_bot+1; k<=lo_mem_stat_max; k++) mem[k].sc=0;
+ /*all glue dimensions are zeroed*/
+@^data structure assumptions@>
+k=mem_bot;@+while (k <= lo_mem_stat_max)
+ /*set first words of glue specifications*/
+ {@+glue_ref_count(k)=null+1;
+ stretch_order(k)=normal;shrink_order(k)=normal;
+ k=k+glue_spec_size;
+ }
+stretch(fil_glue)=unity;stretch_order(fil_glue)=fil;@/
+stretch(fill_glue)=unity;stretch_order(fill_glue)=fill;@/
+stretch(ss_glue)=unity;stretch_order(ss_glue)=fil;@/
+shrink(ss_glue)=unity;shrink_order(ss_glue)=fil;@/
+stretch(fil_neg_glue)=-unity;stretch_order(fil_neg_glue)=fil;@/
+rover=lo_mem_stat_max+1;
+link(rover)=empty_flag; /*now initialize the dynamic memory*/
+node_size(rover)=1000; /*which is a 1000-word available node*/
+llink(rover)=rover;rlink(rover)=rover;@/
+lo_mem_max=rover+1000;link(lo_mem_max)=null;info(lo_mem_max)=null;@/
+for (k=hi_mem_stat_min; k<=mem_top; k++)
+ mem[k]=mem[lo_mem_max]; /*clear list heads*/
+@<Initialize the special list heads and constant nodes@>;
+avail=null;mem_end=mem_top;
+hi_mem_min=hi_mem_stat_min; /*initialize the one-word memory*/
+var_used=lo_mem_stat_max+1-mem_bot;dyn_used=hi_mem_stat_usage;
+ /*initialize statistics*/
+
+@ If \TeX\ is extended improperly, the |mem| array might get screwed up.
+For example, some pointers might be wrong, or some ``dead'' nodes might not
+have been freed when the last reference to them disappeared. Procedures
+|check_mem| and |search_mem| are available to help diagnose such
+problems. These procedures make use of two arrays called |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
+@^debugging@>
+are debugging.)
+
+@<Glob...@>=
+#ifdef @!DEBUG
+bool @!is_free0[mem_max-mem_min+1], *const @!is_free = @!is_free0-mem_min; /*free cells*/
+@t\hskip10pt@>bool @!was_free0[mem_max-mem_min+1], *const @!was_free = @!was_free0-mem_min;
+ /*previously free cells*/
+@t\hskip10pt@>pointer @!was_mem_end, @!was_lo_max, @!was_hi_min;
+ /*previous |mem_end|, |lo_mem_max|, and |hi_mem_min|*/
+@t\hskip10pt@>bool @!panicking; /*do we want to check memory constantly?*/
+#endif
+
+@ @<Set initial...@>=
+#ifdef @!DEBUG
+was_mem_end=mem_min; /*indicate that everything was previously free*/
+was_lo_max=mem_min;was_hi_min=mem_max;
+panicking=false;
+#endif
+
+@ Procedure |check_mem| makes sure that the available space lists of
+|mem| are well formed, and it optionally prints out all locations
+that are reserved now but were free the last time this procedure was called.
+
+@p
+#ifdef @!DEBUG
+void check_mem(bool @!print_locs)
+{@+ /*loop exits*/
+pointer p, @!q; /*current locations of interest in |mem|*/
+bool @!clobbered; /*is something amiss?*/
+for (p=mem_min; p<=lo_mem_max; p++) is_free[p]=false; /*you can probably
+ do this faster*/
+for (p=hi_mem_min; p<=mem_end; p++) is_free[p]=false; /*ditto*/
+@<Check single-word |avail| list@>;
+@<Check variable-size |avail| list@>;
+@<Check flags of unavailable nodes@>;
+if (print_locs) @<Print newly busy locations@>;
+for (p=mem_min; p<=lo_mem_max; p++) was_free[p]=is_free[p];
+for (p=hi_mem_min; p<=mem_end; p++) was_free[p]=is_free[p];
+ /*|was_free=is_free| might be faster*/
+was_mem_end=mem_end;was_lo_max=lo_mem_max;was_hi_min=hi_mem_min;
+}
+#endif
+
+@ @<Check single-word...@>=
+p=avail;q=null;clobbered=false;
+while (p!=null)
+ {@+if ((p > mem_end)||(p < hi_mem_min)) clobbered=true;
+ else if (is_free[p]) clobbered=true;
+ if (clobbered)
+ {@+print_nl("AVAIL list clobbered at ");
+@.AVAIL list clobbered...@>
+ print_int(q);goto done1;
+ }
+ is_free[p]=true;q=p;p=link(q);
+ }
+done1:
+
+@ @<Check variable-size...@>=
+p=rover;q=null;clobbered=false;
+@/do@+{if ((p >= lo_mem_max)||(p < mem_min)) clobbered=true;
+ else if ((rlink(p) >= lo_mem_max)||(rlink(p) < mem_min)) clobbered=true;
+ else if (!(is_empty(p))||(node_size(p) < 2)||@|
+ (p+node_size(p) > lo_mem_max)||@|(llink(rlink(p))!=p)) clobbered=true;
+ if (clobbered)
+ {@+print_nl("Double-AVAIL list clobbered at ");
+ print_int(q);goto done2;
+ }
+for (q=p; q<=p+node_size(p)-1; q++) /*mark all locations free*/
+ {@+if (is_free[q])
+ {@+print_nl("Doubly free location at ");
+@.Doubly free location...@>
+ print_int(q);goto done2;
+ }
+ is_free[q]=true;
+ }
+q=p;p=rlink(p);
+}@+ while (!(p==rover));
+done2:
+
+@ @<Check flags...@>=
+p=mem_min;
+while (p <= lo_mem_max) /*node |p| should not be empty*/
+ {@+if (is_empty(p))
+ {@+print_nl("Bad flag at ");print_int(p);
+@.Bad flag...@>
+ }
+ while ((p <= lo_mem_max)&&!is_free[p]) incr(p);
+ while ((p <= lo_mem_max)&&is_free[p]) incr(p);
+ }
+
+@ @<Print newly busy...@>=
+{@+print_nl("New busy locs:");
+for (p=mem_min; p<=lo_mem_max; p++)
+ if (!is_free[p]&&((p > was_lo_max)||was_free[p]))
+ {@+print_char(' ');print_int(p);
+ }
+for (p=hi_mem_min; p<=mem_end; p++)
+ if (!is_free[p]&&
+ ((p < was_hi_min)||(p > was_mem_end)||was_free[p]))
+ {@+print_char(' ');print_int(p);
+ }
+}
+
+@ The |search_mem| procedure attempts to answer the question ``Who points
+to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem|
+that might not be of type |two_halves|. Strictly speaking, this is
+@^dirty \PASCAL@>
+undefined in \PASCAL, and it can lead to ``false drops'' (words that seem to
+point to |p| purely by coincidence). But for debugging purposes, we want
+to rule out the places that do {\sl not\/} point to |p|, so a few false
+drops are tolerable.
+
+@p
+#ifdef @!DEBUG
+void search_mem(pointer @!p) /*look for pointers to |p|*/
+{@+int q; /*current position being searched*/
+for (q=mem_min; q<=lo_mem_max; q++)
+ {@+if (link(q)==p)
+ {@+print_nl("LINK(");print_int(q);print_char(')');
+ }
+ if (info(q)==p)
+ {@+print_nl("INFO(");print_int(q);print_char(')');
+ }
+ }
+for (q=hi_mem_min; q<=mem_end; q++)
+ {@+if (link(q)==p)
+ {@+print_nl("LINK(");print_int(q);print_char(')');
+ }
+ if (info(q)==p)
+ {@+print_nl("INFO(");print_int(q);print_char(')');
+ }
+ }
+@<Search |eqtb| for equivalents equal to |p|@>;
+@<Search |save_stack| for equivalents that point to |p|@>;
+@<Search |hyph_list| for pointers to |p|@>;
+}
+#endif
+
+@* Displaying boxes.
+We can reinforce our knowledge of the data structures just introduced
+by considering two procedures that display a list in symbolic form.
+The first of these, called |short_display|, is used in ``overfull box''
+messages to give the top-level description of a list. The other one,
+called |show_node_list|, prints a detailed description of exactly what
+is in the data structure.
+
+The philosophy of |short_display| is to ignore the fine points about exactly
+what is inside boxes, except that ligatures and discretionary breaks are
+expanded. As a result, |short_display| is a recursive procedure, but the
+recursion is never more than one level deep.
+@^recursion@>
+
+A global variable |font_in_short_display| keeps track of the font code that
+is assumed to be present when |short_display| begins; deviations from this
+font will be printed.
+
+@<Glob...@>=
+int @!font_in_short_display; /*an internal font number*/
+
+@ Boxes, rules, inserts, whatsits, marks, and things in general that are
+sort of ``complicated'' are indicated only by printing `\.{[]}'.
+
+@p void short_display(int @!p) /*prints highlights of list |p|*/
+{@+int n; /*for replacement counts*/
+while (p > mem_min)
+ {@+if (is_char_node(p))
+ {@+if (p <= mem_end)
+ {@+if (font(p)!=font_in_short_display)
+ {@+if ((font(p) < font_base)||(font(p) > font_max))
+ print_char('*');
+@.*\relax@>
+ else@<Print the font identifier for |font(p)|@>;
+ print_char(' ');font_in_short_display=font(p);
+ }
+ print_ASCII(qo(character(p)));
+ }
+ }
+ else@<Print a short indication of the contents of node |p|@>;
+ p=link(p);
+ }
+}
+
+@ @<Print a short indication of the contents of node |p|@>=
+switch (type(p)) {
+case hlist_node: case vlist_node: case ins_node: case whatsit_node: case mark_node: case adjust_node:
+ case unset_node: print_str("[]");@+break;
+case rule_node: print_char('|');@+break;
+case glue_node: if (glue_ptr(p)!=zero_glue) print_char(' ');@+break;
+case math_node: print_char('$');@+break;
+case ligature_node: short_display(lig_ptr(p));@+break;
+case disc_node: {@+short_display(pre_break(p));
+ short_display(post_break(p));@/
+ n=replace_count(p);
+ while (n > 0)
+ {@+if (link(p)!=null) p=link(p);
+ decr(n);
+ }
+ } @+break;
+default:do_nothing;
+}
+
+@ The |show_node_list| routine requires some auxiliary subroutines: one to
+print a font-and-character combination, one to print a token list without
+its reference count, and one to print a rule dimension.
+
+@p void print_font_and_char(int @!p) /*prints |char_node| data*/
+{@+if (p > mem_end) print_esc(@[@<|"CLOBBERED."|@>@]);
+else{@+if ((font(p) < font_base)||(font(p) > font_max)) print_char('*');
+@.*\relax@>
+ else@<Print the font identifier for |font(p)|@>;
+ print_char(' ');print_ASCII(qo(character(p)));
+ }
+}
+@#
+void print_mark(int @!p) /*prints token list data in braces*/
+{@+print_char('{');
+if ((p < hi_mem_min)||(p > mem_end)) print_esc(@[@<|"CLOBBERED."|@>@]);
+else show_token_list(link(p), null, max_print_line-10);
+print_char('}');
+}
+@#
+void print_rule_dimen(scaled @!d) /*prints dimension in rule node*/
+{@+if (is_running(d)) print_char('*');else print_scaled(d);
+@.*\relax@>
+}
+
+@ Then there is a subroutine that prints glue stretch and shrink, possibly
+followed by the name of finite units:
+
+@p void print_glue(scaled @!d, int @!order, str_number @!s)
+ /*prints a glue component*/
+{@+print_scaled(d);
+if ((order < normal)||(order > filll)) print_str("foul");
+else if (order > normal)
+ {@+print_str("fil");
+ while (order > fil)
+ {@+print_char('l');decr(order);
+ }
+ }
+else if (s!=0) print(s);
+}
+
+@ The next subroutine prints a whole glue specification.
+
+@p void print_spec(int @!p, str_number @!s)
+ /*prints a glue specification*/
+{@+if ((p < mem_min)||(p >= lo_mem_max)) print_char('*');
+@.*\relax@>
+else{@+print_scaled(width(p));
+ if (s!=0) print(s);
+ if (stretch(p)!=0)
+ {@+print_str(" plus ");print_glue(stretch(p), stretch_order(p), s);
+ }
+ if (shrink(p)!=0)
+ {@+print_str(" minus ");print_glue(shrink(p), shrink_order(p), s);
+ }
+ }
+}
+
+@ We also need to declare some procedures that appear later in this
+documentation.
+
+@p@<Declare procedures needed for displaying the elements of mlists@>@;
+@<Declare the procedure called |print_skip_param|@>@;
+
+@ Since boxes can be inside of boxes, |show_node_list| is inherently recursive,
+@^recursion@>
+up to a given maximum number of levels. The history of nesting is indicated
+by the current string, which will be printed at the beginning of each line;
+the length of this string, namely |cur_length|, is the depth of nesting.
+
+Recursive calls on |show_node_list| therefore use the following pattern:
+
+@d node_list_display(X)
+ {@+append_char('.');show_node_list(X);flush_char;
+ } /*|str_room| need not be checked; see |show_box| below*/
+
+@ A global variable called |depth_threshold| is used to record the maximum
+depth of nesting for which |show_node_list| will show information. If we
+have |depth_threshold==0|, for example, only the top level information will
+be given and no sublists will be traversed. Another global variable, called
+|breadth_max|, tells the maximum number of items to show at each level;
+|breadth_max| had better be positive, or you won't see anything.
+
+@<Glob...@>=
+int @!depth_threshold; /*maximum nesting depth in box displays*/
+int @!breadth_max; /*maximum number of items shown at the same list level*/
+
+@ Now we are ready for |show_node_list| itself. This procedure has been
+written to be ``extra robust'' in the sense that it should not crash or get
+into a loop even if the data structures have been messed up by bugs in
+the rest of the program. You can safely call its parent routine
+|show_box(p)| for arbitrary values of |p| when you are debugging \TeX.
+However, in the presence of bad data, the procedure may
+@^dirty \PASCAL@>@^debugging@>
+fetch a |memory_word| whose variant is different from the way it was stored;
+for example, it might try to read |mem[p].hh| when |mem[p]|
+contains a scaled integer, if |p| is a pointer that has been
+clobbered or chosen at random.
+
+@p void show_node_list(int @!p) /*prints a node list symbolically*/
+{@+
+int n; /*the number of items already printed at this level*/
+double @!g; /*a glue ratio, as a floating point number*/
+if (cur_length > depth_threshold)
+ {@+if (p > null) print_str(" []");
+ /*indicate that there's been some truncation*/
+ return;
+ }
+n=0;
+while (p > mem_min)
+ {@+print_ln();print_current_string(); /*display the nesting history*/
+ if (p > mem_end) /*pointer out of range*/
+ {@+print_str("Bad link, display aborted.");return;
+@.Bad link...@>
+ }
+ incr(n);if (n > breadth_max) /*time to stop*/
+ {@+print_str("etc.");return;
+@.etc@>
+ }
+ @<Display node |p|@>;
+ p=link(p);
+ }
+
+}
+
+@ @<Display node |p|@>=
+if (is_char_node(p)) print_font_and_char(p);
+else switch (type(p)) {
+ case hlist_node: case vlist_node: case unset_node: @<Display box |p|@>@;@+break;
+ case rule_node: @<Display rule |p|@>@;@+break;
+ case ins_node: @<Display insertion |p|@>@;@+break;
+ case whatsit_node: @<Display the whatsit node |p|@>@;@+break;
+ case glue_node: @<Display glue |p|@>@;@+break;
+ case kern_node: @<Display kern |p|@>@;@+break;
+ case math_node: @<Display math node |p|@>@;@+break;
+ case ligature_node: @<Display ligature |p|@>@;@+break;
+ case penalty_node: @<Display penalty |p|@>@;@+break;
+ case disc_node: @<Display discretionary |p|@>@;@+break;
+ case mark_node: @<Display mark |p|@>@;@+break;
+ case adjust_node: @<Display adjustment |p|@>@;@+break;
+ @t\4@>@<Cases of |show_node_list| that arise in mlists only@>@;
+ default:print_str("Unknown node type!");
+ }
+
+@ @<Display box |p|@>=
+{@+if (type(p)==hlist_node) print_esc('h');
+else if (type(p)==vlist_node) print_esc('v');
+else print_esc(@[@<|"unset"|@>@]);
+print_str("box(");print_scaled(height(p));print_char('+');
+print_scaled(depth(p));print_str(")x");print_scaled(width(p));
+if (type(p)==unset_node)
+ @<Display special fields of the unset node |p|@>@;
+else{@+@<Display the value of |glue_set(p)|@>;
+ if (shift_amount(p)!=0)
+ {@+print_str(", shifted ");print_scaled(shift_amount(p));
+ }
+ }
+node_list_display(list_ptr(p)); /*recursive call*/
+}
+
+@ @<Display special fields of the unset node |p|@>=
+{@+if (span_count(p)!=min_quarterword)
+ {@+print_str(" (");print_int(qo(span_count(p))+1);
+ print_str(" columns)");
+ }
+if (glue_stretch(p)!=0)
+ {@+print_str(", stretch ");print_glue(glue_stretch(p), glue_order(p), 0);
+ }
+if (glue_shrink(p)!=0)
+ {@+print_str(", shrink ");print_glue(glue_shrink(p), glue_sign(p), 0);
+ }
+}
+
+@ 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.
+@^system dependencies@>
+@^dirty \PASCAL@>
+
+@<Display the value of |glue_set(p)|@>=
+g=float(glue_set(p));
+if ((g!=float_constant(0))&&(glue_sign(p)!=normal))
+ {@+print_str(", glue set ");
+ if (glue_sign(p)==shrinking) print_str("- ");
+ if (abs(mem[p+glue_offset].i) < 04000000) print_str("?.?");
+ else if (abs(g) > float_constant(20000))
+ {@+if (g > float_constant(0)) print_char('>');
+ else print_str("< -");
+ print_glue(20000*unity, glue_order(p), 0);
+ }
+ else print_glue(round(unity*g), glue_order(p), 0);
+@^real multiplication@>
+ }
+
+@ @<Display rule |p|@>=
+{@+print_esc(@[@<|"rule("|@>@]);print_rule_dimen(height(p));print_char('+');
+print_rule_dimen(depth(p));print_str(")x");print_rule_dimen(width(p));
+}
+
+@ @<Display insertion |p|@>=
+{@+print_esc(@[@<|"insert"|@>@]);print_int(qo(subtype(p)));
+print_str(", natural size ");print_scaled(height(p));
+print_str("; split(");print_spec(split_top_ptr(p), 0);
+print_char(',');print_scaled(depth(p));
+print_str("); float cost ");print_int(float_cost(p));
+node_list_display(ins_ptr(p)); /*recursive call*/
+}
+
+@ @<Display glue |p|@>=
+if (subtype(p) >= a_leaders) @<Display leaders |p|@>@;
+else{@+print_esc(@[@<|"glue"|@>@]);
+ if (subtype(p)!=normal)
+ {@+print_char('(');
+ if (subtype(p) < cond_math_glue)
+ print_skip_param(subtype(p)-1);
+ else if (subtype(p)==cond_math_glue) print_esc(@[@<|"nonscript"|@>@]);
+ else print_esc(@[@<|"mskip"|@>@]);
+ print_char(')');
+ }
+ if (subtype(p)!=cond_math_glue)
+ {@+print_char(' ');
+ if (subtype(p) < cond_math_glue) print_spec(glue_ptr(p), 0);
+ else print_spec(glue_ptr(p),@[@<|"mu"|@>@]);
+ }
+ }
+
+@ @<Display leaders |p|@>=
+{@+print_esc(empty_string);
+if (subtype(p)==c_leaders) print_char('c');
+else if (subtype(p)==x_leaders) print_char('x');
+print_str("leaders ");print_spec(glue_ptr(p), 0);
+node_list_display(leader_ptr(p)); /*recursive call*/
+}
+
+@ An ``explicit'' kern value is indicated implicitly by an explicit space.
+
+@<Display kern |p|@>=
+if (subtype(p)!=mu_glue)
+ {@+print_esc(@[@<|"kern"|@>@]);
+ if (subtype(p)!=normal) print_char(' ');
+ print_scaled(width(p));
+ if (subtype(p)==acc_kern) print_str(" (for accent)");
+@.for accent@>
+ }
+else{@+print_esc(@[@<|"mkern"|@>@]);print_scaled(width(p));print_str("mu");
+ }
+
+@ @<Display math node |p|@>=
+{@+print_esc(@[@<|"math"|@>@]);
+if (subtype(p)==before) print_str("on");
+else print_str("off");
+if (width(p)!=0)
+ {@+print_str(", surrounded ");print_scaled(width(p));
+ }
+}
+
+@ @<Display ligature |p|@>=
+{@+print_font_and_char(lig_char(p));print_str(" (ligature ");
+if (subtype(p) > 1) print_char('|');
+font_in_short_display=font(lig_char(p));short_display(lig_ptr(p));
+if (odd(subtype(p))) print_char('|');
+print_char(')');
+}
+
+@ @<Display penalty |p|@>=
+{@+print_esc(@[@<|"penalty "|@>@]);print_int(penalty(p));
+}
+
+@ The |post_break| list of a discretionary node is indicated by a prefixed
+`\.{\char'174}' instead of the `\..' before the |pre_break| list.
+
+@<Display discretionary |p|@>=
+{@+print_esc(@[@<|"discretionary"|@>@]);
+if (replace_count(p) > 0)
+ {@+print_str(" replacing ");print_int(replace_count(p));
+ }
+node_list_display(pre_break(p)); /*recursive call*/
+append_char('|');show_node_list(post_break(p));flush_char; /*recursive call*/
+}
+
+@ @<Display mark |p|@>=
+{@+print_esc(@[@<|"mark"|@>@]);print_mark(mark_ptr(p));
+}
+
+@ @<Display adjustment |p|@>=
+{@+print_esc(@[@<|"vadjust"|@>@]);node_list_display(adjust_ptr(p)); /*recursive call*/
+}
+
+@ The recursive machinery is started by calling |show_box|.
+@^recursion@>
+
+@p void show_box(pointer @!p)
+{@+@<Assign the values |depth_threshold:=show_box_depth| and |breadth_max:=show_box_breadth|@>;
+if (breadth_max <= 0) breadth_max=5;
+if (pool_ptr+depth_threshold >= pool_size)
+ depth_threshold=pool_size-pool_ptr-1;
+ /*now there's enough room for prefix string*/
+show_node_list(p); /*the show starts at |p|*/
+print_ln();
+}
+
+@* Destroying boxes.
+When we are done with a node list, we are obliged to return it to free
+storage, including all of its sublists. The recursive procedure
+|flush_node_list| does this for us.
+
+@ First, however, we shall consider two non-recursive procedures that do
+simpler tasks. The first of these, |delete_token_ref|, is called when
+a pointer to a token list's reference count is being removed. This means
+that the token list should disappear if the reference count was |null|,
+otherwise the count should be decreased by one.
+@^reference counts@>
+
+@d token_ref_count(X) info(X) /*reference count preceding a token list*/
+
+@p void delete_token_ref(pointer @!p) /*|p| points to the reference count
+ of a token list that is losing one reference*/
+{@+if (token_ref_count(p)==null) flush_list(p);
+else decr(token_ref_count(p));
+}
+
+@ Similarly, |delete_glue_ref| is called when a pointer to a glue
+specification is being withdrawn.
+@^reference counts@>
+@d fast_delete_glue_ref(X) @t@>@;@/
+ {@+if (glue_ref_count(X)==null) free_node(X, glue_spec_size);
+ else decr(glue_ref_count(X));
+ }
+
+@p void delete_glue_ref(pointer @!p) /*|p| points to a glue specification*/
+fast_delete_glue_ref(p)
+
+@ Now we are ready to delete any node list, recursively.
+In practice, the nodes deleted are usually charnodes (about 2/3 of the time),
+and they are glue nodes in about half of the remaining cases.
+@^recursion@>
+
+@p void flush_node_list(pointer @!p) /*erase list of nodes starting at |p|*/
+{@+ /*go here when node |p| has been freed*/
+pointer q; /*successor to node |p|*/
+while (p!=null)
+@^inner loop@>
+ {@+q=link(p);
+ if (is_char_node(p)) free_avail(p)@;
+ else{@+switch (type(p)) {
+ case hlist_node: case vlist_node: case unset_node: {@+flush_node_list(list_ptr(p));
+ free_node(p, box_node_size);goto done;
+ }
+ case rule_node: {@+free_node(p, rule_node_size);goto done;
+ }
+ case ins_node: {@+flush_node_list(ins_ptr(p));
+ delete_glue_ref(split_top_ptr(p));
+ free_node(p, ins_node_size);goto done;
+ }
+ case whatsit_node: @<Wipe out the whatsit node |p| and |goto done|@>@;
+ case glue_node: {@+fast_delete_glue_ref(glue_ptr(p));
+ if (leader_ptr(p)!=null) flush_node_list(leader_ptr(p));
+ } @+break;
+ case kern_node: case math_node: case penalty_node: do_nothing;@+break;
+ case ligature_node: flush_node_list(lig_ptr(p));@+break;
+ case mark_node: delete_token_ref(mark_ptr(p));@+break;
+ case disc_node: {@+flush_node_list(pre_break(p));
+ flush_node_list(post_break(p));
+ } @+break;
+ case adjust_node: flush_node_list(adjust_ptr(p));@+break;
+ @t\4@>@<Cases of |flush_node_list| that arise in mlists only@>@;
+ default:confusion(@[@<|"flushing"|@>@]);
+@:this can't happen flushing}{\quad flushing@>
+ } @/
+ free_node(p, small_node_size);
+ done: ;}
+ p=q;
+ }
+}
+
+@* Copying boxes.
+Another recursive operation that acts on boxes is sometimes needed: The
+procedure |copy_node_list| returns a pointer to another node list that has
+the same structure and meaning as the original. Note that since glue
+specifications and token lists have reference counts, we need not make
+copies of them. Reference counts can never get too large to fit in a
+halfword, since each pointer to a node is in a different memory address,
+and the total number of memory addresses fits in a halfword.
+@^recursion@>
+@^reference counts@>
+
+(Well, there actually are also references from outside |mem|; if the
+|save_stack| is made arbitrarily large, it would theoretically be possible
+to break \TeX\ by overflowing a reference count. But who would want to do that?)
+
+@d add_token_ref(X) incr(token_ref_count(X)) /*new reference to a token list*/
+@d add_glue_ref(X) incr(glue_ref_count(X)) /*new reference to a glue spec*/
+
+@ The copying procedure copies words en masse without bothering
+to look at their individual fields. If the node format changes---for
+example, if the size is altered, or if some link field is moved to another
+relative position---then this code may need to be changed too.
+@^data structure assumptions@>
+
+@p pointer copy_node_list(pointer @!p) /*makes a duplicate of the
+ node list that starts at |p| and returns a pointer to the new list*/
+{@+pointer h; /*temporary head of copied list*/
+pointer @!q; /*previous position in new list*/
+pointer @!r; /*current node being fabricated for new list*/
+uint8_t @!words; /*number of words remaining to be copied*/
+h=get_avail();q=h;
+while (p!=null)
+ {@+@<Make a copy of node |p| in node |r|@>;
+ link(q)=r;q=r;p=link(p);
+ }
+link(q)=null;q=link(h);free_avail(h);
+return q;
+}
+
+@ @<Make a copy of node |p|...@>=
+words=1; /*this setting occurs in more branches than any other*/
+if (is_char_node(p)) r=get_avail();
+else@<Case statement to copy different types and set |words| to the number of initial
+words not yet copied@>;
+while (words > 0)
+ {@+decr(words);mem[r+words]=mem[p+words];
+ }
+
+@ @<Case statement to copy...@>=
+switch (type(p)) {
+case hlist_node: case vlist_node: case unset_node: {@+r=get_node(box_node_size);
+ mem[r+6]=mem[p+6];mem[r+5]=mem[p+5]; /*copy the last two words*/
+ list_ptr(r)=copy_node_list(list_ptr(p)); /*this affects |mem[r+5]|*/
+ words=5;
+ } @+break;
+case rule_node: {@+r=get_node(rule_node_size);words=rule_node_size;
+ } @+break;
+case ins_node: {@+r=get_node(ins_node_size);mem[r+4]=mem[p+4];
+ add_glue_ref(split_top_ptr(p));
+ ins_ptr(r)=copy_node_list(ins_ptr(p)); /*this affects |mem[r+4]|*/
+ words=ins_node_size-1;
+ } @+break;
+case whatsit_node: @<Make a partial copy of the whatsit node |p| and make |r| point
+to it; set |words| to the number of initial words not yet copied@>@;@+break;
+case glue_node: {@+r=get_node(small_node_size);add_glue_ref(glue_ptr(p));
+ glue_ptr(r)=glue_ptr(p);leader_ptr(r)=copy_node_list(leader_ptr(p));
+ } @+break;
+case kern_node: case math_node: case penalty_node: {@+r=get_node(small_node_size);
+ words=small_node_size;
+ } @+break;
+case ligature_node: {@+r=get_node(small_node_size);
+ mem[lig_char(r)]=mem[lig_char(p)]; /*copy |font| and |character|*/
+ lig_ptr(r)=copy_node_list(lig_ptr(p));
+ } @+break;
+case disc_node: {@+r=get_node(small_node_size);
+ pre_break(r)=copy_node_list(pre_break(p));
+ post_break(r)=copy_node_list(post_break(p));
+ } @+break;
+case mark_node: {@+r=get_node(small_node_size);add_token_ref(mark_ptr(p));
+ words=small_node_size;
+ } @+break;
+case adjust_node: {@+r=get_node(small_node_size);
+ adjust_ptr(r)=copy_node_list(adjust_ptr(p));
+ } @+break; /*|words==1==small_node_size-1|*/
+default:confusion(@[@<|"copying"|@>@]);
+@:this can't happen copying}{\quad copying@>
+}
+
+@* The command codes.
+Before we can go any further, we need to define symbolic names for the internal
+code numbers that represent the various commands obeyed by \TeX. These codes
+are somewhat arbitrary, but not completely so. For example, the command
+codes for character types are fixed by the language, since a user says,
+e.g., `\.{\\catcode \`\\\${} = 3}' to make \.{\char'44} a math delimiter,
+and the command code |math_shift| is equal to~3. Some other codes have
+been made adjacent so that |case| statements in the program need not consider
+cases that are widely spaced, or so that |case| statements can be replaced
+by |if (| statements.
+
+At any rate, here is the list, for future reference. First come the
+``catcode'' commands, several of which share their numeric codes with
+ordinary commands when the catcode cannot emerge from \TeX's scanning routine.
+
+@d escape 0 /*escape delimiter (called \.\\ in {\sl The \TeX book\/})*/
+@:TeXbook}{\sl The \TeX book@>
+@d relax 0 /*do nothing ( \.{\\relax} )*/
+@d left_brace 1 /*beginning of a group ( \.\{ )*/
+@d right_brace 2 /*ending of a group ( \.\} )*/
+@d math_shift 3 /*mathematics shift character ( \.\$ )*/
+@d tab_mark 4 /*alignment delimiter ( \.\&, \.{\\span} )*/
+@d car_ret 5 /*end of line ( |carriage_return|, \.{\\cr}, \.{\\crcr} )*/
+@d out_param 5 /*output a macro parameter*/
+@d mac_param 6 /*macro parameter symbol ( \.\# )*/
+@d sup_mark 7 /*superscript ( \.{\char'136} )*/
+@d sub_mark 8 /*subscript ( \.{\char'137} )*/
+@d ignore 9 /*characters to ignore ( \.{\^\^@@} )*/
+@d endv 9 /*end of \<v_j> list in alignment template*/
+@d spacer 10 /*characters equivalent to blank space ( \.{\ } )*/
+@d letter 11 /*characters regarded as letters ( \.{A..Z}, \.{a..z} )*/
+@d other_char 12 /*none of the special character types*/
+@d active_char 13 /*characters that invoke macros ( \.{\char`\~} )*/
+@d par_end 13 /*end of paragraph ( \.{\\par} )*/
+@d match 13 /*match a macro parameter*/
+@d comment 14 /*characters that introduce comments ( \.\% )*/
+@d end_match 14 /*end of parameters to macro*/
+@d stop 14 /*end of job ( \.{\\end}, \.{\\dump} )*/
+@d invalid_char 15 /*characters that shouldn't appear ( \.{\^\^?} )*/
+@d delim_num 15 /*specify delimiter numerically ( \.{\\delimiter} )*/
+@d max_char_code 15 /*largest catcode for individual characters*/
+
+@ Next are the ordinary run-of-the-mill command codes. Codes that are
+|min_internal| or more represent internal quantities that might be
+expanded by `\.{\\the}'.
+
+@d char_num 16 /*character specified numerically ( \.{\\char} )*/
+@d math_char_num 17 /*explicit math code ( \.{\\mathchar} )*/
+@d mark 18 /*mark definition ( \.{\\mark} )*/
+@d xray 19 /*peek inside of \TeX\ ( \.{\\show}, \.{\\showbox}, etc.~)*/
+@d make_box 20 /*make a box ( \.{\\box}, \.{\\copy}, \.{\\hbox}, etc.~)*/
+@d hmove 21 /*horizontal motion ( \.{\\moveleft}, \.{\\moveright} )*/
+@d vmove 22 /*vertical motion ( \.{\\raise}, \.{\\lower} )*/
+@d un_hbox 23 /*unglue a box ( \.{\\unhbox}, \.{\\unhcopy} )*/
+@d un_vbox 24 /*unglue a box ( \.{\\unvbox}, \.{\\unvcopy} )*/
+@d remove_item 25 /*nullify last item ( \.{\\unpenalty},
+ \.{\\unkern}, \.{\\unskip} )*/
+@d hskip 26 /*horizontal glue ( \.{\\hskip}, \.{\\hfil}, etc.~)*/
+@d vskip 27 /*vertical glue ( \.{\\vskip}, \.{\\vfil}, etc.~)*/
+@d mskip 28 /*math glue ( \.{\\mskip} )*/
+@d kern 29 /*fixed space ( \.{\\kern})*/
+@d mkern 30 /*math kern ( \.{\\mkern} )*/
+@d leader_ship 31 /*use a box ( \.{\\shipout}, \.{\\leaders}, etc.~)*/
+@d halign 32 /*horizontal table alignment ( \.{\\halign} )*/
+@d valign 33 /*vertical table alignment ( \.{\\valign} )*/
+@d no_align 34 /*temporary escape from alignment ( \.{\\noalign} )*/
+@d vrule 35 /*vertical rule ( \.{\\vrule} )*/
+@d hrule 36 /*horizontal rule ( \.{\\hrule} )*/
+@d insert 37 /*vlist inserted in box ( \.{\\insert} )*/
+@d vadjust 38 /*vlist inserted in enclosing paragraph ( \.{\\vadjust} )*/
+@d ignore_spaces 39 /*gobble |spacer| tokens ( \.{\\ignorespaces} )*/
+@d after_assignment 40 /*save till assignment is done ( \.{\\afterassignment} )*/
+@d after_group 41 /*save till group is done ( \.{\\aftergroup} )*/
+@d break_penalty 42 /*additional badness ( \.{\\penalty} )*/
+@d start_par 43 /*begin paragraph ( \.{\\indent}, \.{\\noindent} )*/
+@d ital_corr 44 /*italic correction ( \.{\\/} )*/
+@d accent 45 /*attach accent in text ( \.{\\accent} )*/
+@d math_accent 46 /*attach accent in math ( \.{\\mathaccent} )*/
+@d discretionary 47 /*discretionary texts ( \.{\\-}, \.{\\discretionary} )*/
+@d eq_no 48 /*equation number ( \.{\\eqno}, \.{\\leqno} )*/
+@d left_right 49 /*variable delimiter ( \.{\\left}, \.{\\right} )*/
+@d math_comp 50 /*component of formula ( \.{\\mathbin}, etc.~)*/
+@d limit_switch 51 /*diddle limit conventions ( \.{\\displaylimits}, etc.~)*/
+@d above 52 /*generalized fraction ( \.{\\above}, \.{\\atop}, etc.~)*/
+@d math_style 53 /*style specification ( \.{\\displaystyle}, etc.~)*/
+@d math_choice 54 /*choice specification ( \.{\\mathchoice} )*/
+@d non_script 55 /*conditional math glue ( \.{\\nonscript} )*/
+@d vcenter 56 /*vertically center a vbox ( \.{\\vcenter} )*/
+@d case_shift 57 /*force specific case ( \.{\\lowercase}, \.{\\uppercase}~)*/
+@d message 58 /*send to user ( \.{\\message}, \.{\\errmessage} )*/
+@d extension 59 /*extensions to \TeX\ ( \.{\\write}, \.{\\special}, etc.~)*/
+@d in_stream 60 /*files for reading ( \.{\\openin}, \.{\\closein} )*/
+@d begin_group 61 /*begin local grouping ( \.{\\begingroup} )*/
+@d end_group 62 /*end local grouping ( \.{\\endgroup} )*/
+@d omit 63 /*omit alignment template ( \.{\\omit} )*/
+@d ex_space 64 /*explicit space ( \.{\\\ } )*/
+@d no_boundary 65 /*suppress boundary ligatures ( \.{\\noboundary} )*/
+@d radical 66 /*square root and similar signs ( \.{\\radical} )*/
+@d end_cs_name 67 /*end control sequence ( \.{\\endcsname} )*/
+@d min_internal 68 /*the smallest code that can follow \.{\\the}*/
+@d char_given 68 /*character code defined by \.{\\chardef}*/
+@d math_given 69 /*math code defined by \.{\\mathchardef}*/
+@d last_item 70 /*most recent item ( \.{\\lastpenalty},
+ \.{\\lastkern}, \.{\\lastskip} )*/
+@d max_non_prefixed_command 70 /*largest command code that can't be \.{\\global}*/
+
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+@d toks_register 71 /*token list register ( \.{\\toks} )*/
+@d assign_toks 72 /*special token list ( \.{\\output}, \.{\\everypar}, etc.~)*/
+@d assign_int 73 /*user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)*/
+@d assign_dimen 74 /*user-defined length ( \.{\\hsize}, etc.~)*/
+@d assign_glue 75 /*user-defined glue ( \.{\\baselineskip}, etc.~)*/
+@d assign_mu_glue 76 /*user-defined muglue ( \.{\\thinmuskip}, etc.~)*/
+@d assign_font_dimen 77 /*user-defined font dimension ( \.{\\fontdimen} )*/
+@d assign_font_int 78 /*user-defined font integer ( \.{\\hyphenchar},
+ \.{\\skewchar} )*/
+@d set_aux 79 /*specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )*/
+@d set_prev_graf 80 /*specify state info ( \.{\\prevgraf} )*/
+@d set_page_dimen 81 /*specify state info ( \.{\\pagegoal}, etc.~)*/
+@d set_page_int 82 /*specify state info ( \.{\\deadcycles},
+ \.{\\insertpenalties} )*/
+@d set_box_dimen 83 /*change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )*/
+@d set_shape 84 /*specify fancy paragraph shape ( \.{\\parshape} )*/
+@d def_code 85 /*define a character code ( \.{\\catcode}, etc.~)*/
+@d def_family 86 /*declare math fonts ( \.{\\textfont}, etc.~)*/
+@d set_font 87 /*set current font ( font identifiers )*/
+@d def_font 88 /*define a font file ( \.{\\font} )*/
+@d register 89 /*internal register ( \.{\\count}, \.{\\dimen}, etc.~)*/
+@d max_internal 89 /*the largest code that can follow \.{\\the}*/
+@d advance 90 /*advance a register or parameter ( \.{\\advance} )*/
+@d multiply 91 /*multiply a register or parameter ( \.{\\multiply} )*/
+@d divide 92 /*divide a register or parameter ( \.{\\divide} )*/
+@d prefix 93 /*qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )*/
+@d let 94 /*assign a command code ( \.{\\let}, \.{\\futurelet} )*/
+@d shorthand_def 95 /*code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)*/
+@d read_to_cs 96 /*read into a control sequence ( \.{\\read} )*/
+@d def 97 /*macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )*/
+@d set_box 98 /*set a box ( \.{\\setbox} )*/
+@d hyph_data 99 /*hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )*/
+@d set_interaction 100 /*define level of interaction ( \.{\\batchmode}, etc.~)*/
+@d max_command 100 /*the largest command code seen at |big_switch|*/
+
+@ The remaining command codes are extra special, since they cannot get through
+\TeX's scanner to the main control routine. They have been given values higher
+than |max_command| so that their special nature is easily discernible.
+The ``expandable'' commands come first.
+
+@d undefined_cs (max_command+1) /*initial state of most |eq_type| fields*/
+@d expand_after (max_command+2) /*special expansion ( \.{\\expandafter} )*/
+@d no_expand (max_command+3) /*special nonexpansion ( \.{\\noexpand} )*/
+@d input (max_command+4) /*input a source file ( \.{\\input}, \.{\\endinput} )*/
+@d if_test (max_command+5) /*conditional text ( \.{\\if}, \.{\\ifcase}, etc.~)*/
+@d fi_or_else (max_command+6) /*delimiters for conditionals ( \.{\\else}, etc.~)*/
+@d cs_name (max_command+7) /*make a control sequence from tokens ( \.{\\csname} )*/
+@d convert (max_command+8) /*convert to text ( \.{\\number}, \.{\\string}, etc.~)*/
+@d the (max_command+9) /*expand an internal quantity ( \.{\\the} )*/
+@d top_bot_mark (max_command+10) /*inserted mark ( \.{\\topmark}, etc.~)*/
+@d call (max_command+11) /*non-long, non-outer control sequence*/
+@d long_call (max_command+12) /*long, non-outer control sequence*/
+@d outer_call (max_command+13) /*non-long, outer control sequence*/
+@d long_outer_call (max_command+14) /*long, outer control sequence*/
+@d end_template (max_command+15) /*end of an alignment template*/
+@d dont_expand (max_command+16) /*the following token was marked by \.{\\noexpand}*/
+@d glue_ref (max_command+17) /*the equivalent points to a glue specification*/
+@d shape_ref (max_command+18) /*the equivalent points to a parshape specification*/
+@d box_ref (max_command+19) /*the equivalent points to a box node, or is |null|*/
+@d data (max_command+20) /*the equivalent is simply a halfword number*/
+
+@* The semantic nest.
+\TeX\ is typically in the midst of building many lists at once. For example,
+when a math formula is being processed, \TeX\ is in math mode and
+working on an mlist; this formula has temporarily interrupted \TeX\ from
+being in horizontal mode and building the hlist of a paragraph; and this
+paragraph has temporarily interrupted \TeX\ from being in vertical mode
+and building the vlist for the next page of a document. Similarly, when a
+\.{\\vbox} occurs inside of an \.{\\hbox}, \TeX\ is temporarily
+interrupted from working in restricted horizontal mode, and it enters
+internal vertical mode. The ``semantic nest'' is a stack that
+keeps track of what lists and modes are currently suspended.
+
+At each level of processing we are in one of six modes:
+
+\yskip\hang|vmode| stands for vertical mode (the page builder);
+
+\hang|hmode| stands for horizontal mode (the paragraph builder);
+
+\hang|mmode| stands for displayed formula mode;
+
+\hang|-vmode| stands for internal vertical mode (e.g., in a \.{\\vbox});
+
+\hang|-hmode| stands for restricted horizontal mode (e.g., in an \.{\\hbox});
+
+\hang|-mmode| stands for math formula mode (not displayed).
+
+\yskip\noindent The mode is temporarily set to zero while processing \.{\\write}
+texts in the |ship_out| routine.
+
+Numeric values are assigned to |vmode|, |hmode|, and |mmode| so that
+\TeX's ``big semantic switch'' can select the appropriate thing to
+do by computing the value |abs(mode)+cur_cmd|, where |mode| is the current
+mode and |cur_cmd| is the current command code.
+
+@d vmode 1 /*vertical mode*/
+@d hmode (vmode+max_command+1) /*horizontal mode*/
+@d mmode (hmode+max_command+1) /*math mode*/
+
+@p void print_mode(int @!m) /*prints the mode represented by |m|*/
+{@+if (m > 0)
+ switch (m/(max_command+1)) {
+ case 0: print_str("vertical");@+break;
+ case 1: print_str("horizontal");@+break;
+ case 2: print_str("display math");
+ }
+else if (m==0) print_str("no");
+else switch ((-m)/(max_command+1)) {
+ case 0: print_str("internal vertical");@+break;
+ case 1: print_str("restricted horizontal");@+break;
+ case 2: print_str("math");
+ }
+print_str(" mode");
+}
+
+@ The state of affairs at any semantic level can be represented by
+five values:
+
+\yskip\hang|mode| is the number representing the semantic mode, as
+just explained.
+
+\yskip\hang|head| is a |pointer| to a list head for the list being built;
+|link(head)| therefore points to the first element of the list, or
+to |null| if the list is empty.
+
+\yskip\hang|tail| is a |pointer| to the final node of the list being
+built; thus, |tail==head| if and only if the list is empty.
+
+\yskip\hang|prev_graf| is the number of lines of the current paragraph that
+have already been put into the present vertical list.
+
+\yskip\hang|aux| is an auxiliary |memory_word| that gives further information
+that is needed to characterize the situation.
+
+\yskip\noindent
+In vertical mode, |aux| is also known as |prev_depth|; it is the scaled
+value representing the depth of the previous box, for use in baseline
+calculations, or it is | <= -1000|pt if the next box on the vertical list is to
+be exempt from baseline calculations. In horizontal mode, |aux| is also
+known as |space_factor| and |clang|; it holds the current space factor used in
+spacing calculations, and the current language used for hyphenation.
+(The value of |clang| is undefined in restricted horizontal mode.)
+In math mode, |aux| is also known as |incompleat_noad|; if
+not |null|, it points to a record that represents the numerator of a
+generalized fraction for which the denominator is currently being formed
+in the current list.
+
+There is also a sixth quantity, |mode_line|, which correlates
+the semantic nest with the user's input; |mode_line| contains the source
+line number at which the current level of nesting was entered. The negative
+of this line number is the |mode_line| at the level of the
+user's output routine.
+
+In horizontal mode, the |prev_graf| field is used for initial language data.
+
+The semantic nest is an array called |nest| that holds the |mode|, |head|,
+|tail|, |prev_graf|, |aux|, and |mode_line| values for all semantic levels
+below the currently active one. Information about the currently active
+level is kept in the global quantities |mode|, |head|, |tail|, |prev_graf|,
+|aux|, and |mode_line|, which live in a \PASCAL\ record that is ready to
+be pushed onto |nest| if necessary.
+
+@d ignore_depth -65536000 /*|prev_depth| value that is ignored*/
+
+@<Types...@>=
+typedef struct { int16_t @!mode_field;@+
+ pointer @!head_field, @!tail_field;
+ int @!pg_field, @!ml_field;@+
+ memory_word @!aux_field;
+ } list_state_record;
+
+@ @d mode cur_list.mode_field /*current mode*/
+@d head cur_list.head_field /*header node of current list*/
+@d tail cur_list.tail_field /*final node on current list*/
+@d prev_graf cur_list.pg_field /*number of paragraph lines accumulated*/
+@d aux cur_list.aux_field /*auxiliary data about the current list*/
+@d prev_depth aux.sc /*the name of |aux| in vertical mode*/
+@d space_factor aux.hh.lh /*part of |aux| in horizontal mode*/
+@d clang aux.hh.rh /*the other part of |aux| in horizontal mode*/
+@d incompleat_noad aux.i /*the name of |aux| in math mode*/
+@d mode_line cur_list.ml_field /*source file line number at beginning of list*/
+
+@<Glob...@>=
+list_state_record @!nest[nest_size+1];
+uint8_t @!nest_ptr; /*first unused location of |nest|*/
+uint8_t @!max_nest_stack; /*maximum of |nest_ptr| when pushing*/
+list_state_record @!cur_list; /*the ``top'' semantic state*/
+int16_t @!shown_mode; /*most recent mode shown by \.{\\tracingcommands}*/
+
+@ Here is a common way to make the current list grow:
+
+@d tail_append(X) {@+link(tail)=X;tail=link(tail);
+ }
+
+@ We will see later that the vertical list at the bottom semantic level is split
+into two parts; the ``current page'' runs from |page_head| to |page_tail|,
+and the ``contribution list'' runs from |contrib_head| to |tail| of
+semantic level zero. The idea is that contributions are first formed in
+vertical mode, then ``contributed'' to the current page (during which time
+the page-breaking decisions are made). For now, we don't need to know
+any more details about the page-building process.
+
+@<Set init...@>=
+nest_ptr=0;max_nest_stack=0;
+mode=vmode;head=contrib_head;tail=contrib_head;
+prev_depth=ignore_depth;mode_line=0;
+prev_graf=0;shown_mode=0;
+@<Start a new current page@>;
+
+@ When \TeX's work on one level is interrupted, the state is saved by
+calling |push_nest|. This routine changes |head| and |tail| so that
+a new (empty) list is begun; it does not change |mode| or |aux|.
+
+@p void push_nest(void) /*enter a new semantic level, save the old*/
+{@+if (nest_ptr > max_nest_stack)
+ {@+max_nest_stack=nest_ptr;
+ if (nest_ptr==nest_size) overflow("semantic nest size", nest_size);
+@:TeX capacity exceeded semantic nest size}{\quad semantic nest size@>
+ }
+nest[nest_ptr]=cur_list; /*stack the record*/
+incr(nest_ptr);head=get_avail();tail=head;prev_graf=0;mode_line=line;
+}
+
+@ Conversely, when \TeX\ is finished on the current level, the former
+state is restored by calling |pop_nest|. This routine will never be
+called at the lowest semantic level, nor will it be called unless |head|
+is a node that should be returned to free memory.
+
+@p void pop_nest(void) /*leave a semantic level, re-enter the old*/
+{@+free_avail(head);decr(nest_ptr);cur_list=nest[nest_ptr];
+}
+
+@ Here is a procedure that displays what \TeX\ is working on, at all levels.
+
+@p void print_totals(void);
+void show_activities(void)
+{@+int p; /*index into |nest|*/
+int16_t @!m; /*mode*/
+memory_word @!a; /*auxiliary*/
+pointer @!q, @!r; /*for showing the current page*/
+int @!t; /*ditto*/
+nest[nest_ptr]=cur_list; /*put the top level into the array*/
+print_nl("");print_ln();
+for (p=nest_ptr; p>=0; p--)
+ {@+m=nest[p].mode_field;a=nest[p].aux_field;
+ print_nl("### ");print_mode(m);
+ print_str(" entered at line ");print_int(abs(nest[p].ml_field));
+ if (m==hmode) if (nest[p].pg_field!=040600000)
+ {@+print_str(" (language");print_int(nest[p].pg_field%0200000);
+ print_str(":hyphenmin");print_int(nest[p].pg_field/020000000);
+ print_char(',');print_int((nest[p].pg_field/0200000)%0100);
+ print_char(')');
+ }
+ if (nest[p].ml_field < 0) print_str(" (\\output routine)");
+ if (p==0)
+ {@+@<Show the status of the current page@>;
+ if (link(contrib_head)!=null)
+ print_nl("### recent contributions:");
+ }
+ show_box(link(nest[p].head_field));
+ @<Show the auxiliary field, |a|@>;
+ }
+}
+
+@ @<Show the auxiliary...@>=
+switch (abs(m)/(max_command+1)) {
+case 0: {@+print_nl("prevdepth ");
+ if (a.sc <= ignore_depth) print_str("ignored");
+ else print_scaled(a.sc);
+ if (nest[p].pg_field!=0)
+ {@+print_str(", prevgraf ");
+ print_int(nest[p].pg_field);print_str(" line");
+ if (nest[p].pg_field!=1) print_char('s');
+ }
+ } @+break;
+case 1: {@+print_nl("spacefactor ");print_int(a.hh.lh);
+ if (m > 0) @+if (a.hh.rh > 0)
+ {@+print_str(", current language ");print_int(a.hh.rh);@+
+ }
+ } @+break;
+case 2: if (a.i!=null)
+ {@+print_str("this will be denominator of:");show_box(a.i);@+
+ }
+} /*there are no other cases*/
+
+@* 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-1)]| holds the current
+equivalents of single-character control sequences.
+
+\yskip\hangg 2) |eqtb[hash_base dotdot(glue_base-1)]| holds the current
+equivalents of multiletter control sequences.
+
+\yskip\hangg 3) |eqtb[glue_base dotdot(local_base-1)]| holds the current
+equivalents of glue parameters like the current baselineskip.
+
+\yskip\hangg 4) |eqtb[local_base dotdot(int_base-1)]| holds the current
+equivalents of local halfword quantities like the current box registers,
+the current ``catcodes,'' the current font, and a pointer to the current
+paragraph shape.
+
+\yskip\hangg 5) |eqtb[int_base dotdot(dimen_base-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.
+
+@ Each entry in |eqtb| is a |memory_word|. Most of these words are of type
+|two_halves|, and subdivided into three fields:
+
+\yskip\hangg 1) The |eq_level| (a quarterword) is the level of grouping at
+which this equivalent was defined. If the level is |level_zero|, the
+equivalent has never been defined; |level_one| refers to the outer level
+(outside of all groups), and this level is also used for global
+definitions that never go away. Higher levels are for equivalents that
+will disappear at the end of their group. @^global definitions@>
+
+\yskip\hangg 2) The |eq_type| (another quarterword) specifies what kind of
+entry this is. There are many types, since each \TeX\ primitive like
+\.{\\hbox}, \.{\\def}, etc., has its own special code. The list of
+command codes above includes all possible settings of the |eq_type| field.
+
+\yskip\hangg 3) The |equiv| (a halfword) is the current equivalent value.
+This may be a font number, a pointer into |mem|, or a variety of other
+things.
+
+@d eq_level_field(X) X.hh.b1
+@d eq_type_field(X) X.hh.b0
+@d equiv_field(X) X.hh.rh
+@d eq_level(X) eq_level_field(eqtb[X]) /*level of definition*/
+@d eq_type(X) eq_type_field(eqtb[X]) /*command code for equivalent*/
+@d equiv(X) equiv_field(eqtb[X]) /*equivalent value*/
+@d level_zero min_quarterword /*level for undefined quantities*/
+@d level_one (level_zero+1) /*outermost level for defined quantities*/
+
+@ Many locations in |eqtb| have symbolic names. The purpose of the next
+paragraphs is to define these names, and to set up the initial values of the
+equivalents.
+
+In the first region we have 256 equivalents for ``active characters'' that
+act as control sequences, followed by 256 equivalents for single-character
+control sequences.
+
+Then comes region~2, which corresponds to the hash table that we will
+define later. The maximum address in this region is used for a dummy
+control sequence that is perpetually undefined. There also are several
+locations for control sequences that are perpetually defined
+(since they are used in error recovery).
+
+@d active_base 1 /*beginning of region 1, for active character equivalents*/
+@d single_base (active_base+256) /*equivalents of one-character control sequences*/
+@d null_cs (single_base+256) /*equivalent of \.{\\csname\\endcsname}*/
+@d hash_base (null_cs+1) /*beginning of region 2, for the hash table*/
+@d frozen_control_sequence (hash_base+hash_size) /*for error recovery*/
+@d frozen_protection frozen_control_sequence /*inaccessible but definable*/
+@d frozen_cr (frozen_control_sequence+1) /*permanent `\.{\\cr}'*/
+@d frozen_end_group (frozen_control_sequence+2) /*permanent `\.{\\endgroup}'*/
+@d frozen_right (frozen_control_sequence+3) /*permanent `\.{\\right}'*/
+@d frozen_fi (frozen_control_sequence+4) /*permanent `\.{\\fi}'*/
+@d frozen_end_template (frozen_control_sequence+5) /*permanent `\.{\\endtemplate}'*/
+@d frozen_endv (frozen_control_sequence+6) /*second permanent `\.{\\endtemplate}'*/
+@d frozen_relax (frozen_control_sequence+7) /*permanent `\.{\\relax}'*/
+@d end_write (frozen_control_sequence+8) /*permanent `\.{\\endwrite}'*/
+@d frozen_dont_expand (frozen_control_sequence+9)
+ /*permanent `\.{\\notexpanded:}'*/
+@d frozen_null_font (frozen_control_sequence+10)
+ /*permanent `\.{\\nullfont}'*/
+@d font_id_base (frozen_null_font-font_base)
+ /*begins table of 257 permanent font identifiers*/
+@d undefined_control_sequence (frozen_null_font+257) /*dummy location*/
+@d glue_base (undefined_control_sequence+1) /*beginning of region 3*/
+
+@<Initialize table entries...@>=
+eq_type(undefined_control_sequence)=undefined_cs;
+equiv(undefined_control_sequence)=null;
+eq_level(undefined_control_sequence)=level_zero;
+for (k=active_base; k<=undefined_control_sequence-1; k++)
+ eqtb[k]=eqtb[undefined_control_sequence];
+
+@ Here is a routine that displays the current meaning of an |eqtb| entry
+in region 1 or~2. (Similar routines for the other regions will appear
+below.)
+
+@<Show equivalent |n|, in region 1 or 2@>=
+{@+sprint_cs(n);print_char('=');print_cmd_chr(eq_type(n), equiv(n));
+if (eq_type(n) >= call)
+ {@+print_char(':');show_token_list(link(equiv(n)), null, 32);
+ }
+}
+
+@ Region 3 of |eqtb| contains the 256 \.{\\skip} registers, as well as the
+glue parameters defined here. It is important that the ``muskip''
+parameters have larger numbers than the others.
+
+@d line_skip_code 0 /*interline glue if |baseline_skip| is infeasible*/
+@d baseline_skip_code 1 /*desired glue between baselines*/
+@d par_skip_code 2 /*extra glue just above a paragraph*/
+@d above_display_skip_code 3 /*extra glue just above displayed math*/
+@d below_display_skip_code 4 /*extra glue just below displayed math*/
+@d above_display_short_skip_code 5
+ /*glue above displayed math following short lines*/
+@d below_display_short_skip_code 6
+ /*glue below displayed math following short lines*/
+@d left_skip_code 7 /*glue at left of justified lines*/
+@d right_skip_code 8 /*glue at right of justified lines*/
+@d top_skip_code 9 /*glue at top of main pages*/
+@d split_top_skip_code 10 /*glue at top of split pages*/
+@d tab_skip_code 11 /*glue between aligned entries*/
+@d space_skip_code 12 /*glue between words (if not |zero_glue|)*/
+@d xspace_skip_code 13 /*glue after sentences (if not |zero_glue|)*/
+@d par_fill_skip_code 14 /*glue on last line of paragraph*/
+@d thin_mu_skip_code 15 /*thin space in math formula*/
+@d med_mu_skip_code 16 /*medium space in math formula*/
+@d thick_mu_skip_code 17 /*thick space in math formula*/
+@d glue_pars 18 /*total number of glue parameters*/
+@d skip_base (glue_base+glue_pars) /*table of 256 ``skip'' registers*/
+@d mu_skip_base (skip_base+256) /*table of 256 ``muskip'' registers*/
+@d local_base (mu_skip_base+256) /*beginning of region 4*/
+@#
+@d skip(X) equiv(skip_base+X) /*|mem| location of glue specification*/
+@d mu_skip(X) equiv(mu_skip_base+X) /*|mem| location of math glue spec*/
+@d glue_par(X) equiv(glue_base+X) /*|mem| location of glue specification*/
+@d line_skip glue_par(line_skip_code)
+@d baseline_skip glue_par(baseline_skip_code)
+@d par_skip glue_par(par_skip_code)
+@d above_display_skip glue_par(above_display_skip_code)
+@d below_display_skip glue_par(below_display_skip_code)
+@d above_display_short_skip glue_par(above_display_short_skip_code)
+@d below_display_short_skip glue_par(below_display_short_skip_code)
+@d left_skip glue_par(left_skip_code)
+@d right_skip glue_par(right_skip_code)
+@d top_skip glue_par(top_skip_code)
+@d split_top_skip glue_par(split_top_skip_code)
+@d tab_skip glue_par(tab_skip_code)
+@d space_skip glue_par(space_skip_code)
+@d xspace_skip glue_par(xspace_skip_code)
+@d par_fill_skip glue_par(par_fill_skip_code)
+@d thin_mu_skip glue_par(thin_mu_skip_code)
+@d med_mu_skip glue_par(med_mu_skip_code)
+@d thick_mu_skip glue_par(thick_mu_skip_code)
+
+@<Current |mem| equivalent of glue parameter number |n|@>=glue_par(n)
+
+@ Sometimes we need to convert \TeX's internal code numbers into symbolic
+form. The |print_skip_param| routine gives the symbolic name of a glue
+parameter.
+
+@<Declare the procedure called |print_skip_param|@>=
+void print_skip_param(int @!n)
+{@+switch (n) {
+case line_skip_code: print_esc(@[@<|"lineskip"|@>@]);@+break;
+case baseline_skip_code: print_esc(@[@<|"baselineskip"|@>@]);@+break;
+case par_skip_code: print_esc(@[@<|"parskip"|@>@]);@+break;
+case above_display_skip_code: print_esc(@[@<|"abovedisplayskip"|@>@]);@+break;
+case below_display_skip_code: print_esc(@[@<|"belowdisplayskip"|@>@]);@+break;
+case above_display_short_skip_code: print_esc(@[@<|"abovedisplayshortskip"|@>@]);@+break;
+case below_display_short_skip_code: print_esc(@[@<|"belowdisplayshortskip"|@>@]);@+break;
+case left_skip_code: print_esc(@[@<|"leftskip"|@>@]);@+break;
+case right_skip_code: print_esc(@[@<|"rightskip"|@>@]);@+break;
+case top_skip_code: print_esc(@[@<|"topskip"|@>@]);@+break;
+case split_top_skip_code: print_esc(@[@<|"splittopskip"|@>@]);@+break;
+case tab_skip_code: print_esc(@[@<|"tabskip"|@>@]);@+break;
+case space_skip_code: print_esc(@[@<|"spaceskip"|@>@]);@+break;
+case xspace_skip_code: print_esc(@[@<|"xspaceskip"|@>@]);@+break;
+case par_fill_skip_code: print_esc(@[@<|"parfillskip"|@>@]);@+break;
+case thin_mu_skip_code: print_esc(@[@<|"thinmuskip"|@>@]);@+break;
+case med_mu_skip_code: print_esc(@[@<|"medmuskip"|@>@]);@+break;
+case thick_mu_skip_code: print_esc(@[@<|"thickmuskip"|@>@]);@+break;
+default:print_str("[unknown glue parameter!]");
+}
+}
+
+@ The symbolic names for glue parameters are put into \TeX's hash table
+by using the routine called |primitive|, defined below. Let us enter them
+now, so that we don't have to list all those parameter names anywhere else.
+
+@<Put each of \TeX's primitives into the hash table@>=
+primitive(@[@<|"lineskip"|@>@], assign_glue, glue_base+line_skip_code);@/
+@!@:line_skip_}{\.{\\lineskip} primitive@>
+primitive(@[@<|"baselineskip"|@>@], assign_glue, glue_base+baseline_skip_code);@/
+@!@:baseline_skip_}{\.{\\baselineskip} primitive@>
+primitive(@[@<|"parskip"|@>@], assign_glue, glue_base+par_skip_code);@/
+@!@:par_skip_}{\.{\\parskip} primitive@>
+primitive(@[@<|"abovedisplayskip"|@>@], assign_glue, glue_base+above_display_skip_code);@/
+@!@:above_display_skip_}{\.{\\abovedisplayskip} primitive@>
+primitive(@[@<|"belowdisplayskip"|@>@], assign_glue, glue_base+below_display_skip_code);@/
+@!@:below_display_skip_}{\.{\\belowdisplayskip} primitive@>
+primitive(@[@<|"abovedisplayshortskip"|@>@],
+ assign_glue, glue_base+above_display_short_skip_code);@/
+@!@:above_display_short_skip_}{\.{\\abovedisplayshortskip} primitive@>
+primitive(@[@<|"belowdisplayshortskip"|@>@],
+ assign_glue, glue_base+below_display_short_skip_code);@/
+@!@:below_display_short_skip_}{\.{\\belowdisplayshortskip} primitive@>
+primitive(@[@<|"leftskip"|@>@], assign_glue, glue_base+left_skip_code);@/
+@!@:left_skip_}{\.{\\leftskip} primitive@>
+primitive(@[@<|"rightskip"|@>@], assign_glue, glue_base+right_skip_code);@/
+@!@:right_skip_}{\.{\\rightskip} primitive@>
+primitive(@[@<|"topskip"|@>@], assign_glue, glue_base+top_skip_code);@/
+@!@:top_skip_}{\.{\\topskip} primitive@>
+primitive(@[@<|"splittopskip"|@>@], assign_glue, glue_base+split_top_skip_code);@/
+@!@:split_top_skip_}{\.{\\splittopskip} primitive@>
+primitive(@[@<|"tabskip"|@>@], assign_glue, glue_base+tab_skip_code);@/
+@!@:tab_skip_}{\.{\\tabskip} primitive@>
+primitive(@[@<|"spaceskip"|@>@], assign_glue, glue_base+space_skip_code);@/
+@!@:space_skip_}{\.{\\spaceskip} primitive@>
+primitive(@[@<|"xspaceskip"|@>@], assign_glue, glue_base+xspace_skip_code);@/
+@!@:xspace_skip_}{\.{\\xspaceskip} primitive@>
+primitive(@[@<|"parfillskip"|@>@], assign_glue, glue_base+par_fill_skip_code);@/
+@!@:par_fill_skip_}{\.{\\parfillskip} primitive@>
+primitive(@[@<|"thinmuskip"|@>@], assign_mu_glue, glue_base+thin_mu_skip_code);@/
+@!@:thin_mu_skip_}{\.{\\thinmuskip} primitive@>
+primitive(@[@<|"medmuskip"|@>@], assign_mu_glue, glue_base+med_mu_skip_code);@/
+@!@:med_mu_skip_}{\.{\\medmuskip} primitive@>
+primitive(@[@<|"thickmuskip"|@>@], assign_mu_glue, glue_base+thick_mu_skip_code);@/
+@!@:thick_mu_skip_}{\.{\\thickmuskip} primitive@>
+
+@ @<Cases of |print_cmd_chr| for symbolic printing of primitives@>=
+case assign_glue: case assign_mu_glue: if (chr_code < skip_base)
+ print_skip_param(chr_code-glue_base);
+ else if (chr_code < mu_skip_base)
+ {@+print_esc(@[@<|"skip"|@>@]);print_int(chr_code-skip_base);
+ }
+ else{@+print_esc(@[@<|"muskip"|@>@]);print_int(chr_code-mu_skip_base);
+ } @+break;
+
+@ All glue parameters and registers are initially `\.{0pt plus0pt minus0pt}'.
+
+@<Initialize table entries...@>=
+equiv(glue_base)=zero_glue;eq_level(glue_base)=level_one;
+eq_type(glue_base)=glue_ref;
+for (k=glue_base+1; k<=local_base-1; k++) eqtb[k]=eqtb[glue_base];
+glue_ref_count(zero_glue)=glue_ref_count(zero_glue)+local_base-glue_base;
+
+@ @<Show equivalent |n|, in region 3@>=
+if (n < skip_base)
+ {@+print_skip_param(n-glue_base);print_char('=');
+ if (n < glue_base+thin_mu_skip_code) print_spec(equiv(n),@[@<|"pt"|@>@]);
+ else print_spec(equiv(n),@[@<|"mu"|@>@]);
+ }
+else if (n < mu_skip_base)
+ {@+print_esc(@[@<|"skip"|@>@]);print_int(n-skip_base);print_char('=');
+ print_spec(equiv(n),@[@<|"pt"|@>@]);
+ }
+else{@+print_esc(@[@<|"muskip"|@>@]);print_int(n-mu_skip_base);print_char('=');
+ print_spec(equiv(n),@[@<|"mu"|@>@]);
+ }
+
+@ Region 4 of |eqtb| contains the local quantities defined here. The
+bulk of this region is taken up by five tables that are indexed by eight-bit
+characters; these tables are important to both the syntactic and semantic
+portions of \TeX. There are also a bunch of special things like font and
+token parameters, as well as the tables of \.{\\toks} and \.{\\box}
+registers.
+
+@d par_shape_loc local_base /*specifies paragraph shape*/
+@d output_routine_loc (local_base+1) /*points to token list for \.{\\output}*/
+@d every_par_loc (local_base+2) /*points to token list for \.{\\everypar}*/
+@d every_math_loc (local_base+3) /*points to token list for \.{\\everymath}*/
+@d every_display_loc (local_base+4) /*points to token list for \.{\\everydisplay}*/
+@d every_hbox_loc (local_base+5) /*points to token list for \.{\\everyhbox}*/
+@d every_vbox_loc (local_base+6) /*points to token list for \.{\\everyvbox}*/
+@d every_job_loc (local_base+7) /*points to token list for \.{\\everyjob}*/
+@d every_cr_loc (local_base+8) /*points to token list for \.{\\everycr}*/
+@d err_help_loc (local_base+9) /*points to token list for \.{\\errhelp}*/
+@d toks_base (local_base+10) /*table of 256 token list registers*/
+@d box_base (toks_base+256) /*table of 256 box registers*/
+@d cur_font_loc (box_base+256) /*internal font number outside math mode*/
+@d math_font_base (cur_font_loc+1) /*table of 48 math font numbers*/
+@d cat_code_base (math_font_base+48)
+ /*table of 256 command codes (the ``catcodes'')*/
+@d lc_code_base (cat_code_base+256) /*table of 256 lowercase mappings*/
+@d uc_code_base (lc_code_base+256) /*table of 256 uppercase mappings*/
+@d sf_code_base (uc_code_base+256) /*table of 256 spacefactor mappings*/
+@d math_code_base (sf_code_base+256) /*table of 256 math mode mappings*/
+@d int_base (math_code_base+256) /*beginning of region 5*/
+@#
+@d par_shape_ptr equiv(par_shape_loc)
+@d output_routine equiv(output_routine_loc)
+@d every_par equiv(every_par_loc)
+@d every_math equiv(every_math_loc)
+@d every_display equiv(every_display_loc)
+@d every_hbox equiv(every_hbox_loc)
+@d every_vbox equiv(every_vbox_loc)
+@d every_job equiv(every_job_loc)
+@d every_cr equiv(every_cr_loc)
+@d err_help equiv(err_help_loc)
+@d toks(X) equiv(toks_base+X)
+@d box(X) equiv(box_base+X)
+@d cur_font equiv(cur_font_loc)
+@d fam_fnt(X) equiv(math_font_base+X)
+@d cat_code(X) equiv(cat_code_base+X)
+@d lc_code(X) equiv(lc_code_base+X)
+@d uc_code(X) equiv(uc_code_base+X)
+@d sf_code(X) equiv(sf_code_base+X)
+@d math_code(X) equiv(math_code_base+X)
+ /*Note: |math_code(c)| is the true math code plus |min_halfword|*/
+
+@<Put each...@>=
+primitive(@[@<|"output"|@>@], assign_toks, output_routine_loc);
+@!@:output_}{\.{\\output} primitive@>
+primitive(@[@<|"everypar"|@>@], assign_toks, every_par_loc);
+@!@:every_par_}{\.{\\everypar} primitive@>
+primitive(@[@<|"everymath"|@>@], assign_toks, every_math_loc);
+@!@:every_math_}{\.{\\everymath} primitive@>
+primitive(@[@<|"everydisplay"|@>@], assign_toks, every_display_loc);
+@!@:every_display_}{\.{\\everydisplay} primitive@>
+primitive(@[@<|"everyhbox"|@>@], assign_toks, every_hbox_loc);
+@!@:every_hbox_}{\.{\\everyhbox} primitive@>
+primitive(@[@<|"everyvbox"|@>@], assign_toks, every_vbox_loc);
+@!@:every_vbox_}{\.{\\everyvbox} primitive@>
+primitive(@[@<|"everyjob"|@>@], assign_toks, every_job_loc);
+@!@:every_job_}{\.{\\everyjob} primitive@>
+primitive(@[@<|"everycr"|@>@], assign_toks, every_cr_loc);
+@!@:every_cr_}{\.{\\everycr} primitive@>
+primitive(@[@<|"errhelp"|@>@], assign_toks, err_help_loc);
+@!@:err_help_}{\.{\\errhelp} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case assign_toks: if (chr_code >= toks_base)
+ {@+print_esc(@[@<|"toks"|@>@]);print_int(chr_code-toks_base);
+ }
+else switch (chr_code) {
+ case output_routine_loc: print_esc(@[@<|"output"|@>@]);@+break;
+ case every_par_loc: print_esc(@[@<|"everypar"|@>@]);@+break;
+ case every_math_loc: print_esc(@[@<|"everymath"|@>@]);@+break;
+ case every_display_loc: print_esc(@[@<|"everydisplay"|@>@]);@+break;
+ case every_hbox_loc: print_esc(@[@<|"everyhbox"|@>@]);@+break;
+ case every_vbox_loc: print_esc(@[@<|"everyvbox"|@>@]);@+break;
+ case every_job_loc: print_esc(@[@<|"everyjob"|@>@]);@+break;
+ case every_cr_loc: print_esc(@[@<|"everycr"|@>@]);@+break;
+ default:print_esc(@[@<|"errhelp"|@>@]);
+ } @+break;
+
+@ We initialize most things to null or undefined values. An undefined font
+is represented by the internal code |font_base|.
+
+However, the character code tables are given initial values based on the
+conventional interpretation of ASCII code. These initial values should
+not be changed when \TeX\ is adapted for use with non-English languages;
+all changes to the initialization conventions should be made in format
+packages, not in \TeX\ itself, so that global interchange of formats is
+possible.
+
+@d null_font font_base
+@d var_code 070000 /*math code meaning ``use the current family''*/
+
+@<Initialize table entries...@>=
+par_shape_ptr=null;eq_type(par_shape_loc)=shape_ref;
+eq_level(par_shape_loc)=level_one;@/
+for (k=output_routine_loc; k<=toks_base+255; k++)
+ eqtb[k]=eqtb[undefined_control_sequence];
+box(0)=null;eq_type(box_base)=box_ref;eq_level(box_base)=level_one;
+for (k=box_base+1; k<=box_base+255; k++) eqtb[k]=eqtb[box_base];
+cur_font=null_font;eq_type(cur_font_loc)=data;
+eq_level(cur_font_loc)=level_one;@/
+for (k=math_font_base; k<=math_font_base+47; k++) eqtb[k]=eqtb[cur_font_loc];
+equiv(cat_code_base)=0;eq_type(cat_code_base)=data;
+eq_level(cat_code_base)=level_one;@/
+for (k=cat_code_base+1; k<=int_base-1; k++) eqtb[k]=eqtb[cat_code_base];
+for (k=0; k<=255; k++)
+ {@+cat_code(k)=other_char;math_code(k)=hi(k);sf_code(k)=1000;
+ }
+cat_code(carriage_return)=car_ret;cat_code(' ')=spacer;
+cat_code('\\')=escape;cat_code('%')=comment;
+cat_code(invalid_code)=invalid_char;cat_code(null_code)=ignore;
+for (k='0'; k<='9'; k++) math_code(k)=hi(k+var_code);
+for (k='A'; k<='Z'; k++)
+ {@+cat_code(k)=letter;cat_code(k+'a'-'A')=letter;@/
+ math_code(k)=hi(k+var_code+0x100);
+ math_code(k+'a'-'A')=hi(k+'a'-'A'+var_code+0x100);@/
+ lc_code(k)=k+'a'-'A';lc_code(k+'a'-'A')=k+'a'-'A';@/
+ uc_code(k)=k;uc_code(k+'a'-'A')=k;@/
+ sf_code(k)=999;
+ }
+
+@ @<Show equivalent |n|, in region 4@>=
+if (n==par_shape_loc)
+ {@+print_esc(@[@<|"parshape"|@>@]);print_char('=');
+ if (par_shape_ptr==null) print_char('0');
+ else print_int(info(par_shape_ptr));
+ }
+else if (n < toks_base)
+ {@+print_cmd_chr(assign_toks, n);print_char('=');
+ if (equiv(n)!=null) show_token_list(link(equiv(n)), null, 32);
+ }
+else if (n < box_base)
+ {@+print_esc(@[@<|"toks"|@>@]);print_int(n-toks_base);print_char('=');
+ if (equiv(n)!=null) show_token_list(link(equiv(n)), null, 32);
+ }
+else if (n < cur_font_loc)
+ {@+print_esc(@[@<|"box"|@>@]);print_int(n-box_base);print_char('=');
+ if (equiv(n)==null) print_str("void");
+ else{@+depth_threshold=0;breadth_max=1;show_node_list(equiv(n));
+ }
+ }
+else if (n < cat_code_base) @<Show the font identifier in |eqtb[n]|@>@;
+else@<Show the halfword code in |eqtb[n]|@>@;
+
+@ @<Show the font identifier in |eqtb[n]|@>=
+{@+if (n==cur_font_loc) print_str("current font");
+else if (n < math_font_base+16)
+ {@+print_esc(@[@<|"textfont"|@>@]);print_int(n-math_font_base);
+ }
+else if (n < math_font_base+32)
+ {@+print_esc(@[@<|"scriptfont"|@>@]);print_int(n-math_font_base-16);
+ }
+else{@+print_esc(@[@<|"scriptscriptfont"|@>@]);print_int(n-math_font_base-32);
+ }
+print_char('=');@/
+print_esc(hash[font_id_base+equiv(n)].rh);
+ /*that's |font_id_text(equiv(n))|*/
+}
+
+@ @<Show the halfword code in |eqtb[n]|@>=
+if (n < math_code_base)
+ {@+if (n < lc_code_base)
+ {@+print_esc(@[@<|"catcode"|@>@]);print_int(n-cat_code_base);
+ }
+ else if (n < uc_code_base)
+ {@+print_esc(@[@<|"lccode"|@>@]);print_int(n-lc_code_base);
+ }
+ else if (n < sf_code_base)
+ {@+print_esc(@[@<|"uccode"|@>@]);print_int(n-uc_code_base);
+ }
+ else{@+print_esc(@[@<|"sfcode"|@>@]);print_int(n-sf_code_base);
+ }
+ print_char('=');print_int(equiv(n));
+ }
+else{@+print_esc(@[@<|"mathcode"|@>@]);print_int(n-math_code_base);
+ print_char('=');print_int(ho(equiv(n)));
+ }
+
+@ 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.
+
+@d pretolerance_code 0 /*badness tolerance before hyphenation*/
+@d tolerance_code 1 /*badness tolerance after hyphenation*/
+@d line_penalty_code 2 /*added to the badness of every line*/
+@d hyphen_penalty_code 3 /*penalty for break after discretionary hyphen*/
+@d ex_hyphen_penalty_code 4 /*penalty for break after explicit hyphen*/
+@d club_penalty_code 5 /*penalty for creating a club line*/
+@d widow_penalty_code 6 /*penalty for creating a widow line*/
+@d display_widow_penalty_code 7 /*ditto, just before a display*/
+@d broken_penalty_code 8 /*penalty for breaking a page at a broken line*/
+@d bin_op_penalty_code 9 /*penalty for breaking after a binary operation*/
+@d rel_penalty_code 10 /*penalty for breaking after a relation*/
+@d pre_display_penalty_code 11
+ /*penalty for breaking just before a displayed formula*/
+@d post_display_penalty_code 12
+ /*penalty for breaking just after a displayed formula*/
+@d inter_line_penalty_code 13 /*additional penalty between lines*/
+@d double_hyphen_demerits_code 14 /*demerits for double hyphen break*/
+@d final_hyphen_demerits_code 15 /*demerits for final hyphen break*/
+@d adj_demerits_code 16 /*demerits for adjacent incompatible lines*/
+@d mag_code 17 /*magnification ratio*/
+@d delimiter_factor_code 18 /*ratio for variable-size delimiters*/
+@d looseness_code 19 /*change in number of lines for a paragraph*/
+@d time_code 20 /*current time of day*/
+@d day_code 21 /*current day of the month*/
+@d month_code 22 /*current month of the year*/
+@d year_code 23 /*current year of our Lord*/
+@d show_box_breadth_code 24 /*nodes per level in |show_box|*/
+@d show_box_depth_code 25 /*maximum level in |show_box|*/
+@d hbadness_code 26 /*hboxes exceeding this badness will be shown by |hpack|*/
+@d vbadness_code 27 /*vboxes exceeding this badness will be shown by |vpack|*/
+@d pausing_code 28 /*pause after each line is read from a file*/
+@d tracing_online_code 29 /*show diagnostic output on terminal*/
+@d tracing_macros_code 30 /*show macros as they are being expanded*/
+@d tracing_stats_code 31 /*show memory usage if \TeX\ knows it*/
+@d tracing_paragraphs_code 32 /*show line-break calculations*/
+@d tracing_pages_code 33 /*show page-break calculations*/
+@d tracing_output_code 34 /*show boxes when they are shipped out*/
+@d tracing_lost_chars_code 35 /*show characters that aren't in the font*/
+@d tracing_commands_code 36 /*show command codes at |big_switch|*/
+@d tracing_restores_code 37 /*show equivalents when they are restored*/
+@d uc_hyph_code 38 /*hyphenate words beginning with a capital letter*/
+@d output_penalty_code 39 /*penalty found at current page break*/
+@d max_dead_cycles_code 40 /*bound on consecutive dead cycles of output*/
+@d hang_after_code 41 /*hanging indentation changes after this many lines*/
+@d floating_penalty_code 42 /*penalty for insertions heldover after a split*/
+@d global_defs_code 43 /*override \.{\\global} specifications*/
+@d cur_fam_code 44 /*current family*/
+@d escape_char_code 45 /*escape character for token output*/
+@d default_hyphen_char_code 46 /*value of \.{\\hyphenchar} when a font is loaded*/
+@d default_skew_char_code 47 /*value of \.{\\skewchar} when a font is loaded*/
+@d end_line_char_code 48 /*character placed at the right end of the buffer*/
+@d new_line_char_code 49 /*character that prints as |print_ln|*/
+@d language_code 50 /*current hyphenation table*/
+@d left_hyphen_min_code 51 /*minimum left hyphenation fragment size*/
+@d right_hyphen_min_code 52 /*minimum right hyphenation fragment size*/
+@d holding_inserts_code 53 /*do not remove insertion nodes from \.{\\box255}*/
+@d error_context_lines_code 54 /*maximum intermediate line pairs shown*/
+@d int_pars 55 /*total number of integer parameters*/
+@d count_base (int_base+int_pars) /*256 user \.{\\count} registers*/
+@d del_code_base (count_base+256) /*256 delimiter code mappings*/
+@d dimen_base (del_code_base+256) /*beginning of region 6*/
+@#
+@d del_code(X) eqtb[del_code_base+X].i
+@d count(X) eqtb[count_base+X].i
+@d int_par(X) eqtb[int_base+X].i /*an integer parameter*/
+@d pretolerance int_par(pretolerance_code)
+@d tolerance int_par(tolerance_code)
+@d line_penalty int_par(line_penalty_code)
+@d hyphen_penalty int_par(hyphen_penalty_code)
+@d ex_hyphen_penalty int_par(ex_hyphen_penalty_code)
+@d club_penalty int_par(club_penalty_code)
+@d widow_penalty int_par(widow_penalty_code)
+@d display_widow_penalty int_par(display_widow_penalty_code)
+@d broken_penalty int_par(broken_penalty_code)
+@d bin_op_penalty int_par(bin_op_penalty_code)
+@d rel_penalty int_par(rel_penalty_code)
+@d pre_display_penalty int_par(pre_display_penalty_code)
+@d post_display_penalty int_par(post_display_penalty_code)
+@d inter_line_penalty int_par(inter_line_penalty_code)
+@d double_hyphen_demerits int_par(double_hyphen_demerits_code)
+@d final_hyphen_demerits int_par(final_hyphen_demerits_code)
+@d adj_demerits int_par(adj_demerits_code)
+@d mag int_par(mag_code)
+@d delimiter_factor int_par(delimiter_factor_code)
+@d looseness int_par(looseness_code)
+@d time int_par(time_code)
+@d day int_par(day_code)
+@d month int_par(month_code)
+@d year int_par(year_code)
+@d show_box_breadth int_par(show_box_breadth_code)
+@d show_box_depth int_par(show_box_depth_code)
+@d hbadness int_par(hbadness_code)
+@d vbadness int_par(vbadness_code)
+@d pausing int_par(pausing_code)
+@d tracing_online int_par(tracing_online_code)
+@d tracing_macros int_par(tracing_macros_code)
+@d tracing_stats int_par(tracing_stats_code)
+@d tracing_paragraphs int_par(tracing_paragraphs_code)
+@d tracing_pages int_par(tracing_pages_code)
+@d tracing_output int_par(tracing_output_code)
+@d tracing_lost_chars int_par(tracing_lost_chars_code)
+@d tracing_commands int_par(tracing_commands_code)
+@d tracing_restores int_par(tracing_restores_code)
+@d uc_hyph int_par(uc_hyph_code)
+@d output_penalty int_par(output_penalty_code)
+@d max_dead_cycles int_par(max_dead_cycles_code)
+@d hang_after int_par(hang_after_code)
+@d floating_penalty int_par(floating_penalty_code)
+@d global_defs int_par(global_defs_code)
+@d cur_fam int_par(cur_fam_code)
+@d escape_char int_par(escape_char_code)
+@d default_hyphen_char int_par(default_hyphen_char_code)
+@d default_skew_char int_par(default_skew_char_code)
+@d end_line_char int_par(end_line_char_code)
+@d new_line_char int_par(new_line_char_code)
+@d language int_par(language_code)
+@d left_hyphen_min int_par(left_hyphen_min_code)
+@d right_hyphen_min int_par(right_hyphen_min_code)
+@d holding_inserts int_par(holding_inserts_code)
+@d error_context_lines int_par(error_context_lines_code)
+
+@<Assign the values |depth_threshold:=show_box_depth|...@>=
+depth_threshold=show_box_depth;
+breadth_max=show_box_breadth
+
+@ We can print the symbolic name of an integer parameter as follows.
+
+@p void print_param(int @!n)
+{@+switch (n) {
+case pretolerance_code: print_esc(@[@<|"pretolerance"|@>@]);@+break;
+case tolerance_code: print_esc(@[@<|"tolerance"|@>@]);@+break;
+case line_penalty_code: print_esc(@[@<|"linepenalty"|@>@]);@+break;
+case hyphen_penalty_code: print_esc(@[@<|"hyphenpenalty"|@>@]);@+break;
+case ex_hyphen_penalty_code: print_esc(@[@<|"exhyphenpenalty"|@>@]);@+break;
+case club_penalty_code: print_esc(@[@<|"clubpenalty"|@>@]);@+break;
+case widow_penalty_code: print_esc(@[@<|"widowpenalty"|@>@]);@+break;
+case display_widow_penalty_code: print_esc(@[@<|"displaywidowpenalty"|@>@]);@+break;
+case broken_penalty_code: print_esc(@[@<|"brokenpenalty"|@>@]);@+break;
+case bin_op_penalty_code: print_esc(@[@<|"binoppenalty"|@>@]);@+break;
+case rel_penalty_code: print_esc(@[@<|"relpenalty"|@>@]);@+break;
+case pre_display_penalty_code: print_esc(@[@<|"predisplaypenalty"|@>@]);@+break;
+case post_display_penalty_code: print_esc(@[@<|"postdisplaypenalty"|@>@]);@+break;
+case inter_line_penalty_code: print_esc(@[@<|"interlinepenalty"|@>@]);@+break;
+case double_hyphen_demerits_code: print_esc(@[@<|"doublehyphendemerits"|@>@]);@+break;
+case final_hyphen_demerits_code: print_esc(@[@<|"finalhyphendemerits"|@>@]);@+break;
+case adj_demerits_code: print_esc(@[@<|"adjdemerits"|@>@]);@+break;
+case mag_code: print_esc(@[@<|"mag"|@>@]);@+break;
+case delimiter_factor_code: print_esc(@[@<|"delimiterfactor"|@>@]);@+break;
+case looseness_code: print_esc(@[@<|"looseness"|@>@]);@+break;
+case time_code: print_esc(@[@<|"time"|@>@]);@+break;
+case day_code: print_esc(@[@<|"day"|@>@]);@+break;
+case month_code: print_esc(@[@<|"month"|@>@]);@+break;
+case year_code: print_esc(@[@<|"year"|@>@]);@+break;
+case show_box_breadth_code: print_esc(@[@<|"showboxbreadth"|@>@]);@+break;
+case show_box_depth_code: print_esc(@[@<|"showboxdepth"|@>@]);@+break;
+case hbadness_code: print_esc(@[@<|"hbadness"|@>@]);@+break;
+case vbadness_code: print_esc(@[@<|"vbadness"|@>@]);@+break;
+case pausing_code: print_esc(@[@<|"pausing"|@>@]);@+break;
+case tracing_online_code: print_esc(@[@<|"tracingonline"|@>@]);@+break;
+case tracing_macros_code: print_esc(@[@<|"tracingmacros"|@>@]);@+break;
+case tracing_stats_code: print_esc(@[@<|"tracingstats"|@>@]);@+break;
+case tracing_paragraphs_code: print_esc(@[@<|"tracingparagraphs"|@>@]);@+break;
+case tracing_pages_code: print_esc(@[@<|"tracingpages"|@>@]);@+break;
+case tracing_output_code: print_esc(@[@<|"tracingoutput"|@>@]);@+break;
+case tracing_lost_chars_code: print_esc(@[@<|"tracinglostchars"|@>@]);@+break;
+case tracing_commands_code: print_esc(@[@<|"tracingcommands"|@>@]);@+break;
+case tracing_restores_code: print_esc(@[@<|"tracingrestores"|@>@]);@+break;
+case uc_hyph_code: print_esc(@[@<|"uchyph"|@>@]);@+break;
+case output_penalty_code: print_esc(@[@<|"outputpenalty"|@>@]);@+break;
+case max_dead_cycles_code: print_esc(@[@<|"maxdeadcycles"|@>@]);@+break;
+case hang_after_code: print_esc(@[@<|"hangafter"|@>@]);@+break;
+case floating_penalty_code: print_esc(@[@<|"floatingpenalty"|@>@]);@+break;
+case global_defs_code: print_esc(@[@<|"globaldefs"|@>@]);@+break;
+case cur_fam_code: print_esc(@[@<|"fam"|@>@]);@+break;
+case escape_char_code: print_esc(@[@<|"escapechar"|@>@]);@+break;
+case default_hyphen_char_code: print_esc(@[@<|"defaulthyphenchar"|@>@]);@+break;
+case default_skew_char_code: print_esc(@[@<|"defaultskewchar"|@>@]);@+break;
+case end_line_char_code: print_esc(@[@<|"endlinechar"|@>@]);@+break;
+case new_line_char_code: print_esc(@[@<|"newlinechar"|@>@]);@+break;
+case language_code: print_esc(@[@<|"language"|@>@]);@+break;
+case left_hyphen_min_code: print_esc(@[@<|"lefthyphenmin"|@>@]);@+break;
+case right_hyphen_min_code: print_esc(@[@<|"righthyphenmin"|@>@]);@+break;
+case holding_inserts_code: print_esc(@[@<|"holdinginserts"|@>@]);@+break;
+case error_context_lines_code: print_esc(@[@<|"errorcontextlines"|@>@]);@+break;
+default:print_str("[unknown integer parameter!]");
+}
+}
+
+@ The integer parameter names must be entered into the hash table.
+
+@<Put each...@>=
+primitive(@[@<|"pretolerance"|@>@], assign_int, int_base+pretolerance_code);@/
+@!@:pretolerance_}{\.{\\pretolerance} primitive@>
+primitive(@[@<|"tolerance"|@>@], assign_int, int_base+tolerance_code);@/
+@!@:tolerance_}{\.{\\tolerance} primitive@>
+primitive(@[@<|"linepenalty"|@>@], assign_int, int_base+line_penalty_code);@/
+@!@:line_penalty_}{\.{\\linepenalty} primitive@>
+primitive(@[@<|"hyphenpenalty"|@>@], assign_int, int_base+hyphen_penalty_code);@/
+@!@:hyphen_penalty_}{\.{\\hyphenpenalty} primitive@>
+primitive(@[@<|"exhyphenpenalty"|@>@], assign_int, int_base+ex_hyphen_penalty_code);@/
+@!@:ex_hyphen_penalty_}{\.{\\exhyphenpenalty} primitive@>
+primitive(@[@<|"clubpenalty"|@>@], assign_int, int_base+club_penalty_code);@/
+@!@:club_penalty_}{\.{\\clubpenalty} primitive@>
+primitive(@[@<|"widowpenalty"|@>@], assign_int, int_base+widow_penalty_code);@/
+@!@:widow_penalty_}{\.{\\widowpenalty} primitive@>
+primitive(@[@<|"displaywidowpenalty"|@>@],
+ assign_int, int_base+display_widow_penalty_code);@/
+@!@:display_widow_penalty_}{\.{\\displaywidowpenalty} primitive@>
+primitive(@[@<|"brokenpenalty"|@>@], assign_int, int_base+broken_penalty_code);@/
+@!@:broken_penalty_}{\.{\\brokenpenalty} primitive@>
+primitive(@[@<|"binoppenalty"|@>@], assign_int, int_base+bin_op_penalty_code);@/
+@!@:bin_op_penalty_}{\.{\\binoppenalty} primitive@>
+primitive(@[@<|"relpenalty"|@>@], assign_int, int_base+rel_penalty_code);@/
+@!@:rel_penalty_}{\.{\\relpenalty} primitive@>
+primitive(@[@<|"predisplaypenalty"|@>@], assign_int, int_base+pre_display_penalty_code);@/
+@!@:pre_display_penalty_}{\.{\\predisplaypenalty} primitive@>
+primitive(@[@<|"postdisplaypenalty"|@>@], assign_int, int_base+post_display_penalty_code);@/
+@!@:post_display_penalty_}{\.{\\postdisplaypenalty} primitive@>
+primitive(@[@<|"interlinepenalty"|@>@], assign_int, int_base+inter_line_penalty_code);@/
+@!@:inter_line_penalty_}{\.{\\interlinepenalty} primitive@>
+primitive(@[@<|"doublehyphendemerits"|@>@],
+ assign_int, int_base+double_hyphen_demerits_code);@/
+@!@:double_hyphen_demerits_}{\.{\\doublehyphendemerits} primitive@>
+primitive(@[@<|"finalhyphendemerits"|@>@],
+ assign_int, int_base+final_hyphen_demerits_code);@/
+@!@:final_hyphen_demerits_}{\.{\\finalhyphendemerits} primitive@>
+primitive(@[@<|"adjdemerits"|@>@], assign_int, int_base+adj_demerits_code);@/
+@!@:adj_demerits_}{\.{\\adjdemerits} primitive@>
+primitive(@[@<|"mag"|@>@], assign_int, int_base+mag_code);@/
+@!@:mag_}{\.{\\mag} primitive@>
+primitive(@[@<|"delimiterfactor"|@>@], assign_int, int_base+delimiter_factor_code);@/
+@!@:delimiter_factor_}{\.{\\delimiterfactor} primitive@>
+primitive(@[@<|"looseness"|@>@], assign_int, int_base+looseness_code);@/
+@!@:looseness_}{\.{\\looseness} primitive@>
+primitive(@[@<|"time"|@>@], assign_int, int_base+time_code);@/
+@!@:time_}{\.{\\time} primitive@>
+primitive(@[@<|"day"|@>@], assign_int, int_base+day_code);@/
+@!@:day_}{\.{\\day} primitive@>
+primitive(@[@<|"month"|@>@], assign_int, int_base+month_code);@/
+@!@:month_}{\.{\\month} primitive@>
+primitive(@[@<|"year"|@>@], assign_int, int_base+year_code);@/
+@!@:year_}{\.{\\year} primitive@>
+primitive(@[@<|"showboxbreadth"|@>@], assign_int, int_base+show_box_breadth_code);@/
+@!@:show_box_breadth_}{\.{\\showboxbreadth} primitive@>
+primitive(@[@<|"showboxdepth"|@>@], assign_int, int_base+show_box_depth_code);@/
+@!@:show_box_depth_}{\.{\\showboxdepth} primitive@>
+primitive(@[@<|"hbadness"|@>@], assign_int, int_base+hbadness_code);@/
+@!@:hbadness_}{\.{\\hbadness} primitive@>
+primitive(@[@<|"vbadness"|@>@], assign_int, int_base+vbadness_code);@/
+@!@:vbadness_}{\.{\\vbadness} primitive@>
+primitive(@[@<|"pausing"|@>@], assign_int, int_base+pausing_code);@/
+@!@:pausing_}{\.{\\pausing} primitive@>
+primitive(@[@<|"tracingonline"|@>@], assign_int, int_base+tracing_online_code);@/
+@!@:tracing_online_}{\.{\\tracingonline} primitive@>
+primitive(@[@<|"tracingmacros"|@>@], assign_int, int_base+tracing_macros_code);@/
+@!@:tracing_macros_}{\.{\\tracingmacros} primitive@>
+primitive(@[@<|"tracingstats"|@>@], assign_int, int_base+tracing_stats_code);@/
+@!@:tracing_stats_}{\.{\\tracingstats} primitive@>
+primitive(@[@<|"tracingparagraphs"|@>@], assign_int, int_base+tracing_paragraphs_code);@/
+@!@:tracing_paragraphs_}{\.{\\tracingparagraphs} primitive@>
+primitive(@[@<|"tracingpages"|@>@], assign_int, int_base+tracing_pages_code);@/
+@!@:tracing_pages_}{\.{\\tracingpages} primitive@>
+primitive(@[@<|"tracingoutput"|@>@], assign_int, int_base+tracing_output_code);@/
+@!@:tracing_output_}{\.{\\tracingoutput} primitive@>
+primitive(@[@<|"tracinglostchars"|@>@], assign_int, int_base+tracing_lost_chars_code);@/
+@!@:tracing_lost_chars_}{\.{\\tracinglostchars} primitive@>
+primitive(@[@<|"tracingcommands"|@>@], assign_int, int_base+tracing_commands_code);@/
+@!@:tracing_commands_}{\.{\\tracingcommands} primitive@>
+primitive(@[@<|"tracingrestores"|@>@], assign_int, int_base+tracing_restores_code);@/
+@!@:tracing_restores_}{\.{\\tracingrestores} primitive@>
+primitive(@[@<|"uchyph"|@>@], assign_int, int_base+uc_hyph_code);@/
+@!@:uc_hyph_}{\.{\\uchyph} primitive@>
+primitive(@[@<|"outputpenalty"|@>@], assign_int, int_base+output_penalty_code);@/
+@!@:output_penalty_}{\.{\\outputpenalty} primitive@>
+primitive(@[@<|"maxdeadcycles"|@>@], assign_int, int_base+max_dead_cycles_code);@/
+@!@:max_dead_cycles_}{\.{\\maxdeadcycles} primitive@>
+primitive(@[@<|"hangafter"|@>@], assign_int, int_base+hang_after_code);@/
+@!@:hang_after_}{\.{\\hangafter} primitive@>
+primitive(@[@<|"floatingpenalty"|@>@], assign_int, int_base+floating_penalty_code);@/
+@!@:floating_penalty_}{\.{\\floatingpenalty} primitive@>
+primitive(@[@<|"globaldefs"|@>@], assign_int, int_base+global_defs_code);@/
+@!@:global_defs_}{\.{\\globaldefs} primitive@>
+primitive(@[@<|"fam"|@>@], assign_int, int_base+cur_fam_code);@/
+@!@:fam_}{\.{\\fam} primitive@>
+primitive(@[@<|"escapechar"|@>@], assign_int, int_base+escape_char_code);@/
+@!@:escape_char_}{\.{\\escapechar} primitive@>
+primitive(@[@<|"defaulthyphenchar"|@>@], assign_int, int_base+default_hyphen_char_code);@/
+@!@:default_hyphen_char_}{\.{\\defaulthyphenchar} primitive@>
+primitive(@[@<|"defaultskewchar"|@>@], assign_int, int_base+default_skew_char_code);@/
+@!@:default_skew_char_}{\.{\\defaultskewchar} primitive@>
+primitive(@[@<|"endlinechar"|@>@], assign_int, int_base+end_line_char_code);@/
+@!@:end_line_char_}{\.{\\endlinechar} primitive@>
+primitive(@[@<|"newlinechar"|@>@], assign_int, int_base+new_line_char_code);@/
+@!@:new_line_char_}{\.{\\newlinechar} primitive@>
+primitive(@[@<|"language"|@>@], assign_int, int_base+language_code);@/
+@!@:language_}{\.{\\language} primitive@>
+primitive(@[@<|"lefthyphenmin"|@>@], assign_int, int_base+left_hyphen_min_code);@/
+@!@:left_hyphen_min_}{\.{\\lefthyphenmin} primitive@>
+primitive(@[@<|"righthyphenmin"|@>@], assign_int, int_base+right_hyphen_min_code);@/
+@!@:right_hyphen_min_}{\.{\\righthyphenmin} primitive@>
+primitive(@[@<|"holdinginserts"|@>@], assign_int, int_base+holding_inserts_code);@/
+@!@:holding_inserts_}{\.{\\holdinginserts} primitive@>
+primitive(@[@<|"errorcontextlines"|@>@], assign_int, int_base+error_context_lines_code);@/
+@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case assign_int: if (chr_code < count_base) print_param(chr_code-int_base);
+ else{@+print_esc(@[@<|"count"|@>@]);print_int(chr_code-count_base);
+ } @+break;
+
+@ The integer parameters should really be initialized by a macro package;
+the following initialization does the minimum to keep \TeX\ from
+complete failure.
+@^null delimiter@>
+
+@<Initialize table entries...@>=
+for (k=int_base; k<=del_code_base-1; k++) eqtb[k].i=0;
+mag=1000;tolerance=10000;hang_after=1;max_dead_cycles=25;
+escape_char='\\';end_line_char=carriage_return;
+for (k=0; k<=255; k++) del_code(k)=-1;
+del_code('.')=0; /*this null delimiter is used in error recovery*/
+
+@ The following procedure, which is called just before \TeX\ initializes its
+input and output, establishes the initial values of the date and time.
+@^system dependencies@>
+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.
+
+@p void fix_date_and_time(void)
+{@+time=12*60; /*minutes since midnight*/
+day=4; /*fourth day of the month*/
+month=7; /*seventh month of the year*/
+year=1776; /*Anno Domini*/
+}
+
+@ @<Show equivalent |n|, in region 5@>=
+{@+if (n < count_base) print_param(n-int_base);
+else if (n < del_code_base)
+ {@+print_esc(@[@<|"count"|@>@]);print_int(n-count_base);
+ }
+else{@+print_esc(@[@<|"delcode"|@>@]);print_int(n-del_code_base);
+ }
+print_char('=');print_int(eqtb[n].i);
+}
+
+@ @<Set variable |c| to the current escape character@>=c=escape_char
+
+@ @<Character |s| is the current new-line character@>=s==new_line_char
+
+@ \TeX\ is occasionally supposed to print diagnostic information that
+goes only into the transcript file, unless |tracing_online| is positive.
+Here are two routines that adjust the destination of print commands:
+
+@p void begin_diagnostic(void) /*prepare to do some tracing*/
+{@+old_setting=selector;
+if ((tracing_online <= 0)&&(selector==term_and_log))
+ {@+decr(selector);
+ if (history==spotless) history=warning_issued;
+ }
+}
+@#
+void end_diagnostic(bool @!blank_line)
+ /*restore proper conditions after tracing*/
+{@+print_nl("");
+if (blank_line) print_ln();
+selector=old_setting;
+}
+
+@ Of course we had better declare another global variable, if the previous
+routines are going to work.
+
+@<Glob...@>=
+uint8_t @!old_setting;
+
+@ The final region of |eqtb| contains the dimension parameters defined
+here, and the 256 \.{\\dimen} registers.
+
+@d par_indent_code 0 /*indentation of paragraphs*/
+@d math_surround_code 1 /*space around math in text*/
+@d line_skip_limit_code 2 /*threshold for |line_skip| instead of |baseline_skip|*/
+@d hsize_code 3 /*line width in horizontal mode*/
+@d vsize_code 4 /*page height in vertical mode*/
+@d max_depth_code 5 /*maximum depth of boxes on main pages*/
+@d split_max_depth_code 6 /*maximum depth of boxes on split pages*/
+@d box_max_depth_code 7 /*maximum depth of explicit vboxes*/
+@d hfuzz_code 8 /*tolerance for overfull hbox messages*/
+@d vfuzz_code 9 /*tolerance for overfull vbox messages*/
+@d delimiter_shortfall_code 10 /*maximum amount uncovered by variable delimiters*/
+@d null_delimiter_space_code 11 /*blank space in null delimiters*/
+@d script_space_code 12 /*extra space after subscript or superscript*/
+@d pre_display_size_code 13 /*length of text preceding a display*/
+@d display_width_code 14 /*length of line for displayed equation*/
+@d display_indent_code 15 /*indentation of line for displayed equation*/
+@d overfull_rule_code 16 /*width of rule that identifies overfull hboxes*/
+@d hang_indent_code 17 /*amount of hanging indentation*/
+@d h_offset_code 18 /*amount of horizontal offset when shipping pages out*/
+@d v_offset_code 19 /*amount of vertical offset when shipping pages out*/
+@d emergency_stretch_code 20 /*reduces badnesses on final pass of line-breaking*/
+@d dimen_pars 21 /*total number of dimension parameters*/
+@d scaled_base (dimen_base+dimen_pars)
+ /*table of 256 user-defined \.{\\dimen} registers*/
+@d eqtb_size (scaled_base+255) /*largest subscript of |eqtb|*/
+@#
+@d dimen(X) eqtb[scaled_base+X].sc
+@d dimen_par(X) eqtb[dimen_base+X].sc /*a scaled quantity*/
+@d par_indent dimen_par(par_indent_code)
+@d math_surround dimen_par(math_surround_code)
+@d line_skip_limit dimen_par(line_skip_limit_code)
+@d hsize dimen_par(hsize_code)
+@d vsize dimen_par(vsize_code)
+@d max_depth dimen_par(max_depth_code)
+@d split_max_depth dimen_par(split_max_depth_code)
+@d box_max_depth dimen_par(box_max_depth_code)
+@d hfuzz dimen_par(hfuzz_code)
+@d vfuzz dimen_par(vfuzz_code)
+@d delimiter_shortfall dimen_par(delimiter_shortfall_code)
+@d null_delimiter_space dimen_par(null_delimiter_space_code)
+@d script_space dimen_par(script_space_code)
+@d pre_display_size dimen_par(pre_display_size_code)
+@d display_width dimen_par(display_width_code)
+@d display_indent dimen_par(display_indent_code)
+@d overfull_rule dimen_par(overfull_rule_code)
+@d hang_indent dimen_par(hang_indent_code)
+@d h_offset dimen_par(h_offset_code)
+@d v_offset dimen_par(v_offset_code)
+@d emergency_stretch dimen_par(emergency_stretch_code)
+
+@p void print_length_param(int @!n)
+{@+switch (n) {
+case par_indent_code: print_esc(@[@<|"parindent"|@>@]);@+break;
+case math_surround_code: print_esc(@[@<|"mathsurround"|@>@]);@+break;
+case line_skip_limit_code: print_esc(@[@<|"lineskiplimit"|@>@]);@+break;
+case hsize_code: print_esc(@[@<|"hsize"|@>@]);@+break;
+case vsize_code: print_esc(@[@<|"vsize"|@>@]);@+break;
+case max_depth_code: print_esc(@[@<|"maxdepth"|@>@]);@+break;
+case split_max_depth_code: print_esc(@[@<|"splitmaxdepth"|@>@]);@+break;
+case box_max_depth_code: print_esc(@[@<|"boxmaxdepth"|@>@]);@+break;
+case hfuzz_code: print_esc(@[@<|"hfuzz"|@>@]);@+break;
+case vfuzz_code: print_esc(@[@<|"vfuzz"|@>@]);@+break;
+case delimiter_shortfall_code: print_esc(@[@<|"delimitershortfall"|@>@]);@+break;
+case null_delimiter_space_code: print_esc(@[@<|"nulldelimiterspace"|@>@]);@+break;
+case script_space_code: print_esc(@[@<|"scriptspace"|@>@]);@+break;
+case pre_display_size_code: print_esc(@[@<|"predisplaysize"|@>@]);@+break;
+case display_width_code: print_esc(@[@<|"displaywidth"|@>@]);@+break;
+case display_indent_code: print_esc(@[@<|"displayindent"|@>@]);@+break;
+case overfull_rule_code: print_esc(@[@<|"overfullrule"|@>@]);@+break;
+case hang_indent_code: print_esc(@[@<|"hangindent"|@>@]);@+break;
+case h_offset_code: print_esc(@[@<|"hoffset"|@>@]);@+break;
+case v_offset_code: print_esc(@[@<|"voffset"|@>@]);@+break;
+case emergency_stretch_code: print_esc(@[@<|"emergencystretch"|@>@]);@+break;
+default:print_str("[unknown dimen parameter!]");
+}
+}
+
+@ @<Put each...@>=
+primitive(@[@<|"parindent"|@>@], assign_dimen, dimen_base+par_indent_code);@/
+@!@:par_indent_}{\.{\\parindent} primitive@>
+primitive(@[@<|"mathsurround"|@>@], assign_dimen, dimen_base+math_surround_code);@/
+@!@:math_surround_}{\.{\\mathsurround} primitive@>
+primitive(@[@<|"lineskiplimit"|@>@], assign_dimen, dimen_base+line_skip_limit_code);@/
+@!@:line_skip_limit_}{\.{\\lineskiplimit} primitive@>
+primitive(@[@<|"hsize"|@>@], assign_dimen, dimen_base+hsize_code);@/
+@!@:hsize_}{\.{\\hsize} primitive@>
+primitive(@[@<|"vsize"|@>@], assign_dimen, dimen_base+vsize_code);@/
+@!@:vsize_}{\.{\\vsize} primitive@>
+primitive(@[@<|"maxdepth"|@>@], assign_dimen, dimen_base+max_depth_code);@/
+@!@:max_depth_}{\.{\\maxdepth} primitive@>
+primitive(@[@<|"splitmaxdepth"|@>@], assign_dimen, dimen_base+split_max_depth_code);@/
+@!@:split_max_depth_}{\.{\\splitmaxdepth} primitive@>
+primitive(@[@<|"boxmaxdepth"|@>@], assign_dimen, dimen_base+box_max_depth_code);@/
+@!@:box_max_depth_}{\.{\\boxmaxdepth} primitive@>
+primitive(@[@<|"hfuzz"|@>@], assign_dimen, dimen_base+hfuzz_code);@/
+@!@:hfuzz_}{\.{\\hfuzz} primitive@>
+primitive(@[@<|"vfuzz"|@>@], assign_dimen, dimen_base+vfuzz_code);@/
+@!@:vfuzz_}{\.{\\vfuzz} primitive@>
+primitive(@[@<|"delimitershortfall"|@>@],
+ assign_dimen, dimen_base+delimiter_shortfall_code);@/
+@!@:delimiter_shortfall_}{\.{\\delimitershortfall} primitive@>
+primitive(@[@<|"nulldelimiterspace"|@>@],
+ assign_dimen, dimen_base+null_delimiter_space_code);@/
+@!@:null_delimiter_space_}{\.{\\nulldelimiterspace} primitive@>
+primitive(@[@<|"scriptspace"|@>@], assign_dimen, dimen_base+script_space_code);@/
+@!@:script_space_}{\.{\\scriptspace} primitive@>
+primitive(@[@<|"predisplaysize"|@>@], assign_dimen, dimen_base+pre_display_size_code);@/
+@!@:pre_display_size_}{\.{\\predisplaysize} primitive@>
+primitive(@[@<|"displaywidth"|@>@], assign_dimen, dimen_base+display_width_code);@/
+@!@:display_width_}{\.{\\displaywidth} primitive@>
+primitive(@[@<|"displayindent"|@>@], assign_dimen, dimen_base+display_indent_code);@/
+@!@:display_indent_}{\.{\\displayindent} primitive@>
+primitive(@[@<|"overfullrule"|@>@], assign_dimen, dimen_base+overfull_rule_code);@/
+@!@:overfull_rule_}{\.{\\overfullrule} primitive@>
+primitive(@[@<|"hangindent"|@>@], assign_dimen, dimen_base+hang_indent_code);@/
+@!@:hang_indent_}{\.{\\hangindent} primitive@>
+primitive(@[@<|"hoffset"|@>@], assign_dimen, dimen_base+h_offset_code);@/
+@!@:h_offset_}{\.{\\hoffset} primitive@>
+primitive(@[@<|"voffset"|@>@], assign_dimen, dimen_base+v_offset_code);@/
+@!@:v_offset_}{\.{\\voffset} primitive@>
+primitive(@[@<|"emergencystretch"|@>@], assign_dimen, dimen_base+emergency_stretch_code);@/
+@!@:emergency_stretch_}{\.{\\emergencystretch} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case assign_dimen: if (chr_code < scaled_base)
+ print_length_param(chr_code-dimen_base);
+ else{@+print_esc(@[@<|"dimen"|@>@]);print_int(chr_code-scaled_base);
+ } @+break;
+
+@ @<Initialize table entries...@>=
+for (k=dimen_base; k<=eqtb_size; k++) eqtb[k].sc=0;
+
+@ @<Show equivalent |n|, in region 6@>=
+{@+if (n < scaled_base) print_length_param(n-dimen_base);
+else{@+print_esc(@[@<|"dimen"|@>@]);print_int(n-scaled_base);
+ }
+print_char('=');print_scaled(eqtb[n].sc);print_str("pt");
+}
+
+@ Here is a procedure that displays the contents of |eqtb[n]|
+symbolically.
+
+@p@t\4@>@<Declare the procedure called |print_cmd_chr|@>@;@/
+#ifdef @!STAT
+void show_eqtb(pointer @!n)
+{@+if (n < active_base) print_char('?'); /*this can't happen*/
+else if (n < glue_base) @<Show equivalent |n|, in region 1 or 2@>@;
+else if (n < local_base) @<Show equivalent |n|, in region 3@>@;
+else if (n < int_base) @<Show equivalent |n|, in region 4@>@;
+else if (n < dimen_base) @<Show equivalent |n|, in region 5@>@;
+else if (n <= eqtb_size) @<Show equivalent |n|, in region 6@>@;
+else print_char('?'); /*this can't happen either*/
+}
+#endif
+
+@ The last two regions of |eqtb| have fullword values instead of the
+three fields |eq_level|, |eq_type|, and |equiv|. An |eq_type| is unnecessary,
+but \TeX\ needs to store the |eq_level| information in another array
+called |xeq_level|.
+
+@<Glob...@>=
+memory_word @!eqtb0[eqtb_size-active_base+1], *const @!eqtb = @!eqtb0-active_base;
+quarterword @!xeq_level0[eqtb_size-int_base+1], *const @!xeq_level = @!xeq_level0-int_base;
+
+@ @<Set init...@>=
+for (k=int_base; k<=eqtb_size; k++) xeq_level[k]=level_one;
+
+@ When the debugging routine |search_mem| is looking for pointers having a
+given value, it is interested only in regions 1 to~3 of~|eqtb|, and in the
+first part of region~4.
+
+@<Search |eqtb| for equivalents equal to |p|@>=
+for (q=active_base; q<=box_base+255; q++)
+ {@+if (equiv(q)==p)
+ {@+print_nl("EQUIV(");print_int(q);print_char(')');
+ }
+ }
+
+@* The hash table.
+Control sequences are stored and retrieved by means of a fairly standard hash
+table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
+in {\sl The Art of Computer Programming\/}). Once a control sequence enters the
+table, it is never removed, because there are complicated situations
+involving \.{\\gdef} where the removal of a control sequence at the end of
+a group would be a mistake preventable only by the introduction of a
+complicated reference-count mechanism.
+
+The actual sequence of letters forming a control sequence identifier is
+stored in the |str_pool| array together with all the other strings. An
+auxiliary array |hash| consists of items with two halfword fields per
+word. The first of these, called |next(p)|, points to the next identifier
+belonging to the same coalesced list as the identifier corresponding to~|p|;
+and the other, called |text(p)|, points to the |str_start| entry for
+|p|'s identifier. If position~|p| of the hash table is empty, we have
+|text(p)==0|; if position |p| is either empty or the end of a coalesced
+hash list, we have |next(p)==0|. An auxiliary pointer variable called
+|hash_used| is maintained in such a way that all locations |p >= hash_used|
+are nonempty. The global variable |cs_count| tells how many multiletter
+control sequences have been defined, if statistics are being kept.
+
+A global boolean variable called |no_new_control_sequence| is set to
+|true| during the time that new hash table entries are forbidden.
+
+@d next(X) hash[X].lh /*link for coalesced lists*/
+@d text(X) hash[X].rh /*string number for control sequence name*/
+@d hash_is_full (hash_used==hash_base) /*test if all positions are occupied*/
+@d font_id_text(X) text(font_id_base+X) /*a frozen font identifier's name*/
+
+@<Glob...@>=
+two_halves @!hash0[undefined_control_sequence-hash_base], *const @!hash = @!hash0-hash_base;
+ /*the hash table*/
+pointer @!hash_used; /*allocation pointer for |hash|*/
+bool @!no_new_control_sequence; /*are new identifiers legal?*/
+int @!cs_count; /*total number of known identifiers*/
+
+@ @<Set init...@>=
+no_new_control_sequence=true; /*new identifiers are usually forbidden*/
+next(hash_base)=0;text(hash_base)=0;
+for (k=hash_base+1; k<=undefined_control_sequence-1; k++) hash[k]=hash[hash_base];
+
+@ @<Initialize table entries...@>=
+hash_used=frozen_control_sequence; /*nothing is used*/
+cs_count=0;
+eq_type(frozen_dont_expand)=dont_expand;
+text(frozen_dont_expand)=@[@<|"notexpanded:"|@>@];
+@.notexpanded:@>
+
+@ Here is the subroutine that searches the hash table for an identifier
+that matches a given string of length |l > 1| appearing in |buffer[j dotdot
+(j+l-1)]|. If the identifier is found, the corresponding hash table address
+is returned. Otherwise, if the global variable |no_new_control_sequence|
+is |true|, the dummy address |undefined_control_sequence| is returned.
+Otherwise the identifier is inserted into the hash table and its location
+is returned.
+
+@p pointer id_lookup(int @!j, int @!l) /*search the hash table*/
+{@+ /*go here if you found it*/
+int h; /*hash code*/
+int @!d; /*number of characters in incomplete current string*/
+pointer @!p; /*index in |hash| array*/
+pointer @!k; /*index in |buffer| array*/
+@<Compute the hash code |h|@>;
+p=h+hash_base; /*we start searching here; note that |0 <= h < hash_prime|*/
+loop@+{@+if (text(p) > 0) if (length(text(p))==l)
+ if (str_eq_buf(text(p), j)) goto found;
+ if (next(p)==0)
+ {@+if (no_new_control_sequence)
+ p=undefined_control_sequence;
+ else@<Insert a new control sequence after |p|, then make |p| point to it@>;
+ goto found;
+ }
+ p=next(p);
+ }
+found: return p;
+}
+
+@ @<Insert a new control...@>=
+{@+if (text(p) > 0)
+ {@+@/do@+{if (hash_is_full) overflow("hash size", hash_size);
+@:TeX capacity exceeded hash size}{\quad hash size@>
+ decr(hash_used);
+ }@+ while (!(text(hash_used)==0)); /*search for an empty location in |hash|*/
+ next(p)=hash_used;p=hash_used;
+ }
+str_room(l);d=cur_length;
+while (pool_ptr > str_start[str_ptr])
+ {@+decr(pool_ptr);str_pool[pool_ptr+l]=str_pool[pool_ptr];
+ } /*move current string up to make room for another*/
+for (k=j; k<=j+l-1; k++) append_char(buffer[k]);
+text(p)=make_string();pool_ptr=pool_ptr+d;
+#ifdef @!STAT
+incr(cs_count);
+#endif
+@;@/
+}
+
+@ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
+should be a prime number. The theory of hashing tells us to expect fewer
+than two table probes, on the average, when the search is successful.
+[See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
+@^Vitter, Jeffrey Scott@>
+
+@<Compute the hash code |h|@>=
+h=buffer[j];
+for (k=j+1; k<=j+l-1; k++)
+ {@+h=h+h+buffer[k];
+ while (h >= hash_prime) h=h-hash_prime;
+ }
+
+@ Single-character control sequences do not need to be looked up in a hash
+table, since we can use the character code itself as a direct address.
+The procedure |print_cs| prints the name of a control sequence, given
+a pointer to its address in |eqtb|. A space is printed after the name
+unless it is a single nonletter or an active character. This procedure
+might be invoked with invalid data, so it is ``extra robust.'' The
+individual characters must be printed one at a time using |print|, since
+they may be unprintable.
+
+@<Basic printing...@>=
+void print_cs(int @!p) /*prints a purported control sequence*/
+{@+if (p < hash_base) /*single character*/
+ if (p >= single_base)
+ if (p==null_cs)
+ {@+print_esc(@[@<|"csname"|@>@]);print_esc(@[@<|"endcsname"|@>@]);print_char(' ');
+ }
+ else{@+print_esc(p-single_base);
+ if (cat_code(p-single_base)==letter) print_char(' ');
+ }
+ else if (p < active_base) print_esc(@[@<|"IMPOSSIBLE."|@>@]);
+@.IMPOSSIBLE@>
+ else print(p-active_base);
+else if (p >= undefined_control_sequence) print_esc(@[@<|"IMPOSSIBLE."|@>@]);
+else if ((text(p) < 0)||(text(p) >= str_ptr)) print_esc(@[@<|"NONEXISTENT."|@>@]);
+@.NONEXISTENT@>
+else{@+print_esc(text(p));
+ print_char(' ');
+ }
+}
+
+@ Here is a similar procedure; it avoids the error checks, and it never
+prints a space after the control sequence.
+
+@<Basic printing procedures@>=
+void sprint_cs(pointer @!p) /*prints a control sequence*/
+{@+if (p < hash_base)
+ if (p < single_base) print(p-active_base);
+ else if (p < null_cs) print_esc(p-single_base);
+ else{@+print_esc(@[@<|"csname"|@>@]);print_esc(@[@<|"endcsname"|@>@]);
+ }
+else print_esc(text(p));
+}
+
+@ We need to put \TeX's ``primitive'' control sequences into the hash
+table, together with their command code (which will be the |eq_type|)
+and an operand (which will be the |equiv|). The |primitive| procedure
+does this, in a way that no \TeX\ user can. The global value |cur_val|
+contains the new |eqtb| pointer after |primitive| has acted.
+
+@p
+#ifdef @!INIT
+void primitive(str_number @!s, quarterword @!c, halfword @!o)
+{@+pool_pointer k; /*index into |str_pool|*/
+int @!j; /*index into |buffer|*/
+small_number @!l; /*length of the string*/
+if (s < 256) cur_val=s+single_base;
+else{@+k=str_start[s];l=str_start[s+1]-k;
+ /*we will move |s| into the (empty) |buffer|*/
+ for (j=0; j<=l-1; j++) buffer[j]=so(str_pool[k+j]);
+ cur_val=id_lookup(0, l); /*|no_new_control_sequence| is |false|*/
+ flush_string;text(cur_val)=s; /*we don't want to have the string twice*/
+ }
+eq_level(cur_val)=level_one;eq_type(cur_val)=c;equiv(cur_val)=o;
+}
+#endif
+
+@ Many of \TeX's primitives need no |equiv|, since they are identifiable
+by their |eq_type| alone. These primitives are loaded into the hash table
+as follows:
+
+@<Put each of \TeX's primitives into the hash table@>=
+primitive(' ', ex_space, 0);@/
+@!@:Single-character primitives /}{\quad\.{\\\ }@>
+primitive('/', ital_corr, 0);@/
+@!@:Single-character primitives /}{\quad\.{\\/}@>
+primitive(@[@<|"accent"|@>@], accent, 0);@/
+@!@:accent_}{\.{\\accent} primitive@>
+primitive(@[@<|"advance"|@>@], advance, 0);@/
+@!@:advance_}{\.{\\advance} primitive@>
+primitive(@[@<|"afterassignment"|@>@], after_assignment, 0);@/
+@!@:after_assignment_}{\.{\\afterassignment} primitive@>
+primitive(@[@<|"aftergroup"|@>@], after_group, 0);@/
+@!@:after_group_}{\.{\\aftergroup} primitive@>
+primitive(@[@<|"begingroup"|@>@], begin_group, 0);@/
+@!@:begin_group_}{\.{\\begingroup} primitive@>
+primitive(@[@<|"char"|@>@], char_num, 0);@/
+@!@:char_}{\.{\\char} primitive@>
+primitive(@[@<|"csname"|@>@], cs_name, 0);@/
+@!@:cs_name_}{\.{\\csname} primitive@>
+primitive(@[@<|"delimiter"|@>@], delim_num, 0);@/
+@!@:delimiter_}{\.{\\delimiter} primitive@>
+primitive(@[@<|"divide"|@>@], divide, 0);@/
+@!@:divide_}{\.{\\divide} primitive@>
+primitive(@[@<|"endcsname"|@>@], end_cs_name, 0);@/
+@!@:end_cs_name_}{\.{\\endcsname} primitive@>
+primitive(@[@<|"endgroup"|@>@], end_group, 0);
+@!@:end_group_}{\.{\\endgroup} primitive@>
+text(frozen_end_group)=@[@<|"endgroup"|@>@];eqtb[frozen_end_group]=eqtb[cur_val];@/
+primitive(@[@<|"expandafter"|@>@], expand_after, 0);@/
+@!@:expand_after_}{\.{\\expandafter} primitive@>
+primitive(@[@<|"font"|@>@], def_font, 0);@/
+@!@:font_}{\.{\\font} primitive@>
+primitive(@[@<|"fontdimen"|@>@], assign_font_dimen, 0);@/
+@!@:font_dimen_}{\.{\\fontdimen} primitive@>
+primitive(@[@<|"halign"|@>@], halign, 0);@/
+@!@:halign_}{\.{\\halign} primitive@>
+primitive(@[@<|"hrule"|@>@], hrule, 0);@/
+@!@:hrule_}{\.{\\hrule} primitive@>
+primitive(@[@<|"ignorespaces"|@>@], ignore_spaces, 0);@/
+@!@:ignore_spaces_}{\.{\\ignorespaces} primitive@>
+primitive(@[@<|"insert"|@>@], insert, 0);@/
+@!@:insert_}{\.{\\insert} primitive@>
+primitive(@[@<|"mark"|@>@], mark, 0);@/
+@!@:mark_}{\.{\\mark} primitive@>
+primitive(@[@<|"mathaccent"|@>@], math_accent, 0);@/
+@!@:math_accent_}{\.{\\mathaccent} primitive@>
+primitive(@[@<|"mathchar"|@>@], math_char_num, 0);@/
+@!@:math_char_}{\.{\\mathchar} primitive@>
+primitive(@[@<|"mathchoice"|@>@], math_choice, 0);@/
+@!@:math_choice_}{\.{\\mathchoice} primitive@>
+primitive(@[@<|"multiply"|@>@], multiply, 0);@/
+@!@:multiply_}{\.{\\multiply} primitive@>
+primitive(@[@<|"noalign"|@>@], no_align, 0);@/
+@!@:no_align_}{\.{\\noalign} primitive@>
+primitive(@[@<|"noboundary"|@>@], no_boundary, 0);@/
+@!@:no_boundary_}{\.{\\noboundary} primitive@>
+primitive(@[@<|"noexpand"|@>@], no_expand, 0);@/
+@!@:no_expand_}{\.{\\noexpand} primitive@>
+primitive(@[@<|"nonscript"|@>@], non_script, 0);@/
+@!@:non_script_}{\.{\\nonscript} primitive@>
+primitive(@[@<|"omit"|@>@], omit, 0);@/
+@!@:omit_}{\.{\\omit} primitive@>
+primitive(@[@<|"parshape"|@>@], set_shape, 0);@/
+@!@:par_shape_}{\.{\\parshape} primitive@>
+primitive(@[@<|"penalty"|@>@], break_penalty, 0);@/
+@!@:penalty_}{\.{\\penalty} primitive@>
+primitive(@[@<|"prevgraf"|@>@], set_prev_graf, 0);@/
+@!@:prev_graf_}{\.{\\prevgraf} primitive@>
+primitive(@[@<|"radical"|@>@], radical, 0);@/
+@!@:radical_}{\.{\\radical} primitive@>
+primitive(@[@<|"read"|@>@], read_to_cs, 0);@/
+@!@:read_}{\.{\\read} primitive@>
+primitive(@[@<|"relax"|@>@], relax, 256); /*cf.\ |scan_file_name|*/
+@!@:relax_}{\.{\\relax} primitive@>
+text(frozen_relax)=@[@<|"relax"|@>@];eqtb[frozen_relax]=eqtb[cur_val];@/
+primitive(@[@<|"setbox"|@>@], set_box, 0);@/
+@!@:set_box_}{\.{\\setbox} primitive@>
+primitive(@[@<|"the"|@>@], the, 0);@/
+@!@:the_}{\.{\\the} primitive@>
+primitive(@[@<|"toks"|@>@], toks_register, 0);@/
+@!@:toks_}{\.{\\toks} primitive@>
+primitive(@[@<|"vadjust"|@>@], vadjust, 0);@/
+@!@:vadjust_}{\.{\\vadjust} primitive@>
+primitive(@[@<|"valign"|@>@], valign, 0);@/
+@!@:valign_}{\.{\\valign} primitive@>
+primitive(@[@<|"vcenter"|@>@], vcenter, 0);@/
+@!@:vcenter_}{\.{\\vcenter} primitive@>
+primitive(@[@<|"vrule"|@>@], vrule, 0);@/
+@!@:vrule_}{\.{\\vrule} primitive@>
+
+@ Each primitive has a corresponding inverse, so that it is possible to
+display the cryptic numeric contents of |eqtb| in symbolic form.
+Every call of |primitive| in this program is therefore accompanied by some
+straightforward code that forms part of the |print_cmd_chr| routine
+below.
+
+@<Cases of |print_cmd_chr|...@>=
+case accent: print_esc(@[@<|"accent"|@>@]);@+break;
+case advance: print_esc(@[@<|"advance"|@>@]);@+break;
+case after_assignment: print_esc(@[@<|"afterassignment"|@>@]);@+break;
+case after_group: print_esc(@[@<|"aftergroup"|@>@]);@+break;
+case assign_font_dimen: print_esc(@[@<|"fontdimen"|@>@]);@+break;
+case begin_group: print_esc(@[@<|"begingroup"|@>@]);@+break;
+case break_penalty: print_esc(@[@<|"penalty"|@>@]);@+break;
+case char_num: print_esc(@[@<|"char"|@>@]);@+break;
+case cs_name: print_esc(@[@<|"csname"|@>@]);@+break;
+case def_font: print_esc(@[@<|"font"|@>@]);@+break;
+case delim_num: print_esc(@[@<|"delimiter"|@>@]);@+break;
+case divide: print_esc(@[@<|"divide"|@>@]);@+break;
+case end_cs_name: print_esc(@[@<|"endcsname"|@>@]);@+break;
+case end_group: print_esc(@[@<|"endgroup"|@>@]);@+break;
+case ex_space: print_esc(' ');@+break;
+case expand_after: print_esc(@[@<|"expandafter"|@>@]);@+break;
+case halign: print_esc(@[@<|"halign"|@>@]);@+break;
+case hrule: print_esc(@[@<|"hrule"|@>@]);@+break;
+case ignore_spaces: print_esc(@[@<|"ignorespaces"|@>@]);@+break;
+case insert: print_esc(@[@<|"insert"|@>@]);@+break;
+case ital_corr: print_esc('/');@+break;
+case mark: print_esc(@[@<|"mark"|@>@]);@+break;
+case math_accent: print_esc(@[@<|"mathaccent"|@>@]);@+break;
+case math_char_num: print_esc(@[@<|"mathchar"|@>@]);@+break;
+case math_choice: print_esc(@[@<|"mathchoice"|@>@]);@+break;
+case multiply: print_esc(@[@<|"multiply"|@>@]);@+break;
+case no_align: print_esc(@[@<|"noalign"|@>@]);@+break;
+case no_boundary: print_esc(@[@<|"noboundary"|@>@]);@+break;
+case no_expand: print_esc(@[@<|"noexpand"|@>@]);@+break;
+case non_script: print_esc(@[@<|"nonscript"|@>@]);@+break;
+case omit: print_esc(@[@<|"omit"|@>@]);@+break;
+case radical: print_esc(@[@<|"radical"|@>@]);@+break;
+case read_to_cs: print_esc(@[@<|"read"|@>@]);@+break;
+case relax: print_esc(@[@<|"relax"|@>@]);@+break;
+case set_box: print_esc(@[@<|"setbox"|@>@]);@+break;
+case set_prev_graf: print_esc(@[@<|"prevgraf"|@>@]);@+break;
+case set_shape: print_esc(@[@<|"parshape"|@>@]);@+break;
+case the: print_esc(@[@<|"the"|@>@]);@+break;
+case toks_register: print_esc(@[@<|"toks"|@>@]);@+break;
+case vadjust: print_esc(@[@<|"vadjust"|@>@]);@+break;
+case valign: print_esc(@[@<|"valign"|@>@]);@+break;
+case vcenter: print_esc(@[@<|"vcenter"|@>@]);@+break;
+case vrule: print_esc(@[@<|"vrule"|@>@]);@+break;
+
+@ We will deal with the other primitives later, at some point in the program
+where their |eq_type| and |equiv| values are more meaningful. For example,
+the primitives for math mode will be loaded when we consider the routines
+that deal with formulas. It is easy to find where each particular
+primitive was treated by looking in the index at the end; for example, the
+section where |@[@<|"radical"|@>@]| entered |eqtb| is listed under `\.{\\radical}
+primitive'. (Primitives consisting of a single nonalphabetic character,
+@!like `\.{\\/}', are listed under `Single-character primitives'.)
+@!@^Single-character primitives@>
+
+Meanwhile, this is a convenient place to catch up on something we were unable
+to do before the hash table was defined:
+
+@<Print the font identifier for |font(p)|@>=
+print_esc(font_id_text(font(p)))
+
+@* Saving and restoring equivalents.
+The nested structure provided by `$\.{\char'173}\ldots\.{\char'175}$' groups
+in \TeX\ means that |eqtb| entries valid in outer groups should be saved
+and restored later if they are overridden inside the braces. When a new |eqtb|
+value is being assigned, the program therefore checks to see if the previous
+entry belongs to an outer level. In such a case, the old value is placed
+on the |save_stack| just before the new value enters |eqtb|. At the
+end of a grouping level, i.e., when the right brace is sensed, the
+|save_stack| is used to restore the outer values, and the inner ones are
+destroyed.
+
+Entries on the |save_stack| are of type |memory_word|. The top item on
+this stack is |save_stack[p]|, where |p==save_ptr-1|; it contains three
+fields called |save_type|, |save_level|, and |save_index|, and it is
+interpreted in one of four ways:
+
+\yskip\hangg 1) If |save_type(p)==restore_old_value|, then
+|save_index(p)| is a location in |eqtb| whose current value should
+be destroyed at the end of the current group and replaced by |save_stack[p-1]|.
+Furthermore if |save_index(p) >= int_base|, then |save_level(p)|
+should replace the corresponding entry in |xeq_level|.
+
+\yskip\hangg 2) If |save_type(p)==restore_zero|, then |save_index(p)|
+is a location in |eqtb| whose current value should be destroyed at the end
+of the current group, when it should be
+replaced by the current value of |eqtb[undefined_control_sequence]|.
+
+\yskip\hangg 3) If |save_type(p)==insert_token|, then |save_index(p)|
+is a token that should be inserted into \TeX's input when the current
+group ends.
+
+\yskip\hangg 4) If |save_type(p)==level_boundary|, then |save_level(p)|
+is a code explaining what kind of group we were previously in, and
+|save_index(p)| points to the level boundary word at the bottom of
+the entries for that group.
+
+@d save_type(X) save_stack[X].hh.b0 /*classifies a |save_stack| entry*/
+@d save_level(X) save_stack[X].hh.b1
+ /*saved level for regions 5 and 6, or group code*/
+@d save_index(X) save_stack[X].hh.rh
+ /*|eqtb| location or token or |save_stack| location*/
+@d restore_old_value 0 /*|save_type| when a value should be restored later*/
+@d restore_zero 1 /*|save_type| when an undefined entry should be restored*/
+@d insert_token 2 /*|save_type| when a token is being saved for later use*/
+@d level_boundary 3 /*|save_type| corresponding to beginning of group*/
+
+@ Here are the group codes that are used to discriminate between different
+kinds of groups. They allow \TeX\ to decide what special actions, if any,
+should be performed when a group ends.
+\def\grp{\.{\char'173...\char'175}}
+
+Some groups are not supposed to be ended by right braces. For example,
+the `\.\$' that begins a math formula causes a |math_shift_group| to
+be started, and this should be terminated by a matching `\.\$'. Similarly,
+a group that starts with \.{\\left} should end with \.{\\right}, and
+one that starts with \.{\\begingroup} should end with \.{\\endgroup}.
+
+@d bottom_level 0 /*group code for the outside world*/
+@d simple_group 1 /*group code for local structure only*/
+@d hbox_group 2 /*code for `\.{\\hbox}\grp'*/
+@d adjusted_hbox_group 3 /*code for `\.{\\hbox}\grp' in vertical mode*/
+@d vbox_group 4 /*code for `\.{\\vbox}\grp'*/
+@d vtop_group 5 /*code for `\.{\\vtop}\grp'*/
+@d align_group 6 /*code for `\.{\\halign}\grp', `\.{\\valign}\grp'*/
+@d no_align_group 7 /*code for `\.{\\noalign}\grp'*/
+@d output_group 8 /*code for output routine*/
+@d math_group 9 /*code for, e.g., `\.{\char'136}\grp'*/
+@d disc_group 10 /*code for `\.{\\discretionary}\grp\grp\grp'*/
+@d insert_group 11 /*code for `\.{\\insert}\grp', `\.{\\vadjust}\grp'*/
+@d vcenter_group 12 /*code for `\.{\\vcenter}\grp'*/
+@d math_choice_group 13 /*code for `\.{\\mathchoice}\grp\grp\grp\grp'*/
+@d semi_simple_group 14 /*code for `\.{\\begingroup...\\endgroup}'*/
+@d math_shift_group 15 /*code for `\.{\$...\$}'*/
+@d math_left_group 16 /*code for `\.{\\left...\\right}'*/
+@d max_group_code 16
+
+@<Types...@>=
+typedef uint8_t group_code; /*|save_level| for a level boundary*/
+
+@ The global variable |cur_group| keeps track of what sort of group we are
+currently in. Another global variable, |cur_boundary|, points to the
+topmost |level_boundary| word. And |cur_level| is the current depth of
+nesting. The routines are designed to preserve the condition that no entry
+in the |save_stack| or in |eqtb| ever has a level greater than |cur_level|.
+
+@ @<Glob...@>=
+memory_word @!save_stack[save_size+1];
+uint16_t @!save_ptr; /*first unused entry on |save_stack|*/
+uint16_t @!max_save_stack; /*maximum usage of save stack*/
+quarterword @!cur_level; /*current nesting level for groups*/
+group_code @!cur_group; /*current group type*/
+uint16_t @!cur_boundary; /*where the current level begins*/
+
+@ At this time it might be a good idea for the reader to review the introduction
+to |eqtb| that was given above just before the long lists of parameter names.
+Recall that the ``outer level'' of the program is |level_one|, since
+undefined control sequences are assumed to be ``defined'' at |level_zero|.
+
+@<Set init...@>=
+save_ptr=0;cur_level=level_one;cur_group=bottom_level;cur_boundary=0;
+max_save_stack=0;
+
+@ The following macro is used to test if there is room for up to six more
+entries on |save_stack|. By making a conservative test like this, we can
+get by with testing for overflow in only a few places.
+
+@d check_full_save_stack if (save_ptr > max_save_stack)
+ {@+max_save_stack=save_ptr;
+ if (max_save_stack > save_size-6) overflow("save size", save_size);
+@:TeX capacity exceeded save size}{\quad save size@>
+ }
+
+@ Procedure |new_save_level| is called when a group begins. The
+argument is a group identification code like `|hbox_group|'. After
+calling this routine, it is safe to put five more entries on |save_stack|.
+
+In some cases integer-valued items are placed onto the
+|save_stack| just below a |level_boundary| word, because this is a
+convenient place to keep information that is supposed to ``pop up'' just
+when the group has finished.
+For example, when `\.{\\hbox to 100pt}\grp' is being treated, the 100pt
+dimension is stored on |save_stack| just before |new_save_level| is
+called.
+
+We use the notation |saved(k)| to stand for an integer item that
+appears in location |save_ptr+k| of the save stack.
+
+@d saved(X) save_stack[save_ptr+X].i
+
+@p void new_save_level(group_code @!c) /*begin a new level of grouping*/
+{@+check_full_save_stack;
+save_type(save_ptr)=level_boundary;save_level(save_ptr)=cur_group;
+save_index(save_ptr)=cur_boundary;
+if (cur_level==max_quarterword) overflow("grouping levels",
+@:TeX capacity exceeded grouping levels}{\quad grouping levels@>
+ max_quarterword-min_quarterword);
+ /*quit if |(cur_level+1)| is too big to be stored in |eqtb|*/
+cur_boundary=save_ptr;incr(cur_level);incr(save_ptr);cur_group=c;
+}
+
+@ Just before an entry of |eqtb| is changed, the following procedure should
+be called to update the other data structures properly. It is important
+to keep in mind that reference counts in |mem| include references from
+within |save_stack|, so these counts must be handled carefully.
+@^reference counts@>
+
+@p void eq_destroy(memory_word @!w) /*gets ready to forget |w|*/
+{@+pointer q; /*|equiv| field of |w|*/
+switch (eq_type_field(w)) {
+case call: case long_call: case outer_call: case long_outer_call: delete_token_ref(equiv_field(w));@+break;
+case glue_ref: delete_glue_ref(equiv_field(w));@+break;
+case shape_ref: {@+q=equiv_field(w); /*we need to free a \.{\\parshape} block*/
+ if (q!=null) free_node(q, info(q)+info(q)+1);
+ } @+break; /*such a block is |2 n+1| words long, where |n==info(q)|*/
+case box_ref: flush_node_list(equiv_field(w));@+break;
+default:do_nothing;
+}
+}
+
+@ To save a value of |eqtb[p]| that was established at level |l|, we
+can use the following subroutine.
+
+@p void eq_save(pointer @!p, quarterword @!l) /*saves |eqtb[p]|*/
+{@+check_full_save_stack;
+if (l==level_zero) save_type(save_ptr)=restore_zero;
+else{@+save_stack[save_ptr]=eqtb[p];incr(save_ptr);
+ save_type(save_ptr)=restore_old_value;
+ }
+save_level(save_ptr)=l;save_index(save_ptr)=p;incr(save_ptr);
+}
+
+@ The procedure |eq_define| defines an |eqtb| entry having specified
+|eq_type| and |equiv| fields, and saves the former value if appropriate.
+This procedure is used only for entries in the first four regions of |eqtb|,
+i.e., only for entries that have |eq_type| and |equiv| fields.
+After calling this routine, it is safe to put four more entries on
+|save_stack|, provided that there was room for four more entries before
+the call, since |eq_save| makes the necessary test.
+
+@p void eq_define(pointer @!p, quarterword @!t, halfword @!e)
+ /*new data for |eqtb|*/
+{@+if (eq_level(p)==cur_level) eq_destroy(eqtb[p]);
+else if (cur_level > level_one) eq_save(p, eq_level(p));
+eq_level(p)=cur_level;eq_type(p)=t;equiv(p)=e;
+}
+
+@ The counterpart of |eq_define| for the remaining (fullword) positions in
+|eqtb| is called |eq_word_define|. Since |xeq_level[p] >= level_one| for all
+|p|, a `|restore_zero|' will never be used in this case.
+
+@p void eq_word_define(pointer @!p, int @!w)
+{@+if (xeq_level[p]!=cur_level)
+ {@+eq_save(p, xeq_level[p]);xeq_level[p]=cur_level;
+ }
+eqtb[p].i=w;
+}
+
+@ The |eq_define| and |eq_word_define| routines take care of local definitions.
+@^global definitions@>
+Global definitions are done in almost the same way, but there is no need
+to save old values, and the new value is associated with |level_one|.
+
+@p void geq_define(pointer @!p, quarterword @!t, halfword @!e)
+ /*global |eq_define|*/
+{@+eq_destroy(eqtb[p]);
+eq_level(p)=level_one;eq_type(p)=t;equiv(p)=e;
+}
+@#
+void geq_word_define(pointer @!p, int @!w) /*global |eq_word_define|*/
+{@+eqtb[p].i=w;xeq_level[p]=level_one;
+}
+
+@ Subroutine |save_for_after| puts a token on the stack for save-keeping.
+
+@p void save_for_after(halfword @!t)
+{@+if (cur_level > level_one)
+ {@+check_full_save_stack;
+ save_type(save_ptr)=insert_token;save_level(save_ptr)=level_zero;
+ save_index(save_ptr)=t;incr(save_ptr);
+ }
+}
+
+@ The |unsave| routine goes the other way, taking items off of |save_stack|.
+This routine takes care of restoration when a level ends; everything
+belonging to the topmost group is cleared off of the save stack.
+
+@p@t\4@>@<Declare the procedure called |restore_trace|@>@;@/
+void back_input(void);
+void unsave(void) /*pops the top level off the save stack*/
+{@+
+pointer p; /*position to be restored*/
+quarterword @!l; /*saved level, if in fullword regions of |eqtb|*/
+halfword @!t; /*saved value of |cur_tok|*/
+if (cur_level > level_one)
+ {@+decr(cur_level);
+ @<Clear off top level from |save_stack|@>;
+ }
+else confusion(@[@<|"curlevel"|@>@]); /*|unsave| is not used when |cur_group==bottom_level|*/
+@:this can't happen curlevel}{\quad curlevel@>
+}
+
+@ @<Clear off...@>=
+loop@+{@+decr(save_ptr);
+ if (save_type(save_ptr)==level_boundary) goto done;
+ p=save_index(save_ptr);
+ if (save_type(save_ptr)==insert_token)
+ @<Insert token |p| into \TeX's input@>@;
+ else{@+if (save_type(save_ptr)==restore_old_value)
+ {@+l=save_level(save_ptr);decr(save_ptr);
+ }
+ else save_stack[save_ptr]=eqtb[undefined_control_sequence];
+ @<Store \(s)|save_stack[save_ptr]| in |eqtb[p]|, unless |eqtb[p]| holds a global
+value@>;
+ }
+ }
+done: cur_group=save_level(save_ptr);cur_boundary=save_index(save_ptr)
+
+@ A global definition, which sets the level to |level_one|,
+@^global definitions@>
+will not be undone by |unsave|. If at least one global definition of
+|eqtb[p]| has been carried out within the group that just ended, the
+last such definition will therefore survive.
+
+@<Store \(s)|save...@>=
+if (p < int_base)
+ if (eq_level(p)==level_one)
+ {@+eq_destroy(save_stack[save_ptr]); /*destroy the saved value*/
+
+#ifdef @!STAT
+if (tracing_restores > 0) restore_trace(p,@[@<|"retaining"|@>@]);
+#endif
+@;@/
+ }
+ else{@+eq_destroy(eqtb[p]); /*destroy the current value*/
+ eqtb[p]=save_stack[save_ptr]; /*restore the saved value*/
+
+#ifdef @!STAT
+if (tracing_restores > 0) restore_trace(p,@[@<|"restoring"|@>@]);
+#endif
+@;@/
+ }
+else if (xeq_level[p]!=level_one)
+ {@+eqtb[p]=save_stack[save_ptr];xeq_level[p]=l;
+
+#ifdef @!STAT
+if (tracing_restores > 0) restore_trace(p,@[@<|"restoring"|@>@]);
+#endif
+@;@/
+ }
+else{
+
+#ifdef @!STAT
+if (tracing_restores > 0) restore_trace(p,@[@<|"retaining"|@>@]);
+#endif
+@;@/
+ }
+
+@ @<Declare the procedure called |restore_trace|@>=
+#ifdef @!STAT
+void restore_trace(pointer @!p, str_number @!s)
+ /*|eqtb[p]| has just been restored or retained*/
+{@+begin_diagnostic();print_char('{');print(s);print_char(' ');
+show_eqtb(p);print_char('}');
+end_diagnostic(false);
+}
+#endif
+
+@ When looking for possible pointers to a memory location, it is helpful
+to look for references from |eqtb| that might be waiting on the
+save stack. Of course, we might find spurious pointers too; but this
+routine is merely an aid when debugging, and at such times we are
+grateful for any scraps of information, even if they prove to be irrelevant.
+@^dirty \PASCAL@>
+
+@<Search |save_stack| for equivalents that point to |p|@>=
+if (save_ptr > 0) for (q=0; q<=save_ptr-1; q++)
+ {@+if (equiv_field(save_stack[q])==p)
+ {@+print_nl("SAVE(");print_int(q);print_char(')');
+ }
+ }
+
+@ Most of the parameters kept in |eqtb| can be changed freely, but there's
+an exception: The magnification should not be used with two different
+values during any \TeX\ job, since a single magnification is applied to an
+entire run. The global variable |mag_set| is set to the current magnification
+whenever it becomes necessary to ``freeze'' it at a particular value.
+
+@<Glob...@>=
+int @!mag_set; /*if nonzero, this magnification should be used henceforth*/
+
+@ @<Set init...@>=
+mag_set=0;
+
+@ The |prepare_mag| subroutine is called whenever \TeX\ wants to use |mag|
+for magnification.
+
+@p void prepare_mag(void)
+{@+if ((mag_set > 0)&&(mag!=mag_set))
+ {@+print_err("Incompatible magnification (");print_int(mag);
+@.Incompatible magnification@>
+ print_str(");");print_nl(" the previous value will be retained");
+ help2("I can handle only one magnification ratio per job. So I've")@/
+ ("reverted to the magnification you used earlier on this run.");@/
+ int_error(mag_set);
+ geq_word_define(int_base+mag_code, mag_set); /*|mag=mag_set|*/
+ }
+if ((mag <= 0)||(mag > 32768))
+ {@+print_err("Illegal magnification has been changed to 1000");@/
+@.Illegal magnification...@>
+ help1("The magnification ratio must be between 1 and 32768.");
+ int_error(mag);geq_word_define(int_base+mag_code, 1000);
+ }
+mag_set=mag;
+}
+
+@* Token lists.
+A \TeX\ token is either a character or a control sequence, and it is
+@^token@>
+represented internally in one of two ways: (1)~A character whose ASCII
+code number is |c| and whose command code is |m| is represented as the
+number $2^8m+c$; the command code is in the range |1 <= m <= 14|. (2)~A control
+sequence whose |eqtb| address is |p| is represented as the number
+|cs_token_flag+p|. Here |cs_token_flag==@t$2^{12}-1$@>| is larger than
+$2^8m+c$, yet it is small enough that |cs_token_flag+p < max_halfword|;
+thus, a token fits comfortably in a halfword.
+
+A token |t| represents a |left_brace| command if and only if
+|t < left_brace_limit|; it represents a |right_brace| command if and only if
+we have |left_brace_limit <= t < right_brace_limit|; and it represents a |match| or
+|end_match| command if and only if |match_token <= t <= end_match_token|.
+The following definitions take care of these token-oriented constants
+and a few others.
+
+@d cs_token_flag 07777 /*amount added to the |eqtb| location in a
+ token that stands for a control sequence; is a multiple of~256, less~1*/
+@d left_brace_token 00400 /*$2^8\cdot|left_brace|$*/
+@d left_brace_limit 01000 /*$2^8\cdot(|left_brace|+1)$*/
+@d right_brace_token 01000 /*$2^8\cdot|right_brace|$*/
+@d right_brace_limit 01400 /*$2^8\cdot(|right_brace|+1)$*/
+@d math_shift_token 01400 /*$2^8\cdot|math_shift|$*/
+@d tab_token 02000 /*$2^8\cdot|tab_mark|$*/
+@d out_param_token 02400 /*$2^8\cdot|out_param|$*/
+@d space_token 05040 /*$2^8\cdot|spacer|+|' '|$*/
+@d letter_token 05400 /*$2^8\cdot|letter|$*/
+@d other_token 06000 /*$2^8\cdot|other_char|$*/
+@d match_token 06400 /*$2^8\cdot|match|$*/
+@d end_match_token 07000 /*$2^8\cdot|end_match|$*/
+
+@ @<Check the ``constant''...@>=
+if (cs_token_flag+undefined_control_sequence > max_halfword) bad=21;
+
+@ A token list is a singly linked list of one-word nodes in |mem|, where
+each word contains a token and a link. Macro definitions, output-routine
+definitions, marks, \.{\\write} texts, and a few other things
+are remembered by \TeX\ in the form
+of token lists, usually preceded by a node with a reference count in its
+|token_ref_count| field. The token stored in location |p| is called
+|info(p)|.
+
+Three special commands appear in the token lists of macro definitions.
+When |m==match|, it means that \TeX\ should scan a parameter
+for the current macro; when |m==end_match|, it means that parameter
+matching should end and \TeX\ should start reading the macro text; and
+when |m==out_param|, it means that \TeX\ should insert parameter
+number |c| into the text at this point.
+
+The enclosing \.{\char'173} and \.{\char'175} characters of a macro
+definition are omitted, but the final right brace of an output routine
+is included at the end of its token list.
+
+Here is an example macro definition that illustrates these conventions.
+After \TeX\ processes the text
+$$\.{\\def\\mac a\#1\#2 \\b \{\#1\\-a \#\#1\#2 \#2\}}$$
+the definition of \.{\\mac} is represented as a token list containing
+$$\def\,{\hskip2pt}
+\vbox{\halign{\hfil#\hfil\cr
+(reference count), |letter|\,\.a, |match|\,\#, |match|\,\#, |spacer|\,\.\ ,
+\.{\\b}, |end_match|,\cr
+|out_param|\,1, \.{\\-}, |letter|\,\.a, |spacer|\,\.\ , |mac_param|\,\#,
+|other_char|\,\.1,\cr
+|out_param|\,2, |spacer|\,\.\ , |out_param|\,2.\cr}}$$
+The procedure |scan_toks| builds such token lists, and |macro_call|
+does the parameter matching.
+@^reference counts@>
+
+Examples such as
+$$\.{\\def\\m\{\\def\\m\{a\}\ b\}}$$
+explain why reference counts would be needed even if \TeX\ had no \.{\\let}
+operation: When the token list for \.{\\m} is being read, the redefinition of
+\.{\\m} changes the |eqtb| entry before the token list has been fully
+consumed, so we dare not simply destroy a token list when its
+control sequence is being redefined.
+
+If the parameter-matching part of a definition ends with `\.{\#\{}',
+the corresponding token list will have `\.\{' just before the `|end_match|'
+and also at the very end. The first `\.\{' is used to delimit the parameter; the
+second one keeps the first from disappearing.
+
+@ The procedure |show_token_list|, which prints a symbolic form of
+the token list that starts at a given node |p|, illustrates these
+conventions. The token list being displayed should not begin with a reference
+count. However, the procedure is intended to be robust, so that if the
+memory links are awry or if |p| is not really a pointer to a token list,
+nothing catastrophic will happen.
+
+An additional parameter |q| is also given; this parameter is either null
+or it points to a node in the token list where a certain magic computation
+takes place that will be explained later. (Basically, |q| is non-null when
+we are printing the two-line context information at the time of an error
+message; |q| marks the place corresponding to where the second line
+should begin.)
+
+For example, if |p| points to the node containing the first \.a in the
+token list above, then |show_token_list| will print the string
+$$\hbox{`\.{a\#1\#2\ \\b\ ->\#1\\-a\ \#\#1\#2\ \#2}';}$$
+and if |q| points to the node containing the second \.a,
+the magic computation will be performed just before the second \.a is printed.
+
+The generation will stop, and `\.{\\ETC.}' will be printed, if the length
+of printing exceeds a given limit~|l|. Anomalous entries are printed in the
+form of control sequences that are not followed by a blank space, e.g.,
+`\.{\\BAD.}'; this cannot be confused with actual control sequences because
+a real control sequence named \.{BAD} would come out `\.{\\BAD\ }'.
+
+@<Declare the procedure called |show_token_list|@>=
+void show_token_list(int @!p, int @!q, int @!l)
+{@+
+int m, @!c; /*pieces of a token*/
+ASCII_code @!match_chr; /*character used in a `|match|'*/
+ASCII_code @!n; /*the highest parameter number, as an ASCII digit*/
+match_chr='#';n='0';tally=0;
+while ((p!=null)&&(tally < l))
+ {@+if (p==q) @<Do magic computation@>;
+ @<Display token |p|, and |return| if there are problems@>;
+ p=link(p);
+ }
+if (p!=null) print_esc(@[@<|"ETC."|@>@]);
+@.ETC@>
+
+}
+
+@ @<Display token |p|...@>=
+if ((p < hi_mem_min)||(p > mem_end))
+ {@+print_esc(@[@<|"CLOBBERED."|@>@]);return;
+@.CLOBBERED@>
+ }
+if (info(p) >= cs_token_flag) print_cs(info(p)-cs_token_flag);
+else{@+m=info(p)/0400;c=info(p)%0400;
+ if (info(p) < 0) print_esc(@[@<|"BAD."|@>@]);
+@.BAD@>
+ else@<Display the token $(|m|,|c|)$@>;
+ }
+
+@ The procedure usually ``learns'' the character code used for macro
+parameters by seeing one in a |match| command before it runs into any
+|out_param| commands.
+
+@<Display the token...@>=
+switch (m) {
+case left_brace: case right_brace: case math_shift: case tab_mark: case sup_mark: case sub_mark: case spacer:
+ case letter: case other_char: print(c);@+break;
+case mac_param: {@+print(c);print(c);
+ } @+break;
+case out_param: {@+print(match_chr);
+ if (c <= 9) print_char(c+'0');
+ else{@+print_char('!');return;
+ }
+ } @+break;
+case match: {@+match_chr=c;print(c);incr(n);print_char(n);
+ if (n > '9') return;
+ } @+break;
+case end_match: print_str("->");@+break;
+@.->@>
+default:print_esc(@[@<|"BAD."|@>@]);
+@.BAD@>
+}
+
+@ Here's the way we sometimes want to display a token list, given a pointer
+to its reference count; the pointer may be null.
+
+@p void token_show(pointer @!p)
+{@+if (p!=null) show_token_list(link(p), null, 10000000);
+}
+
+@ The |print_meaning| subroutine displays |cur_cmd| and |cur_chr| in
+symbolic form, including the expansion of a macro or mark.
+
+@p void print_meaning(void)
+{@+print_cmd_chr(cur_cmd, cur_chr);
+if (cur_cmd >= call)
+ {@+print_char(':');print_ln();token_show(cur_chr);
+ }
+else if (cur_cmd==top_bot_mark)
+ {@+print_char(':');print_ln();
+ token_show(cur_mark[cur_chr]);
+ }
+}
+
+@* Introduction to the syntactic routines.
+Let's pause a moment now and try to look at the Big Picture.
+The \TeX\ program consists of three main parts: syntactic routines,
+semantic routines, and output routines. The chief purpose of the
+syntactic routines is to deliver the user's input to the semantic routines,
+one token at a time. The semantic routines act as an interpreter
+responding to these tokens, which may be regarded as commands. And the
+output routines are periodically called on to convert box-and-glue
+lists into a compact set of instructions that will be sent
+to a typesetter. We have discussed the basic data structures and utility
+routines of \TeX, so we are good and ready to plunge into the real activity by
+considering the syntactic routines.
+
+Our current goal is to come to grips with the |get_next| procedure,
+which is the keystone of \TeX's input mechanism. Each call of |get_next|
+sets the value of three variables |cur_cmd|, |cur_chr|, and |cur_cs|,
+representing the next input token.
+$$\vbox{\halign{#\hfil\cr
+ \hbox{|cur_cmd| denotes a command code from the long list of codes
+ given above;}\cr
+ \hbox{|cur_chr| denotes a character code or other modifier of the command
+ code;}\cr
+ \hbox{|cur_cs| is the |eqtb| location of the current control sequence,}\cr
+ \hbox{\qquad if the current token was a control sequence,
+ otherwise it's zero.}\cr}}$$
+Underlying this external behavior of |get_next| is all the machinery
+necessary to convert from character files to tokens. At a given time we
+may be only partially finished with the reading of several files (for
+which \.{\\input} was specified), and partially finished with the expansion
+of some user-defined macros and/or some macro parameters, and partially
+finished with the generation of some text in a template for \.{\\halign},
+and so on. When reading a character file, special characters must be
+classified as math delimiters, etc.; comments and extra blank spaces must
+be removed, paragraphs must be recognized, and control sequences must be
+found in the hash table. Furthermore there are occasions in which the
+scanning routines have looked ahead for a word like `\.{plus}' but only
+part of that word was found, hence a few characters must be put back
+into the input and scanned again.
+
+To handle these situations, which might all be present simultaneously,
+\TeX\ uses various stacks that hold information about the incomplete
+activities, and there is a finite state control for each level of the
+input mechanism. These stacks record the current state of an implicitly
+recursive process, but the |get_next| procedure is not recursive.
+Therefore it will not be difficult to translate these algorithms into
+low-level languages that do not support recursion.
+
+@<Glob...@>=
+eight_bits @!cur_cmd; /*current command set by |get_next|*/
+halfword @!cur_chr; /*operand of current command*/
+pointer @!cur_cs; /*control sequence found here, zero if none found*/
+halfword @!cur_tok; /*packed representative of |cur_cmd| and |cur_chr|*/
+
+@ The |print_cmd_chr| routine prints a symbolic interpretation of a
+command code and its modifier. This is used in certain `\.{You can\'t}'
+error messages, and in the implementation of diagnostic routines like
+\.{\\show}.
+
+The body of |print_cmd_chr| is a rather tedious listing of print
+commands, and most of it is essentially an inverse to the |primitive|
+routine that enters a \TeX\ primitive into |eqtb|. Therefore much of
+this procedure appears elsewhere in the program,
+together with the corresponding |primitive| calls.
+
+@d chr_cmd(X) {@+print_str(X);print_ASCII(chr_code);
+ }
+
+@<Declare the procedure called |print_cmd_chr|@>=
+void print_cmd_chr(quarterword @!cmd, halfword @!chr_code)
+{@+switch (cmd) {
+case left_brace: chr_cmd("begin-group character ")@;@+break;
+case right_brace: chr_cmd("end-group character ")@;@+break;
+case math_shift: chr_cmd("math shift character ")@;@+break;
+case mac_param: chr_cmd("macro parameter character ")@;@+break;
+case sup_mark: chr_cmd("superscript character ")@;@+break;
+case sub_mark: chr_cmd("subscript character ")@;@+break;
+case endv: print_str("end of alignment template");@+break;
+case spacer: chr_cmd("blank space ")@;@+break;
+case letter: chr_cmd("the letter ")@;@+break;
+case other_char: chr_cmd("the character ")@;@+break;
+@t\4@>@<Cases of |print_cmd_chr| for symbolic printing of primitives@>@;
+default:print_str("[unknown command code!]");
+}
+}
+
+@ Here is a procedure that displays the current command.
+
+@p void show_cur_cmd_chr(void)
+{@+begin_diagnostic();print_nl("{");
+if (mode!=shown_mode)
+ {@+print_mode(mode);print_str(": ");shown_mode=mode;
+ }
+print_cmd_chr(cur_cmd, cur_chr);print_char('}');
+end_diagnostic(false);
+}
+
+@* Input stacks and states.
+This implementation of
+\TeX\ uses two different conventions for representing sequential stacks.
+@^stack conventions@>@^conventions for representing stacks@>
+
+\yskip\hangg 1) If there is frequent access to the top entry, and if the
+stack is essentially never empty, then the top entry is kept in a global
+variable (even better would be a machine register), and the other entries
+appear in the array $\\{stack}[0\to(\\{ptr}-1)]$. For example, the
+semantic stack described above is handled this way, and so is the input
+stack that we are about to study.
+
+\yskip\hangg 2) If there is infrequent top access, the entire stack contents
+are in the array $\\{stack}[0\to(\\{ptr}-1)]$. For example, the |save_stack|
+is treated this way, as we have seen.
+
+\yskip\noindent
+The state of \TeX's input mechanism appears in the input stack, whose
+entries are records with six fields, called |state|, |index|, |start|, |loc|,
+|limit|, and |name|. This stack is maintained with
+convention~(1), so it is declared in the following way:
+
+@<Types...@>=
+typedef struct {
+ quarterword @!state_field, @!index_field;
+ halfword @!start_field, @!loc_field, @!limit_field, @!name_field;
+ } in_state_record;
+
+@ @<Glob...@>=
+in_state_record @!input_stack[stack_size+1];
+uint8_t @!input_ptr; /*first unused location of |input_stack|*/
+uint8_t @!max_in_stack; /*largest value of |input_ptr| when pushing*/
+in_state_record @!cur_input;
+ /*the ``top'' input state, according to convention (1)*/
+
+@ We've already defined the special variable |loc====cur_input.loc_field|
+in our discussion of basic input-output routines. The other components of
+|cur_input| are defined in the same way:
+
+@d state cur_input.state_field /*current scanner state*/
+@d index cur_input.index_field /*reference for buffer information*/
+@d start cur_input.start_field /*starting position in |buffer|*/
+@d limit cur_input.limit_field /*end of current line in |buffer|*/
+@d name cur_input.name_field /*name of the current file*/
+
+@ Let's look more closely now at the control variables
+(|state|,~|index|,~|start|,~|loc|,~|limit|,~|name|),
+assuming that \TeX\ is reading a line of characters that have been input
+from some file or from the user's terminal. There is an array called
+|buffer| that acts as a stack of all lines of characters that are
+currently being read from files, including all lines on subsidiary
+levels of the input stack that are not yet completed. \TeX\ will return to
+the other lines when it is finished with the present input file.
+
+(Incidentally, on a machine with byte-oriented addressing, it might be
+appropriate to combine |buffer| with the |str_pool| array,
+letting the buffer entries grow downward from the top of the string pool
+and checking that these two tables don't bump into each other.)
+
+The line we are currently working on begins in position |start| of the
+buffer; the next character we are about to read is |buffer[loc]|; and
+|limit| is the location of the last character present. If |loc > limit|,
+the line has been completely read. Usually |buffer[limit]| is the
+|end_line_char|, denoting the end of a line, but this is not
+true if the current line is an insertion that was entered on the user's
+terminal in response to an error message.
+
+The |name| variable is a string number that designates the name of
+the current file, if we are reading a text file. It is zero if we
+are reading from the terminal; it is |n+1| if we are reading from
+input stream |n|, where |0 <= n <= 16|. (Input stream 16 stands for
+an invalid stream number; in such cases the input is actually from
+the terminal, under control of the procedure |read_toks|.)
+
+The |state| variable has one of three values, when we are scanning such
+files:
+$$\baselineskip 15pt\vbox{\halign{#\hfil\cr
+1) |state==mid_line| is the normal state.\cr
+2) |state==skip_blanks| is like |mid_line|, but blanks are ignored.\cr
+3) |state==new_line| is the state at the beginning of a line.\cr}}$$
+These state values are assigned numeric codes so that if we add the state
+code to the next character's command code, we get distinct values. For
+example, `|mid_line+spacer|' stands for the case that a blank
+space character occurs in the middle of a line when it is not being
+ignored; after this case is processed, the next value of |state| will
+be |skip_blanks|.
+
+@d mid_line 1 /*|state| code when scanning a line of characters*/
+@d skip_blanks (2+max_char_code) /*|state| code when ignoring blanks*/
+@d new_line (3+max_char_code+max_char_code) /*|state| code at start of line*/
+
+@ Additional information about the current line is available via the
+|index| variable, which counts how many lines of characters are present
+in the buffer below the current level. We have |index==0| when reading
+from the terminal and prompting the user for each line; then if the user types,
+e.g., `\.{\\input paper}', we will have |index==1| while reading
+the file \.{paper.tex}. However, it does not follow that |index| is the
+same as the input stack pointer, since many of the levels on the input
+stack may come from token lists. For example, the instruction `\.{\\input
+paper}' might occur in a token list.
+
+The global variable |in_open| is equal to the |index|
+value of the highest non-token-list level. Thus, the number of partially read
+lines in the buffer is |in_open+1|, and we have |in_open==index|
+when we are not reading a token list.
+
+If we are not currently reading from the terminal, or from an input
+stream, we are reading from the file variable |input_file[index]|. We use
+the notation |terminal_input| as a convenient abbreviation for |name==0|,
+and |cur_file| as an abbreviation for |input_file[index]|.
+
+The global variable |line| contains the line number in the topmost
+open file, for use in error messages. If we are not reading from
+the terminal, |line_stack[index]| holds the line number for the
+enclosing level, so that |line| can be restored when the current
+file has been read. Line numbers should never be negative, since the
+negative of the current line number is used to identify the user's output
+routine in the |mode_line| field of the semantic nest entries.
+
+If more information about the input state is needed, it can be
+included in small arrays like those shown here. For example,
+the current page or segment number in the input file might be
+put into a variable |@!page|, maintained for enclosing levels in
+`\ignorespaces|@!page_stack: array[1 dotdot max_in_open]int|\unskip'
+by analogy with |line_stack|.
+@^system dependencies@>
+
+@d terminal_input (name==0) /*are we reading from the terminal?*/
+@d cur_file input_file[index] /*the current |alpha_file| variable*/
+
+@<Glob...@>=
+uint8_t @!in_open; /*the number of lines in the buffer, less one*/
+uint8_t @!open_parens; /*the number of open text files*/
+alpha_file @!input_file0[max_in_open], *const @!input_file = @!input_file0-1;
+int @!line; /*current line number in the current source file*/
+int @!line_stack0[max_in_open], *const @!line_stack = @!line_stack0-1;
+
+@ Users of \TeX\ sometimes forget to balance left and right braces properly,
+and one of the ways \TeX\ tries to spot such errors is by considering an
+input file as broken into subfiles by control sequences that
+are declared to be \.{\\outer}.
+
+A variable called |scanner_status| tells \TeX\ whether or not to complain
+when a subfile ends. This variable has six possible values:
+
+\yskip\hang|normal|, means that a subfile can safely end here without incident.
+
+\yskip\hang|skipping|, means that a subfile can safely end here, but not a file,
+because we're reading past some conditional text that was not selected.
+
+\yskip\hang|defining|, means that a subfile shouldn't end now because a
+macro is being defined.
+
+\yskip\hang|matching|, means that a subfile shouldn't end now because a
+macro is being used and we are searching for the end of its arguments.
+
+\yskip\hang|aligning|, means that a subfile shouldn't end now because we are
+not finished with the preamble of an \.{\\halign} or \.{\\valign}.
+
+\yskip\hang|absorbing|, means that a subfile shouldn't end now because we are
+reading a balanced token list for \.{\\message}, \.{\\write}, etc.
+
+\yskip\noindent
+If the |scanner_status| is not |normal|, the variable |warning_index| points
+to the |eqtb| location for the relevant control sequence name to print
+in an error message.
+
+@d skipping 1 /*|scanner_status| when passing conditional text*/
+@d defining 2 /*|scanner_status| when reading a macro definition*/
+@d matching 3 /*|scanner_status| when reading macro arguments*/
+@d aligning 4 /*|scanner_status| when reading an alignment preamble*/
+@d absorbing 5 /*|scanner_status| when reading a balanced text*/
+
+@<Glob...@>=
+uint8_t @!scanner_status; /*can a subfile end now?*/
+pointer @!warning_index; /*identifier relevant to non-|normal| scanner status*/
+pointer @!def_ref; /*reference count of token list being defined*/
+
+@ Here is a procedure that uses |scanner_status| to print a warning message
+when a subfile has ended, and at certain other crucial times:
+
+@<Declare the procedure called |runaway|@>=
+void runaway(void)
+{@+pointer p; /*head of runaway list*/
+if (scanner_status > skipping)
+ {@+print_nl("Runaway ");
+@.Runaway...@>
+ switch (scanner_status) {
+ case defining: {@+print_str("definition");p=def_ref;
+ } @+break;
+ case matching: {@+print_str("argument");p=temp_head;
+ } @+break;
+ case aligning: {@+print_str("preamble");p=hold_head;
+ } @+break;
+ case absorbing: {@+print_str("text");p=def_ref;
+ }
+ } /*there are no other cases*/
+ print_char('?');print_ln();show_token_list(link(p), null, error_line-10);
+ }
+}
+
+@ However, all this discussion about input state really applies only to the
+case that we are inputting from a file. There is another important case,
+namely when we are currently getting input from a token list. In this case
+|state==token_list|, and the conventions about the other state variables
+are different:
+
+\yskip\hang|loc| is a pointer to the current node in the token list, i.e.,
+the node that will be read next. If |loc==null|, the token list has been
+fully read.
+
+\yskip\hang|start| points to the first node of the token list; this node
+may or may not contain a reference count, depending on the type of token
+list involved.
+
+\yskip\hang|token_type|, which takes the place of |index| in the
+discussion above, is a code number that explains what kind of token list
+is being scanned.
+
+\yskip\hang|name| points to the |eqtb| address of the control sequence
+being expanded, if the current token list is a macro.
+
+\yskip\hang|param_start|, which takes the place of |limit|, tells where
+the parameters of the current macro begin in the |param_stack|, if the
+current token list is a macro.
+
+\yskip\noindent The |token_type| can take several values, depending on
+where the current token list came from:
+
+\yskip\hang|parameter|, if a parameter is being scanned;
+
+\hang|u_template|, if the \<u_j> part of an alignment
+template is being scanned;
+
+\hang|v_template|, if the \<v_j> part of an alignment
+template is being scanned;
+
+\hang|backed_up|, if the token list being scanned has been inserted as
+`to be read again'.
+
+\hang|inserted|, if the token list being scanned has been inserted as
+the text expansion of a \.{\\count} or similar variable;
+
+\hang|macro|, if a user-defined control sequence is being scanned;
+
+\hang|output_text|, if an \.{\\output} routine is being scanned;
+
+\hang|every_par_text|, if the text of \.{\\everypar} is being scanned;
+
+\hang|every_math_text|, if the text of \.{\\everymath} is being scanned;
+
+\hang|every_display_text|, if the text of \.{\\everydisplay} is being scanned;
+
+\hang|every_hbox_text|, if the text of \.{\\everyhbox} is being scanned;
+
+\hang|every_vbox_text|, if the text of \.{\\everyvbox} is being scanned;
+
+\hang|every_job_text|, if the text of \.{\\everyjob} is being scanned;
+
+\hang|every_cr_text|, if the text of \.{\\everycr} is being scanned;
+
+\hang|mark_text|, if the text of a \.{\\mark} is being scanned;
+
+\hang|write_text|, if the text of a \.{\\write} is being scanned.
+
+\yskip\noindent
+The codes for |output_text|, |every_par_text|, etc., are equal to a constant
+plus the corresponding codes for token list parameters |output_routine_loc|,
+|every_par_loc|, etc. The token list begins with a reference count if and
+only if |token_type >= macro|.
+@^reference counts@>
+
+@d token_list 0 /*|state| code when scanning a token list*/
+@d token_type index /*type of current token list*/
+@d param_start limit /*base of macro parameters in |param_stack|*/
+@d parameter 0 /*|token_type| code for parameter*/
+@d u_template 1 /*|token_type| code for \<u_j> template*/
+@d v_template 2 /*|token_type| code for \<v_j> template*/
+@d backed_up 3 /*|token_type| code for text to be reread*/
+@d inserted 4 /*|token_type| code for inserted texts*/
+@d macro 5 /*|token_type| code for defined control sequences*/
+@d output_text 6 /*|token_type| code for output routines*/
+@d every_par_text 7 /*|token_type| code for \.{\\everypar}*/
+@d every_math_text 8 /*|token_type| code for \.{\\everymath}*/
+@d every_display_text 9 /*|token_type| code for \.{\\everydisplay}*/
+@d every_hbox_text 10 /*|token_type| code for \.{\\everyhbox}*/
+@d every_vbox_text 11 /*|token_type| code for \.{\\everyvbox}*/
+@d every_job_text 12 /*|token_type| code for \.{\\everyjob}*/
+@d every_cr_text 13 /*|token_type| code for \.{\\everycr}*/
+@d mark_text 14 /*|token_type| code for \.{\\topmark}, etc.*/
+@d write_text 15 /*|token_type| code for \.{\\write}*/
+
+@ The |param_stack| is an auxiliary array used to hold pointers to the token
+lists for parameters at the current level and subsidiary levels of input.
+This stack is maintained with convention (2), and it grows at a different
+rate from the others.
+
+@<Glob...@>=
+pointer @!param_stack[param_size+1];
+ /*token list pointers for parameters*/
+uint8_t @!param_ptr; /*first unused entry in |param_stack|*/
+int @!max_param_stack;
+ /*largest value of |param_ptr|, will be | <= param_size+9|*/
+
+@ The input routines must also interact with the processing of
+\.{\\halign} and \.{\\valign}, since the appearance of tab marks and
+\.{\\cr} in certain places is supposed to trigger the beginning of special
+\<v_j> template text in the scanner. This magic is accomplished by an
+|align_state| variable that is increased by~1 when a `\.{\char'173}' is
+scanned and decreased by~1 when a `\.{\char'175}' is scanned. The |align_state|
+is nonzero during the \<u_j> template, after which it is set to zero; the
+\<v_j> template begins when a tab mark or \.{\\cr} occurs at a time that
+|align_state==0|.
+
+@<Glob...@>=
+int @!align_state; /*group level with respect to current alignment*/
+
+@ Thus, the ``current input state'' can be very complicated indeed; there
+can be many levels and each level can arise in a variety of ways. The
+|show_context| procedure, which is used by \TeX's error-reporting routine to
+print out the current input state on all levels down to the most recent
+line of characters from an input file, illustrates most of these conventions.
+The global variable |base_ptr| contains the lowest level that was
+displayed by this procedure.
+
+@<Glob...@>=
+uint8_t @!base_ptr; /*shallowest level shown by |show_context|*/
+
+@ The status at each level is indicated by printing two lines, where the first
+line indicates what was read so far and the second line shows what remains
+to be read. The context is cropped, if necessary, so that the first line
+contains at most |half_error_line| characters, and the second contains
+at most |error_line|. Non-current input levels whose |token_type| is
+`|backed_up|' are shown only if they have not been fully read.
+
+@p void show_context(void) /*prints where the scanner is*/
+{@+
+uint8_t old_setting; /*saved |selector| setting*/
+int @!nn; /*number of contexts shown so far, less one*/
+bool @!bottom_line; /*have we reached the final context to be shown?*/
+@<Local variables for formatting calculations@>@;
+base_ptr=input_ptr;input_stack[base_ptr]=cur_input;
+ /*store current state*/
+nn=-1;bottom_line=false;
+loop@+{@+cur_input=input_stack[base_ptr]; /*enter into the context*/
+ if ((state!=token_list))
+ if ((name > 17)||(base_ptr==0)) bottom_line=true;
+ if ((base_ptr==input_ptr)||bottom_line||(nn < error_context_lines))
+ @<Display the current context@>@;
+ else if (nn==error_context_lines)
+ {@+print_nl("...");incr(nn); /*omitted if |error_context_lines < 0|*/
+ }
+ if (bottom_line) goto done;
+ decr(base_ptr);
+ }
+done: cur_input=input_stack[input_ptr]; /*restore original state*/
+}
+
+@ @<Display the current context@>=
+{@+if ((base_ptr==input_ptr)||(state!=token_list)||
+ (token_type!=backed_up)||(loc!=null))
+ /*we omit backed-up token lists that have already been read*/
+ {@+tally=0; /*get ready to count characters*/
+ old_setting=selector;
+ if (state!=token_list)
+ {@+@<Print location of current line@>;
+ @<Pseudoprint the line@>;
+ }
+ else{@+@<Print type of token list@>;
+ @<Pseudoprint the token list@>;
+ }
+ selector=old_setting; /*stop pseudoprinting*/
+ @<Print two lines using the tricky pseudoprinted information@>;
+ incr(nn);
+ }
+}
+
+@ This routine should be changed, if necessary, to give the best possible
+indication of where the current line resides in the input file.
+For example, on some systems it is best to print both a page and line number.
+@^system dependencies@>
+
+@<Print location of current line@>=
+if (name <= 17)
+ if (terminal_input)
+ if (base_ptr==0) print_nl("<*>");else print_nl("<insert> ");
+ else{@+print_nl("<read ");
+ if (name==17) print_char('*');@+else print_int(name-1);
+@.*\relax@>
+ print_char('>');
+ }
+else{@+print_nl("l.");print_int(line);
+ }
+print_char(' ')
+
+@ @<Print type of token list@>=
+switch (token_type) {
+case parameter: print_nl("<argument> ");@+break;
+case u_template: case v_template: print_nl("<template> ");@+break;
+case backed_up: if (loc==null) print_nl("<recently read> ");
+ else print_nl("<to be read again> ");@+break;
+case inserted: print_nl("<inserted text> ");@+break;
+case macro: {@+print_ln();print_cs(name);
+ } @+break;
+case output_text: print_nl("<output> ");@+break;
+case every_par_text: print_nl("<everypar> ");@+break;
+case every_math_text: print_nl("<everymath> ");@+break;
+case every_display_text: print_nl("<everydisplay> ");@+break;
+case every_hbox_text: print_nl("<everyhbox> ");@+break;
+case every_vbox_text: print_nl("<everyvbox> ");@+break;
+case every_job_text: print_nl("<everyjob> ");@+break;
+case every_cr_text: print_nl("<everycr> ");@+break;
+case mark_text: print_nl("<mark> ");@+break;
+case write_text: print_nl("<write> ");@+break;
+default:print_nl("?"); /*this should never happen*/
+}
+
+@ 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%error_line]|} if
+|k < trick_count|, otherwise character |k| is dropped. Initially we set
+|tally=0| and |trick_count=1000000|; then when we reach the
+point where transition from line 1 to line 2 should occur, we
+set |first_count=tally| and |trick_count=@tmax@>(error_line,
+tally+1+error_line-half_error_line)|. At the end of the
+pseudoprinting, the values of |first_count|, |tally|, and
+|trick_count| give us all the information we need to print the two lines,
+and all of the necessary text is in |trick_buf|.
+
+Namely, let |l| be the length of the descriptive information that appears
+on the first line. The length of the context information gathered for that
+line is |k==first_count|, and the length of the context information
+gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k <= h|,
+where |h==half_error_line|, we print |trick_buf[0 dotdot k-1]| after the
+descriptive information on line~1, and set |n=l+k|; here |n| is the
+length of line~1. If $l+k>h$, some cropping is necessary, so we set |n=h|
+and print `\.{...}' followed by
+$$\hbox{|trick_buf[(l+k-h+3)dotdot k-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-1)]|,
+unless |n+m > error_line|; in the latter case, further cropping is done.
+This is easier to program than to explain.
+
+@<Local variables for formatting...@>=
+int @!i; /*index into |buffer|*/
+uint16_t @!j; /*end of current line in |buffer|*/
+uint8_t @!l; /*length of descriptive information on line 1*/
+int @!m; /*context information gathered for line 2*/
+uint8_t @!n; /*length of line 1*/
+int @!p; /*starting or ending place in |trick_buf|*/
+int @!q; /*temporary index*/
+
+@ The following code sets up the print routines so that they will gather
+the desired information.
+
+@d begin_pseudoprint
+ {@+l=tally;tally=0;selector=pseudo;
+ trick_count=1000000;
+ }
+@d set_trick_count
+ {@+first_count=tally;
+ trick_count=tally+1+error_line-half_error_line;
+ if (trick_count < error_line) trick_count=error_line;
+ }
+
+@ And the following code uses the information after it has been gathered.
+
+@<Print two lines using the tricky pseudoprinted information@>=
+if (trick_count==1000000) set_trick_count;
+ /*|set_trick_count| must be performed*/
+if (tally < trick_count) m=tally-first_count;
+else m=trick_count-first_count; /*context on line 2*/
+if (l+first_count <= half_error_line)
+ {@+p=0;n=l+first_count;
+ }
+else{@+print_str("...");p=l+first_count-half_error_line+3;
+ n=half_error_line;
+ }
+for (q=p; q<=first_count-1; q++) print_char(trick_buf[q%error_line]);
+print_ln();
+for (q=1; q<=n; q++) print_char(' '); /*print |n| spaces to begin line~2*/
+if (m+n <= error_line) p=first_count+m;else p=first_count+(error_line-n-3);
+for (q=first_count; q<=p-1; q++) print_char(trick_buf[q%error_line]);
+if (m+n > error_line) print_str("...")
+
+@ But the trick is distracting us from our current goal, which is to
+understand the input state. So let's concentrate on the data structures that
+are being pseudoprinted as we finish up the |show_context| procedure.
+
+@<Pseudoprint the line@>=
+begin_pseudoprint;
+if (buffer[limit]==end_line_char) j=limit;
+else j=limit+1; /*determine the effective end of the line*/
+if (j > 0) for (i=start; i<=j-1; i++)
+ {@+if (i==loc) set_trick_count;
+ print(buffer[i]);
+ }
+
+@ @<Pseudoprint the token list@>=
+begin_pseudoprint;
+if (token_type < macro) show_token_list(start, loc, 100000);
+else show_token_list(link(start), loc, 100000) /*avoid reference count*/
+
+@ Here is the missing piece of |show_token_list| that is activated when the
+token beginning line~2 is about to be shown:
+
+@<Do magic computation@>=set_trick_count
+
+@* Maintaining the input stacks.
+The following subroutines change the input status in commonly needed ways.
+
+First comes |push_input|, which stores the current state and creates a
+new level (having, initially, the same properties as the old).
+
+@d push_input @t@> /*enter a new input level, save the old*/
+ {@+if (input_ptr > max_in_stack)
+ {@+max_in_stack=input_ptr;
+ if (input_ptr==stack_size) overflow("input stack size", stack_size);
+@:TeX capacity exceeded input stack size}{\quad input stack size@>
+ }
+ input_stack[input_ptr]=cur_input; /*stack the record*/
+ incr(input_ptr);
+ }
+
+@ And of course what goes up must come down.
+
+@d pop_input @t@> /*leave an input level, re-enter the old*/
+ {@+decr(input_ptr);cur_input=input_stack[input_ptr];
+ }
+
+@ Here is a procedure that starts a new level of token-list input, given
+a token list |p| and its type |t|. If |t==macro|, the calling routine should
+set |name| and |loc|.
+
+@d back_list(X) begin_token_list(X, backed_up) /*backs up a simple token list*/
+@d ins_list(X) begin_token_list(X, inserted) /*inserts a simple token list*/
+
+@p void begin_token_list(pointer @!p, quarterword @!t)
+{@+push_input;state=token_list;start=p;token_type=t;
+if (t >= macro) /*the token list starts with a reference count*/
+ {@+add_token_ref(p);
+ if (t==macro) param_start=param_ptr;
+ else{@+loc=link(p);
+ if (tracing_macros > 1)
+ {@+begin_diagnostic();print_nl("");
+ switch (t) {
+ case mark_text: print_esc(@[@<|"mark"|@>@]);@+break;
+ case write_text: print_esc(@[@<|"write"|@>@]);@+break;
+ default:print_cmd_chr(assign_toks, t-output_text+output_routine_loc);
+ } @/
+ print_str("->");token_show(p);end_diagnostic(false);
+ }
+ }
+ }
+else loc=p;
+}
+
+@ When a token list has been fully scanned, the following computations
+should be done as we leave that level of input. The |token_type| tends
+to be equal to either |backed_up| or |inserted| about 2/3 of the time.
+@^inner loop@>
+
+@p void end_token_list(void) /*leave a token-list input level*/
+{@+if (token_type >= backed_up) /*token list to be deleted*/
+ {@+if (token_type <= inserted) flush_list(start);
+ else{@+delete_token_ref(start); /*update reference count*/
+ if (token_type==macro) /*parameters must be flushed*/
+ while (param_ptr > param_start)
+ {@+decr(param_ptr);
+ flush_list(param_stack[param_ptr]);
+ }
+ }
+ }
+else if (token_type==u_template)
+ if (align_state > 500000) align_state=0;
+ else fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+pop_input;
+check_interrupt;
+}
+
+@ Sometimes \TeX\ has read too far and wants to ``unscan'' what it has
+seen. The |back_input| procedure takes care of this by putting the token
+just scanned back into the input stream, ready to be read again. This
+procedure can be used only if |cur_tok| represents the token to be
+replaced. Some applications of \TeX\ use this procedure a lot,
+so it has been slightly optimized for speed.
+@^inner loop@>
+
+@p void back_input(void) /*undoes one token of input*/
+{@+pointer p; /*a token list of length one*/
+while ((state==token_list)&&(loc==null)&&(token_type!=v_template))
+ end_token_list(); /*conserve stack space*/
+p=get_avail();info(p)=cur_tok;
+if (cur_tok < right_brace_limit)
+ if (cur_tok < left_brace_limit) decr(align_state);
+ else incr(align_state);
+push_input;state=token_list;start=p;token_type=backed_up;
+loc=p; /*that was |back_list(p)|, without procedure overhead*/
+}
+
+@ @<Insert token |p| into \TeX's input@>=
+{@+t=cur_tok;cur_tok=p;back_input();cur_tok=t;
+}
+
+@ The |back_error| routine is used when we want to replace an offending token
+just before issuing an error message. This routine, like |back_input|,
+requires that |cur_tok| has been set. We disable interrupts during the
+call of |back_input| so that the help message won't be lost.
+
+@p void back_error(void) /*back up one token and call |error|*/
+{@+OK_to_interrupt=false;back_input();OK_to_interrupt=true;error();
+}
+@#
+void ins_error(void) /*back up one inserted token and call |error|*/
+{@+OK_to_interrupt=false;back_input();token_type=inserted;
+OK_to_interrupt=true;error();
+}
+
+@ The |begin_file_reading| procedure starts a new level of input for lines
+of characters to be read from a file, or as an insertion from the
+terminal. It does not take care of opening the file, nor does it set |loc|
+or |limit| or |line|.
+@^system dependencies@>
+
+@p void begin_file_reading(void)
+{@+if (in_open==max_in_open) overflow("text input levels", max_in_open);
+@:TeX capacity exceeded text input levels}{\quad text input levels@>
+if (first==buf_size) overflow("buffer size", buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+incr(in_open);push_input;index=in_open;
+line_stack[index]=line;start=first;state=mid_line;
+name=0; /*|terminal_input| is now |true|*/
+}
+
+@ Conversely, the variables must be downdated when such a level of input
+is finished:
+
+@p void end_file_reading(void)
+{@+first=start;line=line_stack[index];
+if (name > 17) a_close(&cur_file); /*forget it*/
+pop_input;decr(in_open);
+}
+
+@ In order to keep the stack from overflowing during a long sequence of
+inserted `\.{\\show}' commands, the following routine removes completed
+error-inserted lines from memory.
+
+@p void clear_for_error_prompt(void)
+{@+while ((state!=token_list)&&terminal_input&&@|
+ (input_ptr > 0)&&(loc > limit)) end_file_reading();
+print_ln();clear_terminal;
+}
+
+@ To get \TeX's whole input mechanism going, we perform the following
+actions.
+
+@<Initialize the input routines@>=
+{@+input_ptr=0;max_in_stack=0;
+in_open=0;open_parens=0;max_buf_stack=0;
+param_ptr=0;max_param_stack=0;
+first=buf_size;@/do@+{buffer[first]=0;decr(first);}@+ while (!(first==0));
+scanner_status=normal;warning_index=null;first=1;
+state=new_line;start=1;index=0;line=0;name=0;
+force_eof=false;
+align_state=1000000;@/
+if (!init_terminal()) exit(0);
+limit=last;first=last+1; /*|init_terminal| has set |loc| and |last|*/
+}
+
+@* Getting the next token.
+The heart of \TeX's input mechanism is the |get_next| procedure, which
+we shall develop in the next few sections of the program. Perhaps we
+shouldn't actually call it the ``heart,'' however, because it really acts
+as \TeX's eyes and mouth, reading the source files and gobbling them up.
+And it also helps \TeX\ to regurgitate stored token lists that are to be
+processed again.
+@^eyes and mouth@>
+
+The main duty of |get_next| is to input one token and to set |cur_cmd|
+and |cur_chr| to that token's command code and modifier. Furthermore, if
+the input token is a control sequence, the |eqtb| location of that control
+sequence is stored in |cur_cs|; otherwise |cur_cs| is set to zero.
+
+Underlying this simple description is a certain amount of complexity
+because of all the cases that need to be handled.
+However, the inner loop of |get_next| is reasonably short and fast.
+
+When |get_next| is asked to get the next token of a \.{\\read} line,
+it sets |cur_cmd==cur_chr==cur_cs==0| in the case that no more tokens
+appear on that line. (There might not be any tokens at all, if the
+|end_line_char| has |ignore| as its catcode.)
+
+@ The value of |par_loc| is the |eqtb| address of `\.{\\par}'. This quantity
+is needed because a blank line of input is supposed to be exactly equivalent
+to the appearance of \.{\\par}; we must set |cur_cs=par_loc|
+when detecting a blank line.
+
+@<Glob...@>=
+pointer @!par_loc; /*location of `\.{\\par}' in |eqtb|*/
+halfword @!par_token; /*token representing `\.{\\par}'*/
+
+@ @<Put each...@>=
+primitive(@[@<|"par"|@>@], par_end, 256); /*cf.\ |scan_file_name|*/
+@!@:par_}{\.{\\par} primitive@>
+par_loc=cur_val;par_token=cs_token_flag+par_loc;
+
+@ @<Cases of |print_cmd_chr|...@>=
+case par_end: print_esc(@[@<|"par"|@>@]);@+break;
+
+@ Before getting into |get_next|, let's consider the subroutine that
+is called when an `\.{\\outer}' control sequence has been scanned or
+when the end of a file has been reached. These two cases are distinguished
+by |cur_cs|, which is zero at the end of a file.
+
+@p void check_outer_validity(void)
+{@+pointer p; /*points to inserted token list*/
+pointer @!q; /*auxiliary pointer*/
+if (scanner_status!=normal)
+ {@+deletions_allowed=false;
+ @<Back up an outer control sequence so that it can be reread@>;
+ if (scanner_status > skipping)
+ @<Tell the user what has run away and try to recover@>@;
+ else{@+print_err("Incomplete ");print_cmd_chr(if_test, cur_if);
+@.Incomplete \\if...@>
+ print_str("; all text was ignored after line ");print_int(skip_line);
+ help3("A forbidden control sequence occurred in skipped text.")@/
+ ("This kind of error happens when you say `\\if...' and forget")@/
+ ("the matching `\\fi'. I've inserted a `\\fi'; this might work.");
+ if (cur_cs!=0) cur_cs=0;
+ else help_line[2]=@|
+ "The file ended while I was skipping conditional text.";
+ cur_tok=cs_token_flag+frozen_fi;ins_error();
+ }
+ deletions_allowed=true;
+ }
+}
+
+@ An outer control sequence that occurs in a \.{\\read} will not be reread,
+since the error recovery for \.{\\read} is not very powerful.
+
+@<Back up an outer control sequence so that it can be reread@>=
+if (cur_cs!=0)
+ {@+if ((state==token_list)||(name < 1)||(name > 17))
+ {@+p=get_avail();info(p)=cs_token_flag+cur_cs;
+ back_list(p); /*prepare to read the control sequence again*/
+ }
+ cur_cmd=spacer;cur_chr=' '; /*replace it by a space*/
+ }
+
+@ @<Tell the user what has run away...@>=
+{@+runaway(); /*print a definition, argument, or preamble*/
+if (cur_cs==0) print_err("File ended")@;
+@.File ended while scanning...@>
+else{@+cur_cs=0;print_err("Forbidden control sequence found");
+@.Forbidden control sequence...@>
+ }
+print_str(" while scanning ");
+@<Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `\.{text}', and
+insert tokens that should lead to recovery@>;
+print_str(" of ");sprint_cs(warning_index);
+help4("I suspect you have forgotten a `}', causing me")@/
+("to read past where you wanted me to stop.")@/
+("I'll try to recover; but if the error is serious,")@/
+("you'd better type `E' or `X' now and fix your file.");@/
+error();
+}
+
+@ The recovery procedure can't be fully understood without knowing more
+about the \TeX\ routines that should be aborted, but we can sketch the
+ideas here: For a runaway definition we will insert a right brace; for a
+runaway preamble, we will insert a special \.{\\cr} token and a right
+brace; and for a runaway argument, we will set |long_state| to
+|outer_call| and insert \.{\\par}.
+
+@<Print either `\.{definition}' or...@>=
+p=get_avail();
+switch (scanner_status) {
+case defining: {@+print_str("definition");info(p)=right_brace_token+'}';
+ } @+break;
+case matching: {@+print_str("use");info(p)=par_token;long_state=outer_call;
+ } @+break;
+case aligning: {@+print_str("preamble");info(p)=right_brace_token+'}';q=p;
+ p=get_avail();link(p)=q;info(p)=cs_token_flag+frozen_cr;
+ align_state=-1000000;
+ } @+break;
+case absorbing: {@+print_str("text");info(p)=right_brace_token+'}';
+ }
+} /*there are no other cases*/
+ins_list(p)
+
+@ We need to mention a procedure here that may be called by |get_next|.
+
+@p void firm_up_the_line(void);
+
+@ Now we're ready to take the plunge into |get_next| itself. Parts of
+this routine are executed more often than any other instructions of \TeX.
+@^mastication@>@^inner loop@>
+
+@p void get_next(void) /*sets |cur_cmd|, |cur_chr|, |cur_cs| to next token*/
+{@+ /*go here to get the next input token*/
+ /*go here to eat the next character from a file*/
+ /*go here to digest it again*/
+ /*go here to start looking for a control sequence*/
+ /*go here when a control sequence has been found*/
+ /*go here when the next input token has been got*/
+uint16_t k; /*an index into |buffer|*/
+halfword @!t; /*a token*/
+uint8_t @!cat; /*|cat_code(cur_chr)|, usually*/
+ASCII_code @!c, @!cc; /*constituents of a possible expanded code*/
+uint8_t @!d; /*number of excess characters in an expanded code*/
+restart: cur_cs=0;
+if (state!=token_list)
+@<Input from external file, |goto restart| if no input found@>@;
+else@<Input from token list, |goto restart| if end of list or if a parameter needs
+to be expanded@>;
+@<If an alignment entry has just ended, take appropriate action@>;
+}
+
+@ An alignment entry ends when a tab or \.{\\cr} occurs, provided that the
+current level of braces is the same as the level that was present at the
+beginning of that alignment entry; i.e., provided that |align_state| has
+returned to the value it had after the \<u_j> template for that entry.
+@^inner loop@>
+
+@<If an alignment entry has just ended, take appropriate action@>=
+if (cur_cmd <= car_ret) if (cur_cmd >= tab_mark) if (align_state==0)
+ @<Insert the \(v)\<v_j> template and |goto restart|@>@;
+
+@ @<Input from external file, |goto restart| if no input found@>=
+@^inner loop@>
+{@+get_cur_chr: if (loc <= limit) /*current line not yet finished*/
+ {@+cur_chr=buffer[loc];incr(loc);
+ reswitch: cur_cmd=cat_code(cur_chr);
+ @<Change state if necessary, and |goto switch| if the current character should be
+ignored, or |goto reswitch| if the current character changes to another@>;
+ }
+else{@+state=new_line;@/
+ @<Move to next line of file, or |goto restart| if there is no next line, or |return|
+if a \.{\\read} line has finished@>;
+ check_interrupt;
+ goto get_cur_chr;
+ }
+}
+
+@ The following 48-way switch accomplishes the scanning quickly, assuming
+that a decent \PASCAL\ compiler has translated the code. Note that the numeric
+values for |mid_line|, |skip_blanks|, and |new_line| are spaced
+apart from each other by |max_char_code+1|, so we can add a character's
+command code to the state to get a single number that characterizes both.
+
+@d any_state_plus(X) case mid_line+X: case skip_blanks+X: case new_line+X
+
+@<Change state if necessary...@>=
+switch (state+cur_cmd) {
+@<Cases where character is ignored@>: goto get_cur_chr;
+any_state_plus(escape): @<Scan a control sequence and set |state:=skip_blanks| or
+|mid_line|@>@;@+break;
+any_state_plus(active_char): @<Process an active-character control sequence and set
+|state:=mid_line|@>@;@+break;
+any_state_plus(sup_mark): @<If this |sup_mark| starts an expanded character like~\.{\^\^A}
+or~\.{\^\^df}, then |goto reswitch|, otherwise set |state:=mid_line|@>@;@+break;
+any_state_plus(invalid_char): @<Decry the invalid character and |goto restart|@>@;
+@t\4@>@<Handle situations involving spaces, braces, changes of state@>@;
+default:do_nothing;
+}
+
+@ @<Cases where character is ignored@>=
+any_state_plus(ignore): case skip_blanks+spacer: case new_line+spacer
+
+@ 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|).
+
+@<Decry the invalid...@>=
+{@+print_err("Text line contains an invalid character");
+@.Text line contains...@>
+help2("A funny symbol that I can't read has just been input.")@/
+("Continue, and I'll forget that it ever happened.");@/
+deletions_allowed=false;error();deletions_allowed=true;
+goto restart;
+}
+
+@ @d add_delims_to(X) X+math_shift: X+tab_mark: X+mac_param:
+ X+sub_mark: X+letter: X+other_char
+
+@<Handle situations involving spaces, braces, changes of state@>=
+case mid_line+spacer: @<Enter |skip_blanks| state, emit a space@>@;@+break;
+case mid_line+car_ret: @<Finish line, emit a space@>@;@+break;
+case skip_blanks+car_ret: any_state_plus(comment):
+ @<Finish line, |goto switch|@>@;
+case new_line+car_ret: @<Finish line, emit a \.{\\par}@>@;@+break;
+case mid_line+left_brace: incr(align_state);@+break;
+case skip_blanks+left_brace: case new_line+left_brace: {@+
+ state=mid_line;incr(align_state);
+ } @+break;
+case mid_line+right_brace: decr(align_state);@+break;
+case skip_blanks+right_brace: case new_line+right_brace: {@+
+ state=mid_line;decr(align_state);
+ } @+break;
+add_delims_to(case skip_blanks): add_delims_to(case new_line): state=mid_line;@+break;
+
+@ 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.
+
+@<Finish line, emit a space@>=
+{@+loc=limit+1;cur_cmd=spacer;cur_chr=' ';
+}
+
+@ The following code is performed only when |cur_cmd==spacer|.
+
+@<Enter |skip_blanks| state, emit a space@>=
+{@+state=skip_blanks;cur_chr=' ';
+}
+
+@ @<Finish line, |goto switch|@>=
+{@+loc=limit+1;goto get_cur_chr;
+}
+
+@ @<Finish line, emit a \.{\\par}@>=
+{@+loc=limit+1;cur_cs=par_loc;cur_cmd=eq_type(cur_cs);
+cur_chr=equiv(cur_cs);
+if (cur_cmd >= outer_call) check_outer_validity();
+}
+
+@ Notice that a code like \.{\^\^8} becomes \.x if not followed by a hex digit.
+
+@d is_hex(X) (((X >= '0')&&(X <= '9'))||((X >= 'a')&&(X <= 'f')))
+@d hex_to_cur_chr
+ if (c <= '9') cur_chr=c-'0';@+else cur_chr=c-'a'+10;
+ if (cc <= '9') cur_chr=16*cur_chr+cc-'0';
+ else cur_chr=16*cur_chr+cc-'a'+10
+
+@<If this |sup_mark| starts an expanded character...@>=
+{@+if (cur_chr==buffer[loc]) if (loc < limit)
+ {@+c=buffer[loc+1];@+if (c < 0200) /*yes we have an expanded char*/
+ {@+loc=loc+2;
+ if (is_hex(c)) if (loc <= limit)
+ {@+cc=buffer[loc];@+if (is_hex(cc))
+ {@+incr(loc);hex_to_cur_chr;goto reswitch;
+ }
+ }
+ if (c < 0100) cur_chr=c+0100;@+else cur_chr=c-0100;
+ goto reswitch;
+ }
+ }
+state=mid_line;
+}
+
+@ @<Process an active-character...@>=
+{@+cur_cs=cur_chr+active_base;
+cur_cmd=eq_type(cur_cs);cur_chr=equiv(cur_cs);state=mid_line;
+if (cur_cmd >= outer_call) check_outer_validity();
+}
+
+@ Control sequence names are scanned only when they appear in some line of
+a file; once they have been scanned the first time, their |eqtb| location
+serves as a unique identification, so \TeX\ doesn't need to refer to the
+original name any more except when it prints the equivalent in symbolic form.
+
+The program that scans a control sequence has been written carefully
+in order to avoid the blowups that might otherwise occur if a malicious
+user tried something like `\.{\\catcode\'15=0}'. The algorithm might
+look at |buffer[limit+1]|, but it never looks at |buffer[limit+2]|.
+
+If expanded characters like `\.{\^\^A}' or `\.{\^\^df}'
+appear in or just following
+a control sequence name, they are converted to single characters in the
+buffer and the process is repeated, slowly but surely.
+
+@<Scan a control...@>=
+{@+if (loc > limit) cur_cs=null_cs; /*|state| is irrelevant in this case*/
+else{@+start_cs: k=loc;cur_chr=buffer[k];cat=cat_code(cur_chr);
+ incr(k);
+ if (cat==letter) state=skip_blanks;
+ else if (cat==spacer) state=skip_blanks;
+ else state=mid_line;
+ if ((cat==letter)&&(k <= limit))
+ @<Scan ahead in the buffer until finding a nonletter; if an expanded code is encountered,
+reduce it and |goto start_cs|; otherwise if a multiletter control sequence is found,
+adjust |cur_cs| and |loc|, and |goto found|@>@;
+ else@<If an expanded code is present, reduce it and |goto start_cs|@>;
+ cur_cs=single_base+buffer[loc];incr(loc);
+ }
+found: cur_cmd=eq_type(cur_cs);cur_chr=equiv(cur_cs);
+if (cur_cmd >= outer_call) check_outer_validity();
+}
+
+@ Whenever we reach the following piece of code, we will have
+|cur_chr==buffer[k-1]| and |k <= limit+1| and |cat==cat_code(cur_chr)|. If an
+expanded code like \.{\^\^A} or \.{\^\^df} appears in |buffer[(k-1)dotdot(k+1)]|
+or |buffer[(k-1)dotdot(k+2)]|, we
+will store the corresponding code in |buffer[k-1]| and shift the rest of
+the buffer left two or three places.
+
+@<If an expanded...@>=
+{@+if (buffer[k]==cur_chr) @+if (cat==sup_mark) @+if (k < limit)
+ {@+c=buffer[k+1];@+if (c < 0200) /*yes, one is indeed present*/
+ {@+d=2;
+ if (is_hex(c)) @+if (k+2 <= limit)
+ {@+cc=buffer[k+2];@+if (is_hex(cc)) incr(d);
+ }
+ if (d > 2)
+ {@+hex_to_cur_chr;buffer[k-1]=cur_chr;
+ }
+ else if (c < 0100) buffer[k-1]=c+0100;
+ else buffer[k-1]=c-0100;
+ limit=limit-d;first=first-d;
+ while (k <= limit)
+ {@+buffer[k]=buffer[k+d];incr(k);
+ }
+ goto start_cs;
+ }
+ }
+}
+
+@ @<Scan ahead in the buffer...@>=
+{@+@/do@+{cur_chr=buffer[k];cat=cat_code(cur_chr);incr(k);
+}@+ while (!((cat!=letter)||(k > limit)));
+@<If an expanded...@>;
+if (cat!=letter) decr(k);
+ /*now |k| points to first nonletter*/
+if (k > loc+1) /*multiletter control sequence has been scanned*/
+ {@+cur_cs=id_lookup(loc, k-loc);loc=k;goto found;
+ }
+}
+
+@ Let's consider now what happens when |get_next| is looking at a token list.
+
+@<Input from token list, |goto restart| if end of list or if a parameter needs to
+be expanded@>=
+if (loc!=null) /*list not exhausted*/
+@^inner loop@>
+ {@+t=info(loc);loc=link(loc); /*move to next*/
+ if (t >= cs_token_flag) /*a control sequence token*/
+ {@+cur_cs=t-cs_token_flag;
+ cur_cmd=eq_type(cur_cs);cur_chr=equiv(cur_cs);
+ if (cur_cmd >= outer_call)
+ if (cur_cmd==dont_expand)
+ @<Get the next token, suppressing expansion@>@;
+ else check_outer_validity();
+ }
+ else{@+cur_cmd=t/0400;cur_chr=t%0400;
+ switch (cur_cmd) {
+ case left_brace: incr(align_state);@+break;
+ case right_brace: decr(align_state);@+break;
+ case out_param: @<Insert macro parameter and |goto restart|@>@;
+ default:do_nothing;
+ }
+ }
+ }
+else{@+ /*we are done with this token list*/
+ end_token_list();goto restart; /*resume previous level*/
+ }
+
+@ The present point in the program is reached only when the |expand|
+routine has inserted a special marker into the input. In this special
+case, |info(loc)| is known to be a control sequence token, and |link(loc)==null|.
+
+@d no_expand_flag 257 /*this characterizes a special variant of |relax|*/
+
+@<Get the next token, suppressing expansion@>=
+{@+cur_cs=info(loc)-cs_token_flag;loc=null;@/
+cur_cmd=eq_type(cur_cs);cur_chr=equiv(cur_cs);
+if (cur_cmd > max_command)
+ {@+cur_cmd=relax;cur_chr=no_expand_flag;
+ }
+}
+
+@ @<Insert macro parameter...@>=
+{@+begin_token_list(param_stack[param_start+cur_chr-1], parameter);
+goto restart;
+}
+
+@ All of the easy branches of |get_next| have now been taken care of.
+There is one more branch.
+
+@d end_line_char_inactive (end_line_char < 0)||(end_line_char > 255)
+
+@<Move to next line of file, or |goto restart|...@>=
+if (name > 17) @<Read next line of file into |buffer|, or |goto restart| if the file
+has ended@>@;
+else{@+if (!terminal_input) /*\.{\\read} line has ended*/
+ {@+cur_cmd=0;cur_chr=0;return;
+ }
+ if (input_ptr > 0) /*text was inserted during error recovery*/
+ {@+end_file_reading();goto restart; /*resume previous level*/
+ }
+ if (selector < log_only) open_log_file();
+ if (interaction > nonstop_mode)
+ {@+if (end_line_char_inactive) incr(limit);
+ if (limit==start) /*previous line was empty*/
+ print_nl("(Please type a command or say `\\end')");
+@.Please type...@>
+ print_ln();first=start;
+ prompt_input("*"); /*input on-line into |buffer|*/
+@.*\relax@>
+ limit=last;
+ if (end_line_char_inactive) decr(limit);
+ else buffer[limit]=end_line_char;
+ first=limit+1;
+ loc=start;
+ }
+ else fatal_error("*** (job aborted, no legal \\end found)");
+@.job aborted@>
+ /*nonstop mode, which is intended for overnight batch processing,
+ never waits for on-line input*/
+ }
+
+@ The global variable |force_eof| is normally |false|; it is set |true|
+by an \.{\\endinput} command.
+
+@<Glob...@>=
+bool @!force_eof; /*should the next \.{\\input} be aborted early?*/
+
+@ @<Read next line of file into |buffer|, or |goto restart| if the file has ended@>=
+{@+incr(line);first=start;
+if (!force_eof)
+ {@+if (input_ln(&cur_file, true)) /*not end of file*/
+ firm_up_the_line(); /*this sets |limit|*/
+ else force_eof=true;
+ }
+if (force_eof)
+ {@+print_char(')');decr(open_parens);
+ update_terminal; /*show user that file has been read*/
+ force_eof=false;
+ end_file_reading(); /*resume previous level*/
+ check_outer_validity();goto restart;
+ }
+if (end_line_char_inactive) decr(limit);
+else buffer[limit]=end_line_char;
+first=limit+1;loc=start; /*ready to read*/
+}
+
+@ If the user has set the |pausing| parameter to some positive value,
+and if nonstop mode has not been selected, each line of input is displayed
+on the terminal and the transcript file, followed by `\.{=>}'.
+\TeX\ waits for a response. If the response is simply |carriage_return|, the
+line is accepted as it stands, otherwise the line typed is
+used instead of the line in the file.
+
+@p void firm_up_the_line(void)
+{@+int k; /*an index into |buffer|*/
+limit=last;
+if (pausing > 0) if (interaction > nonstop_mode)
+ {@+wake_up_terminal;print_ln();
+ if (start < limit) for (k=start; k<=limit-1; k++) print(buffer[k]);
+ first=limit;prompt_input("=>"); /*wait for user response*/
+@.=>@>
+ if (last > first)
+ {@+for (k=first; k<=last-1; k++) /*move line down in buffer*/
+ buffer[k+start-first]=buffer[k];
+ limit=start+last-first;
+ }
+ }
+}
+
+@ Since |get_next| is used so frequently in \TeX, it is convenient
+to define three related procedures that do a little more:
+
+\yskip\hang|get_token| not only sets |cur_cmd| and |cur_chr|, it
+also sets |cur_tok|, a packed halfword version of the current token.
+
+\yskip\hang|get_x_token|, meaning ``get an expanded token,'' is like
+|get_token|, but if the current token turns out to be a user-defined
+control sequence (i.e., a macro call), or a conditional,
+or something like \.{\\topmark} or \.{\\expandafter} or \.{\\csname},
+it is eliminated from the input by beginning the expansion of the macro
+or the evaluation of the conditional.
+
+\yskip\hang|x_token| is like |get_x_token| except that it assumes that
+|get_next| has already been called.
+
+\yskip\noindent
+In fact, these three procedures account for almost every use of |get_next|.
+
+@ No new control sequences will be defined except during a call of
+|get_token|, or when \.{\\csname} compresses a token list, because
+|no_new_control_sequence| is always |true| at other times.
+
+@p void get_token(void) /*sets |cur_cmd|, |cur_chr|, |cur_tok|*/
+{@+no_new_control_sequence=false;get_next();no_new_control_sequence=true;
+@^inner loop@>
+if (cur_cs==0) cur_tok=(cur_cmd*0400)+cur_chr;
+else cur_tok=cs_token_flag+cur_cs;
+}
+
+@* 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.
+@^recursion@>
+
+@p@t\4@>@<Declare the procedure called |macro_call|@>@;@/
+@t\4@>@<Declare the procedure called |insert_relax|@>@;@/
+void pass_text(void);
+void start_input(void);
+void conditional(void);
+void get_x_token(void);
+void conv_toks(void);
+void ins_the_toks(void);
+void expand(void)
+{@+halfword t; /*token that is being ``expanded after''*/
+pointer @!p, @!q, @!r; /*for list manipulation*/
+uint16_t @!j; /*index into |buffer|*/
+int @!cv_backup; /*to save the global quantity |cur_val|*/
+small_number @!cvl_backup, @!radix_backup, @!co_backup;
+ /*to save |cur_val_level|, etc.*/
+pointer @!backup_backup; /*to save |link(backup_head)|*/
+small_number @!save_scanner_status; /*temporary storage of |scanner_status|*/
+cv_backup=cur_val;cvl_backup=cur_val_level;radix_backup=radix;
+co_backup=cur_order;backup_backup=link(backup_head);
+if (cur_cmd < call) @<Expand a nonmacro@>@;
+else if (cur_cmd < end_template) macro_call();
+else@<Insert a token containing |frozen_endv|@>;
+cur_val=cv_backup;cur_val_level=cvl_backup;radix=radix_backup;
+cur_order=co_backup;link(backup_head)=backup_backup;
+}
+
+@ @<Expand a nonmacro@>=
+{@+if (tracing_commands > 1) show_cur_cmd_chr();
+switch (cur_cmd) {
+case top_bot_mark: @<Insert the \(a)appropriate mark text into the scanner@>@;@+break;
+case expand_after: @<Expand the token after the next token@>@;@+break;
+case no_expand: @<Suppress expansion of the next token@>@;@+break;
+case cs_name: @<Manufacture a control sequence name@>@;@+break;
+case convert: conv_toks();@+break; /*this procedure is discussed in Part 27 below*/
+case the: ins_the_toks();@+break; /*this procedure is discussed in Part 27 below*/
+case if_test: conditional();@+break; /*this procedure is discussed in Part 28 below*/
+case fi_or_else: @<Terminate the current conditional and skip to \.{\\fi}@>@;@+break;
+case input: @<Initiate or terminate input from a file@>;@+break;
+default:@<Complain about an undefined macro@>@;
+}
+}
+
+@ It takes only a little shuffling to do what \TeX\ calls \.{\\expandafter}.
+
+@<Expand the token after...@>=
+{@+get_token();t=cur_tok;get_token();
+if (cur_cmd > max_command) expand();@+else back_input();
+cur_tok=t;back_input();
+}
+
+@ The implementation of \.{\\noexpand} is a bit trickier, because it is
+necessary to insert a special `|dont_expand|' marker into \TeX's reading
+mechanism. This special marker is processed by |get_next|, but it does
+not slow down the inner loop.
+
+Since \.{\\outer} macros might arise here, we must also
+clear the |scanner_status| temporarily.
+
+@<Suppress expansion...@>=
+{@+save_scanner_status=scanner_status;scanner_status=normal;
+get_token();scanner_status=save_scanner_status;t=cur_tok;
+back_input(); /*now |start| and |loc| point to the backed-up token |t|*/
+if (t >= cs_token_flag)
+ {@+p=get_avail();info(p)=cs_token_flag+frozen_dont_expand;
+ link(p)=loc;start=p;loc=p;
+ }
+}
+
+@ @<Complain about an undefined macro@>=
+{@+print_err("Undefined control sequence");
+@.Undefined control sequence@>
+help5("The control sequence at the end of the top line")@/
+("of your error message was never \\def'ed. If you have")@/
+("misspelled it (e.g., `\\hobx'), type `I' and the correct")@/
+("spelling (e.g., `I\\hbox'). Otherwise just continue,")@/
+("and I'll forget about whatever was undefined.");
+error();
+}
+
+@ The |expand| procedure and some other routines that construct token
+lists find it convenient to use the following macros, which are valid only if
+the variables |p| and |q| are reserved for token-list building.
+
+@d store_new_token(X) {@+q=get_avail();link(p)=q;info(q)=X;
+ p=q; /*|link(p)| is |null|*/
+ }
+@d fast_store_new_token(X) {@+fast_get_avail(q);link(p)=q;info(q)=X;
+ p=q; /*|link(p)| is |null|*/
+ }
+
+@ @<Manufacture a control...@>=
+{@+r=get_avail();p=r; /*head of the list of characters*/
+@/do@+{get_x_token();
+if (cur_cs==0) store_new_token(cur_tok);
+}@+ while (!(cur_cs!=0));
+if (cur_cmd!=end_cs_name) @<Complain about missing \.{\\endcsname}@>;
+@<Look up the characters of list |r| in the hash table, and set |cur_cs|@>;
+flush_list(r);
+if (eq_type(cur_cs)==undefined_cs)
+ {@+eq_define(cur_cs, relax, 256); /*N.B.: The |save_stack| might change*/
+ } /*the control sequence will now match `\.{\\relax}'*/
+cur_tok=cur_cs+cs_token_flag;back_input();
+}
+
+@ @<Complain about missing \.{\\endcsname}@>=
+{@+print_err("Missing ");print_esc(@[@<|"endcsname"|@>@]);print_str(" inserted");
+@.Missing \\endcsname...@>
+help2("The control sequence marked <to be read again> should")@/
+ ("not appear between \\csname and \\endcsname.");
+back_error();
+}
+
+@ @<Look up the characters of list |r| in the hash table...@>=
+j=first;p=link(r);
+while (p!=null)
+ {@+if (j >= max_buf_stack)
+ {@+max_buf_stack=j+1;
+ if (max_buf_stack==buf_size)
+ overflow("buffer size", buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+ }
+ buffer[j]=info(p)%0400;incr(j);p=link(p);
+ }
+if (j > first+1)
+ {@+no_new_control_sequence=false;cur_cs=id_lookup(first, j-first);
+ no_new_control_sequence=true;
+ }
+else if (j==first) cur_cs=null_cs; /*the list is empty*/
+else cur_cs=single_base+buffer[first] /*the list has length one*/
+
+@ An |end_template| command is effectively changed to an |endv| command
+by the following code. (The reason for this is discussed below; the
+|frozen_end_template| at the end of the template has passed the
+|check_outer_validity| test, so its mission of error detection has been
+accomplished.)
+
+@<Insert a token containing |frozen_endv|@>=
+{@+cur_tok=cs_token_flag+frozen_endv;back_input();
+}
+
+@ The processing of \.{\\input} involves the |start_input| subroutine,
+which will be declared later; the processing of \.{\\endinput} is trivial.
+
+@<Put each...@>=
+primitive(@[@<|"input"|@>@], input, 0);@/
+@!@:input_}{\.{\\input} primitive@>
+primitive(@[@<|"endinput"|@>@], input, 1);@/
+@!@:end_input_}{\.{\\endinput} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case input: if (chr_code==0) print_esc(@[@<|"input"|@>@]);@+else print_esc(@[@<|"endinput"|@>@]);@+break;
+
+@ @<Initiate or terminate input...@>=
+if (cur_chr > 0) force_eof=true;
+else if (name_in_progress) insert_relax();
+else start_input()
+
+@ Sometimes the expansion looks too far ahead, so we want to insert
+a harmless \.{\\relax} into the user's input.
+
+@<Declare the procedure called |insert_relax|@>=
+void insert_relax(void)
+{@+cur_tok=cs_token_flag+cur_cs;back_input();
+cur_tok=cs_token_flag+frozen_relax;back_input();token_type=inserted;
+}
+
+@ Here is a recursive procedure that is \TeX's usual way to get the
+next token of input. It has been slightly optimized to take account of
+common cases.
+
+@p void get_x_token(void) /*sets |cur_cmd|, |cur_chr|, |cur_tok|,
+ and expands macros*/
+{@+
+restart: get_next();
+@^inner loop@>
+if (cur_cmd <= max_command) goto done;
+if (cur_cmd >= call)
+ if (cur_cmd < end_template) macro_call();
+ else{@+cur_cs=frozen_endv;cur_cmd=endv;
+ goto done; /*|cur_chr==null_list|*/
+ }
+else expand();
+goto restart;
+done: if (cur_cs==0) cur_tok=(cur_cmd*0400)+cur_chr;
+else cur_tok=cs_token_flag+cur_cs;
+}
+
+@ The |get_x_token| procedure is equivalent to two consecutive
+procedure calls: |get_next;x_token|.
+
+@p void x_token(void) /*|get_x_token| without the initial |get_next|*/
+{@+while (cur_cmd > max_command)
+ {@+expand();
+ get_next();
+ }
+if (cur_cs==0) cur_tok=(cur_cmd*0400)+cur_chr;
+else cur_tok=cs_token_flag+cur_cs;
+}
+
+@ A control sequence that has been \.{\\def}'ed by the user is expanded by
+\TeX's |macro_call| procedure.
+
+Before we get into the details of |macro_call|, however, let's consider the
+treatment of primitives like \.{\\topmark}, since they are essentially
+macros without parameters. The token lists for such marks are kept in a
+global array of five pointers; we refer to the individual entries of this
+array by symbolic names |top_mark|, etc. The value of |top_mark| is either
+|null| or a pointer to the reference count of a token list.
+
+@d top_mark_code 0 /*the mark in effect at the previous page break*/
+@d first_mark_code 1 /*the first mark between |top_mark| and |bot_mark|*/
+@d bot_mark_code 2 /*the mark in effect at the current page break*/
+@d split_first_mark_code 3 /*the first mark found by \.{\\vsplit}*/
+@d split_bot_mark_code 4 /*the last mark found by \.{\\vsplit}*/
+@d top_mark cur_mark[top_mark_code]
+@d first_mark cur_mark[first_mark_code]
+@d bot_mark cur_mark[bot_mark_code]
+@d split_first_mark cur_mark[split_first_mark_code]
+@d split_bot_mark cur_mark[split_bot_mark_code]
+
+@<Glob...@>=
+pointer @!cur_mark0[split_bot_mark_code-top_mark_code+1], *const @!cur_mark = @!cur_mark0-top_mark_code;
+ /*token lists for marks*/
+
+@ @<Set init...@>=
+top_mark=null;first_mark=null;bot_mark=null;
+split_first_mark=null;split_bot_mark=null;
+
+@ @<Put each...@>=
+primitive(@[@<|"topmark"|@>@], top_bot_mark, top_mark_code);
+@!@:top_mark_}{\.{\\topmark} primitive@>
+primitive(@[@<|"firstmark"|@>@], top_bot_mark, first_mark_code);
+@!@:first_mark_}{\.{\\firstmark} primitive@>
+primitive(@[@<|"botmark"|@>@], top_bot_mark, bot_mark_code);
+@!@:bot_mark_}{\.{\\botmark} primitive@>
+primitive(@[@<|"splitfirstmark"|@>@], top_bot_mark, split_first_mark_code);
+@!@:split_first_mark_}{\.{\\splitfirstmark} primitive@>
+primitive(@[@<|"splitbotmark"|@>@], top_bot_mark, split_bot_mark_code);
+@!@:split_bot_mark_}{\.{\\splitbotmark} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case top_bot_mark: switch (chr_code) {
+ case first_mark_code: print_esc(@[@<|"firstmark"|@>@]);@+break;
+ case bot_mark_code: print_esc(@[@<|"botmark"|@>@]);@+break;
+ case split_first_mark_code: print_esc(@[@<|"splitfirstmark"|@>@]);@+break;
+ case split_bot_mark_code: print_esc(@[@<|"splitbotmark"|@>@]);@+break;
+ default:print_esc(@[@<|"topmark"|@>@]);
+ } @+break;
+
+@ The following code is activated when |cur_cmd==top_bot_mark| and
+when |cur_chr| is a code like |top_mark_code|.
+
+@<Insert the \(a)appropriate mark text into the scanner@>=
+{@+if (cur_mark[cur_chr]!=null)
+ begin_token_list(cur_mark[cur_chr], mark_text);
+}
+
+@ Now let's consider |macro_call| itself, which is invoked when \TeX\ is
+scanning a control sequence whose |cur_cmd| is either |call|, |long_call|,
+|outer_call|, or |long_outer_call|. The control sequence definition
+appears in the token list whose reference count is in location |cur_chr|
+of |mem|.
+
+The global variable |long_state| will be set to |call| or to |long_call|,
+depending on whether or not the control sequence disallows \.{\\par}
+in its parameters. The |get_next| routine will set |long_state| to
+|outer_call| and emit \.{\\par}, if a file ends or if an \.{\\outer}
+control sequence occurs in the midst of an argument.
+
+@<Glob...@>=
+uint8_t @!long_state; /*governs the acceptance of \.{\\par}*/
+
+@ The parameters, if any, must be scanned before the macro is expanded.
+Parameters are token lists without reference counts. They are placed on
+an auxiliary stack called |pstack| while they are being scanned, since
+the |param_stack| may be losing entries during the matching process.
+(Note that |param_stack| can't be gaining entries, since |macro_call| is
+the only routine that puts anything onto |param_stack|, and it
+is not recursive.)
+
+@<Glob...@>=
+pointer @!pstack[9]; /*arguments supplied to a macro*/
+
+@ After parameter scanning is complete, the parameters are moved to the
+|param_stack|. Then the macro body is fed to the scanner; in other words,
+|macro_call| places the defined text of the control sequence at the
+top of\/ \TeX's input stack, so that |get_next| will proceed to read it
+next.
+
+The global variable |cur_cs| contains the |eqtb| address of the control sequence
+being expanded, when |macro_call| begins. If this control sequence has not been
+declared \.{\\long}, i.e., if its command code in the |eq_type| field is
+not |long_call| or |long_outer_call|, its parameters are not allowed to contain
+the control sequence \.{\\par}. If an illegal \.{\\par} appears, the macro
+call is aborted, and the \.{\\par} will be rescanned.
+
+@<Declare the procedure called |macro_call|@>=
+void macro_call(void) /*invokes a user-defined control sequence*/
+{@+
+pointer r; /*current node in the macro's token list*/
+pointer @!p; /*current node in parameter token list being built*/
+pointer @!q; /*new node being put into the token list*/
+pointer @!s; /*backup pointer for parameter matching*/
+pointer @!t; /*cycle pointer for backup recovery*/
+pointer @!u, @!v; /*auxiliary pointers for backup recovery*/
+pointer @!rbrace_ptr; /*one step before the last |right_brace| token*/
+small_number @!n; /*the number of parameters scanned*/
+halfword @!unbalance; /*unmatched left braces in current parameter*/
+int @!m; /*the number of tokens or groups (usually)*/
+pointer @!ref_count; /*start of the token list*/
+small_number @!save_scanner_status; /*|scanner_status| upon entry*/
+pointer @!save_warning_index; /*|warning_index| upon entry*/
+ASCII_code @!match_chr; /*character used in parameter*/
+save_scanner_status=scanner_status;save_warning_index=warning_index;
+warning_index=cur_cs;ref_count=cur_chr;r=link(ref_count);n=0;
+if (tracing_macros > 0) @<Show the text of the macro being expanded@>;
+if (info(r)!=end_match_token)
+ @<Scan the parameters and make |link(r)| point to the macro body; but |return| if
+an illegal \.{\\par} is detected@>;
+@<Feed the macro body and its parameters to the scanner@>;
+end: scanner_status=save_scanner_status;warning_index=save_warning_index;
+}
+
+@ Before we put a new token list on the input stack, it is wise to clean off
+all token lists that have recently been depleted. Then a user macro that ends
+with a call to itself will not require unbounded stack space.
+
+@<Feed the macro body and its parameters to the scanner@>=
+while ((state==token_list)&&(loc==null)&&(token_type!=v_template))
+ end_token_list(); /*conserve stack space*/
+begin_token_list(ref_count, macro);name=warning_index;loc=link(r);
+if (n > 0)
+ {@+if (param_ptr+n > max_param_stack)
+ {@+max_param_stack=param_ptr+n;
+ if (max_param_stack > param_size)
+ overflow("parameter stack size", param_size);
+@:TeX capacity exceeded parameter stack size}{\quad parameter stack size@>
+ }
+ for (m=0; m<=n-1; m++) param_stack[param_ptr+m]=pstack[m];
+ param_ptr=param_ptr+n;
+ }
+
+@ At this point, the reader will find it advisable to review the explanation
+of token list format that was presented earlier, since many aspects of that
+format are of importance chiefly in the |macro_call| routine.
+
+The token list might begin with a string of compulsory tokens before the
+first |match| or |end_match|. In that case the macro name is supposed to be
+followed by those tokens; the following program will set |s==null| to
+represent this restriction. Otherwise |s| will be set to the first token of
+a string that will delimit the next parameter.
+
+@<Scan the parameters and make |link(r)| point to the macro body...@>=
+{@+scanner_status=matching;unbalance=0;
+long_state=eq_type(cur_cs);
+if (long_state >= outer_call) long_state=long_state-2;
+@/do@+{link(temp_head)=null;
+if ((info(r) > match_token+255)||(info(r) < match_token)) s=null;
+else{@+match_chr=info(r)-match_token;s=link(r);r=s;
+ p=temp_head;m=0;
+ }
+@<Scan a parameter until its delimiter string has been found; or, if |s=null|, simply
+scan the delimiter string@>;@/
+ /*now |info(r)| is a token whose command code is either |match| or |end_match|*/
+}@+ while (!(info(r)==end_match_token));
+}
+
+@ If |info(r)| is a |match| or |end_match| command, it cannot be equal to
+any token found by |get_token|. Therefore an undelimited parameter---i.e.,
+a |match| that is immediately followed by |match| or |end_match|---will
+always fail the test `|cur_tok==info(r)|' in the following algorithm.
+
+@<Scan a parameter until its delimiter string has been found; or,...@>=
+resume: get_token(); /*set |cur_tok| to the next token of input*/
+if (cur_tok==info(r))
+ @<Advance \(r)|r|; |goto found| if the parameter delimiter has been fully matched,
+otherwise |goto continue|@>;
+@<Contribute the recently matched tokens to the current parameter, and |goto continue|
+if a partial match is still in effect; but abort if |s=null|@>;
+if (cur_tok==par_token) if (long_state!=long_call)
+ @<Report a runaway argument and abort@>;
+if (cur_tok < right_brace_limit)
+ if (cur_tok < left_brace_limit)
+ @<Contribute an entire group to the current parameter@>@;
+ else@<Report an extra right brace and |goto continue|@>@;
+else@<Store the current token, but |goto continue| if it is a blank space that would
+become an undelimited parameter@>;
+incr(m);
+if (info(r) > end_match_token) goto resume;
+if (info(r) < match_token) goto resume;
+found: if (s!=null) @<Tidy up the parameter just scanned, and tuck it away@>@;
+
+@ @<Store the current token, but |goto continue| if it is...@>=
+{@+if (cur_tok==space_token)
+ if (info(r) <= end_match_token)
+ if (info(r) >= match_token) goto resume;
+store_new_token(cur_tok);
+}
+
+@ A slightly subtle point arises here: When the parameter delimiter ends
+with `\.{\#\{}', the token list will have a left brace both before and
+after the |end_match|\kern-.4pt. Only one of these should affect the
+|align_state|, but both will be scanned, so we must make a correction.
+
+@<Advance \(r)|r|; |goto found| if the parameter delimiter has been fully...@>=
+{@+r=link(r);
+if ((info(r) >= match_token)&&(info(r) <= end_match_token))
+ {@+if (cur_tok < left_brace_limit) decr(align_state);
+ goto found;
+ }
+else goto resume;
+}
+
+@ @<Report an extra right brace and |goto continue|@>=
+{@+back_input();print_err("Argument of ");sprint_cs(warning_index);
+@.Argument of \\x has...@>
+print_str(" has an extra }");
+help6("I've run across a `}' that doesn't seem to match anything.")@/
+ ("For example, `\\def\\a#1{...}' and `\\a}' would produce")@/
+ ("this error. If you simply proceed now, the `\\par' that")@/
+ ("I've just inserted will cause me to report a runaway")@/
+ ("argument that might be the root of the problem. But if")@/
+ ("your `}' was spurious, just type `2' and it will go away.");
+incr(align_state);long_state=call;cur_tok=par_token;ins_error();
+goto resume;
+} /*a white lie; the \.{\\par} won't always trigger a runaway*/
+
+@ If |long_state==outer_call|, a runaway argument has already been reported.
+
+@<Report a runaway argument and abort@>=
+{@+if (long_state==call)
+ {@+runaway();print_err("Paragraph ended before ");
+@.Paragraph ended before...@>
+ sprint_cs(warning_index);print_str(" was complete");
+ help3("I suspect you've forgotten a `}', causing me to apply this")@/
+ ("control sequence to too much text. How can we recover?")@/
+ ("My plan is to forget the whole thing and hope for the best.");
+ back_error();
+ }
+pstack[n]=link(temp_head);align_state=align_state-unbalance;
+for (m=0; m<=n; m++) flush_list(pstack[m]);
+goto end;
+}
+
+@ When the following code becomes active, we have matched tokens from |s| to
+the predecessor of |r|, and we have found that |cur_tok!=info(r)|. An
+interesting situation now presents itself: If the parameter is to be
+delimited by a string such as `\.{ab}', and if we have scanned `\.{aa}',
+we want to contribute one `\.a' to the current parameter and resume
+looking for a `\.b'. The program must account for such partial matches and
+for others that can be quite complex. But most of the time we have |s==r|
+and nothing needs to be done.
+
+Incidentally, it is possible for \.{\\par} tokens to sneak in to certain
+parameters of non-\.{\\long} macros. For example, consider a case like
+`\.{\\def\\a\#1\\par!\{...\}}' where the first \.{\\par} is not followed
+by an exclamation point. In such situations it does not seem appropriate
+to prohibit the \.{\\par}, so \TeX\ keeps quiet about this bending of
+the rules.
+
+@<Contribute the recently matched tokens to the current parameter...@>=
+if (s!=r)
+ if (s==null) @<Report an improper use of the macro and abort@>@;
+ else{@+t=s;
+ @/do@+{store_new_token(info(t));incr(m);u=link(t);v=s;
+ loop@+{@+if (u==r)
+ if (cur_tok!=info(v)) goto done;
+ else{@+r=link(v);goto resume;
+ }
+ if (info(u)!=info(v)) goto done;
+ u=link(u);v=link(v);
+ }
+ done: t=link(t);
+ }@+ while (!(t==r));
+ r=s; /*at this point, no tokens are recently matched*/
+ }
+
+@ @<Report an improper use...@>=
+{@+print_err("Use of ");sprint_cs(warning_index);
+@.Use of x doesn't match...@>
+print_str(" doesn't match its definition");
+help4("If you say, e.g., `\\def\\a1{...}', then you must always")@/
+ ("put `1' after `\\a', since control sequence names are")@/
+ ("made up of letters only. The macro here has not been")@/
+ ("followed by the required stuff, so I'm ignoring it.");
+error();goto end;
+}
+
+@ @<Contribute an entire group to the current parameter@>=
+{@+unbalance=1;
+@^inner loop@>
+loop@+{@+fast_store_new_token(cur_tok);get_token();
+ if (cur_tok==par_token) if (long_state!=long_call)
+ @<Report a runaway argument and abort@>;
+ if (cur_tok < right_brace_limit)
+ if (cur_tok < left_brace_limit) incr(unbalance);
+ else{@+decr(unbalance);
+ if (unbalance==0) goto done1;
+ }
+ }
+done1: rbrace_ptr=p;store_new_token(cur_tok);
+}
+
+@ If the parameter consists of a single group enclosed in braces, we must
+strip off the enclosing braces. That's why |rbrace_ptr| was introduced.
+
+@<Tidy up the parameter just scanned, and tuck it away@>=
+{@+if ((m==1)&&(info(p) < right_brace_limit)&&(p!=temp_head))
+ {@+link(rbrace_ptr)=null;free_avail(p);
+ p=link(temp_head);pstack[n]=link(p);free_avail(p);
+ }
+else pstack[n]=link(temp_head);
+incr(n);
+if (tracing_macros > 0)
+ {@+begin_diagnostic();print_nl("");print(match_chr);print_int(n);
+ print_str("<-");show_token_list(pstack[n-1], null, 1000);
+ end_diagnostic(false);
+ }
+}
+
+@ @<Show the text of the macro being expanded@>=
+{@+begin_diagnostic();print_ln();print_cs(warning_index);
+token_show(ref_count);end_diagnostic(false);
+}
+
+@* Basic scanning subroutines.
+Let's turn now to some procedures that \TeX\ calls upon frequently to digest
+certain kinds of patterns in the input. Most of these are quite simple;
+some are quite elaborate. Almost all of the routines call |get_x_token|,
+which can cause them to be invoked recursively.
+@^stomach@>
+@^recursion@>
+
+@ The |scan_left_brace| routine is called when a left brace is supposed to be
+the next non-blank token. (The term ``left brace'' means, more precisely,
+a character whose catcode is |left_brace|.) \TeX\ allows \.{\\relax} to
+appear before the |left_brace|.
+
+@p void scan_left_brace(void) /*reads a mandatory |left_brace|*/
+{@+@<Get the next non-blank non-relax non-call token@>;
+if (cur_cmd!=left_brace)
+ {@+print_err("Missing { inserted");
+@.Missing \{ inserted@>
+ help4("A left brace was mandatory here, so I've put one in.")@/
+ ("You might want to delete and/or insert some corrections")@/
+ ("so that I will find a matching right brace soon.")@/
+ ("(If you're confused by all this, try typing `I}' now.)");
+ back_error();cur_tok=left_brace_token+'{';cur_cmd=left_brace;
+ cur_chr='{';incr(align_state);
+ }
+}
+
+@ @<Get the next non-blank non-relax non-call token@>=
+@/do@+{get_x_token();
+}@+ while (!((cur_cmd!=spacer)&&(cur_cmd!=relax)))
+
+@ The |scan_optional_equals| routine looks for an optional `\.=' sign preceded
+by optional spaces; `\.{\\relax}' is not ignored here.
+
+@p void scan_optional_equals(void)
+{@+@<Get the next non-blank non-call token@>;
+if (cur_tok!=other_token+'=') back_input();
+}
+
+@ @<Get the next non-blank non-call token@>=
+@/do@+{get_x_token();
+}@+ while (!(cur_cmd!=spacer))
+
+@ In case you are getting bored, here is a slightly less trivial routine:
+Given a string of lowercase letters, like `\.{pt}' or `\.{plus}' or
+`\.{width}', the |scan_keyword| routine checks to see whether the next
+tokens of input match this string. The match must be exact, except that
+uppercase letters will match their lowercase counterparts; uppercase
+equivalents are determined by subtracting |'a'-'A'|, rather than using the
+|uc_code| table, since \TeX\ uses this routine only for its own limited
+set of keywords.
+
+If a match is found, the characters are effectively removed from the input
+and |true| is returned. Otherwise |false| is returned, and the input
+is left essentially unchanged (except for the fact that some macros
+may have been expanded, etc.).
+@^inner loop@>
+
+@p bool scan_keyword(str_number @!s) /*look for a given string*/
+{@+
+pointer p; /*tail of the backup list*/
+pointer @!q; /*new node being added to the token list via |store_new_token|*/
+pool_pointer @!k; /*index into |str_pool|*/
+p=backup_head;link(p)=null;k=str_start[s];
+while (k < str_start[s+1])
+ {@+get_x_token(); /*recursion is possible here*/
+@^recursion@>
+ if ((cur_cs==0)&&@|
+ ((cur_chr==so(str_pool[k]))||(cur_chr==so(str_pool[k])-'a'+'A')))
+ {@+store_new_token(cur_tok);incr(k);
+ }
+ else if ((cur_cmd!=spacer)||(p!=backup_head))
+ {@+back_input();
+ if (p!=backup_head) back_list(link(backup_head));
+ return false;
+ }
+ }
+flush_list(link(backup_head));return true;
+}
+
+@ Here is a procedure that sounds an alarm when mu and non-mu units
+are being switched.
+
+@p void mu_error(void)
+{@+print_err("Incompatible glue units");
+@.Incompatible glue units@>
+help1("I'm going to assume that 1mu=1pt when they're mixed.");
+error();
+}
+
+@ The next routine `|scan_something_internal|' is used to fetch internal
+numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}'
+when expanding constructions like `\.{\\the\\toks0}' and
+`\.{\\the\\baselineskip}'. Soon we will be considering the |scan_int|
+procedure, which calls |scan_something_internal|; on the other hand,
+|scan_something_internal| also calls |scan_int|, for constructions like
+`\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we
+have to declare |scan_int| as a |forward| procedure. A few other
+procedures are also declared at this point.
+
+@p void scan_int(void); /*scans an integer value*/
+@t\4\4@>@<Declare procedures that scan restricted classes of integers@>@;
+@t\4\4@>@<Declare procedures that scan font-related stuff@>@;
+
+@ \TeX\ doesn't know exactly what to expect when |scan_something_internal|
+begins. For example, an integer or dimension or glue value could occur
+immediately after `\.{\\hskip}'; and one can even say \.{\\the} with
+respect to token lists in constructions like
+`\.{\\xdef\\o\{\\the\\output\}}'. On the other hand, only integers are
+allowed after a construction like `\.{\\count}'. To handle the various
+possibilities, |scan_something_internal| has a |level| parameter, which
+tells the ``highest'' kind of quantity that |scan_something_internal| is
+allowed to produce. Six levels are distinguished, namely |int_val|,
+|dimen_val|, |glue_val|, |mu_val|, |ident_val|, and |tok_val|.
+
+The output of |scan_something_internal| (and of the other routines
+|scan_int|, |scan_dimen|, and |scan_glue| below) is put into the global
+variable |cur_val|, and its level is put into |cur_val_level|. The highest
+values of |cur_val_level| are special: |mu_val| is used only when
+|cur_val| points to something in a ``muskip'' register, or to one of the
+three parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip};
+|ident_val| is used only when |cur_val| points to a font identifier;
+|tok_val| is used only when |cur_val| points to |null| or to the reference
+count of a token list. The last two cases are allowed only when
+|scan_something_internal| is called with |level==tok_val|.
+
+If the output is glue, |cur_val| will point to a glue specification, and
+the reference count of that glue will have been updated to reflect this
+reference; if the output is a nonempty token list, |cur_val| will point to
+its reference count, but in this case the count will not have been updated.
+Otherwise |cur_val| will contain the integer or scaled value in question.
+
+@d int_val 0 /*integer values*/
+@d dimen_val 1 /*dimension values*/
+@d glue_val 2 /*glue specifications*/
+@d mu_val 3 /*math glue specifications*/
+@d ident_val 4 /*font identifier*/
+@d tok_val 5 /*token lists*/
+
+@<Glob...@>=
+int @!cur_val; /*value returned by numeric scanners*/
+uint8_t @!cur_val_level; /*the ``level'' of this value*/
+
+@ The hash table is initialized with `\.{\\count}', `\.{\\dimen}', `\.{\\skip}',
+and `\.{\\muskip}' all having |register| as their command code; they are
+distinguished by the |chr_code|, which is either |int_val|, |dimen_val|,
+|glue_val|, or |mu_val|.
+
+@<Put each...@>=
+primitive(@[@<|"count"|@>@], register, int_val);
+@!@:count_}{\.{\\count} primitive@>
+primitive(@[@<|"dimen"|@>@], register, dimen_val);
+@!@:dimen_}{\.{\\dimen} primitive@>
+primitive(@[@<|"skip"|@>@], register, glue_val);
+@!@:skip_}{\.{\\skip} primitive@>
+primitive(@[@<|"muskip"|@>@], register, mu_val);
+@!@:mu_skip_}{\.{\\muskip} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case register: if (chr_code==int_val) print_esc(@[@<|"count"|@>@]);
+ else if (chr_code==dimen_val) print_esc(@[@<|"dimen"|@>@]);
+ else if (chr_code==glue_val) print_esc(@[@<|"skip"|@>@]);
+ else print_esc(@[@<|"muskip"|@>@]);@+break;
+
+@ OK, we're ready for |scan_something_internal| itself. A second parameter,
+|negative|, is set |true| if the value that is found should be negated.
+It is assumed that |cur_cmd| and |cur_chr| represent the first token of
+the internal quantity to be scanned; an error will be signalled if
+|cur_cmd < min_internal| or |cur_cmd > max_internal|.
+
+@d scanned_result_end(X) cur_val_level=X;@+}
+@d scanned_result(X) @+{@+cur_val=X;scanned_result_end
+
+@p void scan_something_internal(small_number @!level, bool @!negative)
+ /*fetch an internal parameter*/
+{@+halfword m; /*|chr_code| part of the operand token*/
+uint8_t @!p; /*index into |nest|*/
+m=cur_chr;
+switch (cur_cmd) {
+case def_code: @<Fetch a character code from some table@>@;@+break;
+case toks_register: case assign_toks: case def_family: case set_font: case def_font: @<Fetch
+a token list or font identifier, provided that |level=tok_val|@>@;@+break;
+case assign_int: scanned_result(eqtb[m].i)(int_val)@;@+break;
+case assign_dimen: scanned_result(eqtb[m].sc)(dimen_val)@;@+break;
+case assign_glue: scanned_result(equiv(m))(glue_val)@;@+break;
+case assign_mu_glue: scanned_result(equiv(m))(mu_val)@;@+break;
+case set_aux: @<Fetch the |space_factor| or the |prev_depth|@>@;@+break;
+case set_prev_graf: @<Fetch the |prev_graf|@>@;@+break;
+case set_page_int: @<Fetch the |dead_cycles| or the |insert_penalties|@>@;@+break;
+case set_page_dimen: @<Fetch something on the |page_so_far|@>@;@+break;
+case set_shape: @<Fetch the |par_shape| size@>@;@+break;
+case set_box_dimen: @<Fetch a box dimension@>@;@+break;
+case char_given: case math_given: scanned_result(cur_chr)(int_val)@;@+break;
+case assign_font_dimen: @<Fetch a font dimension@>@;@+break;
+case assign_font_int: @<Fetch a font integer@>@;@+break;
+case register: @<Fetch a register@>@;@+break;
+case last_item: @<Fetch an item in the current node, if appropriate@>@;@+break;
+default:@<Complain that \.{\\the} can't do this; give zero result@>@;
+} @/
+while (cur_val_level > level) @<Convert \(c)|cur_val| to a lower level@>;
+@<Fix the reference count, if any, and negate |cur_val| if |negative|@>;
+}
+
+@ @<Fetch a character code from some table@>=
+{@+scan_char_num();
+if (m==math_code_base) scanned_result(ho(math_code(cur_val)))(int_val)@;
+else if (m < math_code_base) scanned_result(equiv(m+cur_val))(int_val)@;
+else scanned_result(eqtb[m+cur_val].i)(int_val);
+}
+
+@ @<Fetch a token list...@>=
+if (level!=tok_val)
+ {@+print_err("Missing number, treated as zero");
+@.Missing number...@>
+ help3("A number should have been here; I inserted `0'.")@/
+ ("(If you can't figure out why I needed to see a number,")@/
+ ("look up `weird error' in the index to The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+ back_error();scanned_result(0)(dimen_val);
+ }
+else if (cur_cmd <= assign_toks)
+ {@+if (cur_cmd < assign_toks) /*|cur_cmd==toks_register|*/
+ {@+scan_eight_bit_int();m=toks_base+cur_val;
+ }
+ scanned_result(equiv(m))(tok_val);
+ }
+else{@+back_input();scan_font_ident();
+ scanned_result(font_id_base+cur_val)(ident_val);
+ }
+
+@ Users refer to `\.{\\the\\spacefactor}' only in horizontal
+mode, and to `\.{\\the\\prevdepth}' only in vertical mode; so we put the
+associated mode in the modifier part of the |set_aux| command.
+The |set_page_int| command has modifier 0 or 1, for `\.{\\deadcycles}' and
+`\.{\\insertpenalties}', respectively. The |set_box_dimen| command is
+modified by either |width_offset|, |height_offset|, or |depth_offset|.
+And the |last_item| command is modified by either |int_val|, |dimen_val|,
+|glue_val|, |input_line_no_code|, or |badness_code|.
+
+@d input_line_no_code (glue_val+1) /*code for \.{\\inputlineno}*/
+@d badness_code (glue_val+2) /*code for \.{\\badness}*/
+
+@<Put each...@>=
+primitive(@[@<|"spacefactor"|@>@], set_aux, hmode);
+@!@:space_factor_}{\.{\\spacefactor} primitive@>
+primitive(@[@<|"prevdepth"|@>@], set_aux, vmode);@/
+@!@:prev_depth_}{\.{\\prevdepth} primitive@>
+primitive(@[@<|"deadcycles"|@>@], set_page_int, 0);
+@!@:dead_cycles_}{\.{\\deadcycles} primitive@>
+primitive(@[@<|"insertpenalties"|@>@], set_page_int, 1);
+@!@:insert_penalties_}{\.{\\insertpenalties} primitive@>
+primitive(@[@<|"wd"|@>@], set_box_dimen, width_offset);
+@!@:wd_}{\.{\\wd} primitive@>
+primitive(@[@<|"ht"|@>@], set_box_dimen, height_offset);
+@!@:ht_}{\.{\\ht} primitive@>
+primitive(@[@<|"dp"|@>@], set_box_dimen, depth_offset);
+@!@:dp_}{\.{\\dp} primitive@>
+primitive(@[@<|"lastpenalty"|@>@], last_item, int_val);
+@!@:last_penalty_}{\.{\\lastpenalty} primitive@>
+primitive(@[@<|"lastkern"|@>@], last_item, dimen_val);
+@!@:last_kern_}{\.{\\lastkern} primitive@>
+primitive(@[@<|"lastskip"|@>@], last_item, glue_val);
+@!@:last_skip_}{\.{\\lastskip} primitive@>
+primitive(@[@<|"inputlineno"|@>@], last_item, input_line_no_code);
+@!@:input_line_no_}{\.{\\inputlineno} primitive@>
+primitive(@[@<|"badness"|@>@], last_item, badness_code);
+@!@:badness_}{\.{\\badness} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case set_aux: if (chr_code==vmode) print_esc(@[@<|"prevdepth"|@>@]);
+@+else print_esc(@[@<|"spacefactor"|@>@]);@+break;
+case set_page_int: if (chr_code==0) print_esc(@[@<|"deadcycles"|@>@]);
+@+else print_esc(@[@<|"insertpenalties"|@>@]);@+break;
+case set_box_dimen: if (chr_code==width_offset) print_esc(@[@<|"wd"|@>@]);
+else if (chr_code==height_offset) print_esc(@[@<|"ht"|@>@]);
+else print_esc(@[@<|"dp"|@>@]);@+break;
+case last_item: switch (chr_code) {
+ case int_val: print_esc(@[@<|"lastpenalty"|@>@]);@+break;
+ case dimen_val: print_esc(@[@<|"lastkern"|@>@]);@+break;
+ case glue_val: print_esc(@[@<|"lastskip"|@>@]);@+break;
+ case input_line_no_code: print_esc(@[@<|"inputlineno"|@>@]);@+break;
+ default:print_esc(@[@<|"badness"|@>@]);
+ } @+break;
+
+@ @<Fetch the |space_factor| or the |prev_depth|@>=
+if (abs(mode)!=m)
+ {@+print_err("Improper ");print_cmd_chr(set_aux, m);
+@.Improper \\spacefactor@>
+@.Improper \\prevdepth@>
+ help4("You can refer to \\spacefactor only in horizontal mode;")@/
+ ("you can refer to \\prevdepth only in vertical mode; and")@/
+ ("neither of these is meaningful inside \\write. So")@/
+ ("I'm forgetting what you said and using zero instead.");
+ error();
+ if (level!=tok_val) scanned_result(0)(dimen_val)@;
+ else scanned_result(0)(int_val);
+ }
+else if (m==vmode) scanned_result(prev_depth)(dimen_val)@;
+else scanned_result(space_factor)(int_val)
+
+@ @<Fetch the |dead_cycles| or the |insert_penalties|@>=
+{@+if (m==0) cur_val=dead_cycles;@+else cur_val=insert_penalties;
+cur_val_level=int_val;
+}
+
+@ @<Fetch a box dimension@>=
+{@+scan_eight_bit_int();
+if (box(cur_val)==null) cur_val=0;@+else cur_val=mem[box(cur_val)+m].sc;
+cur_val_level=dimen_val;
+}
+
+@ Inside an \.{\\output} routine, a user may wish to look at the page totals
+that were present at the moment when output was triggered.
+
+@d max_dimen 07777777777 /*$2^{30}-1$*/
+
+@<Fetch something on the |page_so_far|@>=
+{@+if ((page_contents==empty)&&(!output_active))
+ if (m==0) cur_val=max_dimen;@+else cur_val=0;
+else cur_val=page_so_far[m];
+cur_val_level=dimen_val;
+}
+
+@ @<Fetch the |prev_graf|@>=
+if (mode==0) scanned_result(0)(int_val)@; /*|prev_graf==0| within \.{\\write}*/
+else{@+nest[nest_ptr]=cur_list;p=nest_ptr;
+ while (abs(nest[p].mode_field)!=vmode) decr(p);
+ scanned_result(nest[p].pg_field)(int_val);
+ }
+
+@ @<Fetch the |par_shape| size@>=
+{@+if (par_shape_ptr==null) cur_val=0;
+else cur_val=info(par_shape_ptr);
+cur_val_level=int_val;
+}
+
+@ 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.
+
+@<Fetch an item in the current node...@>=
+if (cur_chr > glue_val)
+ {@+if (cur_chr==input_line_no_code) cur_val=line;
+ else cur_val=last_badness; /*|cur_chr==badness_code|*/
+ cur_val_level=int_val;
+ }
+else{@+if (cur_chr==glue_val) cur_val=zero_glue;@+else cur_val=0;
+ cur_val_level=cur_chr;
+ if (!is_char_node(tail)&&(mode!=0))
+ switch (cur_chr) {
+ case int_val: if (type(tail)==penalty_node) cur_val=penalty(tail);@+break;
+ case dimen_val: if (type(tail)==kern_node) cur_val=width(tail);@+break;
+ case glue_val: if (type(tail)==glue_node)
+ {@+cur_val=glue_ptr(tail);
+ if (subtype(tail)==mu_glue) cur_val_level=mu_val;
+ }
+ } /*there are no other cases*/
+ else if ((mode==vmode)&&(tail==head))
+ switch (cur_chr) {
+ case int_val: cur_val=last_penalty;@+break;
+ case dimen_val: cur_val=last_kern;@+break;
+ case glue_val: if (last_glue!=max_halfword) cur_val=last_glue;
+ } /*there are no other cases*/
+ }
+
+@ @<Fetch a font dimension@>=
+{@+find_font_dimen(false);font_info[fmem_ptr].sc=0;
+scanned_result(font_info[cur_val].sc)(dimen_val);
+}
+
+@ @<Fetch a font integer@>=
+{@+scan_font_ident();
+if (m==0) scanned_result(hyphen_char[cur_val])(int_val)@;
+else scanned_result(skew_char[cur_val])(int_val);
+}
+
+@ @<Fetch a register@>=
+{@+scan_eight_bit_int();
+switch (m) {
+case int_val: cur_val=count(cur_val);@+break;
+case dimen_val: cur_val=dimen(cur_val);@+break;
+case glue_val: cur_val=skip(cur_val);@+break;
+case mu_val: cur_val=mu_skip(cur_val);
+} /*there are no other cases*/
+cur_val_level=m;
+}
+
+@ @<Complain that \.{\\the} can't do this; give zero result@>=
+{@+print_err("You can't use `");print_cmd_chr(cur_cmd, cur_chr);
+@.You can't use x after ...@>
+print_str("' after ");print_esc(@[@<|"the"|@>@]);
+help1("I'm forgetting what you said and using zero instead.");
+error();
+if (level!=tok_val) scanned_result(0)(dimen_val)@;
+else scanned_result(0)(int_val);
+}
+
+@ When a |glue_val| changes to a |dimen_val|, we use the width component
+of the glue; there is no need to decrease the reference count, since it
+has not yet been increased. When a |dimen_val| changes to an |int_val|,
+we use scaled points so that the value doesn't actually change. And when a
+|mu_val| changes to a |glue_val|, the value doesn't change either.
+
+@<Convert \(c)|cur_val| to a lower level@>=
+{@+if (cur_val_level==glue_val) cur_val=width(cur_val);
+else if (cur_val_level==mu_val) mu_error();
+decr(cur_val_level);
+}
+
+@ If |cur_val| points to a glue specification at this point, the reference
+count for the glue does not yet include the reference by |cur_val|.
+If |negative| is |true|, |cur_val_level| is known to be | <= mu_val|.
+
+@<Fix the reference count, if any,...@>=
+if (negative)
+ if (cur_val_level >= glue_val)
+ {@+cur_val=new_spec(cur_val);
+ @<Negate all three glue components of |cur_val|@>;
+ }
+ else negate(cur_val);
+else if ((cur_val_level >= glue_val)&&(cur_val_level <= mu_val))
+ add_glue_ref(cur_val)
+
+@ @<Negate all three...@>=
+{@+negate(width(cur_val));
+negate(stretch(cur_val));
+negate(shrink(cur_val));
+}
+
+@ Our next goal is to write the |scan_int| procedure, which scans anything that
+\TeX\ treats as an integer. But first we might as well look at some simple
+applications of |scan_int| that have already been made inside of
+|scan_something_internal|.
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+void scan_eight_bit_int(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 255))
+ {@+print_err("Bad register code");
+@.Bad register code@>
+ help2("A register number must be between 0 and 255.")@/
+ ("I changed this one to zero.");int_error(cur_val);cur_val=0;
+ }
+}
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+void scan_char_num(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 255))
+ {@+print_err("Bad character code");
+@.Bad character code@>
+ help2("A character number must be between 0 and 255.")@/
+ ("I changed this one to zero.");int_error(cur_val);cur_val=0;
+ }
+}
+
+@ While we're at it, we might as well deal with similar routines that
+will be needed later.
+
+@<Declare procedures that scan restricted classes of integers@>=
+void scan_four_bit_int(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 15))
+ {@+print_err("Bad number");
+@.Bad number@>
+ help2("Since I expected to read a number between 0 and 15,")@/
+ ("I changed this one to zero.");int_error(cur_val);cur_val=0;
+ }
+}
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+void scan_fifteen_bit_int(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 077777))
+ {@+print_err("Bad mathchar");
+@.Bad mathchar@>
+ help2("A mathchar number must be between 0 and 32767.")@/
+ ("I changed this one to zero.");int_error(cur_val);cur_val=0;
+ }
+}
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+void scan_twenty_seven_bit_int(void)
+{@+scan_int();
+if ((cur_val < 0)||(cur_val > 0777777777))
+ {@+print_err("Bad delimiter code");
+@.Bad delimiter code@>
+ help2("A numeric delimiter code must be between 0 and 2^{27}-1.")@/
+ ("I changed this one to zero.");int_error(cur_val);cur_val=0;
+ }
+}
+
+@ An integer number can be preceded by any number of spaces and `\.+' or
+`\.-' signs. Then comes either a decimal constant (i.e., radix 10), an
+octal constant (i.e., radix 8, preceded by~\.\'), a hexadecimal constant
+(radix 16, preceded by~\."), an alphabetic constant (preceded by~\.\`), or
+an internal variable. After scanning is complete,
+|cur_val| will contain the answer, which must be at most
+$2^{31}-1=2147483647$ in absolute value. The value of |radix| is set to
+10, 8, or 16 in the cases of decimal, octal, or hexadecimal constants,
+otherwise |radix| is set to zero. An optional space follows a constant.
+
+@d octal_token (other_token+'\'') /*apostrophe, indicates an octal constant*/
+@d hex_token (other_token+'"') /*double quote, indicates a hex constant*/
+@d alpha_token (other_token+'`') /*reverse apostrophe, precedes alpha constants*/
+@d point_token (other_token+'.') /*decimal point*/
+@d continental_point_token (other_token+',') /*decimal point, Eurostyle*/
+
+@<Glob...@>=
+small_number @!radix; /*|scan_int| sets this to 8, 10, 16, or zero*/
+
+@ We initialize the following global variables just in case |expand|
+comes into action before any of the basic scanning routines has assigned
+them a value.
+
+@<Set init...@>=
+cur_val=0;cur_val_level=int_val;radix=0;cur_order=normal;
+
+@ The |scan_int| routine is used also to scan the integer part of a
+fraction; for example, the `\.3' in `\.{3.14159}' will be found by
+|scan_int|. The |scan_dimen| routine assumes that |cur_tok==point_token|
+after the integer part of such a fraction has been scanned by |scan_int|,
+and that the decimal point has been backed up to be scanned again.
+
+@p void scan_int(void) /*sets |cur_val| to an integer*/
+{@+
+bool negative; /*should the answer be negated?*/
+int @!m; /*|@t$2^{31}$@>/radix|, the threshold of danger*/
+small_number @!d; /*the digit just scanned*/
+bool @!vacuous; /*have no digits appeared?*/
+bool @!OK_so_far; /*has an error message been issued?*/
+radix=0;OK_so_far=true;@/
+@<Get the next non-blank non-sign token; set |negative| appropriately@>;
+if (cur_tok==alpha_token) @<Scan an alphabetic character code into |cur_val|@>@;
+else if ((cur_cmd >= min_internal)&&(cur_cmd <= max_internal))
+ scan_something_internal(int_val, false);
+else@<Scan a numeric constant@>;
+if (negative) negate(cur_val);
+}
+
+@ @<Get the next non-blank non-sign token...@>=
+negative=false;
+@/do@+{@<Get the next non-blank non-call token@>;
+if (cur_tok==other_token+'-')
+ {@+negative=!negative;cur_tok=other_token+'+';
+ }
+}@+ while (!(cur_tok!=other_token+'+'))
+
+@ A space is ignored after an alphabetic character constant, so that
+such constants behave like numeric ones.
+
+@<Scan an alphabetic character code into |cur_val|@>=
+{@+get_token(); /*suppress macro expansion*/
+if (cur_tok < cs_token_flag)
+ {@+cur_val=cur_chr;
+ if (cur_cmd <= right_brace)
+ if (cur_cmd==right_brace) incr(align_state);
+ else decr(align_state);
+ }
+else if (cur_tok < cs_token_flag+single_base)
+ cur_val=cur_tok-cs_token_flag-active_base;
+else cur_val=cur_tok-cs_token_flag-single_base;
+if (cur_val > 255)
+ {@+print_err("Improper alphabetic constant");
+@.Improper alphabetic constant@>
+ help2("A one-character control sequence belongs after a ` mark.")@/
+ ("So I'm essentially inserting \\0 here.");
+ cur_val='0';back_error();
+ }
+else@<Scan an optional space@>;
+}
+
+@ @<Scan an optional space@>=
+{@+get_x_token();if (cur_cmd!=spacer) back_input();
+}
+
+@ @<Scan a numeric constant@>=
+{@+radix=10;m=214748364;
+if (cur_tok==octal_token)
+ {@+radix=8;m=02000000000;get_x_token();
+ }
+else if (cur_tok==hex_token)
+ {@+radix=16;m=01000000000;get_x_token();
+ }
+vacuous=true;cur_val=0;@/
+@<Accumulate the constant until |cur_tok| is not a suitable digit@>;
+if (vacuous) @<Express astonishment that no number was here@>@;
+else if (cur_cmd!=spacer) back_input();
+}
+
+@ @d infinity 017777777777 /*the largest positive value that \TeX\ knows*/
+@d zero_token (other_token+'0') /*zero, the smallest digit*/
+@d A_token (letter_token+'A') /*the smallest special hex digit*/
+@d other_A_token (other_token+'A') /*special hex digit of type |other_char|*/
+
+@<Accumulate the constant...@>=
+loop@+{@+if ((cur_tok < zero_token+radix)&&(cur_tok >= zero_token)&&
+ (cur_tok <= zero_token+9)) d=cur_tok-zero_token;
+ else if (radix==16)
+ if ((cur_tok <= A_token+5)&&(cur_tok >= A_token)) d=cur_tok-A_token+10;
+ else if ((cur_tok <= other_A_token+5)&&(cur_tok >= other_A_token))
+ d=cur_tok-other_A_token+10;
+ else goto done;
+ else goto done;
+ vacuous=false;
+ if ((cur_val >= m)&&((cur_val > m)||(d > 7)||(radix!=10)))
+ {@+if (OK_so_far)
+ {@+print_err("Number too big");
+@.Number too big@>
+ help2("I can only go up to 2147483647='17777777777=\"7FFFFFFF,")@/
+ ("so I'm using that number instead of yours.");
+ error();cur_val=infinity;OK_so_far=false;
+ }
+ }
+ else cur_val=cur_val*radix+d;
+ get_x_token();
+ }
+done:
+
+@ @<Express astonishment...@>=
+{@+print_err("Missing number, treated as zero");
+@.Missing number...@>
+help3("A number should have been here; I inserted `0'.")@/
+ ("(If you can't figure out why I needed to see a number,")@/
+ ("look up `weird error' in the index to The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+back_error();
+}
+
+@ The |scan_dimen| routine is similar to |scan_int|, but it sets |cur_val| to
+a |scaled| value, i.e., an integral number of sp. One of its main tasks
+is therefore to interpret the abbreviations for various kinds of units and
+to convert measurements to scaled points.
+
+There are three parameters: |mu| is |true| if the finite units must be
+`\.{mu}', while |mu| is |false| if `\.{mu}' units are disallowed;
+|inf| is |true| if the infinite units `\.{fil}', `\.{fill}', `\.{filll}'
+are permitted; and |shortcut| is |true| if |cur_val| already contains
+an integer and only the units need to be considered.
+
+The order of infinity that was found in the case of infinite glue is returned
+in the global variable |cur_order|.
+
+@<Glob...@>=
+glue_ord @!cur_order; /*order of infinity found by |scan_dimen|*/
+
+@ Constructions like `\.{-\'77 pt}' are legal dimensions, so |scan_dimen|
+may begin with |scan_int|. This explains why it is convenient to use
+|scan_int| also for the integer part of a decimal fraction.
+
+Several branches of |scan_dimen| work with |cur_val| as an integer and
+with an auxiliary fraction |f|, so that the actual quantity of interest is
+$|cur_val|+|f|/2^{16}$. At the end of the routine, this ``unpacked''
+representation is put into the single word |cur_val|, which suddenly
+switches significance from |int| to |scaled|.
+
+@d scan_normal_dimen scan_dimen(false, false, false)
+
+@p void scan_dimen(bool @!mu, bool @!inf, bool @!shortcut)
+ /*sets |cur_val| to a dimension*/
+{@+
+bool negative; /*should the answer be negated?*/
+int @!f; /*numerator of a fraction whose denominator is $2^{16}$*/
+@<Local variables for dimension calculations@>@;
+f=0;arith_error=false;cur_order=normal;negative=false;
+if (!shortcut)
+ {@+@<Get the next non-blank non-sign...@>;
+ if ((cur_cmd >= min_internal)&&(cur_cmd <= max_internal))
+ @<Fetch an internal dimension and |goto attach_sign|, or fetch an internal integer@>@;
+ else{@+back_input();
+ if (cur_tok==continental_point_token) cur_tok=point_token;
+ if (cur_tok!=point_token) scan_int();
+ else{@+radix=10;cur_val=0;
+ }
+ if (cur_tok==continental_point_token) cur_tok=point_token;
+ if ((radix==10)&&(cur_tok==point_token)) @<Scan decimal fraction@>;
+ }
+ }
+if (cur_val < 0) /*in this case |f==0|*/
+ {@+negative=!negative;negate(cur_val);
+ }
+@<Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there are |x|
+sp per unit; |goto attach_sign| if the units are internal@>;
+@<Scan an optional space@>;
+attach_sign: if (arith_error||(abs(cur_val) >= 010000000000))
+ @<Report that this dimension is out of range@>;
+if (negative) negate(cur_val);
+}
+
+@ @<Fetch an internal dimension and |goto attach_sign|...@>=
+if (mu)
+ {@+scan_something_internal(mu_val, false);
+ @<Coerce glue to a dimension@>;
+ if (cur_val_level==mu_val) goto attach_sign;
+ if (cur_val_level!=int_val) mu_error();
+ }
+else{@+scan_something_internal(dimen_val, false);
+ if (cur_val_level==dimen_val) goto attach_sign;
+ }
+
+@ @<Local variables for dimension calculations@>=
+uint32_t @!num, @!denom; /*conversion ratio for the scanned units*/
+int @!k, @!kk; /*number of digits in a decimal fraction*/
+pointer @!p, @!q; /*top of decimal digit stack*/
+scaled @!v; /*an internal dimension*/
+int @!save_cur_val; /*temporary storage of |cur_val|*/
+
+@ The following code is executed when |scan_something_internal| was
+called asking for |mu_val|, when we really wanted a ``mudimen'' instead
+of ``muglue.''
+
+@<Coerce glue to a dimension@>=
+if (cur_val_level >= glue_val)
+ {@+v=width(cur_val);delete_glue_ref(cur_val);cur_val=v;
+ }
+
+@ When the following code is executed, we have |cur_tok==point_token|, but this
+token has been backed up using |back_input|; we must first discard it.
+
+It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
+Let's hope people don't use that fact.
+
+@<Scan decimal fraction@>=
+{@+k=0;p=null;get_token(); /*|point_token| is being re-scanned*/
+loop@+{@+get_x_token();
+ if ((cur_tok > zero_token+9)||(cur_tok < zero_token)) goto done1;
+ if (k < 17) /*digits for |k >= 17| cannot affect the result*/
+ {@+q=get_avail();link(q)=p;info(q)=cur_tok-zero_token;
+ p=q;incr(k);
+ }
+ }
+done1: for (kk=k; kk>=1; kk--)
+ {@+dig[kk-1]=info(p);q=p;p=link(p);free_avail(q);
+ }
+f=round_decimals(k);
+if (cur_cmd!=spacer) back_input();
+}
+
+@ Now comes the harder part: At this point in the program, |cur_val| is a
+nonnegative integer and $f/2^{16}$ is a nonnegative fraction less than 1;
+we want to multiply the sum of these two quantities by the appropriate
+factor, based on the specified units, in order to produce a |scaled|
+result, and we want to do the calculation with fixed point arithmetic that
+does not overflow.
+
+@<Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$...@>=
+if (inf) @<Scan for \(f)\.{fil} units; |goto attach_fraction| if found@>;
+@<Scan for \(u)units that are internal dimensions; |goto attach_sign| with |cur_val|
+set if found@>;
+if (mu) @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>;
+if (scan_keyword(@[@<|"true"|@>@])) @<Adjust \(f)for the magnification ratio@>;
+@.true@>
+if (scan_keyword(@[@<|"pt"|@>@])) goto attach_fraction; /*the easy case*/
+@.pt@>
+@<Scan for \(a)all other units and adjust |cur_val| and |f| accordingly; |goto done|
+in the case of scaled points@>;
+attach_fraction: if (cur_val >= 040000) arith_error=true;
+else cur_val=cur_val*unity+f;
+done:
+
+@ A specification like `\.{filllll}' or `\.{fill L L L}' will lead to two
+error messages (one for each additional keyword \.{"l"}).
+
+@<Scan for \(f)\.{fil} units...@>=
+if (scan_keyword(@[@<|"fil"|@>@]))
+@.fil@>
+ {@+cur_order=fil;
+ while (scan_keyword('l'))
+ {@+if (cur_order==filll)
+ {@+print_err("Illegal unit of measure (");
+@.Illegal unit of measure@>
+ print_str("replaced by filll)");
+ help1("I dddon't go any higher than filll.");error();
+ }
+ else incr(cur_order);
+ }
+ goto attach_fraction;
+ }
+
+@ @<Scan for \(u)units that are internal dimensions...@>=
+save_cur_val=cur_val;
+@<Get the next non-blank non-call...@>;
+if ((cur_cmd < min_internal)||(cur_cmd > max_internal)) back_input();
+else{@+if (mu)
+ {@+scan_something_internal(mu_val, false);@<Coerce glue...@>;
+ if (cur_val_level!=mu_val) mu_error();
+ }
+ else scan_something_internal(dimen_val, false);
+ v=cur_val;goto found;
+ }
+if (mu) goto not_found;
+if (scan_keyword(@[@<|"em"|@>@])) v=(@<The em width for |cur_font|@>);
+@.em@>
+else if (scan_keyword(@[@<|"ex"|@>@])) v=(@<The x-height for |cur_font|@>);
+@.ex@>
+else goto not_found;
+@<Scan an optional space@>;
+found: cur_val=nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
+goto attach_sign;
+not_found:
+
+@ @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>=
+if (scan_keyword(@[@<|"mu"|@>@])) goto attach_fraction;
+@.mu@>
+else{@+print_err("Illegal unit of measure (");print_str("mu inserted)");
+@.Illegal unit of measure@>
+ help4("The unit of measurement in math glue must be mu.")@/
+ ("To recover gracefully from this error, it's best to")@/
+ ("delete the erroneous units; e.g., type `2' to delete")@/
+ ("two letters. (See Chapter 27 of The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+ error();goto attach_fraction;
+ }
+
+@ @<Adjust \(f)for the magnification ratio@>=
+{@+prepare_mag();
+if (mag!=1000)
+ {@+cur_val=xn_over_d(cur_val, 1000, mag);
+ f=(1000*f+0200000*rem)/mag;
+ cur_val=cur_val+(f/0200000);f=f%0200000;
+ }
+}
+
+@ The necessary conversion factors can all be specified exactly as
+fractions whose numerator and denominator sum to 32768 or less.
+According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$;
+this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard
+@^Bosshard, Hans Rudolf@>
+in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980).
+
+@d set_conversion_end(X) denom=X;}
+@d set_conversion(X) @+{@+num=X;set_conversion_end
+
+@<Scan for \(a)all other units and adjust |cur_val| and |f|...@>=
+if (scan_keyword(@[@<|"in"|@>@])) set_conversion(7227)(100)@;
+@.in@>
+else if (scan_keyword(@[@<|"pc"|@>@])) set_conversion(12)(1)@;
+@.pc@>
+else if (scan_keyword(@[@<|"cm"|@>@])) set_conversion(7227)(254)@;
+@.cm@>
+else if (scan_keyword(@[@<|"mm"|@>@])) set_conversion(7227)(2540)@;
+@.mm@>
+else if (scan_keyword(@[@<|"bp"|@>@])) set_conversion(7227)(7200)@;
+@.bp@>
+else if (scan_keyword(@[@<|"dd"|@>@])) set_conversion(1238)(1157)@;
+@.dd@>
+else if (scan_keyword(@[@<|"cc"|@>@])) set_conversion(14856)(1157)@;
+@.cc@>
+else if (scan_keyword(@[@<|"sp"|@>@])) goto done;
+@.sp@>
+else@<Complain about unknown unit and |goto done2|@>;
+cur_val=xn_over_d(cur_val, num, denom);
+f=(num*f+0200000*rem)/denom;@/
+cur_val=cur_val+(f/0200000);f=f%0200000;
+done2:
+
+@ @<Complain about unknown unit...@>=
+{@+print_err("Illegal unit of measure (");print_str("pt inserted)");
+@.Illegal unit of measure@>
+help6("Dimensions can be in units of em, ex, in, pt, pc,")@/
+ ("cm, mm, dd, cc, bp, or sp; but yours is a new one!")@/
+ ("I'll assume that you meant to say pt, for printer's points.")@/
+ ("To recover gracefully from this error, it's best to")@/
+ ("delete the erroneous units; e.g., type `2' to delete")@/
+ ("two letters. (See Chapter 27 of The TeXbook.)");
+@:TeXbook}{\sl The \TeX book@>
+error();goto done2;
+}
+
+
+@ @<Report that this dimension is out of range@>=
+{@+print_err("Dimension too large");
+@.Dimension too large@>
+help2("I can't work with sizes bigger than about 19 feet.")@/
+ ("Continue and I'll use the largest value I can.");@/
+error();cur_val=max_dimen;arith_error=false;
+}
+
+@ The final member of \TeX's value-scanning trio is |scan_glue|, which
+makes |cur_val| point to a glue specification. The reference count of that
+glue spec will take account of the fact that |cur_val| is pointing to~it.
+
+The |level| parameter should be either |glue_val| or |mu_val|.
+
+Since |scan_dimen| was so much more complex than |scan_int|, we might expect
+|scan_glue| to be even worse. But fortunately, it is very simple, since
+most of the work has already been done.
+
+@p void scan_glue(small_number @!level)
+ /*sets |cur_val| to a glue spec pointer*/
+{@+
+bool negative; /*should the answer be negated?*/
+pointer @!q; /*new glue specification*/
+bool @!mu; /*does |level==mu_val|?*/
+mu=(level==mu_val);@<Get the next non-blank non-sign...@>;
+if ((cur_cmd >= min_internal)&&(cur_cmd <= max_internal))
+ {@+scan_something_internal(level, negative);
+ if (cur_val_level >= glue_val)
+ {@+if (cur_val_level!=level) mu_error();
+ return;
+ }
+ if (cur_val_level==int_val) scan_dimen(mu, false, true);
+ else if (level==mu_val) mu_error();
+ }
+else{@+back_input();scan_dimen(mu, false, false);
+ if (negative) negate(cur_val);
+ }
+@<Create a new glue specification whose width is |cur_val|; scan for its stretch and
+shrink components@>;
+}
+
+@ @<Create a new glue specification whose width is |cur_val|...@>=
+q=new_spec(zero_glue);width(q)=cur_val;
+if (scan_keyword(@[@<|"plus"|@>@]))
+@.plus@>
+ {@+scan_dimen(mu, true, false);
+ stretch(q)=cur_val;stretch_order(q)=cur_order;
+ }
+if (scan_keyword(@[@<|"minus"|@>@]))
+@.minus@>
+ {@+scan_dimen(mu, true, false);
+ shrink(q)=cur_val;shrink_order(q)=cur_order;
+ }
+cur_val=q
+
+@ Here's a similar procedure that returns a pointer to a rule node. This
+routine is called just after \TeX\ has seen \.{\\hrule} or \.{\\vrule};
+therefore |cur_cmd| will be either |hrule| or |vrule|. The idea is to store
+the default rule dimensions in the node, then to override them if
+`\.{height}' or `\.{width}' or `\.{depth}' specifications are
+found (in any order).
+
+@d default_rule 26214 /*0.4\thinspace pt*/
+
+@p pointer scan_rule_spec(void)
+{@+
+pointer q; /*the rule node being created*/
+q=new_rule(); /*|width|, |depth|, and |height| all equal |null_flag| now*/
+if (cur_cmd==vrule) width(q)=default_rule;
+else{@+height(q)=default_rule;depth(q)=0;
+ }
+reswitch: if (scan_keyword(@[@<|"width"|@>@]))
+@.width@>
+ {@+scan_normal_dimen;width(q)=cur_val;goto reswitch;
+ }
+if (scan_keyword(@[@<|"height"|@>@]))
+@.height@>
+ {@+scan_normal_dimen;height(q)=cur_val;goto reswitch;
+ }
+if (scan_keyword(@[@<|"depth"|@>@]))
+@.depth@>
+ {@+scan_normal_dimen;depth(q)=cur_val;goto reswitch;
+ }
+return q;
+}
+
+@* Building token lists.
+The token lists for macros and for other things like \.{\\mark} and \.{\\output}
+and \.{\\write} are produced by a procedure called |scan_toks|.
+
+Before we get into the details of |scan_toks|, let's consider a much
+simpler task, that of converting the current string into a token list.
+The |str_toks| function does this; it classifies spaces as type |spacer|
+and everything else as type |other_char|.
+
+The token list created by |str_toks| begins at |link(temp_head)| and ends
+at the value |p| that is returned. (If |p==temp_head|, the list is empty.)
+
+@p pointer str_toks(pool_pointer @!b)
+ /*changes the string |str_pool[b dotdot pool_ptr]| to a token list*/
+{@+pointer p; /*tail of the token list*/
+pointer @!q; /*new node being added to the token list via |store_new_token|*/
+halfword @!t; /*token being appended*/
+pool_pointer @!k; /*index into |str_pool|*/
+str_room(1);
+p=temp_head;link(p)=null;k=b;
+while (k < pool_ptr)
+ {@+t=so(str_pool[k]);
+ if (t==' ') t=space_token;
+ else t=other_token+t;
+ fast_store_new_token(t);
+ incr(k);
+ }
+pool_ptr=b;return p;
+}
+
+@ The main reason for wanting |str_toks| is the next function,
+|the_toks|, which has similar input/output characteristics.
+
+This procedure is supposed to scan something like `\.{\\skip\\count12}',
+i.e., whatever can follow `\.{\\the}', and it constructs a token list
+containing something like `\.{-3.0pt minus 0.5fill}'.
+
+@p pointer the_toks(void)
+{@+uint8_t old_setting; /*holds |selector| setting*/
+pointer @!p, @!q, @!r; /*used for copying a token list*/
+pool_pointer @!b; /*base of temporary string*/
+get_x_token();scan_something_internal(tok_val, false);
+if (cur_val_level >= ident_val) @<Copy the token list@>@;
+else{@+old_setting=selector;selector=new_string;b=pool_ptr;
+ switch (cur_val_level) {
+ case int_val: print_int(cur_val);@+break;
+ case dimen_val: {@+print_scaled(cur_val);print_str("pt");
+ } @+break;
+ case glue_val: {@+print_spec(cur_val,@[@<|"pt"|@>@]);delete_glue_ref(cur_val);
+ } @+break;
+ case mu_val: {@+print_spec(cur_val,@[@<|"mu"|@>@]);delete_glue_ref(cur_val);
+ }
+ } /*there are no other cases*/
+ selector=old_setting;return str_toks(b);
+ }
+}
+
+@ @<Copy the token list@>=
+{@+p=temp_head;link(p)=null;
+if (cur_val_level==ident_val) store_new_token(cs_token_flag+cur_val)@;
+else if (cur_val!=null)
+ {@+r=link(cur_val); /*do not copy the reference count*/
+ while (r!=null)
+ {@+fast_store_new_token(info(r));r=link(r);
+ }
+ }
+return p;
+}
+
+@ Here's part of the |expand| subroutine that we are now ready to complete:
+
+@p void ins_the_toks(void)
+{@+link(garbage)=the_toks();ins_list(link(temp_head));
+}
+
+@ The primitives \.{\\number}, \.{\\romannumeral}, \.{\\string}, \.{\\meaning},
+\.{\\fontname}, and \.{\\jobname} are defined as follows.
+
+@d number_code 0 /*command code for \.{\\number}*/
+@d roman_numeral_code 1 /*command code for \.{\\romannumeral}*/
+@d string_code 2 /*command code for \.{\\string}*/
+@d meaning_code 3 /*command code for \.{\\meaning}*/
+@d font_name_code 4 /*command code for \.{\\fontname}*/
+@d job_name_code 5 /*command code for \.{\\jobname}*/
+
+@<Put each...@>=
+primitive(@[@<|"number"|@>@], convert, number_code);@/
+@!@:number_}{\.{\\number} primitive@>
+primitive(@[@<|"romannumeral"|@>@], convert, roman_numeral_code);@/
+@!@:roman_numeral_}{\.{\\romannumeral} primitive@>
+primitive(@[@<|"string"|@>@], convert, string_code);@/
+@!@:string_}{\.{\\string} primitive@>
+primitive(@[@<|"meaning"|@>@], convert, meaning_code);@/
+@!@:meaning_}{\.{\\meaning} primitive@>
+primitive(@[@<|"fontname"|@>@], convert, font_name_code);@/
+@!@:font_name_}{\.{\\fontname} primitive@>
+primitive(@[@<|"jobname"|@>@], convert, job_name_code);@/
+@!@:job_name_}{\.{\\jobname} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case convert: switch (chr_code) {
+ case number_code: print_esc(@[@<|"number"|@>@]);@+break;
+ case roman_numeral_code: print_esc(@[@<|"romannumeral"|@>@]);@+break;
+ case string_code: print_esc(@[@<|"string"|@>@]);@+break;
+ case meaning_code: print_esc(@[@<|"meaning"|@>@]);@+break;
+ case font_name_code: print_esc(@[@<|"fontname"|@>@]);@+break;
+ default:print_esc(@[@<|"jobname"|@>@]);
+ } @+break;
+
+@ The procedure |conv_toks| uses |str_toks| to insert the token list
+for |convert| functions into the scanner; `\.{\\outer}' control sequences
+are allowed to follow `\.{\\string}' and `\.{\\meaning}'.
+
+@p void conv_toks(void)
+{@+uint8_t old_setting; /*holds |selector| setting*/
+uint8_t @!c; /*desired type of conversion*/
+small_number @!save_scanner_status; /*|scanner_status| upon entry*/
+pool_pointer @!b; /*base of temporary string*/
+c=cur_chr;@<Scan the argument for command |c|@>;
+old_setting=selector;selector=new_string;b=pool_ptr;
+@<Print the result of command |c|@>;
+selector=old_setting;link(garbage)=str_toks(b);ins_list(link(temp_head));
+}
+
+@ @<Scan the argument for command |c|@>=
+switch (c) {
+case number_code: case roman_numeral_code: scan_int();@+break;
+case string_code: case meaning_code: {@+save_scanner_status=scanner_status;
+ scanner_status=normal;get_token();scanner_status=save_scanner_status;
+ } @+break;
+case font_name_code: scan_font_ident();@+break;
+case job_name_code: if (job_name==0) open_log_file();
+} /*there are no other cases*/
+
+@ @<Print the result of command |c|@>=
+switch (c) {
+case number_code: print_int(cur_val);@+break;
+case roman_numeral_code: print_roman_int(cur_val);@+break;
+case string_code: if (cur_cs!=0) sprint_cs(cur_cs);
+ else print_char(cur_chr);@+break;
+case meaning_code: print_meaning();@+break;
+case font_name_code: {@+print(font_name[cur_val]);
+ if (font_size[cur_val]!=font_dsize[cur_val])
+ {@+print_str(" at ");print_scaled(font_size[cur_val]);
+ print_str("pt");
+ }
+ } @+break;
+case job_name_code: print(job_name);
+} /*there are no other cases*/
+
+@ Now we can't postpone the difficulties any longer; we must bravely tackle
+|scan_toks|. This function returns a pointer to the tail of a new token
+list, and it also makes |def_ref| point to the reference count at the
+head of that list.
+
+There are two boolean parameters, |macro_def| and |xpand|. If |macro_def|
+is true, the goal is to create the token list for a macro definition;
+otherwise the goal is to create the token list for some other \TeX\
+primitive: \.{\\mark}, \.{\\output}, \.{\\everypar}, \.{\\lowercase},
+\.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\write}, or
+\.{\\special}. In the latter cases a left brace must be scanned next; this
+left brace will not be part of the token list, nor will the matching right
+brace that comes at the end. If |xpand| is false, the token list will
+simply be copied from the input using |get_token|. Otherwise all expandable
+tokens will be expanded until unexpandable tokens are left, except that
+the results of expanding `\.{\\the}' are not expanded further.
+If both |macro_def| and |xpand| are true, the expansion applies
+only to the macro body (i.e., to the material following the first
+|left_brace| character).
+
+The value of |cur_cs| when |scan_toks| begins should be the |eqtb|
+address of the control sequence to display in ``runaway'' error
+messages.
+
+@p pointer scan_toks(bool @!macro_def, bool @!xpand)
+{@+
+halfword t; /*token representing the highest parameter number*/
+halfword @!s; /*saved token*/
+pointer @!p; /*tail of the token list being built*/
+pointer @!q; /*new node being added to the token list via |store_new_token|*/
+halfword @!unbalance; /*number of unmatched left braces*/
+halfword @!hash_brace; /*possible `\.{\#\{}' token*/
+if (macro_def) scanner_status=defining;
+@+else scanner_status=absorbing;
+warning_index=cur_cs;def_ref=get_avail();token_ref_count(def_ref)=null;
+p=def_ref;hash_brace=0;t=zero_token;
+if (macro_def) @<Scan and build the parameter part of the macro definition@>@;
+else scan_left_brace(); /*remove the compulsory left brace*/
+@<Scan and build the body of the token list; |goto found| when finished@>;
+found: scanner_status=normal;
+if (hash_brace!=0) store_new_token(hash_brace);
+return p;
+}
+
+@ @<Scan and build the parameter part...@>=
+{@+loop{@+get_token(); /*set |cur_cmd|, |cur_chr|, |cur_tok|*/
+ if (cur_tok < right_brace_limit) goto done1;
+ if (cur_cmd==mac_param)
+ @<If the next character is a parameter number, make |cur_tok| a |match| token;
+but if it is a left brace, store `|left_brace|, |end_match|', set |hash_brace|, and
+|goto done|@>;
+ store_new_token(cur_tok);
+ }
+done1: store_new_token(end_match_token);
+if (cur_cmd==right_brace)
+ @<Express shock at the missing left brace; |goto found|@>;
+done: ;}
+
+@ @<Express shock...@>=
+{@+print_err("Missing { inserted");incr(align_state);
+@.Missing \{ inserted@>
+help2("Where was the left brace? You said something like `\\def\\a}',")@/
+ ("which I'm going to interpret as `\\def\\a{}'.");error();goto found;
+}
+
+@ @<If the next character is a parameter number...@>=
+{@+s=match_token+cur_chr;get_token();
+if (cur_cmd==left_brace)
+ {@+hash_brace=cur_tok;
+ store_new_token(cur_tok);store_new_token(end_match_token);
+ goto done;
+ }
+if (t==zero_token+9)
+ {@+print_err("You already have nine parameters");
+@.You already have nine...@>
+ help1("I'm going to ignore the # sign you just used.");error();
+ }
+else{@+incr(t);
+ if (cur_tok!=t)
+ {@+print_err("Parameters must be numbered consecutively");
+@.Parameters...consecutively@>
+ help2("I've inserted the digit you should have used after the #.")@/
+ ("Type `1' to delete what you did use.");back_error();
+ }
+ cur_tok=s;
+ }
+}
+
+@ @<Scan and build the body of the token list; |goto found| when finished@>=
+unbalance=1;
+loop@+{@+if (xpand) @<Expand the next part of the input@>@;
+ else get_token();
+ if (cur_tok < right_brace_limit)
+ if (cur_cmd < right_brace) incr(unbalance);
+ else{@+decr(unbalance);
+ if (unbalance==0) goto found;
+ }
+ else if (cur_cmd==mac_param)
+ if (macro_def) @<Look for parameter number or \.{\#\#}@>;
+ store_new_token(cur_tok);
+ }
+
+@ Here we insert an entire token list created by |the_toks| without
+expanding it further.
+
+@<Expand the next part of the input@>=
+{@+loop{@+get_next();
+ if (cur_cmd <= max_command) goto done2;
+ if (cur_cmd!=the) expand();
+ else{@+q=the_toks();
+ if (link(temp_head)!=null)
+ {@+link(p)=link(temp_head);p=q;
+ }
+ }
+ }
+done2: x_token();
+}
+
+@ @<Look for parameter number...@>=
+{@+s=cur_tok;
+if (xpand) get_x_token();else get_token();
+if (cur_cmd!=mac_param)
+ if ((cur_tok <= zero_token)||(cur_tok > t))
+ {@+print_err("Illegal parameter number in definition of ");
+@.Illegal parameter number...@>
+ sprint_cs(warning_index);
+ help3("You meant to type ## instead of #, right?")@/
+ ("Or maybe a } was forgotten somewhere earlier, and things")@/
+ ("are all screwed up? I'm going to assume that you meant ##.");
+ back_error();cur_tok=s;
+ }
+ else cur_tok=out_param_token-'0'+cur_chr;
+}
+
+@ Another way to create a token list is via the \.{\\read} command. The
+sixteen files potentially usable for reading appear in the following
+global variables. The value of |read_open[n]| will be |closed| if
+stream number |n| has not been opened or if it has been fully read;
+|just_open| if an \.{\\openin} but not a \.{\\read} has been done;
+and |normal| if it is open and ready to read the next line.
+
+@d closed 2 /*not open, or at end of file*/
+@d just_open 1 /*newly opened, first line not yet read*/
+
+@<Glob...@>=
+alpha_file @!read_file[16]; /*used for \.{\\read}*/
+uint8_t @!read_open[17]; /*state of |read_file[n]|*/
+
+@ @<Set init...@>=
+for (k=0; k<=16; k++) read_open[k]=closed;
+
+@ The |read_toks| procedure constructs a token list like that for any
+macro definition, and makes |cur_val| point to it. Parameter |r| points
+to the control sequence that will receive this token list.
+
+@p void read_toks(int @!n, pointer @!r)
+{@+
+pointer p; /*tail of the token list*/
+pointer @!q; /*new node being added to the token list via |store_new_token|*/
+int @!s; /*saved value of |align_state|*/
+small_number @!m; /*stream number*/
+scanner_status=defining;warning_index=r;
+def_ref=get_avail();token_ref_count(def_ref)=null;
+p=def_ref; /*the reference count*/
+store_new_token(end_match_token);
+if ((n < 0)||(n > 15)) m=16;@+else m=n;
+s=align_state;align_state=1000000; /*disable tab marks, etc.*/
+@/do@+{@<Input and store tokens from the next line of the file@>;
+}@+ while (!(align_state==1000000));
+cur_val=def_ref;scanner_status=normal;align_state=s;
+}
+
+@ @<Input and store tokens from the next line of the file@>=
+begin_file_reading();name=m+1;
+if (read_open[m]==closed) @<Input for \.{\\read} from the terminal@>;
+else if (read_open[m]==just_open) @<Input the first line of |read_file[m]|@>@;
+else@<Input the next line of |read_file[m]|@>;
+limit=last;
+if (end_line_char_inactive) decr(limit);
+else buffer[limit]=end_line_char;
+first=limit+1;loc=start;state=new_line;@/
+loop@+{@+get_token();
+ if (cur_tok==0) goto done;
+ /*|cur_cmd==cur_chr==0| will occur at the end of the line*/
+ if (align_state < 1000000) /*unmatched `\.\}' aborts the line*/
+ {@+@/do@+{get_token();}@+ while (!(cur_tok==0));
+ align_state=1000000;goto done;
+ }
+ store_new_token(cur_tok);
+ }
+done: end_file_reading()
+
+@ Here we input on-line into the |buffer| array, prompting the user explicitly
+if |n >= 0|. The value of |n| is set negative so that additional prompts
+will not be given in the case of multi-line input.
+
+@<Input for \.{\\read} from the terminal@>=
+if (interaction > nonstop_mode)
+ if (n < 0) prompt_input("")@;
+ else{@+wake_up_terminal;
+ print_ln();sprint_cs(r);prompt_input("=");n=-1;
+ }
+else fatal_error("*** (cannot \\read from terminal in nonstop modes)")
+@.cannot \\read@>
+
+@ The first line of a file must be treated specially, since |input_ln|
+must be told not to start with |get|.
+@^system dependencies@>
+
+@<Input the first line of |read_file[m]|@>=
+if (input_ln(&read_file[m], false)) read_open[m]=normal;
+else{@+a_close(&read_file[m]);read_open[m]=closed;
+ }
+
+@ An empty line is appended at the end of a |read_file|.
+@^empty line at end of file@>
+
+@<Input the next line of |read_file[m]|@>=
+{@+if (!input_ln(&read_file[m], true))
+ {@+a_close(&read_file[m]);read_open[m]=closed;
+ if (align_state!=1000000)
+ {@+runaway();
+ print_err("File ended within ");print_esc(@[@<|"read"|@>@]);
+@.File ended within \\read@>
+ help1("This \\read has unbalanced braces.");
+ align_state=1000000;error();
+ }
+ }
+}
+
+@* Conditional processing.
+We consider now the way \TeX\ handles various kinds of \.{\\if} commands.
+
+@d if_char_code 0 /* `\.{\\if}' */
+@d if_cat_code 1 /* `\.{\\ifcat}' */
+@d if_int_code 2 /* `\.{\\ifnum}' */
+@d if_dim_code 3 /* `\.{\\ifdim}' */
+@d if_odd_code 4 /* `\.{\\ifodd}' */
+@d if_vmode_code 5 /* `\.{\\ifvmode}' */
+@d if_hmode_code 6 /* `\.{\\ifhmode}' */
+@d if_mmode_code 7 /* `\.{\\ifmmode}' */
+@d if_inner_code 8 /* `\.{\\ifinner}' */
+@d if_void_code 9 /* `\.{\\ifvoid}' */
+@d if_hbox_code 10 /* `\.{\\ifhbox}' */
+@d if_vbox_code 11 /* `\.{\\ifvbox}' */
+@d ifx_code 12 /* `\.{\\ifx}' */
+@d if_eof_code 13 /* `\.{\\ifeof}' */
+@d if_true_code 14 /* `\.{\\iftrue}' */
+@d if_false_code 15 /* `\.{\\iffalse}' */
+@d if_case_code 16 /* `\.{\\ifcase}' */
+
+@<Put each...@>=
+primitive(@[@<|"if"|@>@], if_test, if_char_code);
+@!@:if_char_}{\.{\\if} primitive@>
+primitive(@[@<|"ifcat"|@>@], if_test, if_cat_code);
+@!@:if_cat_code_}{\.{\\ifcat} primitive@>
+primitive(@[@<|"ifnum"|@>@], if_test, if_int_code);
+@!@:if_int_}{\.{\\ifnum} primitive@>
+primitive(@[@<|"ifdim"|@>@], if_test, if_dim_code);
+@!@:if_dim_}{\.{\\ifdim} primitive@>
+primitive(@[@<|"ifodd"|@>@], if_test, if_odd_code);
+@!@:if_odd_}{\.{\\ifodd} primitive@>
+primitive(@[@<|"ifvmode"|@>@], if_test, if_vmode_code);
+@!@:if_vmode_}{\.{\\ifvmode} primitive@>
+primitive(@[@<|"ifhmode"|@>@], if_test, if_hmode_code);
+@!@:if_hmode_}{\.{\\ifhmode} primitive@>
+primitive(@[@<|"ifmmode"|@>@], if_test, if_mmode_code);
+@!@:if_mmode_}{\.{\\ifmmode} primitive@>
+primitive(@[@<|"ifinner"|@>@], if_test, if_inner_code);
+@!@:if_inner_}{\.{\\ifinner} primitive@>
+primitive(@[@<|"ifvoid"|@>@], if_test, if_void_code);
+@!@:if_void_}{\.{\\ifvoid} primitive@>
+primitive(@[@<|"ifhbox"|@>@], if_test, if_hbox_code);
+@!@:if_hbox_}{\.{\\ifhbox} primitive@>
+primitive(@[@<|"ifvbox"|@>@], if_test, if_vbox_code);
+@!@:if_vbox_}{\.{\\ifvbox} primitive@>
+primitive(@[@<|"ifx"|@>@], if_test, ifx_code);
+@!@:ifx_}{\.{\\ifx} primitive@>
+primitive(@[@<|"ifeof"|@>@], if_test, if_eof_code);
+@!@:if_eof_}{\.{\\ifeof} primitive@>
+primitive(@[@<|"iftrue"|@>@], if_test, if_true_code);
+@!@:if_true_}{\.{\\iftrue} primitive@>
+primitive(@[@<|"iffalse"|@>@], if_test, if_false_code);
+@!@:if_false_}{\.{\\iffalse} primitive@>
+primitive(@[@<|"ifcase"|@>@], if_test, if_case_code);
+@!@:if_case_}{\.{\\ifcase} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case if_test: switch (chr_code) {
+ case if_cat_code: print_esc(@[@<|"ifcat"|@>@]);@+break;
+ case if_int_code: print_esc(@[@<|"ifnum"|@>@]);@+break;
+ case if_dim_code: print_esc(@[@<|"ifdim"|@>@]);@+break;
+ case if_odd_code: print_esc(@[@<|"ifodd"|@>@]);@+break;
+ case if_vmode_code: print_esc(@[@<|"ifvmode"|@>@]);@+break;
+ case if_hmode_code: print_esc(@[@<|"ifhmode"|@>@]);@+break;
+ case if_mmode_code: print_esc(@[@<|"ifmmode"|@>@]);@+break;
+ case if_inner_code: print_esc(@[@<|"ifinner"|@>@]);@+break;
+ case if_void_code: print_esc(@[@<|"ifvoid"|@>@]);@+break;
+ case if_hbox_code: print_esc(@[@<|"ifhbox"|@>@]);@+break;
+ case if_vbox_code: print_esc(@[@<|"ifvbox"|@>@]);@+break;
+ case ifx_code: print_esc(@[@<|"ifx"|@>@]);@+break;
+ case if_eof_code: print_esc(@[@<|"ifeof"|@>@]);@+break;
+ case if_true_code: print_esc(@[@<|"iftrue"|@>@]);@+break;
+ case if_false_code: print_esc(@[@<|"iffalse"|@>@]);@+break;
+ case if_case_code: print_esc(@[@<|"ifcase"|@>@]);@+break;
+ default:print_esc(@[@<|"if"|@>@]);
+ } @+break;
+
+@ Conditions can be inside conditions, and this nesting has a stack
+that is independent of the |save_stack|.
+
+Four global variables represent the top of the condition stack:
+|cond_ptr| points to pushed-down entries, if any; |if_limit| specifies
+the largest code of a |fi_or_else| command that is syntactically legal;
+|cur_if| is the name of the current type of conditional; and |if_line|
+is the line number at which it began.
+
+If no conditions are currently in progress, the condition stack has the
+special state |cond_ptr==null|, |if_limit==normal|, |cur_if==0|, |if_line==0|.
+Otherwise |cond_ptr| points to a two-word node; the |type|, |subtype|, and
+|link| fields of the first word contain |if_limit|, |cur_if|, and
+|cond_ptr| at the next level, and the second word contains the
+corresponding |if_line|.
+
+@d if_node_size 2 /*number of words in stack entry for conditionals*/
+@d if_line_field(X) mem[X+1].i
+@d if_code 1 /*code for \.{\\if...} being evaluated*/
+@d fi_code 2 /*code for \.{\\fi}*/
+@d else_code 3 /*code for \.{\\else}*/
+@d or_code 4 /*code for \.{\\or}*/
+
+@<Glob...@>=
+pointer @!cond_ptr; /*top of the condition stack*/
+uint8_t @!if_limit; /*upper bound on |fi_or_else| codes*/
+small_number @!cur_if; /*type of conditional being worked on*/
+int @!if_line; /*line where that conditional began*/
+
+@ @<Set init...@>=
+cond_ptr=null;if_limit=normal;cur_if=0;if_line=0;
+
+@ @<Put each...@>=
+primitive(@[@<|"fi"|@>@], fi_or_else, fi_code);
+@!@:fi_}{\.{\\fi} primitive@>
+text(frozen_fi)=@[@<|"fi"|@>@];eqtb[frozen_fi]=eqtb[cur_val];
+primitive(@[@<|"or"|@>@], fi_or_else, or_code);
+@!@:or_}{\.{\\or} primitive@>
+primitive(@[@<|"else"|@>@], fi_or_else, else_code);
+@!@:else_}{\.{\\else} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case fi_or_else: if (chr_code==fi_code) print_esc(@[@<|"fi"|@>@]);
+ else if (chr_code==or_code) print_esc(@[@<|"or"|@>@]);
+ else print_esc(@[@<|"else"|@>@]);@+break;
+
+@ When we skip conditional text, we keep track of the line number
+where skipping began, for use in error messages.
+
+@<Glob...@>=
+int @!skip_line; /*skipping began here*/
+
+@ Here is a procedure that ignores text until coming to an \.{\\or},
+\.{\\else}, or \.{\\fi} at level zero of $\.{\\if}\ldots\.{\\fi}$
+nesting. After it has acted, |cur_chr| will indicate the token that
+was found, but |cur_tok| will not be set (because this makes the
+procedure run faster).
+
+@p void pass_text(void)
+{@+
+int l; /*level of $\.{\\if}\ldots\.{\\fi}$ nesting*/
+small_number @!save_scanner_status; /*|scanner_status| upon entry*/
+save_scanner_status=scanner_status;scanner_status=skipping;l=0;
+skip_line=line;
+loop@+{@+get_next();
+ if (cur_cmd==fi_or_else)
+ {@+if (l==0) goto done;
+ if (cur_chr==fi_code) decr(l);
+ }
+ else if (cur_cmd==if_test) incr(l);
+ }
+done: scanner_status=save_scanner_status;
+}
+
+@ When we begin to process a new \.{\\if}, we set |if_limit=if_code|; then
+if\/ \.{\\or} or \.{\\else} or \.{\\fi} occurs before the current \.{\\if}
+condition has been evaluated, \.{\\relax} will be inserted.
+For example, a sequence of commands like `\.{\\ifvoid1\\else...\\fi}'
+would otherwise require something after the `\.1'.
+
+@<Push the condition stack@>=
+{@+p=get_node(if_node_size);link(p)=cond_ptr;type(p)=if_limit;
+subtype(p)=cur_if;if_line_field(p)=if_line;
+cond_ptr=p;cur_if=cur_chr;if_limit=if_code;if_line=line;
+}
+
+@ @<Pop the condition stack@>=
+{@+p=cond_ptr;if_line=if_line_field(p);
+cur_if=subtype(p);if_limit=type(p);cond_ptr=link(p);
+free_node(p, if_node_size);
+}
+
+@ Here's a procedure that changes the |if_limit| code corresponding to
+a given value of |cond_ptr|.
+
+@p void change_if_limit(small_number @!l, pointer @!p)
+{@+
+pointer q;
+if (p==cond_ptr) if_limit=l; /*that's the easy case*/
+else{@+q=cond_ptr;
+ loop@+{@+if (q==null) confusion(@[@<|"if"|@>@]);
+@:this can't happen if}{\quad if@>
+ if (link(q)==p)
+ {@+type(q)=l;return;
+ }
+ q=link(q);
+ }
+ }
+}
+
+@ A condition is started when the |expand| procedure encounters
+an |if_test| command; in that case |expand| reduces to |conditional|,
+which is a recursive procedure.
+@^recursion@>
+
+@p void conditional(void)
+{@+
+bool b; /*is the condition true?*/
+uint8_t @!r; /*relation to be evaluated*/
+int @!m, @!n; /*to be tested against the second operand*/
+pointer @!p, @!q; /*for traversing token lists in \.{\\ifx} tests*/
+small_number @!save_scanner_status; /*|scanner_status| upon entry*/
+pointer @!save_cond_ptr; /*|cond_ptr| corresponding to this conditional*/
+small_number @!this_if; /*type of this conditional*/
+@<Push the condition stack@>;@+save_cond_ptr=cond_ptr;this_if=cur_chr;@/
+@<Either process \.{\\ifcase} or set |b| to the value of a boolean condition@>;
+if (tracing_commands > 1) @<Display the value of |b|@>;
+if (b)
+ {@+change_if_limit(else_code, save_cond_ptr);
+ return; /*wait for \.{\\else} or \.{\\fi}*/
+ }
+@<Skip to \.{\\else} or \.{\\fi}, then |goto common_ending|@>;
+common_ending: if (cur_chr==fi_code) @<Pop the condition stack@>@;
+else if_limit=fi_code; /*wait for \.{\\fi}*/
+}
+
+@ In a construction like `\.{\\if\\iftrue abc\\else d\\fi}', the first
+\.{\\else} that we come to after learning that the \.{\\if} is false is
+not the \.{\\else} we're looking for. Hence the following curious
+logic is needed.
+
+@ @<Skip to \.{\\else} or \.{\\fi}...@>=
+loop@+{@+pass_text();
+ if (cond_ptr==save_cond_ptr)
+ {@+if (cur_chr!=or_code) goto common_ending;
+ print_err("Extra ");print_esc(@[@<|"or"|@>@]);
+@.Extra \\or@>
+ help1("I'm ignoring this; it doesn't match any \\if.");
+ error();
+ }
+ else if (cur_chr==fi_code) @<Pop the condition stack@>;
+ }
+
+@ @<Either process \.{\\ifcase} or set |b|...@>=
+switch (this_if) {
+case if_char_code: case if_cat_code: @<Test if two characters match@>@;@+break;
+case if_int_code: case if_dim_code: @<Test relation between integers or dimensions@>@;@+break;
+case if_odd_code: @<Test if an integer is odd@>@;@+break;
+case if_vmode_code: b=(abs(mode)==vmode);@+break;
+case if_hmode_code: b=(abs(mode)==hmode);@+break;
+case if_mmode_code: b=(abs(mode)==mmode);@+break;
+case if_inner_code: b=(mode < 0);@+break;
+case if_void_code: case if_hbox_code: case if_vbox_code: @<Test box register status@>@;@+break;
+case ifx_code: @<Test if two tokens match@>@;@+break;
+case if_eof_code: {@+scan_four_bit_int();b=(read_open[cur_val]==closed);
+ } @+break;
+case if_true_code: b=true;@+break;
+case if_false_code: b=false;@+break;
+case if_case_code: @<Select the appropriate case and |return| or |goto common_ending|@>;
+} /*there are no other cases*/
+
+@ @<Display the value of |b|@>=
+{@+begin_diagnostic();
+if (b) print_str("{true}");@+else print_str("{false}");
+end_diagnostic(false);
+}
+
+@ Here we use the fact that |'<'|, |'='|, and |'>'| are consecutive ASCII
+codes.
+@^ASCII code@>
+
+@<Test relation between integers or dimensions@>=
+{@+if (this_if==if_int_code) scan_int();@+else scan_normal_dimen;
+n=cur_val;@<Get the next non-blank non-call...@>;
+if ((cur_tok >= other_token+'<')&&(cur_tok <= other_token+'>'))
+ r=cur_tok-other_token;
+else{@+print_err("Missing = inserted for ");
+@.Missing = inserted@>
+ print_cmd_chr(if_test, this_if);
+ help1("I was expecting to see `<', `=', or `>'. Didn't.");
+ back_error();r='=';
+ }
+if (this_if==if_int_code) scan_int();@+else scan_normal_dimen;
+switch (r) {
+case '<': b=(n < cur_val);@+break;
+case '=': b=(n==cur_val);@+break;
+case '>': b=(n > cur_val);
+}
+}
+
+@ @<Test if an integer is odd@>=
+{@+scan_int();b=odd(cur_val);
+}
+
+@ @<Test box register status@>=
+{@+scan_eight_bit_int();p=box(cur_val);
+if (this_if==if_void_code) b=(p==null);
+else if (p==null) b=false;
+else if (this_if==if_hbox_code) b=(type(p)==hlist_node);
+else b=(type(p)==vlist_node);
+}
+
+@ An active character will be treated as category 13 following
+\.{\\if\\noexpand} or following \.{\\ifcat\\noexpand}. We use the fact that
+active characters have the smallest tokens, among all control sequences.
+
+@d get_x_token_or_active_char @t@>@;
+ {@+get_x_token();
+ if (cur_cmd==relax) if (cur_chr==no_expand_flag)
+ {@+cur_cmd=active_char;
+ cur_chr=cur_tok-cs_token_flag-active_base;
+ }
+ }
+
+@<Test if two characters match@>=
+{@+get_x_token_or_active_char;
+if ((cur_cmd > active_char)||(cur_chr > 255)) /*not a character*/
+ {@+m=relax;n=256;
+ }
+else{@+m=cur_cmd;n=cur_chr;
+ }
+get_x_token_or_active_char;
+if ((cur_cmd > active_char)||(cur_chr > 255))
+ {@+cur_cmd=relax;cur_chr=256;
+ }
+if (this_if==if_char_code) b=(n==cur_chr);@+else b=(m==cur_cmd);
+}
+
+@ Note that `\.{\\ifx}' will declare two macros different if one is \\{long}
+or \\{outer} and the other isn't, even though the texts of the macros are
+the same.
+
+We need to reset |scanner_status|, since \.{\\outer} control sequences
+are allowed, but we might be scanning a macro definition or preamble.
+
+@<Test if two tokens match@>=
+{@+save_scanner_status=scanner_status;scanner_status=normal;
+get_next();n=cur_cs;p=cur_cmd;q=cur_chr;
+get_next();if (cur_cmd!=p) b=false;
+else if (cur_cmd < call) b=(cur_chr==q);
+else@<Test if two macro texts match@>;
+scanner_status=save_scanner_status;
+}
+
+@ Note also that `\.{\\ifx}' decides that macros \.{\\a} and \.{\\b} are
+different in examples like this:
+$$\vbox{\halign{\.{#}\hfil&\qquad\.{#}\hfil\cr
+ {}\\def\\a\{\\c\}&
+ {}\\def\\c\{\}\cr
+ {}\\def\\b\{\\d\}&
+ {}\\def\\d\{\}\cr}}$$
+
+@<Test if two macro texts match@>=
+{@+p=link(cur_chr);q=link(equiv(n)); /*omit reference counts*/
+if (p==q) b=true;
+else{@+while ((p!=null)&&(q!=null))
+ if (info(p)!=info(q)) p=null;
+ else{@+p=link(p);q=link(q);
+ }
+ b=((p==null)&&(q==null));
+ }
+}
+
+@ @<Select the appropriate case and |return| or |goto common_ending|@>=
+{@+scan_int();n=cur_val; /*|n| is the number of cases to pass*/
+if (tracing_commands > 1)
+ {@+begin_diagnostic();print_str("{case ");print_int(n);print_char('}');
+ end_diagnostic(false);
+ }
+while (n!=0)
+ {@+pass_text();
+ if (cond_ptr==save_cond_ptr)
+ if (cur_chr==or_code) decr(n);
+ else goto common_ending;
+ else if (cur_chr==fi_code) @<Pop the condition stack@>;
+ }
+change_if_limit(or_code, save_cond_ptr);
+return; /*wait for \.{\\or}, \.{\\else}, or \.{\\fi}*/
+}
+
+@ The processing of conditionals is complete except for the following
+code, which is actually part of |expand|. It comes into play when
+\.{\\or}, \.{\\else}, or \.{\\fi} is scanned.
+
+@<Terminate the current conditional and skip to \.{\\fi}@>=
+if (cur_chr > if_limit)
+ if (if_limit==if_code) insert_relax(); /*condition not yet evaluated*/
+ else{@+print_err("Extra ");print_cmd_chr(fi_or_else, cur_chr);
+@.Extra \\or@>
+@.Extra \\else@>
+@.Extra \\fi@>
+ help1("I'm ignoring this; it doesn't match any \\if.");
+ error();
+ }
+else{@+while (cur_chr!=fi_code) pass_text(); /*skip to \.{\\fi}*/
+ @<Pop the condition stack@>;
+ }
+
+@* File names.
+It's time now to fret about file names. Besides the fact that different
+operating systems treat files in different ways, we must cope with the
+fact that completely different naming conventions are used by different
+groups of people. The following programs show what is required for one
+particular operating system; similar routines for other systems are not
+difficult to devise.
+@^fingers@>
+@^system dependencies@>
+
+\TeX\ assumes that a file name has three parts: the name proper; its
+``extension''; and a ``file area'' where it is found in an external file
+system. The extension of an input file or a write file is assumed to be
+`\.{.tex}' unless otherwise specified; it is `\.{.log}' on the
+transcript file that records each run of \TeX; it is `\.{.tfm}' on the font
+metric files that describe characters in the fonts \TeX\ uses; it is
+`\.{.dvi}' on the output files that specify typesetting information; and it
+is `\.{.fmt}' on the format files written by \.{INITEX} to initialize \TeX.
+The file area can be arbitrary on input files, but files are usually
+output to the user's current area. If an input file cannot be
+found on the specified area, \TeX\ will look for it on a special system
+area; this special area is intended for commonly used input files like
+\.{webmac.tex}.
+
+Simple uses of \TeX\ refer only to file names that have no explicit
+extension or area. For example, a person usually says `\.{\\input} \.{paper}'
+or `\.{\\font\\tenrm} \.= \.{helvetica}' instead of `\.{\\input}
+\.{paper.new}' or `\.{\\font\\tenrm} \.= \.{<csd.knuth>test}'. Simple file
+names are best, because they make the \TeX\ source files portable;
+whenever a file name consists entirely of letters and digits, it should be
+treated in the same way by all implementations of \TeX. However, users
+need the ability to refer to other files in their environment, especially
+when responding to error messages concerning unopenable files; therefore
+we want to let them use the syntax that appears in their favorite
+operating system.
+
+The following procedures don't allow spaces to be part of
+file names; but some users seem to like names that are spaced-out.
+System-dependent changes to allow such things should probably
+be made with reluctance, and only when an entire file name that
+includes spaces is ``quoted'' somehow.
+
+@ In order to isolate the system-dependent aspects of file names, the
+@^system dependencies@>
+system-independent parts of \TeX\ are expressed in terms
+of three system-dependent
+procedures called |begin_name|, |more_name|, and |end_name|. In
+essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
+the system-independent driver program does the operations
+$$|begin_name|;\,|more_name|(c_1);\,\ldots\,;\,|more_name|(c_n);
+\,|end_name|.$$
+These three procedures communicate with each other via global variables.
+Afterwards the file name will appear in the string pool as three strings
+called |cur_name|\penalty10000\hskip-.05em,
+|cur_area|, and |cur_ext|; the latter two are null (i.e.,
+|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|.
+
+@<Glob...@>=
+str_number @!cur_name; /*name of file just scanned*/
+str_number @!cur_area; /*file area just scanned, or \.{""}*/
+str_number @!cur_ext; /*file extension just scanned, or \.{""}*/
+
+@ 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.
+@^system dependencies@>
+
+We can scan such file names easily by using two global variables that keep track
+of the occurrences of area and extension delimiters:
+
+@<Glob...@>=
+pool_pointer @!area_delimiter; /*the most recent `\.>' or `\.:', if any*/
+pool_pointer @!ext_delimiter; /*the relevant `\..', if any*/
+
+@ Input files that can't be found in the user's area may appear in a standard
+system area called |TEX_area|. Font metric files whose areas are not given
+explicitly are assumed to appear in a standard system area called
+|TEX_font_area|. These system area names will, of course, vary from place
+to place.
+@^system dependencies@>
+@.TeXinputs@>
+@.TeXfonts@>
+
+@ Here now is the first of the system-dependent routines for file name scanning.
+@^system dependencies@>
+
+@p void begin_name(void)
+{@+area_delimiter=0;ext_delimiter=0;
+}
+
+@ And here's the second. The string pool might change as the file name is
+being scanned, since a new \.{\\csname} might be entered; therefore we keep
+|area_delimiter| and |ext_delimiter| relative to the beginning of the current
+string, instead of assigning an absolute address like |pool_ptr| to them.
+@^system dependencies@>
+
+@p bool more_name(ASCII_code @!c)
+{@+if (c==' ') return false;
+else{@+str_room(1);append_char(c); /*contribute |c| to the current string*/
+ if ((c=='>')||(c==':'))
+ {@+area_delimiter=cur_length;ext_delimiter=0;
+ }
+ else if ((c=='.')&&(ext_delimiter==0)) ext_delimiter=cur_length;
+ return true;
+ }
+}
+
+@ The third.
+@^system dependencies@>
+
+@p void end_name(void)
+{@+if (str_ptr+3 > max_strings)
+ overflow("number of strings", max_strings-init_str_ptr);
+@:TeX capacity exceeded number of strings}{\quad number of strings@>
+if (area_delimiter==0) cur_area=empty_string;
+else{@+cur_area=str_ptr;
+ str_start[str_ptr+1]=str_start[str_ptr]+area_delimiter;incr(str_ptr);
+ }
+if (ext_delimiter==0)
+ {@+cur_ext=empty_string;cur_name=make_string();
+ }
+else{@+cur_name=str_ptr;
+ str_start[str_ptr+1]=str_start[str_ptr]+ext_delimiter-area_delimiter-1;
+ incr(str_ptr);cur_ext=make_string();
+ }
+}
+
+@ Conversely, here is a routine that takes three strings and prints a file
+name that might have produced them. (The routine is system dependent, because
+some operating systems put the file area last instead of first.)
+@^system dependencies@>
+
+@<Basic printing...@>=
+void print_file_name(int @!n, int @!a, int @!e)
+{@+slow_print(a);slow_print(n);slow_print(e);
+}
+
+@ Another system-dependent routine is needed to convert three internal
+\TeX\ strings
+into the |name_of_file| value that is used to open files. The present code
+allows both lowercase and uppercase letters in the file name.
+@^system dependencies@>
+
+@d append_to_name(X) {@+c=X;incr(k);
+ if (k <= file_name_size) name_of_file[k]=xchr[c];
+ }
+
+@p void pack_file_name(str_number @!n, str_number @!a, str_number @!e)
+{@+int k; /*number of positions filled in |name_of_file|*/
+ASCII_code @!c; /*character being packed*/
+int @!j; /*index into |str_pool|*/
+k=0;
+for (j=str_start[a]; j<=str_start[a+1]-1; j++) append_to_name(so(str_pool[j]));
+for (j=str_start[n]; j<=str_start[n+1]-1; j++) append_to_name(so(str_pool[j]));
+for (j=str_start[e]; j<=str_start[e+1]-1; j++) append_to_name(so(str_pool[j]));
+if (k <= file_name_size) name_length=k;@+else name_length=file_name_size;
+name_of_file[name_length+1]=0;
+}
+
+@ A messier routine is also needed, since format file names must be scanned
+before \TeX's string mechanism has been initialized. We shall use the
+global variable |TEX_format_default| to supply the text for default system areas
+and extensions related to format files.
+@^system dependencies@>
+
+@d format_default_length 20 /*length of the |TEX_format_default| string*/
+@d format_area_length 11 /*length of its area part*/
+@d format_ext_length 4 /*length of its `\.{.fmt}' part*/
+@d format_extension_str ".fmt" /*the extension, as a \.{WEB} constant*/
+
+@<Glob...@>=
+ASCII_code @!TEX_format_default[1+format_default_length+1]=" TeXformats/plain.fmt";
+@.TeXformats@>
+@.plain@>
+@^system dependencies@>
+
+@ @<Check the ``constant'' values for consistency@>=
+if (format_default_length > file_name_size) bad=31;
+
+@ Here is the messy routine that was just mentioned. It sets |name_of_file|
+from the first |n| characters of |TEX_format_default|, followed by
+|buffer[a 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.
+@^system dependencies@>
+
+@p void pack_buffered_name(small_number @!n, int @!a, int @!b)
+{@+int k; /*number of positions filled in |name_of_file|*/
+ASCII_code @!c; /*character being packed*/
+int @!j; /*index into |buffer| or |TEX_format_default|*/
+if (n+b-a+1+format_ext_length > file_name_size)
+ b=a+file_name_size-n-1-format_ext_length;
+k=0;
+for (j=1; j<=n; j++) append_to_name(xord[TEX_format_default[j]]);
+for (j=a; j<=b; j++) append_to_name(buffer[j]);
+for (j=format_default_length-format_ext_length+1; j<=format_default_length; j++)
+ append_to_name(xord[TEX_format_default[j]]);
+if (k <= file_name_size) name_length=k;@+else name_length=file_name_size;
+name_of_file[name_length+1]=0;
+}
+
+@ 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-1)]|, where
+|loc < last| and |buffer[loc]!=' '|.
+
+@<Declare the function called |open_fmt_file|@>=
+bool open_fmt_file(void)
+{@+
+uint16_t j; /*the first space after the format file name*/
+j=loc;
+if (buffer[loc]=='&')
+ {@+incr(loc);j=loc;buffer[last]=' ';
+ while (buffer[j]!=' ') incr(j);
+ pack_buffered_name(0, loc, j-1); /*try first without the system file area*/
+ if (w_open_in(&fmt_file)) goto found;
+ pack_buffered_name(format_area_length, loc, j-1);
+ /*now try the system format file area*/
+ if (w_open_in(&fmt_file)) goto found;
+ wake_up_terminal;
+ wterm_ln("Sorry, I can't find that format; will try PLAIN.");
+@.Sorry, I can't find...@>
+ update_terminal;
+ }
+ /*now pull out all the stops: try for the system \.{plain} file*/
+pack_buffered_name(format_default_length-format_ext_length, 1, 0);
+if (!w_open_in(&fmt_file))
+ {@+wake_up_terminal;
+ wterm_ln("I can't find the PLAIN format file!");
+@.I can't find PLAIN...@>
+@.plain@>
+ return false;
+ }
+found: loc=j;return true;
+}
+
+@ Operating systems often make it possible to determine the exact name (and
+possible version number) of a file that has been opened. The following routine,
+which simply makes a \TeX\ string from the value of |name_of_file|, should
+ideally be changed to deduce the full name of file~|f|, which is the file
+most recently opened, if it is possible to do this in a \PASCAL\ program.
+@^system dependencies@>
+
+This routine might be called after string memory has overflowed, hence
+we dare not use `|str_room|'.
+
+@p str_number make_name_string(void)
+{@+int k; /*index into |name_of_file|*/
+if ((pool_ptr+name_length > pool_size)||(str_ptr==max_strings)||
+ (cur_length > 0))
+ return'?';
+else{@+for (k=1; k<=name_length; k++) append_char(xord[name_of_file[k]]);
+ return make_string();
+ }
+}
+str_number a_make_name_string(alpha_file *f)
+{@+return make_name_string();
+}
+str_number b_make_name_string(byte_file *f)
+{@+return make_name_string();
+}
+str_number w_make_name_string(word_file *f)
+{@+return make_name_string();
+}
+
+@ Now let's consider the ``driver''
+routines by which \TeX\ deals with file names
+in a system-independent manner. First comes a procedure that looks for a
+file name in the input by calling |get_x_token| for the information.
+
+@p void scan_file_name(void)
+{@+
+name_in_progress=true;begin_name();
+@<Get the next non-blank non-call...@>;
+loop@+{@+if ((cur_cmd > other_char)||(cur_chr > 255)) /*not a character*/
+ {@+back_input();goto done;
+ }
+ if (!more_name(cur_chr)) goto done;
+ get_x_token();
+ }
+done: end_name();name_in_progress=false;
+}
+
+@ The global variable |name_in_progress| is used to prevent recursive
+use of |scan_file_name|, since the |begin_name| and other procedures
+communicate via global variables. Recursion would arise only by
+devious tricks like `\.{\\input\\input f}'; such attempts at sabotage
+must be thwarted. Furthermore, |name_in_progress| prevents \.{\\input}
+@^recursion@>
+from being initiated when a font size specification is being scanned.
+
+Another global variable, |job_name|, contains the file name that was first
+\.{\\input} by the user. This name is extended by `\.{.log}' and `\.{.dvi}'
+and `\.{.fmt}' in the names of \TeX's output files.
+
+@<Glob...@>=
+bool @!name_in_progress; /*is a file name being scanned?*/
+str_number @!job_name; /*principal file name*/
+bool @!log_opened; /*has the transcript file been opened?*/
+
+@ Initially |job_name==0|; it becomes nonzero as soon as the true name is known.
+We have |job_name==0| if and only if the `\.{log}' file has not been opened,
+except of course for a short time just after |job_name| has become nonzero.
+
+@<Initialize the output...@>=
+job_name=0;name_in_progress=false;log_opened=false;
+
+@ Here is a routine that manufactures the output file names, assuming that
+|job_name!=0|. It ignores and changes the current settings of |cur_area|
+and |cur_ext|.
+
+@d pack_cur_name pack_file_name(cur_name, cur_area, cur_ext)
+
+@p void pack_job_name(str_number @!s) /*|s==@[@<|".log"|@>@]|, |@[@<|".dvi"|@>@]|, or
+ |format_extension|*/
+{@+cur_area=empty_string;cur_ext=s;
+cur_name=job_name;pack_cur_name;
+}
+
+@ If some trouble arises when \TeX\ tries to open a file, the following
+routine calls upon the user to supply another file name. Parameter~|s|
+is used in the error message to identify the type of file; parameter~|e|
+is the default extension if none is given. Upon exit from the routine,
+variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are
+ready for another attempt at file opening.
+
+@p void prompt_file_name(char *@!s, str_number @!e)
+{@+
+uint16_t k; /*index into |buffer|*/
+if (interaction==scroll_mode) wake_up_terminal;
+if (strcmp(s,"input file name")==0) print_err("I can't find file `")@;
+@.I can't find file x@>
+else print_err("I can't write on file `");
+@.I can't write on file x@>
+print_file_name(cur_name, cur_area, cur_ext);print_str("'.");
+if (e==@[@<|".tex"|@>@]) show_context();
+print_nl("Please type another ");print_str(s);
+@.Please type...@>
+if (interaction < scroll_mode)
+ fatal_error("*** (job aborted, file error in nonstop mode)");
+@.job aborted, file error...@>
+clear_terminal;prompt_input(": ");@<Scan file name in the buffer@>;
+if (cur_ext==empty_string) cur_ext=e;
+pack_cur_name;
+}
+
+@ @<Scan file name in the buffer@>=
+{@+begin_name();k=first;
+while ((buffer[k]==' ')&&(k < last)) incr(k);
+loop@+{@+if (k==last) goto done;
+ if (!more_name(buffer[k])) goto done;
+ incr(k);
+ }
+done: end_name();
+}
+
+@ Here's an example of how these conventions are used. Whenever it is time to
+ship out a box of stuff, we shall use |@<ensure dvi open@>|.
+
+@<ensure dvi open@>=
+if (output_file_name==0)
+ {@+if (job_name==0) open_log_file();
+ pack_job_name(@[@<|".dvi"|@>@]);
+ while (!b_open_out(&dvi_file))
+ prompt_file_name("file name for output",@[@<|".dvi"|@>@]);
+ output_file_name=b_make_name_string(&dvi_file);
+ }
+
+@ @<Glob...@>=
+byte_file @!dvi_file; /*the device-independent output goes here*/
+str_number @!output_file_name; /*full name of the output file*/
+str_number @!log_name; /*full name of the log file*/
+
+@ @<Initialize the output...@>=output_file_name=0;
+
+@ The |open_log_file| routine is used to open the transcript file and to help
+it catch up to what has previously been printed on the terminal.
+
+@p void open_log_file(void)
+{@+uint8_t old_setting; /*previous |selector| setting*/
+int @!k; /*index into |months| and |buffer|*/
+uint16_t @!l; /*end of first input line*/
+@!ASCII_code @!months[]=" JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; /*abbreviations of month names*/
+old_setting=selector;
+if (job_name==0) job_name=@[@<|"texput"|@>@];
+@.texput@>
+pack_job_name(@[@<|".log"|@>@]);
+while (!a_open_out(&log_file)) @<Try to get a different log file name@>;
+log_name=a_make_name_string(&log_file);
+selector=log_only;log_opened=true;
+@<Print the banner line, including the date and time@>;
+input_stack[input_ptr]=cur_input; /*make sure bottom level is in memory*/
+print_nl("**");
+@.**@>
+l=input_stack[0].limit_field; /*last position of first line*/
+if (buffer[l]==end_line_char) decr(l);
+for (k=1; k<=l; k++) print(buffer[k]);
+print_ln(); /*now the transcript file contains the first line of input*/
+selector=old_setting+2; /*|log_only| or |term_and_log|*/
+}
+
+@ Sometimes |open_log_file| is called at awkward moments when \TeX\ is
+unable to print error messages or even to |show_context|.
+The |prompt_file_name| routine can result in a |fatal_error|, but the |error|
+routine will not be invoked because |log_opened| will be false.
+
+The normal idea of |batch_mode| is that nothing at all should be written
+on the terminal. However, in the unusual case that
+no log file could be opened, we make an exception and allow
+an explanatory message to be seen.
+
+Incidentally, the program always refers to the log file as a `\.{transcript
+file}', because some systems cannot use the extension `\.{.log}' for
+this file.
+
+@<Try to get a different log file name@>=
+{@+selector=term_only;
+prompt_file_name("transcript file name",@[@<|".log"|@>@]);
+}
+
+@ @<Print the banner...@>=
+{@+wlog("%s",banner);
+slow_print(format_ident);print_str(" ");
+print_int(day);print_char(' ');
+for (k=3*month-2; k<=3*month; k++) wlog("%c",months[k]);
+print_char(' ');print_int(year);print_char(' ');
+print_two(time/60);print_char(':');print_two(time%60);
+}
+
+@ Let's turn now to the procedure that is used to initiate file reading
+when an `\.{\\input}' command is being processed.
+
+@p void start_input(void) /*\TeX\ will \.{\\input} something*/
+{@+
+scan_file_name(); /*set |cur_name| to desired file name*/
+if (cur_ext==empty_string) cur_ext=@[@<|".tex"|@>@];
+pack_cur_name;
+loop@+{@+begin_file_reading(); /*set up |cur_file| and new level of input*/
+ if (a_open_in(&cur_file)) goto done;
+ if (cur_area==empty_string)
+ {@+pack_file_name(cur_name, TEX_area, cur_ext);
+ if (a_open_in(&cur_file)) goto done;
+ }
+ end_file_reading(); /*remove the level that didn't work*/
+ prompt_file_name("input file name",@[@<|".tex"|@>@]);
+ }
+done: name=a_make_name_string(&cur_file);
+if (job_name==0)
+ {@+job_name=cur_name;open_log_file();
+ } /*|open_log_file| doesn't |show_context|, so |limit|
+ and |loc| needn't be set to meaningful values yet*/
+if (term_offset+length(name) > max_print_line-2) print_ln();
+else if ((term_offset > 0)||(file_offset > 0)) print_char(' ');
+print_char('(');incr(open_parens);slow_print(name);update_terminal;
+state=new_line;
+if (name==str_ptr-1) /*we can conserve string pool space now*/
+ {@+flush_string;name=cur_name;
+ }
+@<Read the first line of the new file@>;
+}
+
+@ Here we have to remember to tell the |input_ln| routine not to
+start with a |get|. If the file is empty, it is considered to
+contain a single blank line.
+@^system dependencies@>
+@^empty line at end of file@>
+
+@<Read the first line...@>=
+{@+line=1;
+if (input_ln(&cur_file, false)) do_nothing;
+firm_up_the_line();
+if (end_line_char_inactive) decr(limit);
+else buffer[limit]=end_line_char;
+first=limit+1;loc=start;
+}
+
+@* Font metric data.
+\TeX\ gets its knowledge about fonts from font metric files, also called
+\.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX,
+but other programs know about them too.
+@:TFM files}{\.{TFM} files@>
+@^font metric files@>
+
+The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
+Since the number of bytes is always a multiple of 4, we could
+also regard the file as a sequence of 32-bit words, but \TeX\ uses the
+byte interpretation. The format of \.{TFM} files was designed by
+Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
+@^Ramshaw, Lyle Harold@>
+of information in a compact but useful form.
+
+@<Glob...@>=
+byte_file @!tfm_file;
+
+@ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
+integers that give the lengths of the various subsequent portions
+of the file. These twelve integers are, in order:
+$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
+|lf|&length of the entire file, in words;\cr
+|lh|&length of the header data, in words;\cr
+|bc|&smallest character code in the font;\cr
+|ec|&largest character code in the font;\cr
+|nw|&number of words in the width table;\cr
+|nh|&number of words in the height table;\cr
+|nd|&number of words in the depth table;\cr
+|ni|&number of words in the italic correction table;\cr
+|nl|&number of words in the lig/kern table;\cr
+|nk|&number of words in the kern table;\cr
+|ne|&number of words in the extensible character table;\cr
+|np|&number of font parameter words.\cr}}$$
+They are all nonnegative and less than $2^{15}$. We must have |bc-1 <= ec <= 255|,
+and
+$$\hbox{|lf==6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
+Note that a font may contain as many as 256 characters (if |bc==0| and |ec==255|),
+and as few as 0 characters (if |bc==ec+1|).
+
+Incidentally, when two or more 8-bit bytes are combined to form an integer of
+16 or more bits, the most significant bytes appear first in the file.
+This is called BigEndian order.
+@!@^BigEndian order@>
+
+@ 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&|[0 dotdot lh-1]@t\\{stuff}@>|\cr
+char\_info&|[bc dotdot ec]char_info_word|\cr
+width&|[0 dotdot nw-1]fix_word|\cr
+height&|[0 dotdot nh-1]fix_word|\cr
+depth&|[0 dotdot nd-1]fix_word|\cr
+italic&|[0 dotdot ni-1]fix_word|\cr
+lig\_kern&|[0 dotdot nl-1]lig_kern_command|\cr
+kern&|[0 dotdot nk-1]fix_word|\cr
+exten&|[0 dotdot ne-1]extensible_recipe|\cr
+param&|[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$.
+
+@ The first data array is a block of header information, which contains
+general facts about the font. The header must contain at least two words,
+|header[0]| and |header[1]|, whose meaning is explained below.
+Additional header information of use to other software routines might
+also be included, but \TeX82 does not need to know about such details.
+For example, 16 more words of header information are in use at the Xerox
+Palo Alto Research Center; the first ten specify the character coding
+scheme used (e.g., `\.{XEROX text}' or `\.{TeX math symbols}'), the next five
+give the font identifier (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
+last gives the ``face byte.'' The program that converts \.{DVI} files
+to Xerox printing format gets this information by looking at the \.{TFM}
+file, which it needs to read anyway because of other information that
+is not explicitly repeated in \.{DVI}~format.
+
+\yskip\hang|header[0]| is a 32-bit check sum that \TeX\ will copy into
+the \.{DVI} output file. Later on when the \.{DVI} file is printed,
+possibly on another computer, the actual font that gets used is supposed
+to have a check sum that agrees with the one in the \.{TFM} file used by
+\TeX. In this way, users will be warned about potential incompatibilities.
+(However, if the check sum is zero in either the font file or the \.{TFM}
+file, no check is made.) The actual relation between this check sum and
+the rest of the \.{TFM} file is not important; the check sum is simply an
+identification number with the property that incompatible fonts almost
+always have distinct check sums.
+@^check sum@>
+
+\yskip\hang|header[1]| is a |fix_word| containing the design size of
+the font, in units of \TeX\ points. This number must be at least 1.0; it is
+fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
+font, i.e., a font that was designed to look best at a 10-point size,
+whatever that really means. When a \TeX\ user asks for a font
+`\.{at} $\delta$ \.{pt}', the effect is to override the design size
+and replace it by $\delta$, and to multiply the $x$ and~$y$ coordinates
+of the points in the font image by a factor of $\delta$ divided by the
+design size. {\sl All other dimensions in the\/ \.{TFM} file are
+|fix_word|\kern-1pt\ numbers in design-size units}, with the exception of
+|param[1]| (which denotes the slant ratio). Thus, for example, the value
+of |param[6]|, which defines the \.{em} unit, is often the |fix_word| value
+$2^{20}=1.0$, since many fonts have a design size equal to one em.
+The other dimensions must be less than 16 design-size units in absolute
+value; thus, |header[1]| and |param[1]| are the only |fix_word|
+entries in the whole \.{TFM} file whose first byte might be something
+besides 0 or 255.
+
+@ Next comes the |char_info| array, which contains one |@!char_info_word|
+per character. Each word in this part of the file contains six fields
+packed into four bytes as follows.
+
+\yskip\hang first byte: |@!width_index| (8 bits)\par
+\hang second byte: |@!height_index| (4 bits) times 16, plus |@!depth_index|
+ (4~bits)\par
+\hang third byte: |@!italic_index| (6 bits) times 4, plus |@!tag|
+ (2~bits)\par
+\hang fourth byte: |@!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.
+
+@!@^italic correction@>
+The italic correction of a character has two different uses.
+(a)~In ordinary text, the italic correction is added to the width only if
+the \TeX\ user specifies `\.{\\/}' after the character.
+(b)~In math formulas, the italic correction is always added to the width,
+except with respect to the positioning of subscripts.
+
+Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
+\\{italic}[0]=0$ should always hold, so that an index of zero implies a
+value of zero. The |width_index| should never be zero unless the
+character does not exist in the font, since a character is valid if and
+only if it lies between |bc| and |ec| and has a nonzero |width_index|.
+
+@ The |tag| field in a |char_info_word| has four values that explain how to
+interpret the |rem| field.
+
+\yskip\hangg|tag==0| (|no_tag|) means that |rem| is unused.\par
+\hangg|tag==1| (|lig_tag|) means that this character has a ligature/kerning
+program starting at position |rem| in the |lig_kern| array.\par
+\hangg|tag==2| (|list_tag|) means that this character is part of a chain of
+characters of ascending sizes, and not the largest in the chain. The
+|rem| field gives the character code of the next larger character.\par
+\hangg|tag==3| (|ext_tag|) means that this character code represents an
+extensible character, i.e., a character that is built up of smaller pieces
+so that it can be made arbitrarily large. The pieces are specified in
+|@!exten[rem]|.\par
+\yskip\noindent
+Characters with |tag==2| and |tag==3| are treated as characters with |tag==0|
+unless they are used in special circumstances in math formulas. For example,
+the \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
+operation looks for both |list_tag| and |ext_tag|.
+
+@d no_tag 0 /*vanilla character*/
+@d lig_tag 1 /*character has a ligature/kerning program*/
+@d list_tag 2 /*character has a successor in a charlist*/
+@d ext_tag 3 /*character is extensible*/
+
+@ The |lig_kern| array contains instructions in a simple programming language
+that explains what to do for special letter pairs. Each word in this array is a
+|@!lig_kern_command| of four bytes.
+
+\yskip\hang first byte: |skip_byte|, indicates that this is the final program
+ step if the byte is 128 or more, otherwise the next step is obtained by
+ skipping this number of intervening steps.\par
+\hang second byte: |next_char|, ``if |next_char| follows the current character,
+ then perform the operation and stop, otherwise continue.''\par
+\hang third byte: |op_byte|, indicates a ligature step if less than~128,
+ a kern step otherwise.\par
+\hang fourth byte: |rem|.\par
+\yskip\noindent
+In a kern step, an
+additional space equal to |kern[256*(op_byte-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==255|,
+the |next_char| byte is the so-called right boundary character of this font;
+the value of |next_char| need not lie between |bc| and~|ec|.
+If the very last instruction of the |lig_kern| array has |skip_byte==255|,
+there is a special ligature/kerning program for a left boundary character,
+beginning at location |256*op_byte+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 > 128|, the program actually begins in location
+|256*op_byte+rem|. This feature allows access to large |lig_kern|
+arrays, because the first instruction must otherwise
+appear in a location | <= 255|.
+
+Any instruction with |skip_byte > 128| in the |lig_kern| array must satisfy
+the condition
+$$\hbox{|256*op_byte+rem < nl|.}$$
+If such an instruction is encountered during
+normal program execution, it denotes an unconditional halt; no ligature
+or kerning command is performed.
+
+@d stop_flag qi(128) /*value indicating `\.{STOP}' in a lig/kern program*/
+@d kern_flag qi(128) /*op code for a kern step*/
+@d skip_byte(X) X.b0
+@d next_char(X) X.b1
+@d op_byte(X) X.b2
+@d rem_byte(X) X.b3
+
+@ Extensible characters are specified by an |@!extensible_recipe|, which
+consists of four bytes called |@!top|, |@!mid|, |@!bot|, and |@!rep| (in this
+order). These bytes are the character codes of individual pieces used to
+build up a large symbol. If |top|, |mid|, or |bot| are zero, they are not
+present in the built-up result. For example, an extensible vertical line is
+like an extensible bracket, except that the top and bottom pieces are missing.
+
+Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
+if the piece isn't present. Then the extensible characters have the form
+$TR^kMR^kB$ from top to bottom, for some |k >= 0|, unless $M$ is absent;
+in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
+The width of the extensible character is the width of $R$; and the
+height-plus-depth is the sum of the individual height-plus-depths of the
+components used, since the pieces are butted together in a vertical list.
+
+@d ext_top(X) X.b0 /*|top| piece in a recipe*/
+@d ext_mid(X) X.b1 /*|mid| piece in a recipe*/
+@d ext_bot(X) X.b2 /*|bot| piece in a recipe*/
+@d ext_rep(X) X.b3 /*|rep| piece in a recipe*/
+
+@ The final portion of a \.{TFM} file is the |param| array, which is another
+sequence of |fix_word| values.
+
+\yskip\hang|param[1]==slant| is the amount of italic slant, which is used
+to help position accents. For example, |slant==.25| means that when you go
+up one unit, you also go .25 units to the right. The |slant| is a pure
+number; it's the only |fix_word| other than the design size itself that is
+not scaled by the design size.
+
+\hang|param[2]==space| is the normal spacing between words in text.
+Note that character |' '| in the font need not have anything to do with
+blank spaces.
+
+\hang|param[3]==space_stretch| is the amount of glue stretching between words.
+
+\hang|param[4]==space_shrink| is the amount of glue shrinking between words.
+
+\hang|param[5]==x_height| is the size of one ex in the font; it is also
+the height of letters for which accents don't have to be raised or lowered.
+
+\hang|param[6]==quad| is the size of one em in the font.
+
+\hang|param[7]==extra_space| is the amount added to |param[2]| at the
+ends of sentences.
+
+\yskip\noindent
+If fewer than seven parameters are present, \TeX\ sets the missing parameters
+to zero. Fonts used for math symbols are required to have
+additional parameter information, which is explained later.
+
+@d slant_code 1
+@d space_code 2
+@d space_stretch_code 3
+@d space_shrink_code 4
+@d x_height_code 5
+@d quad_code 6
+@d extra_space_code 7
+
+@ So that is what \.{TFM} files hold. Since \TeX\ has to absorb such information
+about lots of fonts, it stores most of the data in a large array called
+|font_info|. Each item of |font_info| is a |memory_word|; the |fix_word|
+data gets converted into |scaled| entries, while everything else goes into
+words of type |four_quarters|.
+
+When the user defines \.{\\font\\f}, say, \TeX\ assigns an internal number
+to the user's font~\.{\\f}. Adding this number to |font_id_base| gives the
+|eqtb| location of a ``frozen'' control sequence that will always select
+the font.
+
+@<Types...@>=
+typedef uint8_t internal_font_number; /*|font| in a |char_node|*/
+typedef uint16_t font_index; /*index into |font_info|*/
+
+@ Here now is the (rather formidable) array of font arrays.
+
+@d non_char qi(256) /*a |halfword| code that can't match a real character*/
+@d non_address 0 /*a spurious |bchar_label|*/
+
+@<Glob...@>=
+memory_word @!font_info[font_mem_size+1];
+ /*the big collection of font data*/
+font_index @!fmem_ptr; /*first unused word of |font_info|*/
+internal_font_number @!font_ptr; /*largest internal font number in use*/
+four_quarters @!font_check0[font_max-font_base+1], *const @!font_check = @!font_check0-font_base; /*check sum*/
+scaled @!font_size0[font_max-font_base+1], *const @!font_size = @!font_size0-font_base; /*``at'' size*/
+scaled @!font_dsize0[font_max-font_base+1], *const @!font_dsize = @!font_dsize0-font_base; /*``design'' size*/
+font_index @!font_params0[font_max-font_base+1], *const @!font_params = @!font_params0-font_base; /*how many font
+ parameters are present*/
+str_number @!font_name0[font_max-font_base+1], *const @!font_name = @!font_name0-font_base; /*name of the font*/
+str_number @!font_area0[font_max-font_base+1], *const @!font_area = @!font_area0-font_base; /*area of the font*/
+eight_bits @!font_bc0[font_max-font_base+1], *const @!font_bc = @!font_bc0-font_base;
+ /*beginning (smallest) character code*/
+eight_bits @!font_ec0[font_max-font_base+1], *const @!font_ec = @!font_ec0-font_base;
+ /*ending (largest) character code*/
+pointer @!font_glue0[font_max-font_base+1], *const @!font_glue = @!font_glue0-font_base;
+ /*glue specification for interword space, |null| if not allocated*/
+bool @!font_used0[font_max-font_base+1], *const @!font_used = @!font_used0-font_base;
+ /*has a character from this font actually appeared in the output?*/
+int @!hyphen_char0[font_max-font_base+1], *const @!hyphen_char = @!hyphen_char0-font_base;
+ /*current \.{\\hyphenchar} values*/
+int @!skew_char0[font_max-font_base+1], *const @!skew_char = @!skew_char0-font_base;
+ /*current \.{\\skewchar} values*/
+font_index @!bchar_label0[font_max-font_base+1], *const @!bchar_label = @!bchar_label0-font_base;
+ /*start of |lig_kern| program for left boundary character,
+ |non_address| if there is none*/
+uint16_t @!font_bchar0[font_max-font_base+1], *const @!font_bchar = @!font_bchar0-font_base;
+ /*right boundary character, |non_char| if there is none*/
+uint16_t @!font_false_bchar0[font_max-font_base+1], *const @!font_false_bchar = @!font_false_bchar0-font_base;
+ /*|font_bchar| if it doesn't exist in the font, otherwise |non_char|*/
+
+@ Besides the arrays just enumerated, we have directory arrays that make it
+easy to get at the individual entries in |font_info|. For example, the
+|char_info| data for character |c| in font |f| will be in
+|font_info[char_base[f]+c].qqqq|; and if |w| is the |width_index|
+part of this word (the |b0| field), the width of the character is
+|font_info[width_base[f]+w].sc|. (These formulas assume that
+|min_quarterword| has already been added to |c| and to |w|, since \TeX\
+stores its quarterwords that way.)
+
+@<Glob...@>=
+int @!char_base0[font_max-font_base+1], *const @!char_base = @!char_base0-font_base;
+ /*base addresses for |char_info|*/
+int @!width_base0[font_max-font_base+1], *const @!width_base = @!width_base0-font_base;
+ /*base addresses for widths*/
+int @!height_base0[font_max-font_base+1], *const @!height_base = @!height_base0-font_base;
+ /*base addresses for heights*/
+int @!depth_base0[font_max-font_base+1], *const @!depth_base = @!depth_base0-font_base;
+ /*base addresses for depths*/
+int @!italic_base0[font_max-font_base+1], *const @!italic_base = @!italic_base0-font_base;
+ /*base addresses for italic corrections*/
+int @!lig_kern_base0[font_max-font_base+1], *const @!lig_kern_base = @!lig_kern_base0-font_base;
+ /*base addresses for ligature/kerning programs*/
+int @!kern_base0[font_max-font_base+1], *const @!kern_base = @!kern_base0-font_base;
+ /*base addresses for kerns*/
+int @!exten_base0[font_max-font_base+1], *const @!exten_base = @!exten_base0-font_base;
+ /*base addresses for extensible recipes*/
+int @!param_base0[font_max-font_base+1], *const @!param_base = @!param_base0-font_base;
+ /*base addresses for font parameters*/
+
+@ @<Set init...@>=
+for (k=font_base; k<=font_max; k++) font_used[k]=false;
+
+@ \TeX\ always knows at least one font, namely the null font. It has no
+characters, and its seven parameters are all equal to zero.
+
+@<Initialize table...@>=
+font_ptr=null_font;fmem_ptr=7;
+font_name[null_font]=@[@<|"nullfont"|@>@];font_area[null_font]=empty_string;
+hyphen_char[null_font]='-';skew_char[null_font]=-1;
+bchar_label[null_font]=non_address;
+font_bchar[null_font]=non_char;font_false_bchar[null_font]=non_char;
+font_bc[null_font]=1;font_ec[null_font]=0;
+font_size[null_font]=0;font_dsize[null_font]=0;
+char_base[null_font]=0;width_base[null_font]=0;
+height_base[null_font]=0;depth_base[null_font]=0;
+italic_base[null_font]=0;lig_kern_base[null_font]=0;
+kern_base[null_font]=0;exten_base[null_font]=0;
+font_glue[null_font]=null;font_params[null_font]=7;
+param_base[null_font]=-1;
+for (k=0; k<=6; k++) font_info[k].sc=0;
+
+@ @<Put each...@>=
+primitive(@[@<|"nullfont"|@>@], set_font, null_font);
+@!@:null_font_}{\.{\\nullfont} primitive@>
+text(frozen_null_font)=@[@<|"nullfont"|@>@];eqtb[frozen_null_font]=eqtb[cur_val];
+
+@ Of course we want to define macros that suppress the detail of how font
+information is actually packed, so that we don't have to write things like
+$$\hbox{|font_info[width_base[f]+font_info[char_base[f]+c].qqqq.b0].sc|}$$
+too often. The \.{WEB} definitions here make |char_info(f)(c)| the
+|four_quarters| word of font information corresponding to character
+|c| of font |f|. If |q| is such a word, |char_width(f)(q)| will be
+the character's width; hence the long formula above is at least
+abbreviated to
+$$\hbox{|char_width(f)(char_info(f)(c))|.}$$
+Usually, of course, we will fetch |q| first and look at several of its
+fields at the same time.
+
+The italic correction of a character will be denoted by
+|char_italic(f)(q)|, so it is analogous to |char_width|. But we will get
+at the height and depth in a slightly different way, since we usually want
+to compute both height and depth if we want either one. The value of
+|height_depth(q)| will be the 8-bit quantity
+$$b=|height_index|\times16+|depth_index|,$$ and if |b| is such a byte we
+will write |char_height(f)(b)| and |char_depth(f)(b)| for the height and
+depth of the character |c| for which |q==char_info(f)(c)|. Got that?
+
+The tag field will be called |char_tag(q)|; the remainder byte will be
+called |rem_byte(q)|, using a macro that we have already defined above.
+
+Access to a character's |width|, |height|, |depth|, and |tag| fields is
+part of \TeX's inner loop, so we want these macros to produce code that is
+as fast as possible under the circumstances.
+@^inner loop@>
+
+@d char_info_end(X) X].qqqq
+@d char_info(X) font_info[char_base[X]+char_info_end
+@d char_width_end(X) X.b0].sc
+@d char_width(X) font_info[width_base[X]+char_width_end
+@d char_exists(X) (X.b0 > min_quarterword)
+@d char_italic_end(X) (qo(X.b2))/4].sc
+@d char_italic(X) font_info[italic_base[X]+char_italic_end
+@d height_depth(X) qo(X.b1)
+@d char_height_end(X) (X)/16].sc
+@d char_height(X) font_info[height_base[X]+char_height_end
+@d char_depth_end(X) (X)%16].sc
+@d char_depth(X) font_info[depth_base[X]+char_depth_end
+@d char_tag(X) ((qo(X.b2))%4)
+
+@ The global variable |null_character| is set up to be a word of
+|char_info| for a character that doesn't exist. Such a word provides a
+convenient way to deal with erroneous situations.
+
+@<Glob...@>=
+four_quarters @!null_character; /*nonexistent character information*/
+
+@ @<Set init...@>=
+null_character.b0=min_quarterword;null_character.b1=min_quarterword;
+null_character.b2=min_quarterword;null_character.b3=min_quarterword;
+
+@ Here are some macros that help process ligatures and kerns.
+We write |char_kern(f)(j)| to find the amount of kerning specified by
+kerning command~|j| in font~|f|. If |j| is the |char_info| for a character
+with a ligature/kern program, the first instruction of that program is either
+|i==font_info[lig_kern_start(f)(j)]| or |font_info[lig_kern_restart(f)(i)]|,
+depending on whether or not |skip_byte(i) <= stop_flag|.
+
+The constant |kern_base_offset| should be simplified, for \PASCAL\ compilers
+that do not do local optimization.
+@^system dependencies@>
+
+@d char_kern_end(X) 256*op_byte(X)+rem_byte(X)].sc
+@d char_kern(X) font_info[kern_base[X]+char_kern_end
+@d kern_base_offset 256*(128+min_quarterword)
+@d lig_kern_start(X) lig_kern_base[X]+rem_byte /*beginning of lig/kern program*/
+@d lig_kern_restart_end(X) 256*op_byte(X)+rem_byte(X)+32768-kern_base_offset
+@d lig_kern_restart(X) lig_kern_base[X]+lig_kern_restart_end
+
+@ Font parameters are referred to as |slant(f)|, |space(f)|, etc.
+
+@d param_end(X) param_base[X]].sc
+@d param(X) font_info[X+param_end
+@d slant param(slant_code) /*slant to the right, per unit distance upward*/
+@d space param(space_code) /*normal space between words*/
+@d space_stretch param(space_stretch_code) /*stretch between words*/
+@d space_shrink param(space_shrink_code) /*shrink between words*/
+@d x_height param(x_height_code) /*one ex*/
+@d quad param(quad_code) /*one em*/
+@d extra_space param(extra_space_code) /*additional space at end of sentence*/
+
+@<The em width for |cur_font|@>=quad(cur_font)
+
+@ @<The x-height for |cur_font|@>=x_height(cur_font)
+
+@ \TeX\ checks the information of a \.{TFM} file for validity as the
+file is being read in, so that no further checks will be needed when
+typesetting is going on. The somewhat tedious subroutine that does this
+is called |read_font_info|. It has four parameters: the user font
+identifier~|u|, the file name and area strings |nom| and |aire|, and the
+``at'' size~|s|. If |s|~is negative, it's the negative of a scale factor
+to be applied to the design size; |s==-1000| is the normal case.
+Otherwise |s| will be substituted for the design size; in this
+case, |s| must be positive and less than $2048\rm\,pt$
+(i.e., it must be less than $2^{27}$ when considered as an integer).
+
+The subroutine opens and closes a global file variable called |tfm_file|.
+It returns the value of the internal font number that was just loaded.
+If an error is detected, an error message is issued and no font
+information is stored; |null_font| is returned in this case.
+
+@d abort goto bad_tfm /*do this when the \.{TFM} data is wrong*/
+
+@p internal_font_number read_font_info(pointer @!u, str_number @!nom, str_number @!aire,
+ scaled @!s) /*input a \.{TFM} file*/
+{@+
+font_index k; /*index into |font_info|*/
+bool @!file_opened; /*was |tfm_file| successfully opened?*/
+halfword @!lf, @!lh, @!bc, @!ec, @!nw, @!nh, @!nd, @!ni, @!nl, @!nk, @!ne, @!np;
+ /*sizes of subfiles*/
+internal_font_number @!f; /*the new font's number*/
+internal_font_number @!g; /*the number to return*/
+eight_bits @!a, @!b, @!c, @!d; /*byte variables*/
+four_quarters @!qw;scaled @!sw; /*accumulators*/
+int @!bch_label; /*left boundary start location, or infinity*/
+uint16_t @!bchar; /*right boundary character, or 256*/
+scaled @!z; /*the design size or the ``at'' size*/
+int @!alpha;uint8_t @!beta;
+ /*auxiliary quantities used in fixed-point multiplication*/
+g=null_font;@/
+@<Read and check the font data; |abort| if the \.{TFM} file is malformed; if there's
+no room for this font, say so and |goto done|; otherwise |incr(font_ptr)| and |goto
+done|@>;
+bad_tfm: @<Report that the font won't be loaded@>;
+done: if (file_opened) b_close(&tfm_file);
+return g;
+}
+
+@ There are programs called \.{TFtoPL} and \.{PLtoTF} that convert
+between the \.{TFM} format and a symbolic property-list format
+that can be easily edited. These programs contain extensive
+diagnostic information, so \TeX\ does not have to bother giving
+precise details about why it rejects a particular \.{TFM} file.
+@.TFtoPL@> @.PLtoTF@>
+
+@d start_font_error_message print_err("Font ");sprint_cs(u);
+ print_char('=');print_file_name(nom, aire, empty_string);
+ if (s >= 0)
+ {@+print_str(" at ");print_scaled(s);print_str("pt");
+ }
+ else if (s!=-1000)
+ {@+print_str(" scaled ");print_int(-s);
+ }
+
+@<Report that the font won't be loaded@>=
+start_font_error_message;
+@.Font x=xx not loadable...@>
+if (file_opened) print_str(" not loadable: Bad metric (TFM) file");
+else print_str(" not loadable: Metric (TFM) file not found");
+help5("I wasn't able to read the size data for this font,")@/
+("so I will ignore the font specification.")@/
+("[Wizards can fix TFM files using TFtoPL/PLtoTF.]")@/
+("You might try inserting a different font spec;")@/
+("e.g., type `I\\font<same font id>=<substitute font name>'.");
+error()
+
+@ @<Read and check...@>=
+@<Open |tfm_file| for input@>;
+@<Read the {\.{TFM}} size fields@>;
+@<Use size fields to allocate font information@>;
+@<Read the {\.{TFM}} header@>;
+@<Read character data@>;
+@<Read box dimensions@>;
+@<Read ligature/kern program@>;
+@<Read extensible character recipes@>;
+@<Read font parameters@>;
+@<Make final adjustments and |goto done|@>@;
+
+@ @<Open |tfm_file| for input@>=
+file_opened=false;
+if (aire==empty_string) pack_file_name(nom, TEX_font_area,@[@<|".tfm"|@>@]);
+else pack_file_name(nom, aire,@[@<|".tfm"|@>@]);
+if (!b_open_in(&tfm_file)) abort;
+file_opened=true
+
+@ Note: A malformed \.{TFM} file might be shorter than it claims to be;
+thus |eof(tfm_file)| might be true when |read_font_info| refers to
+|tfm_file.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'.
+@^system dependencies@>
+
+@d fget get(tfm_file)
+@d fbyte tfm_file.d
+@d read_sixteen(X) {@+X=fbyte;
+ if (X > 127) abort;
+ fget;X=X*0400+fbyte;
+ }
+@d store_four_quarters(X) {@+fget;a=fbyte;qw.b0=qi(a);
+ fget;b=fbyte;qw.b1=qi(b);
+ fget;c=fbyte;qw.b2=qi(c);
+ fget;d=fbyte;qw.b3=qi(d);
+ X=qw;
+ }
+
+@ @<Read the {\.{TFM}} size fields@>=
+{@+read_sixteen(lf);
+fget;read_sixteen(lh);
+fget;read_sixteen(bc);
+fget;read_sixteen(ec);
+if ((bc > ec+1)||(ec > 255)) abort;
+if (bc > 255) /*|bc==256| and |ec==255|*/
+ {@+bc=1;ec=0;
+ }
+fget;read_sixteen(nw);
+fget;read_sixteen(nh);
+fget;read_sixteen(nd);
+fget;read_sixteen(ni);
+fget;read_sixteen(nl);
+fget;read_sixteen(nk);
+fget;read_sixteen(ne);
+fget;read_sixteen(np);
+if (lf!=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np) abort;
+if ((nw==0)||(nh==0)||(nd==0)||(ni==0)) abort;
+}
+
+@ The preliminary settings of the index-offset variables |char_base|,
+|width_base|, |lig_kern_base|, |kern_base|, and |exten_base| will be
+corrected later by subtracting |min_quarterword| from them; and we will
+subtract 1 from |param_base| too. It's best to forget about such anomalies
+until later.
+
+@<Use size fields to allocate font information@>=
+lf=lf-6-lh; /*|lf| words should be loaded into |font_info|*/
+if (np < 7) lf=lf+7-np; /*at least seven parameters will appear*/
+if ((font_ptr==font_max)||(fmem_ptr+lf > font_mem_size))
+ @<Apologize for not loading the font, |goto done|@>;
+f=font_ptr+1;
+char_base[f]=fmem_ptr-bc;
+width_base[f]=char_base[f]+ec+1;
+height_base[f]=width_base[f]+nw;
+depth_base[f]=height_base[f]+nh;
+italic_base[f]=depth_base[f]+nd;
+lig_kern_base[f]=italic_base[f]+ni;
+kern_base[f]=lig_kern_base[f]+nl-kern_base_offset;
+exten_base[f]=kern_base[f]+kern_base_offset+nk;
+param_base[f]=exten_base[f]+ne
+
+@ @<Apologize for not loading...@>=
+{@+start_font_error_message;
+print_str(" not loaded: Not enough room left");
+@.Font x=xx not loaded...@>
+help4("I'm afraid I won't be able to make use of this font,")@/
+("because my memory for character-size data is too small.")@/
+("If you're really stuck, ask a wizard to enlarge me.")@/
+("Or maybe try `I\\font<same font id>=<name of loaded font>'.");
+error();goto done;
+}
+
+@ Only the first two words of the header are needed by \TeX82.
+
+@<Read the {\.{TFM}} header@>=
+{@+if (lh < 2) abort;
+store_four_quarters(font_check[f]);
+fget;read_sixteen(z); /*this rejects a negative design size*/
+fget;z=z*0400+fbyte;fget;z=(z*020)+(fbyte/020);
+if (z < unity) abort;
+while (lh > 2)
+ {@+fget;fget;fget;fget;decr(lh); /*ignore the rest of the header*/
+ }
+font_dsize[f]=z;
+if (s!=-1000)
+ if (s >= 0) z=s;
+ else z=xn_over_d(z,-s, 1000);
+font_size[f]=z;
+}
+
+@ @<Read character data@>=
+for (k=fmem_ptr; k<=width_base[f]-1; k++)
+ {@+store_four_quarters(font_info[k].qqqq);
+ if ((a >= nw)||(b/020 >= nh)||(b%020 >= nd)||
+ (c/4 >= ni)) abort;
+ switch (c%4) {
+ case lig_tag: if (d >= nl) abort;@+break;
+ case ext_tag: if (d >= ne) abort;@+break;
+ case list_tag: @<Check for charlist cycle@>@;@+break;
+ default:do_nothing; /*|no_tag|*/
+ }
+ }
+
+@ We want to make sure that there is no cycle of characters linked together
+by |list_tag| entries, since such a cycle would get \TeX\ into an endless
+loop. If such a cycle exists, the routine here detects it when processing
+the largest character code in the cycle.
+
+@d check_byte_range(X) {@+if ((X < bc)||(X > ec)) abort;@+}
+@d current_character_being_worked_on k+bc-fmem_ptr
+
+@<Check for charlist cycle@>=
+{@+check_byte_range(d);
+while (d < current_character_being_worked_on)
+ {@+qw=char_info(f)(d);
+ /*N.B.: not |qi(d)|, since |char_base[f]| hasn't been adjusted yet*/
+ if (char_tag(qw)!=list_tag) goto not_found;
+ d=qo(rem_byte(qw)); /*next character on the list*/
+ }
+if (d==current_character_being_worked_on) abort; /*yes, there's a cycle*/
+not_found: ;}
+
+@ A |fix_word| whose four bytes are $(a,b,c,d)$ from left to right represents
+the number
+$$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
+-16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$
+(No other choices of |a| are allowed, since the magnitude of a number in
+design-size units must be less than 16.) We want to multiply this
+quantity by the integer~|z|, which is known to be less than $2^{27}$.
+If $|z|<2^{23}$, the individual multiplications $b\cdot z$,
+$c\cdot z$, $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2,
+4, 8, or 16, to obtain a multiplier less than $2^{23}$, and we can
+compensate for this later. If |z| has thereby been replaced by
+$|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we shall compute
+$$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$
+if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$.
+This calculation must be done exactly, in order to guarantee portability
+of \TeX\ between computers.
+
+@d store_scaled(X) {@+fget;a=fbyte;fget;b=fbyte;
+ fget;c=fbyte;fget;d=fbyte;@/
+ sw=(((((d*z)/0400)+(c*z))/0400)+(b*z))/beta;
+ if (a==0) X=sw;@+else if (a==255) X=sw-alpha;@+else abort;
+ }
+
+@<Read box dimensions@>=
+{@+@<Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$@>;
+for (k=width_base[f]; k<=lig_kern_base[f]-1; k++)
+ store_scaled(font_info[k].sc);
+if (font_info[width_base[f]].sc!=0) abort; /*\\{width}[0] must be zero*/
+if (font_info[height_base[f]].sc!=0) abort; /*\\{height}[0] must be zero*/
+if (font_info[depth_base[f]].sc!=0) abort; /*\\{depth}[0] must be zero*/
+if (font_info[italic_base[f]].sc!=0) abort; /*\\{italic}[0] must be zero*/
+}
+
+@ @<Replace |z|...@>=
+{@+alpha=16;
+while (z >= 040000000)
+ {@+z=z/2;alpha=alpha+alpha;
+ }
+beta=256/alpha;alpha=alpha*z;
+}
+
+@ @d check_existence(X) @t@>@;@/
+ {@+check_byte_range(X);
+ qw=char_info(f)(X); /*N.B.: not |qi(X)|*/
+ if (!char_exists(qw)) abort;
+ }
+
+@<Read ligature/kern program@>=
+bch_label=077777;bchar=256;
+if (nl > 0)
+ {@+for (k=lig_kern_base[f]; k<=kern_base[f]+kern_base_offset-1; k++)
+ {@+store_four_quarters(font_info[k].qqqq);
+ if (a > 128)
+ {@+if (256*c+d >= nl) abort;
+ if (a==255) if (k==lig_kern_base[f]) bchar=b;
+ }
+ else{@+if (b!=bchar) check_existence(b);
+ if (c < 128) check_existence(d)@; /*check ligature*/
+ else if (256*(c-128)+d >= nk) abort; /*check kern*/
+ if (a < 128) if (k-lig_kern_base[f]+a+1 >= nl) abort;
+ }
+ }
+ if (a==255) bch_label=256*c+d;
+ }
+for (k=kern_base[f]+kern_base_offset; k<=exten_base[f]-1; k++)
+ store_scaled(font_info[k].sc);
+
+@ @<Read extensible character recipes@>=
+for (k=exten_base[f]; k<=param_base[f]-1; k++)
+ {@+store_four_quarters(font_info[k].qqqq);
+ if (a!=0) check_existence(a);
+ if (b!=0) check_existence(b);
+ if (c!=0) check_existence(c);
+ check_existence(d);
+ }
+
+@ We check to see that the \.{TFM} file doesn't end prematurely; but
+no error message is given for files having more than |lf| words.
+
+@<Read font parameters@>=
+{@+for (k=1; k<=np; k++)
+ if (k==1) /*the |slant| parameter is a pure number*/
+ {@+fget;sw=fbyte;if (sw > 127) sw=sw-256;
+ fget;sw=sw*0400+fbyte;fget;sw=sw*0400+fbyte;
+ fget;font_info[param_base[f]].sc=
+ (sw*020)+(fbyte/020);
+ }
+ else store_scaled(font_info[param_base[f]+k-1].sc);
+if (eof(tfm_file)) abort;
+for (k=np+1; k<=7; k++) font_info[param_base[f]+k-1].sc=0;
+}
+
+@ Now to wrap it up, we have checked all the necessary things about the \.{TFM}
+file, and all we need to do is put the finishing touches on the data for
+the new font.
+
+@d adjust(X) X[f]=qo(X[f])
+ /*correct for the excess |min_quarterword| that was added*/
+
+@<Make final adjustments...@>=
+if (np >= 7) font_params[f]=np;@+else font_params[f]=7;
+hyphen_char[f]=default_hyphen_char;skew_char[f]=default_skew_char;
+if (bch_label < nl) bchar_label[f]=bch_label+lig_kern_base[f];
+else bchar_label[f]=non_address;
+font_bchar[f]=qi(bchar);
+font_false_bchar[f]=qi(bchar);
+if (bchar <= ec) if (bchar >= bc)
+ {@+qw=char_info(f)(bchar); /*N.B.: not |qi(bchar)|*/
+ if (char_exists(qw)) font_false_bchar[f]=non_char;
+ }
+font_name[f]=nom;
+font_area[f]=aire;
+font_bc[f]=bc;font_ec[f]=ec;font_glue[f]=null;
+adjust(char_base);adjust(width_base);adjust(lig_kern_base);
+adjust(kern_base);adjust(exten_base);
+decr(param_base[f]);
+fmem_ptr=fmem_ptr+lf;font_ptr=f;g=f;goto done
+
+@ Before we forget about the format of these tables, let's deal with two
+of \TeX's basic scanning routines related to font information.
+
+@<Declare procedures that scan font-related stuff@>=
+void scan_font_ident(void)
+{@+internal_font_number f;
+halfword @!m;
+@<Get the next non-blank non-call...@>;
+if (cur_cmd==def_font) f=cur_font;
+else if (cur_cmd==set_font) f=cur_chr;
+else if (cur_cmd==def_family)
+ {@+m=cur_chr;scan_four_bit_int();f=equiv(m+cur_val);
+ }
+else{@+print_err("Missing font identifier");
+@.Missing font identifier@>
+ help2("I was looking for a control sequence whose")@/
+ ("current meaning has been defined by \\font.");
+ back_error();f=null_font;
+ }
+cur_val=f;
+}
+
+@ The following routine is used to implement `\.{\\fontdimen} |n| |f|'.
+The boolean parameter |writing| is set |true| if the calling program
+intends to change the parameter value.
+
+@<Declare procedures that scan font-related stuff@>=
+void find_font_dimen(bool @!writing)
+ /*sets |cur_val| to |font_info| location*/
+{@+internal_font_number f;
+int @!n; /*the parameter number*/
+scan_int();n=cur_val;scan_font_ident();f=cur_val;
+if (n <= 0) cur_val=fmem_ptr;
+else{@+if (writing&&(n <= space_shrink_code)&&@|
+ (n >= space_code)&&(font_glue[f]!=null))
+ {@+delete_glue_ref(font_glue[f]);
+ font_glue[f]=null;
+ }
+ if (n > font_params[f])
+ if (f < font_ptr) cur_val=fmem_ptr;
+ else@<Increase the number of parameters in the last font@>@;
+ else cur_val=n+param_base[f];
+ }
+@<Issue an error message if |cur_val=fmem_ptr|@>;
+}
+
+@ @<Issue an error message if |cur_val=fmem_ptr|@>=
+if (cur_val==fmem_ptr)
+ {@+print_err("Font ");print_esc(font_id_text(f));
+ print_str(" has only ");print_int(font_params[f]);
+ print_str(" fontdimen parameters");
+@.Font x has only...@>
+ help2("To increase the number of font parameters, you must")@/
+ ("use \\fontdimen immediately after the \\font is loaded.");
+ error();
+ }
+
+@ @<Increase the number of parameters...@>=
+{@+@/do@+{if (fmem_ptr==font_mem_size)
+ overflow("font memory", font_mem_size);
+@:TeX capacity exceeded font memory}{\quad font memory@>
+font_info[fmem_ptr].sc=0;incr(fmem_ptr);incr(font_params[f]);
+}@+ while (!(n==font_params[f]));
+cur_val=fmem_ptr-1; /*this equals |param_base[f]+font_params[f]|*/
+}
+
+@ 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.
+
+@p void char_warning(internal_font_number @!f, eight_bits @!c)
+{@+if (tracing_lost_chars > 0)
+ {@+begin_diagnostic();
+ print_nl("Missing character: There is no ");
+@.Missing character@>
+ print_ASCII(c);print_str(" in font ");
+ slow_print(font_name[f]);print_char('!');end_diagnostic(false);
+ }
+}
+
+@ 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.
+
+@p pointer new_character(internal_font_number @!f, eight_bits @!c)
+{@+
+pointer p; /*newly allocated node*/
+if (font_bc[f] <= c) if (font_ec[f] >= c)
+ if (char_exists(char_info(f)(qi(c))))
+ {@+p=get_avail();font(p)=f;character(p)=qi(c);
+ return p;
+ }
+char_warning(f, c);
+return null;
+}
+
+@* Device-independent file format.
+The most important output produced by a run of \TeX\ is the ``device
+independent'' (\.{DVI}) file that specifies where characters and rules
+are to appear on printed pages. The form of these files was designed by
+David R. Fuchs in 1979. Almost any reasonable typesetting device can be
+@^Fuchs, David Raymond@>
+@:DVI_files}{\.{DVI} files@>
+driven by a program that takes \.{DVI} files as input, and dozens of such
+\.{DVI}-to-whatever programs have been written. Thus, it is possible to
+print the output of \TeX\ on many different kinds of equipment, using \TeX\
+as a device-independent ``front end.''
+
+A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a
+series of commands in a machine-like language. The first byte of each command
+is the operation code, and this code is followed by zero or more bytes
+that provide parameters to the command. The parameters themselves may consist
+of several consecutive bytes; for example, the `|set_rule|' command has two
+parameters, each of which is four bytes long. Parameters are usually
+regarded as nonnegative integers; but four-byte-long parameters,
+and shorter parameters that denote distances, can be
+either positive or negative. Such parameters are given in two's complement
+notation. For example, a two-byte-long distance parameter has a value between
+$-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy
+more than one byte position appear in BigEndian order.
+
+A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one
+or more ``pages,'' followed by a ``postamble.'' The preamble is simply a
+|pre| command, with its parameters that define the dimensions used in the
+file; this must come first. Each ``page'' consists of a |bop| command,
+followed by any number of other commands that tell where characters are to
+be placed on a physical page, followed by an |eop| command. The pages
+appear in the order that \TeX\ generated them. If we ignore |nop| commands
+and \\{fnt\_def} commands (which are allowed between any two commands in
+the file), each |eop| command is immediately followed by a |bop| command,
+or by a |post| command; in the latter case, there are no more pages in the
+file, and the remaining bytes form the postamble. Further details about
+the postamble will be explained later.
+
+Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
+quantities that give the location number of some other byte in the file;
+the first byte is number~0, then comes number~1, and so on. For example,
+one of the parameters of a |bop| command points to the previous |bop|;
+this makes it feasible to read the pages in backwards order, in case the
+results are being directed to a device that stacks its output face up.
+Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the
+first page occupies bytes 100 to 999, say, and if the second
+page occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000
+points to 100 and the |bop| that starts in byte 2000 points to 1000. (The
+very first |bop|, i.e., the one starting in byte 100, has a pointer of~$-1$.)
+
+@ The \.{DVI} format is intended to be both compact and easily interpreted
+by a machine. Compactness is achieved by making most of the information
+implicit instead of explicit. When a \.{DVI}-reading program reads the
+commands for a page, it keeps track of several quantities: (a)~The current
+font |f| is an integer; this value is changed only
+by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page
+is given by two numbers called the horizontal and vertical coordinates,
+|h| and |v|. Both coordinates are zero at the upper left corner of the page;
+moving to the right corresponds to increasing the horizontal coordinate, and
+moving down corresponds to increasing the vertical coordinate. Thus, the
+coordinates are essentially Cartesian, except that vertical directions are
+flipped; the Cartesian version of |(h, v)| would be |(h,-v)|. (c)~The
+current spacing amounts are given by four numbers |w|, |x|, |y|, and |z|,
+where |w| and~|x| are used for horizontal spacing and where |y| and~|z|
+are used for vertical spacing. (d)~There is a stack containing
+|(h, v, w, x, y, z)| values; the \.{DVI} commands |push| and |pop| are used to
+change the current level of operation. Note that the current font~|f| is
+not pushed and popped; the stack contains only information about
+positioning.
+
+The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up
+to 32 bits, including the sign. Since they represent physical distances,
+there is a small unit of measurement such that increasing |h| by~1 means
+moving a certain tiny distance to the right. The actual unit of
+measurement is variable, as explained below; \TeX\ sets things up so that
+its \.{DVI} output is in sp units, i.e., scaled points, in agreement with
+all the |scaled| dimensions in \TeX's data structures.
+
+@ Here is a list of all the commands that may appear in a \.{DVI} file. Each
+command is specified by its symbolic name (e.g., |bop|), its opcode byte
+(e.g., 139), and its parameters (if any). The parameters are followed
+by a bracketed number telling how many bytes they occupy; for example,
+`|p[4]|' means that parameter |p| is four bytes long.
+
+\yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f|
+such that the reference point of the character is at |(h, v)|. Then
+increase |h| by the width of that character. Note that a character may
+have zero or negative width, so one cannot be sure that |h| will advance
+after this command; but |h| usually does increase.
+
+\yskip\hang\\{set\_char\_1} through \\{set\_char\_127} (opcodes 1 to 127).
+Do the operations of |set_char_0|; but use the character whose number
+matches the opcode, instead of character~0.
+
+\yskip\hang|set1| 128 |c[1]|. Same as |set_char_0|, except that character
+number~|c| is typeset. \TeX82 uses this command for characters in the
+range |128 <= c < 256|.
+
+\yskip\hang|@!set2| 129 |c[2]|. Same as |set1|, except that |c|~is two
+bytes long, so it is in the range |0 <= c < 65536|. \TeX82 never uses this
+command, but it should come in handy for extensions of \TeX\ that deal
+with oriental languages.
+@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
+
+\yskip\hang|@!set3| 130 |c[3]|. Same as |set1|, except that |c|~is three
+bytes long, so it can be as large as $2^{24}-1$. Not even the Chinese
+language has this many characters, but this command might prove useful
+in some yet unforeseen extension.
+
+\yskip\hang|@!set4| 131 |c[4]|. Same as |set1|, except that |c|~is four
+bytes long. Imagine that.
+
+\yskip\hang|set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle
+of height~|a| and width~|b|, with its bottom left corner at |(h, v)|. Then
+set |h=h+b|. If either |a <= 0| or |b <= 0|, nothing should be typeset. Note
+that if |b < 0|, the value of |h| will decrease even though nothing else happens.
+See below for details about how to typeset rules so that consistency with
+\MF\ is guaranteed.
+
+\yskip\hang|@!put1| 133 |c[1]|. Typeset character number~|c| from font~|f|
+such that the reference point of the character is at |(h, v)|. (The `put'
+commands are exactly like the `set' commands, except that they simply put out a
+character or a rule without moving the reference point afterwards.)
+
+\yskip\hang|@!put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.
+
+\yskip\hang|@!put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.
+
+\yskip\hang|@!put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.
+
+\yskip\hang|put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that
+|h| is not changed.
+
+\yskip\hang|nop| 138. No operation, do nothing. Any number of |nop|'s
+may occur between \.{DVI} commands, but a |nop| cannot be inserted between
+a command and its parameters or between two parameters.
+
+\yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning
+of a page: Set |(h, v, w, x, y, z)=(0, 0, 0, 0, 0, 0)| and set the stack empty. Set
+the current font |f| to an undefined value. The ten $c_i$ parameters hold
+the values of \.{\\count0} $\ldots$ \.{\\count9} in \TeX\ at the time
+\.{\\shipout} was invoked for this page; they can be used to identify
+pages, if a user wants to print only part of a \.{DVI} file. The parameter
+|p| points to the previous |bop| in the file; the first
+|bop| has $p=-1$.
+
+\yskip\hang|eop| 140. End of page: Print what you have read since the
+previous |bop|. At this point the stack should be empty. (The \.{DVI}-reading
+programs that drive most output devices will have kept a buffer of the
+material that appears on the page that has just ended. This material is
+largely, but not entirely, in order by |v| coordinate and (for fixed |v|) by
+|h|~coordinate; so it usually needs to be sorted into some order that is
+appropriate for the device in question.)
+
+\yskip\hang|push| 141. Push the current values of |(h, v, w, x, y, z)| onto the
+top of the stack; do not change any of these values. Note that |f| is
+not pushed.
+
+\yskip\hang|pop| 142. Pop the top six values off of the stack and assign
+them respectively to |(h, v, w, x, y, z)|. The number of pops should never
+exceed the number of pushes, since it would be highly embarrassing if the
+stack were empty at the time of a |pop| command.
+
+\yskip\hang|right1| 143 |b[1]|. Set |h=h+b|, i.e., move right |b| units.
+The parameter is a signed number in two's complement notation, |-128 <= b < 128|;
+if |b < 0|, the reference point moves left.
+
+\yskip\hang|right2| 144 |b[2]|. Same as |right1|, except that |b| is a
+two-byte quantity in the range |-32768 <= b < 32768|.
+
+\yskip\hang|right3| 145 |b[3]|. Same as |right1|, except that |b| is a
+three-byte quantity in the range |@t$-2^{23}$@> <= b < @t$2^{23}$@>|.
+
+\yskip\hang|right4| 146 |b[4]|. Same as |right1|, except that |b| is a
+four-byte quantity in the range |@t$-2^{31}$@> <= b < @t$2^{31}$@>|.
+
+\yskip\hang|w0| 147. Set |h=h+w|; i.e., move right |w| units. With luck,
+this parameterless command will usually suffice, because the same kind of motion
+will occur several times in succession; the following commands explain how
+|w| gets particular values.
+
+\yskip\hang|w1| 148 |b[1]|. Set |w=b| and |h=h+b|. The value of |b| is a
+signed quantity in two's complement notation, |-128 <= b < 128|. This command
+changes the current |w|~spacing and moves right by |b|.
+
+\yskip\hang|@!w2| 149 |b[2]|. Same as |w1|, but |b| is two bytes long,
+|-32768 <= b < 32768|.
+
+\yskip\hang|@!w3| 150 |b[3]|. Same as |w1|, but |b| is three bytes long,
+|@t$-2^{23}$@> <= b < @t$2^{23}$@>|.
+
+\yskip\hang|@!w4| 151 |b[4]|. Same as |w1|, but |b| is four bytes long,
+|@t$-2^{31}$@> <= b < @t$2^{31}$@>|.
+
+\yskip\hang|x0| 152. Set |h=h+x|; i.e., move right |x| units. The `|x|'
+commands are like the `|w|' commands except that they involve |x| instead
+of |w|.
+
+\yskip\hang|x1| 153 |b[1]|. Set |x=b| and |h=h+b|. The value of |b| is a
+signed quantity in two's complement notation, |-128 <= b < 128|. This command
+changes the current |x|~spacing and moves right by |b|.
+
+\yskip\hang|@!x2| 154 |b[2]|. Same as |x1|, but |b| is two bytes long,
+|-32768 <= b < 32768|.
+
+\yskip\hang|@!x3| 155 |b[3]|. Same as |x1|, but |b| is three bytes long,
+|@t$-2^{23}$@> <= b < @t$2^{23}$@>|.
+
+\yskip\hang|@!x4| 156 |b[4]|. Same as |x1|, but |b| is four bytes long,
+|@t$-2^{31}$@> <= b < @t$2^{31}$@>|.
+
+\yskip\hang|down1| 157 |a[1]|. Set |v=v+a|, i.e., move down |a| units.
+The parameter is a signed number in two's complement notation, |-128 <= a < 128|;
+if |a < 0|, the reference point moves up.
+
+\yskip\hang|@!down2| 158 |a[2]|. Same as |down1|, except that |a| is a
+two-byte quantity in the range |-32768 <= a < 32768|.
+
+\yskip\hang|@!down3| 159 |a[3]|. Same as |down1|, except that |a| is a
+three-byte quantity in the range |@t$-2^{23}$@> <= a < @t$2^{23}$@>|.
+
+\yskip\hang|@!down4| 160 |a[4]|. Same as |down1|, except that |a| is a
+four-byte quantity in the range |@t$-2^{31}$@> <= a < @t$2^{31}$@>|.
+
+\yskip\hang|y0| 161. Set |v=v+y|; i.e., move down |y| units. With luck,
+this parameterless command will usually suffice, because the same kind of motion
+will occur several times in succession; the following commands explain how
+|y| gets particular values.
+
+\yskip\hang|y1| 162 |a[1]|. Set |y=a| and |v=v+a|. The value of |a| is a
+signed quantity in two's complement notation, |-128 <= a < 128|. This command
+changes the current |y|~spacing and moves down by |a|.
+
+\yskip\hang|@!y2| 163 |a[2]|. Same as |y1|, but |a| is two bytes long,
+|-32768 <= a < 32768|.
+
+\yskip\hang|@!y3| 164 |a[3]|. Same as |y1|, but |a| is three bytes long,
+|@t$-2^{23}$@> <= a < @t$2^{23}$@>|.
+
+\yskip\hang|@!y4| 165 |a[4]|. Same as |y1|, but |a| is four bytes long,
+|@t$-2^{31}$@> <= a < @t$2^{31}$@>|.
+
+\yskip\hang|z0| 166. Set |v=v+z|; i.e., move down |z| units. The `|z|' commands
+are like the `|y|' commands except that they involve |z| instead of |y|.
+
+\yskip\hang|z1| 167 |a[1]|. Set |z=a| and |v=v+a|. The value of |a| is a
+signed quantity in two's complement notation, |-128 <= a < 128|. This command
+changes the current |z|~spacing and moves down by |a|.
+
+\yskip\hang|@!z2| 168 |a[2]|. Same as |z1|, but |a| is two bytes long,
+|-32768 <= a < 32768|.
+
+\yskip\hang|@!z3| 169 |a[3]|. Same as |z1|, but |a| is three bytes long,
+|@t$-2^{23}$@> <= a < @t$2^{23}$@>|.
+
+\yskip\hang|@!z4| 170 |a[4]|. Same as |z1|, but |a| is four bytes long,
+|@t$-2^{31}$@> <= a < @t$2^{31}$@>|.
+
+\yskip\hang|fnt_num_0| 171. Set |f=0|. Font 0 must previously have been
+defined by a \\{fnt\_def} instruction, as explained below.
+
+\yskip\hang\\{fnt\_num\_1} through \\{fnt\_num\_63} (opcodes 172 to 234). Set
+|f=1|, \dots, \hbox{|f=63|}, respectively.
+
+\yskip\hang|fnt1| 235 |k[1]|. Set |f=k|. \TeX82 uses this command for font
+numbers in the range |64 <= k < 256|.
+
+\yskip\hang|@!fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two
+bytes long, so it is in the range |0 <= k < 65536|. \TeX82 never generates this
+command, but large font numbers may prove useful for specifications of
+color or texture, or they may be used for special fonts that have fixed
+numbers in some external coding scheme.
+
+\yskip\hang|@!fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three
+bytes long, so it can be as large as $2^{24}-1$.
+
+\yskip\hang|@!fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four
+bytes long; this is for the really big font numbers (and for the negative ones).
+
+\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
+general; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading
+programs are being used. \TeX82 generates |xxx1| when a short enough
+\.{\\special} appears, setting |k| to the number of bytes being sent. It
+is recommended that |x| be a string having the form of a keyword followed
+by possible parameters relevant to that keyword.
+
+\yskip\hang|@!xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0 <= k < 65536|.
+
+\yskip\hang|@!xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0 <= k < @t$2^{24}$@>|.
+
+\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously
+large. \TeX82 uses |xxx4| when sending a string of length 256 or more.
+
+\yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0 <= k < 256|; font definitions will be explained shortly.
+
+\yskip\hang|@!fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0 <= k < 65536|.
+
+\yskip\hang|@!fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0 <= k < @t$2^{24}$@>|.
+
+\yskip\hang|@!fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |@t$-2^{31}$@> <= k < @t$2^{31}$@>|.
+
+\yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
+Beginning of the preamble; this must come at the very beginning of the
+file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.
+
+\yskip\hang|post| 248. Beginning of the postamble, see below.
+
+\yskip\hang|post_post| 249. Ending of the postamble, see below.
+
+\yskip\noindent Commands 250--255 are undefined at the present time.
+
+@ @d set_char_0 0 /*typeset character 0 and move right*/
+@d set1 128 /*typeset a character and move right*/
+@d set_rule 132 /*typeset a rule and move right*/
+@d put_rule 137 /*typeset a rule*/
+@d nop 138 /*no operation*/
+@d bop 139 /*beginning of page*/
+@d eop 140 /*ending of page*/
+@d push 141 /*save the current positions*/
+@d pop 142 /*restore previous positions*/
+@d right1 143 /*move right*/
+@d w0 147 /*move right by |w|*/
+@d w1 148 /*move right and set |w|*/
+@d x0 152 /*move right by |x|*/
+@d x1 153 /*move right and set |x|*/
+@d down1 157 /*move down*/
+@d y0 161 /*move down by |y|*/
+@d y1 162 /*move down and set |y|*/
+@d z0 166 /*move down by |z|*/
+@d z1 167 /*move down and set |z|*/
+@d fnt_num_0 171 /*set current font to 0*/
+@d fnt1 235 /*set current font*/
+@d xxx1 239 /*extension to \.{DVI} primitives*/
+@d xxx4 242 /*potentially long extension to \.{DVI} primitives*/
+@d fnt_def1 243 /*define the meaning of a font number*/
+@d pre 247 /*preamble*/
+@d post 248 /*postamble beginning*/
+@d post_post 249 /*postamble ending*/
+
+@ The preamble contains basic information about the file as a whole. As
+stated above, there are six parameters:
+$$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
+The |i| byte identifies \.{DVI} format; currently this byte is always set
+to~2. (The value |i==3| is currently used for an extended format that
+allows a mixture of right-to-left and left-to-right typesetting.
+Some day we will set |i==4|, when \.{DVI} format makes another
+incompatible change---perhaps in the year 2048.)
+
+The next two parameters, |num| and |den|, are positive integers that define
+the units of measurement; they are the numerator and denominator of a
+fraction by which all dimensions in the \.{DVI} file could be multiplied
+in order to get lengths in units of $10^{-7}$ meters. Since $\rm 7227{pt} =
+254{cm}$, and since \TeX\ works with scaled points where there are $2^{16}$
+sp in a point, \TeX\ sets
+$|num|/|den|=(254\cdot10^5)/(7227\cdot2^{16})=25400000/473628672$.
+@^sp@>
+
+The |mag| parameter is what \TeX\ calls \.{\\mag}, i.e., 1000 times the
+desired magnification. The actual fraction by which dimensions are
+multiplied is therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\
+source document does not call for any `\.{true}' dimensions, and if you
+change it only by specifying a different \.{\\mag} setting, the \.{DVI}
+file that \TeX\ creates will be completely unchanged except for the value
+of |mag| in the preamble and postamble. (Fancy \.{DVI}-reading programs allow
+users to override the |mag|~setting when a \.{DVI} file is being printed.)
+
+Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
+interpreted further. The length of comment |x| is |k|, where |0 <= k < 256|.
+
+@d id_byte 2 /*identifies the kind of \.{DVI} files described here*/
+
+@ Font definitions for a given font number |k| contain further parameters
+$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$
+The four-byte value |c| is the check sum that \TeX\ found in the \.{TFM}
+file for this font; |c| should match the check sum of the font found by
+programs that read this \.{DVI} file.
+@^check sum@>
+
+Parameter |s| contains a fixed-point scale factor that is applied to
+the character widths in font |k|; font dimensions in \.{TFM} files and
+other font files are relative to this quantity, which is called the
+``at size'' elsewhere in this documentation. The value of |s| is
+always positive and less than $2^{27}$. It is given in the same units
+as the other \.{DVI} dimensions, i.e., in sp when \TeX82 has made the
+file. Parameter |d| is similar to |s|; it is the ``design size,'' and
+(like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be used
+at $|mag|\cdot s/1000d$ times its normal size.
+
+The remaining part of a font definition gives the external name of the font,
+which is an ASCII string of length |a+l|. The number |a| is the length
+of the ``area'' or directory, and |l| is the length of the font name itself;
+the standard local system font area is supposed to be used when |a==0|.
+The |n| field contains the area in its first |a| bytes.
+
+Font definitions must appear before the first use of a particular font number.
+Once font |k| is defined, it must not be defined again; however, we
+shall see below that font definitions appear in the postamble as well as
+in the pages, so in this sense each font number is defined exactly twice,
+if at all. Like |nop| commands, font definitions can
+appear before the first |bop|, or between an |eop| and a |bop|.
+
+@ Sometimes it is desirable to make horizontal or vertical rules line up
+precisely with certain features in characters of a font. It is possible to
+guarantee the correct matching between \.{DVI} output and the characters
+generated by \MF\ by adhering to the following principles: (1)~The \MF\
+characters should be positioned so that a bottom edge or left edge that is
+supposed to line up with the bottom or left edge of a rule appears at the
+reference point, i.e., in row~0 and column~0 of the \MF\ raster. This
+ensures that the position of the rule will not be rounded differently when
+the pixel size is not a perfect multiple of the units of measurement in
+the \.{DVI} file. (2)~A typeset rule of height $a>0$ and width $b>0$
+should be equivalent to a \MF-generated character having black pixels in
+precisely those raster positions whose \MF\ coordinates satisfy
+|0 <= x < @t$\alpha$@>b| and |0 <= y < @t$\alpha$@>a|, where $\alpha$ is the number
+of pixels per \.{DVI} unit.
+@:METAFONT}{\MF@>
+@^alignment of rules with characters@>
+@^rules aligning with characters@>
+
+@ The last page in a \.{DVI} file is followed by `|post|'; this command
+introduces the postamble, which summarizes important facts that \TeX\ has
+accumulated about the file, making it possible to print subsets of the data
+with reasonable efficiency. The postamble has the form
+$$\vbox{\halign{\hbox{#\hfil}\cr
+ |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
+ $\langle\,$font definitions$\,\rangle$\cr
+ |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
+Here |p| is a pointer to the final |bop| in the file. The next three
+parameters, |num|, |den|, and |mag|, are duplicates of the quantities that
+appeared in the preamble.
+
+Parameters |l| and |u| give respectively the height-plus-depth of the tallest
+page and the width of the widest page, in the same units as other dimensions
+of the file. These numbers might be used by a \.{DVI}-reading program to
+position individual ``pages'' on large sheets of film or paper; however,
+the standard convention for output on normal size paper is to position each
+page so that the upper left-hand corner is exactly one inch from the left
+and the top. Experience has shown that it is unwise to design \.{DVI}-to-printer
+software that attempts cleverly to center the output; a fixed position of
+the upper left corner is easiest for users to understand and to work with.
+Therefore |l| and~|u| are often ignored.
+
+Parameter |s| is the maximum stack depth (i.e., the largest excess of
+|push| commands over |pop| commands) needed to process this file. Then
+comes |t|, the total number of pages (|bop| commands) present.
+
+The postamble continues with font definitions, which are any number of
+\\{fnt\_def} commands as described above, possibly interspersed with |nop|
+commands. Each font number that is used in the \.{DVI} file must be defined
+exactly twice: Once before it is first selected by a \\{fnt} command, and once
+in the postamble.
+
+@ The last part of the postamble, following the |post_post| byte that
+signifies the end of the font definitions, contains |q|, a pointer to the
+|post| command that started the postamble. An identification byte, |i|,
+comes next; this 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.
+@^Fuchs, David Raymond@>
+
+This curious way to finish off a \.{DVI} file makes it feasible for
+\.{DVI}-reading programs to find the postamble first, on most computers,
+even though \TeX\ wants to write the postamble last. Most operating
+systems permit random access to individual words or bytes of a file, so
+the \.{DVI} reader can start at the end and skip backwards over the 223's
+until finding the identification byte. Then it can back up four bytes, read
+|q|, and move to byte |q| of the file. This byte should, of course,
+contain the value 248 (|post|); now the postamble can be read, so the
+\.{DVI} reader can discover all the information needed for typesetting the
+pages. Note that it is also possible to skip through the \.{DVI} file at
+reasonably high speed to locate a particular page, if that proves
+desirable. This saves a lot of time, since \.{DVI} files used in production
+jobs tend to be large.
+
+Unfortunately, however, standard \PASCAL\ does not include the ability to
+@^system dependencies@>
+access a random position in a file, or even to determine the length of a file.
+Almost all systems nowadays provide the necessary capabilities, so \.{DVI}
+format has been designed to work most efficiently with modern operating systems.
+But if \.{DVI} files have to be processed under the restrictions of standard
+\PASCAL, one can simply read them from front to back, since the necessary
+header information is present in the preamble and in the font definitions.
+(The |l| and |u| and |s| and |t| parameters, which appear only in the
+postamble, are ``frills'' that are handy but not absolutely necessary.)
+
+@* Shipping pages out.
+After considering \TeX's eyes and stomach, we come now to the bowels.
+@^bowels@>
+
+The |ship_out| procedure is given a pointer to a box; its mission is
+to describe that box in \.{DVI} form, outputting a ``page'' to |dvi_file|.
+The \.{DVI} coordinates $(h,v)=(0,0)$ should correspond to the upper left
+corner of the box being shipped.
+
+Since boxes can be inside of boxes inside of boxes, the main work of
+|ship_out| is done by two mutually recursive routines, |hlist_out|
+and |vlist_out|, which traverse the hlists and vlists inside of horizontal
+and vertical boxes.
+
+As individual pages are being processed, we need to accumulate
+information about the entire set of pages, since such statistics must be
+reported in the postamble. The global variables |total_pages|, |max_v|,
+|max_h|, |max_push|, and |last_bop| are used to record this information.
+
+The variable |doing_leaders| is |true| while leaders are being output.
+The variable |dead_cycles| contains the number of times an output routine
+has been initiated since the last |ship_out|.
+
+A few additional global variables are also defined here for use in
+|vlist_out| and |hlist_out|. They could have been local variables, but
+that would waste stack space when boxes are deeply nested, since the
+values of these variables are not needed during recursive calls.
+@^recursion@>
+
+@<Glob...@>=
+int @!total_pages; /*the number of pages that have been shipped out*/
+scaled @!max_v; /*maximum height-plus-depth of pages shipped so far*/
+scaled @!max_h; /*maximum width of pages shipped so far*/
+int @!max_push; /*deepest nesting of |push| commands encountered so far*/
+int @!last_bop; /*location of previous |bop| in the \.{DVI} output*/
+int @!dead_cycles; /*recent outputs that didn't ship anything out*/
+bool @!doing_leaders; /*are we inside a leader box?*/
+@#
+quarterword @!c, @!f; /*character and font in current |char_node|*/
+scaled @!rule_ht, @!rule_dp, @!rule_wd; /*size of current rule being output*/
+pointer @!g; /*current glue specification*/
+int @!lq, @!lr; /*quantities used in calculations for leaders*/
+
+@ @<Set init...@>=
+total_pages=0;max_v=0;max_h=0;max_push=0;last_bop=-1;
+doing_leaders=false;dead_cycles=0;cur_s=-1;
+
+@ The \.{DVI} bytes are output to a buffer instead of being written directly
+to the output file. This makes it possible to reduce the overhead of
+subroutine calls, thereby measurably speeding up the computation, since
+output of \.{DVI} bytes is part of \TeX's inner loop. And it has another
+advantage as well, since we can change instructions in the buffer in order to
+make the output more compact. For example, a `|down2|' command can be
+changed to a `|y2|', thereby making a subsequent `|y0|' command possible,
+saving two bytes.
+
+The output buffer is divided into two parts of equal size; the bytes found
+in |dvi_buf[0 dotdot half_buf-1]| constitute the first half, and those in
+|dvi_buf[half_buf dotdot dvi_buf_size-1]| constitute the second. The global
+variable |dvi_ptr| points to the position that will receive the next
+output byte. When |dvi_ptr| reaches |dvi_limit|, which is always equal
+to one of the two values |half_buf| or |dvi_buf_size|, the half buffer that
+is about to be invaded next is sent to the output and |dvi_limit| is
+changed to its other value. Thus, there is always at least a half buffer's
+worth of information present, except at the very beginning of the job.
+
+Bytes of the \.{DVI} file are numbered sequentially starting with 0;
+the next byte to be generated will be number |dvi_offset+dvi_ptr|.
+A byte is present in the buffer only if its number is | >= dvi_gone|.
+
+@<Types...@>=
+typedef uint16_t dvi_index; /*an index into the output buffer*/
+
+@ Some systems may find it more efficient to make |dvi_buf| a ||
+array, since output of four bytes at once may be facilitated.
+@^system dependencies@>
+
+@<Glob...@>=
+eight_bits @!dvi_buf[dvi_buf_size+1]; /*buffer for \.{DVI} output*/
+dvi_index @!half_buf; /*half of |dvi_buf_size|*/
+dvi_index @!dvi_limit; /*end of the current half buffer*/
+dvi_index @!dvi_ptr; /*the next available buffer address*/
+int @!dvi_offset; /*|dvi_buf_size| times the number of times the
+ output buffer has been fully emptied*/
+int @!dvi_gone; /*the number of bytes already output to |dvi_file|*/
+
+@ Initially the buffer is all in one piece; we will output half of it only
+after it first fills up.
+
+@<Set init...@>=
+half_buf=dvi_buf_size/2;dvi_limit=dvi_buf_size;dvi_ptr=0;
+dvi_offset=0;dvi_gone=0;
+
+@ 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+1| will both be
+multiples of 4 when |write_dvi(a, b)| is called; therefore it is possible on
+many machines to use efficient methods to pack four bytes per word and to
+output an array of words with one system call.
+@^system dependencies@>
+@^inner loop@>
+@^defecation@>
+
+@p void write_dvi(dvi_index @!a, dvi_index @!b)
+{@+int k;
+for (k=a; k<=b; k++) write(dvi_file, "%c", dvi_buf[k]);
+}
+
+@ To put a byte in the buffer without paying the cost of invoking a procedure
+each time, we use the macro |dvi_out|.
+
+@d dvi_out(X) @+{@+dvi_buf[dvi_ptr]=X;incr(dvi_ptr);
+ if (dvi_ptr==dvi_limit) dvi_swap();
+ }
+
+@p void dvi_swap(void) /*outputs half of the buffer*/
+{@+if (dvi_limit==dvi_buf_size)
+ {@+write_dvi(0, half_buf-1);dvi_limit=half_buf;
+ dvi_offset=dvi_offset+dvi_buf_size;dvi_ptr=0;
+ }
+else{@+write_dvi(half_buf, dvi_buf_size-1);dvi_limit=dvi_buf_size;
+ }
+dvi_gone=dvi_gone+half_buf;
+}
+
+@ Here is how we clean out the buffer when \TeX\ is all through; |dvi_ptr|
+will be a multiple of~4.
+
+@<Empty the last bytes out of |dvi_buf|@>=
+if (dvi_limit==half_buf) write_dvi(half_buf, dvi_buf_size-1);
+if (dvi_ptr > 0) write_dvi(0, dvi_ptr-1)
+
+@ The |dvi_four| procedure outputs four bytes in two's complement notation,
+without risking arithmetic overflow.
+
+@p void dvi_four(int @!x)
+{@+if (x >= 0) dvi_out(x/0100000000)@;
+else{@+x=x+010000000000;
+ x=x+010000000000;
+ dvi_out((x/0100000000)+128);
+ }
+x=x%0100000000;dvi_out(x/0200000);
+x=x%0200000;dvi_out(x/0400);
+dvi_out(x%0400);
+}
+
+@ A mild optimization of the output is performed by the |dvi_pop|
+routine, which issues a |pop| unless it is possible to cancel a
+`|push| |pop|' pair. The parameter to |dvi_pop| is the byte address
+following the old |push| that matches the new |pop|.
+
+@p void dvi_pop(int @!l)
+{@+if ((l==dvi_offset+dvi_ptr)&&(dvi_ptr > 0)) decr(dvi_ptr);
+else dvi_out(pop);
+}
+
+@ Here's a procedure that outputs a font definition. Since \TeX82 uses at
+most 256 different fonts per job, |fnt_def1| is always used as the command code.
+
+@p void dvi_font_def(internal_font_number @!f)
+{@+int k; /*index into |str_pool|*/
+dvi_out(fnt_def1);
+dvi_out(f-font_base-1);@/
+dvi_out(qo(font_check[f].b0));
+dvi_out(qo(font_check[f].b1));
+dvi_out(qo(font_check[f].b2));
+dvi_out(qo(font_check[f].b3));@/
+dvi_four(font_size[f]);
+dvi_four(font_dsize[f]);@/
+dvi_out(length(font_area[f]));
+dvi_out(length(font_name[f]));
+@<Output the font name whose internal number is |f|@>;
+}
+
+@ @<Output the font name whose internal number is |f|@>=
+for (k=str_start[font_area[f]]; k<=str_start[font_area[f]+1]-1; k++)
+ dvi_out(so(str_pool[k]));
+for (k=str_start[font_name[f]]; k<=str_start[font_name[f]+1]-1; k++)
+ dvi_out(so(str_pool[k]))
+
+@ Versions of \TeX\ intended for small computers might well choose to omit
+the ideas in the next few parts of this program, since it is not really
+necessary to optimize the \.{DVI} code by making use of the |w0|, |x0|,
+|y0|, and |z0| commands. Furthermore, the algorithm that we are about to
+describe does not pretend to give an optimum reduction in the length
+of the \.{DVI} code; after all, speed is more important than compactness.
+But the method is surprisingly effective, and it takes comparatively little
+time.
+
+We can best understand the basic idea by first considering a simpler problem
+that has the same essential characteristics. Given a sequence of digits,
+say $3\,1\,4\,1\,5\,9\,2\,6\,5\,3\,5\,8\,9$, we want to assign subscripts
+$d$, $y$, or $z$ to each digit so as to maximize the number of ``$y$-hits''
+and ``$z$-hits''; a $y$-hit is an instance of two appearances of the same
+digit with the subscript $y$, where no $y$'s intervene between the two
+appearances, and a $z$-hit is defined similarly. For example, the sequence
+above could be decorated with subscripts as follows:
+$$3_z\,1_y\,4_d\,1_y\,5_y\,9_d\,2_d\,6_d\,5_y\,3_z\,5_y\,8_d\,9_d.$$
+There are three $y$-hits ($1_y\ldots1_y$ and $5_y\ldots5_y\ldots5_y$) and
+one $z$-hit ($3_z\ldots3_z$); there are no $d$-hits, since the two appearances
+of $9_d$ have $d$'s between them, but we don't count $d$-hits so it doesn't
+matter how many there are. These subscripts are analogous to the \.{DVI}
+commands called \\{down}, $y$, and $z$, and the digits are analogous to
+different amounts of vertical motion; a $y$-hit or $z$-hit corresponds to
+the opportunity to use the one-byte commands |y0| or |z0| in a \.{DVI} file.
+
+\TeX's method of assigning subscripts works like this: Append a new digit,
+say $\delta$, to the right of the sequence. Now look back through the
+sequence until one of the following things happens: (a)~You see
+$\delta_y$ or $\delta_z$, and this was the first time you encountered a
+$y$ or $z$ subscript, respectively. Then assign $y$ or $z$ to the new
+$\delta$; you have scored a hit. (b)~You see $\delta_d$, and no $y$
+subscripts have been encountered so far during this search. Then change
+the previous $\delta_d$ to $\delta_y$ (this corresponds to changing a
+command in the output buffer), and assign $y$ to the new $\delta$; it's
+another hit. (c)~You see $\delta_d$, and a $y$ subscript has been seen
+but not a $z$. Change the previous $\delta_d$ to $\delta_z$ and assign
+$z$ to the new $\delta$. (d)~You encounter both $y$ and $z$ subscripts
+before encountering a suitable $\delta$, or you scan all the way to the
+front of the sequence. Assign $d$ to the new $\delta$; this assignment may
+be changed later.
+
+The subscripts $3_z\,1_y\,4_d\ldots\,$ in the example above were, in fact,
+produced by this procedure, as the reader can verify. (Go ahead and try it.)
+
+@ In order to implement such an idea, \TeX\ maintains a stack of pointers
+to the \\{down}, $y$, and $z$ commands that have been generated for the
+current page. And there is a similar stack for \\{right}, |w|, and |x|
+commands. These stacks are called the down stack and right stack, and their
+top elements are maintained in the variables |down_ptr| and |right_ptr|.
+
+Each entry in these stacks contains four fields: The |width| field is
+the amount of motion down or to the right; the |location| field is the
+byte number of the \.{DVI} command in question (including the appropriate
+|dvi_offset|); the |link| field points to the next item below this one
+on the stack; and the |info| field encodes the options for possible change
+in the \.{DVI} command.
+
+@d movement_node_size 3 /*number of words per entry in the down and right stacks*/
+@d location(X) mem[X+2].i /*\.{DVI} byte number for a movement command*/
+
+@<Glob...@>=
+pointer @!down_ptr, @!right_ptr; /*heads of the down and right stacks*/
+
+@ @<Set init...@>=
+down_ptr=null;right_ptr=null;
+
+@ Here is a subroutine that produces a \.{DVI} command for some specified
+downward or rightward motion. It has two parameters: |w| is the amount
+of motion, and |o| is either |down1| or |right1|. We use the fact that
+the command codes have convenient arithmetic properties: |y1-down1==w1-right1|
+and |z1-down1==x1-right1|.
+
+@p void movement(scaled @!w, eight_bits @!o)
+{@+
+small_number mstate; /*have we seen a |y| or |z|?*/
+pointer @!p, @!q; /*current and top nodes on the stack*/
+int @!k; /*index into |dvi_buf|, modulo |dvi_buf_size|*/
+q=get_node(movement_node_size); /*new node for the top of the stack*/
+width(q)=w;location(q)=dvi_offset+dvi_ptr;
+if (o==down1)
+ {@+link(q)=down_ptr;down_ptr=q;
+ }
+else{@+link(q)=right_ptr;right_ptr=q;
+ }
+@<Look at the other stack entries until deciding what sort of \.{DVI} command to generate;
+|goto found| if node |p| is a ``hit''@>;
+@<Generate a |down| or |right| command for |w| and |return|@>;
+found: @<Generate a |y0| or |z0| command in order to reuse a previous appearance of~|w|@>;
+}
+
+@ The |info| fields in the entries of the down stack or the right stack
+have six possible settings: |y_here| or |z_here| mean that the \.{DVI}
+command refers to |y| or |z|, respectively (or to |w| or |x|, in the
+case of horizontal motion); |yz_OK| means that the \.{DVI} command is
+\\{down} (or \\{right}) but can be changed to either |y| or |z| (or
+to either |w| or |x|); |y_OK| means that it is \\{down} and can be changed
+to |y| but not |z|; |z_OK| is similar; and |d_fixed| means it must stay
+\\{down}.
+
+The four settings |yz_OK|, |y_OK|, |z_OK|, |d_fixed| would not need to
+be distinguished from each other if we were simply solving the
+digit-subscripting problem mentioned above. But in \TeX's case there is
+a complication because of the nested structure of |push| and |pop|
+commands. Suppose we add parentheses to the digit-subscripting problem,
+redefining hits so that $\delta_y\ldots \delta_y$ is a hit if all $y$'s between
+the $\delta$'s are enclosed in properly nested parentheses, and if the
+parenthesis level of the right-hand $\delta_y$ is deeper than or equal to
+that of the left-hand one. Thus, `(' and `)' correspond to `|push|'
+and `|pop|'. Now if we want to assign a subscript to the final 1 in the
+sequence
+$$2_y\,7_d\,1_d\,(\,8_z\,2_y\,8_z\,)\,1$$
+we cannot change the previous $1_d$ to $1_y$, since that would invalidate
+the $2_y\ldots2_y$ hit. But we can change it to $1_z$, scoring a hit
+since the intervening $8_z$'s are enclosed in parentheses.
+
+The program below removes movement nodes that are introduced after a |push|,
+before it outputs the corresponding |pop|.
+
+@d y_here 1 /*|info| when the movement entry points to a |y| command*/
+@d z_here 2 /*|info| when the movement entry points to a |z| command*/
+@d yz_OK 3 /*|info| corresponding to an unconstrained \\{down} command*/
+@d y_OK 4 /*|info| corresponding to a \\{down} that can't become a |z|*/
+@d z_OK 5 /*|info| corresponding to a \\{down} that can't become a |y|*/
+@d d_fixed 6 /*|info| corresponding to a \\{down} that can't change*/
+
+@ When the |movement| procedure gets to the label |found|, the value of
+|info(p)| will be either |y_here| or |z_here|. If it is, say, |y_here|,
+the procedure generates a |y0| command (or a |w0| command), and marks
+all |info| fields between |q| and |p| so that |y| is not OK in that range.
+
+@<Generate a |y0| or |z0| command...@>=
+info(q)=info(p);
+if (info(q)==y_here)
+ {@+dvi_out(o+y0-down1); /*|y0| or |w0|*/
+ while (link(q)!=p)
+ {@+q=link(q);
+ switch (info(q)) {
+ case yz_OK: info(q)=z_OK;@+break;
+ case y_OK: info(q)=d_fixed;@+break;
+ default:do_nothing;
+ }
+ }
+ }
+else{@+dvi_out(o+z0-down1); /*|z0| or |x0|*/
+ while (link(q)!=p)
+ {@+q=link(q);
+ switch (info(q)) {
+ case yz_OK: info(q)=y_OK;@+break;
+ case z_OK: info(q)=d_fixed;@+break;
+ default:do_nothing;
+ }
+ }
+ }
+
+@ @<Generate a |down| or |right|...@>=
+info(q)=yz_OK;
+if (abs(w) >= 040000000)
+ {@+dvi_out(o+3); /*|down4| or |right4|*/
+ dvi_four(w);return;
+ }
+if (abs(w) >= 0100000)
+ {@+dvi_out(o+2); /*|down3| or |right3|*/
+ if (w < 0) w=w+0100000000;
+ dvi_out(w/0200000);w=w%0200000;goto label2;
+ }
+if (abs(w) >= 0200)
+ {@+dvi_out(o+1); /*|down2| or |right2|*/
+ if (w < 0) w=w+0200000;
+ goto label2;
+ }
+dvi_out(o); /*|down1| or |right1|*/
+if (w < 0) w=w+0400;
+goto label1;
+label2: dvi_out(w/0400);
+label1: dvi_out(w%0400);return
+
+@ As we search through the stack, we are in one of three states,
+|y_seen|, |z_seen|, or |none_seen|, depending on whether we have
+encountered |y_here| or |z_here| nodes. These states are encoded as
+multiples of 6, so that they can be added to the |info| fields for quick
+decision-making.
+@^inner loop@>
+
+@d none_seen 0 /*no |y_here| or |z_here| nodes have been encountered yet*/
+@d y_seen 6 /*we have seen |y_here| but not |z_here|*/
+@d z_seen 12 /*we have seen |z_here| but not |y_here|*/
+
+@<Look at the other stack entries until deciding...@>=
+p=link(q);mstate=none_seen;
+while (p!=null)
+ {@+if (width(p)==w) @<Consider a node with matching width; |goto found| if it's
+a hit@>@;
+ else switch (mstate+info(p)) {
+ case none_seen+y_here: mstate=y_seen;@+break;
+ case none_seen+z_here: mstate=z_seen;@+break;
+ case y_seen+z_here: case z_seen+y_here: goto not_found;
+ default:do_nothing;
+ }
+ p=link(p);
+ }
+not_found:
+
+@ We might find a valid hit in a |y| or |z| byte that is already gone
+from the buffer. But we can't change bytes that are gone forever; ``the
+moving finger writes, $\ldots\,\,$.''
+
+@<Consider a node with matching width...@>=
+switch (mstate+info(p)) {
+case none_seen+yz_OK: case none_seen+y_OK: case z_seen+yz_OK: case z_seen+y_OK: @t@>@;@/
+ if (location(p) < dvi_gone) goto not_found;
+ else@<Change buffered instruction to |y| or |w| and |goto found|@>@;@+break;
+case none_seen+z_OK: case y_seen+yz_OK: case y_seen+z_OK: @t@>@;@/
+ if (location(p) < dvi_gone) goto not_found;
+ else@<Change buffered instruction to |z| or |x| and |goto found|@>@;@+break;
+case none_seen+y_here: case none_seen+z_here: case y_seen+z_here: case z_seen+y_here: goto found;
+default:do_nothing;
+}
+
+@ @<Change buffered instruction to |y| or |w| and |goto found|@>=
+{@+k=location(p)-dvi_offset;
+if (k < 0) k=k+dvi_buf_size;
+dvi_buf[k]=dvi_buf[k]+y1-down1;
+info(p)=y_here;goto found;
+}
+
+@ @<Change buffered instruction to |z| or |x| and |goto found|@>=
+{@+k=location(p)-dvi_offset;
+if (k < 0) k=k+dvi_buf_size;
+dvi_buf[k]=dvi_buf[k]+z1-down1;
+info(p)=z_here;goto found;
+}
+
+@ In case you are wondering when all the movement nodes are removed from
+\TeX's memory, the answer is that they are recycled just before
+|hlist_out| and |vlist_out| finish outputting a box. This restores the
+down and right stacks to the state they were in before the box was output,
+except that some |info|'s may have become more restrictive.
+
+@p void prune_movements(int @!l)
+ /*delete movement nodes with |location >= l|*/
+{@+
+pointer p; /*node being deleted*/
+while (down_ptr!=null)
+ {@+if (location(down_ptr) < l) goto done;
+ p=down_ptr;down_ptr=link(p);free_node(p, movement_node_size);
+ }
+done: while (right_ptr!=null)
+ {@+if (location(right_ptr) < l) return;
+ p=right_ptr;right_ptr=link(p);free_node(p, movement_node_size);
+ }
+}
+
+@ The actual distances by which we want to move might be computed as the
+sum of several separate movements. For example, there might be several
+glue nodes in succession, or we might want to move right by the width of
+some box plus some amount of glue. More importantly, the baselineskip
+distances are computed in terms of glue together with the depth and
+height of adjacent boxes, and we want the \.{DVI} file to lump these
+three quantities together into a single motion.
+
+Therefore, \TeX\ maintains two pairs of global variables: |dvi_h| and |dvi_v|
+are the |h| and |v| coordinates corresponding to the commands actually
+output to the \.{DVI} file, while |cur_h| and |cur_v| are the coordinates
+corresponding to the current state of the output routines. Coordinate
+changes will accumulate in |cur_h| and |cur_v| without being reflected
+in the output, until such a change becomes necessary or desirable; we
+can call the |movement| procedure whenever we want to make |dvi_h==cur_h|
+or |dvi_v==cur_v|.
+
+The current font reflected in the \.{DVI} output is called |dvi_f|;
+there is no need for a `\\{cur\_f}' variable.
+
+The depth of nesting of |hlist_out| and |vlist_out| is called |cur_s|;
+this is essentially the depth of |push| commands in the \.{DVI} output.
+
+@d synch_h if (cur_h!=dvi_h)
+ {@+movement(cur_h-dvi_h, right1);dvi_h=cur_h;
+ }
+@d synch_v if (cur_v!=dvi_v)
+ {@+movement(cur_v-dvi_v, down1);dvi_v=cur_v;
+ }
+
+@<Glob...@>=
+scaled @!dvi_h, @!dvi_v; /*a \.{DVI} reader program thinks we are here*/
+scaled @!cur_h, @!cur_v; /*\TeX\ thinks we are here*/
+internal_font_number @!dvi_f; /*the current font*/
+int @!cur_s; /*current depth of output box nesting, initially $-1$*/
+
+@ @<Initialize variables as |ship_out| begins@>=
+dvi_h=0;dvi_v=0;cur_h=h_offset;dvi_f=null_font;
+@<ensure dvi open@>;
+if (total_pages==0)
+ {@+dvi_out(pre);dvi_out(id_byte); /*output the preamble*/
+@^preamble of \.{DVI} file@>
+ dvi_four(25400000);dvi_four(473628672); /*conversion ratio for sp*/
+ prepare_mag();dvi_four(mag); /*magnification factor is frozen*/
+ old_setting=selector;selector=new_string;
+ print_str(" TeX output ");print_int(year);print_char('.');
+ print_two(month);print_char('.');print_two(day);
+ print_char(':');print_two(time/60);
+ print_two(time%60);
+ selector=old_setting;dvi_out(cur_length);
+ for (s=str_start[str_ptr]; s<=pool_ptr-1; s++) dvi_out(so(str_pool[s]));
+ pool_ptr=str_start[str_ptr]; /*flush the current string*/
+ }
+
+@ When |hlist_out| is called, its duty is to output the box represented
+by the |hlist_node| pointed to by |temp_ptr|. The reference point of that
+box has coordinates |(cur_h, cur_v)|.
+
+Similarly, when |vlist_out| is called, its duty is to output the box represented
+by the |vlist_node| pointed to by |temp_ptr|. The reference point of that
+box has coordinates |(cur_h, cur_v)|.
+@^recursion@>
+
+@p void vlist_out(void); /*|hlist_out| and |vlist_out| are mutually
+ recursive*/
+
+@ The recursive procedures |hlist_out| and |vlist_out| each have local variables
+|save_h| and |save_v| to hold the values of |dvi_h| and |dvi_v| just before
+entering a new level of recursion. In effect, the values of |save_h| and
+|save_v| on \TeX's run-time stack correspond to the values of |h| and |v|
+that a \.{DVI}-reading program will push onto its coordinate stack.
+
+@p@t\4@>@<Declare procedures needed in |hlist_out|, |vlist_out|@>@t@>@/
+void hlist_out(void) /*output an |hlist_node| box*/
+{@+
+scaled base_line; /*the baseline coordinate for this box*/
+scaled @!left_edge; /*the left coordinate for this box*/
+scaled @!save_h, @!save_v; /*what |dvi_h| and |dvi_v| should pop to*/
+pointer @!this_box; /*pointer to containing box*/
+glue_ord @!g_order; /*applicable order of infinity for glue*/
+uint8_t @!g_sign; /*selects type of glue*/
+pointer @!p; /*current position in the hlist*/
+int @!save_loc; /*\.{DVI} byte location upon entry*/
+pointer @!leader_box; /*the leader box being replicated*/
+scaled @!leader_wd; /*width of leader box being replicated*/
+scaled @!lx; /*extra space between leader boxes*/
+bool @!outer_doing_leaders; /*were we doing leaders?*/
+scaled @!edge; /*left edge of sub-box, or right edge of leader space*/
+double @!glue_temp; /*glue value before rounding*/
+double @!cur_glue; /*glue seen so far*/
+scaled @!cur_g; /*rounded equivalent of |cur_glue| times the glue ratio*/
+cur_g=0;cur_glue=float_constant(0);
+this_box=temp_ptr;g_order=glue_order(this_box);
+g_sign=glue_sign(this_box);p=list_ptr(this_box);
+incr(cur_s);
+if (cur_s > 0) dvi_out(push);
+if (cur_s > max_push) max_push=cur_s;
+save_loc=dvi_offset+dvi_ptr;base_line=cur_v;left_edge=cur_h;
+while (p!=null) @<Output node |p| for |hlist_out| and move to the next node, maintaining
+the condition |cur_v=base_line|@>;
+prune_movements(save_loc);
+if (cur_s > 0) dvi_pop(save_loc);
+decr(cur_s);
+}
+
+@ We ought to give special care to the efficiency of one part of |hlist_out|,
+since it belongs to \TeX's inner loop. When a |char_node| is encountered,
+we save a little time by processing several nodes in succession until
+reaching a non-|char_node|. The program uses the fact that |set_char_0==0|.
+@^inner loop@>
+
+@<Output node |p| for |hlist_out|...@>=
+reswitch: if (is_char_node(p))
+ {@+synch_h;synch_v;
+ @/do@+{f=font(p);c=character(p);
+ if (f!=dvi_f) @<Change font |dvi_f| to |f|@>;
+ if (c >= qi(128)) dvi_out(set1);
+ dvi_out(qo(c));@/
+ cur_h=cur_h+char_width(f)(char_info(f)(c));
+ p=link(p);
+ }@+ while (!(!is_char_node(p)));
+ dvi_h=cur_h;
+ }
+else@<Output the non-|char_node| |p| for |hlist_out| and move to the next node@>@;
+
+@ @<Change font |dvi_f| to |f|@>=
+{@+if (!font_used[f])
+ {@+dvi_font_def(f);font_used[f]=true;
+ }
+if (f <= 64+font_base) dvi_out(f-font_base-1+fnt_num_0)@;
+else{@+dvi_out(fnt1);dvi_out(f-font_base-1);
+ }
+dvi_f=f;
+}
+
+@ @<Output the non-|char_node| |p| for |hlist_out|...@>=
+{@+switch (type(p)) {
+case hlist_node: case vlist_node: @<Output a box in an hlist@>@;@+break;
+case rule_node: {@+rule_ht=height(p);rule_dp=depth(p);rule_wd=width(p);
+ goto fin_rule;
+ }
+case whatsit_node: @<Output the whatsit node |p| in an hlist@>;@+break;
+case glue_node: @<Move right or output leaders@>@;
+case kern_node: case math_node: cur_h=cur_h+width(p);@+break;
+case ligature_node: @<Make node |p| look like a |char_node| and |goto reswitch|@>@;
+default:do_nothing;
+} @/
+goto next_p;
+fin_rule: @<Output a rule in an hlist@>;
+move_past: cur_h=cur_h+rule_wd;
+next_p: p=link(p);
+}
+
+@ @<Output a box in an hlist@>=
+if (list_ptr(p)==null) cur_h=cur_h+width(p);
+else{@+save_h=dvi_h;save_v=dvi_v;
+ cur_v=base_line+shift_amount(p); /*shift the box down*/
+ temp_ptr=p;edge=cur_h;
+ if (type(p)==vlist_node) vlist_out();@+else hlist_out();
+ dvi_h=save_h;dvi_v=save_v;
+ cur_h=edge+width(p);cur_v=base_line;
+ }
+
+@ @<Output a rule in an hlist@>=
+if (is_running(rule_ht)) rule_ht=height(this_box);
+if (is_running(rule_dp)) rule_dp=depth(this_box);
+rule_ht=rule_ht+rule_dp; /*this is the rule thickness*/
+if ((rule_ht > 0)&&(rule_wd > 0)) /*we don't output empty rules*/
+ {@+synch_h;cur_v=base_line+rule_dp;synch_v;
+ dvi_out(set_rule);dvi_four(rule_ht);dvi_four(rule_wd);
+ cur_v=base_line;dvi_h=dvi_h+rule_wd;
+ }
+
+@ @d billion float_constant(1000000000)
+@d vet_glue(X) glue_temp=X;
+ if (glue_temp > billion)
+ glue_temp=billion;
+ else if (glue_temp < -billion)
+ glue_temp=-billion
+
+@<Move right or output leaders@>=
+{@+g=glue_ptr(p);rule_wd=width(g)-cur_g;
+if (g_sign!=normal)
+ {@+if (g_sign==stretching)
+ {@+if (stretch_order(g)==g_order)
+ {@+cur_glue=cur_glue+stretch(g);
+ vet_glue(float(glue_set(this_box))*cur_glue);
+@^real multiplication@>
+ cur_g=round(glue_temp);
+ }
+ }
+ else if (shrink_order(g)==g_order)
+ {@+cur_glue=cur_glue-shrink(g);
+ vet_glue(float(glue_set(this_box))*cur_glue);
+ cur_g=round(glue_temp);
+ }
+ }
+rule_wd=rule_wd+cur_g;
+if (subtype(p) >= a_leaders)
+ @<Output leaders in an hlist, |goto fin_rule| if a rule or to |next_p| if done@>;
+goto move_past;
+}
+
+@ @<Output leaders in an hlist...@>=
+{@+leader_box=leader_ptr(p);
+if (type(leader_box)==rule_node)
+ {@+rule_ht=height(leader_box);rule_dp=depth(leader_box);
+ goto fin_rule;
+ }
+leader_wd=width(leader_box);
+if ((leader_wd > 0)&&(rule_wd > 0))
+ {@+rule_wd=rule_wd+10; /*compensate for floating-point rounding*/
+ edge=cur_h+rule_wd;lx=0;
+ @<Let |cur_h| be the position of the first box, and set |leader_wd+lx| to the spacing
+between corresponding parts of boxes@>;
+ while (cur_h+leader_wd <= edge)
+ @<Output a leader box at |cur_h|, then advance |cur_h| by |leader_wd+lx|@>;
+ cur_h=edge-10;goto next_p;
+ }
+}
+
+@ 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.
+
+@<Let |cur_h| be the position of the first box,...@>=
+if (subtype(p)==a_leaders)
+ {@+save_h=cur_h;
+ cur_h=left_edge+leader_wd*((cur_h-left_edge)/leader_wd);
+ if (cur_h < save_h) cur_h=cur_h+leader_wd;
+ }
+else{@+lq=rule_wd/leader_wd; /*the number of box copies*/
+ lr=rule_wd%leader_wd; /*the remaining space*/
+ if (subtype(p)==c_leaders) cur_h=cur_h+(lr/2);
+ else{@+lx=lr/(lq+1);
+ cur_h=cur_h+((lr-(lq-1)*lx)/2);
+ }
+ }
+
+@ The `\\{synch}' operations here are intended to decrease the number of
+bytes needed to specify horizontal and vertical motion in the \.{DVI} output.
+
+@<Output a leader box at |cur_h|,...@>=
+{@+cur_v=base_line+shift_amount(leader_box);synch_v;save_v=dvi_v;@/
+synch_h;save_h=dvi_h;temp_ptr=leader_box;
+outer_doing_leaders=doing_leaders;doing_leaders=true;
+if (type(leader_box)==vlist_node) vlist_out();@+else hlist_out();
+doing_leaders=outer_doing_leaders;
+dvi_v=save_v;dvi_h=save_h;cur_v=base_line;
+cur_h=save_h+leader_wd+lx;
+}
+
+@ The |vlist_out| routine is similar to |hlist_out|, but a bit simpler.
+
+@p void vlist_out(void) /*output a |vlist_node| box*/
+{@+
+scaled left_edge; /*the left coordinate for this box*/
+scaled @!top_edge; /*the top coordinate for this box*/
+scaled @!save_h, @!save_v; /*what |dvi_h| and |dvi_v| should pop to*/
+pointer @!this_box; /*pointer to containing box*/
+glue_ord @!g_order; /*applicable order of infinity for glue*/
+uint8_t @!g_sign; /*selects type of glue*/
+pointer @!p; /*current position in the vlist*/
+int @!save_loc; /*\.{DVI} byte location upon entry*/
+pointer @!leader_box; /*the leader box being replicated*/
+scaled @!leader_ht; /*height of leader box being replicated*/
+scaled @!lx; /*extra space between leader boxes*/
+bool @!outer_doing_leaders; /*were we doing leaders?*/
+scaled @!edge; /*bottom boundary of leader space*/
+double @!glue_temp; /*glue value before rounding*/
+double @!cur_glue; /*glue seen so far*/
+scaled @!cur_g; /*rounded equivalent of |cur_glue| times the glue ratio*/
+cur_g=0;cur_glue=float_constant(0);
+this_box=temp_ptr;g_order=glue_order(this_box);
+g_sign=glue_sign(this_box);p=list_ptr(this_box);
+incr(cur_s);
+if (cur_s > 0) dvi_out(push);
+if (cur_s > max_push) max_push=cur_s;
+save_loc=dvi_offset+dvi_ptr;left_edge=cur_h;cur_v=cur_v-height(this_box);
+top_edge=cur_v;
+while (p!=null) @<Output node |p| for |vlist_out| and move to the next node, maintaining
+the condition |cur_h=left_edge|@>;
+prune_movements(save_loc);
+if (cur_s > 0) dvi_pop(save_loc);
+decr(cur_s);
+}
+
+@ @<Output node |p| for |vlist_out|...@>=
+{@+if (is_char_node(p)) confusion(@[@<|"vlistout"|@>@]);
+@:this can't happen vlistout}{\quad vlistout@>
+else@<Output the non-|char_node| |p| for |vlist_out|@>;
+next_p: p=link(p);
+}
+
+@ @<Output the non-|char_node| |p| for |vlist_out|@>=
+{@+switch (type(p)) {
+case hlist_node: case vlist_node: @<Output a box in a vlist@>@;@+break;
+case rule_node: {@+rule_ht=height(p);rule_dp=depth(p);rule_wd=width(p);
+ goto fin_rule;
+ }
+case whatsit_node: @<Output the whatsit node |p| in a vlist@>;@+break;
+case glue_node: @<Move down or output leaders@>@;
+case kern_node: cur_v=cur_v+width(p);@+break;
+default:do_nothing;
+} @/
+goto next_p;
+fin_rule: @<Output a rule in a vlist, |goto next_p|@>;
+move_past: cur_v=cur_v+rule_ht;
+}
+
+@ The |synch_v| here allows the \.{DVI} output to use one-byte commands
+for adjusting |v| in most cases, since the baselineskip distance will
+usually be constant.
+
+@<Output a box in a vlist@>=
+if (list_ptr(p)==null) cur_v=cur_v+height(p)+depth(p);
+else{@+cur_v=cur_v+height(p);synch_v;
+ save_h=dvi_h;save_v=dvi_v;
+ cur_h=left_edge+shift_amount(p); /*shift the box right*/
+ temp_ptr=p;
+ if (type(p)==vlist_node) vlist_out();@+else hlist_out();
+ dvi_h=save_h;dvi_v=save_v;
+ cur_v=save_v+depth(p);cur_h=left_edge;
+ }
+
+@ @<Output a rule in a vlist...@>=
+if (is_running(rule_wd)) rule_wd=width(this_box);
+rule_ht=rule_ht+rule_dp; /*this is the rule thickness*/
+cur_v=cur_v+rule_ht;
+if ((rule_ht > 0)&&(rule_wd > 0)) /*we don't output empty rules*/
+ {@+synch_h;synch_v;
+ dvi_out(put_rule);dvi_four(rule_ht);dvi_four(rule_wd);
+ }
+goto next_p
+
+@ @<Move down or output leaders@>=
+{@+g=glue_ptr(p);rule_ht=width(g)-cur_g;
+if (g_sign!=normal)
+ {@+if (g_sign==stretching)
+ {@+if (stretch_order(g)==g_order)
+ {@+cur_glue=cur_glue+stretch(g);
+ vet_glue(float(glue_set(this_box))*cur_glue);
+@^real multiplication@>
+ cur_g=round(glue_temp);
+ }
+ }
+ else if (shrink_order(g)==g_order)
+ {@+cur_glue=cur_glue-shrink(g);
+ vet_glue(float(glue_set(this_box))*cur_glue);
+ cur_g=round(glue_temp);
+ }
+ }
+rule_ht=rule_ht+cur_g;
+if (subtype(p) >= a_leaders)
+ @<Output leaders in a vlist, |goto fin_rule| if a rule or to |next_p| if done@>;
+goto move_past;
+}
+
+@ @<Output leaders in a vlist...@>=
+{@+leader_box=leader_ptr(p);
+if (type(leader_box)==rule_node)
+ {@+rule_wd=width(leader_box);rule_dp=0;
+ goto fin_rule;
+ }
+leader_ht=height(leader_box)+depth(leader_box);
+if ((leader_ht > 0)&&(rule_ht > 0))
+ {@+rule_ht=rule_ht+10; /*compensate for floating-point rounding*/
+ edge=cur_v+rule_ht;lx=0;
+ @<Let |cur_v| be the position of the first box, and set |leader_ht+lx| to the spacing
+between corresponding parts of boxes@>;
+ while (cur_v+leader_ht <= edge)
+ @<Output a leader box at |cur_v|, then advance |cur_v| by |leader_ht+lx|@>;
+ cur_v=edge-10;goto next_p;
+ }
+}
+
+@ @<Let |cur_v| be the position of the first box,...@>=
+if (subtype(p)==a_leaders)
+ {@+save_v=cur_v;
+ cur_v=top_edge+leader_ht*((cur_v-top_edge)/leader_ht);
+ if (cur_v < save_v) cur_v=cur_v+leader_ht;
+ }
+else{@+lq=rule_ht/leader_ht; /*the number of box copies*/
+ lr=rule_ht%leader_ht; /*the remaining space*/
+ if (subtype(p)==c_leaders) cur_v=cur_v+(lr/2);
+ else{@+lx=lr/(lq+1);
+ cur_v=cur_v+((lr-(lq-1)*lx)/2);
+ }
+ }
+
+@ When we reach this part of the program, |cur_v| indicates the top of a
+leader box, not its baseline.
+
+@<Output a leader box at |cur_v|,...@>=
+{@+cur_h=left_edge+shift_amount(leader_box);synch_h;save_h=dvi_h;@/
+cur_v=cur_v+height(leader_box);synch_v;save_v=dvi_v;
+temp_ptr=leader_box;
+outer_doing_leaders=doing_leaders;doing_leaders=true;
+if (type(leader_box)==vlist_node) vlist_out();@+else hlist_out();
+doing_leaders=outer_doing_leaders;
+dvi_v=save_v;dvi_h=save_h;cur_h=left_edge;
+cur_v=save_v-height(leader_box)+leader_ht+lx;
+}
+
+@ The |hlist_out| and |vlist_out| procedures are now complete, so we are
+ready for the |ship_out| routine that gets them started in the first place.
+
+@p void ship_out(pointer @!p) /*output the box |p|*/
+{@+
+int page_loc; /*location of the current |bop|*/
+uint8_t @!j, @!k; /*indices to first ten count registers*/
+int @!s; /*index into |str_pool|*/
+uint8_t @!old_setting; /*saved |selector| setting*/
+if (tracing_output > 0)
+ {@+print_nl("");print_ln();
+ print_str("Completed box being shipped out");
+@.Completed box...@>
+ }
+if (term_offset > max_print_line-9) print_ln();
+else if ((term_offset > 0)||(file_offset > 0)) print_char(' ');
+print_char('[');j=9;
+while ((count(j)==0)&&(j > 0)) decr(j);
+for (k=0; k<=j; k++)
+ {@+print_int(count(k));
+ if (k < j) print_char('.');
+ }
+update_terminal;
+if (tracing_output > 0)
+ {@+print_char(']');
+ begin_diagnostic();show_box(p);end_diagnostic(true);
+ }
+@<Ship box |p| out@>;
+if (tracing_output <= 0) print_char(']');
+dead_cycles=0;
+update_terminal; /*progress report*/
+@<Flush the box from memory, showing statistics if requested@>;
+}
+
+@ @<Flush the box from memory, showing statistics if requested@>=
+#ifdef @!STAT
+if (tracing_stats > 1)
+ {@+print_nl("Memory usage before: ");
+@.Memory usage...@>
+ print_int(var_used);print_char('&');
+ print_int(dyn_used);print_char(';');
+ }
+#endif
+flush_node_list(p);
+#ifdef @!STAT
+if (tracing_stats > 1)
+ {@+print_str(" after: ");
+ print_int(var_used);print_char('&');
+ print_int(dyn_used);print_str("; still untouched: ");
+ print_int(hi_mem_min-lo_mem_max-1);print_ln();
+ }
+#endif
+
+@ @<Ship box |p| out@>=
+@<Update the values of |max_h| and |max_v|; but if the page is too large, |goto done|@>;
+@<Initialize variables as |ship_out| begins@>;
+page_loc=dvi_offset+dvi_ptr;
+dvi_out(bop);
+for (k=0; k<=9; k++) dvi_four(count(k));
+dvi_four(last_bop);last_bop=page_loc;
+cur_v=height(p)+v_offset;temp_ptr=p;
+if (type(p)==vlist_node) vlist_out();@+else hlist_out();
+dvi_out(eop);incr(total_pages);cur_s=-1;
+done:
+
+@ Sometimes the user will generate a huge page because other error messages
+are being ignored. Such pages are not output to the \.{dvi} file, since they
+may confuse the printing software.
+
+@<Update the values of |max_h| and |max_v|; but if the page is too large...@>=
+if ((height(p) > max_dimen)||@|(depth(p) > max_dimen)||@|
+ (height(p)+depth(p)+v_offset > max_dimen)||@|
+ (width(p)+h_offset > max_dimen))
+ {@+print_err("Huge page cannot be shipped out");
+@.Huge page...@>
+ help2("The page just created is more than 18 feet tall or")@/
+ ("more than 18 feet wide, so I suspect something went wrong.");
+ error();
+ if (tracing_output <= 0)
+ {@+begin_diagnostic();
+ print_nl("The following box has been deleted:");
+@.The following...deleted@>
+ show_box(p);
+ end_diagnostic(true);
+ }
+ goto done;
+ }
+if (height(p)+depth(p)+v_offset > max_v) max_v=height(p)+depth(p)+v_offset;
+if (width(p)+h_offset > max_h) max_h=width(p)+h_offset
+
+@ At the end of the program, we must finish things off by writing the
+post\-amble. If |total_pages==0|, the \.{DVI} file was never opened.
+If |total_pages >= 65536|, the \.{DVI} file will lie. And if
+|max_push >= 65536|, the user deserves whatever chaos might ensue.
+
+An integer variable |k| will be declared for use by this routine.
+
+@<Finish the \.{DVI} file@>=
+while (cur_s > -1)
+ {@+if (cur_s > 0) dvi_out(pop)@;
+ else{@+dvi_out(eop);incr(total_pages);
+ }
+ decr(cur_s);
+ }
+if (total_pages==0) print_nl("No pages of output.");
+@.No pages of output@>
+else{@+dvi_out(post); /*beginning of the postamble*/
+ dvi_four(last_bop);last_bop=dvi_offset+dvi_ptr-5; /*|post| location*/
+ dvi_four(25400000);dvi_four(473628672); /*conversion ratio for sp*/
+ prepare_mag();dvi_four(mag); /*magnification factor*/
+ dvi_four(max_v);dvi_four(max_h);@/
+ dvi_out(max_push/256);dvi_out(max_push%256);@/
+ dvi_out((total_pages/256)%256);dvi_out(total_pages%256);@/
+ @<Output the font definitions for all fonts that were used@>;
+ dvi_out(post_post);dvi_four(last_bop);dvi_out(id_byte);@/
+ k=4+((dvi_buf_size-dvi_ptr)%4); /*the number of 223's*/
+ while (k > 0)
+ {@+dvi_out(223);decr(k);
+ }
+ @<Empty the last bytes out of |dvi_buf|@>;
+ print_nl("Output written on ");slow_print(output_file_name);
+@.Output written on x@>
+ print_str(" (");print_int(total_pages);print_str(" page");
+ if (total_pages!=1) print_char('s');
+ print_str(", ");print_int(dvi_offset+dvi_ptr);print_str(" bytes).");
+ b_close(&dvi_file);
+ }
+
+@ @<Output the font definitions...@>=
+while (font_ptr > font_base)
+ {@+if (font_used[font_ptr]) dvi_font_def(font_ptr);
+ decr(font_ptr);
+ }
+
+@* Packaging.
+We're essentially done with the parts of \TeX\ that are concerned with
+the input (|get_next|) and the output (|ship_out|). So it's time to
+get heavily into the remaining part, which does the real work of typesetting.
+
+After lists are constructed, \TeX\ wraps them up and puts them into boxes.
+Two major subroutines are given the responsibility for this task: |hpack|
+applies to horizontal lists (hlists) and |vpack| applies to vertical lists
+(vlists). The main duty of |hpack| and |vpack| is to compute the dimensions
+of the resulting boxes, and to adjust the glue if one of those dimensions
+is pre-specified. The computed sizes normally enclose all of the material
+inside the new box; but some items may stick out if negative glue is used,
+if the box is overfull, or if a \.{\\vbox} includes other boxes that have
+been shifted left.
+
+The subroutine call |hpack(p, w, m)| returns a pointer to an |hlist_node|
+for a box containing the hlist that starts at |p|. Parameter |w| specifies
+a width; and parameter |m| is either `|exactly|' or `|additional|'. Thus,
+|hpack(p, w, exactly)| produces a box whose width is exactly |w|, while
+|hpack(p, w, additional)| yields a box whose width is the natural width plus
+|w|. It is convenient to define a macro called `|natural|' to cover the
+most common case, so that we can say |hpack(p, natural)| to get a box that
+has the natural width of list |p|.
+
+Similarly, |vpack(p, w, m)| returns a pointer to a |vlist_node| for a
+box containing the vlist that starts at |p|. In this case |w| represents
+a height instead of a width; the parameter |m| is interpreted as in |hpack|.
+
+@d exactly 0 /*a box dimension is pre-specified*/
+@d additional 1 /*a box dimension is increased from the natural one*/
+@d natural 0, additional /*shorthand for parameters to |hpack| and |vpack|*/
+
+@ The parameters to |hpack| and |vpack| correspond to \TeX's primitives
+like `\.{\\hbox} \.{to} \.{300pt}', `\.{\\hbox} \.{spread} \.{10pt}'; note
+that `\.{\\hbox}' with no dimension following it is equivalent to
+`\.{\\hbox} \.{spread} \.{0pt}'. The |scan_spec| subroutine scans such
+constructions in the user's input, including the mandatory left brace that
+follows them, and it puts the specification onto |save_stack| so that the
+desired box can later be obtained by executing the following code:
+$$\vbox{\halign{#\hfil\cr
+|save_ptr=save_ptr-2;|\cr
+|hpack(p, saved(1), saved(0)).|\cr}}$$
+Special care is necessary to ensure that the special |save_stack| codes
+are placed just below the new group code, because scanning can change
+|save_stack| when \.{\\csname} appears.
+
+@p void scan_spec(group_code @!c, bool @!three_codes)
+ /*scans a box specification and left brace*/
+{@+
+int @!s; /*temporarily saved value*/
+uint8_t @!spec_code;
+if (three_codes) s=saved(0);
+if (scan_keyword(@[@<|"to"|@>@])) spec_code=exactly;
+@.to@>
+else if (scan_keyword(@[@<|"spread"|@>@])) spec_code=additional;
+@.spread@>
+else{@+spec_code=additional;cur_val=0;
+ goto found;
+ }
+scan_normal_dimen;
+found: if (three_codes)
+ {@+saved(0)=s;incr(save_ptr);
+ }
+saved(0)=spec_code;saved(1)=cur_val;save_ptr=save_ptr+2;
+new_save_level(c);scan_left_brace();
+}
+
+@ To figure out the glue setting, |hpack| and |vpack| determine how much
+stretchability and shrinkability are present, considering all four orders
+of infinity. The highest order of infinity that has a nonzero coefficient
+is then used as if no other orders were present.
+
+For example, suppose that the given list contains six glue nodes with
+the respective stretchabilities 3pt, 8fill, 5fil, 6pt, $-3$fil, $-8$fill.
+Then the total is essentially 2fil; and if a total additional space of 6pt
+is to be achieved by stretching, the actual amounts of stretch will be
+0pt, 0pt, 15pt, 0pt, $-9$pt, and 0pt, since only `fil' glue will be
+considered. (The `fill' glue is therefore not really stretching infinitely
+with respect to `fil'; nobody would actually want that to happen.)
+
+The arrays |total_stretch| and |total_shrink| are used to determine how much
+glue of each kind is present. A global variable |last_badness| is used
+to implement \.{\\badness}.
+
+@<Glob...@>=
+scaled @!total_stretch0[filll-normal+1], *const @!total_stretch = @!total_stretch0-normal, @!total_shrink0[filll-normal+1], *const @!total_shrink = @!total_shrink0-normal;
+ /*glue found by |hpack| or |vpack|*/
+int @!last_badness; /*badness of the most recently packaged box*/
+
+@ If the global variable |adjust_tail| is non-null, the |hpack| routine
+also removes all occurrences of |ins_node|, |mark_node|, and |adjust_node|
+items and appends the resulting material onto the list that ends at
+location |adjust_tail|.
+
+@<Glob...@>=
+pointer @!adjust_tail; /*tail of adjustment list*/
+
+@ @<Set init...@>=adjust_tail=null;last_badness=0;
+
+@ Here now is |hpack|, which contains few if any surprises.
+
+@p pointer hpack(pointer @!p, scaled @!w, small_number @!m)
+{@+
+pointer r; /*the box node that will be returned*/
+pointer @!q; /*trails behind |p|*/
+scaled @!h, @!d, @!x; /*height, depth, and natural width*/
+scaled @!s; /*shift amount*/
+pointer @!g; /*points to a glue specification*/
+glue_ord @!o; /*order of infinity*/
+internal_font_number @!f; /*the font in a |char_node|*/
+four_quarters @!i; /*font information about a |char_node|*/
+eight_bits @!hd; /*height and depth indices for a character*/
+last_badness=0;r=get_node(box_node_size);type(r)=hlist_node;
+subtype(r)=min_quarterword;shift_amount(r)=0;
+q=r+list_offset;link(q)=p;@/
+h=0;@<Clear dimensions to zero@>;
+while (p!=null) @<Examine node |p| in the hlist, taking account of its effect on the
+dimensions of the new box, or moving it to the adjustment list; then advance |p| to
+the next node@>;
+if (adjust_tail!=null) link(adjust_tail)=null;
+height(r)=h;depth(r)=d;@/
+@<Determine the value of |width(r)| and the appropriate glue setting; then |return|
+or |goto common_ending|@>;
+common_ending: @<Finish issuing a diagnostic message for an overfull or underfull
+hbox@>;
+end: return r;
+}
+
+@ @<Clear dimensions to zero@>=
+d=0;x=0;
+total_stretch[normal]=0;total_shrink[normal]=0;
+total_stretch[fil]=0;total_shrink[fil]=0;
+total_stretch[fill]=0;total_shrink[fill]=0;
+total_stretch[filll]=0;total_shrink[filll]=0
+
+@ @<Examine node |p| in the hlist, taking account of its effect...@>=
+@^inner loop@>
+{@+reswitch: while (is_char_node(p))
+ @<Incorporate character dimensions into the dimensions of the hbox that will contain~it,
+then move to the next node@>;
+if (p!=null)
+ {@+switch (type(p)) {
+ case hlist_node: case vlist_node: case rule_node: case unset_node:
+ @<Incorporate box dimensions into the dimensions of the hbox that will contain~it@>@;@+break;
+ case ins_node: case mark_node: case adjust_node: if (adjust_tail!=null)
+ @<Transfer node |p| to the adjustment list@>@;@+break;
+ case whatsit_node: @<Incorporate a whatsit node into an hbox@>;@+break;
+ case glue_node: @<Incorporate glue into the horizontal totals@>@;@+break;
+ case kern_node: case math_node: x=x+width(p);@+break;
+ case ligature_node: @<Make node |p| look like a |char_node| and |goto reswitch|@>@;
+ default:do_nothing;
+ } @/
+ p=link(p);
+ }
+}
+
+
+@ @<Make node |p| look like a |char_node| and |goto reswitch|@>=
+{@+mem[lig_trick]=mem[lig_char(p)];link(lig_trick)=link(p);
+p=lig_trick;goto reswitch;
+}
+
+@ The code here implicitly uses the fact that running dimensions are
+indicated by |null_flag|, which will be ignored in the calculations
+because it is a highly negative number.
+
+@<Incorporate box dimensions into the dimensions of the hbox...@>=
+{@+x=x+width(p);
+if (type(p) >= rule_node) s=0;@+else s=shift_amount(p);
+if (height(p)-s > h) h=height(p)-s;
+if (depth(p)+s > d) d=depth(p)+s;
+}
+
+@ The following code is part of \TeX's inner loop; i.e., adding another
+character of text to the user's input will cause each of these instructions
+to be exercised one more time.
+@^inner loop@>
+
+@<Incorporate character dimensions into the dimensions of the hbox...@>=
+{@+f=font(p);i=char_info(f)(character(p));hd=height_depth(i);
+x=x+char_width(f)(i);@/
+s=char_height(f)(hd);@+if (s > h) h=s;
+s=char_depth(f)(hd);@+if (s > d) d=s;
+p=link(p);
+}
+
+@ Although node |q| is not necessarily the immediate predecessor of node |p|,
+it always points to some node in the list preceding |p|. Thus, we can delete
+nodes by moving |q| when necessary. The algorithm takes linear time, and the
+extra computation does not intrude on the inner loop unless it is necessary
+to make a deletion.
+@^inner loop@>
+
+@<Transfer node |p| to the adjustment list@>=
+{@+while (link(q)!=p) q=link(q);
+if (type(p)==adjust_node)
+ {@+link(adjust_tail)=adjust_ptr(p);
+ while (link(adjust_tail)!=null) adjust_tail=link(adjust_tail);
+ p=link(p);free_node(link(q), small_node_size);
+ }
+else{@+link(adjust_tail)=p;adjust_tail=p;p=link(p);
+ }
+link(q)=p;p=q;
+}
+
+@ @<Incorporate glue into the horizontal totals@>=
+{@+g=glue_ptr(p);x=x+width(g);@/
+o=stretch_order(g);total_stretch[o]=total_stretch[o]+stretch(g);
+o=shrink_order(g);total_shrink[o]=total_shrink[o]+shrink(g);
+if (subtype(p) >= a_leaders)
+ {@+g=leader_ptr(p);
+ if (height(g) > h) h=height(g);
+ if (depth(g) > d) d=depth(g);
+ }
+}
+
+@ When we get to the present part of the program, |x| is the natural width
+of the box being packaged.
+
+@<Determine the value of |width(r)| and the appropriate glue setting...@>=
+if (m==additional) w=x+w;
+width(r)=w;x=w-x; /*now |x| is the excess to be made up*/
+if (x==0)
+ {@+glue_sign(r)=normal;glue_order(r)=normal;
+ set_glue_ratio_zero(glue_set(r));
+ goto end;
+ }
+else if (x > 0) @<Determine horizontal glue stretch setting, then |return| or \hbox{|goto
+common_ending|}@>@;
+else@<Determine horizontal glue shrink setting, then |return| or \hbox{|goto common_ending|}@>@;
+
+@ @<Determine horizontal glue stretch setting...@>=
+{@+@<Determine the stretch order@>;
+glue_order(r)=o;glue_sign(r)=stretching;
+if (total_stretch[o]!=0) glue_set(r)=unfloat(x/(double)total_stretch[o]);
+@^real division@>
+else{@+glue_sign(r)=normal;
+ set_glue_ratio_zero(glue_set(r)); /*there's nothing to stretch*/
+ }
+if (o==normal) if (list_ptr(r)!=null)
+ @<Report an underfull hbox and |goto common_ending|, if this box is sufficiently
+bad@>;
+goto end;
+}
+
+@ @<Determine the stretch order@>=
+if (total_stretch[filll]!=0) o=filll;
+else if (total_stretch[fill]!=0) o=fill;
+else if (total_stretch[fil]!=0) o=fil;
+else o=normal
+
+@ @<Report an underfull hbox and |goto common_ending|, if...@>=
+{@+last_badness=badness(x, total_stretch[normal]);
+if (last_badness > hbadness)
+ {@+print_ln();
+ if (last_badness > 100) print_nl("Underfull");@+else print_nl("Loose");
+ print_str(" \\hbox (badness ");print_int(last_badness);
+@.Underfull \\hbox...@>
+@.Loose \\hbox...@>
+ goto common_ending;
+ }
+}
+
+@ In order to provide a decent indication of where an overfull or underfull
+box originated, we use a global variable |pack_begin_line| that is
+set nonzero only when |hpack| is being called by the paragraph builder
+or the alignment finishing routine.
+
+@<Glob...@>=
+int @!pack_begin_line; /*source file line where the current paragraph
+ or alignment began; a negative value denotes alignment*/
+
+@ @<Set init...@>=
+pack_begin_line=0;
+
+@ @<Finish issuing a diagnostic message for an overfull or underfull hbox@>=
+if (output_active) print_str(") has occurred while \\output is active");
+else{@+if (pack_begin_line!=0)
+ {@+if (pack_begin_line > 0) print_str(") in paragraph at lines ");
+ else print_str(") in alignment at lines ");
+ print_int(abs(pack_begin_line));
+ print_str("--");
+ }
+ else print_str(") detected at line ");
+ print_int(line);
+ }
+print_ln();@/
+font_in_short_display=null_font;short_display(list_ptr(r));print_ln();@/
+begin_diagnostic();show_box(r);end_diagnostic(true)
+
+@ @<Determine horizontal glue shrink setting...@>=
+{@+@<Determine the shrink order@>;
+glue_order(r)=o;glue_sign(r)=shrinking;
+if (total_shrink[o]!=0) glue_set(r)=unfloat((-x)/(double)total_shrink[o]);
+@^real division@>
+else{@+glue_sign(r)=normal;
+ set_glue_ratio_zero(glue_set(r)); /*there's nothing to shrink*/
+ }
+if ((total_shrink[o] < -x)&&(o==normal)&&(list_ptr(r)!=null))
+ {@+last_badness=1000000;
+ set_glue_ratio_one(glue_set(r)); /*use the maximum shrinkage*/
+ @<Report an overfull hbox and |goto common_ending|, if this box is sufficiently
+bad@>;
+ }
+else if (o==normal) if (list_ptr(r)!=null)
+ @<Report a tight hbox and |goto common_ending|, if this box is sufficiently bad@>;
+goto end;
+}
+
+@ @<Determine the shrink order@>=
+if (total_shrink[filll]!=0) o=filll;
+else if (total_shrink[fill]!=0) o=fill;
+else if (total_shrink[fil]!=0) o=fil;
+else o=normal
+
+@ @<Report an overfull hbox and |goto common_ending|, if...@>=
+if ((-x-total_shrink[normal] > hfuzz)||(hbadness < 100))
+ {@+if ((overfull_rule > 0)&&(-x-total_shrink[normal] > hfuzz))
+ {@+while (link(q)!=null) q=link(q);
+ link(q)=new_rule();
+ width(link(q))=overfull_rule;
+ }
+ print_ln();print_nl("Overfull \\hbox (");
+@.Overfull \\hbox...@>
+ print_scaled(-x-total_shrink[normal]);print_str("pt too wide");
+ goto common_ending;
+ }
+
+@ @<Report a tight hbox and |goto common_ending|, if...@>=
+{@+last_badness=badness(-x, total_shrink[normal]);
+if (last_badness > hbadness)
+ {@+print_ln();print_nl("Tight \\hbox (badness ");print_int(last_badness);
+@.Tight \\hbox...@>
+ goto common_ending;
+ }
+}
+
+@ 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.
+
+@p
+#define vpack(...) @[vpackage(__VA_ARGS__, max_dimen)@]
+ /*special case of unconstrained depth*/
+
+pointer vpackage(pointer @!p, scaled @!h, small_number @!m, scaled @!l)
+{@+
+pointer r; /*the box node that will be returned*/
+scaled @!w, @!d, @!x; /*width, depth, and natural height*/
+scaled @!s; /*shift amount*/
+pointer @!g; /*points to a glue specification*/
+glue_ord @!o; /*order of infinity*/
+last_badness=0;r=get_node(box_node_size);type(r)=vlist_node;
+subtype(r)=min_quarterword;shift_amount(r)=0;
+list_ptr(r)=p;@/
+w=0;@<Clear dimensions to zero@>;
+while (p!=null) @<Examine node |p| in the vlist, taking account of its effect on the
+dimensions of the new box; then advance |p| to the next node@>;
+width(r)=w;
+if (d > l)
+ {@+x=x+d-l;depth(r)=l;
+ }
+else depth(r)=d;
+@<Determine the value of |height(r)| and the appropriate glue setting; then |return|
+or |goto common_ending|@>;
+common_ending: @<Finish issuing a diagnostic message for an overfull or underfull
+vbox@>;
+end: return r;
+}
+
+@ @<Examine node |p| in the vlist, taking account of its effect...@>=
+{@+if (is_char_node(p)) confusion(@[@<|"vpack"|@>@]);
+@:this can't happen vpack}{\quad vpack@>
+else switch (type(p)) {
+ case hlist_node: case vlist_node: case rule_node: case unset_node:
+ @<Incorporate box dimensions into the dimensions of the vbox that will contain~it@>@;@+break;
+ case whatsit_node: @<Incorporate a whatsit node into a vbox@>;@+break;
+ case glue_node: @<Incorporate glue into the vertical totals@>@;@+break;
+ case kern_node: {@+x=x+d+width(p);d=0;
+ } @+break;
+ default:do_nothing;
+ }
+p=link(p);
+}
+
+@ @<Incorporate box dimensions into the dimensions of the vbox...@>=
+{@+x=x+d+height(p);d=depth(p);
+if (type(p) >= rule_node) s=0;@+else s=shift_amount(p);
+if (width(p)+s > w) w=width(p)+s;
+}
+
+@ @<Incorporate glue into the vertical totals@>=
+{@+x=x+d;d=0;@/
+g=glue_ptr(p);x=x+width(g);@/
+o=stretch_order(g);total_stretch[o]=total_stretch[o]+stretch(g);
+o=shrink_order(g);total_shrink[o]=total_shrink[o]+shrink(g);
+if (subtype(p) >= a_leaders)
+ {@+g=leader_ptr(p);
+ if (width(g) > w) w=width(g);
+ }
+}
+
+@ When we get to the present part of the program, |x| is the natural height
+of the box being packaged.
+
+@<Determine the value of |height(r)| and the appropriate glue setting...@>=
+if (m==additional) h=x+h;
+height(r)=h;x=h-x; /*now |x| is the excess to be made up*/
+if (x==0)
+ {@+glue_sign(r)=normal;glue_order(r)=normal;
+ set_glue_ratio_zero(glue_set(r));
+ goto end;
+ }
+else if (x > 0) @<Determine vertical glue stretch setting, then |return| or \hbox{|goto
+common_ending|}@>@;
+else@<Determine vertical glue shrink setting, then |return| or \hbox{|goto common_ending|}@>@;
+
+@ @<Determine vertical glue stretch setting...@>=
+{@+@<Determine the stretch order@>;
+glue_order(r)=o;glue_sign(r)=stretching;
+if (total_stretch[o]!=0) glue_set(r)=unfloat(x/(double)total_stretch[o]);
+@^real division@>
+else{@+glue_sign(r)=normal;
+ set_glue_ratio_zero(glue_set(r)); /*there's nothing to stretch*/
+ }
+if (o==normal) if (list_ptr(r)!=null)
+ @<Report an underfull vbox and |goto common_ending|, if this box is sufficiently
+bad@>;
+goto end;
+}
+
+@ @<Report an underfull vbox and |goto common_ending|, if...@>=
+{@+last_badness=badness(x, total_stretch[normal]);
+if (last_badness > vbadness)
+ {@+print_ln();
+ if (last_badness > 100) print_nl("Underfull");@+else print_nl("Loose");
+ print_str(" \\vbox (badness ");print_int(last_badness);
+@.Underfull \\vbox...@>
+@.Loose \\vbox...@>
+ goto common_ending;
+ }
+}
+
+@ @<Finish issuing a diagnostic message for an overfull or underfull vbox@>=
+if (output_active) print_str(") has occurred while \\output is active");
+else{@+if (pack_begin_line!=0) /*it's actually negative*/
+ {@+print_str(") in alignment at lines ");
+ print_int(abs(pack_begin_line));
+ print_str("--");
+ }
+ else print_str(") detected at line ");
+ print_int(line);
+ print_ln();@/
+ }
+begin_diagnostic();show_box(r);end_diagnostic(true)
+
+@ @<Determine vertical glue shrink setting...@>=
+{@+@<Determine the shrink order@>;
+glue_order(r)=o;glue_sign(r)=shrinking;
+if (total_shrink[o]!=0) glue_set(r)=unfloat((-x)/(double)total_shrink[o]);
+@^real division@>
+else{@+glue_sign(r)=normal;
+ set_glue_ratio_zero(glue_set(r)); /*there's nothing to shrink*/
+ }
+if ((total_shrink[o] < -x)&&(o==normal)&&(list_ptr(r)!=null))
+ {@+last_badness=1000000;
+ set_glue_ratio_one(glue_set(r)); /*use the maximum shrinkage*/
+ @<Report an overfull vbox and |goto common_ending|, if this box is sufficiently
+bad@>;
+ }
+else if (o==normal) if (list_ptr(r)!=null)
+ @<Report a tight vbox and |goto common_ending|, if this box is sufficiently bad@>;
+goto end;
+}
+
+@ @<Report an overfull vbox and |goto common_ending|, if...@>=
+if ((-x-total_shrink[normal] > vfuzz)||(vbadness < 100))
+ {@+print_ln();print_nl("Overfull \\vbox (");
+@.Overfull \\vbox...@>
+ print_scaled(-x-total_shrink[normal]);print_str("pt too high");
+ goto common_ending;
+ }
+
+@ @<Report a tight vbox and |goto common_ending|, if...@>=
+{@+last_badness=badness(-x, total_shrink[normal]);
+if (last_badness > vbadness)
+ {@+print_ln();print_nl("Tight \\vbox (badness ");print_int(last_badness);
+@.Tight \\vbox...@>
+ goto common_ending;
+ }
+}
+
+@ When a box is being appended to the current vertical list, the
+baselineskip calculation is handled by the |append_to_vlist| routine.
+
+@p void append_to_vlist(pointer @!b)
+{@+scaled d; /*deficiency of space between baselines*/
+pointer @!p; /*a new glue node*/
+if (prev_depth > ignore_depth)
+ {@+d=width(baseline_skip)-prev_depth-height(b);
+ if (d < line_skip_limit) p=new_param_glue(line_skip_code);
+ else{@+p=new_skip_param(baseline_skip_code);
+ width(temp_ptr)=d; /*|temp_ptr==glue_ptr(p)|*/
+ }
+ link(tail)=p;tail=p;
+ }
+link(tail)=b;tail=b;prev_depth=depth(b);
+}
+
+@* Data structures for math mode.
+When \TeX\ reads a formula that is enclosed between \.\$'s, it constructs an
+{\sl mlist}, which is essentially a tree structure representing that
+formula. An mlist is a linear sequence of items, but we can regard it as
+a tree structure because mlists can appear within mlists. For example, many
+of the entries can be subscripted or superscripted, and such ``scripts''
+are mlists in their own right.
+
+An entire formula is parsed into such a tree before any of the actual
+typesetting is done, because the current style of type is usually not
+known until the formula has been fully scanned. For example, when the
+formula `\.{\$a+b \\over c+d\$}' is being read, there is no way to tell
+that `\.{a+b}' will be in script size until `\.{\\over}' has appeared.
+
+During the scanning process, each element of the mlist being built is
+classified as a relation, a binary operator, an open parenthesis, etc.,
+or as a construct like `\.{\\sqrt}' that must be built up. This classification
+appears in the mlist data structure.
+
+After a formula has been fully scanned, the mlist is converted to an hlist
+so that it can be incorporated into the surrounding text. This conversion is
+controlled by a recursive procedure that decides all of the appropriate
+styles by a ``top-down'' process starting at the outermost level and working
+in towards the subformulas. The formula is ultimately pasted together using
+combinations of horizontal and vertical boxes, with glue and penalty nodes
+inserted as necessary.
+
+An mlist is represented internally as a linked list consisting chiefly
+of ``noads'' (pronounced ``no-adds''), to distinguish them from the somewhat
+similar ``nodes'' in hlists and vlists. Certain kinds of ordinary nodes are
+allowed to appear in mlists together with the noads; \TeX\ tells the difference
+by means of the |type| field, since a noad's |type| is always greater than
+that of a node. An mlist does not contain character nodes, hlist nodes, vlist
+nodes, math nodes, ligature nodes,
+or unset nodes; in particular, each mlist item appears in the
+variable-size part of |mem|, so the |type| field is always present.
+
+@ Each noad is four or more words long. The first word contains the |type|
+and |subtype| and |link| fields that are already so familiar to us; the
+second, third, and fourth words are called the noad's |nucleus|, |subscr|,
+and |supscr| fields.
+
+Consider, for example, the simple formula `\.{\$x\^2\$}', which would be
+parsed into an mlist containing a single element called an |ord_noad|.
+The |nucleus| of this noad is a representation of `\.x', the |subscr| is
+empty, and the |supscr| is a representation of `\.2'.
+
+The |nucleus|, |subscr|, and |supscr| fields are further broken into
+subfields. If |p| points to a noad, and if |q| is one of its principal
+fields (e.g., |q==subscr(p)|), there are several possibilities for the
+subfields, depending on the |math_type| of |q|.
+
+\yskip\hang|math_type(q)==math_char| means that |fam(q)| refers to one of
+the sixteen font families, and |character(q)| is the number of a character
+within a font of that family, as in a character node.
+
+\yskip\hang|math_type(q)==math_text_char| is similar, but the character is
+unsubscripted and unsuperscripted and it is followed immediately by another
+character from the same font. (This |math_type| setting appears only
+briefly during the processing; it is used to suppress unwanted italic
+corrections.)
+
+\yskip\hang|math_type(q)==empty| indicates a field with no value (the
+corresponding attribute of noad |p| is not present).
+
+\yskip\hang|math_type(q)==sub_box| means that |info(q)| points to a box
+node (either an |hlist_node| or a |vlist_node|) that should be used as the
+value of the field. The |shift_amount| in the subsidiary box node is the
+amount by which that box will be shifted downward.
+
+\yskip\hang|math_type(q)==sub_mlist| means that |info(q)| points to
+an mlist; the mlist must be converted to an hlist in order to obtain
+the value of this field.
+
+\yskip\noindent In the latter case, we might have |info(q)==null|. This
+is not the same as |math_type(q)==empty|; for example, `\.{\$P\_\{\}\$}'
+and `\.{\$P\$}' produce different results (the former will not have the
+``italic correction'' added to the width of |P|, but the ``script skip''
+will be added).
+
+The definitions of subfields given here are evidently wasteful of space,
+since a halfword is being used for the |math_type| although only three
+bits would be needed. However, there are hardly ever many noads present at
+once, since they are soon converted to nodes that take up even more space,
+so we can afford to represent them in whatever way simplifies the
+programming.
+
+@d noad_size 4 /*number of words in a normal noad*/
+@d nucleus(X) X+1 /*the |nucleus| field of a noad*/
+@d supscr(X) X+2 /*the |supscr| field of a noad*/
+@d subscr(X) X+3 /*the |subscr| field of a noad*/
+@d math_type link /*a |halfword| in |mem|*/
+@d fam font /*a |quarterword| in |mem|*/
+@d math_char 1 /*|math_type| when the attribute is simple*/
+@d sub_box 2 /*|math_type| when the attribute is a box*/
+@d sub_mlist 3 /*|math_type| when the attribute is a formula*/
+@d math_text_char 4 /*|math_type| when italic correction is dubious*/
+
+@ Each portion of a formula is classified as Ord, Op, Bin, Rel, Ope,
+Clo, Pun, or Inn, for purposes of spacing and line breaking. An
+|ord_noad|, |op_noad|, |bin_noad|, |rel_noad|, |open_noad|, |close_noad|,
+|punct_noad|, or |inner_noad| is used to represent portions of the various
+types. For example, an `\.=' sign in a formula leads to the creation of a
+|rel_noad| whose |nucleus| field is a representation of an equals sign
+(usually |fam==0|, |character==075|). A formula preceded by \.{\\mathrel}
+also results in a |rel_noad|. When a |rel_noad| is followed by an
+|op_noad|, say, and possibly separated by one or more ordinary nodes (not
+noads), \TeX\ will insert a penalty node (with the current |rel_penalty|)
+just after the formula that corresponds to the |rel_noad|, unless there
+already was a penalty immediately following; and a ``thick space'' will be
+inserted just before the formula that corresponds to the |op_noad|.
+
+A noad of type |ord_noad|, |op_noad|, \dots, |inner_noad| usually
+has a |subtype==normal|. The only exception is that an |op_noad| might
+have |subtype==limits| or |no_limits|, if the normal positioning of
+limits has been overridden for this operator.
+
+@d ord_noad (unset_node+3) /*|type| of a noad classified Ord*/
+@d op_noad (ord_noad+1) /*|type| of a noad classified Op*/
+@d bin_noad (ord_noad+2) /*|type| of a noad classified Bin*/
+@d rel_noad (ord_noad+3) /*|type| of a noad classified Rel*/
+@d open_noad (ord_noad+4) /*|type| of a noad classified Ope*/
+@d close_noad (ord_noad+5) /*|type| of a noad classified Clo*/
+@d punct_noad (ord_noad+6) /*|type| of a noad classified Pun*/
+@d inner_noad (ord_noad+7) /*|type| of a noad classified Inn*/
+@d limits 1 /*|subtype| of |op_noad| whose scripts are to be above, below*/
+@d no_limits 2 /*|subtype| of |op_noad| whose scripts are to be normal*/
+
+@ A |radical_noad| is five words long; the fifth word is the |left_delimiter|
+field, which usually represents a square root sign.
+
+A |fraction_noad| is six words long; it has a |right_delimiter| field
+as well as a |left_delimiter|.
+
+Delimiter fields are of type |four_quarters|, and they have four subfields
+called |small_fam|, |small_char|, |large_fam|, |large_char|. These subfields
+represent variable-size delimiters by giving the ``small'' and ``large''
+starting characters, as explained in Chapter~17 of {\sl The \TeX book}.
+@:TeXbook}{\sl The \TeX book@>
+
+A |fraction_noad| is actually quite different from all other noads. Not
+only does it have six words, it has |thickness|, |denominator|, and
+|numerator| fields instead of |nucleus|, |subscr|, and |supscr|. The
+|thickness| is a scaled value that tells how thick to make a fraction
+rule; however, the special value |default_code| is used to stand for the
+|default_rule_thickness| of the current size. The |numerator| and
+|denominator| point to mlists that define a fraction; we always have
+$$\hbox{|math_type(numerator)==math_type(denominator)==sub_mlist|}.$$ The
+|left_delimiter| and |right_delimiter| fields specify delimiters that will
+be placed at the left and right of the fraction. In this way, a
+|fraction_noad| is able to represent all of \TeX's operators \.{\\over},
+\.{\\atop}, \.{\\above}, \.{\\overwithdelims}, \.{\\atopwithdelims}, and
+ \.{\\abovewithdelims}.
+
+@d left_delimiter(X) X+4 /*first delimiter field of a noad*/
+@d right_delimiter(X) X+5 /*second delimiter field of a fraction noad*/
+@d radical_noad (inner_noad+1) /*|type| of a noad for square roots*/
+@d radical_noad_size 5 /*number of |mem| words in a radical noad*/
+@d fraction_noad (radical_noad+1) /*|type| of a noad for generalized fractions*/
+@d fraction_noad_size 6 /*number of |mem| words in a fraction noad*/
+@d small_fam(X) mem[X].qqqq.b0 /*|fam| for ``small'' delimiter*/
+@d small_char(X) mem[X].qqqq.b1 /*|character| for ``small'' delimiter*/
+@d large_fam(X) mem[X].qqqq.b2 /*|fam| for ``large'' delimiter*/
+@d large_char(X) mem[X].qqqq.b3 /*|character| for ``large'' delimiter*/
+@d thickness width /*|thickness| field in a fraction noad*/
+@d default_code 010000000000 /*denotes |default_rule_thickness|*/
+@d numerator supscr /*|numerator| field in a fraction noad*/
+@d denominator subscr /*|denominator| field in a fraction noad*/
+
+@ The global variable |empty_field| is set up for initialization of empty
+fields in new noads. Similarly, |null_delimiter| is for the initialization
+of delimiter fields.
+
+@<Glob...@>=
+two_halves @!empty_field;
+four_quarters @!null_delimiter;
+
+@ @<Set init...@>=
+empty_field.rh=empty;empty_field.lh=null;@/
+null_delimiter.b0=0;null_delimiter.b1=min_quarterword;@/
+null_delimiter.b2=0;null_delimiter.b3=min_quarterword;
+
+@ The |new_noad| function creates an |ord_noad| that is completely null.
+
+@p pointer new_noad(void)
+{@+pointer p;
+p=get_node(noad_size);
+type(p)=ord_noad;subtype(p)=normal;
+mem[nucleus(p)].hh=empty_field;
+mem[subscr(p)].hh=empty_field;
+mem[supscr(p)].hh=empty_field;
+return p;
+}
+
+@ A few more kinds of noads will complete the set: An |under_noad| has its
+nucleus underlined; an |over_noad| has it overlined. An |accent_noad| places
+an accent over its nucleus; the accent character appears as
+|fam(accent_chr(p))| and |character(accent_chr(p))|. A |vcenter_noad|
+centers its nucleus vertically with respect to the axis of the formula;
+in such noads we always have |math_type(nucleus(p))==sub_box|.
+
+And finally, we have |left_noad| and |right_noad| types, to implement
+\TeX's \.{\\left} and \.{\\right}. The |nucleus| of such noads is
+replaced by a |delimiter| field; thus, for example, `\.{\\left(}' produces
+a |left_noad| such that |delimiter(p)| holds the family and character
+codes for all left parentheses. A |left_noad| never appears in an mlist
+except as the first element, and a |right_noad| never appears in an mlist
+except as the last element; furthermore, we either have both a |left_noad|
+and a |right_noad|, or neither one is present. The |subscr| and |supscr|
+fields are always |empty| in a |left_noad| and a |right_noad|.
+
+@d under_noad (fraction_noad+1) /*|type| of a noad for underlining*/
+@d over_noad (under_noad+1) /*|type| of a noad for overlining*/
+@d accent_noad (over_noad+1) /*|type| of a noad for accented subformulas*/
+@d accent_noad_size 5 /*number of |mem| words in an accent noad*/
+@d accent_chr(X) X+4 /*the |accent_chr| field of an accent noad*/
+@d vcenter_noad (accent_noad+1) /*|type| of a noad for \.{\\vcenter}*/
+@d left_noad (vcenter_noad+1) /*|type| of a noad for \.{\\left}*/
+@d right_noad (left_noad+1) /*|type| of a noad for \.{\\right}*/
+@d delimiter nucleus /*|delimiter| field in left and right noads*/
+@d scripts_allowed(X) (type(X) >= ord_noad)&&(type(X) < left_noad)
+
+@ Math formulas can also contain instructions like \.{\\textstyle} that
+override \TeX's normal style rules. A |style_node| is inserted into the
+data structure to record such instructions; it is three words long, so it
+is considered a node instead of a noad. The |subtype| is either |display_style|
+or |text_style| or |script_style| or |script_script_style|. The
+second and third words of a |style_node| are not used, but they are
+present because a |choice_node| is converted to a |style_node|.
+
+\TeX\ uses even numbers 0, 2, 4, 6 to encode the basic styles
+|display_style|, \dots, |script_script_style|, and adds~1 to get the
+``cramped'' versions of these styles. This gives a numerical order that
+is backwards from the convention of Appendix~G in {\sl The \TeX book\/};
+i.e., a smaller style has a larger numerical value.
+@:TeXbook}{\sl The \TeX book@>
+
+@d style_node (unset_node+1) /*|type| of a style node*/
+@d style_node_size 3 /*number of words in a style node*/
+@d display_style 0 /*|subtype| for \.{\\displaystyle}*/
+@d text_style 2 /*|subtype| for \.{\\textstyle}*/
+@d script_style 4 /*|subtype| for \.{\\scriptstyle}*/
+@d script_script_style 6 /*|subtype| for \.{\\scriptscriptstyle}*/
+@d cramped 1 /*add this to an uncramped style if you want to cramp it*/
+
+@p pointer new_style(small_number @!s) /*create a style node*/
+{@+pointer p; /*the new node*/
+p=get_node(style_node_size);type(p)=style_node;
+subtype(p)=s;width(p)=0;depth(p)=0; /*the |width| and |depth| are not used*/
+return p;
+}
+
+@ Finally, the \.{\\mathchoice} primitive creates a |choice_node|, which
+has special subfields |display_mlist|, |text_mlist|, |script_mlist|,
+and |script_script_mlist| pointing to the mlists for each style.
+
+@d choice_node (unset_node+2) /*|type| of a choice node*/
+@d display_mlist(X) info(X+1) /*mlist to be used in display style*/
+@d text_mlist(X) link(X+1) /*mlist to be used in text style*/
+@d script_mlist(X) info(X+2) /*mlist to be used in script style*/
+@d script_script_mlist(X) link(X+2) /*mlist to be used in scriptscript style*/
+
+@p pointer new_choice(void) /*create a choice node*/
+{@+pointer p; /*the new node*/
+p=get_node(style_node_size);type(p)=choice_node;
+subtype(p)=0; /*the |subtype| is not used*/
+display_mlist(p)=null;text_mlist(p)=null;script_mlist(p)=null;
+script_script_mlist(p)=null;
+return p;
+}
+
+@ Let's consider now the previously unwritten part of |show_node_list|
+that displays the things that can only be present in mlists; this
+program illustrates how to access the data structures just defined.
+
+In the context of the following program, |p| points to a node or noad that
+should be displayed, and the current string contains the ``recursion history''
+that leads to this point. The recursion history consists of a dot for each
+outer level in which |p| is subsidiary to some node, or in which |p| is
+subsidiary to the |nucleus| field of some noad; the dot is replaced by
+`\.\_' or `\.\^' or `\./' or `\.\\' if |p| is descended from the |subscr|
+or |supscr| or |denominator| or |numerator| fields of noads. For example,
+the current string would be `\.{.\^.\_/}' if |p| points to the |ord_noad| for
+|x| in the (ridiculous) formula
+`\.{\$\\sqrt\{a\^\{\\mathinner\{b\_\{c\\over x+y\}\}\}\}\$}'.
+
+@<Cases of |show_node_list| that arise...@>=
+case style_node: print_style(subtype(p));@+break;
+case choice_node: @<Display choice node |p|@>@;@+break;
+case ord_noad: case op_noad: case bin_noad: case rel_noad: case open_noad: case close_noad: case punct_noad: case inner_noad:
+ case radical_noad: case over_noad: case under_noad: case vcenter_noad: case accent_noad:
+ case left_noad: case right_noad: @<Display normal noad |p|@>@;@+break;
+case fraction_noad: @<Display fraction noad |p|@>@;@+break;
+
+@ Here are some simple routines used in the display of noads.
+
+@<Declare procedures needed for displaying the elements of mlists@>=
+void print_fam_and_char(pointer @!p) /*prints family and character*/
+{@+print_esc(@[@<|"fam"|@>@]);print_int(fam(p));print_char(' ');
+print_ASCII(qo(character(p)));
+}
+@#
+void print_delimiter(pointer @!p) /*prints a delimiter as 24-bit hex value*/
+{@+int a; /*accumulator*/
+a=small_fam(p)*256+qo(small_char(p));
+a=a*0x1000+large_fam(p)*256+qo(large_char(p));
+if (a < 0) print_int(a); /*this should never happen*/
+else print_hex(a);
+}
+
+@ The next subroutine will descend to another level of recursion when a
+subsidiary mlist needs to be displayed. The parameter |c| indicates what
+character is to become part of the recursion history. An empty mlist is
+distinguished from a field with |math_type(p)==empty|, because these are
+not equivalent (as explained above).
+@^recursion@>
+
+@<Declare procedures needed for displaying...@>=
+void show_info(void); /*|show_node_list(info(temp_ptr))|*/
+void print_subsidiary_data(pointer @!p, ASCII_code @!c)
+ /*display a noad field*/
+{@+if (cur_length >= depth_threshold)
+ {@+if (math_type(p)!=empty) print_str(" []");
+ }
+else{@+append_char(c); /*include |c| in the recursion history*/
+ temp_ptr=p; /*prepare for |show_info| if recursion is needed*/
+ switch (math_type(p)) {
+ case math_char: {@+print_ln();print_current_string();print_fam_and_char(p);
+ } @+break;
+ case sub_box: show_info();@+break; /*recursive call*/
+ case sub_mlist: if (info(p)==null)
+ {@+print_ln();print_current_string();print_str("{}");
+ }
+ else show_info();@+break; /*recursive call*/
+ default:do_nothing; /*|empty|*/
+ } @/
+ flush_char; /*remove |c| from the recursion history*/
+ }
+}
+
+@ The inelegant introduction of |show_info| in the code above seems better
+than the alternative of using \PASCAL's strange |forward| declaration for a
+procedure with parameters. The \PASCAL\ convention about dropping parameters
+from a post-|forward| procedure is, frankly, so intolerable to the author
+of \TeX\ that he would rather stoop to communication via a global temporary
+variable. (A similar stoopidity occurred with respect to |hlist_out| and
+|vlist_out| above, and it will occur with respect to |mlist_to_hlist| below.)
+@^Knuth, Donald Ervin@>
+@:PASCAL}{\PASCAL@>
+
+@p void show_info(void) /*the reader will kindly forgive this*/
+{@+show_node_list(info(temp_ptr));
+}
+
+@ @<Declare procedures needed for displaying...@>=
+void print_style(int @!c)
+{@+switch (c/2) {
+case 0: print_esc(@[@<|"displaystyle"|@>@]);@+break; /*|display_style==0|*/
+case 1: print_esc(@[@<|"textstyle"|@>@]);@+break; /*|text_style==2|*/
+case 2: print_esc(@[@<|"scriptstyle"|@>@]);@+break; /*|script_style==4|*/
+case 3: print_esc(@[@<|"scriptscriptstyle"|@>@]);@+break; /*|script_script_style==6|*/
+default:print_str("Unknown style!");
+}
+}
+
+@ @<Display choice node |p|@>=
+{@+print_esc(@[@<|"mathchoice"|@>@]);
+append_char('D');show_node_list(display_mlist(p));flush_char;
+append_char('T');show_node_list(text_mlist(p));flush_char;
+append_char('S');show_node_list(script_mlist(p));flush_char;
+append_char('s');show_node_list(script_script_mlist(p));flush_char;
+}
+
+@ @<Display normal noad |p|@>=
+{@+switch (type(p)) {
+case ord_noad: print_esc(@[@<|"mathord"|@>@]);@+break;
+case op_noad: print_esc(@[@<|"mathop"|@>@]);@+break;
+case bin_noad: print_esc(@[@<|"mathbin"|@>@]);@+break;
+case rel_noad: print_esc(@[@<|"mathrel"|@>@]);@+break;
+case open_noad: print_esc(@[@<|"mathopen"|@>@]);@+break;
+case close_noad: print_esc(@[@<|"mathclose"|@>@]);@+break;
+case punct_noad: print_esc(@[@<|"mathpunct"|@>@]);@+break;
+case inner_noad: print_esc(@[@<|"mathinner"|@>@]);@+break;
+case over_noad: print_esc(@[@<|"overline"|@>@]);@+break;
+case under_noad: print_esc(@[@<|"underline"|@>@]);@+break;
+case vcenter_noad: print_esc(@[@<|"vcenter"|@>@]);@+break;
+case radical_noad: {@+print_esc(@[@<|"radical"|@>@]);print_delimiter(left_delimiter(p));
+ } @+break;
+case accent_noad: {@+print_esc(@[@<|"accent"|@>@]);print_fam_and_char(accent_chr(p));
+ } @+break;
+case left_noad: {@+print_esc(@[@<|"left"|@>@]);print_delimiter(delimiter(p));
+ } @+break;
+case right_noad: {@+print_esc(@[@<|"right"|@>@]);print_delimiter(delimiter(p));
+ }
+}
+if (subtype(p)!=normal)
+ if (subtype(p)==limits) print_esc(@[@<|"limits"|@>@]);
+ else print_esc(@[@<|"nolimits"|@>@]);
+if (type(p) < left_noad) print_subsidiary_data(nucleus(p),'.');
+print_subsidiary_data(supscr(p),'^');
+print_subsidiary_data(subscr(p),'_');
+}
+
+@ @<Display fraction noad |p|@>=
+{@+print_esc(@[@<|"fraction, thickness "|@>@]);
+if (thickness(p)==default_code) print_str("= default");
+else print_scaled(thickness(p));
+if ((small_fam(left_delimiter(p))!=0)||@+
+ (small_char(left_delimiter(p))!=min_quarterword)||@|
+ (large_fam(left_delimiter(p))!=0)||@|
+ (large_char(left_delimiter(p))!=min_quarterword))
+ {@+print_str(", left-delimiter ");print_delimiter(left_delimiter(p));
+ }
+if ((small_fam(right_delimiter(p))!=0)||@|
+ (small_char(right_delimiter(p))!=min_quarterword)||@|
+ (large_fam(right_delimiter(p))!=0)||@|
+ (large_char(right_delimiter(p))!=min_quarterword))
+ {@+print_str(", right-delimiter ");print_delimiter(right_delimiter(p));
+ }
+print_subsidiary_data(numerator(p),'\\');
+print_subsidiary_data(denominator(p),'/');
+}
+
+@ That which can be displayed can also be destroyed.
+
+@<Cases of |flush_node_list| that arise...@>=
+case style_node: {@+free_node(p, style_node_size);goto done;
+ }
+case choice_node: {@+flush_node_list(display_mlist(p));
+ flush_node_list(text_mlist(p));
+ flush_node_list(script_mlist(p));
+ flush_node_list(script_script_mlist(p));
+ free_node(p, style_node_size);goto done;
+ }
+case ord_noad: case op_noad: case bin_noad: case rel_noad: case open_noad: case close_noad: case punct_noad: case inner_noad:
+ case radical_noad: case over_noad: case under_noad: case vcenter_noad: case accent_noad: @t@>@;@/
+ {@+if (math_type(nucleus(p)) >= sub_box)
+ flush_node_list(info(nucleus(p)));
+ if (math_type(supscr(p)) >= sub_box)
+ flush_node_list(info(supscr(p)));
+ if (math_type(subscr(p)) >= sub_box)
+ flush_node_list(info(subscr(p)));
+ if (type(p)==radical_noad) free_node(p, radical_noad_size);
+ else if (type(p)==accent_noad) free_node(p, accent_noad_size);
+ else free_node(p, noad_size);
+ goto done;
+ }
+case left_noad: case right_noad: {@+free_node(p, noad_size);goto done;
+ }
+case fraction_noad: {@+flush_node_list(info(numerator(p)));
+ flush_node_list(info(denominator(p)));
+ free_node(p, fraction_noad_size);goto done;
+ }
+
+@* Subroutines for math mode.
+In order to convert mlists to hlists, i.e., noads to nodes, we need several
+subroutines that are conveniently dealt with now.
+
+Let us first introduce the macros that make it easy to get at the parameters and
+other font information. A size code, which is a multiple of 16, is added to a
+family number to get an index into the table of internal font numbers
+for each combination of family and size. (Be alert: Size codes get
+larger as the type gets smaller.)
+
+@d text_size 0 /*size code for the largest size in a family*/
+@d script_size 16 /*size code for the medium size in a family*/
+@d script_script_size 32 /*size code for the smallest size in a family*/
+
+@<Basic printing procedures@>=
+void print_size(int @!s)
+{@+if (s==text_size) print_esc(@[@<|"textfont"|@>@]);
+else if (s==script_size) print_esc(@[@<|"scriptfont"|@>@]);
+else print_esc(@[@<|"scriptscriptfont"|@>@]);
+}
+
+@ Before an mlist is converted to an hlist, \TeX\ makes sure that
+the fonts in family~2 have enough parameters to be math-symbol
+fonts, and that the fonts in family~3 have enough parameters to be
+math-extension fonts. The math-symbol parameters are referred to by using the
+following macros, which take a size code as their parameter; for example,
+|num1(cur_size)| gives the value of the |num1| parameter for the current size.
+@^parameters for symbols@>
+@^font parameters@>
+
+@d mathsy_end(X) fam_fnt(2+X)]].sc
+@d mathsy(X) font_info[X+param_base[mathsy_end
+@d math_x_height mathsy(5) /*height of `\.x'*/
+@d math_quad mathsy(6) /*\.{18mu}*/
+@d num1 mathsy(8) /*numerator shift-up in display styles*/
+@d num2 mathsy(9) /*numerator shift-up in non-display, non-\.{\\atop}*/
+@d num3 mathsy(10) /*numerator shift-up in non-display \.{\\atop}*/
+@d denom1 mathsy(11) /*denominator shift-down in display styles*/
+@d denom2 mathsy(12) /*denominator shift-down in non-display styles*/
+@d sup1 mathsy(13) /*superscript shift-up in uncramped display style*/
+@d sup2 mathsy(14) /*superscript shift-up in uncramped non-display*/
+@d sup3 mathsy(15) /*superscript shift-up in cramped styles*/
+@d sub1 mathsy(16) /*subscript shift-down if superscript is absent*/
+@d sub2 mathsy(17) /*subscript shift-down if superscript is present*/
+@d sup_drop mathsy(18) /*superscript baseline below top of large box*/
+@d sub_drop mathsy(19) /*subscript baseline below bottom of large box*/
+@d delim1 mathsy(20) /*size of \.{\\atopwithdelims} delimiters
+ in display styles*/
+@d delim2 mathsy(21) /*size of \.{\\atopwithdelims} delimiters in non-displays*/
+@d axis_height mathsy(22) /*height of fraction lines above the baseline*/
+@d total_mathsy_params 22
+
+@ The math-extension parameters have similar macros, but the size code is
+omitted (since it is always |cur_size| when we refer to such parameters).
+@^parameters for symbols@>
+@^font parameters@>
+
+@d mathex(X) font_info[X+param_base[fam_fnt(3+cur_size)]].sc
+@d default_rule_thickness mathex(8) /*thickness of \.{\\over} bars*/
+@d big_op_spacing1 mathex(9) /*minimum clearance above a displayed op*/
+@d big_op_spacing2 mathex(10) /*minimum clearance below a displayed op*/
+@d big_op_spacing3 mathex(11) /*minimum baselineskip above displayed op*/
+@d big_op_spacing4 mathex(12) /*minimum baselineskip below displayed op*/
+@d big_op_spacing5 mathex(13) /*padding above and below displayed limits*/
+@d total_mathex_params 13
+
+@ We also need to compute the change in style between mlists and their
+subsidiaries. The following macros define the subsidiary style for
+an overlined nucleus (|cramped_style|), for a subscript or a superscript
+(|sub_style| or |sup_style|), or for a numerator or denominator (|num_style|
+or |denom_style|).
+
+@d cramped_style(X) 2*(X/2)+cramped /*cramp the style*/
+@d sub_style(X) 2*(X/4)+script_style+cramped /*smaller and cramped*/
+@d sup_style(X) 2*(X/4)+script_style+(X%2) /*smaller*/
+@d num_style(X) X+2-2*(X/6) /*smaller unless already script-script*/
+@d denom_style(X) 2*(X/2)+cramped+2-2*(X/6) /*smaller, cramped*/
+
+@ When the style changes, the following piece of program computes associated
+information:
+
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>=
+{@+if (cur_style < script_style) cur_size=text_size;
+else cur_size=16*((cur_style-text_style)/2);
+cur_mu=x_over_n(math_quad(cur_size), 18);
+}
+
+@ Here is a function that returns a pointer to a rule node having a given
+thickness |t|. The rule will extend horizontally to the boundary of the vlist
+that eventually contains it.
+
+@p pointer fraction_rule(scaled @!t)
+ /*construct the bar for a fraction*/
+{@+pointer p; /*the new node*/
+p=new_rule();height(p)=t;depth(p)=0;return p;
+}
+
+@ The |overbar| function returns a pointer to a vlist box that consists of
+a given box |b|, above which has been placed a kern of height |k| under a
+fraction rule of thickness |t| under additional space of height |t|.
+
+@p pointer overbar(pointer @!b, scaled @!k, scaled @!t)
+{@+pointer p, @!q; /*nodes being constructed*/
+p=new_kern(k);link(p)=b;q=fraction_rule(t);link(q)=p;
+p=new_kern(t);link(p)=q;return vpack(p, natural);
+}
+
+@ The |var_delimiter| function, which finds or constructs a sufficiently
+large delimiter, is the most interesting of the auxiliary functions that
+currently concern us. Given a pointer |d| to a delimiter field in some noad,
+together with a size code |s| and a vertical distance |v|, this function
+returns a pointer to a box that contains the smallest variant of |d| whose
+height plus depth is |v| or more. (And if no variant is large enough, it
+returns the largest available variant.) In particular, this routine will
+construct arbitrarily large delimiters from extensible components, if
+|d| leads to such characters.
+
+The value returned is a box whose |shift_amount| has been set so that
+the box is vertically centered with respect to the axis in the given size.
+If a built-up symbol is returned, the height of the box before shifting
+will be the height of its topmost component.
+
+@p@t\4@>@<Declare subprocedures for |var_delimiter|@>@;
+pointer var_delimiter(pointer @!d, small_number @!s, scaled @!v)
+{@+
+pointer b; /*the box that will be constructed*/
+internal_font_number @!f, @!g; /*best-so-far and tentative font codes*/
+quarterword @!c, @!x, @!y; /*best-so-far and tentative character codes*/
+int @!m, @!n; /*the number of extensible pieces*/
+scaled @!u; /*height-plus-depth of a tentative character*/
+scaled @!w; /*largest height-plus-depth so far*/
+four_quarters @!q; /*character info*/
+eight_bits @!hd; /*height-depth byte*/
+four_quarters @!r; /*extensible pieces*/
+small_number @!z; /*runs through font family members*/
+bool @!large_attempt; /*are we trying the ``large'' variant?*/
+f=null_font;w=0;large_attempt=false;
+z=small_fam(d);x=small_char(d);
+loop@+{@+@<Look at the variants of |(z,x)|; set |f| and |c| whenever a better character
+is found; |goto found| as soon as a large enough variant is encountered@>;
+ if (large_attempt) goto found; /*there were none large enough*/
+ large_attempt=true;z=large_fam(d);x=large_char(d);
+ }
+found: if (f!=null_font)
+ @<Make variable |b| point to a box for |(f,c)|@>;
+else{@+b=new_null_box();
+ width(b)=null_delimiter_space; /*use this width if no delimiter was found*/
+ }
+shift_amount(b)=half(height(b)-depth(b))-axis_height(s);
+return b;
+}
+
+@ The search process is complicated slightly by the facts that some of the
+characters might not be present in some of the fonts, and they might not
+be probed in increasing order of height.
+
+@<Look at the variants of |(z,x)|; set |f| and |c|...@>=
+if ((z!=0)||(x!=min_quarterword))
+ {@+z=z+s+16;
+ @/do@+{z=z-16;g=fam_fnt(z);
+ if (g!=null_font)
+ @<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@>;
+ }@+ while (!(z < 16));
+ }
+
+@ @<Look at the list of characters starting with |x|...@>=
+{@+y=x;
+if ((qo(y) >= font_bc[g])&&(qo(y) <= font_ec[g]))
+ {@+resume: q=char_info(g)(y);
+ if (char_exists(q))
+ {@+if (char_tag(q)==ext_tag)
+ {@+f=g;c=y;goto found;
+ }
+ hd=height_depth(q);
+ u=char_height(g)(hd)+char_depth(g)(hd);
+ if (u > w)
+ {@+f=g;c=y;w=u;
+ if (u >= v) goto found;
+ }
+ if (char_tag(q)==list_tag)
+ {@+y=rem_byte(q);goto resume;
+ }
+ }
+ }
+}
+
+@ Here is a subroutine that creates a new box, whose list contains a
+single character, and whose width includes the italic correction for
+that character. The height or depth of the box will be negative, if
+the height or depth of the character is negative; thus, this routine
+may deliver a slightly different result than |hpack| would produce.
+
+@<Declare subprocedures for |var_delimiter|@>=
+pointer char_box(internal_font_number @!f, quarterword @!c)
+{@+four_quarters q;
+eight_bits @!hd; /*|height_depth| byte*/
+pointer @!b, @!p; /*the new box and its character node*/
+q=char_info(f)(c);hd=height_depth(q);
+b=new_null_box();width(b)=char_width(f)(q)+char_italic(f)(q);
+height(b)=char_height(f)(hd);depth(b)=char_depth(f)(hd);
+p=get_avail();character(p)=c;font(p)=f;list_ptr(b)=p;return b;
+}
+
+@ When the following code is executed, |char_tag(q)| will be equal to
+|ext_tag| if and only if a built-up symbol is supposed to be returned.
+
+@<Make variable |b| point to a box for |(f,c)|@>=
+if (char_tag(q)==ext_tag)
+ @<Construct an extensible character in a new box |b|, using recipe |rem_byte(q)|
+and font |f|@>@;
+else b=char_box(f, c)
+
+@ When we build an extensible character, it's handy to have the
+following subroutine, which puts a given character on top
+of the characters already in box |b|:
+
+@<Declare subprocedures for |var_delimiter|@>=
+void stack_into_box(pointer @!b, internal_font_number @!f,
+ quarterword @!c)
+{@+pointer p; /*new node placed into |b|*/
+p=char_box(f, c);link(p)=list_ptr(b);list_ptr(b)=p;
+height(b)=height(p);
+}
+
+@ Another handy subroutine computes the height plus depth of
+a given character:
+
+@<Declare subprocedures for |var_delimiter|@>=
+scaled height_plus_depth(internal_font_number @!f, quarterword @!c)
+{@+four_quarters q;
+eight_bits @!hd; /*|height_depth| byte*/
+q=char_info(f)(c);hd=height_depth(q);
+return char_height(f)(hd)+char_depth(f)(hd);
+}
+
+@ @<Construct an extensible...@>=
+{@+b=new_null_box();
+type(b)=vlist_node;
+r=font_info[exten_base[f]+rem_byte(q)].qqqq;@/
+@<Compute the minimum suitable height, |w|, and the corresponding number of extension
+steps, |n|; also set |width(b)|@>;
+c=ext_bot(r);
+if (c!=min_quarterword) stack_into_box(b, f, c);
+c=ext_rep(r);
+for (m=1; m<=n; m++) stack_into_box(b, f, c);
+c=ext_mid(r);
+if (c!=min_quarterword)
+ {@+stack_into_box(b, f, c);c=ext_rep(r);
+ for (m=1; m<=n; m++) stack_into_box(b, f, c);
+ }
+c=ext_top(r);
+if (c!=min_quarterword) stack_into_box(b, f, c);
+depth(b)=w-height(b);
+}
+
+@ The width of an extensible character is the width of the repeatable
+module. If this module does not have positive height plus depth,
+we don't use any copies of it, otherwise we use as few as possible
+(in groups of two if there is a middle part).
+
+@<Compute the minimum suitable height, |w|, and...@>=
+c=ext_rep(r);u=height_plus_depth(f, c);
+w=0;q=char_info(f)(c);width(b)=char_width(f)(q)+char_italic(f)(q);@/
+c=ext_bot(r);@+if (c!=min_quarterword) w=w+height_plus_depth(f, c);
+c=ext_mid(r);@+if (c!=min_quarterword) w=w+height_plus_depth(f, c);
+c=ext_top(r);@+if (c!=min_quarterword) w=w+height_plus_depth(f, c);
+n=0;
+if (u > 0) while (w < v)
+ {@+w=w+u;incr(n);
+ if (ext_mid(r)!=min_quarterword) w=w+u;
+ }
+
+@ The next subroutine is much simpler; it is used for numerators and
+denominators of fractions as well as for displayed operators and
+their limits above and below. It takes a given box~|b| and
+changes it so that the new box is centered in a box of width~|w|.
+The centering is done by putting \.{\\hss} glue at the left and right
+of the list inside |b|, then packaging the new box; thus, the
+actual box might not really be centered, if it already contains
+infinite glue.
+
+The given box might contain a single character whose italic correction
+has been added to the width of the box; in this case a compensating
+kern is inserted.
+
+@p pointer rebox(pointer @!b, scaled @!w)
+{@+pointer p; /*temporary register for list manipulation*/
+internal_font_number @!f; /*font in a one-character box*/
+scaled @!v; /*width of a character without italic correction*/
+if ((width(b)!=w)&&(list_ptr(b)!=null))
+ {@+if (type(b)==vlist_node) b=hpack(b, natural);
+ p=list_ptr(b);
+ if ((is_char_node(p))&&(link(p)==null))
+ {@+f=font(p);v=char_width(f)(char_info(f)(character(p)));
+ if (v!=width(b)) link(p)=new_kern(width(b)-v);
+ }
+ free_node(b, box_node_size);
+ b=new_glue(ss_glue);link(b)=p;
+ while (link(p)!=null) p=link(p);
+ link(p)=new_glue(ss_glue);
+ return hpack(b, w, exactly);
+ }
+else{@+width(b)=w;return b;
+ }
+}
+
+@ Here is a subroutine that creates a new glue specification from another
+one that is expressed in `\.{mu}', given the value of the math unit.
+
+@d mu_mult(X) nx_plus_y(n, X, xn_over_d(X, f, 0200000))
+
+@p pointer math_glue(pointer @!g, scaled @!m)
+{@+pointer p; /*the new glue specification*/
+int @!n; /*integer part of |m|*/
+scaled @!f; /*fraction part of |m|*/
+n=x_over_n(m, 0200000);f=rem;@/
+if (f < 0)
+ {@+decr(n);f=f+0200000;
+ }
+p=get_node(glue_spec_size);
+width(p)=mu_mult(width(g)); /*convert \.{mu} to \.{pt}*/
+stretch_order(p)=stretch_order(g);
+if (stretch_order(p)==normal) stretch(p)=mu_mult(stretch(g));
+else stretch(p)=stretch(g);
+shrink_order(p)=shrink_order(g);
+if (shrink_order(p)==normal) shrink(p)=mu_mult(shrink(g));
+else shrink(p)=shrink(g);
+return p;
+}
+
+@ The |math_kern| subroutine removes |mu_glue| from a kern node, given
+the value of the math unit.
+
+@p void math_kern(pointer @!p, scaled @!m)
+{@+int @!n; /*integer part of |m|*/
+scaled @!f; /*fraction part of |m|*/
+if (subtype(p)==mu_glue)
+ {@+n=x_over_n(m, 0200000);f=rem;@/
+ if (f < 0)
+ {@+decr(n);f=f+0200000;
+ }
+ width(p)=mu_mult(width(p));subtype(p)=explicit;
+ }
+}
+
+@ Sometimes it is necessary to destroy an mlist. The following
+subroutine empties the current list, assuming that |abs(mode)==mmode|.
+
+@p void flush_math(void)
+{@+flush_node_list(link(head));flush_node_list(incompleat_noad);
+link(head)=null;tail=head;incompleat_noad=null;
+}
+
+@* Typesetting math formulas.
+\TeX's most important routine for dealing with formulas is called
+|mlist_to_hlist|. After a formula has been scanned and represented as an
+mlist, this routine converts it to an hlist that can be placed into a box
+or incorporated into the text of a paragraph. There are three implicit
+parameters, passed in global variables: |cur_mlist| points to the first
+node or noad in the given mlist (and it might be |null|); |cur_style| is a
+style code; and |mlist_penalties| is |true| if penalty nodes for potential
+line breaks are to be inserted into the resulting hlist. After
+|mlist_to_hlist| has acted, |link(temp_head)| points to the translated hlist.
+
+Since mlists can be inside mlists, the procedure is recursive. And since this
+is not part of \TeX's inner loop, the program has been written in a manner
+that stresses compactness over efficiency.
+@^recursion@>
+
+@<Glob...@>=
+pointer @!cur_mlist; /*beginning of mlist to be translated*/
+small_number @!cur_style; /*style code at current place in the list*/
+small_number @!cur_size; /*size code corresponding to |cur_style|*/
+scaled @!cur_mu; /*the math unit width corresponding to |cur_size|*/
+bool @!mlist_penalties; /*should |mlist_to_hlist| insert penalties?*/
+
+@ The recursion in |mlist_to_hlist| is due primarily to a subroutine
+called |clean_box| that puts a given noad field into a box using a given
+math style; |mlist_to_hlist| can call |clean_box|, which can call
+|mlist_to_hlist|.
+@^recursion@>
+
+The box returned by |clean_box| is ``clean'' in the
+sense that its |shift_amount| is zero.
+
+@p void mlist_to_hlist(void);@/
+pointer clean_box(pointer @!p, small_number @!s)
+{@+
+pointer q; /*beginning of a list to be boxed*/
+small_number @!save_style; /*|cur_style| to be restored*/
+pointer @!x; /*box to be returned*/
+pointer @!r; /*temporary pointer*/
+switch (math_type(p)) {
+case math_char: {@+cur_mlist=new_noad();mem[nucleus(cur_mlist)]=mem[p];
+ } @+break;
+case sub_box: {@+q=info(p);goto found;
+ }
+case sub_mlist: cur_mlist=info(p);@+break;
+default:{@+q=new_null_box();goto found;
+ }
+} @/
+save_style=cur_style;cur_style=s;mlist_penalties=false;@/
+mlist_to_hlist();q=link(temp_head); /*recursive call*/
+cur_style=save_style; /*restore the style*/
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+found: if (is_char_node(q)||(q==null)) x=hpack(q, natural);
+ else if ((link(q)==null)&&(type(q) <= vlist_node)&&(shift_amount(q)==0))
+ x=q; /*it's already clean*/
+ else x=hpack(q, natural);
+@<Simplify a trivial box@>;
+return x;
+}
+
+@ Here we save memory space in a common case.
+
+@<Simplify a trivial box@>=
+q=list_ptr(x);
+if (is_char_node(q))
+ {@+r=link(q);
+ if (r!=null) if (link(r)==null) if (!is_char_node(r))
+ if (type(r)==kern_node) /*unneeded italic correction*/
+ {@+free_node(r, small_node_size);link(q)=null;
+ }
+ }
+
+@ It is convenient to have a procedure that converts a |math_char|
+field to an ``unpacked'' form. The |fetch| routine sets |cur_f|, |cur_c|,
+and |cur_i| to the font code, character code, and character information bytes of
+a given noad field. It also takes care of issuing error messages for
+nonexistent characters; in such cases, |char_exists(cur_i)| will be |false|
+after |fetch| has acted, and the field will also have been reset to |empty|.
+
+@p void fetch(pointer @!a) /*unpack the |math_char| field |a|*/
+{@+cur_c=character(a);cur_f=fam_fnt(fam(a)+cur_size);
+if (cur_f==null_font)
+ @<Complain about an undefined family and set |cur_i| null@>@;
+else{@+if ((qo(cur_c) >= font_bc[cur_f])&&(qo(cur_c) <= font_ec[cur_f]))
+ cur_i=char_info(cur_f)(cur_c);
+ else cur_i=null_character;
+ if (!(char_exists(cur_i)))
+ {@+char_warning(cur_f, qo(cur_c));
+ math_type(a)=empty;
+ }
+ }
+}
+
+@ @<Complain about an undefined family...@>=
+{@+print_err("");print_size(cur_size);print_char(' ');
+print_int(fam(a));print_str(" is undefined (character ");
+print_ASCII(qo(cur_c));print_char(')');
+help4("Somewhere in the math formula just ended, you used the")@/
+("stated character from an undefined font family. For example,")@/
+("plain TeX doesn't allow \\it or \\sl in subscripts. Proceed,")@/
+("and I'll try to forget that I needed that character.");
+error();cur_i=null_character;math_type(a)=empty;
+}
+
+@ The outputs of |fetch| are placed in global variables.
+
+@<Glob...@>=
+internal_font_number @!cur_f; /*the |font| field of a |math_char|*/
+quarterword @!cur_c; /*the |character| field of a |math_char|*/
+four_quarters @!cur_i; /*the |char_info| of a |math_char|,
+ or a lig/kern instruction*/
+
+@ We need to do a lot of different things, so |mlist_to_hlist| makes two
+passes over the given mlist.
+
+The first pass does most of the processing: It removes ``mu'' spacing from
+glue, it recursively evaluates all subsidiary mlists so that only the
+top-level mlist remains to be handled, it puts fractions and square roots
+and such things into boxes, it attaches subscripts and superscripts, and
+it computes the overall height and depth of the top-level mlist so that
+the size of delimiters for a |left_noad| and a |right_noad| will be known.
+The hlist resulting from each noad is recorded in that noad's |new_hlist|
+field, an integer field that replaces the |nucleus| or |thickness|.
+@^recursion@>
+
+The second pass eliminates all noads and inserts the correct glue and
+penalties between nodes.
+
+@d new_hlist(X) mem[nucleus(X)].i /*the translation of an mlist*/
+
+@ Here is the overall plan of |mlist_to_hlist|, and the list of its
+local variables.
+
+@p@t\4@>@<Declare math construction procedures@>@;
+void mlist_to_hlist(void)
+{@+
+
+pointer mlist; /*beginning of the given list*/
+bool @!penalties; /*should penalty nodes be inserted?*/
+small_number @!style; /*the given style*/
+small_number @!save_style; /*holds |cur_style| during recursion*/
+pointer @!q; /*runs through the mlist*/
+pointer @!r; /*the most recent noad preceding |q|*/
+small_number @!r_type; /*the |type| of noad |r|, or |op_noad| if |r==null|*/
+small_number @!t; /*the effective |type| of noad |q| during the second pass*/
+pointer @!p, @!x, @!y, @!z; /*temporary registers for list construction*/
+int @!pen; /*a penalty to be inserted*/
+small_number @!s; /*the size of a noad to be deleted*/
+scaled @!max_h, @!max_d; /*maximum height and depth of the list translated so far*/
+scaled @!delta; /*offset between subscript and superscript*/
+mlist=cur_mlist;penalties=mlist_penalties;
+style=cur_style; /*tuck global parameters away as local variables*/
+q=mlist;r=null;r_type=op_noad;max_h=0;max_d=0;
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+while (q!=null) @<Process node-or-noad |q| as much as possible in preparation for
+the second pass of |mlist_to_hlist|, then move to the next item in the mlist@>;
+@<Convert \(a)a final |bin_noad| to an |ord_noad|@>;
+@<Make a second pass over the mlist, removing all noads and inserting the proper spacing
+and penalties@>;
+}
+
+@ We use the fact that no character nodes appear in an mlist, hence
+the field |type(q)| is always present.
+
+@<Process node-or-noad...@>=
+{@+@<Do first-pass processing based on |type(q)|; |goto done_with_noad| if a noad
+has been fully processed, |goto check_dimensions| if it has been translated into |new_hlist(q)|,
+or |goto done_with_node| if a node has been fully processed@>;
+check_dimensions: z=hpack(new_hlist(q), natural);
+if (height(z) > max_h) max_h=height(z);
+if (depth(z) > max_d) max_d=depth(z);
+free_node(z, box_node_size);
+done_with_noad: r=q;r_type=type(r);
+done_with_node: q=link(q);
+}
+
+@ One of the things we must do on the first pass is change a |bin_noad| to
+an |ord_noad| if the |bin_noad| is not in the context of a binary operator.
+The values of |r| and |r_type| make this fairly easy.
+
+@<Do first-pass processing...@>=
+reswitch: delta=0;
+switch (type(q)) {
+case bin_noad: switch (r_type) {
+ case bin_noad: case op_noad: case rel_noad: case open_noad: case punct_noad: case left_noad:
+ {@+type(q)=ord_noad;goto reswitch;
+ }
+ default:do_nothing;
+ } @+break;
+case rel_noad: case close_noad: case punct_noad: case right_noad: {@+@t@>@;@/
+ @<Convert \(a)a final |bin_noad| to an |ord_noad|@>;
+ if (type(q)==right_noad) goto done_with_noad;
+ } @+break;
+@t\4@>@<Cases for noads that can follow a |bin_noad|@>@;
+@t\4@>@<Cases for nodes that can appear in an mlist, after which we |goto done_with_node|@>@;
+default:confusion(@[@<|"mlist1"|@>@]);
+@:this can't happen mlist1}{\quad mlist1@>
+} @/
+@<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@>@;
+
+@ @<Convert \(a)a final |bin_noad| to an |ord_noad|@>=
+if (r_type==bin_noad) type(r)=ord_noad
+
+@ @<Cases for nodes that can appear in an mlist...@>=
+case style_node: {@+cur_style=subtype(q);
+ @<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+ goto done_with_node;
+ }
+case choice_node: @<Change this node to a style node followed by the correct choice,
+then |goto done_with_node|@>@;
+case ins_node: case mark_node: case adjust_node:
+ case whatsit_node: case penalty_node: case disc_node: goto done_with_node;
+case rule_node: {@+if (height(q) > max_h) max_h=height(q);
+ if (depth(q) > max_d) max_d=depth(q);goto done_with_node;
+ }
+case glue_node: {@+@<Convert \(m)math glue to ordinary glue@>;
+ goto done_with_node;
+ }
+case kern_node: {@+math_kern(q, cur_mu);goto done_with_node;
+ }
+
+@ @d choose_mlist(X) {@+p=X(q);X(q)=null;@+}
+
+@<Change this node to a style node...@>=
+{@+switch (cur_style/2) {
+case 0: choose_mlist(display_mlist)@;@+break; /*|display_style==0|*/
+case 1: choose_mlist(text_mlist)@;@+break; /*|text_style==2|*/
+case 2: choose_mlist(script_mlist)@;@+break; /*|script_style==4|*/
+case 3: choose_mlist(script_script_mlist); /*|script_script_style==6|*/
+} /*there are no other cases*/
+flush_node_list(display_mlist(q));
+flush_node_list(text_mlist(q));
+flush_node_list(script_mlist(q));
+flush_node_list(script_script_mlist(q));@/
+type(q)=style_node;subtype(q)=cur_style;width(q)=0;depth(q)=0;
+if (p!=null)
+ {@+z=link(q);link(q)=p;
+ while (link(p)!=null) p=link(p);
+ link(p)=z;
+ }
+goto done_with_node;
+}
+
+@ Conditional math glue (`\.{\\nonscript}') results in a |glue_node|
+pointing to |zero_glue|, with |subtype(q)==cond_math_glue|; in such a case
+the node following will be eliminated if it is a glue or kern node and if the
+current size is different from |text_size|. Unconditional math glue
+(`\.{\\muskip}') is converted to normal glue by multiplying the dimensions
+by |cur_mu|.
+@!@:non_script_}{\.{\\nonscript} primitive@>
+
+@<Convert \(m)math glue to ordinary glue@>=
+if (subtype(q)==mu_glue)
+ {@+x=glue_ptr(q);
+ y=math_glue(x, cur_mu);delete_glue_ref(x);glue_ptr(q)=y;
+ subtype(q)=normal;
+ }
+else if ((cur_size!=text_size)&&(subtype(q)==cond_math_glue))
+ {@+p=link(q);
+ if (p!=null) if ((type(p)==glue_node)||(type(p)==kern_node))
+ {@+link(q)=link(p);link(p)=null;flush_node_list(p);
+ }
+ }
+
+@ @<Cases for noads that can follow a |bin_noad|@>=
+case left_noad: goto done_with_noad;
+case fraction_noad: {@+make_fraction(q);goto check_dimensions;
+ }
+case op_noad: {@+delta=make_op(q);
+ if (subtype(q)==limits) goto check_dimensions;
+ } @+break;
+case ord_noad: make_ord(q);@+break;
+case open_noad: case inner_noad: do_nothing;@+break;
+case radical_noad: make_radical(q);@+break;
+case over_noad: make_over(q);@+break;
+case under_noad: make_under(q);@+break;
+case accent_noad: make_math_accent(q);@+break;
+case vcenter_noad: make_vcenter(q);@+break;
+
+@ Most of the actual construction work of |mlist_to_hlist| is done
+by procedures with names
+like |make_fraction|, |make_radical|, etc. To illustrate
+the general setup of such procedures, let's begin with a couple of
+simple ones.
+
+@<Declare math...@>=
+void make_over(pointer @!q)
+{@+info(nucleus(q))=@|
+ overbar(clean_box(nucleus(q), cramped_style(cur_style)),@|
+ 3*default_rule_thickness, default_rule_thickness);
+math_type(nucleus(q))=sub_box;
+}
+
+@ @<Declare math...@>=
+void make_under(pointer @!q)
+{@+pointer p, @!x, @!y; /*temporary registers for box construction*/
+scaled @!delta; /*overall height plus depth*/
+x=clean_box(nucleus(q), cur_style);
+p=new_kern(3*default_rule_thickness);link(x)=p;
+link(p)=fraction_rule(default_rule_thickness);
+y=vpack(x, natural);
+delta=height(y)+depth(y)+default_rule_thickness;
+height(y)=height(x);depth(y)=delta-height(y);
+info(nucleus(q))=y;math_type(nucleus(q))=sub_box;
+}
+
+@ @<Declare math...@>=
+void make_vcenter(pointer @!q)
+{@+pointer v; /*the box that should be centered vertically*/
+scaled @!delta; /*its height plus depth*/
+v=info(nucleus(q));
+if (type(v)!=vlist_node) confusion(@[@<|"vcenter"|@>@]);
+@:this can't happen vcenter}{\quad vcenter@>
+delta=height(v)+depth(v);
+height(v)=axis_height(cur_size)+half(delta);
+depth(v)=delta-height(v);
+}
+
+@ According to the rules in the \.{DVI} file specifications, we ensure alignment
+@^square roots@>
+between a square root sign and the rule above its nucleus by assuming that the
+baseline of the square-root symbol is the same as the bottom of the rule. The
+height of the square-root symbol will be the thickness of the rule, and the
+depth of the square-root symbol should exceed or equal the height-plus-depth
+of the nucleus plus a certain minimum clearance~|clr|. The symbol will be
+placed so that the actual clearance is |clr| plus half the excess.
+
+@<Declare math...@>=
+void make_radical(pointer @!q)
+{@+pointer x, @!y; /*temporary registers for box construction*/
+scaled @!delta, @!clr; /*dimensions involved in the calculation*/
+x=clean_box(nucleus(q), cramped_style(cur_style));
+if (cur_style < text_style) /*display style*/
+ clr=default_rule_thickness+(abs(math_x_height(cur_size))/4);
+else{@+clr=default_rule_thickness;clr=clr+(abs(clr)/4);
+ }
+y=var_delimiter(left_delimiter(q), cur_size, height(x)+depth(x)+clr+
+ default_rule_thickness);
+delta=depth(y)-(height(x)+depth(x)+clr);
+if (delta > 0) clr=clr+half(delta); /*increase the actual clearance*/
+shift_amount(y)=-(height(x)+clr);
+link(y)=overbar(x, clr, height(y));
+info(nucleus(q))=hpack(y, natural);math_type(nucleus(q))=sub_box;
+}
+
+@ Slants are not considered when placing accents in math mode. The accenter is
+centered over the accentee, and the accent width is treated as zero with
+respect to the size of the final box.
+
+@<Declare math...@>=
+void make_math_accent(pointer @!q)
+{@+
+pointer p, @!x, @!y; /*temporary registers for box construction*/
+int @!a; /*address of lig/kern instruction*/
+quarterword @!c; /*accent character*/
+internal_font_number @!f; /*its font*/
+four_quarters @!i; /*its |char_info|*/
+scaled @!s; /*amount to skew the accent to the right*/
+scaled @!h; /*height of character being accented*/
+scaled @!delta; /*space to remove between accent and accentee*/
+scaled @!w; /*width of the accentee, not including sub/superscripts*/
+fetch(accent_chr(q));
+if (char_exists(cur_i))
+ {@+i=cur_i;c=cur_c;f=cur_f;@/
+ @<Compute the amount of skew@>;
+ x=clean_box(nucleus(q), cramped_style(cur_style));w=width(x);h=height(x);
+ @<Switch to a larger accent if available and appropriate@>;
+ if (h < x_height(f)) delta=h;@+else delta=x_height(f);
+ if ((math_type(supscr(q))!=empty)||(math_type(subscr(q))!=empty))
+ if (math_type(nucleus(q))==math_char)
+ @<Swap the subscript and superscript into box |x|@>;
+ y=char_box(f, c);
+ shift_amount(y)=s+half(w-width(y));
+ width(y)=0;p=new_kern(-delta);link(p)=x;link(y)=p;
+ y=vpack(y, natural);width(y)=width(x);
+ if (height(y) < h) @<Make the height of box |y| equal to |h|@>;
+ info(nucleus(q))=y;
+ math_type(nucleus(q))=sub_box;
+ }
+}
+
+@ @<Make the height of box |y|...@>=
+{@+p=new_kern(h-height(y));link(p)=list_ptr(y);list_ptr(y)=p;
+height(y)=h;
+}
+
+@ @<Switch to a larger accent if available and appropriate@>=
+loop@+{@+if (char_tag(i)!=list_tag) goto done;
+ y=rem_byte(i);
+ i=char_info(f)(y);
+ if (!char_exists(i)) goto done;
+ if (char_width(f)(i) > w) goto done;
+ c=y;
+ }
+done:
+
+@ @<Compute the amount of skew@>=
+s=0;
+if (math_type(nucleus(q))==math_char)
+ {@+fetch(nucleus(q));
+ if (char_tag(cur_i)==lig_tag)
+ {@+a=lig_kern_start(cur_f)(cur_i);
+ cur_i=font_info[a].qqqq;
+ if (skip_byte(cur_i) > stop_flag)
+ {@+a=lig_kern_restart(cur_f)(cur_i);
+ cur_i=font_info[a].qqqq;
+ }
+ loop@+{@+if (qo(next_char(cur_i))==skew_char[cur_f])
+ {@+if (op_byte(cur_i) >= kern_flag)
+ if (skip_byte(cur_i) <= stop_flag) s=char_kern(cur_f)(cur_i);
+ goto done1;
+ }
+ if (skip_byte(cur_i) >= stop_flag) goto done1;
+ a=a+qo(skip_byte(cur_i))+1;
+ cur_i=font_info[a].qqqq;
+ }
+ }
+ }
+done1:
+
+@ @<Swap the subscript and superscript into box |x|@>=
+{@+flush_node_list(x);x=new_noad();
+mem[nucleus(x)]=mem[nucleus(q)];
+mem[supscr(x)]=mem[supscr(q)];
+mem[subscr(x)]=mem[subscr(q)];@/
+mem[supscr(q)].hh=empty_field;
+mem[subscr(q)].hh=empty_field;@/
+math_type(nucleus(q))=sub_mlist;info(nucleus(q))=x;
+x=clean_box(nucleus(q), cur_style);delta=delta+height(x)-h;h=height(x);
+}
+
+@ The |make_fraction| procedure is a bit different because it sets
+|new_hlist(q)| directly rather than making a sub-box.
+
+@<Declare math...@>=
+void make_fraction(pointer @!q)
+{@+pointer p, @!v, @!x, @!y, @!z; /*temporary registers for box construction*/
+scaled @!delta, @!delta1, @!delta2, @!shift_up, @!shift_down, @!clr;
+ /*dimensions for box calculations*/
+if (thickness(q)==default_code) thickness(q)=default_rule_thickness;
+@<Create equal-width boxes |x| and |z| for the numerator and denominator, and compute
+the default amounts |shift_up| and |shift_down| by which they are displaced from the
+baseline@>;
+if (thickness(q)==0) @<Adjust \(s)|shift_up| and |shift_down| for the case of no fraction
+line@>@;
+else@<Adjust \(s)|shift_up| and |shift_down| for the case of a fraction line@>;
+@<Construct a vlist box for the fraction, according to |shift_up| and |shift_down|@>;
+@<Put the \(f)fraction into a box with its delimiters, and make |new_hlist(q)| point
+to it@>;
+}
+
+@ @<Create equal-width boxes |x| and |z| for the numerator and denom...@>=
+x=clean_box(numerator(q), num_style(cur_style));
+z=clean_box(denominator(q), denom_style(cur_style));
+if (width(x) < width(z)) x=rebox(x, width(z));
+else z=rebox(z, width(x));
+if (cur_style < text_style) /*display style*/
+ {@+shift_up=num1(cur_size);shift_down=denom1(cur_size);
+ }
+else{@+shift_down=denom2(cur_size);
+ if (thickness(q)!=0) shift_up=num2(cur_size);
+ else shift_up=num3(cur_size);
+ }
+
+@ The numerator and denominator must be separated by a certain minimum
+clearance, called |clr| in the following program. The difference between
+|clr| and the actual clearance is |2 delta|.
+
+@<Adjust \(s)|shift_up| and |shift_down| for the case of no fraction line@>=
+{@+if (cur_style < text_style) clr=7*default_rule_thickness;
+else clr=3*default_rule_thickness;
+delta=half(clr-((shift_up-depth(x))-(height(z)-shift_down)));
+if (delta > 0)
+ {@+shift_up=shift_up+delta;
+ shift_down=shift_down+delta;
+ }
+}
+
+@ In the case of a fraction line, the minimum clearance depends on the actual
+thickness of the line.
+
+@<Adjust \(s)|shift_up| and |shift_down| for the case of a fraction line@>=
+{@+if (cur_style < text_style) clr=3*thickness(q);
+else clr=thickness(q);
+delta=half(thickness(q));
+delta1=clr-((shift_up-depth(x))-(axis_height(cur_size)+delta));
+delta2=clr-((axis_height(cur_size)-delta)-(height(z)-shift_down));
+if (delta1 > 0) shift_up=shift_up+delta1;
+if (delta2 > 0) shift_down=shift_down+delta2;
+}
+
+@ @<Construct a vlist box for the fraction...@>=
+v=new_null_box();type(v)=vlist_node;
+height(v)=shift_up+height(x);depth(v)=depth(z)+shift_down;
+width(v)=width(x); /*this also equals |width(z)|*/
+if (thickness(q)==0)
+ {@+p=new_kern((shift_up-depth(x))-(height(z)-shift_down));
+ link(p)=z;
+ }
+else{@+y=fraction_rule(thickness(q));@/
+ p=new_kern((axis_height(cur_size)-delta)-@|(height(z)-shift_down));@/
+ link(y)=p;link(p)=z;@/
+ p=new_kern((shift_up-depth(x))-(axis_height(cur_size)+delta));
+ link(p)=y;
+ }
+link(x)=p;list_ptr(v)=x
+
+@ @<Put the \(f)fraction into a box with its delimiters...@>=
+if (cur_style < text_style) delta=delim1(cur_size);
+else delta=delim2(cur_size);
+x=var_delimiter(left_delimiter(q), cur_size, delta);link(x)=v;@/
+z=var_delimiter(right_delimiter(q), cur_size, delta);link(v)=z;@/
+new_hlist(q)=hpack(x, natural)
+
+@ If the nucleus of an |op_noad| is a single character, it is to be
+centered vertically with respect to the axis, after first being enlarged
+(via a character list in the font) if we are in display style. The normal
+convention for placing displayed limits is to put them above and below the
+operator in display style.
+
+The italic correction is removed from the character if there is a subscript
+and the limits are not being displayed. The |make_op|
+routine returns the value that should be used as an offset between
+subscript and superscript.
+
+After |make_op| has acted, |subtype(q)| will be |limits| if and only if
+the limits have been set above and below the operator. In that case,
+|new_hlist(q)| will already contain the desired final box.
+
+@<Declare math...@>=
+scaled make_op(pointer @!q)
+{@+scaled delta; /*offset between subscript and superscript*/
+pointer @!p, @!v, @!x, @!y, @!z; /*temporary registers for box construction*/
+quarterword @!c;@+four_quarters @!i; /*registers for character examination*/
+scaled @!shift_up, @!shift_down; /*dimensions for box calculation*/
+if ((subtype(q)==normal)&&(cur_style < text_style))
+ subtype(q)=limits;
+if (math_type(nucleus(q))==math_char)
+ {@+fetch(nucleus(q));
+ if ((cur_style < text_style)&&(char_tag(cur_i)==list_tag)) /*make it larger*/
+ {@+c=rem_byte(cur_i);i=char_info(cur_f)(c);
+ if (char_exists(i))
+ {@+cur_c=c;cur_i=i;character(nucleus(q))=c;
+ }
+ }
+ delta=char_italic(cur_f)(cur_i);x=clean_box(nucleus(q), cur_style);
+ if ((math_type(subscr(q))!=empty)&&(subtype(q)!=limits))
+ width(x)=width(x)-delta; /*remove italic correction*/
+ shift_amount(x)=half(height(x)-depth(x))-axis_height(cur_size);
+ /*center vertically*/
+ math_type(nucleus(q))=sub_box;info(nucleus(q))=x;
+ }
+else delta=0;
+if (subtype(q)==limits)
+ @<Construct a box with limits above and below it, skewed by |delta|@>;
+return delta;
+}
+
+@ The following program builds a vlist box |v| for displayed limits. The
+width of the box is not affected by the fact that the limits may be skewed.
+
+@<Construct a box with limits above and below it...@>=
+{@+x=clean_box(supscr(q), sup_style(cur_style));
+y=clean_box(nucleus(q), cur_style);
+z=clean_box(subscr(q), sub_style(cur_style));
+v=new_null_box();type(v)=vlist_node;width(v)=width(y);
+if (width(x) > width(v)) width(v)=width(x);
+if (width(z) > width(v)) width(v)=width(z);
+x=rebox(x, width(v));y=rebox(y, width(v));z=rebox(z, width(v));@/
+shift_amount(x)=half(delta);shift_amount(z)=-shift_amount(x);
+height(v)=height(y);depth(v)=depth(y);
+@<Attach the limits to |y| and adjust |height(v)|, |depth(v)| to account for their
+presence@>;
+new_hlist(q)=v;
+}
+
+@ We use |shift_up| and |shift_down| in the following program for the
+amount of glue between the displayed operator |y| and its limits |x| and
+|z|. The vlist inside box |v| will consist of |x| followed by |y| followed
+by |z|, with kern nodes for the spaces between and around them.
+
+@<Attach the limits to |y| and adjust |height(v)|, |depth(v)|...@>=
+if (math_type(supscr(q))==empty)
+ {@+free_node(x, box_node_size);list_ptr(v)=y;
+ }
+else{@+shift_up=big_op_spacing3-depth(x);
+ if (shift_up < big_op_spacing1) shift_up=big_op_spacing1;
+ p=new_kern(shift_up);link(p)=y;link(x)=p;@/
+ p=new_kern(big_op_spacing5);link(p)=x;list_ptr(v)=p;
+ height(v)=height(v)+big_op_spacing5+height(x)+depth(x)+shift_up;
+ }
+if (math_type(subscr(q))==empty) free_node(z, box_node_size);
+else{@+shift_down=big_op_spacing4-height(z);
+ if (shift_down < big_op_spacing2) shift_down=big_op_spacing2;
+ p=new_kern(shift_down);link(y)=p;link(p)=z;@/
+ p=new_kern(big_op_spacing5);link(z)=p;
+ depth(v)=depth(v)+big_op_spacing5+height(z)+depth(z)+shift_down;
+ }
+
+@ A ligature found in a math formula does not create a |ligature_node|, because
+there is no question of hyphenation afterwards; the ligature will simply be
+stored in an ordinary |char_node|, after residing in an |ord_noad|.
+
+The |math_type| is converted to |math_text_char| here if we would not want to
+apply an italic correction to the current character unless it belongs
+to a math font (i.e., a font with |space==0|).
+
+No boundary characters enter into these ligatures.
+
+@<Declare math...@>=
+void make_ord(pointer @!q)
+{@+
+int a; /*address of lig/kern instruction*/
+pointer @!p, @!r; /*temporary registers for list manipulation*/
+restart: @t@>@;@/
+if (math_type(subscr(q))==empty) if (math_type(supscr(q))==empty)
+ if (math_type(nucleus(q))==math_char)
+ {@+p=link(q);
+ if (p!=null) if ((type(p) >= ord_noad)&&(type(p) <= punct_noad))
+ if (math_type(nucleus(p))==math_char)
+ if (fam(nucleus(p))==fam(nucleus(q)))
+ {@+math_type(nucleus(q))=math_text_char;
+ fetch(nucleus(q));
+ if (char_tag(cur_i)==lig_tag)
+ {@+a=lig_kern_start(cur_f)(cur_i);
+ cur_c=character(nucleus(p));
+ cur_i=font_info[a].qqqq;
+ if (skip_byte(cur_i) > stop_flag)
+ {@+a=lig_kern_restart(cur_f)(cur_i);
+ cur_i=font_info[a].qqqq;
+ }
+ loop@+{@+@<If instruction |cur_i| is a kern with |cur_c|, attach the kern
+after~|q|; or if it is a ligature with |cur_c|, combine noads |q| and~|p| appropriately;
+then |return| if the cursor has moved past a noad, or |goto restart|@>;
+ if (skip_byte(cur_i) >= stop_flag) return;
+ a=a+qo(skip_byte(cur_i))+1;
+ cur_i=font_info[a].qqqq;
+ }
+ }
+ }
+ }
+}
+
+@ Note that a ligature between an |ord_noad| and another kind of noad
+is replaced by an |ord_noad|, when the two noads collapse into one.
+But we could make a parenthesis (say) change shape when it follows
+certain letters. Presumably a font designer will define such
+ligatures only when this convention makes sense.
+
+\chardef\?='174 % vertical line to indicate character retention
+
+@<If instruction |cur_i| is a kern with |cur_c|,...@>=
+if (next_char(cur_i)==cur_c) if (skip_byte(cur_i) <= stop_flag)
+ if (op_byte(cur_i) >= kern_flag)
+ {@+p=new_kern(char_kern(cur_f)(cur_i));
+ link(p)=link(q);link(q)=p;return;
+ }
+ else{@+check_interrupt; /*allow a way out of infinite ligature loop*/
+ switch (op_byte(cur_i)) {
+ qi(case 1): qi(case 5): character(nucleus(q))=rem_byte(cur_i);@+break; /*\.{=:\?}, \.{=:\?>}*/
+ qi(case 2): qi(case 6): character(nucleus(p))=rem_byte(cur_i);@+break; /*\.{\?=:}, \.{\?=:>}*/
+ qi(case 3): qi(case 7): qi(case 11): {@+r=new_noad(); /*\.{\?=:\?}, \.{\?=:\?>}, \.{\?=:\?>>}*/
+ character(nucleus(r))=rem_byte(cur_i);
+ fam(nucleus(r))=fam(nucleus(q));@/
+ link(q)=r;link(r)=p;
+ if (op_byte(cur_i) < qi(11)) math_type(nucleus(r))=math_char;
+ else math_type(nucleus(r))=math_text_char; /*prevent combination*/
+ } @+break;
+ default:{@+link(q)=link(p);
+ character(nucleus(q))=rem_byte(cur_i); /*\.{=:}*/
+ mem[subscr(q)]=mem[subscr(p)];mem[supscr(q)]=mem[supscr(p)];@/
+ free_node(p, noad_size);
+ }
+ }
+ if (op_byte(cur_i) > qi(3)) return;
+ math_type(nucleus(q))=math_char;goto restart;
+ }
+
+@ When we get to the following part of the program, we have ``fallen through''
+from cases that did not lead to |check_dimensions| or |done_with_noad| or
+|done_with_node|. Thus, |q|~points to a noad whose nucleus may need to be
+converted to an hlist, and whose subscripts and superscripts need to be
+appended if they are present.
+
+If |nucleus(q)| is not a |math_char|, the variable |delta| is the amount
+by which a superscript should be moved right with respect to a subscript
+when both are present.
+@^subscripts@>
+@^superscripts@>
+
+@<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@>=
+switch (math_type(nucleus(q))) {
+case math_char: case math_text_char:
+ @<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@>@;@+break;
+case empty: p=null;@+break;
+case sub_box: p=info(nucleus(q));@+break;
+case sub_mlist: {@+cur_mlist=info(nucleus(q));save_style=cur_style;
+ mlist_penalties=false;mlist_to_hlist(); /*recursive call*/
+@^recursion@>
+ cur_style=save_style;@<Set up the values...@>;
+ p=hpack(link(temp_head), natural);
+ } @+break;
+default:confusion(@[@<|"mlist2"|@>@]);
+@:this can't happen mlist2}{\quad mlist2@>
+} @/
+new_hlist(q)=p;
+if ((math_type(subscr(q))==empty)&&(math_type(supscr(q))==empty))
+ goto check_dimensions;
+make_scripts(q, delta)
+
+@ @<Create a character node |p| for |nucleus(q)|...@>=
+{@+fetch(nucleus(q));
+if (char_exists(cur_i))
+ {@+delta=char_italic(cur_f)(cur_i);p=new_character(cur_f, qo(cur_c));
+ if ((math_type(nucleus(q))==math_text_char)&&(space(cur_f)!=0))
+ delta=0; /*no italic correction in mid-word of text font*/
+ if ((math_type(subscr(q))==empty)&&(delta!=0))
+ {@+link(p)=new_kern(delta);delta=0;
+ }
+ }
+else p=null;
+}
+
+@ 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.
+
+@<Declare math...@>=
+void make_scripts(pointer @!q, scaled @!delta)
+{@+pointer p, @!x, @!y, @!z; /*temporary registers for box construction*/
+scaled @!shift_up, @!shift_down, @!clr; /*dimensions in the calculation*/
+small_number @!t; /*subsidiary size code*/
+p=new_hlist(q);
+if (is_char_node(p))
+ {@+shift_up=0;shift_down=0;
+ }
+else{@+z=hpack(p, natural);
+ if (cur_style < script_style) t=script_size;@+else t=script_script_size;
+ shift_up=height(z)-sup_drop(t);
+ shift_down=depth(z)+sub_drop(t);
+ free_node(z, box_node_size);
+ }
+if (math_type(supscr(q))==empty)
+ @<Construct a subscript box |x| when there is no superscript@>@;
+else{@+@<Construct a superscript box |x|@>;
+ if (math_type(subscr(q))==empty) shift_amount(x)=-shift_up;
+ else@<Construct a sub/superscript combination box |x|, with the superscript offset
+by |delta|@>;
+ }
+if (new_hlist(q)==null) new_hlist(q)=x;
+else{@+p=new_hlist(q);
+ while (link(p)!=null) p=link(p);
+ link(p)=x;
+ }
+}
+
+@ When there is a subscript without a superscript, the top of the subscript
+should not exceed the baseline plus four-fifths of the x-height.
+
+@<Construct a subscript box |x| when there is no superscript@>=
+{@+x=clean_box(subscr(q), sub_style(cur_style));
+width(x)=width(x)+script_space;
+if (shift_down < sub1(cur_size)) shift_down=sub1(cur_size);
+clr=height(x)-(abs(math_x_height(cur_size)*4)/5);
+if (shift_down < clr) shift_down=clr;
+shift_amount(x)=shift_down;
+}
+
+@ The bottom of a superscript should never descend below the baseline plus
+one-fourth of the x-height.
+
+@<Construct a superscript box |x|@>=
+{@+x=clean_box(supscr(q), sup_style(cur_style));
+width(x)=width(x)+script_space;
+if (odd(cur_style)) clr=sup3(cur_size);
+else if (cur_style < text_style) clr=sup1(cur_size);
+else clr=sup2(cur_size);
+if (shift_up < clr) shift_up=clr;
+clr=depth(x)+(abs(math_x_height(cur_size))/4);
+if (shift_up < clr) shift_up=clr;
+}
+
+@ When both subscript and superscript are present, the subscript must be
+separated from the superscript by at least four times |default_rule_thickness|.
+If this condition would be violated, the subscript moves down, after which
+both subscript and superscript move up so that the bottom of the superscript
+is at least as high as the baseline plus four-fifths of the x-height.
+
+@<Construct a sub/superscript combination box |x|...@>=
+{@+y=clean_box(subscr(q), sub_style(cur_style));
+width(y)=width(y)+script_space;
+if (shift_down < sub2(cur_size)) shift_down=sub2(cur_size);
+clr=4*default_rule_thickness-
+ ((shift_up-depth(x))-(height(y)-shift_down));
+if (clr > 0)
+ {@+shift_down=shift_down+clr;
+ clr=(abs(math_x_height(cur_size)*4)/5)-(shift_up-depth(x));
+ if (clr > 0)
+ {@+shift_up=shift_up+clr;
+ shift_down=shift_down-clr;
+ }
+ }
+shift_amount(x)=delta; /*superscript is |delta| to the right of the subscript*/
+p=new_kern((shift_up-depth(x))-(height(y)-shift_down));link(x)=p;link(p)=y;
+x=vpack(x, natural);shift_amount(x)=shift_down;
+}
+
+@ We have now tied up all the loose ends of the first pass of |mlist_to_hlist|.
+The second pass simply goes through and hooks everything together with the
+proper glue and penalties. It also handles the |left_noad| and |right_noad| that
+might be present, since |max_h| and |max_d| are now known. Variable |p| points
+to a node at the current end of the final hlist.
+
+@<Make a second pass over the mlist,...@>=
+p=temp_head;link(p)=null;q=mlist;r_type=0;cur_style=style;
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+while (q!=null)
+ {@+@<If node |q| is a style node, change the style and |goto delete_q|; otherwise
+if it is not a noad, put it into the hlist, advance |q|, and |goto done|; otherwise
+set |s| to the size of noad |q|, set |t| to the associated type (|ord_noad.. inner_noad|),
+and set |pen| to the associated penalty@>;
+ @<Append inter-element spacing based on |r_type| and |t|@>;
+ @<Append any |new_hlist| entries for |q|, and any appropriate penalties@>;
+ r_type=t;
+ delete_q: r=q;q=link(q);free_node(r, s);
+ done: ;}
+
+@ Just before doing the big |case| switch in the second pass, the program
+sets up default values so that most of the branches are short.
+
+@<If node |q| is a style node, change the style...@>=
+t=ord_noad;s=noad_size;pen=inf_penalty;
+switch (type(q)) {
+case op_noad: case open_noad: case close_noad: case punct_noad: case inner_noad: t=type(q);@+break;
+case bin_noad: {@+t=bin_noad;pen=bin_op_penalty;
+ } @+break;
+case rel_noad: {@+t=rel_noad;pen=rel_penalty;
+ } @+break;
+case ord_noad: case vcenter_noad: case over_noad: case under_noad: do_nothing;@+break;
+case radical_noad: s=radical_noad_size;@+break;
+case accent_noad: s=accent_noad_size;@+break;
+case fraction_noad: {@+t=inner_noad;s=fraction_noad_size;
+ } @+break;
+case left_noad: case right_noad: t=make_left_right(q, style, max_d, max_h);@+break;
+case style_node: @<Change the current style and |goto delete_q|@>@;
+case whatsit_node: case penalty_node: case rule_node: case disc_node: case adjust_node: case ins_node: case mark_node:
+ case glue_node: case kern_node: @t@>@;@/
+ {@+link(p)=q;p=q;q=link(q);link(p)=null;goto done;
+ }
+default:confusion(@[@<|"mlist3"|@>@]);
+@:this can't happen mlist3}{\quad mlist3@>
+}
+
+@ The |make_left_right| function constructs a left or right delimiter of
+the required size and returns the value |open_noad| or |close_noad|. The
+|right_noad| and |left_noad| will both be based on the original |style|,
+so they will have consistent sizes.
+
+We use the fact that |right_noad-left_noad==close_noad-open_noad|.
+
+@<Declare math...@>=
+small_number make_left_right(pointer @!q, small_number @!style,
+ scaled @!max_d, scaled @!max_h)
+{@+scaled delta, @!delta1, @!delta2; /*dimensions used in the calculation*/
+if (style < script_style) cur_size=text_size;
+else cur_size=16*((style-text_style)/2);
+delta2=max_d+axis_height(cur_size);
+delta1=max_h+max_d-delta2;
+if (delta2 > delta1) delta1=delta2; /*|delta1| is max distance from axis*/
+delta=(delta1/500)*delimiter_factor;
+delta2=delta1+delta1-delimiter_shortfall;
+if (delta < delta2) delta=delta2;
+new_hlist(q)=var_delimiter(delimiter(q), cur_size, delta);
+return type(q)-(left_noad-open_noad); /*|open_noad| or |close_noad|*/
+}
+
+@ @<Change the current style and |goto delete_q|@>=
+{@+cur_style=subtype(q);s=style_node_size;
+@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>;
+goto delete_q;
+}
+
+@ The inter-element spacing in math formulas depends on a $8\times8$ table that
+\TeX\ preloads as a 64-digit string. The elements of this string have the
+following significance:
+$$\vbox{\halign{#\hfil\cr
+\.0 means no space;\cr
+\.1 means a conditional thin space (\.{\\nonscript\\mskip\\thinmuskip});\cr
+\.2 means a thin space (\.{\\mskip\\thinmuskip});\cr
+\.3 means a conditional medium space
+ (\.{\\nonscript\\mskip\\medmuskip});\cr
+\.4 means a conditional thick space
+ (\.{\\nonscript\\mskip\\thickmuskip});\cr
+\.* means an impossible case.\cr}}$$
+This is all pretty cryptic, but {\sl The \TeX book\/} explains what is
+supposed to happen, and the string makes it happen.
+@:TeXbook}{\sl The \TeX book@>
+
+A global variable |magic_offset| is computed so that if |a| and |b| are
+in the range |ord_noad dotdot inner_noad|, then |str_pool[a*8+b+magic_offset]|
+is the digit for spacing between noad types |a| and |b|.
+
+If \PASCAL\ had provided a good way to preload constant arrays, this part of
+the program would not have been so strange.
+@:PASCAL}{\PASCAL@>
+
+@d math_spacing_str @;@/
+@t\hskip-35pt@>
+"math_spacing"
+@t$ \hskip-35pt$@>
+
+@<Glob...@>=
+int @!magic_offset; /*used to find inter-element spacing*/
+
+@ @<Compute the magic offset@>=
+magic_offset=str_start[math_spacing]-9*ord_noad
+
+@ @<Append inter-element spacing based on |r_type| and |t|@>=
+if (r_type > 0) /*not the first noad*/
+ {@+switch (so(str_pool[r_type*8+t+magic_offset])) {
+ case '0': x=0;@+break;
+ case '1': if (cur_style < script_style) x=thin_mu_skip_code;@+else x=0;@+break;
+ case '2': x=thin_mu_skip_code;@+break;
+ case '3': if (cur_style < script_style) x=med_mu_skip_code;@+else x=0;@+break;
+ case '4': if (cur_style < script_style) x=thick_mu_skip_code;@+else x=0;@+break;
+ default:confusion(@[@<|"mlist4"|@>@]);
+@:this can't happen mlist4}{\quad mlist4@>
+ }
+ if (x!=0)
+ {@+y=math_glue(glue_par(x), cur_mu);
+ z=new_glue(y);glue_ref_count(y)=null;link(p)=z;p=z;@/
+ subtype(z)=x+1; /*store a symbolic subtype*/
+ }
+ }
+
+@ We insert a penalty node after the hlist entries of noad |q| if |pen|
+is not an ``infinite'' penalty, and if the node immediately following |q|
+is not a penalty node or a |rel_noad| or absent entirely.
+
+@<Append any |new_hlist| entries for |q|, and any appropriate penalties@>=
+if (new_hlist(q)!=null)
+ {@+link(p)=new_hlist(q);
+ @/do@+{p=link(p);
+ }@+ while (!(link(p)==null));
+ }
+if (penalties) if (link(q)!=null) if (pen < inf_penalty)
+ {@+r_type=type(link(q));
+ if (r_type!=penalty_node) if (r_type!=rel_noad)
+ {@+z=new_penalty(pen);link(p)=z;p=z;
+ }
+ }
+
+@* Alignment.
+It's sort of a miracle whenever \.{\\halign} and \.{\\valign} work, because
+they cut across so many of the control structures of \TeX.
+
+Therefore the
+present page is probably not the best place for a beginner to start reading
+this program; it is better to master everything else first.
+
+Let us focus our thoughts on an example of what the input might be, in order
+to get some idea about how the alignment miracle happens. The example doesn't
+do anything useful, but it is sufficiently general to indicate all of the
+special cases that must be dealt with; please do not be disturbed by its
+apparent complexity and meaninglessness.
+$$\vbox{\halign{\.{#}\hfil\cr
+{}\\tabskip 2pt plus 3pt\cr
+{}\\halign to 300pt\{u1\#v1\&\cr
+\hskip 50pt\\tabskip 1pt plus 1fil u2\#v2\&\cr
+\hskip 50pt u3\#v3\\cr\cr
+\hskip 25pt a1\&\\omit a2\&\\vrule\\cr\cr
+\hskip 25pt \\noalign\{\\vskip 3pt\}\cr
+\hskip 25pt b1\\span b2\\cr\cr
+\hskip 25pt \\omit\&c2\\span\\omit\\cr\}\cr}}$$
+Here's what happens:
+
+\yskip
+(0) When `\.{\\halign to 300pt\{}' is scanned, the |scan_spec| routine
+places the 300pt dimension onto the |save_stack|, and an |align_group|
+code is placed above it. This will make it possible to complete the alignment
+when the matching `\.\}' is found.
+
+(1) The preamble is scanned next. Macros in the preamble are not expanded,
+@^preamble@>
+except as part of a tabskip specification. For example, if \.{u2} had been
+a macro in the preamble above, it would have been expanded, since \TeX\
+must look for `\.{minus...}' as part of the tabskip glue. A ``preamble list''
+is constructed based on the user's preamble; in our case it contains the
+following seven items:
+$$\vbox{\halign{\.{#}\hfil\qquad&(#)\hfil\cr
+{}\\glue 2pt plus 3pt&the tabskip preceding column 1\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 1\cr
+{}\\glue 2pt plus 3pt&the tabskip between columns 1 and 2\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 2\cr
+{}\\glue 1pt plus 1fil&the tabskip between columns 2 and 3\cr
+{}\\alignrecord, width $-\infty$&preamble info for column 3\cr
+{}\\glue 1pt plus 1fil&the tabskip following column 3\cr}}$$
+These ``alignrecord'' entries have the same size as an |unset_node|,
+since they will later be converted into such nodes. However, at the
+moment they have no |type| or |subtype| fields; they have |info| fields
+instead, and these |info| fields are initially set to the value |end_span|,
+for reasons explained below. Furthermore, the alignrecord nodes have no
+|height| or |depth| fields; these are renamed |u_part| and |v_part|,
+and they point to token lists for the templates of the alignment.
+For example, the |u_part| field in the first alignrecord points to the
+token list `\.{u1}', i.e., the template preceding the `\.\#' for column~1.
+
+(2) \TeX\ now looks at what follows the \.{\\cr} that ended the preamble.
+It is not `\.{\\noalign}' or `\.{\\omit}', so this input is put back to
+be read again, and the template `\.{u1}' is fed to the scanner. Just
+before reading `\.{u1}', \TeX\ goes into restricted horizontal mode.
+Just after reading `\.{u1}', \TeX\ will see `\.{a1}', and then (when the
+{\.\&} is sensed) \TeX\ will see `\.{v1}'. Then \TeX\ scans an |endv|
+token, indicating the end of a column. At this point an |unset_node| is
+created, containing the contents of the current hlist (i.e., `\.{u1a1v1}').
+The natural width of this unset node replaces the |width| field of the
+alignrecord for column~1; in general, the alignrecords will record the
+maximum natural width that has occurred so far in a given column.
+
+(3) Since `\.{\\omit}' follows the `\.\&', the templates for column~2
+are now bypassed. Again \TeX\ goes into restricted horizontal mode and
+makes an |unset_node| from the resulting hlist; but this time the
+hlist contains simply `\.{a2}'. The natural width of the new unset box
+is remembered in the |width| field of the alignrecord for column~2.
+
+(4) A third |unset_node| is created for column 3, using essentially the
+mechanism that worked for column~1; this unset box contains `\.{u3\\vrule
+v3}'. The vertical rule in this case has running dimensions that will later
+extend to the height and depth of the whole first row, since each |unset_node|
+in a row will eventually inherit the height and depth of its enclosing box.
+
+(5) The first row has now ended; it is made into a single unset box
+comprising the following seven items:
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: u1a1v1\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: a2\cr
+{}\\glue 1pt plus 1fil\cr
+{}\\unsetbox for 1 column: u3\\vrule v3\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+The width of this unset row is unimportant, but it has the correct height
+and depth, so the correct baselineskip glue will be computed as the row
+is inserted into a vertical list.
+
+(6) Since `\.{\\noalign}' follows the current \.{\\cr}, \TeX\ appends
+additional material (in this case \.{\\vskip 3pt}) to the vertical list.
+While processing this material, \TeX\ will be in internal vertical
+mode, and |no_align_group| will be on |save_stack|.
+
+(7) The next row produces an unset box that looks like this:
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 2 columns: u1b1v1u2b2v2\cr
+{}\\glue 1pt plus 1fil\cr
+{}\\unsetbox for 1 column: {\rm(empty)}\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+The natural width of the unset box that spans columns 1~and~2 is stored
+in a ``span node,'' which we will explain later; the |info| field of the
+alignrecord for column~1 now points to the new span node, and the |info|
+of the span node points to |end_span|.
+
+(8) The final row produces the unset box
+$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 1 column: {\rm(empty)}\cr
+{}\\glue 2pt plus 3pt\cr
+{}\\unsetbox for 2 columns: u2c2v2\cr
+{}\\glue 1pt plus 1fil\cr}}$$
+A new span node is attached to the alignrecord for column 2.
+
+(9) The last step is to compute the true column widths and to change all the
+unset boxes to hboxes, appending the whole works to the vertical list that
+encloses the \.{\\halign}. The rules for deciding on the final widths of
+each unset column box will be explained below.
+
+\yskip\noindent
+Note that as \.{\\halign} is being processed, we fearlessly give up control
+to the rest of \TeX. At critical junctures, an alignment routine is
+called upon to step in and do some little action, but most of the time
+these routines just lurk in the background. It's something like
+post-hypnotic suggestion.
+
+@ We have mentioned that alignrecords contain no |height| or |depth| fields.
+Their |glue_sign| and |glue_order| are pre-empted as well, since it
+is necessary to store information about what to do when a template ends.
+This information is called the |extra_info| field.
+
+@d u_part(X) mem[X+height_offset].i /*pointer to \<u_j> token list*/
+@d v_part(X) mem[X+depth_offset].i /*pointer to \<v_j> token list*/
+@d extra_info(X) info(X+list_offset) /*info to remember during template*/
+
+@ Alignments can occur within alignments, so a small stack is used to access
+the alignrecord information. At each level we have a |preamble| pointer,
+indicating the beginning of the preamble list; a |cur_align| pointer,
+indicating the current position in the preamble list; a |cur_span| pointer,
+indicating the value of |cur_align| at the beginning of a sequence of
+spanned columns; a |cur_loop| pointer, indicating the tabskip glue before
+an alignrecord that should be copied next if the current list is extended;
+and the |align_state| variable, which indicates the nesting of braces so
+that \.{\\cr} and \.{\\span} and tab marks are properly intercepted.
+There also are pointers |cur_head| and |cur_tail| to the head and tail
+of a list of adjustments being moved out from horizontal mode to
+vertical~mode.
+
+The current values of these seven quantities appear in global variables;
+when they have to be pushed down, they are stored in 5-word nodes, and
+|align_ptr| points to the topmost such node.
+
+@d preamble link(align_head) /*the current preamble list*/
+@d align_stack_node_size 5 /*number of |mem| words to save alignment states*/
+
+@<Glob...@>=
+pointer @!cur_align; /*current position in preamble list*/
+pointer @!cur_span; /*start of currently spanned columns in preamble list*/
+pointer @!cur_loop; /*place to copy when extending a periodic preamble*/
+pointer @!align_ptr; /*most recently pushed-down alignment stack node*/
+pointer @!cur_head, @!cur_tail; /*adjustment list pointers*/
+
+@ The |align_state| and |preamble| variables are initialized elsewhere.
+
+@<Set init...@>=
+align_ptr=null;cur_align=null;cur_span=null;cur_loop=null;
+cur_head=null;cur_tail=null;
+
+@ Alignment stack maintenance is handled by a pair of trivial routines
+called |push_alignment| and |pop_alignment|.
+
+@p void push_alignment(void)
+{@+pointer p; /*the new alignment stack node*/
+p=get_node(align_stack_node_size);
+link(p)=align_ptr;info(p)=cur_align;
+llink(p)=preamble;rlink(p)=cur_span;
+mem[p+2].i=cur_loop;mem[p+3].i=align_state;
+info(p+4)=cur_head;link(p+4)=cur_tail;
+align_ptr=p;
+cur_head=get_avail();
+}
+@#
+void pop_alignment(void)
+{@+pointer p; /*the top alignment stack node*/
+free_avail(cur_head);
+p=align_ptr;
+cur_tail=link(p+4);cur_head=info(p+4);
+align_state=mem[p+3].i;cur_loop=mem[p+2].i;
+cur_span=rlink(p);preamble=llink(p);
+cur_align=info(p);align_ptr=link(p);
+free_node(p, align_stack_node_size);
+}
+
+@ \TeX\ has eight procedures that govern alignments: |init_align| and
+|fin_align| are used at the very beginning and the very end; |init_row| and
+|fin_row| are used at the beginning and end of individual rows; |init_span|
+is used at the beginning of a sequence of spanned columns (possibly involving
+only one column); |init_col| and |fin_col| are used at the beginning and
+end of individual columns; and |align_peek| is used after \.{\\cr} to see
+whether the next item is \.{\\noalign}.
+
+We shall consider these routines in the order they are first used during
+the course of a complete \.{\\halign}, namely |init_align|, |align_peek|,
+|init_row|, |init_span|, |init_col|, |fin_col|, |fin_row|, |fin_align|.
+
+@ When \.{\\halign} or \.{\\valign} has been scanned in an appropriate
+mode, \TeX\ calls |init_align|, whose task is to get everything off to a
+good start. This mostly involves scanning the preamble and putting its
+information into the preamble list.
+@^preamble@>
+
+@p@t\4@>@<Declare the procedure called |get_preamble_token|@>@t@>@/
+void align_peek(void);@/
+void normal_paragraph(void);@/
+void init_align(void)
+{@+
+pointer save_cs_ptr; /*|warning_index| value for error messages*/
+pointer @!p; /*for short-term temporary use*/
+save_cs_ptr=cur_cs; /*\.{\\halign} or \.{\\valign}, usually*/
+push_alignment();align_state=-1000000; /*enter a new alignment level*/
+@<Check for improper alignment in displayed math@>;
+push_nest(); /*enter a new semantic level*/
+@<Change current mode to |-vmode| for \.{\\halign}, |-hmode| for \.{\\valign}@>;
+scan_spec(align_group, false);@/
+@<Scan the preamble and record it in the |preamble| list@>;
+new_save_level(align_group);
+if (every_cr!=null) begin_token_list(every_cr, every_cr_text);
+align_peek(); /*look for \.{\\noalign} or \.{\\omit}*/
+}
+
+@ In vertical modes, |prev_depth| already has the correct value. But
+if we are in |mmode| (displayed formula mode), we reach out to the
+enclosing vertical mode for the |prev_depth| value that produces the
+correct baseline calculations.
+
+@<Change current mode...@>=
+if (mode==mmode)
+ {@+mode=-vmode;prev_depth=nest[nest_ptr-2].aux_field.sc;
+ }
+else if (mode > 0) negate(mode)
+
+@ When \.{\\halign} is used as a displayed formula, there should be
+no other pieces of mlists present.
+
+@<Check for improper alignment in displayed math@>=
+if ((mode==mmode)&&((tail!=head)||(incompleat_noad!=null)))
+ {@+print_err("Improper ");print_esc(@[@<|"halign"|@>@]);print_str(" inside $$'s");
+@.Improper \\halign...@>
+ help3("Displays can use special alignments (like \\eqalignno)")@/
+ ("only if nothing but the alignment itself is between $$'s.")@/
+ ("So I've deleted the formulas that preceded this alignment.");
+ error();flush_math();
+ }
+
+@ @<Scan the preamble and record it in the |preamble| list@>=
+preamble=null;cur_align=align_head;cur_loop=null;scanner_status=aligning;
+warning_index=save_cs_ptr;align_state=-1000000;
+ /*at this point, |cur_cmd==left_brace|*/
+loop@+{@+@<Append the current tabskip glue to the preamble list@>;
+ if (cur_cmd==car_ret) goto done; /*\.{\\cr} ends the preamble*/
+ @<Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret|, looking for changes
+in the tabskip glue; append an alignrecord to the preamble list@>;
+ }
+done: scanner_status=normal
+
+@ @<Append the current tabskip glue to the preamble list@>=
+link(cur_align)=new_param_glue(tab_skip_code);
+cur_align=link(cur_align)
+
+@ @<Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret|...@>=
+@<Scan the template \<u_j>, putting the resulting token list in |hold_head|@>;
+link(cur_align)=new_null_box();cur_align=link(cur_align); /*a new alignrecord*/
+info(cur_align)=end_span;width(cur_align)=null_flag;
+u_part(cur_align)=link(hold_head);
+@<Scan the template \<v_j>, putting the resulting token list in |hold_head|@>;
+v_part(cur_align)=link(hold_head)
+
+@ We enter `\.{\\span}' into |eqtb| with |tab_mark| as its command code,
+and with |span_code| as the command modifier. This makes \TeX\ interpret it
+essentially the same as an alignment delimiter like `\.\&', yet it is
+recognizably different when we need to distinguish it from a normal delimiter.
+It also turns out to be useful to give a special |cr_code| to `\.{\\cr}',
+and an even larger |cr_cr_code| to `\.{\\crcr}'.
+
+The end of a template is represented by two ``frozen'' control sequences
+called \.{\\endtemplate}. The first has the command code |end_template|, which
+is | > outer_call|, so it will not easily disappear in the presence of errors.
+The |get_x_token| routine converts the first into the second, which has |endv|
+as its command code.
+
+@d span_code 256 /*distinct from any character*/
+@d cr_code 257 /*distinct from |span_code| and from any character*/
+@d cr_cr_code (cr_code+1) /*this distinguishes \.{\\crcr} from \.{\\cr}*/
+@d end_template_token cs_token_flag+frozen_end_template
+
+@<Put each of \TeX's primitives into the hash table@>=
+primitive(@[@<|"span"|@>@], tab_mark, span_code);@/
+@!@:span_}{\.{\\span} primitive@>
+primitive(@[@<|"cr"|@>@], car_ret, cr_code);
+@!@:cr_}{\.{\\cr} primitive@>
+text(frozen_cr)=@[@<|"cr"|@>@];eqtb[frozen_cr]=eqtb[cur_val];@/
+primitive(@[@<|"crcr"|@>@], car_ret, cr_cr_code);
+@!@:cr_cr_}{\.{\\crcr} primitive@>
+text(frozen_end_template)=@[@<|"endtemplate"|@>@];text(frozen_endv)=@[@<|"endtemplate"|@>@];
+eq_type(frozen_endv)=endv;equiv(frozen_endv)=null_list;
+eq_level(frozen_endv)=level_one;@/
+eqtb[frozen_end_template]=eqtb[frozen_endv];
+eq_type(frozen_end_template)=end_template;
+
+@ @<Cases of |print_cmd_chr|...@>=
+case tab_mark: if (chr_code==span_code) print_esc(@[@<|"span"|@>@]);
+ else chr_cmd("alignment tab character ")@;@+break;
+case car_ret: if (chr_code==cr_code) print_esc(@[@<|"cr"|@>@]);
+ else print_esc(@[@<|"crcr"|@>@]);@+break;
+
+@ The preamble is copied directly, except that \.{\\tabskip} causes a change
+to the tabskip glue, thereby possibly expanding macros that immediately
+follow it. An appearance of \.{\\span} also causes such an expansion.
+
+Note that if the preamble contains `\.{\\global\\tabskip}', the `\.{\\global}'
+token survives in the preamble and the `\.{\\tabskip}' defines new
+tabskip glue (locally).
+
+@<Declare the procedure called |get_preamble_token|@>=
+void get_preamble_token(void)
+{@+
+restart: get_token();
+while ((cur_chr==span_code)&&(cur_cmd==tab_mark))
+ {@+get_token(); /*this token will be expanded once*/
+ if (cur_cmd > max_command)
+ {@+expand();get_token();
+ }
+ }
+if (cur_cmd==endv)
+ fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+if ((cur_cmd==assign_glue)&&(cur_chr==glue_base+tab_skip_code))
+ {@+scan_optional_equals();scan_glue(glue_val);
+ if (global_defs > 0) geq_define(glue_base+tab_skip_code, glue_ref, cur_val);
+ else eq_define(glue_base+tab_skip_code, glue_ref, cur_val);
+ goto restart;
+ }
+}
+
+@ Spaces are eliminated from the beginning of a template.
+
+@<Scan the template \<u_j>...@>=
+p=hold_head;link(p)=null;
+loop@+{@+get_preamble_token();
+ if (cur_cmd==mac_param) goto done1;
+ if ((cur_cmd <= car_ret)&&(cur_cmd >= tab_mark)&&(align_state==-1000000))
+ if ((p==hold_head)&&(cur_loop==null)&&(cur_cmd==tab_mark)
+ ) cur_loop=cur_align;
+ else{@+print_err("Missing # inserted in alignment preamble");
+@.Missing \# inserted...@>
+ help3("There should be exactly one # between &'s, when an")@/
+ ("\\halign or \\valign is being set up. In this case you had")@/
+ ("none, so I've put one in; maybe that will work.");
+ back_error();goto done1;
+ }
+ else if ((cur_cmd!=spacer)||(p!=hold_head))
+ {@+link(p)=get_avail();p=link(p);info(p)=cur_tok;
+ }
+ }
+done1:
+
+@ @<Scan the template \<v_j>...@>=
+p=hold_head;link(p)=null;
+loop@+{@+resume: get_preamble_token();
+ if ((cur_cmd <= car_ret)&&(cur_cmd >= tab_mark)&&(align_state==-1000000))
+ goto done2;
+ if (cur_cmd==mac_param)
+ {@+print_err("Only one # is allowed per tab");
+@.Only one \# is allowed...@>
+ help3("There should be exactly one # between &'s, when an")@/
+ ("\\halign or \\valign is being set up. In this case you had")@/
+ ("more than one, so I'm ignoring all but the first.");
+ error();goto resume;
+ }
+ link(p)=get_avail();p=link(p);info(p)=cur_tok;
+ }
+done2: link(p)=get_avail();p=link(p);
+info(p)=end_template_token /*put \.{\\endtemplate} at the end*/
+
+@ The tricky part about alignments is getting the templates into the
+scanner at the right time, and recovering control when a row or column
+is finished.
+
+We usually begin a row after each \.{\\cr} has been sensed, unless that
+\.{\\cr} is followed by \.{\\noalign} or by the right brace that terminates
+the alignment. The |align_peek| routine is used to look ahead and do
+the right thing; it either gets a new row started, or gets a \.{\\noalign}
+started, or finishes off the alignment.
+
+@<Declare the procedure called |align_peek|@>=
+void align_peek(void)
+{@+
+restart: align_state=1000000;@<Get the next non-blank non-call token@>;
+if (cur_cmd==no_align)
+ {@+scan_left_brace();new_save_level(no_align_group);
+ if (mode==-vmode) normal_paragraph();
+ }
+else if (cur_cmd==right_brace) fin_align();
+else if ((cur_cmd==car_ret)&&(cur_chr==cr_cr_code))
+ goto restart; /*ignore \.{\\crcr}*/
+else{@+init_row(); /*start a new row*/
+ init_col(); /*start a new column and replace what we peeked at*/
+ }
+}
+
+@ To start a row (i.e., a `row' that rhymes with `dough' but not with `bough'),
+we enter a new semantic level, copy the first tabskip glue, and change
+from internal vertical mode to restricted horizontal mode or vice versa.
+The |space_factor| and |prev_depth| are not used on this semantic level,
+but we clear them to zero just to be tidy.
+
+@p@t\4@>@<Declare the procedure called |init_span|@>@t@>@/
+void init_row(void)
+{@+push_nest();mode=(-hmode-vmode)-mode;
+if (mode==-hmode) space_factor=0;@+else prev_depth=0;
+tail_append(new_glue(glue_ptr(preamble)));
+subtype(tail)=tab_skip_code+1;@/
+cur_align=link(preamble);cur_tail=cur_head;init_span(cur_align);
+}
+
+@ The parameter to |init_span| is a pointer to the alignrecord where the
+next column or group of columns will begin. A new semantic level is
+entered, so that the columns will generate a list for subsequent packaging.
+
+@<Declare the procedure called |init_span|@>=
+void init_span(pointer @!p)
+{@+push_nest();
+if (mode==-hmode) space_factor=1000;
+else{@+prev_depth=ignore_depth;normal_paragraph();
+ }
+cur_span=p;
+}
+
+@ When a column begins, we assume that |cur_cmd| is either |omit| or else
+the current token should be put back into the input until the \<u_j>
+template has been scanned. (Note that |cur_cmd| might be |tab_mark| or
+|car_ret|.) We also assume that |align_state| is approximately 1000000 at
+this time. We remain in the same mode, and start the template if it is
+called for.
+
+@p void init_col(void)
+{@+extra_info(cur_align)=cur_cmd;
+if (cur_cmd==omit) align_state=0;
+else{@+back_input();begin_token_list(u_part(cur_align), u_template);
+ } /*now |align_state==1000000|*/
+}
+
+@ The scanner sets |align_state| to zero when the \<u_j> template ends. When
+a subsequent \.{\\cr} or \.{\\span} or tab mark occurs with |align_state==0|,
+the scanner activates the following code, which fires up the \<v_j> template.
+We need to remember the |cur_chr|, which is either |cr_cr_code|, |cr_code|,
+|span_code|, or a character code, depending on how the column text has ended.
+
+This part of the program had better not be activated when the preamble
+to another alignment is being scanned, or when no alignment preamble is active.
+
+@<Insert the \(v)\<v_j>...@>=
+{@+if ((scanner_status==aligning)||(cur_align==null))
+ fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+cur_cmd=extra_info(cur_align);extra_info(cur_align)=cur_chr;
+if (cur_cmd==omit) begin_token_list(omit_template, v_template);
+else begin_token_list(v_part(cur_align), v_template);
+align_state=1000000;goto restart;
+}
+
+@ The token list |omit_template| just referred to is a constant token
+list that contains the special control sequence \.{\\endtemplate} only.
+
+@<Initialize the special...@>=
+info(omit_template)=end_template_token; /*|link(omit_template)==null|*/
+
+@ When the |endv| command at the end of a \<v_j> template comes through the
+scanner, things really start to happen; and it is the |fin_col| routine
+that makes them happen. This routine returns |true| if a row as well as a
+column has been finished.
+
+@p bool fin_col(void)
+{@+
+pointer p; /*the alignrecord after the current one*/
+pointer @!q, @!r; /*temporary pointers for list manipulation*/
+pointer @!s; /*a new span node*/
+pointer @!u; /*a new unset box*/
+scaled @!w; /*natural width*/
+glue_ord @!o; /*order of infinity*/
+halfword @!n; /*span counter*/
+if (cur_align==null) confusion(@[@<|"endv"|@>@]);
+q=link(cur_align);@+if (q==null) confusion(@[@<|"endv"|@>@]);
+@:this can't happen endv}{\quad endv@>
+if (align_state < 500000)
+ fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+p=link(q);
+@<If the preamble list has been traversed, check that the row has ended@>;
+if (extra_info(cur_align)!=span_code)
+ {@+unsave();new_save_level(align_group);@/
+ @<Package an unset box for the current column and record its width@>;
+ @<Copy the tabskip glue between columns@>;
+ if (extra_info(cur_align) >= cr_code)
+ {@+return true;
+ }
+ init_span(p);
+ }
+align_state=1000000;@<Get the next non-blank non-call token@>;
+cur_align=p;
+init_col();return false;
+}
+
+@ @<If the preamble list has been traversed, check that the row has ended@>=
+if ((p==null)&&(extra_info(cur_align) < cr_code))
+ if (cur_loop!=null) @<Lengthen the preamble periodically@>@;
+ else{@+print_err("Extra alignment tab has been changed to ");
+@.Extra alignment tab...@>
+ print_esc(@[@<|"cr"|@>@]);
+ help3("You have given more \\span or & marks than there were")@/
+ ("in the preamble to the \\halign or \\valign now in progress.")@/
+ ("So I'll assume that you meant to type \\cr instead.");
+ extra_info(cur_align)=cr_code;error();
+ }
+
+@ @<Lengthen the preamble...@>=
+{@+link(q)=new_null_box();p=link(q); /*a new alignrecord*/
+info(p)=end_span;width(p)=null_flag;cur_loop=link(cur_loop);
+@<Copy the templates from node |cur_loop| into node |p|@>;
+cur_loop=link(cur_loop);
+link(p)=new_glue(glue_ptr(cur_loop));
+}
+
+@ @<Copy the templates from node |cur_loop| into node |p|@>=
+q=hold_head;r=u_part(cur_loop);
+while (r!=null)
+ {@+link(q)=get_avail();q=link(q);info(q)=info(r);r=link(r);
+ }
+link(q)=null;u_part(p)=link(hold_head);
+q=hold_head;r=v_part(cur_loop);
+while (r!=null)
+ {@+link(q)=get_avail();q=link(q);info(q)=info(r);r=link(r);
+ }
+link(q)=null;v_part(p)=link(hold_head)
+
+@ @<Copy the tabskip glue...@>=
+tail_append(new_glue(glue_ptr(link(cur_align))));
+subtype(tail)=tab_skip_code+1
+
+@ @<Package an unset...@>=
+{@+if (mode==-hmode)
+ {@+adjust_tail=cur_tail;u=hpack(link(head), natural);w=width(u);
+ cur_tail=adjust_tail;adjust_tail=null;
+ }
+else{@+u=vpackage(link(head), natural, 0);w=height(u);
+ }
+n=min_quarterword; /*this represents a span count of 1*/
+if (cur_span!=cur_align) @<Update width entry for spanned columns@>@;
+else if (w > width(cur_align)) width(cur_align)=w;
+type(u)=unset_node;span_count(u)=n;@/
+@<Determine the stretch order@>;
+glue_order(u)=o;glue_stretch(u)=total_stretch[o];@/
+@<Determine the shrink order@>;
+glue_sign(u)=o;glue_shrink(u)=total_shrink[o];@/
+pop_nest();link(tail)=u;tail=u;
+}
+
+@ A span node is a 2-word record containing |width|, |info|, and |link|
+fields. The |link| field is not really a link, it indicates the number of
+spanned columns; the |info| field points to a span node for the same
+starting column, having a greater extent of spanning, or to |end_span|,
+which has the largest possible |link| field; the |width| field holds the
+largest natural width corresponding to a particular set of spanned columns.
+
+A list of the maximum widths so far, for spanned columns starting at a
+given column, begins with the |info| field of the alignrecord for that
+column.
+
+@d span_node_size 2 /*number of |mem| words for a span node*/
+
+@<Initialize the special list heads...@>=
+link(end_span)=max_quarterword+1;info(end_span)=null;
+
+@ @<Update width entry for spanned columns@>=
+{@+q=cur_span;
+@/do@+{incr(n);q=link(link(q));
+}@+ while (!(q==cur_align));
+if (n > max_quarterword) confusion(@[@<|"256 spans"|@>@]); /*this can happen, but won't*/
+@^system dependencies@>
+@:this can't happen 256 spans}{\quad 256 spans@>
+q=cur_span;while (link(info(q)) < n) q=info(q);
+if (link(info(q)) > n)
+ {@+s=get_node(span_node_size);info(s)=info(q);link(s)=n;
+ info(q)=s;width(s)=w;
+ }
+else if (width(info(q)) < w) width(info(q))=w;
+}
+
+@ At the end of a row, we append an unset box to the current vlist (for
+\.{\\halign}) or the current hlist (for \.{\\valign}). This unset box
+contains the unset boxes for the columns, separated by the tabskip glue.
+Everything will be set later.
+
+@p void fin_row(void)
+{@+pointer p; /*the new unset box*/
+if (mode==-hmode)
+ {@+p=hpack(link(head), natural);
+ pop_nest();append_to_vlist(p);
+ if (cur_head!=cur_tail)
+ {@+link(tail)=link(cur_head);tail=cur_tail;
+ }
+ }
+else{@+p=vpack(link(head), natural);pop_nest();
+ link(tail)=p;tail=p;space_factor=1000;
+ }
+type(p)=unset_node;glue_stretch(p)=0;
+if (every_cr!=null) begin_token_list(every_cr, every_cr_text);
+align_peek();
+} /*note that |glue_shrink(p)==0| since |glue_shrink====shift_amount|*/
+
+@ Finally, we will reach the end of the alignment, and we can breathe a
+sigh of relief that memory hasn't overflowed. All the unset boxes will now be
+set so that the columns line up, taking due account of spanned columns.
+
+@p void do_assignments(void);@/
+void resume_after_display(void);@/
+void build_page(void);@/
+void fin_align(void)
+{@+pointer @!p, @!q, @!r, @!s, @!u, @!v; /*registers for the list operations*/
+scaled @!t, @!w; /*width of column*/
+scaled @!o; /*shift offset for unset boxes*/
+halfword @!n; /*matching span amount*/
+scaled @!rule_save; /*temporary storage for |overfull_rule|*/
+memory_word @!aux_save; /*temporary storage for |aux|*/
+if (cur_group!=align_group) confusion(@[@<|"align1"|@>@]);
+@:this can't happen align}{\quad align@>
+unsave(); /*that |align_group| was for individual entries*/
+if (cur_group!=align_group) confusion(@[@<|"align0"|@>@]);
+unsave(); /*that |align_group| was for the whole alignment*/
+if (nest[nest_ptr-1].mode_field==mmode) o=display_indent;
+ else o=0;
+@<Go through the preamble list, determining the column widths and changing the alignrecords
+to dummy unset boxes@>;
+@<Package the preamble list, to determine the actual tabskip glue amounts, and let
+|p| point to this prototype box@>;
+@<Set the glue in all the unset boxes of the current list@>;
+flush_node_list(p);pop_alignment();
+@<Insert the \(c)current list into its environment@>;
+} @/
+@t\4@>@<Declare the procedure called |align_peek|@>@;
+
+@ It's time now to dismantle the preamble list and to compute the column
+widths. Let $w_{ij}$ be the maximum of the natural widths of all entries
+that span columns $i$ through $j$, inclusive. The alignrecord for column~$i$
+contains $w_{ii}$ in its |width| field, and there is also a linked list of
+the nonzero $w_{ij}$ for increasing $j$, accessible via the |info| field;
+these span nodes contain the value $j-i+|min_quarterword|$ in their
+|link| fields. The values of $w_{ii}$ were initialized to |null_flag|, which
+we regard as $-\infty$.
+
+The final column widths are defined by the formula
+$$w_j=\max_{1\L i\L j}\biggl( w_{ij}-\sum_{i\L k<j}(t_k+w_k)\biggr),$$
+where $t_k$ is the natural width of the tabskip glue between columns
+$k$ and~$k+1$. However, if $w_{ij}=-\infty$ for all |i| in the range
+|1 <= i <= j| (i.e., if every entry that involved column~|j| also involved
+column~|j+1|), we let $w_j=0$, and we zero out the tabskip glue after
+column~|j|.
+
+\TeX\ computes these values by using the following scheme: First $w_1=w_{11}$.
+Then replace $w_{2j}$ by $\max(w_{2j},w_{1j}-t_1-w_1)$, for all $j>1$.
+Then $w_2=w_{22}$. Then replace $w_{3j}$ by $\max(w_{3j},w_{2j}-t_2-w_2)$
+for all $j>2$; and so on. If any $w_j$ turns out to be $-\infty$, its
+value is changed to zero and so is the next tabskip.
+
+@<Go through the preamble list,...@>=
+q=link(preamble);
+@/do@+{flush_list(u_part(q));flush_list(v_part(q));
+p=link(link(q));
+if (width(q)==null_flag)
+ @<Nullify |width(q)| and the tabskip glue following this column@>;
+if (info(q)!=end_span)
+ @<Merge the widths in the span nodes of |q| with those of |p|, destroying the span
+nodes of |q|@>;
+type(q)=unset_node;span_count(q)=min_quarterword;height(q)=0;
+depth(q)=0;glue_order(q)=normal;glue_sign(q)=normal;
+glue_stretch(q)=0;glue_shrink(q)=0;q=p;
+}@+ while (!(q==null))
+
+@ @<Nullify |width(q)| and the tabskip glue following this column@>=
+{@+width(q)=0;r=link(q);s=glue_ptr(r);
+if (s!=zero_glue)
+ {@+add_glue_ref(zero_glue);delete_glue_ref(s);
+ glue_ptr(r)=zero_glue;
+ }
+}
+
+@ 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)==n| or |link(r) > n| or |link(r) < n|.
+
+@<Merge the widths...@>=
+{@+t=width(q)+width(glue_ptr(link(q)));
+r=info(q);s=end_span;info(s)=p;n=min_quarterword+1;
+@/do@+{width(r)=width(r)-t;u=info(r);
+while (link(r) > n)
+ {@+s=info(s);n=link(info(s))+1;
+ }
+if (link(r) < n)
+ {@+info(r)=info(s);info(s)=r;decr(link(r));s=r;
+ }
+else{@+if (width(r) > width(info(s))) width(info(s))=width(r);
+ free_node(r, span_node_size);
+ }
+r=u;
+}@+ while (!(r==end_span));
+}
+
+@ Now the preamble list has been converted to a list of alternating unset
+boxes and tabskip glue, where the box widths are equal to the final
+column sizes. In case of \.{\\valign}, we change the widths to heights,
+so that a correct error message will be produced if the alignment is
+overfull or underfull.
+
+@<Package the preamble list...@>=
+save_ptr=save_ptr-2;pack_begin_line=-mode_line;
+if (mode==-vmode)
+ {@+rule_save=overfull_rule;
+ overfull_rule=0; /*prevent rule from being packaged*/
+ p=hpack(preamble, saved(1), saved(0));overfull_rule=rule_save;
+ }
+else{@+q=link(preamble);
+ @/do@+{height(q)=width(q);width(q)=0;q=link(link(q));
+ }@+ while (!(q==null));
+ p=vpack(preamble, saved(1), saved(0));
+ q=link(preamble);
+ @/do@+{width(q)=height(q);height(q)=0;q=link(link(q));
+ }@+ while (!(q==null));
+ }
+pack_begin_line=0
+
+@ @<Set the glue in all the unset...@>=
+q=link(head);s=head;
+while (q!=null)
+ {@+if (!is_char_node(q))
+ if (type(q)==unset_node)
+ @<Set the unset box |q| and the unset boxes in it@>@;
+ else if (type(q)==rule_node)
+ @<Make the running dimensions in rule |q| extend to the boundaries of the alignment@>;
+ s=q;q=link(q);
+ }
+
+@ @<Make the running dimensions in rule |q| extend...@>=
+{@+if (is_running(width(q))) width(q)=width(p);
+if (is_running(height(q))) height(q)=height(p);
+if (is_running(depth(q))) depth(q)=depth(p);
+if (o!=0)
+ {@+r=link(q);link(q)=null;q=hpack(q, natural);
+ shift_amount(q)=o;link(q)=r;link(s)=q;
+ }
+}
+
+@ The unset box |q| represents a row that contains one or more unset boxes,
+depending on how soon \.{\\cr} occurred in that row.
+
+@<Set the unset box |q| and the unset boxes in it@>=
+{@+if (mode==-vmode)
+ {@+type(q)=hlist_node;width(q)=width(p);
+ }
+else{@+type(q)=vlist_node;height(q)=height(p);
+ }
+glue_order(q)=glue_order(p);glue_sign(q)=glue_sign(p);
+glue_set(q)=glue_set(p);shift_amount(q)=o;
+r=link(list_ptr(q));s=link(list_ptr(p));
+@/do@+{@<Set the glue in node |r| and change it from an unset node@>;
+r=link(link(r));s=link(link(s));
+}@+ while (!(r==null));
+}
+
+@ A box made from spanned columns will be followed by tabskip glue nodes and
+by empty boxes as if there were no spanning. This permits perfect alignment
+of subsequent entries, and it prevents values that depend on floating point
+arithmetic from entering into the dimensions of any boxes.
+
+@<Set the glue in node |r|...@>=
+n=span_count(r);t=width(s);w=t;u=hold_head;
+while (n > min_quarterword)
+ {@+decr(n);
+ @<Append tabskip glue and an empty box to list |u|, and update |s| and |t| as the
+prototype nodes are passed@>;
+ }
+if (mode==-vmode)
+ @<Make the unset node |r| into an |hlist_node| of width |w|, setting the glue as
+if the width were |t|@>@;
+else@<Make the unset node |r| into a |vlist_node| of height |w|, setting the glue
+as if the height were |t|@>;
+shift_amount(r)=0;
+if (u!=hold_head) /*append blank boxes to account for spanned nodes*/
+ {@+link(u)=link(r);link(r)=link(hold_head);r=u;
+ }
+
+@ @<Append tabskip glue and an empty box to list |u|...@>=
+s=link(s);v=glue_ptr(s);link(u)=new_glue(v);u=link(u);
+subtype(u)=tab_skip_code+1;t=t+width(v);
+if (glue_sign(p)==stretching)
+ {@+if (stretch_order(v)==glue_order(p))
+ t=t+round(float(glue_set(p))*stretch(v));
+@^real multiplication@>
+ }
+else if (glue_sign(p)==shrinking)
+ {@+if (shrink_order(v)==glue_order(p))
+ t=t-round(float(glue_set(p))*shrink(v));
+ }
+s=link(s);link(u)=new_null_box();u=link(u);t=t+width(s);
+if (mode==-vmode) width(u)=width(s);@+else
+ {@+type(u)=vlist_node;height(u)=width(s);
+ }
+
+@ @<Make the unset node |r| into an |hlist_node| of width |w|...@>=
+{@+height(r)=height(q);depth(r)=depth(q);
+if (t==width(r))
+ {@+glue_sign(r)=normal;glue_order(r)=normal;
+ set_glue_ratio_zero(glue_set(r));
+ }
+else if (t > width(r))
+ {@+glue_sign(r)=stretching;
+ if (glue_stretch(r)==0) set_glue_ratio_zero(glue_set(r));
+ else glue_set(r)=unfloat((t-width(r))/(double)glue_stretch(r));
+@^real division@>
+ }
+else{@+glue_order(r)=glue_sign(r);glue_sign(r)=shrinking;
+ if (glue_shrink(r)==0) set_glue_ratio_zero(glue_set(r));
+ else if ((glue_order(r)==normal)&&(width(r)-t > glue_shrink(r)))
+ set_glue_ratio_one(glue_set(r));
+ else glue_set(r)=unfloat((width(r)-t)/(double)glue_shrink(r));
+ }
+width(r)=w;type(r)=hlist_node;
+}
+
+@ @<Make the unset node |r| into a |vlist_node| of height |w|...@>=
+{@+width(r)=width(q);
+if (t==height(r))
+ {@+glue_sign(r)=normal;glue_order(r)=normal;
+ set_glue_ratio_zero(glue_set(r));
+ }
+else if (t > height(r))
+ {@+glue_sign(r)=stretching;
+ if (glue_stretch(r)==0) set_glue_ratio_zero(glue_set(r));
+ else glue_set(r)=unfloat((t-height(r))/(double)glue_stretch(r));
+@^real division@>
+ }
+else{@+glue_order(r)=glue_sign(r);glue_sign(r)=shrinking;
+ if (glue_shrink(r)==0) set_glue_ratio_zero(glue_set(r));
+ else if ((glue_order(r)==normal)&&(height(r)-t > glue_shrink(r)))
+ set_glue_ratio_one(glue_set(r));
+ else glue_set(r)=unfloat((height(r)-t)/(double)glue_shrink(r));
+ }
+height(r)=w;type(r)=vlist_node;
+}
+
+@ We now have a completed alignment, in the list that starts at |head|
+and ends at |tail|. This list will be merged with the one that encloses
+it. (In case the enclosing mode is |mmode|, for displayed formulas,
+we will need to insert glue before and after the display; that part of the
+program will be deferred until we're more familiar with such operations.)
+
+In restricted horizontal mode, the |clang| part of |aux| is undefined;
+an over-cautious \PASCAL\ runtime system may complain about this.
+@^dirty \PASCAL@>
+
+@<Insert the \(c)current list into its environment@>=
+aux_save=aux;p=link(head);q=tail;pop_nest();
+if (mode==mmode) @<Finish an alignment in a display@>@;
+else{@+aux=aux_save;link(tail)=p;
+ if (p!=null) tail=q;
+ if (mode==vmode) build_page();
+ }
+
+@* Breaking paragraphs into lines.
+We come now to what is probably the most interesting algorithm of \TeX:
+the mechanism for choosing the ``best possible'' breakpoints that yield
+the individual lines of a paragraph. \TeX's line-breaking algorithm takes
+a given horizontal list and converts it to a sequence of boxes that are
+appended to the current vertical list. In the course of doing this, it
+creates a special data structure containing three kinds of records that are
+not used elsewhere in \TeX. Such nodes are created while a paragraph is
+being processed, and they are destroyed afterwards; thus, the other parts
+of \TeX\ do not need to know anything about how line-breaking is done.
+
+The method used here is based on an approach devised by Michael F. Plass and
+@^Plass, Michael Frederick@>
+@^Knuth, Donald Ervin@>
+the author in 1977, subsequently generalized and improved by the same two
+people in 1980. A detailed discussion appears in {\sl SOFTWARE---Practice
+\AM\ Experience \bf11} (1981), 1119--1184, where it is shown that the
+line-breaking problem can be regarded as a special case of the problem of
+computing the shortest path in an acyclic network. The cited paper includes
+numerous examples and describes the history of line breaking as it has been
+practiced by printers through the ages. The present implementation adds two
+new ideas to the algorithm of 1980: Memory space requirements are considerably
+reduced by using smaller records for inactive nodes than for active ones,
+and arithmetic overflow is avoided by using ``delta distances'' instead of
+keeping track of the total distance from the beginning of the paragraph to the
+current point.
+
+@ The |line_break| procedure should be invoked only in horizontal mode; it
+leaves that mode and places its output into the current vlist of the
+enclosing vertical mode (or internal vertical mode).
+There is one explicit parameter: |final_widow_penalty| is the amount of
+additional penalty to be inserted before the final line of the paragraph.
+
+There are also a number of implicit parameters: The hlist to be broken
+starts at |link(head)|, and it is nonempty. The value of |prev_graf| in the
+enclosing semantic level tells where the paragraph should begin in the
+sequence of line numbers, in case hanging indentation or \.{\\parshape}
+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.
+
+@<Glob...@>=
+pointer @!just_box; /*the |hlist_node| for the last line of the new paragraph*/
+
+@ Since |line_break| is a rather lengthy procedure---sort of a small world unto
+itself---we must build it up little by little, somewhat more cautiously
+than we have done with the simpler procedures of \TeX. Here is the
+general outline.
+
+@p@t\4@>@<Declare subprocedures for |line_break|@>@;
+void line_break(int @!final_widow_penalty)
+{@+
+@<Local variables for line breaking@>@;
+pack_begin_line=mode_line; /*this is for over/underfull box messages*/
+@<Get ready to start line breaking@>;
+@<Find optimal breakpoints@>;
+@<Break the paragraph at the chosen breakpoints, justify the resulting lines to the
+correct widths, and append them to the current vertical list@>;
+@<Clean up the memory by removing the break nodes@>;
+pack_begin_line=0;
+}
+
+@ The first task is to move the list from |head| to |temp_head| and go
+into the enclosing semantic level. We also append the \.{\\parfillskip}
+glue to the end of the paragraph, removing a space (or other glue node) if
+it was there, since spaces usually precede blank lines and instances of
+`\.{\$\$}'. The |par_fill_skip| is preceded by an infinite penalty, so
+it will never be considered as a potential breakpoint.
+
+This code assumes that a |glue_node| and a |penalty_node| occupy the
+same number of |mem|~words.
+@^data structure assumptions@>
+
+@<Get ready to start...@>=
+link(temp_head)=link(head);
+if (is_char_node(tail)) tail_append(new_penalty(inf_penalty))@;
+else if (type(tail)!=glue_node) tail_append(new_penalty(inf_penalty))@;
+else{@+type(tail)=penalty_node;delete_glue_ref(glue_ptr(tail));
+ flush_node_list(leader_ptr(tail));penalty(tail)=inf_penalty;
+ }
+link(tail)=new_param_glue(par_fill_skip_code);
+init_cur_lang=prev_graf%0200000;
+init_l_hyf=prev_graf/020000000;
+init_r_hyf=(prev_graf/0200000)%0100;
+pop_nest();
+
+@ When looking for optimal line breaks, \TeX\ creates a ``break node'' for
+each break that is {\sl feasible}, in the sense that there is a way to end
+a line at the given place without requiring any line to stretch more than
+a given tolerance. A break node is characterized by three things: the position
+of the break (which is a pointer to a |glue_node|, |math_node|, |penalty_node|,
+or |disc_node|); the ordinal number of the line that will follow this
+breakpoint; and the fitness classification of the line that has just
+ended, i.e., |tight_fit|, |decent_fit|, |loose_fit|, or |very_loose_fit|.
+
+@d tight_fit 3 /*fitness classification for lines shrinking 0.5 to 1.0 of their
+ shrinkability*/
+@d loose_fit 1 /*fitness classification for lines stretching 0.5 to 1.0 of their
+ stretchability*/
+@d very_loose_fit 0 /*fitness classification for lines stretching more than
+ their stretchability*/
+@d decent_fit 2 /*fitness classification for all other lines*/
+
+@ The algorithm essentially determines the best possible way to achieve
+each feasible combination of position, line, and fitness. Thus, it answers
+questions like, ``What is the best way to break the opening part of the
+paragraph so that the fourth line is a tight line ending at such-and-such
+a place?'' However, the fact that all lines are to be the same length
+after a certain point makes it possible to regard all sufficiently large
+line numbers as equivalent, when the looseness parameter is zero, and this
+makes it possible for the algorithm to save space and time.
+
+An ``active node'' and a ``passive node'' are created in |mem| for each
+feasible breakpoint that needs to be considered. Active nodes are three
+words long and passive nodes are two words long. We need active nodes only
+for breakpoints near the place in the paragraph that is currently being
+examined, so they are recycled within a comparatively short time after
+they are created.
+
+@ An active node for a given breakpoint contains six fields:
+
+\yskip\hang|link| points to the next node in the list of active nodes; the
+last active node has |link==last_active|.
+
+\yskip\hang|break_node| points to the passive node associated with this
+breakpoint.
+
+\yskip\hang|line_number| is the number of the line that follows this
+breakpoint.
+
+\yskip\hang|fitness| is the fitness classification of the line ending at this
+breakpoint.
+
+\yskip\hang|type| is either |hyphenated| or |unhyphenated|, depending on
+whether this breakpoint is a |disc_node|.
+
+\yskip\hang|total_demerits| is the minimum possible sum of demerits over all
+lines leading from the beginning of the paragraph to this breakpoint.
+
+\yskip\noindent
+The value of |link(active)| points to the first active node on a linked list
+of all currently active nodes. This list is in order by |line_number|,
+except that nodes with |line_number > easy_line| may be in any order relative
+to each other.
+
+@d active_node_size 3 /*number of words in active nodes*/
+@d fitness subtype /*|very_loose_fit dotdot tight_fit| on final line for this break*/
+@d break_node rlink /*pointer to the corresponding passive node*/
+@d line_number llink /*line that begins at this breakpoint*/
+@d total_demerits(X) mem[X+2].i /*the quantity that \TeX\ minimizes*/
+@d unhyphenated 0 /*the |type| of a normal active break node*/
+@d hyphenated 1 /*the |type| of an active node that breaks at a |disc_node|*/
+@d last_active active /*the active list ends where it begins*/
+
+@ @<Initialize the special list heads...@>=
+type(last_active)=hyphenated;line_number(last_active)=max_halfword;
+subtype(last_active)=0; /*the |subtype| is never examined by the algorithm*/
+
+@ The passive node for a given breakpoint contains only four fields:
+
+\yskip\hang|link| points to the passive node created just before this one,
+if any, otherwise it is |null|.
+
+\yskip\hang|cur_break| points to the position of this breakpoint in the
+horizontal list for the paragraph being broken.
+
+\yskip\hang|prev_break| points to the passive node that should precede this
+one in an optimal path to this breakpoint.
+
+\yskip\hang|serial| is equal to |n| if this passive node is the |n|th
+one created during the current pass. (This field is used only when
+printing out detailed statistics about the line-breaking calculations.)
+
+\yskip\noindent
+There is a global variable called |passive| that points to the most
+recently created passive node. Another global variable, |printed_node|,
+is used to help print out the paragraph when detailed information about
+the line-breaking computation is being displayed.
+
+@d passive_node_size 2 /*number of words in passive nodes*/
+@d cur_break rlink /*in passive node, points to position of this breakpoint*/
+@d prev_break llink /*points to passive node that should precede this one*/
+@d serial info /*serial number for symbolic identification*/
+
+@<Glob...@>=
+pointer @!passive; /*most recent node on passive list*/
+pointer @!printed_node; /*most recent node that has been printed*/
+halfword @!pass_number; /*the number of passive nodes allocated on this pass*/
+
+@ The active list also contains ``delta'' nodes that help the algorithm
+compute the badness of individual lines. Such nodes appear only between two
+active nodes, and they have |type==delta_node|. If |p| and |r| are active nodes
+and if |q| is a delta node between them, so that |link(p)==q| and |link(q)==r|,
+then |q| tells the space difference between lines in the horizontal list that
+start after breakpoint |p| and lines that start after breakpoint |r|. In
+other words, if we know the length of the line that starts after |p| and
+ends at our current position, then the corresponding length of the line that
+starts after |r| is obtained by adding the amounts in node~|q|. A delta node
+contains six scaled numbers, since it must record the net change in glue
+stretchability with respect to all orders of infinity. The natural width
+difference appears in |mem[q+1].sc|; the stretch differences in units of
+pt, fil, fill, and filll appear in |mem[q+2 dotdot q+5].sc|; and the shrink difference
+appears in |mem[q+6].sc|. The |subtype| field of a delta node is not used.
+
+@d delta_node_size 7 /*number of words in a delta node*/
+@d delta_node 2 /*|type| field in a delta node*/
+
+@ As the algorithm runs, it maintains a set of six delta-like registers
+for the length of the line following the first active breakpoint to the
+current position in the given hlist. When it makes a pass through the
+active list, it also maintains a similar set of six registers for the
+length following the active breakpoint of current interest. A third set
+holds the length of an empty line (namely, the sum of \.{\\leftskip} and
+\.{\\rightskip}); and a fourth set is used to create new delta nodes.
+
+When we pass a delta node we want to do operations like
+$$\hbox{\ignorespaces|for
+k=1 to 6 do cur_active_width[k]=cur_active_width[k]+mem[q+k].sc|};$$ and we
+want to do this without the overhead of |for| loops. The |do_all_six|
+macro makes such six-tuples convenient.
+
+@d do_all_six(X) X(1);X(2);X(3);X(4);X(5);X(6)
+
+@<Glob...@>=
+scaled @!active_width0[6], *const @!active_width = @!active_width0-1;
+ /*distance from first active node to~|cur_p|*/
+scaled @!cur_active_width0[6], *const @!cur_active_width = @!cur_active_width0-1; /*distance from current active node*/
+scaled @!background0[6], *const @!background = @!background0-1; /*length of an ``empty'' line*/
+scaled @!break_width0[6], *const @!break_width = @!break_width0-1; /*length being computed after current break*/
+
+@ Let's state the principles of the delta nodes more precisely and concisely,
+so that the following programs will be less obscure. For each legal
+breakpoint~|p| in the paragraph, we define two quantities $\alpha(p)$ and
+$\beta(p)$ such that the length of material in a line from breakpoint~|p|
+to breakpoint~|q| is $\gamma+\beta(q)-\alpha(p)$, for some fixed $\gamma$.
+Intuitively, $\alpha(p)$ and $\beta(q)$ are the total length of material from
+the beginning of the paragraph to a point ``after'' a break at |p| and to a
+point ``before'' a break at |q|; and $\gamma$ is the width of an empty line,
+namely the length contributed by \.{\\leftskip} and \.{\\rightskip}.
+
+Suppose, for example, that the paragraph consists entirely of alternating
+boxes and glue skips; let the boxes have widths $x_1\ldots x_n$ and
+let the skips have widths $y_1\ldots y_n$, so that the paragraph can be
+represented by $x_1y_1\ldots x_ny_n$. Let $p_i$ be the legal breakpoint
+at $y_i$; then $\alpha(p_i)=x_1+y_1+\cdots+x_i+y_i$, and $\beta(p_i)=
+x_1+y_1+\cdots+x_i$. To check this, note that the length of material from
+$p_2$ to $p_5$, say, is $\gamma+x_3+y_3+x_4+y_4+x_5=\gamma+\beta(p_5)
+-\alpha(p_2)$.
+
+The quantities $\alpha$, $\beta$, $\gamma$ involve glue stretchability and
+shrinkability as well as a natural width. If we were to compute $\alpha(p)$
+and $\beta(p)$ for each |p|, we would need multiple precision arithmetic, and
+the multiprecise numbers would have to be kept in the active nodes.
+\TeX\ avoids this problem by working entirely with relative differences
+or ``deltas.'' Suppose, for example, that the active list contains
+$a_1\,\delta_1\,a_2\,\delta_2\,a_3$, where the |a|'s are active breakpoints
+and the $\delta$'s are delta nodes. Then $\delta_1=\alpha(a_1)-\alpha(a_2)$
+and $\delta_2=\alpha(a_2)-\alpha(a_3)$. If the line breaking algorithm is
+currently positioned at some other breakpoint |p|, the |active_width| array
+contains the value $\gamma+\beta(p)-\alpha(a_1)$. If we are scanning through
+the list of active nodes and considering a tentative line that runs from
+$a_2$ to~|p|, say, the |cur_active_width| array will contain the value
+$\gamma+\beta(p)-\alpha(a_2)$. Thus, when we move from $a_2$ to $a_3$,
+we want to add $\alpha(a_2)-\alpha(a_3)$ to |cur_active_width|; and this
+is just $\delta_2$, which appears in the active list between $a_2$ and
+$a_3$. The |background| array contains $\gamma$. The |break_width| array
+will be used to calculate values of new delta nodes when the active
+list is being updated.
+
+@ Glue nodes in a horizontal list that is being paragraphed are not supposed to
+include ``infinite'' shrinkability; that is why the algorithm maintains
+four registers for stretching but only one for shrinking. If the user tries to
+introduce infinite shrinkability, the shrinkability will be reset to finite
+and an error message will be issued. A boolean variable |no_shrink_error_yet|
+prevents this error message from appearing more than once per paragraph.
+
+@d check_shrinkage(X) if ((shrink_order(X)!=normal)&&(shrink(X)!=0))
+ {@+X=finite_shrink(X);
+ }
+
+@<Glob...@>=
+bool @!no_shrink_error_yet; /*have we complained about infinite shrinkage?*/
+
+@ @<Declare subprocedures for |line_break|@>=
+pointer finite_shrink(pointer @!p) /*recovers from infinite shrinkage*/
+{@+pointer q; /*new glue specification*/
+if (no_shrink_error_yet)
+ {@+no_shrink_error_yet=false;
+ print_err("Infinite glue shrinkage found in a paragraph");
+@.Infinite glue shrinkage...@>
+ help5("The paragraph just ended includes some glue that has")@/
+ ("infinite shrinkability, e.g., `\\hskip 0pt minus 1fil'.")@/
+ ("Such glue doesn't belong there---it allows a paragraph")@/
+ ("of any length to fit on one line. But it's safe to proceed,")@/
+ ("since the offensive shrinkability has been made finite.");
+ error();
+ }
+q=new_spec(p);shrink_order(q)=normal;
+delete_glue_ref(p);return q;
+}
+
+@ @<Get ready to start...@>=
+no_shrink_error_yet=true;@/
+check_shrinkage(left_skip);check_shrinkage(right_skip);@/
+q=left_skip;r=right_skip;background[1]=width(q)+width(r);@/
+background[2]=0;background[3]=0;background[4]=0;background[5]=0;@/
+background[2+stretch_order(q)]=stretch(q);@/
+background[2+stretch_order(r)]=@|background[2+stretch_order(r)]+stretch(r);@/
+background[6]=shrink(q)+shrink(r);
+
+@ A pointer variable |cur_p| runs through the given horizontal list as we look
+for breakpoints. This variable is global, since it is used both by |line_break|
+and by its subprocedure |try_break|.
+
+Another global variable called |threshold| is used to determine the feasibility
+of individual lines: Breakpoints are feasible if there is a way to reach
+them without creating lines whose badness exceeds |threshold|. (The
+badness is compared to |threshold| before penalties are added, so that
+penalty values do not affect the feasibility of breakpoints, except that
+no break is allowed when the penalty is 10000 or more.) If |threshold|
+is 10000 or more, all legal breaks are considered feasible, since the
+|badness| function specified above never returns a value greater than~10000.
+
+Up to three passes might be made through the paragraph in an attempt to find at
+least one set of feasible breakpoints. On the first pass, we have
+|threshold==pretolerance| and |second_pass==final_pass==false|.
+If this pass fails to find a
+feasible solution, |threshold| is set to |tolerance|, |second_pass| is set
+|true|, and an attempt is made to hyphenate as many words as possible.
+If that fails too, we add |emergency_stretch| to the background
+stretchability and set |final_pass==true|.
+
+@<Glob...@>=
+pointer @!cur_p; /*the current breakpoint under consideration*/
+bool @!second_pass; /*is this our second attempt to break this paragraph?*/
+bool @!final_pass; /*is this our final attempt to break this paragraph?*/
+int @!threshold; /*maximum badness on feasible lines*/
+
+@ The heart of the line-breaking procedure is `|try_break|', a subroutine
+that tests if the current breakpoint |cur_p| is feasible, by running
+through the active list to see what lines of text can be made from active
+nodes to~|cur_p|. If feasible breaks are possible, new break nodes are
+created. If |cur_p| is too far from an active node, that node is
+deactivated.
+
+The parameter |pi| to |try_break| is the penalty associated
+with a break at |cur_p|; we have |pi==eject_penalty| if the break is forced,
+and |pi==inf_penalty| if the break is illegal.
+
+The other parameter, |break_type|, is set to |hyphenated| or |unhyphenated|,
+depending on whether or not the current break is at a |disc_node|. The
+end of a paragraph is also regarded as `|hyphenated|'; this case is
+distinguishable by the condition |cur_p==null|.
+
+@d copy_to_cur_active(X) cur_active_width[X]=active_width[X]
+@<Declare subprocedures for |line_break|@>=
+void try_break(int @!pi, small_number @!break_type)
+{@+
+pointer r; /*runs through the active list*/
+pointer @!prev_r; /*stays a step behind |r|*/
+halfword @!old_l; /*maximum line number in current equivalence class of lines*/
+bool @!no_break_yet; /*have we found a feasible break at |cur_p|?*/
+@<Other local variables for |try_break|@>@;
+@<Make sure that |pi| is in the proper range@>;
+no_break_yet=true;prev_r=active;old_l=0;
+do_all_six(copy_to_cur_active);
+loop@+{@+resume: r=link(prev_r);
+ @<If node |r| is of type |delta_node|, update |cur_active_width|, set |prev_r| and
+|prev_prev_r|, then |goto continue|@>;
+ @<If a line number class has ended, create new active nodes for the best feasible
+breaks in that class; then |return| if |r=last_active|, otherwise compute the new
+|line_width|@>;
+ @<Consider the demerits for a line from |r| to |cur_p|; deactivate node |r| if it
+should no longer be active; then |goto continue| if a line from |r| to |cur_p| is
+infeasible, otherwise record a new feasible break@>;
+ }
+end: ;
+#ifdef @!STAT
+@<Update the value of |printed_node| for symbolic displays@>;
+#endif
+@;
+}
+
+@ @<Other local variables for |try_break|@>=
+pointer @!prev_prev_r; /*a step behind |prev_r|, if |type(prev_r)==delta_node|*/
+pointer @!s; /*runs through nodes ahead of |cur_p|*/
+pointer @!q; /*points to a new node being created*/
+pointer @!v; /*points to a glue specification or a node ahead of |cur_p|*/
+int @!t; /*node count, if |cur_p| is a discretionary node*/
+internal_font_number @!f; /*used in character width calculation*/
+halfword @!l; /*line number of current active node*/
+bool @!node_r_stays_active; /*should node |r| remain in the active list?*/
+scaled @!line_width; /*the current line will be justified to this width*/
+uint8_t @!fit_class; /*possible fitness class of test line*/
+halfword @!b; /*badness of test line*/
+int @!d; /*demerits of test line*/
+bool @!artificial_demerits; /*has |d| been forced to zero?*/
+#ifdef @!STAT
+pointer @!save_link; /*temporarily holds value of |link(cur_p)|*/
+#endif
+scaled @!shortfall; /*used in badness calculations*/
+
+@ @<Make sure that |pi| is in the proper range@>=
+if (abs(pi) >= inf_penalty)
+ if (pi > 0) goto end; /*this breakpoint is inhibited by infinite penalty*/
+ else pi=eject_penalty /*this breakpoint will be forced*/
+
+@ The following code uses the fact that |type(last_active)!=delta_node|.
+
+@d update_width(X) @|
+ cur_active_width[X]=cur_active_width[X]+mem[r+X].sc
+
+@<If node |r|...@>=
+@^inner loop@>
+if (type(r)==delta_node)
+ {@+do_all_six(update_width);
+ prev_prev_r=prev_r;prev_r=r;goto resume;
+ }
+
+@ As we consider various ways to end a line at |cur_p|, in a given line number
+class, we keep track of the best total demerits known, in an array with
+one entry for each of the fitness classifications. For example,
+|minimal_demerits[tight_fit]| contains the fewest total demerits of feasible
+line breaks ending at |cur_p| with a |tight_fit| line; |best_place[tight_fit]|
+points to the passive node for the break before~|cur_p| that achieves such
+an optimum; and |best_pl_line[tight_fit]| is the |line_number| field in the
+active node corresponding to |best_place[tight_fit]|. When no feasible break
+sequence is known, the |minimal_demerits| entries will be equal to
+|awful_bad|, which is $2^{30}-1$. Another variable, |minimum_demerits|,
+keeps track of the smallest value in the |minimal_demerits| array.
+
+@d awful_bad 07777777777 /*more than a billion demerits*/
+
+@<Global...@>=
+int @!minimal_demerits0[tight_fit-very_loose_fit+1], *const @!minimal_demerits = @!minimal_demerits0-very_loose_fit; /*best total
+ demerits known for current line class and position, given the fitness*/
+int @!minimum_demerits; /*best total demerits known for current line class
+ and position*/
+pointer @!best_place0[tight_fit-very_loose_fit+1], *const @!best_place = @!best_place0-very_loose_fit; /*how to achieve
+ |minimal_demerits|*/
+halfword @!best_pl_line0[tight_fit-very_loose_fit+1], *const @!best_pl_line = @!best_pl_line0-very_loose_fit; /*corresponding
+ line number*/
+
+@ @<Get ready to start...@>=
+minimum_demerits=awful_bad;
+minimal_demerits[tight_fit]=awful_bad;
+minimal_demerits[decent_fit]=awful_bad;
+minimal_demerits[loose_fit]=awful_bad;
+minimal_demerits[very_loose_fit]=awful_bad;
+
+@ The first part of the following code is part of \TeX's inner loop, so
+we don't want to waste any time. The current active node, namely node |r|,
+contains the line number that will be considered next. At the end of the
+list we have arranged the data structure so that |r==last_active| and
+|line_number(last_active) > old_l|.
+@^inner loop@>
+
+@<If a line number class...@>=
+{@+l=line_number(r);
+if (l > old_l)
+ {@+ /*now we are no longer in the inner loop*/
+ if ((minimum_demerits < awful_bad)&&@|
+ ((old_l!=easy_line)||(r==last_active)))
+ @<Create new active nodes for the best feasible breaks just found@>;
+ if (r==last_active) goto end;
+ @<Compute the new line width@>;
+ }
+}
+
+@ It is not necessary to create new active nodes having |minimal_demerits|
+greater than
+|minimum_demerits+abs(adj_demerits)|, since such active nodes will never
+be chosen in the final paragraph breaks. This observation allows us to
+omit a substantial number of feasible breakpoints from further consideration.
+
+@<Create new active nodes...@>=
+{@+if (no_break_yet) @<Compute the values of |break_width|@>;
+@<Insert a delta node to prepare for breaks at |cur_p|@>;
+if (abs(adj_demerits) >= awful_bad-minimum_demerits)
+ minimum_demerits=awful_bad-1;
+else minimum_demerits=minimum_demerits+abs(adj_demerits);
+for (fit_class=very_loose_fit; fit_class<=tight_fit; fit_class++)
+ {@+if (minimal_demerits[fit_class] <= minimum_demerits)
+ @<Insert a new active node from |best_place[fit_class]| to |cur_p|@>;
+ minimal_demerits[fit_class]=awful_bad;
+ }
+minimum_demerits=awful_bad;
+@<Insert a delta node to prepare for the next active node@>;
+}
+
+@ When we insert a new active node for a break at |cur_p|, suppose this
+new node is to be placed just before active node |a|; then we essentially
+want to insert `$\delta\,|cur_p|\,\delta^\prime$' before |a|, where
+$\delta=\alpha(a)-\alpha(|cur_p|)$ and $\delta^\prime=\alpha(|cur_p|)-\alpha(a)$
+in the notation explained above. The |cur_active_width| array now holds
+$\gamma+\beta(|cur_p|)-\alpha(a)$; so $\delta$ can be obtained by
+subtracting |cur_active_width| from the quantity $\gamma+\beta(|cur_p|)-
+\alpha(|cur_p|)$. The latter quantity can be regarded as the length of a
+line ``from |cur_p| to |cur_p|''; we call it the |break_width| at |cur_p|.
+
+The |break_width| is usually negative, since it consists of the background
+(which is normally zero) minus the width of nodes following~|cur_p| that are
+eliminated after a break. If, for example, node |cur_p| is a glue node, the
+width of this glue is subtracted from the background; and we also look
+ahead to eliminate all subsequent glue and penalty and kern and math
+nodes, subtracting their widths as well.
+
+Kern nodes do not disappear at a line break unless they are |explicit|.
+
+@d set_break_width_to_background(X) break_width[X]=background[X]
+
+@<Compute the values of |break...@>=
+{@+no_break_yet=false;do_all_six(set_break_width_to_background);
+s=cur_p;
+if (break_type > unhyphenated) if (cur_p!=null)
+ @<Compute the discretionary |break_width| values@>;
+while (s!=null)
+ {@+if (is_char_node(s)) goto done;
+ switch (type(s)) {
+ case glue_node: @<Subtract glue from |break_width|@>@;@+break;
+ case penalty_node: do_nothing;@+break;
+ case math_node: break_width[1]=break_width[1]-width(s);@+break;
+ case kern_node: if (subtype(s)!=explicit) goto done;
+ else break_width[1]=break_width[1]-width(s);@+break;
+ default:goto done;
+ } @/
+ s=link(s);
+ }
+done: ;}
+
+@ @<Subtract glue from |break...@>=
+{@+v=glue_ptr(s);break_width[1]=break_width[1]-width(v);
+break_width[2+stretch_order(v)]=break_width[2+stretch_order(v)]-stretch(v);
+break_width[6]=break_width[6]-shrink(v);
+}
+
+@ When |cur_p| is a discretionary break, the length of a line ``from |cur_p| to
+|cur_p|'' has to be defined properly so that the other calculations work out.
+Suppose that the pre-break text at |cur_p| has length $l_0$, the post-break
+text has length $l_1$, and the replacement text has length |l|. Suppose
+also that |q| is the node following the replacement text. Then length of a
+line from |cur_p| to |q| will be computed as $\gamma+\beta(q)-\alpha(|cur_p|)$,
+where $\beta(q)=\beta(|cur_p|)-l_0+l$. The actual length will be the background
+plus $l_1$, so the length from |cur_p| to |cur_p| should be $\gamma+l_0+l_1-l$.
+If the post-break text of the discretionary is empty, a break may also
+discard~|q|; in that unusual case we subtract the length of~|q| and any
+other nodes that will be discarded after the discretionary break.
+
+The value of $l_0$ need not be computed, since |line_break| will put
+it into the global variable |disc_width| before calling |try_break|.
+
+@<Glob...@>=
+scaled @!disc_width; /*the length of discretionary material preceding a break*/
+
+@ @<Compute the discretionary |break...@>=
+{@+t=replace_count(cur_p);v=cur_p;s=post_break(cur_p);
+while (t > 0)
+ {@+decr(t);v=link(v);
+ @<Subtract the width of node |v| from |break_width|@>;
+ }
+while (s!=null)
+ {@+@<Add the width of node |s| to |break_width|@>;
+ s=link(s);
+ }
+break_width[1]=break_width[1]+disc_width;
+if (post_break(cur_p)==null) s=link(v);
+ /*nodes may be discardable after the break*/
+}
+
+@ Replacement texts and discretionary texts are supposed to contain
+only character nodes, kern nodes, ligature nodes, and box or rule nodes.
+
+@<Subtract the width of node |v|...@>=
+if (is_char_node(v))
+ {@+f=font(v);
+ break_width[1]=break_width[1]-char_width(f)(char_info(f)(character(v)));
+ }
+else switch (type(v)) {
+ case ligature_node: {@+f=font(lig_char(v));@/
+ break_width[1]=@|break_width[1]-
+ char_width(f)(char_info(f)(character(lig_char(v))));
+ } @+break;
+ case hlist_node: case vlist_node: case rule_node: case kern_node:
+ break_width[1]=break_width[1]-width(v);@+break;
+ default:confusion(@[@<|"disc1"|@>@]);
+@:this can't happen disc1}{\quad disc1@>
+ }
+
+@ @<Add the width of node |s| to |b...@>=
+if (is_char_node(s))
+ {@+f=font(s);
+ break_width[1]=@|break_width[1]+char_width(f)(char_info(f)(character(s)));
+ }
+else switch (type(s)) {
+ case ligature_node: {@+f=font(lig_char(s));
+ break_width[1]=break_width[1]+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ } @+break;
+ case hlist_node: case vlist_node: case rule_node: case kern_node:
+ break_width[1]=break_width[1]+width(s);@+break;
+ default:confusion(@[@<|"disc2"|@>@]);
+@:this can't happen disc2}{\quad disc2@>
+ }
+
+@ We use the fact that |type(active)!=delta_node|.
+
+@d convert_to_break_width(X) @|
+ mem[prev_r+X].sc=@|@t\hskip10pt@>mem[prev_r+X].sc
+ -cur_active_width[X]+break_width[X]
+@d store_break_width(X) active_width[X]=break_width[X]
+@d new_delta_to_break_width(X) @|
+ mem[q+X].sc=break_width[X]-cur_active_width[X]
+
+@<Insert a delta node to prepare for breaks at |cur_p|@>=
+if (type(prev_r)==delta_node) /*modify an existing delta node*/
+ {@+do_all_six(convert_to_break_width);
+ }
+else if (prev_r==active) /*no delta node needed at the beginning*/
+ {@+do_all_six(store_break_width);
+ }
+else{@+q=get_node(delta_node_size);link(q)=r;type(q)=delta_node;@/
+ subtype(q)=0; /*the |subtype| is not used*/
+ do_all_six(new_delta_to_break_width);
+ link(prev_r)=q;prev_prev_r=prev_r;prev_r=q;
+ }
+
+@ When the following code is performed, we will have just inserted at
+least one active node before |r|, so |type(prev_r)!=delta_node|.
+
+@d new_delta_from_break_width(X) @|mem[q+X].sc=
+ cur_active_width[X]-break_width[X]
+
+@<Insert a delta node to prepare for the next active node@>=
+if (r!=last_active)
+ {@+q=get_node(delta_node_size);link(q)=r;type(q)=delta_node;@/
+ subtype(q)=0; /*the |subtype| is not used*/
+ do_all_six(new_delta_from_break_width);
+ link(prev_r)=q;prev_prev_r=prev_r;prev_r=q;
+ }
+
+@ When we create an active node, we also create the corresponding
+passive node.
+
+@<Insert a new active node from |best_place[fit_class]| to |cur_p|@>=
+{@+q=get_node(passive_node_size);
+link(q)=passive;passive=q;cur_break(q)=cur_p;
+#ifdef @!STAT
+incr(pass_number);serial(q)=pass_number;
+#endif
+@;@/
+prev_break(q)=best_place[fit_class];@/
+q=get_node(active_node_size);break_node(q)=passive;
+line_number(q)=best_pl_line[fit_class]+1;
+fitness(q)=fit_class;type(q)=break_type;
+total_demerits(q)=minimal_demerits[fit_class];
+link(q)=r;link(prev_r)=q;prev_r=q;
+#ifdef @!STAT
+if (tracing_paragraphs > 0)
+ @<Print a symbolic description of the new break node@>;
+#endif
+@;@/
+}
+
+@ @<Print a symbolic description of the new break node@>=
+{@+print_nl("@@@@");print_int(serial(passive));
+@.\AT!\AT!@>
+print_str(": line ");print_int(line_number(q)-1);
+print_char('.');print_int(fit_class);
+if (break_type==hyphenated) print_char('-');
+print_str(" t=");print_int(total_demerits(q));
+print_str(" -> @@@@");
+if (prev_break(passive)==null) print_char('0');
+else print_int(serial(prev_break(passive)));
+}
+
+@ The length of lines depends on whether the user has specified
+\.{\\parshape} or \.{\\hangindent}. If |par_shape_ptr| is not null, it
+points to a $(2n+1)$-word record in |mem|, where the |info| in the first
+word contains the value of |n|, and the other $2n$ words contain the left
+margins and line lengths for the first |n| lines of the paragraph; the
+specifications for line |n| apply to all subsequent lines. If
+|par_shape_ptr==null|, the shape of the paragraph depends on the value of
+|n==hang_after|; if |n >= 0|, hanging indentation takes place on lines |n+1|,
+|n+2|, \dots, otherwise it takes place on lines 1, \dots, $\vert
+n\vert$. When hanging indentation is active, the left margin is
+|hang_indent|, if |hang_indent >= 0|, else it is 0; the line length is
+$|hsize|-\vert|hang_indent|\vert$. The normal setting is
+|par_shape_ptr==null|, |hang_after==1|, and |hang_indent==0|.
+Note that if |hang_indent==0|, the value of |hang_after| is irrelevant.
+@^length of lines@> @^hanging indentation@>
+
+@<Glob...@>=
+halfword @!easy_line; /*line numbers | > easy_line| are equivalent in break nodes*/
+halfword @!last_special_line; /*line numbers | > last_special_line| all have
+ the same width*/
+scaled @!first_width; /*the width of all lines | <= last_special_line|, if
+ no \.{\\parshape} has been specified*/
+scaled @!second_width; /*the width of all lines | > last_special_line|*/
+scaled @!first_indent; /*left margin to go with |first_width|*/
+scaled @!second_indent; /*left margin to go with |second_width|*/
+
+@ We compute the values of |easy_line| and the other local variables relating
+to line length when the |line_break| procedure is initializing itself.
+
+@<Get ready to start...@>=
+if (par_shape_ptr==null)
+ if (hang_indent==0)
+ {@+last_special_line=0;second_width=hsize;
+ second_indent=0;
+ }
+ else@<Set line length parameters in preparation for hanging indentation@>@;
+else{@+last_special_line=info(par_shape_ptr)-1;
+ second_width=mem[par_shape_ptr+2*(last_special_line+1)].sc;
+ second_indent=mem[par_shape_ptr+2*last_special_line+1].sc;
+ }
+if (looseness==0) easy_line=last_special_line;
+else easy_line=max_halfword
+
+@ @<Set line length parameters in preparation for hanging indentation@>=
+{@+last_special_line=abs(hang_after);
+if (hang_after < 0)
+ {@+first_width=hsize-abs(hang_indent);
+ if (hang_indent >= 0) first_indent=hang_indent;
+ else first_indent=0;
+ second_width=hsize;second_indent=0;
+ }
+else{@+first_width=hsize;first_indent=0;
+ second_width=hsize-abs(hang_indent);
+ if (hang_indent >= 0) second_indent=hang_indent;
+ else second_indent=0;
+ }
+}
+
+@ When we come to the following code, we have just encountered the first
+active node~|r| whose |line_number| field contains |l|. Thus we want to
+compute the length of the $l\mskip1mu$th line of the current paragraph. Furthermore,
+we want to set |old_l| to the last number in the class of line numbers
+equivalent to~|l|.
+
+@<Compute the new line width@>=
+if (l > easy_line)
+ {@+line_width=second_width;old_l=max_halfword-1;
+ }
+else{@+old_l=l;
+ if (l > last_special_line) line_width=second_width;
+ else if (par_shape_ptr==null) line_width=first_width;
+ else line_width=mem[par_shape_ptr+2*l@,].sc;
+ }
+
+@ The remaining part of |try_break| deals with the calculation of
+demerits for a break from |r| to |cur_p|.
+
+The first thing to do is calculate the badness, |b|. This value will always
+be between zero and |inf_bad+1|; the latter value occurs only in the
+case of lines from |r| to |cur_p| that cannot shrink enough to fit the necessary
+width. In such cases, node |r| will be deactivated.
+We also deactivate node~|r| when a break at~|cur_p| is forced, since future
+breaks must go through a forced break.
+
+@<Consider the demerits for a line from |r| to |cur_p|...@>=
+{@+artificial_demerits=false;@/
+@^inner loop@>
+shortfall=line_width-cur_active_width[1]; /*we're this much too short*/
+if (shortfall > 0)
+ @<Set the value of |b| to the badness for stretching the line, and compute the corresponding
+|fit_class|@>@;
+else@<Set the value of |b| to the badness for shrinking the line, and compute the
+corresponding |fit_class|@>;
+if ((b > inf_bad)||(pi==eject_penalty))
+ @<Prepare to deactivate node~|r|, and |goto deactivate| unless there is a reason
+to consider lines of text from |r| to |cur_p|@>@;
+else{@+prev_r=r;
+ if (b > threshold) goto resume;
+ node_r_stays_active=true;
+ }
+@<Record a new feasible break@>;
+if (node_r_stays_active) goto resume; /*|prev_r| has been set to |r|*/
+deactivate: @<Deactivate node |r|@>;
+}
+
+@ When a line must stretch, the available stretchability can be found in the
+subarray |cur_active_width[2 dotdot 5]|, in units of points, fil, fill, and filll.
+
+The present section is part of \TeX's inner loop, and it is most often performed
+when the badness is infinite; therefore it is worth while to make a quick
+test for large width excess and small stretchability, before calling the
+|badness| subroutine.
+@^inner loop@>
+
+@<Set the value of |b| to the badness for stretching...@>=
+if ((cur_active_width[3]!=0)||(cur_active_width[4]!=0)||@|
+ (cur_active_width[5]!=0))
+ {@+b=0;fit_class=decent_fit; /*infinite stretch*/
+ }
+else{@+if (shortfall > 7230584) if (cur_active_width[2] < 1663497)
+ {@+b=inf_bad;fit_class=very_loose_fit;goto done1;
+ }
+ b=badness(shortfall, cur_active_width[2]);
+ if (b > 12)
+ if (b > 99) fit_class=very_loose_fit;
+ else fit_class=loose_fit;
+ else fit_class=decent_fit;
+ done1: ;
+ }
+
+@ Shrinkability is never infinite in a paragraph;
+we can shrink the line from |r| to |cur_p| by at most |cur_active_width[6]|.
+
+@<Set the value of |b| to the badness for shrinking...@>=
+{@+if (-shortfall > cur_active_width[6]) b=inf_bad+1;
+else b=badness(-shortfall, cur_active_width[6]);
+if (b > 12) fit_class=tight_fit;@+else fit_class=decent_fit;
+}
+
+@ During the final pass, we dare not lose all active nodes, lest we lose
+touch with the line breaks already found. The code shown here makes sure
+that such a catastrophe does not happen, by permitting overfull boxes as
+a last resort. This particular part of \TeX\ was a source of several subtle
+bugs before the correct program logic was finally discovered; readers
+who seek to ``improve'' \TeX\ should therefore think thrice before daring
+to make any changes here.
+@^overfull boxes@>
+
+@<Prepare to deactivate node~|r|, and |goto deactivate| unless...@>=
+{@+if (final_pass&&(minimum_demerits==awful_bad)&&@|
+ (link(r)==last_active)&&
+ (prev_r==active))
+ artificial_demerits=true; /*set demerits zero, this break is forced*/
+else if (b > threshold) goto deactivate;
+node_r_stays_active=false;
+}
+
+@ When we get to this part of the code, the line from |r| to |cur_p| is
+feasible, its badness is~|b|, and its fitness classification is |fit_class|.
+We don't want to make an active node for this break yet, but we will
+compute the total demerits and record them in the |minimal_demerits| array,
+if such a break is the current champion among all ways to get to |cur_p|
+in a given line-number class and fitness class.
+
+@<Record a new feasible break@>=
+if (artificial_demerits) d=0;
+else@<Compute the demerits, |d|, from |r| to |cur_p|@>;
+#ifdef @!STAT
+if (tracing_paragraphs > 0)
+ @<Print a symbolic description of this feasible break@>;
+#endif
+@;@/
+d=d+total_demerits(r); /*this is the minimum total demerits
+ from the beginning to |cur_p| via |r|*/
+if (d <= minimal_demerits[fit_class])
+ {@+minimal_demerits[fit_class]=d;
+ best_place[fit_class]=break_node(r);best_pl_line[fit_class]=l;
+ if (d < minimum_demerits) minimum_demerits=d;
+ }
+
+@ @<Print a symbolic description of this feasible break@>=
+{@+if (printed_node!=cur_p)
+ @<Print the list between |printed_node| and |cur_p|, then set |printed_node:=cur_p|@>;
+print_nl("@@");
+@.\AT!@>
+if (cur_p==null) print_esc(@[@<|"par"|@>@]);
+else if (type(cur_p)!=glue_node)
+ {@+if (type(cur_p)==penalty_node) print_esc(@[@<|"penalty"|@>@]);
+ else if (type(cur_p)==disc_node) print_esc(@[@<|"discretionary"|@>@]);
+ else if (type(cur_p)==kern_node) print_esc(@[@<|"kern"|@>@]);
+ else print_esc(@[@<|"math"|@>@]);
+ }
+print_str(" via @@@@");
+if (break_node(r)==null) print_char('0');
+else print_int(serial(break_node(r)));
+print_str(" b=");
+if (b > inf_bad) print_char('*');@+else print_int(b);
+@.*\relax@>
+print_str(" p=");print_int(pi);print_str(" d=");
+if (artificial_demerits) print_char('*');@+else print_int(d);
+}
+
+@ @<Print the list between |printed_node| and |cur_p|...@>=
+{@+print_nl("");
+if (cur_p==null) short_display(link(printed_node));
+else{@+save_link=link(cur_p);
+ link(cur_p)=null;print_nl("");short_display(link(printed_node));
+ link(cur_p)=save_link;
+ }
+printed_node=cur_p;
+}
+
+@ When the data for a discretionary break is being displayed, we will have
+printed the |pre_break| and |post_break| lists; we want to skip over the
+third list, so that the discretionary data will not appear twice. The
+following code is performed at the very end of |try_break|.
+
+@<Update the value of |printed_node|...@>=
+if (cur_p==printed_node) if (cur_p!=null) if (type(cur_p)==disc_node)
+ {@+t=replace_count(cur_p);
+ while (t > 0)
+ {@+decr(t);printed_node=link(printed_node);
+ }
+ }
+
+@ @<Compute the demerits, |d|, from |r| to |cur_p|@>=
+{@+d=line_penalty+b;
+if (abs(d) >= 10000) d=100000000;@+else d=d*d;
+if (pi!=0)
+ if (pi > 0) d=d+pi*pi;
+ else if (pi > eject_penalty) d=d-pi*pi;
+if ((break_type==hyphenated)&&(type(r)==hyphenated))
+ if (cur_p!=null) d=d+double_hyphen_demerits;
+ else d=d+final_hyphen_demerits;
+if (abs(fit_class-fitness(r)) > 1) d=d+adj_demerits;
+}
+
+@ When an active node disappears, we must delete an adjacent delta node if the
+active node was at the beginning or the end of the active list, or if it
+was surrounded by delta nodes. We also must preserve the property that
+|cur_active_width| represents the length of material from |link(prev_r)|
+to~|cur_p|.
+
+@d combine_two_deltas(X) @|mem[prev_r+X].sc=mem[prev_r+X].sc+mem[r+X].sc
+@d downdate_width(X) @|cur_active_width[X]=cur_active_width[X]-
+ mem[prev_r+X].sc
+
+@<Deactivate node |r|@>=
+link(prev_r)=link(r);free_node(r, active_node_size);
+if (prev_r==active) @<Update the active widths, since the first active node has been
+deleted@>@;
+else if (type(prev_r)==delta_node)
+ {@+r=link(prev_r);
+ if (r==last_active)
+ {@+do_all_six(downdate_width);
+ link(prev_prev_r)=last_active;
+ free_node(prev_r, delta_node_size);prev_r=prev_prev_r;
+ }
+ else if (type(r)==delta_node)
+ {@+do_all_six(update_width);
+ do_all_six(combine_two_deltas);
+ link(prev_r)=link(r);free_node(r, delta_node_size);
+ }
+ }
+
+@ The following code uses the fact that |type(last_active)!=delta_node|. If the
+active list has just become empty, we do not need to update the
+|active_width| array, since it will be initialized when an active
+node is next inserted.
+
+@d update_active(X) active_width[X]=active_width[X]+mem[r+X].sc
+
+@<Update the active widths,...@>=
+{@+r=link(active);
+if (type(r)==delta_node)
+ {@+do_all_six(update_active);
+ do_all_six(copy_to_cur_active);
+ link(active)=link(r);free_node(r, delta_node_size);
+ }
+}
+
+@* Breaking paragraphs into lines, continued.
+So far we have gotten a little way into the |line_break| routine, having
+covered its important |try_break| subroutine. Now let's consider the
+rest of the process.
+
+The main loop of |line_break| traverses the given hlist,
+starting at |link(temp_head)|, and calls |try_break| at each legal
+breakpoint. A variable called |auto_breaking| is set to true except
+within math formulas, since glue nodes are not legal breakpoints when
+they appear in formulas.
+
+The current node of interest in the hlist is pointed to by |cur_p|. Another
+variable, |prev_p|, is usually one step behind |cur_p|, but the real
+meaning of |prev_p| is this: If |type(cur_p)==glue_node| then |cur_p| is a legal
+breakpoint if and only if |auto_breaking| is true and |prev_p| does not
+point to a glue node, penalty node, explicit kern node, or math node.
+
+The following declarations provide for a few other local variables that are
+used in special calculations.
+
+@<Local variables for line breaking@>=
+bool @!auto_breaking; /*is node |cur_p| outside a formula?*/
+pointer @!prev_p; /*helps to determine when glue nodes are breakpoints*/
+pointer @!q, @!r, @!s, @!prev_s; /*miscellaneous nodes of temporary interest*/
+internal_font_number @!f; /*used when calculating character widths*/
+
+@ The `\ignorespaces|loop|\unskip' in the following code is performed at most
+thrice per call of |line_break|, since it is actually a pass over the
+entire paragraph.
+
+@<Find optimal breakpoints@>=
+threshold=pretolerance;
+if (threshold >= 0)
+ {
+#ifdef @!STAT
+if (tracing_paragraphs > 0)
+ {@+begin_diagnostic();print_nl("@@firstpass");@+} @;
+#endif
+@;@/
+ second_pass=false;final_pass=false;
+ }
+else{@+threshold=tolerance;second_pass=true;
+ final_pass=(emergency_stretch <= 0);
+
+#ifdef @!STAT
+if (tracing_paragraphs > 0) begin_diagnostic();
+#endif
+@;
+ }
+loop@+{@+if (threshold > inf_bad) threshold=inf_bad;
+ if (second_pass) @<Initialize for hyphenating a paragraph@>;
+ @<Create an active breakpoint representing the beginning of the paragraph@>;
+ cur_p=link(temp_head);auto_breaking=true;@/
+ prev_p=cur_p; /*glue at beginning is not a legal breakpoint*/
+ while ((cur_p!=null)&&(link(active)!=last_active))
+ @<Call |try_break| if |cur_p| is a legal breakpoint; on the second pass, also
+try to hyphenate the next word, if |cur_p| is a glue node; then advance |cur_p| to
+the next node of the paragraph that could possibly be a legal breakpoint@>;
+ if (cur_p==null)
+ @<Try the final line break at the end of the paragraph, and |goto done| if the
+desired breakpoints have been found@>;
+ @<Clean up the memory by removing the break nodes@>;
+ if (!second_pass)
+ {
+#ifdef @!STAT
+if (tracing_paragraphs > 0) print_nl("@@secondpass");@;
+#endif
+ threshold=tolerance;second_pass=true;final_pass=(emergency_stretch <= 0);
+ } /*if at first you don't succeed, \dots*/
+ else{
+#ifdef @!STAT
+if (tracing_paragraphs > 0)
+ print_nl("@@emergencypass");@;
+#endif
+ background[2]=background[2]+emergency_stretch;final_pass=true;
+ }
+ }
+done:
+#ifdef @!STAT
+if (tracing_paragraphs > 0)
+ {@+end_diagnostic(true);normalize_selector();
+ }
+#endif
+
+@ The active node that represents the starting point does not need a
+corresponding passive node.
+
+@d store_background(X) active_width[X]=background[X]
+
+@<Create an active breakpoint representing the beginning of the paragraph@>=
+q=get_node(active_node_size);
+type(q)=unhyphenated;fitness(q)=decent_fit;
+link(q)=last_active;break_node(q)=null;
+line_number(q)=prev_graf+1;total_demerits(q)=0;link(active)=q;
+do_all_six(store_background);@/
+passive=null;printed_node=temp_head;pass_number=0;
+font_in_short_display=null_font
+
+@ @<Clean...@>=
+q=link(active);
+while (q!=last_active)
+ {@+cur_p=link(q);
+ if (type(q)==delta_node) free_node(q, delta_node_size);
+ else free_node(q, active_node_size);
+ q=cur_p;
+ }
+q=passive;
+while (q!=null)
+ {@+cur_p=link(q);
+ free_node(q, passive_node_size);
+ q=cur_p;
+ }
+
+@ Here is the main switch in the |line_break| routine, where legal breaks
+are determined. As we move through the hlist, we need to keep the |active_width|
+array up to date, so that the badness of individual lines is readily calculated
+by |try_break|. It is convenient to use the short name |act_width| for
+the component of active width that represents real width as opposed to glue.
+
+@d act_width active_width[1] /*length from first active node to current node*/
+@d kern_break {@+if (!is_char_node(link(cur_p))&&auto_breaking)
+ if (type(link(cur_p))==glue_node) try_break(0, unhyphenated);
+ act_width=act_width+width(cur_p);
+ }
+
+@<Call |try_break| if |cur_p| is a legal breakpoint...@>=
+{@+if (is_char_node(cur_p))
+ @<Advance \(c)|cur_p| to the node following the present string of characters@>;
+switch (type(cur_p)) {
+case hlist_node: case vlist_node: case rule_node: act_width=act_width+width(cur_p);@+break;
+case whatsit_node: @<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>@;@+break;
+case glue_node: {@+@<If node |cur_p| is a legal breakpoint, call |try_break|; then
+update the active widths by including the glue in |glue_ptr(cur_p)|@>;
+ if (second_pass&&auto_breaking)
+ @<Try to hyphenate the following word@>;
+ } @+break;
+case kern_node: if (subtype(cur_p)==explicit) kern_break@;
+ else act_width=act_width+width(cur_p);@+break;
+case ligature_node: {@+f=font(lig_char(cur_p));
+ act_width=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
+ } @+break;
+case disc_node: @<Try to break after a discretionary fragment, then |goto done5|@>@;
+case math_node: {@+auto_breaking=(subtype(cur_p)==after);kern_break;
+ } @+break;
+case penalty_node: try_break(penalty(cur_p), unhyphenated);@+break;
+case mark_node: case ins_node: case adjust_node: do_nothing;@+break;
+default:confusion(@[@<|"paragraph"|@>@]);
+@:this can't happen paragraph}{\quad paragraph@>
+} @/
+prev_p=cur_p;cur_p=link(cur_p);
+done5: ;}
+
+@ The code that passes over the characters of words in a paragraph is
+part of \TeX's inner loop, so it has been streamlined for speed. We use
+the fact that `\.{\\parfillskip}' glue appears at the end of each paragraph;
+it is therefore unnecessary to check if |link(cur_p)==null| when |cur_p| is a
+character node.
+@^inner loop@>
+
+@<Advance \(c)|cur_p| to the node following the present string...@>=
+{@+prev_p=cur_p;
+@/do@+{f=font(cur_p);
+act_width=act_width+char_width(f)(char_info(f)(character(cur_p)));
+cur_p=link(cur_p);
+}@+ while (!(!is_char_node(cur_p)));
+}
+
+@ When node |cur_p| is a glue node, we look at |prev_p| to see whether or not
+a breakpoint is legal at |cur_p|, as explained above.
+
+@<If node |cur_p| is a legal breakpoint, call...@>=
+if (auto_breaking)
+ {@+if (is_char_node(prev_p)) try_break(0, unhyphenated);
+ else if (precedes_break(prev_p)) try_break(0, unhyphenated);
+ else if ((type(prev_p)==kern_node)&&(subtype(prev_p)!=explicit))
+ try_break(0, unhyphenated);
+ }
+check_shrinkage(glue_ptr(cur_p));q=glue_ptr(cur_p);
+act_width=act_width+width(q);@|
+active_width[2+stretch_order(q)]=@|
+ active_width[2+stretch_order(q)]+stretch(q);@/
+active_width[6]=active_width[6]+shrink(q)
+
+@ The following code knows that discretionary texts contain
+only character nodes, kern nodes, box nodes, rule nodes, and ligature nodes.
+
+@<Try to break after a discretionary fragment...@>=
+{@+s=pre_break(cur_p);disc_width=0;
+if (s==null) try_break(ex_hyphen_penalty, hyphenated);
+else{@+@/do@+{@<Add the width of node |s| to |disc_width|@>;
+ s=link(s);
+ }@+ while (!(s==null));
+ act_width=act_width+disc_width;
+ try_break(hyphen_penalty, hyphenated);
+ act_width=act_width-disc_width;
+ }
+r=replace_count(cur_p);s=link(cur_p);
+while (r > 0)
+ {@+@<Add the width of node |s| to |act_width|@>;
+ decr(r);s=link(s);
+ }
+prev_p=cur_p;cur_p=s;goto done5;
+}
+
+@ @<Add the width of node |s| to |disc_width|@>=
+if (is_char_node(s))
+ {@+f=font(s);
+ disc_width=disc_width+char_width(f)(char_info(f)(character(s)));
+ }
+else switch (type(s)) {
+ case ligature_node: {@+f=font(lig_char(s));
+ disc_width=disc_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ } @+break;
+ case hlist_node: case vlist_node: case rule_node: case kern_node:
+ disc_width=disc_width+width(s);@+break;
+ default:confusion(@[@<|"disc3"|@>@]);
+@:this can't happen disc3}{\quad disc3@>
+ }
+
+@ @<Add the width of node |s| to |act_width|@>=
+if (is_char_node(s))
+ {@+f=font(s);
+ act_width=act_width+char_width(f)(char_info(f)(character(s)));
+ }
+else switch (type(s)) {
+ case ligature_node: {@+f=font(lig_char(s));
+ act_width=act_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ } @+break;
+ case hlist_node: case vlist_node: case rule_node: case kern_node:
+ act_width=act_width+width(s);@+break;
+ default:confusion(@[@<|"disc4"|@>@]);
+@:this can't happen disc4}{\quad disc4@>
+ }
+
+@ The forced line break at the paragraph's end will reduce the list of
+breakpoints so that all active nodes represent breaks at |cur_p==null|.
+On the first pass, we insist on finding an active node that has the
+correct ``looseness.'' On the final pass, there will be at least one active
+node, and we will match the desired looseness as well as we can.
+
+The global variable |best_bet| will be set to the active node for the best
+way to break the paragraph, and a few other variables are used to
+help determine what is best.
+
+@<Glob...@>=
+pointer @!best_bet; /*use this passive node and its predecessors*/
+int @!fewest_demerits; /*the demerits associated with |best_bet|*/
+halfword @!best_line; /*line number following the last line of the new paragraph*/
+int @!actual_looseness; /*the difference between |line_number(best_bet)|
+ and the optimum |best_line|*/
+int @!line_diff; /*the difference between the current line number and
+ the optimum |best_line|*/
+
+@ @<Try the final line break at the end of the paragraph...@>=
+{@+try_break(eject_penalty, hyphenated);
+if (link(active)!=last_active)
+ {@+@<Find an active node with fewest demerits@>;
+ if (looseness==0) goto done;
+ @<Find the best active node for the desired looseness@>;
+ if ((actual_looseness==looseness)||final_pass) goto done;
+ }
+}
+
+@ @<Find an active node...@>=
+r=link(active);fewest_demerits=awful_bad;
+@/do@+{if (type(r)!=delta_node) if (total_demerits(r) < fewest_demerits)
+ {@+fewest_demerits=total_demerits(r);best_bet=r;
+ }
+r=link(r);
+}@+ while (!(r==last_active));
+best_line=line_number(best_bet)
+
+@ The adjustment for a desired looseness is a slightly more complicated
+version of the loop just considered. Note that if a paragraph is broken
+into segments by displayed equations, each segment will be subject to the
+looseness calculation, independently of the other segments.
+
+@<Find the best active node...@>=
+{@+r=link(active);actual_looseness=0;
+@/do@+{if (type(r)!=delta_node)
+ {@+line_diff=line_number(r)-best_line;
+ if (((line_diff < actual_looseness)&&(looseness <= line_diff))||@|
+ ((line_diff > actual_looseness)&&(looseness >= line_diff)))
+ {@+best_bet=r;actual_looseness=line_diff;
+ fewest_demerits=total_demerits(r);
+ }
+ else if ((line_diff==actual_looseness)&&@|
+ (total_demerits(r) < fewest_demerits))
+ {@+best_bet=r;fewest_demerits=total_demerits(r);
+ }
+ }
+r=link(r);
+}@+ while (!(r==last_active));
+best_line=line_number(best_bet);
+}
+
+@ Once the best sequence of breakpoints has been found (hurray), we call on the
+procedure |post_line_break| to finish the remainder of the work.
+(By introducing this subprocedure, we are able to keep |line_break|
+from getting extremely long.)
+
+@<Break the paragraph at the chosen...@>=
+post_line_break(final_widow_penalty)
+
+@ The total number of lines that will be set by |post_line_break|
+is |best_line-prev_graf-1|. The last breakpoint is specified by
+|break_node(best_bet)|, and this passive node points to the other breakpoints
+via the |prev_break| links. The finishing-up phase starts by linking the
+relevant passive nodes in forward order, changing |prev_break| to
+|next_break|. (The |next_break| fields actually reside in the same memory
+space as the |prev_break| fields did, but we give them a new name because
+of their new significance.) Then the lines are justified, one by one.
+
+@d next_break prev_break /*new name for |prev_break| after links are reversed*/
+
+@<Declare subprocedures for |line_break|@>=
+void post_line_break(int @!final_widow_penalty)
+{@+
+pointer q, @!r, @!s; /*temporary registers for list manipulation*/
+bool @!disc_break; /*was the current break at a discretionary node?*/
+bool @!post_disc_break; /*and did it have a nonempty post-break part?*/
+scaled @!cur_width; /*width of line number |cur_line|*/
+scaled @!cur_indent; /*left margin of line number |cur_line|*/
+quarterword @!t; /*used for replacement counts in discretionary nodes*/
+int @!pen; /*use when calculating penalties between lines*/
+halfword @!cur_line; /*the current line number being justified*/
+@<Reverse the links of the relevant passive nodes, setting |cur_p| to the first breakpoint@>;
+cur_line=prev_graf+1;
+@/do@+{@<Justify the line ending at breakpoint |cur_p|, and append it to the current
+vertical list, together with associated penalties and other insertions@>;
+incr(cur_line);cur_p=next_break(cur_p);
+if (cur_p!=null) if (!post_disc_break)
+ @<Prune unwanted nodes at the beginning of the next line@>;
+}@+ while (!(cur_p==null));
+if ((cur_line!=best_line)||(link(temp_head)!=null))
+ confusion(@[@<|"line breaking"|@>@]);
+@:this can't happen line breaking}{\quad line breaking@>
+prev_graf=best_line-1;
+}
+
+@ The job of reversing links in a list is conveniently regarded as the job
+of taking items off one stack and putting them on another. In this case we
+take them off a stack pointed to by |q| and having |prev_break| fields;
+we put them on a stack pointed to by |cur_p| and having |next_break| fields.
+Node |r| is the passive node being moved from stack to stack.
+
+@<Reverse the links of the relevant passive nodes...@>=
+q=break_node(best_bet);cur_p=null;
+@/do@+{r=q;q=prev_break(q);next_break(r)=cur_p;cur_p=r;
+}@+ while (!(q==null))
+
+@ Glue and penalty and kern and math nodes are deleted at the beginning of
+a line, except in the anomalous case that the node to be deleted is actually
+one of the chosen breakpoints. Otherwise
+the pruning done here is designed to match
+the lookahead computation in |try_break|, where the |break_width| values
+are computed for non-discretionary breakpoints.
+
+@<Prune unwanted nodes at the beginning of the next line@>=
+{@+r=temp_head;
+loop@+{@+q=link(r);
+ if (q==cur_break(cur_p)) goto done1;
+ /*|cur_break(cur_p)| is the next breakpoint*/
+ /*now |q| cannot be |null|*/
+ if (is_char_node(q)) goto done1;
+ if (non_discardable(q)) goto done1;
+ if (type(q)==kern_node) if (subtype(q)!=explicit) goto done1;
+ r=q; /*now |type(q)==glue_node|, |kern_node|, |math_node| or |penalty_node|*/
+ }
+done1: if (r!=temp_head)
+ {@+link(r)=null;flush_node_list(link(temp_head));
+ link(temp_head)=q;
+ }
+}
+
+@ The current line to be justified appears in a horizontal list starting
+at |link(temp_head)| and ending at |cur_break(cur_p)|. If |cur_break(cur_p)| is
+a glue node, we reset the glue to equal the |right_skip| glue; otherwise
+we append the |right_skip| glue at the right. If |cur_break(cur_p)| is a
+discretionary node, we modify the list so that the discretionary break
+is compulsory, and we set |disc_break| to |true|. We also append
+the |left_skip| glue at the left of the line, unless it is zero.
+
+@<Justify the line ending at breakpoint |cur_p|, and append it...@>=
+@<Modify the end of the line to reflect the nature of the break and to include \.{\\rightskip};
+also set the proper value of |disc_break|@>;
+@<Put the \(l)\.{\\leftskip} glue at the left and detach this line@>;
+@<Call the packaging subroutine, setting |just_box| to the justified box@>;
+@<Append the new box to the current vertical list, followed by the list of special
+nodes taken out of the box by the packager@>;
+@<Append a penalty node, if a nonzero penalty is appropriate@>@;
+
+@ At the end of the following code, |q| will point to the final node on the
+list about to be justified.
+
+@<Modify the end of the line...@>=
+q=cur_break(cur_p);disc_break=false;post_disc_break=false;
+if (q!=null) /*|q| cannot be a |char_node|*/
+ if (type(q)==glue_node)
+ {@+delete_glue_ref(glue_ptr(q));
+ glue_ptr(q)=right_skip;
+ subtype(q)=right_skip_code+1;add_glue_ref(right_skip);
+ goto done;
+ }
+ else{@+if (type(q)==disc_node)
+ @<Change discretionary to compulsory and set |disc_break:=true|@>@;
+ else if ((type(q)==math_node)||(type(q)==kern_node)) width(q)=0;
+ }
+else{@+q=temp_head;
+ while (link(q)!=null) q=link(q);
+ }
+@<Put the \(r)\.{\\rightskip} glue after node |q|@>;
+done:
+
+@ @<Change discretionary to compulsory...@>=
+{@+t=replace_count(q);
+@<Destroy the |t| nodes following |q|, and make |r| point to the following node@>;
+if (post_break(q)!=null) @<Transplant the post-break list@>;
+if (pre_break(q)!=null) @<Transplant the pre-break list@>;
+link(q)=r;disc_break=true;
+}
+
+@ @<Destroy the |t| nodes following |q|...@>=
+if (t==0) r=link(q);
+else{@+r=q;
+ while (t > 1)
+ {@+r=link(r);decr(t);
+ }
+ s=link(r);
+ r=link(s);link(s)=null;
+ flush_node_list(link(q));replace_count(q)=0;
+ }
+
+@ We move the post-break list from inside node |q| to the main list by
+re\-attaching it just before the present node |r|, then resetting |r|.
+
+@<Transplant the post-break list@>=
+{@+s=post_break(q);
+while (link(s)!=null) s=link(s);
+link(s)=r;r=post_break(q);post_break(q)=null;post_disc_break=true;
+}
+
+@ We move the pre-break list from inside node |q| to the main list by
+re\-attaching it just after the present node |q|, then resetting |q|.
+
+@<Transplant the pre-break list@>=
+{@+s=pre_break(q);link(q)=s;
+while (link(s)!=null) s=link(s);
+pre_break(q)=null;q=s;
+}
+
+@ @<Put the \(r)\.{\\rightskip} glue after node |q|@>=
+r=new_param_glue(right_skip_code);link(r)=link(q);link(q)=r;q=r
+
+@ The following code begins with |q| at the end of the list to be
+justified. It ends with |q| at the beginning of that list, and with
+|link(temp_head)| pointing to the remainder of the paragraph, if any.
+
+@<Put the \(l)\.{\\leftskip} glue at the left...@>=
+r=link(q);link(q)=null;q=link(temp_head);link(temp_head)=r;
+if (left_skip!=zero_glue)
+ {@+r=new_param_glue(left_skip_code);
+ link(r)=q;q=r;
+ }
+
+@ @<Append the new box to the current vertical list...@>=
+append_to_vlist(just_box);
+if (adjust_head!=adjust_tail)
+ {@+link(tail)=link(adjust_head);tail=adjust_tail;
+ }
+adjust_tail=null
+
+@ Now |q| points to the hlist that represents the current line of the
+paragraph. We need to compute the appropriate line width, pack the
+line into a box of this size, and shift the box by the appropriate
+amount of indentation.
+
+@<Call the packaging subroutine...@>=
+if (cur_line > last_special_line)
+ {@+cur_width=second_width;cur_indent=second_indent;
+ }
+else if (par_shape_ptr==null)
+ {@+cur_width=first_width;cur_indent=first_indent;
+ }
+else{@+cur_width=mem[par_shape_ptr+2*cur_line].sc;
+ cur_indent=mem[par_shape_ptr+2*cur_line-1].sc;
+ }
+adjust_tail=adjust_head;just_box=hpack(q, cur_width, exactly);
+shift_amount(just_box)=cur_indent
+
+@ Penalties between the lines of a paragraph come from club and widow lines,
+from the |inter_line_penalty| parameter, and from lines that end at
+discretionary breaks. Breaking between lines of a two-line paragraph gets
+both club-line and widow-line penalties. The local variable |pen| will
+be set to the sum of all relevant penalties for the current line, except
+that the final line is never penalized.
+
+@<Append a penalty node, if a nonzero penalty is appropriate@>=
+if (cur_line+1!=best_line)
+ {@+pen=inter_line_penalty;
+ if (cur_line==prev_graf+1) pen=pen+club_penalty;
+ if (cur_line+2==best_line) pen=pen+final_widow_penalty;
+ if (disc_break) pen=pen+broken_penalty;
+ if (pen!=0)
+ {@+r=new_penalty(pen);
+ link(tail)=r;tail=r;
+ }
+ }
+
+@* Pre-hyphenation.
+When the line-breaking routine is unable to find a feasible sequence of
+breakpoints, it makes a second pass over the paragraph, attempting to
+hyphenate the hyphenatable words. The goal of hyphenation is to insert
+discretionary material into the paragraph so that there are more
+potential places to break.
+
+The general rules for hyphenation are somewhat complex and technical,
+because we want to be able to hyphenate words that are preceded or
+followed by punctuation marks, and because we want the rules to work
+for languages other than English. We also must contend with the fact
+that hyphens might radically alter the ligature and kerning structure
+of a word.
+
+A sequence of characters will be considered for hyphenation only if it
+belongs to a ``potentially hyphenatable part'' of the current paragraph.
+This is a sequence of nodes $p_0p_1\ldots p_m$ where $p_0$ is a glue node,
+$p_1\ldots p_{m-1}$ are either character or ligature or whatsit or
+implicit kern nodes, and $p_m$ is a glue or penalty or insertion or adjust
+or mark or whatsit or explicit kern node. (Therefore hyphenation is
+disabled by boxes, math formulas, and discretionary nodes already inserted
+by the user.) The ligature nodes among $p_1\ldots p_{m-1}$ are effectively
+expanded into the original non-ligature characters; the kern nodes and
+whatsits are ignored. Each character |c| is now classified as either a
+nonletter (if |lc_code(c)==0|), a lowercase letter (if
+|lc_code(c)==c|), or an uppercase letter (otherwise); an uppercase letter
+is treated as if it were |lc_code(c)| for purposes of hyphenation. The
+characters generated by $p_1\ldots p_{m-1}$ may begin with nonletters; let
+$c_1$ be the first letter that is not in the middle of a ligature. Whatsit
+nodes preceding $c_1$ are ignored; a whatsit found after $c_1$ will be the
+terminating node $p_m$. All characters that do not have the same font as
+$c_1$ will be treated as nonletters. The |hyphen_char| for that font
+must be between 0 and 255, otherwise hyphenation will not be attempted.
+\TeX\ looks ahead for as many consecutive letters $c_1\ldots c_n$ as
+possible; however, |n| must be less than 64, so a character that would
+otherwise be $c_{64}$ is effectively not a letter. Furthermore $c_n$ must
+not be in the middle of a ligature. In this way we obtain a string of
+letters $c_1\ldots c_n$ that are generated by nodes $p_a\ldots p_b$, where
+|1 <= a <= b+1 <= m|. If |n >= l_hyf+r_hyf|, this string qualifies for hyphenation;
+however, |uc_hyph| must be positive, if $c_1$ is uppercase.
+
+The hyphenation process takes place in three stages. First, the candidate
+sequence $c_1\ldots c_n$ is found; then potential positions for hyphens
+are determined by referring to hyphenation tables; and finally, the nodes
+$p_a\ldots p_b$ are replaced by a new sequence of nodes that includes the
+discretionary breaks found.
+
+Fortunately, we do not have to do all this calculation very often, because
+of the way it has been taken out of \TeX's inner loop. For example, when
+the second edition of the author's 700-page book {\sl Seminumerical
+Algorithms} was typeset by \TeX, only about 1.2 hyphenations needed to be
+@^Knuth, Donald Ervin@>
+tried per paragraph, since the line breaking algorithm needed to use two
+passes on only about 5 per cent of the paragraphs.
+
+@<Initialize for hyphenating...@>=
+{
+#ifdef @!INIT
+if (trie_not_ready) init_trie();
+#endif
+@;@/
+cur_lang=init_cur_lang;l_hyf=init_l_hyf;r_hyf=init_r_hyf;
+}
+
+@ The letters $c_1\ldots c_n$ that are candidates for hyphenation are placed
+into an array called |hc|; the number |n| is placed into |hn|; pointers to
+nodes $p_{a-1}$ and~$p_b$ in the description above are placed into variables
+|ha| and |hb|; and the font number is placed into |hf|.
+
+@<Glob...@>=
+uint16_t @!hc[66]; /*word to be hyphenated*/
+small_number @!hn; /*the number of positions occupied in |hc|*/
+pointer @!ha, @!hb; /*nodes |ha dotdot hb| should be replaced by the hyphenated result*/
+internal_font_number @!hf; /*font number of the letters in |hc|*/
+uint16_t @!hu[64]; /*like |hc|, before conversion to lowercase*/
+int @!hyf_char; /*hyphen character of the relevant font*/
+ASCII_code @!cur_lang, @!init_cur_lang; /*current hyphenation table of interest*/
+int @!l_hyf, @!r_hyf, @!init_l_hyf, @!init_r_hyf; /*limits on fragment sizes*/
+halfword @!hyf_bchar; /*boundary character after $c_n$*/
+
+@ Hyphenation routines need a few more local variables.
+
+@<Local variables for line...@>=
+small_number @!j; /*an index into |hc| or |hu|*/
+uint8_t @!c; /*character being considered for hyphenation*/
+
+@ When the following code is activated, the |line_break| procedure is in its
+second pass, and |cur_p| points to a glue node.
+
+@<Try to hyphenate...@>=
+{@+prev_s=cur_p;s=link(prev_s);
+if (s!=null)
+ {@+@<Skip to node |ha|, or |goto done1| if no hyphenation should be attempted@>;
+ if (l_hyf+r_hyf > 63) goto done1;
+ @<Skip to node |hb|, putting letters into |hu| and |hc|@>;
+ @<Check that the nodes following |hb| permit hyphenation and that at least |l_hyf+r_hyf|
+letters have been found, otherwise |goto done1|@>;
+ hyphenate();
+ }
+done1: ;}
+
+@ @<Declare subprocedures for |line_break|@>=
+@t\4@>@<Declare the function called |reconstitute|@>@;
+void hyphenate(void)
+{@+
+@<Local variables for hyphenation@>@;
+@<Find hyphen locations for the word in |hc|, or |return|@>;
+@<If no hyphens were found, |return|@>;
+@<Replace nodes |ha..hb| by a sequence of nodes that includes the discretionary hyphens@>;
+}
+
+@ The first thing we need to do is find the node |ha| just before the
+first letter.
+
+@<Skip to node |ha|, or |goto done1|...@>=
+loop@+{@+if (is_char_node(s))
+ {@+c=qo(character(s));hf=font(s);
+ }
+ else if (type(s)==ligature_node)
+ if (lig_ptr(s)==null) goto resume;
+ else{@+q=lig_ptr(s);c=qo(character(q));hf=font(q);
+ }
+ else if ((type(s)==kern_node)&&(subtype(s)==normal)) goto resume;
+ else if (type(s)==whatsit_node)
+ {@+@<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>;
+ goto resume;
+ }
+ else goto done1;
+ if (lc_code(c)!=0)
+ if ((lc_code(c)==c)||(uc_hyph > 0)) goto done2;
+ else goto done1;
+resume: prev_s=s;s=link(prev_s);
+ }
+done2: hyf_char=hyphen_char[hf];
+if (hyf_char < 0) goto done1;
+if (hyf_char > 255) goto done1;
+ha=prev_s
+
+@ The word to be hyphenated is now moved to the |hu| and |hc| arrays.
+
+@<Skip to node |hb|, putting letters...@>=
+hn=0;
+loop@+{@+if (is_char_node(s))
+ {@+if (font(s)!=hf) goto done3;
+ hyf_bchar=character(s);c=qo(hyf_bchar);
+ if (lc_code(c)==0) goto done3;
+ if (hn==63) goto done3;
+ hb=s;incr(hn);hu[hn]=c;hc[hn]=lc_code(c);hyf_bchar=non_char;
+ }
+ else if (type(s)==ligature_node)
+ @<Move the characters of a ligature node to |hu| and |hc|; but |goto done3| if
+they are not all letters@>@;
+ else if ((type(s)==kern_node)&&(subtype(s)==normal))
+ {@+hb=s;
+ hyf_bchar=font_bchar[hf];
+ }
+ else goto done3;
+ s=link(s);
+ }
+done3:
+
+@ We let |j| be the index of the character being stored when a ligature node
+is being expanded, since we do not want to advance |hn| until we are sure
+that the entire ligature consists of letters. Note that it is possible
+to get to |done3| with |hn==0| and |hb| not set to any value.
+
+@<Move the characters of a ligature node to |hu| and |hc|...@>=
+{@+if (font(lig_char(s))!=hf) goto done3;
+j=hn;q=lig_ptr(s);@+if (q > null) hyf_bchar=character(q);
+while (q > null)
+ {@+c=qo(character(q));
+ if (lc_code(c)==0) goto done3;
+ if (j==63) goto done3;
+ incr(j);hu[j]=c;hc[j]=lc_code(c);@/
+ q=link(q);
+ }
+hb=s;hn=j;
+if (odd(subtype(s))) hyf_bchar=font_bchar[hf];@+else hyf_bchar=non_char;
+}
+
+@ @<Check that the nodes following |hb| permit hyphenation...@>=
+if (hn < l_hyf+r_hyf) goto done1; /*|l_hyf| and |r_hyf| are | >= 1|*/
+loop@+{@+if (!(is_char_node(s)))
+ switch (type(s)) {
+ case ligature_node: do_nothing;@+break;
+ case kern_node: if (subtype(s)!=normal) goto done4;@+break;
+ case whatsit_node: case glue_node: case penalty_node: case ins_node: case adjust_node: case mark_node:
+ goto done4;
+ default:goto done1;
+ }
+ s=link(s);
+ }
+done4:
+
+@* Post-hyphenation.
+If a hyphen may be inserted between |hc[j]| and |hc[j+1]|, the hyphenation
+procedure will set |hyf[j]| to some small odd number. But before we look
+at \TeX's hyphenation procedure, which is independent of the rest of the
+line-breaking algorithm, let us consider what we will do with the hyphens
+it finds, since it is better to work on this part of the program before
+forgetting what |ha| and |hb|, etc., are all about.
+
+@<Glob...@>=
+uint8_t @!hyf[65]; /*odd values indicate discretionary hyphens*/
+pointer @!init_list; /*list of punctuation characters preceding the word*/
+bool @!init_lig; /*does |init_list| represent a ligature?*/
+bool @!init_lft; /*if so, did the ligature involve a left boundary?*/
+
+@ @<Local variables for hyphenation@>=
+int @!i, @!j, @!l; /*indices into |hc| or |hu|*/
+pointer @!q, @!r, @!s; /*temporary registers for list manipulation*/
+halfword @!bchar; /*right boundary character of hyphenated word, or |non_char|*/
+
+@ \TeX\ will never insert a hyphen that has fewer than
+\.{\\lefthyphenmin} letters before it or fewer than
+\.{\\righthyphenmin} after it; hence, a short word has
+comparatively little chance of being hyphenated. If no hyphens have
+been found, we can save time by not having to make any changes to the
+paragraph.
+
+@<If no hyphens were found, |return|@>=
+for (j=l_hyf; j<=hn-r_hyf; j++) if (odd(hyf[j])) goto found1;
+return;
+found1:
+
+@ If hyphens are in fact going to be inserted, \TeX\ first deletes the
+subsequence of nodes between |ha| and~|hb|. An attempt is made to
+preserve the effect that implicit boundary characters and punctuation marks
+had on ligatures inside the hyphenated word, by storing a left boundary or
+preceding character in |hu[0]| and by storing a possible right boundary
+in |bchar|. We set |j=0| if |hu[0]| is to be part of the reconstruction;
+otherwise |j=1|.
+The variable |s| will point to the tail of the current hlist, and
+|q| will point to the node following |hb|, so that
+things can be hooked up after we reconstitute the hyphenated word.
+
+@<Replace nodes |ha..hb| by a sequence of nodes...@>=
+q=link(hb);link(hb)=null;r=link(ha);link(ha)=null;bchar=hyf_bchar;
+if (is_char_node(ha))
+ if (font(ha)!=hf) goto found2;
+ else{@+init_list=ha;init_lig=false;hu[0]=qo(character(ha));
+ }
+else if (type(ha)==ligature_node)
+ if (font(lig_char(ha))!=hf) goto found2;
+ else{@+init_list=lig_ptr(ha);init_lig=true;init_lft=(subtype(ha) > 1);
+ hu[0]=qo(character(lig_char(ha)));
+ if (init_list==null) if (init_lft)
+ {@+hu[0]=256;init_lig=false;
+ } /*in this case a ligature will be reconstructed from scratch*/
+ free_node(ha, small_node_size);
+ }
+else{@+ /*no punctuation found; look for left boundary*/
+ if (!is_char_node(r)) if (type(r)==ligature_node)
+ if (subtype(r) > 1) goto found2;
+ j=1;s=ha;init_list=null;goto common_ending;
+ }
+s=cur_p; /*we have |cur_p!=ha| because |type(cur_p)==glue_node|*/
+while (link(s)!=ha) s=link(s);
+j=0;goto common_ending;
+found2: s=ha;j=0;hu[0]=256;init_lig=false;init_list=null;
+common_ending: flush_node_list(r);
+@<Reconstitute nodes for the hyphenated word, inserting discretionary hyphens@>;
+flush_list(init_list)
+
+@ We must now face the fact that the battle is not over, even though the
+{\def\!{\kern-1pt}%
+hyphens have been found: The process of reconstituting a word can be nontrivial
+because ligatures might change when a hyphen is present. {\sl The \TeX book\/}
+discusses the difficulties of the word ``difficult'', and
+the discretionary material surrounding a
+hyphen can be considerably more complex than that. Suppose
+\.{abcdef} is a word in a font for which the only ligatures are \.{b\!c},
+\.{c\!d}, \.{d\!e}, and \.{e\!f}. If this word permits hyphenation
+between \.b and \.c, the two patterns with and without hyphenation are
+$\.a\,\.b\,\.-\,\.{c\!d}\,\.{e\!f}$ and $\.a\,\.{b\!c}\,\.{d\!e}\,\.f$.
+Thus the insertion of a hyphen might cause effects to ripple arbitrarily
+far into the rest of the word. A further complication arises if additional
+hyphens appear together with such rippling, e.g., if the word in the
+example just given could also be hyphenated between \.c and \.d; \TeX\
+avoids this by simply ignoring the additional hyphens in such weird cases.}
+
+Still further complications arise in the presence of ligatures that do not
+delete the original characters. When punctuation precedes the word being
+hyphenated, \TeX's method is not perfect under all possible scenarios,
+because punctuation marks and letters can propagate information back and forth.
+For example, suppose the original pre-hyphenation pair
+\.{*a} changes to \.{*y} via a \.{\?=:} ligature, which changes to \.{xy}
+via a \.{=:\?} ligature; if $p_{a-1}=\.x$ and $p_a=\.y$, the reconstitution
+procedure isn't smart enough to obtain \.{xy} again. In such cases the
+font designer should include a ligature that goes from \.{xa} to \.{xy}.
+
+@ The processing is facilitated by a subroutine called |reconstitute|. Given
+a string of characters $x_j\ldots x_n$, there is a smallest index $m\ge j$
+such that the ``translation'' of $x_j\ldots x_n$ by ligatures and kerning
+has the form $y_1\ldots y_t$ followed by the translation of $x_{m+1}\ldots x_n$,
+where $y_1\ldots y_t$ is some nonempty sequence of character, ligature, and
+kern nodes. We call $x_j\ldots x_m$ a ``cut prefix'' of $x_j\ldots x_n$.
+For example, if $x_1x_2x_3=\.{fly}$, and if the font contains `fl' as a
+ligature and a kern between `fl' and `y', then $m=2$, $t=2$, and $y_1$ will
+be a ligature node for `fl' followed by an appropriate kern node~$y_2$.
+In the most common case, $x_j$~forms no ligature with $x_{j+1}$ and we
+simply have $m=j$, $y_1=x_j$. If $m<n$ we can repeat the procedure on
+$x_{m+1}\ldots x_n$ until the entire translation has been found.
+
+The |reconstitute| function returns the integer $m$ and puts the nodes
+$y_1\ldots y_t$ into a linked list starting at |link(hold_head)|,
+getting the input $x_j\ldots x_n$ from the |hu| array. If $x_j=256$,
+we consider $x_j$ to be an implicit left boundary character; in this
+case |j| must be strictly less than~|n|. There is a
+parameter |bchar|, which is either 256 or an implicit right boundary character
+assumed to be present just following~$x_n$. (The value |hu[n+1]| is never
+explicitly examined, but the algorithm imagines that |bchar| is there.)
+
+If there exists an index |k| in the range $j\le k\le m$ such that |hyf[k]|
+is odd and such that the result of |reconstitute| would have been different
+if $x_{k+1}$ had been |hchar|, then |reconstitute| sets |hyphen_passed|
+to the smallest such~|k|. Otherwise it sets |hyphen_passed| to zero.
+
+A special convention is used in the case |j==0|: Then we assume that the
+translation of |hu[0]| appears in a special list of charnodes starting at
+|init_list|; moreover, if |init_lig| is |true|, then |hu[0]| will be
+a ligature character, involving a left boundary if |init_lft| is |true|.
+This facility is provided for cases when a hyphenated
+word is preceded by punctuation (like single or double quotes) that might
+affect the translation of the beginning of the word.
+
+@<Glob...@>=
+small_number @!hyphen_passed; /*first hyphen in a ligature, if any*/
+
+@ @<Declare the function called |reconstitute|@>=
+
+ small_number reconstitute(small_number @!j, small_number @!n, halfword @!bchar, halfword @!hchar)
+{@+
+pointer @!p; /*temporary register for list manipulation*/
+pointer @!t; /*a node being appended to*/
+four_quarters @!q; /*character information or a lig/kern instruction*/
+halfword @!cur_rh; /*hyphen character for ligature testing*/
+halfword @!test_char; /*hyphen or other character for ligature testing*/
+scaled @!w; /*amount of kerning*/
+font_index @!k; /*position of current lig/kern instruction*/
+hyphen_passed=0;t=hold_head;w=0;link(hold_head)=null;
+ /*at this point |ligature_present==lft_hit==rt_hit==false|*/
+@<Set up data structures with the cursor following position |j|@>;
+resume: @<If there's a ligature or kern at the cursor position, update the data structures,
+possibly advancing~|j|; continue until the cursor moves@>;
+@<Append a ligature and/or kern to the translation; |goto continue| if the stack of
+inserted ligatures is nonempty@>;
+return j;
+}
+
+@ The reconstitution procedure shares many of the global data structures
+by which \TeX\ has processed the words before they were hyphenated.
+There is an implied ``cursor'' between characters |cur_l| and |cur_r|;
+these characters will be tested for possible ligature activity. If
+|ligature_present| then |cur_l| is a ligature character formed from the
+original characters following |cur_q| in the current translation list.
+There is a ``ligature stack'' between the cursor and character |j+1|,
+consisting of pseudo-ligature nodes linked together by their |link| fields.
+This stack is normally empty unless a ligature command has created a new
+character that will need to be processed later. A pseudo-ligature is
+a special node having a |character| field that represents a potential
+ligature and a |lig_ptr| field that points to a |char_node| or is |null|.
+We have
+$$|cur_r|=\cases{|character(lig_stack)|,&if |lig_stack > null|;\cr
+ \hbox{|qi(hu[j+1])|},&if |lig_stack==null| and |j < n|;\cr
+ bchar,&if |lig_stack==null| and |j==n|.\cr}$$
+
+@<Glob...@>=
+halfword @!cur_l, @!cur_r; /*characters before and after the cursor*/
+pointer @!cur_q; /*where a ligature should be detached*/
+pointer @!lig_stack; /*unfinished business to the right of the cursor*/
+bool @!ligature_present; /*should a ligature node be made for |cur_l|?*/
+bool @!lft_hit, @!rt_hit; /*did we hit a ligature with a boundary character?*/
+
+@ @d append_charnode_to_t(X) {@+link(t)=get_avail();t=link(t);
+ font(t)=hf;character(t)=X;
+ }
+@d set_cur_r {@+if (j < n) cur_r=qi(hu[j+1]);@+else cur_r=bchar;
+ if (odd(hyf[j])) cur_rh=hchar;@+else cur_rh=non_char;
+ }
+
+@<Set up data structures with the cursor following position |j|@>=
+cur_l=qi(hu[j]);cur_q=t;
+if (j==0)
+ {@+ligature_present=init_lig;p=init_list;
+ if (ligature_present) lft_hit=init_lft;
+ while (p > null)
+ {@+append_charnode_to_t(character(p));p=link(p);
+ }
+ }
+else if (cur_l < non_char) append_charnode_to_t(cur_l);
+lig_stack=null;set_cur_r
+
+@ We may want to look at the lig/kern program twice, once for a hyphen
+and once for a normal letter. (The hyphen might appear after the letter
+in the program, so we'd better not try to look for both at once.)
+
+@<If there's a ligature or kern at the cursor position, update...@>=
+if (cur_l==non_char)
+ {@+k=bchar_label[hf];
+ if (k==non_address) goto done;@+else q=font_info[k].qqqq;
+ }
+else{@+q=char_info(hf)(cur_l);
+ if (char_tag(q)!=lig_tag) goto done;
+ k=lig_kern_start(hf)(q);q=font_info[k].qqqq;
+ if (skip_byte(q) > stop_flag)
+ {@+k=lig_kern_restart(hf)(q);q=font_info[k].qqqq;
+ }
+ } /*now |k| is the starting address of the lig/kern program*/
+if (cur_rh < non_char) test_char=cur_rh;@+else test_char=cur_r;
+loop@+{@+if (next_char(q)==test_char) if (skip_byte(q) <= stop_flag)
+ if (cur_rh < non_char)
+ {@+hyphen_passed=j;hchar=non_char;cur_rh=non_char;
+ goto resume;
+ }
+ else{@+if (hchar < non_char) if (odd(hyf[j]))
+ {@+hyphen_passed=j;hchar=non_char;
+ }
+ if (op_byte(q) < kern_flag)
+ @<Carry out a ligature replacement, updating the cursor structure and possibly
+advancing~|j|; |goto continue| if the cursor doesn't advance, otherwise |goto done|@>;
+ w=char_kern(hf)(q);goto done; /*this kern will be inserted below*/
+ }
+ if (skip_byte(q) >= stop_flag)
+ if (cur_rh==non_char) goto done;
+ else{@+cur_rh=non_char;goto resume;
+ }
+ k=k+qo(skip_byte(q))+1;q=font_info[k].qqqq;
+ }
+done:
+
+@ @d wrap_lig(X) if (ligature_present)
+ {@+p=new_ligature(hf, cur_l, link(cur_q));
+ if (lft_hit)
+ {@+subtype(p)=2;lft_hit=false;
+ }
+ if (X) if (lig_stack==null)
+ {@+incr(subtype(p));rt_hit=false;
+ }
+ link(cur_q)=p;t=p;ligature_present=false;
+ }
+@d pop_lig_stack {@+if (lig_ptr(lig_stack) > null)
+ {@+link(t)=lig_ptr(lig_stack); /*this is a charnode for |hu[j+1]|*/
+ t=link(t);incr(j);
+ }
+ p=lig_stack;lig_stack=link(p);free_node(p, small_node_size);
+ if (lig_stack==null) set_cur_r@;@+else cur_r=character(lig_stack);
+ } /*if |lig_stack| isn't |null| we have |cur_rh==non_char|*/
+
+@<Append a ligature and/or kern to the translation...@>=
+wrap_lig(rt_hit);
+if (w!=0)
+ {@+link(t)=new_kern(w);t=link(t);w=0;
+ }
+if (lig_stack > null)
+ {@+cur_q=t;cur_l=character(lig_stack);ligature_present=true;
+ pop_lig_stack;goto resume;
+ }
+
+@ @<Carry out a ligature replacement, updating the cursor structure...@>=
+{@+if (cur_l==non_char) lft_hit=true;
+if (j==n) if (lig_stack==null) rt_hit=true;
+check_interrupt; /*allow a way out in case there's an infinite ligature loop*/
+switch (op_byte(q)) {
+qi(case 1): qi(case 5): {@+cur_l=rem_byte(q); /*\.{=:\?}, \.{=:\?>}*/
+ ligature_present=true;
+ } @+break;
+qi(case 2): qi(case 6): {@+cur_r=rem_byte(q); /*\.{\?=:}, \.{\?=:>}*/
+ if (lig_stack > null) character(lig_stack)=cur_r;
+ else{@+lig_stack=new_lig_item(cur_r);
+ if (j==n) bchar=non_char;
+ else{@+p=get_avail();lig_ptr(lig_stack)=p;
+ character(p)=qi(hu[j+1]);font(p)=hf;
+ }
+ }
+ } @+break;
+qi(case 3): {@+cur_r=rem_byte(q); /*\.{\?=:\?}*/
+ p=lig_stack;lig_stack=new_lig_item(cur_r);link(lig_stack)=p;
+ } @+break;
+qi(case 7): qi(case 11): {@+wrap_lig(false); /*\.{\?=:\?>}, \.{\?=:\?>>}*/
+ cur_q=t;cur_l=rem_byte(q);ligature_present=true;
+ } @+break;
+default:{@+cur_l=rem_byte(q);ligature_present=true; /*\.{=:}*/
+ if (lig_stack > null) pop_lig_stack@;
+ else if (j==n) goto done;
+ else{@+append_charnode_to_t(cur_r);incr(j);set_cur_r;
+ }
+ }
+}
+if (op_byte(q) > qi(4)) if (op_byte(q)!=qi(7)) goto done;
+goto resume;
+}
+
+@ Okay, we're ready to insert the potential hyphenations that were found.
+When the following program is executed, we want to append the word
+|hu[1 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:
+
+@<Local variables for hyph...@>=
+pointer @!major_tail, @!minor_tail; /*the end of lists in the main and
+ discretionary branches being reconstructed*/
+ASCII_code @!c; /*character temporarily replaced by a hyphen*/
+uint8_t @!c_loc; /*where that character came from*/
+int @!r_count; /*replacement count for discretionary*/
+pointer @!hyf_node; /*the hyphen, if it exists*/
+
+@ When the following code is performed, |hyf[0]| and |hyf[hn]| will be zero.
+
+@<Reconstitute nodes for the hyphenated word...@>=
+@/do@+{l=j;j=reconstitute(j, hn, bchar, qi(hyf_char))+1;
+if (hyphen_passed==0)
+ {@+link(s)=link(hold_head);
+ while (link(s) > null) s=link(s);
+ if (odd(hyf[j-1]))
+ {@+l=j;hyphen_passed=j-1;link(hold_head)=null;
+ }
+ }
+if (hyphen_passed > 0)
+ @<Create and append a discretionary node as an alternative to the unhyphenated word,
+and continue to develop both branches until they become equivalent@>;
+}@+ while (!(j > hn));
+link(s)=q
+
+@ In this repeat loop we will insert another discretionary if |hyf[j-1]| is
+odd, when both branches of the previous discretionary end at position |j-1|.
+Strictly speaking, we aren't justified in doing this, because we don't know
+that a hyphen after |j-1| is truly independent of those branches. But in almost
+all applications we would rather not lose a potentially valuable hyphenation
+point. (Consider the word `difficult', where the letter `c' is in position |j|.)
+
+@d advance_major_tail {@+major_tail=link(major_tail);incr(r_count);
+ }
+
+@<Create and append a discretionary node as an alternative...@>=
+@/do@+{r=get_node(small_node_size);
+link(r)=link(hold_head);type(r)=disc_node;
+major_tail=r;r_count=0;
+while (link(major_tail) > null) advance_major_tail;
+i=hyphen_passed;hyf[i]=0;
+@<Put the \(c)characters |hu[l..i]| and a hyphen into |pre_break(r)|@>;
+@<Put the \(c)characters |hu[i+1..]| into |post_break(r)|, appending to this list
+and to |major_tail| until synchronization has been achieved@>;
+@<Move pointer |s| to the end of the current list, and set |replace_count(r)| appropriately@>;
+hyphen_passed=j-1;link(hold_head)=null;
+}@+ while (!(!odd(hyf[j-1])))
+
+@ The new hyphen might combine with the previous character via ligature
+or kern. At this point we have |l-1 <= i < j| and |i < hn|.
+
+@<Put the \(c)characters |hu[l..i]| and a hyphen into |pre_break(r)|@>=
+minor_tail=null;pre_break(r)=null;hyf_node=new_character(hf, hyf_char);
+if (hyf_node!=null)
+ {@+incr(i);c=hu[i];hu[i]=hyf_char;free_avail(hyf_node);
+ }
+while (l <= i)
+ {@+l=reconstitute(l, i, font_bchar[hf], non_char)+1;
+ if (link(hold_head) > null)
+ {@+if (minor_tail==null) pre_break(r)=link(hold_head);
+ else link(minor_tail)=link(hold_head);
+ minor_tail=link(hold_head);
+ while (link(minor_tail) > null) minor_tail=link(minor_tail);
+ }
+ }
+if (hyf_node!=null)
+ {@+hu[i]=c; /*restore the character in the hyphen position*/
+ l=i;decr(i);
+ }
+
+@ The synchronization algorithm begins with |l==i+1 <= j|.
+
+@<Put the \(c)characters |hu[i+1..]| into |post_break(r)|...@>=
+minor_tail=null;post_break(r)=null;c_loc=0;
+if (bchar_label[hf]!=non_address) /*put left boundary at beginning of new line*/
+ {@+decr(l);c=hu[l];c_loc=l;hu[l]=256;
+ }
+while (l < j)
+ {@+@/do@+{l=reconstitute(l, hn, bchar, non_char)+1;
+ if (c_loc > 0)
+ {@+hu[c_loc]=c;c_loc=0;
+ }
+ if (link(hold_head) > null)
+ {@+if (minor_tail==null) post_break(r)=link(hold_head);
+ else link(minor_tail)=link(hold_head);
+ minor_tail=link(hold_head);
+ while (link(minor_tail) > null) minor_tail=link(minor_tail);
+ }
+ }@+ while (!(l >= j));
+ while (l > j)
+ @<Append characters of |hu[j..]| to |major_tail|, advancing~|j|@>;
+ }
+
+@ @<Append characters of |hu[j..]|...@>=
+{@+j=reconstitute(j, hn, bchar, non_char)+1;
+link(major_tail)=link(hold_head);
+while (link(major_tail) > null) advance_major_tail;
+}
+
+@ Ligature insertion can cause a word to grow exponentially in size. Therefore
+we must test the size of |r_count| here, even though the hyphenated text
+was at most 63 characters long.
+
+@<Move pointer |s| to the end of the current list...@>=
+if (r_count > 127) /*we have to forget the discretionary hyphen*/
+ {@+link(s)=link(r);link(r)=null;flush_node_list(r);
+ }
+else{@+link(s)=r;replace_count(r)=r_count;
+ }
+s=major_tail
+
+@* Hyphenation.
+When a word |hc[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.
+@^Liang, Franklin Mark@>
+
+Let's consider Liang's method first, since it is much more interesting than the
+exception-lookup routine. The algorithm begins by setting |hyf[j]| to zero
+for all |j|, and invalid characters are inserted into |hc[0]|
+and |hc[hn+1]| to serve as delimiters. Then a reasonably fast method is
+used to see which of a given set of patterns occurs in the word
+|hc[0 dotdot(hn+1)]|. Each pattern $p_1\ldots p_k$ of length |k| has an associated
+sequence of |k+1| numbers $n_0\ldots n_k$; and if the pattern occurs in
+|hc[(j+1)dotdot(j+k)]|, \TeX\ will set |hyf[j+i]=@tmax@>(hyf[j+i],@t$n_i$@>)| for
+|0 <= i <= k|. After this has been done for each pattern that occurs, a
+discretionary hyphen will be inserted between |hc[j]| and |hc[j+1]| when
+|hyf[j]| is odd, as we have already seen.
+
+The set of patterns $p_1\ldots p_k$ and associated numbers $n_0\ldots n_k$
+depends, of course, on the language whose words are being hyphenated, and
+on the degree of hyphenation that is desired. A method for finding
+appropriate |p|'s and |n|'s, from a given dictionary of words and acceptable
+hyphenations, is discussed in Liang's Ph.D. thesis (Stanford University,
+1983); \TeX\ simply starts with the patterns and works from there.
+
+@ The patterns are stored in a compact table that is also efficient for
+retrieval, using a variant of ``trie memory'' [cf.\ {\sl The Art of
+Computer Programming \bf3} (1973), 481--505]. We can find each pattern
+$p_1\ldots p_k$ by letting $z_0$ be one greater than the relevant language
+index and then, for |1 <= i <= k|,
+setting |@t$z_i$@>=trie_link@t$(z_{i-1})+p_i$@>|; the pattern will be
+identified by the number $z_k$. Since all the pattern information is
+packed together into a single |trie_link| array, it is necessary to
+prevent confusion between the data from inequivalent patterns, so another
+table is provided such that |trie_char@t$(z_i)=p_i$@>| for all |i|. There
+is also a table |trie_op|$(z_k)$ to identify the numbers $n_0\ldots n_k$
+associated with $p_1\ldots p_k$.
+
+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(@t$z_k$@>)!=min_quarterword|, when $p_1\ldots p_k$ has matched
+the letters in |hc[(l-k+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=trie_op(@t$z_k$@>)|. Then set |v=v+op_start[t]|,
+|hyf[l-hyf_distance[v]]=@tmax@>(hyf[l-hyf_distance[v]], hyf_num[v])|,
+and |v=hyf_next[v]|; repeat, if necessary, until |v==min_quarterword|.
+
+@<Types...@>=
+typedef uint16_t trie_pointer; /*an index into |trie|*/
+
+@ @d trie_link(X) trie[X].rh /*``downward'' link in a trie*/
+@d trie_char(X) trie[X].b1 /*character matched at this trie location*/
+@d trie_op(X) trie[X].b0 /*program for hyphenation at this trie location*/
+
+@<Glob...@>=
+two_halves @!trie[trie_size+1]; /*|trie_link|, |trie_char|, |trie_op|*/
+small_number @!hyf_distance0[trie_op_size], *const @!hyf_distance = @!hyf_distance0-1; /*position |k-j| of $n_j$*/
+small_number @!hyf_num0[trie_op_size], *const @!hyf_num = @!hyf_num0-1; /*value of $n_j$*/
+quarterword @!hyf_next0[trie_op_size], *const @!hyf_next = @!hyf_next0-1; /*continuation code*/
+uint16_t @!op_start[256]; /*offset for current language*/
+
+@ @<Local variables for hyph...@>=
+trie_pointer @!z; /*an index into |trie|*/
+int @!v; /*an index into |hyf_distance|, etc.*/
+
+@ Assuming that these auxiliary tables have been set up properly, the
+hyphenation algorithm is quite short. In the following code we set |hc[hn+2]|
+to the impossible value 256, in order to guarantee that |hc[hn+3]| will
+never be fetched.
+
+@<Find hyphen locations for the word in |hc|...@>=
+for (j=0; j<=hn; j++) hyf[j]=0;
+@<Look for the word |hc[1..hn]| in the exception table, and |goto found| (with |hyf|
+containing the hyphens) if an entry is found@>;
+if (trie_char(cur_lang+1)!=qi(cur_lang)) return; /*no patterns for |cur_lang|*/
+hc[0]=0;hc[hn+1]=0;hc[hn+2]=256; /*insert delimiters*/
+for (j=0; j<=hn-r_hyf+1; j++)
+ {@+z=trie_link(cur_lang+1)+hc[j];l=j;
+ while (hc[l]==qo(trie_char(z)))
+ {@+if (trie_op(z)!=min_quarterword)
+ @<Store \(m)maximum values in the |hyf| table@>;
+ incr(l);z=trie_link(z)+hc[l];
+ }
+ }
+found: for (j=0; j<=l_hyf-1; j++) hyf[j]=0;
+for (j=0; j<=r_hyf-1; j++) hyf[hn-j]=0
+
+@ @<Store \(m)maximum values in the |hyf| table@>=
+{@+v=trie_op(z);
+@/do@+{v=v+op_start[cur_lang];i=l-hyf_distance[v];
+if (hyf_num[v] > hyf[i]) hyf[i]=hyf_num[v];
+v=hyf_next[v];
+}@+ while (!(v==min_quarterword));
+}
+
+@ The exception table that is built by \TeX's \.{\\hyphenation} primitive is
+organized as an ordered hash table [cf.\ Amble and Knuth, {\sl The Computer
+@^Amble, Ole@> @^Knuth, Donald Ervin@>
+Journal\/ \bf17} (1974), 135--142] using linear probing. If $\alpha$ and
+$\beta$ are words, we will say that $\alpha<\beta$ if $\vert\alpha\vert<
+\vert\beta\vert$ or if $\vert\alpha\vert=\vert\beta\vert$ and
+$\alpha$ is lexicographically smaller than $\beta$. (The notation $\vert
+\alpha\vert$ stands for the length of $\alpha$.) The idea of ordered hashing
+is to arrange the table so that a given word $\alpha$ can be sought by computing
+a hash address $h=h(\alpha)$ and then looking in table positions |h|, |h-1|,
+\dots, until encountering the first word $\L\alpha$. If this word is
+different from $\alpha$, we can conclude that $\alpha$ is not in the table.
+
+The words in the table point to lists in |mem| that specify hyphen positions
+in their |info| fields. The list for $c_1\ldots c_n$ contains the number |k| if
+the word $c_1\ldots c_n$ has a discretionary hyphen between $c_k$ and
+$c_{k+1}$.
+
+@<Types...@>=
+typedef uint16_t hyph_pointer; /*an index into the ordered hash table*/
+
+@ @<Glob...@>=
+str_number @!hyph_word[hyph_size+1]; /*exception words*/
+pointer @!hyph_list[hyph_size+1]; /*lists of hyphen positions*/
+hyph_pointer @!hyph_count; /*the number of words in the exception dictionary*/
+
+@ @<Local variables for init...@>=
+hyph_pointer @!z; /*runs through the exception dictionary*/
+
+@ @<Set init...@>=
+for (z=0; z<=hyph_size; z++)
+ {@+hyph_word[z]=0;hyph_list[z]=null;
+ }
+hyph_count=0;
+
+@ The algorithm for exception lookup is quite simple, as soon as we have
+a few more local variables to work with.
+
+@<Local variables for hyph...@>=
+hyph_pointer @!h; /*an index into |hyph_word| and |hyph_list|*/
+str_number @!k; /*an index into |str_start|*/
+pool_pointer @!u; /*an index into |str_pool|*/
+
+@ First we compute the hash code |h|, then we search until we either
+find the word or we don't. Words from different languages are kept
+separate by appending the language code to the string.
+
+@<Look for the word |hc[1...@>=
+h=hc[1];incr(hn);hc[hn]=cur_lang;
+for (j=2; j<=hn; j++) h=(h+h+hc[j])%hyph_size;
+loop@+{@+@<If the string |hyph_word[h]| is less than \(hc)|hc[1..hn]|, |goto not_found|;
+but if the two strings are equal, set |hyf| to the hyphen positions and |goto found|@>;
+ if (h > 0) decr(h);@+else h=hyph_size;
+ }
+not_found: decr(hn)
+
+@ @<If the string |hyph_word[h]| is less than \(hc)...@>=
+k=hyph_word[h];if (k==0) goto not_found;
+if (length(k) < hn) goto not_found;
+if (length(k)==hn)
+ {@+j=1;u=str_start[k];
+ @/do@+{if (so(str_pool[u]) < hc[j]) goto not_found;
+ if (so(str_pool[u]) > hc[j]) goto done;
+ incr(j);incr(u);
+ }@+ while (!(j > hn));
+ @<Insert hyphens as specified in |hyph_list[h]|@>;
+ decr(hn);goto found;
+ }
+done:
+
+@ @<Insert hyphens as specified...@>=
+s=hyph_list[h];
+while (s!=null)
+ {@+hyf[info(s)]=1;s=link(s);
+ }
+
+@ @<Search |hyph_list| for pointers to |p|@>=
+for (q=0; q<=hyph_size; q++)
+ {@+if (hyph_list[q]==p)
+ {@+print_nl("HYPH(");print_int(q);print_char(')');
+ }
+ }
+
+@ We have now completed the hyphenation routine, so the |line_break| procedure
+is finished at last. Since the hyphenation exception table is fresh in our
+minds, it's a good time to deal with the routine that adds new entries to it.
+
+When \TeX\ has scanned `\.{\\hyphenation}', it calls on a procedure named
+|new_hyph_exceptions| to do the right thing.
+
+@d set_cur_lang if (language <= 0) cur_lang=0;
+ else if (language > 255) cur_lang=0;
+ else cur_lang=language
+
+@p void new_hyph_exceptions(void) /*enters new exceptions*/
+{@+
+uint8_t n; /*length of current word; not always a |small_number|*/
+int @!j; /*an index into |hc|*/
+hyph_pointer @!h; /*an index into |hyph_word| and |hyph_list|*/
+str_number @!k; /*an index into |str_start|*/
+pointer @!p; /*head of a list of hyphen positions*/
+pointer @!q; /*used when creating a new node for list |p|*/
+str_number @!s, @!t; /*strings being compared or stored*/
+pool_pointer @!u, @!v; /*indices into |str_pool|*/
+scan_left_brace(); /*a left brace must follow \.{\\hyphenation}*/
+set_cur_lang;
+@<Enter as many hyphenation exceptions as are listed, until coming to a right brace;
+then |return|@>;
+}
+
+@ @<Enter as many...@>=
+n=0;p=null;
+loop@+{@+get_x_token();
+ reswitch: switch (cur_cmd) {
+ case letter: case other_char: case char_given: @<Append a new letter or hyphen@>@;@+break;
+ case char_num: {@+scan_char_num();cur_chr=cur_val;cur_cmd=char_given;
+ goto reswitch;
+ }
+ case spacer: case right_brace: {@+if (n > 1) @<Enter a hyphenation exception@>;
+ if (cur_cmd==right_brace) return;
+ n=0;p=null;
+ } @+break;
+ default:@<Give improper \.{\\hyphenation} error@>@;
+ }
+ }
+
+@ @<Give improper \.{\\hyph...@>=
+{@+print_err("Improper ");print_esc(@[@<|"hyphenation"|@>@]);
+@.Improper \\hyphenation...@>
+ print_str(" will be flushed");
+help2("Hyphenation exceptions must contain only letters")@/
+ ("and hyphens. But continue; I'll forgive and forget.");
+error();
+}
+
+@ @<Append a new letter or hyphen@>=
+if (cur_chr=='-') @<Append the value |n| to list |p|@>@;
+else{@+if (lc_code(cur_chr)==0)
+ {@+print_err("Not a letter");
+@.Not a letter@>
+ help2("Letters in \\hyphenation words must have \\lccode>0.")@/
+ ("Proceed; I'll ignore the character I just read.");
+ error();
+ }
+ else if (n < 63)
+ {@+incr(n);hc[n]=lc_code(cur_chr);
+ }
+ }
+
+@ @<Append the value |n| to list |p|@>=
+{@+if (n < 63)
+ {@+q=get_avail();link(q)=p;info(q)=n;p=q;
+ }
+}
+
+@ @<Enter a hyphenation exception@>=
+{@+incr(n);hc[n]=cur_lang;str_room(n);h=0;
+for (j=1; j<=n; j++)
+ {@+h=(h+h+hc[j])%hyph_size;
+ append_char(hc[j]);
+ }
+s=make_string();
+@<Insert the \(p)pair |(s,p)| into the exception table@>;
+}
+
+@ @<Insert the \(p)pair |(s,p)|...@>=
+if (hyph_count==hyph_size) overflow("exception dictionary", hyph_size);
+@:TeX capacity exceeded exception dictionary}{\quad exception dictionary@>
+incr(hyph_count);
+while (hyph_word[h]!=0)
+ {@+@<If the string |hyph_word[h]| is less than \(or)or equal to |s|, interchange
+|(hyph_word[h],hyph_list[h])| with |(s,p)|@>;
+ if (h > 0) decr(h);@+else h=hyph_size;
+ }
+hyph_word[h]=s;hyph_list[h]=p
+
+@ @<If the string |hyph_word[h]| is less than \(or)...@>=
+k=hyph_word[h];
+if (length(k) < length(s)) goto found;
+if (length(k) > length(s)) goto not_found;
+u=str_start[k];v=str_start[s];
+@/do@+{if (str_pool[u] < str_pool[v]) goto found;
+if (str_pool[u] > str_pool[v]) goto not_found;
+incr(u);incr(v);
+}@+ while (!(u==str_start[k+1]));
+found: q=hyph_list[h];hyph_list[h]=p;p=q;@/
+t=hyph_word[h];hyph_word[h]=s;s=t;
+not_found:
+
+@* Initializing the hyphenation tables.
+The trie for \TeX's hyphenation algorithm is built from a sequence of
+patterns following a \.{\\patterns} specification. Such a specification
+is allowed only in \.{INITEX}, since the extra memory for auxiliary tables
+and for the initialization program itself would only clutter up the
+production version of \TeX\ with a lot of deadwood.
+
+The first step is to build a trie that is linked, instead of packed
+into sequential storage, so that insertions are readily made.
+After all patterns have been processed, \.{INITEX}
+compresses the linked trie by identifying common subtries. Finally the
+trie is packed into the efficient sequential form that the hyphenation
+algorithm actually uses.
+
+@<Declare subprocedures for |line_break|@>=
+#ifdef @!INIT
+@<Declare procedures for preprocessing hyphenation patterns@>@;
+#endif
+
+@ Before we discuss trie building in detail, let's consider the simpler
+problem of creating the |hyf_distance|, |hyf_num|, and |hyf_next| arrays.
+
+Suppose, for example, that \TeX\ reads the pattern `\.{ab2cde1}'. This is
+a pattern of length 5, with $n_0\ldots n_5=0\,0\,2\,0\,0\,1$ in the
+notation above. We want the corresponding |trie_op| code |v| to have
+|hyf_distance[v]==3|, |hyf_num[v]==2|, and |hyf_next[v]==@t$v^\prime$@>|,
+where the auxiliary |trie_op| code $v^\prime$ has
+|hyf_distance[@t$v^\prime$@>]==0|, |hyf_num[@t$v^\prime$@>]==1|, and
+|hyf_next[@t$v^\prime$@>]==min_quarterword|.
+
+\TeX\ computes an appropriate value |v| with the |new_trie_op| subroutine
+below, by setting
+$$\hbox{|@t$v^\prime$@>=new_trie_op(0, 1, min_quarterword)|,\qquad
+|v=new_trie_op(3, 2,@t$v^\prime$@>)|.}$$
+This subroutine looks up its three
+parameters in a special hash table, assigning a new value only if these
+three have not appeared before for the current language.
+
+The hash table is called |trie_op_hash|, and the number of entries it contains
+is |trie_op_ptr|.
+
+@<Glob...@>=
+#ifdef @!INIT
+uint16_t @!trie_op_hash0[trie_op_size+trie_op_size+1], *const @!trie_op_hash = @!trie_op_hash0+trie_op_size;
+ /*trie op codes for quadruples*/
+quarterword @!trie_used[256];
+ /*largest opcode used so far for this language*/
+ASCII_code @!trie_op_lang0[trie_op_size], *const @!trie_op_lang = @!trie_op_lang0-1;
+ /*language part of a hashed quadruple*/
+quarterword @!trie_op_val0[trie_op_size], *const @!trie_op_val = @!trie_op_val0-1;
+ /*opcode corresponding to a hashed quadruple*/
+uint16_t @!trie_op_ptr; /*number of stored ops so far*/
+#endif
+
+@ 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.
+
+@<Declare procedures for preprocessing hyph...@>=
+quarterword new_trie_op(small_number @!d, small_number @!n, quarterword @!v)
+{@+
+int16_t h; /*trial hash location*/
+quarterword @!u; /*trial op code*/
+uint16_t @!l; /*pointer to stored data*/
+h=abs(n+313*d+361*v+1009*cur_lang)%(trie_op_size+trie_op_size)
+ -trie_op_size;
+loop@+{@+l=trie_op_hash[h];
+ if (l==0) /*empty position found for a new op*/
+ {@+if (trie_op_ptr==trie_op_size)
+ overflow("pattern memory ops", trie_op_size);
+ u=trie_used[cur_lang];
+ if (u==max_quarterword)
+ overflow("pattern memory ops per language",
+ max_quarterword-min_quarterword);
+ incr(trie_op_ptr);incr(u);trie_used[cur_lang]=u;
+ hyf_distance[trie_op_ptr]=d;
+ hyf_num[trie_op_ptr]=n;hyf_next[trie_op_ptr]=v;
+ trie_op_lang[trie_op_ptr]=cur_lang;trie_op_hash[h]=trie_op_ptr;
+ trie_op_val[trie_op_ptr]=u;return u;
+ }
+ if ((hyf_distance[l]==d)&&(hyf_num[l]==n)&&(hyf_next[l]==v)
+ &&(trie_op_lang[l]==cur_lang))
+ {@+return trie_op_val[l];
+ }
+ if (h > -trie_op_size) decr(h);@+else h=trie_op_size;
+ }
+}
+
+@ After |new_trie_op| has compressed the necessary opcode information,
+plenty of information is available to unscramble the data into the
+final form needed by our hyphenation algorithm.
+
+@<Sort \(t)the hyphenation op tables into proper order@>=
+op_start[0]=-min_quarterword;
+for (j=1; j<=255; j++) op_start[j]=op_start[j-1]+qo(trie_used[j-1]);
+for (j=1; j<=trie_op_ptr; j++)
+ trie_op_hash[j]=op_start[trie_op_lang[j]]+trie_op_val[j]; /*destination*/
+for (j=1; j<=trie_op_ptr; j++) while (trie_op_hash[j] > j)
+ {@+k=trie_op_hash[j];@/
+ t=hyf_distance[k];hyf_distance[k]=hyf_distance[j];hyf_distance[j]=t;@/
+ t=hyf_num[k];hyf_num[k]=hyf_num[j];hyf_num[j]=t;@/
+ t=hyf_next[k];hyf_next[k]=hyf_next[j];hyf_next[j]=t;@/
+ trie_op_hash[j]=trie_op_hash[k];trie_op_hash[k]=k;
+ }
+
+@ Before we forget how to initialize the data structures that have been
+mentioned so far, let's write down the code that gets them started.
+
+@<Initialize table entries...@>=
+for (k=-trie_op_size; k<=trie_op_size; k++) trie_op_hash[k]=0;
+for (k=0; k<=255; k++) trie_used[k]=min_quarterword;
+trie_op_ptr=0;
+
+@ The linked trie that is used to preprocess hyphenation patterns appears
+in several global arrays. Each node represents an instruction of the form
+``if you see character |c|, then perform operation |o|, move to the
+next character, and go to node |l|; otherwise go to node |r|.''
+The four quantities |c|, |o|, |l|, and |r| are stored in four arrays
+|trie_c|, |trie_o|, |trie_l|, and |trie_r|. The root of the trie
+is |trie_l[0]|, and the number of nodes is |trie_ptr|. Null trie
+pointers are represented by zero. To initialize the trie, we simply
+set |trie_l[0]| and |trie_ptr| to zero. We also set |trie_c[0]| to some
+arbitrary value, since the algorithm may access it.
+
+The algorithms maintain the condition
+$$\hbox{|trie_c[trie_r[z]] > trie_c[z]|\qquad
+whenever |z!=0| and |trie_r[z]!=0|};$$ in other words, sibling nodes are
+ordered by their |c| fields.
+
+@d trie_root trie_l[0] /*root of the linked trie*/
+
+@<Glob...@>=
+#ifdef @!INIT
+packed_ASCII_code @!trie_c[trie_size+1];
+ /*characters to match*/
+@t\hskip10pt@>quarterword @!trie_o[trie_size+1];
+ /*operations to perform*/
+@t\hskip10pt@>trie_pointer @!trie_l[trie_size+1];
+ /*left subtrie links*/
+@t\hskip10pt@>trie_pointer @!trie_r[trie_size+1];
+ /*right subtrie links*/
+@t\hskip10pt@>trie_pointer @!trie_ptr; /*the number of nodes in the trie*/
+@t\hskip10pt@>trie_pointer @!trie_hash[trie_size+1];
+ /*used to identify equivalent subtries*/
+#endif
+
+@ Let us suppose that a linked trie has already been constructed.
+Experience shows that we can often reduce its size by recognizing common
+subtries; therefore another hash table is introduced for this purpose,
+somewhat similar to |trie_op_hash|. The new hash table will be
+initialized to zero.
+
+The function |trie_node(p)| returns |p| if |p| is distinct from other nodes
+that it has seen, otherwise it returns the number of the first equivalent
+node that it has seen.
+
+Notice that we might make subtries equivalent even if they correspond to
+patterns for different languages, in which the trie ops might mean quite
+different things. That's perfectly all right.
+
+@<Declare procedures for preprocessing hyph...@>=
+trie_pointer trie_node(trie_pointer @!p) /*converts
+ to a canonical form*/
+{@+
+trie_pointer h; /*trial hash location*/
+trie_pointer @!q; /*trial trie node*/
+h=abs(trie_c[p]+1009*trie_o[p]+@|
+ 2718*trie_l[p]+3142*trie_r[p])%trie_size;
+loop@+{@+q=trie_hash[h];
+ if (q==0)
+ {@+trie_hash[h]=p;return p;
+ }
+ if ((trie_c[q]==trie_c[p])&&(trie_o[q]==trie_o[p])&&@|
+ (trie_l[q]==trie_l[p])&&(trie_r[q]==trie_r[p]))
+ {@+return q;
+ }
+ if (h > 0) decr(h);@+else h=trie_size;
+ }
+}
+
+@ A neat recursive procedure is now able to compress a trie by
+traversing it and applying |trie_node| to its nodes in ``bottom up''
+fashion. We will compress the entire trie by clearing |trie_hash| to
+zero and then saying `|trie_root=compress_trie(trie_root)|'.
+@^recursion@>
+
+@<Declare procedures for preprocessing hyph...@>=
+trie_pointer compress_trie(trie_pointer @!p)
+{@+if (p==0) return 0;
+else{@+trie_l[p]=compress_trie(trie_l[p]);
+ trie_r[p]=compress_trie(trie_r[p]);
+ return trie_node(p);
+ }
+}
+
+@ The compressed trie will be packed into the |trie| array using a
+``top-down first-fit'' procedure. This is a little tricky, so the reader
+should pay close attention: The |trie_hash| array is cleared to zero
+again and renamed |trie_ref| for this phase of the operation; later on,
+|trie_ref[p]| will be nonzero only if the linked trie node |p| is the
+smallest character
+in a family and if the characters |c| of that family have been allocated to
+locations |trie_ref[p]+c| in the |trie| array. Locations of |trie| that
+are in use will have |trie_link==0|, while the unused holes in |trie|
+will be doubly linked with |trie_link| pointing to the next larger vacant
+location and |trie_back| pointing to the next smaller one. This double
+linking will have been carried out only as far as |trie_max|, where
+|trie_max| is the largest index of |trie| that will be needed.
+To save time at the low end of the trie, we maintain array entries
+|trie_min[c]| pointing to the smallest hole that is greater than~|c|.
+Another array |trie_taken| tells whether or not a given location is
+equal to |trie_ref[p]| for some |p|; this array is used to ensure that
+distinct nodes in the compressed trie will have distinct |trie_ref|
+entries.
+
+@d trie_ref trie_hash /*where linked trie families go into |trie|*/
+@d trie_back(X) trie[X].lh /*backward links in |trie| holes*/
+
+@<Glob...@>=
+#ifdef @!INIT
+bool @!trie_taken0[trie_size], *const @!trie_taken = @!trie_taken0-1;
+ /*does a family start here?*/
+@t\hskip10pt@>trie_pointer @!trie_min[256];
+ /*the first possible slot for each character*/
+@t\hskip10pt@>trie_pointer @!trie_max; /*largest location used in |trie|*/
+@t\hskip10pt@>bool @!trie_not_ready; /*is the trie still in linked form?*/
+#endif
+
+@ Each time \.{\\patterns} appears, it contributes further patterns to
+the future trie, which will be built only when hyphenation is attempted or
+when a format file is dumped. The boolean variable |trie_not_ready|
+will change to |false| when the trie is compressed; this will disable
+further patterns.
+
+@<Initialize table entries...@>=
+trie_not_ready=true;trie_root=0;trie_c[0]=si(0);trie_ptr=0;
+
+@ Here is how the trie-compression data structures are initialized.
+If storage is tight, it would be possible to overlap |trie_op_hash|,
+|trie_op_lang|, and |trie_op_val| with |trie|, |trie_hash|, and |trie_taken|,
+because we finish with the former just before we need the latter.
+
+@<Get ready to compress the trie@>=
+@<Sort \(t)the hyphenation...@>;
+for (p=0; p<=trie_size; p++) trie_hash[p]=0;
+trie_root=compress_trie(trie_root); /*identify equivalent subtries*/
+for (p=0; p<=trie_ptr; p++) trie_ref[p]=0;
+for (p=0; p<=255; p++) trie_min[p]=p+1;
+trie_link(0)=1;trie_max=0
+
+@ The |first_fit| procedure finds the smallest hole |z| in |trie| such that
+a trie family starting at a given node |p| will fit into vacant positions
+starting at |z|. If |c==trie_c[p]|, this means that location |z-c| must
+not already be taken by some other family, and that |z-c+@t$c^\prime$@>|
+must be vacant for all characters $c^\prime$ in the family. The procedure
+sets |trie_ref[p]| to |z-c| when the first fit has been found.
+
+@<Declare procedures for preprocessing hyph...@>=
+void first_fit(trie_pointer @!p) /*packs a family into |trie|*/
+{@+
+trie_pointer h; /*candidate for |trie_ref[p]|*/
+trie_pointer @!z; /*runs through holes*/
+trie_pointer @!q; /*runs through the family starting at |p|*/
+ASCII_code @!c; /*smallest character in the family*/
+trie_pointer @!l, @!r; /*left and right neighbors*/
+uint16_t @!ll; /*upper limit of |trie_min| updating*/
+c=so(trie_c[p]);
+z=trie_min[c]; /*get the first conceivably good hole*/
+loop@+{@+h=z-c;@/
+ @<Ensure that |trie_max>=h+256|@>;
+ if (trie_taken[h]) goto not_found;
+ @<If all characters of the family fit relative to |h|, then |goto found|,\30\ otherwise
+|goto not_found|@>;
+ not_found: z=trie_link(z); /*move to the next hole*/
+ }
+found: @<Pack the family into |trie| relative to |h|@>;
+}
+
+@ By making sure that |trie_max| is at least |h+256|, we can be sure that
+|trie_max > z|, since |h==z-c|. It follows that location |trie_max| will
+never be occupied in |trie|, and we will have |trie_max >= trie_link(z)|.
+
+@<Ensure that |trie_max>=h+256|@>=
+if (trie_max < h+256)
+ {@+if (trie_size <= h+256) overflow("pattern memory", trie_size);
+@:TeX capacity exceeded pattern memory}{\quad pattern memory@>
+ @/do@+{incr(trie_max);trie_taken[trie_max]=false;
+ trie_link(trie_max)=trie_max+1;trie_back(trie_max)=trie_max-1;
+ }@+ while (!(trie_max==h+256));
+ }
+
+@ @<If all characters of the family fit relative to |h|...@>=
+q=trie_r[p];
+while (q > 0)
+ {@+if (trie_link(h+so(trie_c[q]))==0) goto not_found;
+ q=trie_r[q];
+ }
+goto found
+
+@ @<Pack the family into |trie| relative to |h|@>=
+trie_taken[h]=true;trie_ref[p]=h;q=p;
+@/do@+{z=h+so(trie_c[q]);l=trie_back(z);r=trie_link(z);
+trie_back(r)=l;trie_link(l)=r;trie_link(z)=0;
+if (l < 256)
+ {@+if (z < 256) ll=z;@+else ll=256;
+ @/do@+{trie_min[l]=r;incr(l);
+ }@+ while (!(l==ll));
+ }
+q=trie_r[q];
+}@+ while (!(q==0))
+
+@ To pack the entire linked trie, we use the following recursive procedure.
+@^recursion@>
+
+@<Declare procedures for preprocessing hyph...@>=
+void trie_pack(trie_pointer @!p) /*pack subtries of a family*/
+{@+trie_pointer q; /*a local variable that need not be saved on recursive calls*/
+@/do@+{q=trie_l[p];
+if ((q > 0)&&(trie_ref[q]==0))
+ {@+first_fit(q);trie_pack(q);
+ }
+p=trie_r[p];
+}@+ while (!(p==0));
+}
+
+@ 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.
+
+@<Move the data into |trie|@>=
+h.rh=0;h.b0=min_quarterword;h.b1=min_quarterword; /*|trie_link=0|,
+ |trie_op=min_quarterword|, |trie_char=qi(0)|*/
+if (trie_root==0) /*no patterns were given*/
+ {@+for (r=0; r<=256; r++) trie[r]=h;
+ trie_max=256;
+ }
+else{@+trie_fix(trie_root); /*this fixes the non-holes in |trie|*/
+ r=0; /*now we will zero out all the holes*/
+ @/do@+{s=trie_link(r);trie[r]=h;r=s;
+ }@+ while (!(r > trie_max));
+ }
+trie_char(0)=qi('?'); /*make |trie_char(c)!=c| for all |c|*/
+
+@ The fixing-up procedure is, of course, recursive. Since the linked trie
+usually has overlapping subtries, the same data may be moved several
+times; but that causes no harm, and at most as much work is done as it
+took to build the uncompressed trie.
+@^recursion@>
+
+@<Declare procedures for preprocessing hyph...@>=
+void trie_fix(trie_pointer @!p) /*moves |p| and its siblings into |trie|*/
+{@+trie_pointer q; /*a local variable that need not be saved on recursive calls*/
+ASCII_code @!c; /*another one that need not be saved*/
+trie_pointer @!z; /*|trie| reference; this local variable must be saved*/
+z=trie_ref[p];
+@/do@+{q=trie_l[p];c=so(trie_c[p]);
+trie_link(z+c)=trie_ref[q];trie_char(z+c)=qi(c);trie_op(z+c)=trie_o[p];
+if (q > 0) trie_fix(q);
+p=trie_r[p];
+}@+ while (!(p==0));
+}
+
+@ Now let's go back to the easier problem, of building the linked
+trie. When \.{INITEX} has scanned the `\.{\\patterns}' control
+sequence, it calls on |new_patterns| to do the right thing.
+
+@<Declare procedures for preprocessing hyph...@>=
+void new_patterns(void) /*initializes the hyphenation pattern data*/
+{@+
+uint8_t k, @!l; /*indices into |hc| and |hyf|;
+ not always in |small_number| range*/
+bool @!digit_sensed; /*should the next digit be treated as a letter?*/
+quarterword @!v; /*trie op code*/
+trie_pointer @!p, @!q; /*nodes of trie traversed during insertion*/
+bool @!first_child; /*is |p==trie_l[q]|?*/
+ASCII_code @!c; /*character being inserted*/
+if (trie_not_ready)
+ {@+set_cur_lang;scan_left_brace(); /*a left brace must follow \.{\\patterns}*/
+ @<Enter all of the patterns into a linked trie, until coming to a right brace@>;
+ }
+else{@+print_err("Too late for ");print_esc(@[@<|"patterns"|@>@]);
+ help1("All patterns must be given before typesetting begins.");
+ error();link(garbage)=scan_toks(false, false);flush_list(def_ref);
+ }
+}
+
+@ Novices are not supposed to be using \.{\\patterns}, so the error
+messages are terse. (Note that all error messages appear in \TeX's string
+pool, even if they are used only by \.{INITEX}.)
+
+@<Enter all of the patterns into a linked trie...@>=
+k=0;hyf[0]=0;digit_sensed=false;
+loop@+{@+get_x_token();
+ switch (cur_cmd) {
+ case letter: case other_char: @<Append a new letter or a hyphen level@>@;@+break;
+ case spacer: case right_brace: {@+if (k > 0)
+ @<Insert a new pattern into the linked trie@>;
+ if (cur_cmd==right_brace) goto done;
+ k=0;hyf[0]=0;digit_sensed=false;
+ } @+break;
+ default:{@+print_err("Bad ");print_esc(@[@<|"patterns"|@>@]);
+@.Bad \\patterns@>
+ help1("(See Appendix H.)");error();
+ }
+ }
+ }
+done:
+
+@ @<Append a new letter or a hyphen level@>=
+if (digit_sensed||(cur_chr < '0')||(cur_chr > '9'))
+ {@+if (cur_chr=='.') cur_chr=0; /*edge-of-word delimiter*/
+ else{@+cur_chr=lc_code(cur_chr);
+ if (cur_chr==0)
+ {@+print_err("Nonletter");
+@.Nonletter@>
+ help1("(See Appendix H.)");error();
+ }
+ }
+ if (k < 63)
+ {@+incr(k);hc[k]=cur_chr;hyf[k]=0;digit_sensed=false;
+ }
+ }
+else if (k < 63)
+ {@+hyf[k]=cur_chr-'0';digit_sensed=true;
+ }
+
+@ When the following code comes into play, the pattern $p_1\ldots p_k$
+appears in |hc[1 dotdot k]|, and the corresponding sequence of numbers $n_0\ldots
+n_k$ appears in |hyf[0 dotdot k]|.
+
+@<Insert a new pattern into the linked trie@>=
+{@+@<Compute the trie op code, |v|, and set |l:=0|@>;
+q=0;hc[0]=cur_lang;
+while (l <= k)
+ {@+c=hc[l];incr(l);p=trie_l[q];first_child=true;
+ while ((p > 0)&&(c > so(trie_c[p])))
+ {@+q=p;p=trie_r[q];first_child=false;
+ }
+ if ((p==0)||(c < so(trie_c[p])))
+ @<Insert a new trie node between |q| and |p|, and make |p| point to it@>;
+ q=p; /*now node |q| represents $p_1\ldots p_{l-1}$*/
+ }
+if (trie_o[q]!=min_quarterword)
+ {@+print_err("Duplicate pattern");
+@.Duplicate pattern@>
+ help1("(See Appendix H.)");error();
+ }
+trie_o[q]=v;
+}
+
+@ @<Insert a new trie node between |q| and |p|...@>=
+{@+if (trie_ptr==trie_size) overflow("pattern memory", trie_size);
+@:TeX capacity exceeded pattern memory}{\quad pattern memory@>
+incr(trie_ptr);trie_r[trie_ptr]=p;p=trie_ptr;trie_l[p]=0;
+if (first_child) trie_l[q]=p;@+else trie_r[q]=p;
+trie_c[p]=si(c);trie_o[p]=min_quarterword;
+}
+
+@ @<Compute the trie op code, |v|...@>=
+if (hc[1]==0) hyf[0]=0;
+if (hc[k]==0) hyf[k]=0;
+l=k;v=min_quarterword;
+loop@+{@+if (hyf[l]!=0) v=new_trie_op(k-l, hyf[l], v);
+ if (l > 0) decr(l);@+else goto done1;
+ }
+done1:
+
+@ Finally we put everything together: Here is how the trie gets to its
+final, efficient form.
+The following packing routine is rigged so that the root of the linked
+tree gets mapped into location 1 of |trie|, as required by the hyphenation
+algorithm. This happens because the first call of |first_fit| will
+``take'' location~1.
+
+@<Declare procedures for preprocessing hyphenation patterns@>=
+void init_trie(void)
+{@+trie_pointer @!p; /*pointer for initialization*/
+int @!j, @!k, @!t; /*all-purpose registers for initialization*/
+trie_pointer @!r, @!s; /*used to clean up the packed |trie|*/
+two_halves @!h; /*template used to zero out |trie|'s holes*/
+@<Get ready to compress the trie@>;
+if (trie_root!=0)
+ {@+first_fit(trie_root);trie_pack(trie_root);
+ }
+@<Move the data into |trie|@>;
+trie_not_ready=false;
+}
+
+@* Breaking vertical lists into pages.
+The |vsplit| procedure, which implements \TeX's \.{\\vsplit} operation,
+is considerably simpler than |line_break| because it doesn't have to
+worry about hyphenation, and because its mission is to discover a single
+break instead of an optimum sequence of breakpoints. But before we get
+into the details of |vsplit|, we need to consider a few more basic things.
+
+@ A subroutine called |prune_page_top| takes a pointer to a vlist and
+returns a pointer to a modified vlist in which all glue, kern, and penalty nodes
+have been deleted before the first box or rule node. However, the first
+box or rule is actually preceded by a newly created glue node designed so that
+the topmost baseline will be at distance |split_top_skip| from the top,
+whenever this is possible without backspacing.
+
+In this routine and those that follow, we make use of the fact that a
+vertical list contains no character nodes, hence the |type| field exists
+for each node in the list.
+@^data structure assumptions@>
+
+@p pointer prune_page_top(pointer @!p) /*adjust top after page break*/
+{@+pointer prev_p; /*lags one step behind |p|*/
+pointer @!q; /*temporary variable for list manipulation*/
+prev_p=temp_head;link(temp_head)=p;
+while (p!=null)
+ switch (type(p)) {
+ case hlist_node: case vlist_node: case rule_node: @<Insert glue for |split_top_skip|
+and set~|p:=null|@>@;@+break;
+ case whatsit_node: case mark_node: case ins_node: {@+prev_p=p;p=link(prev_p);
+ } @+break;
+ case glue_node: case kern_node: case penalty_node: {@+q=p;p=link(q);link(q)=null;
+ link(prev_p)=p;flush_node_list(q);
+ } @+break;
+ default:confusion(@[@<|"pruning"|@>@]);
+@:this can't happen pruning}{\quad pruning@>
+ }
+return link(temp_head);
+}
+
+@ @<Insert glue for |split_top_skip|...@>=
+{@+q=new_skip_param(split_top_skip_code);link(prev_p)=q;link(q)=p;
+ /*now |temp_ptr==glue_ptr(q)|*/
+if (width(temp_ptr) > height(p)) width(temp_ptr)=width(temp_ptr)-height(p);
+else width(temp_ptr)=0;
+p=null;
+}
+
+@ The next subroutine finds the best place to break a given vertical list
+so as to obtain a box of height~|h|, with maximum depth~|d|.
+A pointer to the beginning of the vertical list is given,
+and a pointer to the optimum breakpoint is returned. The list is effectively
+followed by a forced break, i.e., a penalty node with the |eject_penalty|;
+if the best break occurs at this artificial node, the value |null| is returned.
+
+An array of six |scaled| distances is used to keep track of the height
+from the beginning of the list to the current place, just as in |line_break|.
+In fact, we use one of the same arrays, only changing its name to reflect
+its new significance.
+
+@d active_height active_width /*new name for the six distance variables*/
+@d cur_height active_height[1] /*the natural height*/
+@d set_height_zero(X) active_height[X]=0 /*initialize the height to zero*/
+@#
+@p pointer vert_break(pointer @!p, scaled @!h, scaled @!d)
+ /*finds optimum page break*/
+{@+
+pointer prev_p; /*if |p| is a glue node, |type(prev_p)| determines
+ whether |p| is a legal breakpoint*/
+pointer @!q, @!r; /*glue specifications*/
+int @!pi; /*penalty value*/
+int @!b; /*badness at a trial breakpoint*/
+int @!least_cost; /*the smallest badness plus penalties found so far*/
+pointer @!best_place; /*the most recent break that leads to |least_cost|*/
+scaled @!prev_dp; /*depth of previous box in the list*/
+small_number @!t; /*|type| of the node following a kern*/
+prev_p=p; /*an initial glue node is not a legal breakpoint*/
+least_cost=awful_bad;do_all_six(set_height_zero);prev_dp=0;
+loop@+{@+@<If node |p| is a legal breakpoint, check if this break is the best known,
+and |goto done| if |p| is null or if the page-so-far is already too full to accept
+more stuff@>;
+ prev_p=p;p=link(prev_p);
+ }
+done: return best_place;
+}
+
+@ A global variable |best_height_plus_depth| will be set to the natural size
+of the box that corresponds to the optimum breakpoint found by |vert_break|.
+(This value is used by the insertion-splitting algorithm of the page builder.)
+
+@<Glob...@>=
+scaled @!best_height_plus_depth; /*height of the best box, without stretching or
+ shrinking*/
+
+@ A subtle point to be noted here is that the maximum depth~|d| might be
+negative, so |cur_height| and |prev_dp| might need to be corrected even
+after a glue or kern node.
+
+@<If node |p| is a legal breakpoint, check...@>=
+if (p==null) pi=eject_penalty;
+else@<Use node |p| to update the current height and depth measurements; if this node
+is not a legal breakpoint, |goto not_found| or |update_heights|, otherwise set |pi|
+to the associated penalty at the break@>;
+@<Check if node |p| is a new champion breakpoint; then \(go)|goto done| if |p| is
+a forced break or if the page-so-far is already too full@>;
+if ((type(p) < glue_node)||(type(p) > kern_node)) goto not_found;
+update_heights: @<Update the current height and depth measurements with respect to
+a glue or kern node~|p|@>;
+not_found: if (prev_dp > d)
+ {@+cur_height=cur_height+prev_dp-d;
+ prev_dp=d;
+ }
+
+@ @<Use node |p| to update the current height and depth measurements...@>=
+switch (type(p)) {
+case hlist_node: case vlist_node: case rule_node: {@+@t@>@;@/
+ cur_height=cur_height+prev_dp+height(p);prev_dp=depth(p);
+ goto not_found;
+ }
+case whatsit_node: @<Process whatsit |p| in |vert_break| loop, |goto not_found|@>;
+case glue_node: if (precedes_break(prev_p)) pi=0;
+ else goto update_heights;@+break;
+case kern_node: {@+if (link(p)==null) t=penalty_node;
+ else t=type(link(p));
+ if (t==glue_node) pi=0;@+else goto update_heights;
+ } @+break;
+case penalty_node: pi=penalty(p);@+break;
+case mark_node: case ins_node: goto not_found;
+default:confusion(@[@<|"vertbreak"|@>@]);
+@:this can't happen vertbreak}{\quad vertbreak@>
+}
+
+@ @d deplorable 100000 /*more than |inf_bad|, but less than |awful_bad|*/
+
+@<Check if node |p| is a new champion breakpoint; then \(go)...@>=
+if (pi < inf_penalty)
+ {@+@<Compute the badness, |b|, using |awful_bad| if the box is too full@>;
+ if (b < awful_bad)
+ if (pi <= eject_penalty) b=pi;
+ else if (b < inf_bad) b=b+pi;
+ else b=deplorable;
+ if (b <= least_cost)
+ {@+best_place=p;least_cost=b;
+ best_height_plus_depth=cur_height+prev_dp;
+ }
+ if ((b==awful_bad)||(pi <= eject_penalty)) goto done;
+ }
+
+@ @<Compute the badness, |b|, using |awful_bad| if the box is too full@>=
+if (cur_height < h)
+ if ((active_height[3]!=0)||(active_height[4]!=0)||
+ (active_height[5]!=0)) b=0;
+ else b=badness(h-cur_height, active_height[2]);
+else if (cur_height-h > active_height[6]) b=awful_bad;
+else b=badness(cur_height-h, active_height[6])
+
+@ Vertical lists that are subject to the |vert_break| procedure should not
+contain infinite shrinkability, since that would permit any amount of
+information to ``fit'' on one page.
+
+@<Update the current height and depth measurements with...@>=
+if (type(p)==kern_node) q=p;
+else{@+q=glue_ptr(p);
+ active_height[2+stretch_order(q)]=@|
+ active_height[2+stretch_order(q)]+stretch(q);@/
+ active_height[6]=active_height[6]+shrink(q);
+ if ((shrink_order(q)!=normal)&&(shrink(q)!=0))
+ {@+@t@>@;@/
+ print_err("Infinite glue shrinkage found in box being split");@/
+@.Infinite glue shrinkage...@>
+ help4("The box you are \\vsplitting contains some infinitely")@/
+ ("shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.")@/
+ ("Such glue doesn't belong there; but you can safely proceed,")@/
+ ("since the offensive shrinkability has been made finite.");
+ error();r=new_spec(q);shrink_order(r)=normal;delete_glue_ref(q);
+ glue_ptr(p)=r;q=r;
+ }
+ }
+cur_height=cur_height+prev_dp+width(q);prev_dp=0
+
+@ Now we are ready to consider |vsplit| itself. Most of
+its work is accomplished by the two subroutines that we have just considered.
+
+Given the number of a vlist box |n|, and given a desired page height |h|,
+the |vsplit| function finds the best initial segment of the vlist and
+returns a box for a page of height~|h|. The remainder of the vlist, if
+any, replaces the original box, after removing glue and penalties and
+adjusting for |split_top_skip|. Mark nodes in the split-off box are used to
+set the values of |split_first_mark| and |split_bot_mark|; we use the
+fact that |split_first_mark==null| if and only if |split_bot_mark==null|.
+
+The original box becomes ``void'' if and only if it has been entirely
+extracted. The extracted box is ``void'' if and only if the original
+box was void (or if it was, erroneously, an hlist box).
+
+@p pointer vsplit(eight_bits @!n, scaled @!h)
+ /*extracts a page of height |h| from box |n|*/
+{@+
+pointer v; /*the box to be split*/
+pointer p; /*runs through the vlist*/
+pointer q; /*points to where the break occurs*/
+v=box(n);
+if (split_first_mark!=null)
+ {@+delete_token_ref(split_first_mark);split_first_mark=null;
+ delete_token_ref(split_bot_mark);split_bot_mark=null;
+ }
+@<Dispense with trivial cases of void or bad boxes@>;
+q=vert_break(list_ptr(v), h, split_max_depth);
+@<Look at all the marks in nodes before the break, and set the final link to |null|
+at the break@>;
+q=prune_page_top(q);p=list_ptr(v);free_node(v, box_node_size);
+if (q==null) box(n)=null; /*the |eq_level| of the box stays the same*/
+else box(n)=vpack(q, natural);
+return vpackage(p, h, exactly, split_max_depth);
+}
+
+@ @<Dispense with trivial cases of void or bad boxes@>=
+if (v==null)
+ {@+return null;
+ }
+if (type(v)!=vlist_node)
+ {@+print_err("");print_esc(@[@<|"vsplit"|@>@]);print_str(" needs a ");
+ print_esc(@[@<|"vbox"|@>@]);
+@:vsplit_}{\.{\\vsplit needs a \\vbox}@>
+ help2("The box you are trying to split is an \\hbox.")@/
+ ("I can't split such a box, so I'll leave it alone.");
+ error();return null;
+ }
+
+@ It's possible that the box begins with a penalty node that is the
+``best'' break, so we must be careful to handle this special case correctly.
+
+@<Look at all the marks...@>=
+p=list_ptr(v);
+if (p==q) list_ptr(v)=null;
+else loop@+{@+if (type(p)==mark_node)
+ if (split_first_mark==null)
+ {@+split_first_mark=mark_ptr(p);
+ split_bot_mark=split_first_mark;
+ token_ref_count(split_first_mark)=@|
+ token_ref_count(split_first_mark)+2;
+ }
+ else{@+delete_token_ref(split_bot_mark);
+ split_bot_mark=mark_ptr(p);
+ add_token_ref(split_bot_mark);
+ }
+ if (link(p)==q)
+ {@+link(p)=null;goto done;
+ }
+ p=link(p);
+ }
+done:
+
+@* The page builder.
+When \TeX\ appends new material to its main vlist in vertical mode, it uses
+a method something like |vsplit| to decide where a page ends, except that
+the calculations are done ``on line'' as new items come in.
+The main complication in this process is that insertions must be put
+into their boxes and removed from the vlist, in a more-or-less optimum manner.
+
+We shall use the term ``current page'' for that part of the main vlist that
+is being considered as a candidate for being broken off and sent to the
+user's output routine. The current page starts at |link(page_head)|, and
+it ends at |page_tail|. We have |page_head==page_tail| if this list is empty.
+@^current page@>
+
+Utter chaos would reign if the user kept changing page specifications
+while a page is being constructed, so the page builder keeps the pertinent
+specifications frozen as soon as the page receives its first box or
+insertion. The global variable |page_contents| is |empty| when the
+current page contains only mark nodes and content-less whatsit nodes; it
+is |inserts_only| if the page contains only insertion nodes in addition to
+marks and whatsits. Glue nodes, kern nodes, and penalty nodes are
+discarded until a box or rule node appears, at which time |page_contents|
+changes to |box_there|. As soon as |page_contents| becomes non-|empty|,
+the current |vsize| and |max_depth| are squirreled away into |page_goal|
+and |page_max_depth|; the latter values will be used until the page has
+been forwarded to the user's output routine. The \.{\\topskip} adjustment
+is made when |page_contents| changes to |box_there|.
+
+Although |page_goal| starts out equal to |vsize|, it is decreased by the
+scaled natural height-plus-depth of the insertions considered so far, and by
+the \.{\\skip} corrections for those insertions. Therefore it represents
+the size into which the non-inserted material should fit, assuming that
+all insertions in the current page have been made.
+
+The global variables |best_page_break| and |least_page_cost| correspond
+respectively to the local variables |best_place| and |least_cost| in the
+|vert_break| routine that we have already studied; i.e., they record the
+location and value of the best place currently known for breaking the
+current page. The value of |page_goal| at the time of the best break is
+stored in |best_size|.
+
+@d inserts_only 1
+ /*|page_contents| when an insert node has been contributed, but no boxes*/
+@d box_there 2 /*|page_contents| when a box or rule has been contributed*/
+
+@<Glob...@>=
+pointer @!page_tail; /*the final node on the current page*/
+uint8_t @!page_contents; /*what is on the current page so far?*/
+scaled @!page_max_depth; /*maximum box depth on page being built*/
+pointer @!best_page_break; /*break here to get the best page known so far*/
+int @!least_page_cost; /*the score for this currently best page*/
+scaled @!best_size; /*its |page_goal|*/
+
+@ The page builder has another data structure to keep track of insertions.
+This is a list of four-word nodes, starting and ending at |page_ins_head|.
+That is, the first element of the list is node |r@t$_1$@>==link(page_ins_head)|;
+node $r_j$ is followed by |r@t$_{j+1}$@>==link(r@t$_j$@>)|; and if there are
+|n| items we have |r@t$_{n+1}$@>==page_ins_head|. The |subtype| field of
+each node in this list refers to an insertion number; for example, `\.{\\insert
+250}' would correspond to a node whose |subtype| is |qi(250)|
+(the same as the |subtype| field of the relevant |ins_node|). These |subtype|
+fields are in increasing order, and |subtype(page_ins_head)==
+qi(255)|, so |page_ins_head| serves as a convenient sentinel
+at the end of the list. A record is present for each insertion number that
+appears in the current page.
+
+The |type| field in these nodes distinguishes two possibilities that
+might occur as we look ahead before deciding on the optimum page break.
+If |type(r)==inserting|, then |height(r)| contains the total of the
+height-plus-depth dimensions of the box and all its inserts seen so far.
+If |type(r)==split_up|, then no more insertions will be made into this box,
+because at least one previous insertion was too big to fit on the current
+page; |broken_ptr(r)| points to the node where that insertion will be
+split, if \TeX\ decides to split it, |broken_ins(r)| points to the
+insertion node that was tentatively split, and |height(r)| includes also the
+natural height plus depth of the part that would be split off.
+
+In both cases, |last_ins_ptr(r)| points to the last |ins_node|
+encountered for box |qo(subtype(r))| that would be at least partially
+inserted on the next page; and |best_ins_ptr(r)| points to the last
+such |ins_node| that should actually be inserted, to get the page with
+minimum badness among all page breaks considered so far. We have
+|best_ins_ptr(r)==null| if and only if no insertion for this box should
+be made to produce this optimum page.
+
+The data structure definitions here use the fact that the |@!height| field
+appears in the fourth word of a box node.
+@^data structure assumptions@>
+
+@d page_ins_node_size 4 /*number of words for a page insertion node*/
+@d inserting 0 /*an insertion class that has not yet overflowed*/
+@d split_up 1 /*an overflowed insertion class*/
+@d broken_ptr(X) link(X+1)
+ /*an insertion for this class will break here if anywhere*/
+@d broken_ins(X) info(X+1) /*this insertion might break at |broken_ptr|*/
+@d last_ins_ptr(X) link(X+2) /*the most recent insertion for this |subtype|*/
+@d best_ins_ptr(X) info(X+2) /*the optimum most recent insertion*/
+
+@<Initialize the special list heads...@>=
+subtype(page_ins_head)=qi(255);
+type(page_ins_head)=split_up;link(page_ins_head)=page_ins_head;
+
+@ An array |page_so_far| records the heights and depths of everything
+on the current page. This array contains six |scaled| numbers, like the
+similar arrays already considered in |line_break| and |vert_break|; and it
+also contains |page_goal| and |page_depth|, since these values are
+all accessible to the user via |set_page_dimen| commands. The
+value of |page_so_far[1]| is also called |page_total|. The stretch
+and shrink components of the \.{\\skip} corrections for each insertion are
+included in |page_so_far|, but the natural space components of these
+corrections are not, since they have been subtracted from |page_goal|.
+
+The variable |page_depth| records the depth of the current page; it has been
+adjusted so that it is at most |page_max_depth|. The variable
+|last_glue| points to the glue specification of the most recent node
+contributed from the contribution list, if this was a glue node; otherwise
+|last_glue==max_halfword|. (If the contribution list is nonempty,
+however, the value of |last_glue| is not necessarily accurate.)
+The variables |last_penalty| and |last_kern| are similar. And
+finally, |insert_penalties| holds the sum of the penalties associated with
+all split and floating insertions.
+
+@d page_goal page_so_far[0] /*desired height of information on page being built*/
+@d page_total page_so_far[1] /*height of the current page*/
+@d page_shrink page_so_far[6] /*shrinkability of the current page*/
+@d page_depth page_so_far[7] /*depth of the current page*/
+
+@<Glob...@>=
+scaled @!page_so_far[8]; /*height and glue of the current page*/
+pointer @!last_glue; /*used to implement \.{\\lastskip}*/
+int @!last_penalty; /*used to implement \.{\\lastpenalty}*/
+scaled @!last_kern; /*used to implement \.{\\lastkern}*/
+int @!insert_penalties; /*sum of the penalties for held-over insertions*/
+
+@ @<Put each...@>=
+primitive(@[@<|"pagegoal"|@>@], set_page_dimen, 0);
+@!@:page_goal_}{\.{\\pagegoal} primitive@>
+primitive(@[@<|"pagetotal"|@>@], set_page_dimen, 1);
+@!@:page_total_}{\.{\\pagetotal} primitive@>
+primitive(@[@<|"pagestretch"|@>@], set_page_dimen, 2);
+@!@:page_stretch_}{\.{\\pagestretch} primitive@>
+primitive(@[@<|"pagefilstretch"|@>@], set_page_dimen, 3);
+@!@:page_fil_stretch_}{\.{\\pagefilstretch} primitive@>
+primitive(@[@<|"pagefillstretch"|@>@], set_page_dimen, 4);
+@!@:page_fill_stretch_}{\.{\\pagefillstretch} primitive@>
+primitive(@[@<|"pagefilllstretch"|@>@], set_page_dimen, 5);
+@!@:page_filll_stretch_}{\.{\\pagefilllstretch} primitive@>
+primitive(@[@<|"pageshrink"|@>@], set_page_dimen, 6);
+@!@:page_shrink_}{\.{\\pageshrink} primitive@>
+primitive(@[@<|"pagedepth"|@>@], set_page_dimen, 7);
+@!@:page_depth_}{\.{\\pagedepth} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case set_page_dimen: switch (chr_code) {
+case 0: print_esc(@[@<|"pagegoal"|@>@]);@+break;
+case 1: print_esc(@[@<|"pagetotal"|@>@]);@+break;
+case 2: print_esc(@[@<|"pagestretch"|@>@]);@+break;
+case 3: print_esc(@[@<|"pagefilstretch"|@>@]);@+break;
+case 4: print_esc(@[@<|"pagefillstretch"|@>@]);@+break;
+case 5: print_esc(@[@<|"pagefilllstretch"|@>@]);@+break;
+case 6: print_esc(@[@<|"pageshrink"|@>@]);@+break;
+default:print_esc(@[@<|"pagedepth"|@>@]);
+} @+break;
+
+@ @d print_plus_end(X) print_str(X);@+}
+@d print_plus(X) if (page_so_far[X]!=0)
+ {@+print_str(" plus ");print_scaled(page_so_far[X]);print_plus_end
+
+@p void print_totals(void)
+{@+print_scaled(page_total);
+print_plus(2)("");
+print_plus(3)("fil");
+print_plus(4)("fill");
+print_plus(5)("filll");
+if (page_shrink!=0)
+ {@+print_str(" minus ");print_scaled(page_shrink);
+ }
+}
+
+@ @<Show the status of the current page@>=
+if (page_head!=page_tail)
+ {@+print_nl("### current page:");
+ if (output_active) print_str(" (held over for next output)");
+@.held over for next output@>
+ show_box(link(page_head));
+ if (page_contents > empty)
+ {@+print_nl("total height ");print_totals();
+@:total_height}{\.{total height}@>
+ print_nl(" goal height ");print_scaled(page_goal);
+@.goal height@>
+ r=link(page_ins_head);
+ while (r!=page_ins_head)
+ {@+print_ln();print_esc(@[@<|"insert"|@>@]);t=qo(subtype(r));
+ print_int(t);print_str(" adds ");
+ if (count(t)==1000) t=height(r);
+ else t=x_over_n(height(r), 1000)*count(t);
+ print_scaled(t);
+ if (type(r)==split_up)
+ {@+q=page_head;t=0;
+ @/do@+{q=link(q);
+ if ((type(q)==ins_node)&&(subtype(q)==subtype(r))) incr(t);
+ }@+ while (!(q==broken_ins(r)));
+ print_str(", #");print_int(t);print_str(" might split");
+ }
+ r=link(r);
+ }
+ }
+ }
+
+@ Here is a procedure that is called when the |page_contents| is changing
+from |empty| to |inserts_only| or |box_there|.
+
+@d set_page_so_far_zero(X) page_so_far[X]=0
+
+@p void freeze_page_specs(small_number @!s)
+{@+page_contents=s;
+page_goal=vsize;page_max_depth=max_depth;
+page_depth=0;do_all_six(set_page_so_far_zero);
+least_page_cost=awful_bad;
+#ifdef @!STAT
+if (tracing_pages > 0)
+ {@+begin_diagnostic();
+ print_nl("%% goal height=");print_scaled(page_goal);
+@.goal height@>
+ print_str(", max depth=");print_scaled(page_max_depth);
+ end_diagnostic(false);
+ } @;
+#endif
+@;@/
+}
+
+@ Pages are built by appending nodes to the current list in \TeX's
+vertical mode, which is at the outermost level of the semantic nest. This
+vlist is split into two parts; the ``current page'' that we have been
+talking so much about already, and the ``contribution list'' that receives
+new nodes as they are created. The current page contains everything that
+the page builder has accounted for in its data structures, as described
+above, while the contribution list contains other things that have been
+generated by other parts of \TeX\ but have not yet been
+seen by the page builder.
+The contribution list starts at |link(contrib_head)|, and it ends at the
+current node in \TeX's vertical mode.
+
+When \TeX\ has appended new material in vertical mode, it calls the procedure
+|build_page|, which tries to catch up by moving nodes from the contribution
+list to the current page. This procedure will succeed in its goal of
+emptying the contribution list, unless a page break is discovered, i.e.,
+unless the current page has grown to the point where the optimum next
+page break has been determined. In the latter case, the nodes after the
+optimum break will go back onto the contribution list, and control will
+effectively pass to the user's output routine.
+
+We make |type(page_head)==glue_node|, so that an initial glue node on
+the current page will not be considered a valid breakpoint.
+
+@<Initialize the special list...@>=
+type(page_head)=glue_node;subtype(page_head)=normal;
+
+@ The global variable |output_active| is true during the time the
+user's output routine is driving \TeX.
+
+@<Glob...@>=
+bool @!output_active; /*are we in the midst of an output routine?*/
+
+@ @<Set init...@>=
+output_active=false;insert_penalties=0;
+
+@ The page builder is ready to start a fresh page if we initialize
+the following state variables. (However, the page insertion list is initialized
+elsewhere.)
+
+@<Start a new current page@>=
+page_contents=empty;page_tail=page_head;link(page_head)=null;@/
+last_glue=max_halfword;last_penalty=0;last_kern=0;
+page_depth=0;page_max_depth=0
+
+@ At certain times box 255 is supposed to be void (i.e., |null|),
+or an insertion box is supposed to be ready to accept a vertical list.
+If not, an error message is printed, and the following subroutine
+flushes the unwanted contents, reporting them to the user.
+
+@p void box_error(eight_bits @!n)
+{@+error();begin_diagnostic();
+print_nl("The following box has been deleted:");
+@.The following...deleted@>
+show_box(box(n));end_diagnostic(true);
+flush_node_list(box(n));box(n)=null;
+}
+
+@ The following procedure guarantees that a given box register
+does not contain an \.{\\hbox}.
+
+@p void ensure_vbox(eight_bits @!n)
+{@+pointer p; /*the box register contents*/
+p=box(n);
+if (p!=null) if (type(p)==hlist_node)
+ {@+print_err("Insertions can only be added to a vbox");
+@.Insertions can only...@>
+ help3("Tut tut: You're trying to \\insert into a")@/
+ ("\\box register that now contains an \\hbox.")@/
+ ("Proceed, and I'll discard its present contents.");
+ box_error(n);
+ }
+}
+
+@ \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.
+
+@p@t\4@>@<Declare the procedure called |fire_up|@>@;@/
+void build_page(void) /*append contributions to the current page*/
+{@+
+pointer p; /*the node being appended*/
+pointer @!q, @!r; /*nodes being examined*/
+int @!b, @!c; /*badness and cost of current page*/
+int @!pi; /*penalty to be added to the badness*/
+uint8_t @!n; /*insertion box number*/
+scaled @!delta, @!h, @!w; /*sizes used for insertion calculations*/
+if ((link(contrib_head)==null)||output_active) return;
+@/do@+{resume: p=link(contrib_head);@/
+@<Update the values of |last_glue|, |last_penalty|, and |last_kern|@>;
+@<Move node |p| to the current page; if it is time for a page break, put the nodes
+following the break back onto the contribution list, and |return| to the user's output
+routine if there is one@>;
+}@+ while (!(link(contrib_head)==null));
+@<Make the contribution list empty by setting its tail to |contrib_head|@>;
+}
+
+@ @d contrib_tail nest[0].tail_field /*tail of the contribution list*/
+
+@<Make the contribution list empty...@>=
+if (nest_ptr==0) tail=contrib_head; /*vertical mode*/
+else contrib_tail=contrib_head /*other modes*/
+
+@ @<Update the values of |last_glue|...@>=
+if (last_glue!=max_halfword) delete_glue_ref(last_glue);
+last_penalty=0;last_kern=0;
+if (type(p)==glue_node)
+ {@+last_glue=glue_ptr(p);add_glue_ref(last_glue);
+ }
+else{@+last_glue=max_halfword;
+ if (type(p)==penalty_node) last_penalty=penalty(p);
+ else if (type(p)==kern_node) last_kern=width(p);
+ }
+
+@ The code here is an example of a many-way switch into routines that
+merge together in different places. Some people call this unstructured
+programming, but the author doesn't see much wrong with it, as long as
+@^Knuth, Donald Ervin@>
+the various labels have a well-understood meaning.
+
+@<Move node |p| to the current page;...@>=
+@<If the current page is empty and node |p| is to be deleted, |goto done1|; otherwise
+use node |p| to update the state of the current page; if this node is an insertion,
+|goto contribute|; otherwise if this node is not a legal breakpoint, |goto contribute|
+or |update_heights|; otherwise set |pi| to the penalty associated with this breakpoint@>;
+@<Check if node |p| is a new champion breakpoint; then \(if)if it is time for a page
+break, prepare for output, and either fire up the user's output routine and |return|
+or ship out the page and |goto done|@>;
+if ((type(p) < glue_node)||(type(p) > kern_node)) goto contribute;
+update_heights: @<Update the current page measurements with respect to the glue or
+kern specified by node~|p|@>;
+contribute: @<Make sure that |page_max_depth| is not exceeded@>;
+@<Link node |p| into the current page and |goto done|@>;
+done1: @<Recycle node |p|@>;
+done:
+
+@ @<Link node |p| into the current page and |goto done|@>=
+link(page_tail)=p;page_tail=p;
+link(contrib_head)=link(p);link(p)=null;goto done
+
+@ @<Recycle node |p|@>=
+link(contrib_head)=link(p);link(p)=null;flush_node_list(p)
+
+@ The title of this section is already so long, it seems best to avoid
+making it more accurate but still longer, by mentioning the fact that a
+kern node at the end of the contribution list will not be contributed until
+we know its successor.
+
+@<If the current page is empty...@>=
+switch (type(p)) {
+case hlist_node: case vlist_node: case rule_node: if (page_contents < box_there)
+ @<Initialize the current page, insert the \.{\\topskip} glue ahead of |p|, and
+|goto continue|@>@;
+ else@<Prepare to move a box or rule node to the current page, then |goto contribute|@>@;@+break;
+case whatsit_node: @<Prepare to move whatsit |p| to the current page, then |goto contribute|@>;
+case glue_node: if (page_contents < box_there) goto done1;
+ else if (precedes_break(page_tail)) pi=0;
+ else goto update_heights;@+break;
+case kern_node: if (page_contents < box_there) goto done1;
+ else if (link(p)==null) return;
+ else if (type(link(p))==glue_node) pi=0;
+ else goto update_heights;@+break;
+case penalty_node: if (page_contents < box_there) goto done1;@+else pi=penalty(p);@+break;
+case mark_node: goto contribute;
+case ins_node: @<Append an insertion to the current page and |goto contribute|@>@;
+default:confusion(@[@<|"page"|@>@]);
+@:this can't happen page}{\quad page@>
+}
+
+@ @<Initialize the current page, insert the \.{\\topskip} glue...@>=
+{@+if (page_contents==empty) freeze_page_specs(box_there);
+else page_contents=box_there;
+q=new_skip_param(top_skip_code); /*now |temp_ptr==glue_ptr(q)|*/
+if (width(temp_ptr) > height(p)) width(temp_ptr)=width(temp_ptr)-height(p);
+else width(temp_ptr)=0;
+link(q)=p;link(contrib_head)=q;goto resume;
+}
+
+@ @<Prepare to move a box or rule node to the current page...@>=
+{@+page_total=page_total+page_depth+height(p);
+page_depth=depth(p);
+goto contribute;
+}
+
+@ @<Make sure that |page_max_depth| is not exceeded@>=
+if (page_depth > page_max_depth)
+ {@+page_total=@|
+ page_total+page_depth-page_max_depth;@/
+ page_depth=page_max_depth;
+ }
+
+@ @<Update the current page measurements with respect to the glue...@>=
+if (type(p)==kern_node) q=p;
+else{@+q=glue_ptr(p);
+ page_so_far[2+stretch_order(q)]=@|
+ page_so_far[2+stretch_order(q)]+stretch(q);@/
+ page_shrink=page_shrink+shrink(q);
+ if ((shrink_order(q)!=normal)&&(shrink(q)!=0))
+ {@+@t@>@;@/
+ print_err("Infinite glue shrinkage found on current page");@/
+@.Infinite glue shrinkage...@>
+ help4("The page about to be output contains some infinitely")@/
+ ("shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.")@/
+ ("Such glue doesn't belong there; but you can safely proceed,")@/
+ ("since the offensive shrinkability has been made finite.");
+ error();
+ r=new_spec(q);shrink_order(r)=normal;delete_glue_ref(q);
+ glue_ptr(p)=r;q=r;
+ }
+ }
+page_total=page_total+page_depth+width(q);page_depth=0
+
+@ @<Check if node |p| is a new champion breakpoint; then \(if)...@>=
+if (pi < inf_penalty)
+ {@+@<Compute the badness, |b|, of the current page, using |awful_bad| if the box
+is too full@>;
+ if (b < awful_bad)
+ if (pi <= eject_penalty) c=pi;
+ else if (b < inf_bad) c=b+pi+insert_penalties;
+ else c=deplorable;
+ else c=b;
+ if (insert_penalties >= 10000) c=awful_bad;
+
+#ifdef @!STAT
+if (tracing_pages > 0) @<Display the page break cost@>;
+#endif
+@;@/
+ if (c <= least_page_cost)
+ {@+best_page_break=p;best_size=page_goal;
+ least_page_cost=c;
+ r=link(page_ins_head);
+ while (r!=page_ins_head)
+ {@+best_ins_ptr(r)=last_ins_ptr(r);
+ r=link(r);
+ }
+ }
+ if ((c==awful_bad)||(pi <= eject_penalty))
+ {@+fire_up(p); /*output the current page at the best place*/
+ if (output_active) return; /*user's output routine will act*/
+ goto done; /*the page has been shipped out by default output routine*/
+ }
+ }
+
+@ @<Display the page break cost@>=
+{@+begin_diagnostic();print_nl("%");
+print_str(" t=");print_totals();@/
+print_str(" g=");print_scaled(page_goal);@/
+print_str(" b=");
+if (b==awful_bad) print_char('*');@+else print_int(b);
+@.*\relax@>
+print_str(" p=");print_int(pi);
+print_str(" c=");
+if (c==awful_bad) print_char('*');@+else print_int(c);
+if (c <= least_page_cost) print_char('#');
+end_diagnostic(false);
+}
+
+@ @<Compute the badness, |b|, of the current page...@>=
+if (page_total < page_goal)
+ if ((page_so_far[3]!=0)||(page_so_far[4]!=0)||@|
+ (page_so_far[5]!=0)) b=0;
+ else b=badness(page_goal-page_total, page_so_far[2]);
+else if (page_total-page_goal > page_shrink) b=awful_bad;
+else b=badness(page_total-page_goal, page_shrink)
+
+@ @<Append an insertion to the current page and |goto contribute|@>=
+{@+if (page_contents==empty) freeze_page_specs(inserts_only);
+n=subtype(p);r=page_ins_head;
+while (n >= subtype(link(r))) r=link(r);
+n=qo(n);
+if (subtype(r)!=qi(n))
+ @<Create a page insertion node with |subtype(r)=qi(n)|, and include the glue correction
+for box |n| in the current page state@>;
+if (type(r)==split_up) insert_penalties=insert_penalties+float_cost(p);
+else{@+last_ins_ptr(r)=p;
+ delta=page_goal-page_total-page_depth+page_shrink;
+ /*this much room is left if we shrink the maximum*/
+ if (count(n)==1000) h=height(p);
+ else h=x_over_n(height(p), 1000)*count(n); /*this much room is needed*/
+ if (((h <= 0)||(h <= delta))&&(height(p)+height(r) <= dimen(n)))
+ {@+page_goal=page_goal-h;height(r)=height(r)+height(p);
+ }
+ else@<Find the best way to split the insertion, and change |type(r)| to |split_up|@>;
+ }
+goto contribute;
+}
+
+@ We take note of the value of \.{\\skip} |n| and the height plus depth
+of \.{\\box}~|n| only when the first \.{\\insert}~|n| node is
+encountered for a new page. A user who changes the contents of \.{\\box}~|n|
+after that first \.{\\insert}~|n| had better be either extremely careful
+or extremely lucky, or both.
+
+@<Create a page insertion node...@>=
+{@+q=get_node(page_ins_node_size);link(q)=link(r);link(r)=q;r=q;
+subtype(r)=qi(n);type(r)=inserting;ensure_vbox(n);
+if (box(n)==null) height(r)=0;
+else height(r)=height(box(n))+depth(box(n));
+best_ins_ptr(r)=null;@/
+q=skip(n);
+if (count(n)==1000) h=height(r);
+else h=x_over_n(height(r), 1000)*count(n);
+page_goal=page_goal-h-width(q);@/
+page_so_far[2+stretch_order(q)]=@|page_so_far[2+stretch_order(q)]+stretch(q);@/
+page_shrink=page_shrink+shrink(q);
+if ((shrink_order(q)!=normal)&&(shrink(q)!=0))
+ {@+print_err("Infinite glue shrinkage inserted from ");print_esc(@[@<|"skip"|@>@]);
+@.Infinite glue shrinkage...@>
+ print_int(n);
+ help3("The correction glue for page breaking with insertions")@/
+ ("must have finite shrinkability. But you may proceed,")@/
+ ("since the offensive shrinkability has been made finite.");
+ error();
+ }
+}
+
+@ Here is the code that will split a long footnote between pages, in an
+emergency. The current situation deserves to be recapitulated: Node |p|
+is an insertion into box |n|; the insertion will not fit, in its entirety,
+either because it would make the total contents of box |n| greater than
+\.{\\dimen} |n|, or because it would make the incremental amount of growth
+|h| greater than the available space |delta|, or both. (This amount |h| has
+been weighted by the insertion scaling factor, i.e., by \.{\\count} |n|
+over 1000.) Now we will choose the best way to break the vlist of the
+insertion, using the same criteria as in the \.{\\vsplit} operation.
+
+@<Find the best way to split the insertion...@>=
+{@+if (count(n) <= 0) w=max_dimen;
+else{@+w=page_goal-page_total-page_depth;
+ if (count(n)!=1000) w=x_over_n(w, count(n))*1000;
+ }
+if (w > dimen(n)-height(r)) w=dimen(n)-height(r);
+q=vert_break(ins_ptr(p), w, depth(p));
+height(r)=height(r)+best_height_plus_depth;
+#ifdef @!STAT
+if (tracing_pages > 0) @<Display the insertion split cost@>;
+#endif
+@;@/
+if (count(n)!=1000)
+ best_height_plus_depth=x_over_n(best_height_plus_depth, 1000)*count(n);
+page_goal=page_goal-best_height_plus_depth;
+type(r)=split_up;broken_ptr(r)=q;broken_ins(r)=p;
+if (q==null) insert_penalties=insert_penalties+eject_penalty;
+else if (type(q)==penalty_node) insert_penalties=insert_penalties+penalty(q);
+}
+
+@ @<Display the insertion split cost@>=
+{@+begin_diagnostic();print_nl("% split");print_int(n);
+@.split@>
+print_str(" to ");print_scaled(w);
+print_char(',');print_scaled(best_height_plus_depth);@/
+print_str(" p=");
+if (q==null) print_int(eject_penalty);
+else if (type(q)==penalty_node) print_int(penalty(q));
+else print_char('0');
+end_diagnostic(false);
+}
+
+@ When the page builder has looked at as much material as could appear before
+the next page break, it makes its decision. The break that gave minimum
+badness will be used to put a completed ``page'' into box 255, with insertions
+appended to their other boxes.
+
+We also set the values of |top_mark|, |first_mark|, and |bot_mark|. The
+program uses the fact that |bot_mark!=null| implies |first_mark!=null|;
+it also knows that |bot_mark==null| implies |top_mark==first_mark==null|.
+
+The |fire_up| subroutine prepares to output the current page at the best
+place; then it fires up the user's output routine, if there is one,
+or it simply ships out the page. There is one parameter, |c|, which represents
+the node that was being contributed to the page when the decision to
+force an output was made.
+
+@<Declare the procedure called |fire_up|@>=
+void fire_up(pointer @!c)
+{@+
+pointer p, @!q, @!r, @!s; /*nodes being examined and/or changed*/
+pointer @!prev_p; /*predecessor of |p|*/
+uint8_t @!n; /*insertion box number*/
+bool @!wait; /*should the present insertion be held over?*/
+int @!save_vbadness; /*saved value of |vbadness|*/
+scaled @!save_vfuzz; /*saved value of |vfuzz|*/
+pointer @!save_split_top_skip; /*saved value of |split_top_skip|*/
+@<Set the value of |output_penalty|@>;
+if (bot_mark!=null)
+ {@+if (top_mark!=null) delete_token_ref(top_mark);
+ top_mark=bot_mark;add_token_ref(top_mark);
+ delete_token_ref(first_mark);first_mark=null;
+ }
+@<Put the \(o)optimal current page into box 255, update |first_mark| and |bot_mark|,
+append insertions to their boxes, and put the remaining nodes back on the contribution
+list@>;
+if ((top_mark!=null)&&(first_mark==null))
+ {@+first_mark=top_mark;add_token_ref(top_mark);
+ }
+if (output_routine!=null)
+ if (dead_cycles >= max_dead_cycles)
+ @<Explain that too many dead cycles have occurred in a row@>@;
+ else@<Fire up the user's output routine and |return|@>;
+@<Perform the default output routine@>;
+}
+
+@ @<Set the value of |output_penalty|@>=
+if (type(best_page_break)==penalty_node)
+ {@+geq_word_define(int_base+output_penalty_code, penalty(best_page_break));
+ penalty(best_page_break)=inf_penalty;
+ }
+else geq_word_define(int_base+output_penalty_code, inf_penalty)
+
+@ As the page is finally being prepared for output,
+pointer |p| runs through the vlist, with |prev_p| trailing behind;
+pointer |q| is the tail of a list of insertions that
+are being held over for a subsequent page.
+
+@<Put the \(o)optimal current page into box 255...@>=
+if (c==best_page_break) best_page_break=null; /*|c| not yet linked in*/
+@<Ensure that box 255 is empty before output@>;
+insert_penalties=0; /*this will count the number of insertions held over*/
+save_split_top_skip=split_top_skip;
+if (holding_inserts <= 0)
+ @<Prepare all the boxes involved in insertions to act as queues@>;
+q=hold_head;link(q)=null;prev_p=page_head;p=link(prev_p);
+while (p!=best_page_break)
+ {@+if (type(p)==ins_node)
+ {@+if (holding_inserts <= 0)
+ @<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@>;
+ }
+ else if (type(p)==mark_node) @<Update the values of |first_mark| and |bot_mark|@>;
+ prev_p=p;p=link(prev_p);
+ }
+split_top_skip=save_split_top_skip;
+@<Break the current page at node |p|, put it in box~255, and put the remaining nodes
+on the contribution list@>;
+@<Delete \(t)the page-insertion nodes@>@;
+
+@ @<Ensure that box 255 is empty before output@>=
+if (box(255)!=null)
+ {@+print_err("");print_esc(@[@<|"box"|@>@]);print_str("255 is not void");
+@:box255}{\.{\\box255 is not void}@>
+ help2("You shouldn't use \\box255 except in \\output routines.")@/
+ ("Proceed, and I'll discard its present contents.");
+ box_error(255);
+ }
+
+@ @<Update the values of |first_mark| and |bot_mark|@>=
+{@+if (first_mark==null)
+ {@+first_mark=mark_ptr(p);
+ add_token_ref(first_mark);
+ }
+if (bot_mark!=null) delete_token_ref(bot_mark);
+bot_mark=mark_ptr(p);add_token_ref(bot_mark);
+}
+
+@ When the following code is executed, the current page runs from node
+|link(page_head)| to node |prev_p|, and the nodes from |p| to |page_tail|
+are to be placed back at the front of the contribution list. Furthermore
+the heldover insertions appear in a list from |link(hold_head)| to |q|; we
+will put them into the current page list for safekeeping while the user's
+output routine is active. We might have |q==hold_head|; and |p==null| if
+and only if |prev_p==page_tail|. Error messages are suppressed within
+|vpackage|, since the box might appear to be overfull or underfull simply
+because the stretch and shrink from the \.{\\skip} registers for inserts
+are not actually present in the box.
+
+@<Break the current page at node |p|, put it...@>=
+if (p!=null)
+ {@+if (link(contrib_head)==null)
+ if (nest_ptr==0) tail=page_tail;
+ else contrib_tail=page_tail;
+ link(page_tail)=link(contrib_head);
+ link(contrib_head)=p;
+ link(prev_p)=null;
+ }
+save_vbadness=vbadness;vbadness=inf_bad;
+save_vfuzz=vfuzz;vfuzz=max_dimen; /*inhibit error messages*/
+box(255)=vpackage(link(page_head), best_size, exactly, page_max_depth);
+vbadness=save_vbadness;vfuzz=save_vfuzz;
+if (last_glue!=max_halfword) delete_glue_ref(last_glue);
+@<Start a new current page@>; /*this sets |last_glue=max_halfword|*/
+if (q!=hold_head)
+ {@+link(page_head)=link(hold_head);page_tail=q;
+ }
+
+@ If many insertions are supposed to go into the same box, we want to know
+the position of the last node in that box, so that we don't need to waste time
+when linking further information into it. The |last_ins_ptr| fields of the
+page insertion nodes are therefore used for this purpose during the
+packaging phase.
+
+@<Prepare all the boxes involved in insertions to act as queues@>=
+{@+r=link(page_ins_head);
+while (r!=page_ins_head)
+ {@+if (best_ins_ptr(r)!=null)
+ {@+n=qo(subtype(r));ensure_vbox(n);
+ if (box(n)==null) box(n)=new_null_box();
+ p=box(n)+list_offset;
+ while (link(p)!=null) p=link(p);
+ last_ins_ptr(r)=p;
+ }
+ r=link(r);
+ }
+}
+
+@ @<Delete \(t)the page-insertion nodes@>=
+r=link(page_ins_head);
+while (r!=page_ins_head)
+ {@+q=link(r);free_node(r, page_ins_node_size);r=q;
+ }
+link(page_ins_head)=page_ins_head
+
+@ We will set |best_ins_ptr=null| and package the box corresponding to
+insertion node~|r|, just after making the final insertion into that box.
+If this final insertion is `|split_up|', the remainder after splitting
+and pruning (if any) will be carried over to the next page.
+
+@<Either insert the material specified by node |p| into...@>=
+{@+r=link(page_ins_head);
+while (subtype(r)!=subtype(p)) r=link(r);
+if (best_ins_ptr(r)==null) wait=true;
+else{@+wait=false;s=last_ins_ptr(r);link(s)=ins_ptr(p);
+ if (best_ins_ptr(r)==p)
+ @<Wrap up the box specified by node |r|, splitting node |p| if called for; set
+|wait:=true| if node |p| holds a remainder after splitting@>@;
+ else{@+while (link(s)!=null) s=link(s);
+ last_ins_ptr(r)=s;
+ }
+ }
+@<Either append the insertion node |p| after node |q|, and remove it from the current
+page, or delete |node(p)|@>;
+}
+
+@ @<Wrap up the box specified by node |r|, splitting node |p| if...@>=
+{@+if (type(r)==split_up)
+ if ((broken_ins(r)==p)&&(broken_ptr(r)!=null))
+ {@+while (link(s)!=broken_ptr(r)) s=link(s);
+ link(s)=null;
+ split_top_skip=split_top_ptr(p);
+ ins_ptr(p)=prune_page_top(broken_ptr(r));
+ if (ins_ptr(p)!=null)
+ {@+temp_ptr=vpack(ins_ptr(p), natural);
+ height(p)=height(temp_ptr)+depth(temp_ptr);
+ free_node(temp_ptr, box_node_size);wait=true;
+ }
+ }
+best_ins_ptr(r)=null;
+n=qo(subtype(r));
+temp_ptr=list_ptr(box(n));
+free_node(box(n), box_node_size);
+box(n)=vpack(temp_ptr, natural);
+}
+
+@ @<Either append the insertion node |p|...@>=
+link(prev_p)=link(p);link(p)=null;
+if (wait)
+ {@+link(q)=p;q=p;incr(insert_penalties);
+ }
+else{@+delete_glue_ref(split_top_ptr(p));
+ free_node(p, ins_node_size);
+ }
+p=prev_p
+
+@ The list of heldover insertions, running from |link(page_head)| to
+|page_tail|, must be moved to the contribution list when the user has
+specified no output routine.
+
+@<Perform the default output routine@>=
+{@+if (link(page_head)!=null)
+ {@+if (link(contrib_head)==null)
+ if (nest_ptr==0) tail=page_tail;@+else contrib_tail=page_tail;
+ else link(page_tail)=link(contrib_head);
+ link(contrib_head)=link(page_head);
+ link(page_head)=null;page_tail=page_head;
+ }
+ship_out(box(255));box(255)=null;
+}
+
+@ @<Explain that too many dead cycles have occurred in a row@>=
+{@+print_err("Output loop---");print_int(dead_cycles);
+@.Output loop...@>
+print_str(" consecutive dead cycles");
+help3("I've concluded that your \\output is awry; it never does a")@/
+("\\shipout, so I'm shipping \\box255 out myself. Next time")@/
+("increase \\maxdeadcycles if you want me to be more patient!");error();
+}
+
+@ @<Fire up the user's output routine and |return|@>=
+{@+output_active=true;
+incr(dead_cycles);
+push_nest();mode=-vmode;prev_depth=ignore_depth;mode_line=-line;
+begin_token_list(output_routine, output_text);
+new_save_level(output_group);normal_paragraph();
+scan_left_brace();
+return;
+}
+
+@ When the user's output routine finishes, it has constructed a vlist
+in internal vertical mode, and \TeX\ will do the following:
+
+@<Resume the page builder after an output routine has come to an end@>=
+{@+if ((loc!=null)||
+ ((token_type!=output_text)&&(token_type!=backed_up)))
+ @<Recover from an unbalanced output routine@>;
+end_token_list(); /*conserve stack space in case more outputs are triggered*/
+end_graf();unsave();output_active=false;insert_penalties=0;@/
+@<Ensure that box 255 is empty after output@>;
+if (tail!=head) /*current list goes after heldover insertions*/
+ {@+link(page_tail)=link(head);
+ page_tail=tail;
+ }
+if (link(page_head)!=null) /*and both go before heldover contributions*/
+ {@+if (link(contrib_head)==null) contrib_tail=page_tail;
+ link(page_tail)=link(contrib_head);
+ link(contrib_head)=link(page_head);
+ link(page_head)=null;page_tail=page_head;
+ }
+pop_nest();build_page();
+}
+
+@ @<Recover from an unbalanced output routine@>=
+{@+print_err("Unbalanced output routine");
+@.Unbalanced output routine@>
+help2("Your sneaky output routine has problematic {'s and/or }'s.")@/
+("I can't handle that very well; good luck.");error();
+@/do@+{get_token();
+}@+ while (!(loc==null));
+} /*loops forever if reading from a file, since |null==min_halfword <= 0|*/
+
+@ @<Ensure that box 255 is empty after output@>=
+if (box(255)!=null)
+ {@+print_err("Output routine didn't use all of ");
+ print_esc(@[@<|"box"|@>@]);print_int(255);
+@.Output routine didn't use...@>
+ help3("Your \\output commands should empty \\box255,")@/
+ ("e.g., by saying `\\shipout\\box255'.")@/
+ ("Proceed; I'll discard its present contents.");
+ box_error(255);
+ }
+
+@* The chief executive.
+We come now to the |main_control| routine, which contains the master
+switch that causes all the various pieces of \TeX\ to do their things,
+in the right order.
+
+In a sense, this is the grand climax of the program: It applies all the
+tools that we have worked so hard to construct. In another sense, this is
+the messiest part of the program: It necessarily refers to other pieces
+of code all over the place, so that a person can't fully understand what is
+going on without paging back and forth to be reminded of conventions that
+are defined elsewhere. We are now at the hub of the web, the central nervous
+system that touches most of the other parts and ties them together.
+@^brain@>
+
+The structure of |main_control| itself is quite simple. There's a label
+called |big_switch|, at which point the next token of input is fetched
+using |get_x_token|. Then the program branches at high speed into one of
+about 100 possible directions, based on the value of the current
+mode and the newly fetched command code; the sum |abs(mode)+cur_cmd|
+indicates what to do next. For example, the case `|vmode+letter|' arises
+when a letter occurs in vertical mode (or internal vertical mode); this
+case leads to instructions that initialize a new paragraph and enter
+horizontal mode.
+
+The big |case| statement that contains this multiway switch has been labeled
+|reswitch|, so that the program can |goto reswitch| when the next token
+has already been fetched. Most of the cases are quite short; they call
+an ``action procedure'' that does the work for that case, and then they
+either |goto reswitch| or they ``fall through'' to the end of the |case|
+statement, which returns control back to |big_switch|. Thus, |main_control|
+is not an extremely large procedure, in spite of the multiplicity of things
+it must do; it is small enough to be handled by \PASCAL\ compilers that put
+severe restrictions on procedure size.
+@!@^action procedure@>
+
+One case is singled out for special treatment, because it accounts for most
+of \TeX's activities in typical applications. The process of reading simple
+text and converting it into |char_node| records, while looking for ligatures
+and kerns, is part of \TeX's ``inner loop''; the whole program runs
+efficiently when its inner loop is fast, so this part has been written
+with particular care.
+
+@ We shall concentrate first on the inner loop of |main_control|, deferring
+consideration of the other cases until later.
+@^inner loop@>
+
+@p@t\4@>@<Declare action procedures for use by |main_control|@>@;
+@t\4@>@<Declare the procedure called |handle_right_brace|@>@;
+void main_control(void) /*governs \TeX's activities*/
+{@+
+
+
+
+
+int @!t; /*general-purpose temporary variable*/
+if (every_job!=null) begin_token_list(every_job, every_job_text);
+big_switch: get_x_token();@/
+reswitch: @<Give diagnostic information, if requested@>;
+switch (abs(mode)+cur_cmd) {
+case hmode+letter: case hmode+other_char: case hmode+char_given: goto main_loop;
+case hmode+char_num: {@+scan_char_num();cur_chr=cur_val;goto main_loop;@+}
+case hmode+no_boundary: {@+get_x_token();
+ if ((cur_cmd==letter)||(cur_cmd==other_char)||(cur_cmd==char_given)||
+ (cur_cmd==char_num)) cancel_boundary=true;
+ goto reswitch;
+ }
+case hmode+spacer: if (space_factor==1000) goto append_normal_space;
+ else app_space();@+break;
+case hmode+ex_space: case mmode+ex_space: goto append_normal_space;
+@t\4@>@<Cases of |main_control| that are not part of the inner loop@>@;
+} /*of the big |case| statement*/
+goto big_switch;
+main_loop: @<Append character |cur_chr| and the following characters (if~any) to the
+current hlist in the current font; |goto reswitch| when a non-character has been fetched@>;
+append_normal_space: @<Append a normal inter-word space to the current list, then
+|goto big_switch|@>;
+}
+
+@ When a new token has just been fetched at |big_switch|, we have an
+ideal place to monitor \TeX's activity.
+@^debugging@>
+
+@<Give diagnostic information, if requested@>=
+if (interrupt!=0) if (OK_to_interrupt)
+ {@+back_input();check_interrupt;goto big_switch;
+ }
+#ifdef @!DEBUG
+if (panicking) check_mem(false);@;
+#endif
+if (tracing_commands > 0) show_cur_cmd_chr()
+
+@ The following part of the program was first written in a structured
+manner, according to the philosophy that ``premature optimization is
+the root of all evil.'' Then it was rearranged into pieces of
+spaghetti so that the most common actions could proceed with little or
+no redundancy.
+
+The original unoptimized form of this algorithm resembles the
+|reconstitute| procedure, which was described earlier in connection with
+hyphenation. Again we have an implied ``cursor'' between characters
+|cur_l| and |cur_r|. The main difference is that the |lig_stack| can now
+contain a charnode as well as pseudo-ligatures; that stack is now
+usually nonempty, because the next character of input (if any) has been
+appended to it. In |main_control| we have
+$$|cur_r|=\cases{|character(lig_stack)|,&if |lig_stack > null|;\cr
+ |font_bchar[cur_font]|,&otherwise;\cr}$$
+except when |character(lig_stack)==font_false_bchar[cur_font]|.
+Several additional global variables are needed.
+
+@<Glob...@>=
+internal_font_number @!main_f; /*the current font*/
+four_quarters @!main_i; /*character information bytes for |cur_l|*/
+four_quarters @!main_j; /*ligature/kern command*/
+font_index @!main_k; /*index into |font_info|*/
+pointer @!main_p; /*temporary register for list manipulation*/
+int @!main_s; /*space factor value*/
+halfword @!bchar; /*right boundary character of current font, or |non_char|*/
+halfword @!false_bchar; /*nonexistent character matching |bchar|, or |non_char|*/
+bool @!cancel_boundary; /*should the left boundary be ignored?*/
+bool @!ins_disc; /*should we insert a discretionary node?*/
+
+@ The boolean variables of the main loop are normally false, and always reset
+to false before the loop is left. That saves us the extra work of initializing
+each time.
+
+@<Set init...@>=
+ligature_present=false;cancel_boundary=false;lft_hit=false;rt_hit=false;
+ins_disc=false;
+
+@ We leave the |space_factor| unchanged if |sf_code(cur_chr)==0|; otherwise we
+set it equal to |sf_code(cur_chr)|, except that it should never change
+from a value less than 1000 to a value exceeding 1000. The most common
+case is |sf_code(cur_chr)==1000|, so we want that case to be fast.
+
+The overall structure of the main loop is presented here. Some program labels
+are inside the individual sections.
+@^inner loop@>
+
+@d adjust_space_factor @t@>@;@/
+ main_s=sf_code(cur_chr);
+ if (main_s==1000) space_factor=1000;
+ else if (main_s < 1000)
+ {@+if (main_s > 0) space_factor=main_s;
+ }
+ else if (space_factor < 1000) space_factor=1000;
+ else space_factor=main_s
+
+@<Append character |cur_chr|...@>=
+adjust_space_factor;@/
+main_f=cur_font;
+bchar=font_bchar[main_f];false_bchar=font_false_bchar[main_f];
+if (mode > 0) if (language!=clang) fix_language();
+fast_get_avail(lig_stack);font(lig_stack)=main_f;cur_l=qi(cur_chr);
+character(lig_stack)=cur_l;@/
+cur_q=tail;
+if (cancel_boundary)
+ {@+cancel_boundary=false;main_k=non_address;
+ }
+else main_k=bchar_label[main_f];
+if (main_k==non_address) goto main_loop_move2; /*no left boundary processing*/
+cur_r=cur_l;cur_l=non_char;
+goto main_lig_loop1; /*begin with cursor after left boundary*/
+@#
+main_loop_wrapup: @<Make a ligature node, if |ligature_present|; insert a null discretionary,
+if appropriate@>;
+main_loop_move: @<If the cursor is immediately followed by the right boundary, |goto
+reswitch|; if it's followed by an invalid character, |goto big_switch|; otherwise
+move the cursor one step to the right and |goto main_lig_loop|@>;
+main_loop_lookahead: @<Look ahead for another character, or leave |lig_stack| empty
+if there's none there@>;
+main_lig_loop: @<If there's a ligature/kern command relevant to |cur_l| and |cur_r|,
+adjust the text appropriately; exit to |main_loop_wrapup|@>;
+main_loop_move_lig: @<Move the cursor past a pseudo-ligature, then |goto main_loop_lookahead|
+or |main_lig_loop|@>@;
+
+@ If |link(cur_q)| is nonnull when |wrapup| is invoked, |cur_q| points to
+the list of characters that were consumed while building the ligature
+character~|cur_l|.
+
+A discretionary break is not inserted for an explicit hyphen when we are in
+restricted horizontal mode. In particular, this avoids putting discretionary
+nodes inside of other discretionaries.
+@^inner loop@>
+
+@d pack_lig(X) /*the parameter is either |rt_hit| or |false|*/
+ {@+main_p=new_ligature(main_f, cur_l, link(cur_q));
+ if (lft_hit)
+ {@+subtype(main_p)=2;lft_hit=false;
+ }
+ if (X) if (lig_stack==null)
+ {@+incr(subtype(main_p));rt_hit=false;
+ }
+ link(cur_q)=main_p;tail=main_p;ligature_present=false;
+ }
+
+@d wrapup(X) if (cur_l < non_char)
+ {@+if (link(cur_q) > null)
+ if (character(tail)==qi(hyphen_char[main_f])) ins_disc=true;
+ if (ligature_present) pack_lig(X);
+ if (ins_disc)
+ {@+ins_disc=false;
+ if (mode > 0) tail_append(new_disc());
+ }
+ }
+
+@<Make a ligature node, if |ligature_present|;...@>=
+wrapup(rt_hit)
+
+@ @<If the cursor is immediately followed by the right boundary...@>=
+@^inner loop@>
+if (lig_stack==null) goto reswitch;
+cur_q=tail;cur_l=character(lig_stack);
+main_loop_move1: if (!is_char_node(lig_stack)) goto main_loop_move_lig;
+main_loop_move2: if ((cur_chr < font_bc[main_f])||(cur_chr > font_ec[main_f]))
+ {@+char_warning(main_f, cur_chr);free_avail(lig_stack);goto big_switch;
+ }
+main_i=char_info(main_f)(cur_l);
+if (!char_exists(main_i))
+ {@+char_warning(main_f, cur_chr);free_avail(lig_stack);goto big_switch;
+ }
+link(tail)=lig_stack;tail=lig_stack /*|main_loop_lookahead| is next*/
+
+@ Here we are at |main_loop_move_lig|.
+When we begin this code we have |cur_q==tail| and |cur_l==character(lig_stack)|.
+
+@<Move the cursor past a pseudo-ligature...@>=
+main_p=lig_ptr(lig_stack);
+if (main_p > null) tail_append(main_p); /*append a single character*/
+temp_ptr=lig_stack;lig_stack=link(temp_ptr);
+free_node(temp_ptr, small_node_size);
+main_i=char_info(main_f)(cur_l);ligature_present=true;
+if (lig_stack==null)
+ if (main_p > null) goto main_loop_lookahead;
+ else cur_r=bchar;
+else cur_r=character(lig_stack);
+goto main_lig_loop
+
+@ The result of \.{\\char} can participate in a ligature or kern, so we must
+look ahead for it.
+
+@<Look ahead for another character...@>=
+get_next(); /*set only |cur_cmd| and |cur_chr|, for speed*/
+if (cur_cmd==letter) goto main_loop_lookahead1;
+if (cur_cmd==other_char) goto main_loop_lookahead1;
+if (cur_cmd==char_given) goto main_loop_lookahead1;
+x_token(); /*now expand and set |cur_cmd|, |cur_chr|, |cur_tok|*/
+if (cur_cmd==letter) goto main_loop_lookahead1;
+if (cur_cmd==other_char) goto main_loop_lookahead1;
+if (cur_cmd==char_given) goto main_loop_lookahead1;
+if (cur_cmd==char_num)
+ {@+scan_char_num();cur_chr=cur_val;goto main_loop_lookahead1;
+ }
+if (cur_cmd==no_boundary) bchar=non_char;
+cur_r=bchar;lig_stack=null;goto main_lig_loop;
+main_loop_lookahead1: adjust_space_factor;
+fast_get_avail(lig_stack);font(lig_stack)=main_f;
+cur_r=qi(cur_chr);character(lig_stack)=cur_r;
+if (cur_r==false_bchar) cur_r=non_char /*this prevents spurious ligatures*/
+
+@ Even though comparatively few characters have a lig/kern program, several
+of the instructions here count as part of \TeX's inner loop, since a
+@^inner loop@>
+potentially long sequential search must be performed. For example, tests with
+Computer Modern Roman showed that about 40 per cent of all characters
+actually encountered in practice had a lig/kern program, and that about four
+lig/kern commands were investigated for every such character.
+
+At the beginning of this code we have |main_i==char_info(main_f)(cur_l)|.
+
+@<If there's a ligature/kern command...@>=
+if (char_tag(main_i)!=lig_tag) goto main_loop_wrapup;
+if (cur_r==non_char) goto main_loop_wrapup;
+main_k=lig_kern_start(main_f)(main_i);main_j=font_info[main_k].qqqq;
+if (skip_byte(main_j) <= stop_flag) goto main_lig_loop2;
+main_k=lig_kern_restart(main_f)(main_j);
+main_lig_loop1: main_j=font_info[main_k].qqqq;
+main_lig_loop2: if (next_char(main_j)==cur_r)
+ if (skip_byte(main_j) <= stop_flag)
+ @<Do ligature or kern command, returning to |main_lig_loop| or |main_loop_wrapup|
+or |main_loop_move|@>;
+if (skip_byte(main_j)==qi(0)) incr(main_k);
+else{@+if (skip_byte(main_j) >= stop_flag) goto main_loop_wrapup;
+ main_k=main_k+qo(skip_byte(main_j))+1;
+ }
+goto main_lig_loop1
+
+@ When a ligature or kern instruction matches a character, we know from
+|read_font_info| that the character exists in the font, even though we
+haven't verified its existence in the normal way.
+
+This section could be made into a subroutine, if the code inside
+|main_control| needs to be shortened.
+
+\chardef\?='174 % vertical line to indicate character retention
+
+@<Do ligature or kern command...@>=
+{@+if (op_byte(main_j) >= kern_flag)
+ {@+wrapup(rt_hit);
+ tail_append(new_kern(char_kern(main_f)(main_j)));goto main_loop_move;
+ }
+if (cur_l==non_char) lft_hit=true;
+else if (lig_stack==null) rt_hit=true;
+check_interrupt; /*allow a way out in case there's an infinite ligature loop*/
+switch (op_byte(main_j)) {
+qi(case 1): qi(case 5): {@+cur_l=rem_byte(main_j); /*\.{=:\?}, \.{=:\?>}*/
+ main_i=char_info(main_f)(cur_l);ligature_present=true;
+ } @+break;
+qi(case 2): qi(case 6): {@+cur_r=rem_byte(main_j); /*\.{\?=:}, \.{\?=:>}*/
+ if (lig_stack==null) /*right boundary character is being consumed*/
+ {@+lig_stack=new_lig_item(cur_r);bchar=non_char;
+ }
+ else if (is_char_node(lig_stack)) /*|link(lig_stack)==null|*/
+ {@+main_p=lig_stack;lig_stack=new_lig_item(cur_r);
+ lig_ptr(lig_stack)=main_p;
+ }
+ else character(lig_stack)=cur_r;
+ } @+break;
+qi(case 3): {@+cur_r=rem_byte(main_j); /*\.{\?=:\?}*/
+ main_p=lig_stack;lig_stack=new_lig_item(cur_r);
+ link(lig_stack)=main_p;
+ } @+break;
+qi(case 7): qi(case 11): {@+wrapup(false); /*\.{\?=:\?>}, \.{\?=:\?>>}*/
+ cur_q=tail;cur_l=rem_byte(main_j);
+ main_i=char_info(main_f)(cur_l);ligature_present=true;
+ } @+break;
+default:{@+cur_l=rem_byte(main_j);ligature_present=true; /*\.{=:}*/
+ if (lig_stack==null) goto main_loop_wrapup;
+ else goto main_loop_move1;
+ }
+}
+if (op_byte(main_j) > qi(4))
+ if (op_byte(main_j)!=qi(7)) goto main_loop_wrapup;
+if (cur_l < non_char) goto main_lig_loop;
+main_k=bchar_label[main_f];goto main_lig_loop1;
+}
+
+@ The occurrence of blank spaces is almost part of \TeX's inner loop,
+@^inner loop@>
+since we usually encounter about one space for every five non-blank characters.
+Therefore |main_control| gives second-highest priority to ordinary spaces.
+
+When a glue parameter like \.{\\spaceskip} is set to `\.{0pt}', we will
+see to it later that the corresponding glue specification is precisely
+|zero_glue|, not merely a pointer to some specification that happens
+to be full of zeroes. Therefore it is simple to test whether a glue parameter
+is zero or~not.
+
+@<Append a normal inter-word space...@>=
+if (space_skip==zero_glue)
+ {@+@<Find the glue specification, |main_p|, for text spaces in the current font@>;
+ temp_ptr=new_glue(main_p);
+ }
+else temp_ptr=new_param_glue(space_skip_code);
+link(tail)=temp_ptr;tail=temp_ptr;
+goto big_switch
+
+@ Having |font_glue| allocated for each text font saves both time and memory.
+If any of the three spacing parameters are subsequently changed by the
+use of \.{\\fontdimen}, the |find_font_dimen| procedure deallocates the
+|font_glue| specification allocated here.
+
+@<Find the glue specification...@>=
+{@+main_p=font_glue[cur_font];
+if (main_p==null)
+ {@+main_p=new_spec(zero_glue);main_k=param_base[cur_font]+space_code;
+ width(main_p)=font_info[main_k].sc; /*that's |space(cur_font)|*/
+ stretch(main_p)=font_info[main_k+1].sc; /*and |space_stretch(cur_font)|*/
+ shrink(main_p)=font_info[main_k+2].sc; /*and |space_shrink(cur_font)|*/
+ font_glue[cur_font]=main_p;
+ }
+}
+
+@ @<Declare act...@>=
+void app_space(void) /*handle spaces when |space_factor!=1000|*/
+{@+pointer @!q; /*glue node*/
+if ((space_factor >= 2000)&&(xspace_skip!=zero_glue))
+ q=new_param_glue(xspace_skip_code);
+else{@+if (space_skip!=zero_glue) main_p=space_skip;
+ else@<Find the glue specification...@>;
+ main_p=new_spec(main_p);
+ @<Modify the glue specification in |main_p| according to the space factor@>;
+ q=new_glue(main_p);glue_ref_count(main_p)=null;
+ }
+link(tail)=q;tail=q;
+}
+
+@ @<Modify the glue specification in |main_p| according to the space factor@>=
+if (space_factor >= 2000) width(main_p)=width(main_p)+extra_space(cur_font);
+stretch(main_p)=xn_over_d(stretch(main_p), space_factor, 1000);
+shrink(main_p)=xn_over_d(shrink(main_p), 1000, space_factor)
+
+@ Whew---that covers the main loop. We can now proceed at a leisurely
+pace through the other combinations of possibilities.
+
+@d any_mode(X) case vmode+X: case hmode+X: case mmode+X /*for mode-independent commands*/
+
+@<Cases of |main_control| that are not part of the inner loop@>=
+any_mode(relax): case vmode+spacer: case mmode+spacer: case mmode+no_boundary: do_nothing;
+any_mode(ignore_spaces): {@+@<Get the next non-blank non-call...@>;
+ goto reswitch;
+ }
+case vmode+stop: if (its_all_over()) return;@+break; /*this is the only way out*/
+@t\4@>@<Forbidden cases detected in |main_control|@>@+@, any_mode(mac_param):
+ report_illegal_case();@+break;
+@<Math-only cases in non-math modes, or vice versa@>: insert_dollar_sign();@+break;
+@t\4@>@<Cases of |main_control| that build boxes and lists@>@;
+@t\4@>@<Cases of |main_control| that don't depend on |mode|@>@;
+@t\4@>@<Cases of |main_control| that are for extensions to \TeX@>@;
+
+@ Here is a list of cases where the user has probably gotten into or out of math
+mode by mistake. \TeX\ will insert a dollar sign and rescan the current token.
+
+@d non_math(X) case vmode+X: case hmode+X
+
+@<Math-only cases in non-math modes...@>=
+non_math(sup_mark): non_math(sub_mark): non_math(math_char_num):
+non_math(math_given): non_math(math_comp): non_math(delim_num):
+non_math(left_right): non_math(above): non_math(radical):
+non_math(math_style): non_math(math_choice): non_math(vcenter):
+non_math(non_script): non_math(mkern): non_math(limit_switch):
+non_math(mskip): non_math(math_accent):
+case mmode+endv: case mmode+par_end: case mmode+stop: case mmode+vskip: case mmode+un_vbox:
+case mmode+valign: case mmode+hrule
+
+@ @<Declare action...@>=
+void insert_dollar_sign(void)
+{@+back_input();cur_tok=math_shift_token+'$';
+print_err("Missing $ inserted");
+@.Missing \$ inserted@>
+help2("I've inserted a begin-math/end-math symbol since I think")@/
+("you left one out. Proceed, with fingers crossed.");ins_error();
+}
+
+@ When erroneous situations arise, \TeX\ usually issues an error message
+specific to the particular error. For example, `\.{\\noalign}' should
+not appear in any mode, since it is recognized by the |align_peek| routine
+in all of its legitimate appearances; a special error message is given
+when `\.{\\noalign}' occurs elsewhere. But sometimes the most appropriate
+error message is simply that the user is not allowed to do what he or she
+has attempted. For example, `\.{\\moveleft}' is allowed only in vertical mode,
+and `\.{\\lower}' only in non-vertical modes. Such cases are enumerated
+here and in the other sections referred to under `See also \dots.'
+
+@<Forbidden cases...@>=
+case vmode+vmove: case hmode+hmove: case mmode+hmove: any_mode(last_item):
+
+@ The `|you_cant|' procedure prints a line saying that the current command
+is illegal in the current mode; it identifies these things symbolically.
+
+@<Declare action...@>=
+void you_cant(void)
+{@+print_err("You can't use `");
+@.You can't use x in y mode@>
+print_cmd_chr(cur_cmd, cur_chr);
+print_str("' in ");print_mode(mode);
+}
+
+@ @<Declare act...@>=
+void report_illegal_case(void)
+{@+you_cant();
+help4("Sorry, but I'm not programmed to handle this case;")@/
+("I'll just pretend that you didn't ask for it.")@/
+("If you're in the wrong mode, you might be able to")@/
+("return to the right one by typing `I}' or `I$' or `I\\par'.");@/
+error();
+}
+
+@ Some operations are allowed only in privileged modes, i.e., in cases
+that |mode > 0|. The |privileged| function is used to detect violations
+of this rule; it issues an error message and returns |false| if the
+current |mode| is negative.
+
+@<Declare act...@>=
+bool privileged(void)
+{@+if (mode > 0) return true;
+else{@+report_illegal_case();return false;
+ }
+}
+
+@ Either \.{\\dump} or \.{\\end} will cause |main_control| to enter the
+endgame, since both of them have `|stop|' as their command code.
+
+@<Put each...@>=
+primitive(@[@<|"end"|@>@], stop, 0);@/
+@!@:end_}{\.{\\end} primitive@>
+primitive(@[@<|"dump"|@>@], stop, 1);@/
+@!@:dump_}{\.{\\dump} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case stop: if (chr_code==1) print_esc(@[@<|"dump"|@>@]);@+else print_esc(@[@<|"end"|@>@]);@+break;
+
+@ We don't want to leave |main_control| immediately when a |stop| command
+is sensed, because it may be necessary to invoke an \.{\\output} routine
+several times before things really grind to a halt. (The output routine
+might even say `\.{\\gdef\\end\{...\}}', to prolong the life of the job.)
+Therefore |its_all_over| is |true| only when the current page
+and contribution list are empty, and when the last output was not a
+``dead cycle.''
+
+@<Declare act...@>=
+bool its_all_over(void) /*do this when \.{\\end} or \.{\\dump} occurs*/
+{@+
+if (privileged())
+ {@+if ((page_head==page_tail)&&(head==tail)&&(dead_cycles==0))
+ {@+return true;
+ }
+ back_input(); /*we will try to end again after ejecting residual material*/
+ tail_append(new_null_box());
+ width(tail)=hsize;
+ tail_append(new_glue(fill_glue));
+ tail_append(new_penalty(-010000000000));@/
+ build_page(); /*append \.{\\hbox to \\hsize\{\}\\vfill\\penalty-'10000000000}*/
+ }
+return false;
+}
+
+@* Building boxes and lists.
+The most important parts of |main_control| are concerned with \TeX's
+chief mission of box-making. We need to control the activities that put
+entries on vlists and hlists, as well as the activities that convert
+those lists into boxes. All of the necessary machinery has already been
+developed; it remains for us to ``push the buttons'' at the right times.
+
+@ As an introduction to these routines, let's consider one of the simplest
+cases: What happens when `\.{\\hrule}' occurs in vertical mode, or
+`\.{\\vrule}' in horizontal mode or math mode? The code in |main_control|
+is short, since the |scan_rule_spec| routine already does most of what is
+required; thus, there is no need for a special action procedure.
+
+Note that baselineskip calculations are disabled after a rule in vertical
+mode, by setting |prev_depth=ignore_depth|.
+
+@<Cases of |main_control| that build...@>=
+case vmode+hrule: case hmode+vrule: case mmode+vrule: {@+tail_append(scan_rule_spec());
+ if (abs(mode)==vmode) prev_depth=ignore_depth;
+ else if (abs(mode)==hmode) space_factor=1000;
+ } @+break;
+
+@ The processing of things like \.{\\hskip} and \.{\\vskip} is slightly
+more complicated. But the code in |main_control| is very short, since
+it simply calls on the action routine |append_glue|. Similarly, \.{\\kern}
+activates |append_kern|.
+
+@<Cases of |main_control| that build...@>=
+case vmode+vskip: case hmode+hskip: case mmode+hskip: case mmode+mskip: append_glue();@+break;
+any_mode(kern): case mmode+mkern: append_kern();@+break;
+
+@ The |hskip| and |vskip| command codes are used for control sequences
+like \.{\\hss} and \.{\\vfil} as well as for \.{\\hskip} and \.{\\vskip}.
+The difference is in the value of |cur_chr|.
+
+@d fil_code 0 /*identifies \.{\\hfil} and \.{\\vfil}*/
+@d fill_code 1 /*identifies \.{\\hfill} and \.{\\vfill}*/
+@d ss_code 2 /*identifies \.{\\hss} and \.{\\vss}*/
+@d fil_neg_code 3 /*identifies \.{\\hfilneg} and \.{\\vfilneg}*/
+@d skip_code 4 /*identifies \.{\\hskip} and \.{\\vskip}*/
+@d mskip_code 5 /*identifies \.{\\mskip}*/
+
+@<Put each...@>=
+primitive(@[@<|"hskip"|@>@], hskip, skip_code);@/
+@!@:hskip_}{\.{\\hskip} primitive@>
+primitive(@[@<|"hfil"|@>@], hskip, fil_code);
+@!@:hfil_}{\.{\\hfil} primitive@>
+primitive(@[@<|"hfill"|@>@], hskip, fill_code);@/
+@!@:hfill_}{\.{\\hfill} primitive@>
+primitive(@[@<|"hss"|@>@], hskip, ss_code);
+@!@:hss_}{\.{\\hss} primitive@>
+primitive(@[@<|"hfilneg"|@>@], hskip, fil_neg_code);@/
+@!@:hfil_neg_}{\.{\\hfilneg} primitive@>
+primitive(@[@<|"vskip"|@>@], vskip, skip_code);@/
+@!@:vskip_}{\.{\\vskip} primitive@>
+primitive(@[@<|"vfil"|@>@], vskip, fil_code);
+@!@:vfil_}{\.{\\vfil} primitive@>
+primitive(@[@<|"vfill"|@>@], vskip, fill_code);@/
+@!@:vfill_}{\.{\\vfill} primitive@>
+primitive(@[@<|"vss"|@>@], vskip, ss_code);
+@!@:vss_}{\.{\\vss} primitive@>
+primitive(@[@<|"vfilneg"|@>@], vskip, fil_neg_code);@/
+@!@:vfil_neg_}{\.{\\vfilneg} primitive@>
+primitive(@[@<|"mskip"|@>@], mskip, mskip_code);@/
+@!@:mskip_}{\.{\\mskip} primitive@>
+primitive(@[@<|"kern"|@>@], kern, explicit);
+@!@:kern_}{\.{\\kern} primitive@>
+primitive(@[@<|"mkern"|@>@], mkern, mu_glue);@/
+@!@:mkern_}{\.{\\mkern} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case hskip: switch (chr_code) {
+ case skip_code: print_esc(@[@<|"hskip"|@>@]);@+break;
+ case fil_code: print_esc(@[@<|"hfil"|@>@]);@+break;
+ case fill_code: print_esc(@[@<|"hfill"|@>@]);@+break;
+ case ss_code: print_esc(@[@<|"hss"|@>@]);@+break;
+ default:print_esc(@[@<|"hfilneg"|@>@]);
+ } @+break;
+case vskip: switch (chr_code) {
+ case skip_code: print_esc(@[@<|"vskip"|@>@]);@+break;
+ case fil_code: print_esc(@[@<|"vfil"|@>@]);@+break;
+ case fill_code: print_esc(@[@<|"vfill"|@>@]);@+break;
+ case ss_code: print_esc(@[@<|"vss"|@>@]);@+break;
+ default:print_esc(@[@<|"vfilneg"|@>@]);
+ } @+break;
+case mskip: print_esc(@[@<|"mskip"|@>@]);@+break;
+case kern: print_esc(@[@<|"kern"|@>@]);@+break;
+case mkern: print_esc(@[@<|"mkern"|@>@]);@+break;
+
+@ All the work relating to glue creation has been relegated to the
+following subroutine. It does not call |build_page|, because it is
+used in at least one place where that would be a mistake.
+
+@<Declare action...@>=
+void append_glue(void)
+{@+small_number s; /*modifier of skip command*/
+s=cur_chr;
+switch (s) {
+case fil_code: cur_val=fil_glue;@+break;
+case fill_code: cur_val=fill_glue;@+break;
+case ss_code: cur_val=ss_glue;@+break;
+case fil_neg_code: cur_val=fil_neg_glue;@+break;
+case skip_code: scan_glue(glue_val);@+break;
+case mskip_code: scan_glue(mu_val);
+} /*now |cur_val| points to the glue specification*/
+tail_append(new_glue(cur_val));
+if (s >= skip_code)
+ {@+decr(glue_ref_count(cur_val));
+ if (s > skip_code) subtype(tail)=mu_glue;
+ }
+}
+
+@ @<Declare act...@>=
+void append_kern(void)
+{@+quarterword s; /*|subtype| of the kern node*/
+s=cur_chr;scan_dimen(s==mu_glue, false, false);
+tail_append(new_kern(cur_val));subtype(tail)=s;
+}
+
+@ Many of the actions related to box-making are triggered by the appearance
+of braces in the input. For example, when the user says `\.{\\hbox}
+\.{to} \.{100pt\{$\langle\,\hbox{hlist}\,\rangle$\}}' in vertical mode,
+the information about the box size (100pt, |exactly|) is put onto |save_stack|
+with a level boundary word just above it, and |cur_group=adjusted_hbox_group|;
+\TeX\ enters restricted horizontal mode to process the hlist. The right
+brace eventually causes |save_stack| to be restored to its former state,
+at which time the information about the box size (100pt, |exactly|) is
+available once again; a box is packaged and we leave restricted horizontal
+mode, appending the new box to the current list of the enclosing mode
+(in this case to the current list of vertical mode), followed by any
+vertical adjustments that were removed from the box by |hpack|.
+
+The next few sections of the program are therefore concerned with the
+treatment of left and right curly braces.
+
+@ If a left brace occurs in the middle of a page or paragraph, it simply
+introduces a new level of grouping, and the matching right brace will not have
+such a drastic effect. Such grouping affects neither the mode nor the
+current list.
+
+@<Cases of |main_control| that build...@>=
+non_math(left_brace): new_save_level(simple_group);@+break;
+any_mode(begin_group): new_save_level(semi_simple_group);@+break;
+any_mode(end_group): if (cur_group==semi_simple_group) unsave();
+ else off_save();@+break;
+
+@ We have to deal with errors in which braces and such things are not
+properly nested. Sometimes the user makes an error of commission by
+inserting an extra symbol, but sometimes the user makes an error of omission.
+\TeX\ can't always tell one from the other, so it makes a guess and tries
+to avoid getting into a loop.
+
+The |off_save| routine is called when the current group code is wrong. It tries
+to insert something into the user's input that will help clean off
+the top level.
+
+@<Declare act...@>=
+void off_save(void)
+{@+pointer p; /*inserted token*/
+if (cur_group==bottom_level)
+ @<Drop current token and complain that it was unmatched@>@;
+else{@+back_input();p=get_avail();link(temp_head)=p;
+ print_err("Missing ");
+ @<Prepare to insert a token that matches |cur_group|, and print what it is@>;
+ print_str(" inserted");ins_list(link(temp_head));
+ help5("I've inserted something that you may have forgotten.")@/
+ ("(See the <inserted text> above.)")@/
+ ("With luck, this will get me unwedged. But if you")@/
+ ("really didn't forget anything, try typing `2' now; then")@/
+ ("my insertion and my current dilemma will both disappear.");
+ error();
+ }
+}
+
+@ At this point, |link(temp_head)==p|, a pointer to an empty one-word node.
+
+@<Prepare to insert a token that matches |cur_group|...@>=
+switch (cur_group) {
+case semi_simple_group: {@+info(p)=cs_token_flag+frozen_end_group;
+ print_esc(@[@<|"endgroup"|@>@]);
+@.Missing \\endgroup inserted@>
+ } @+break;
+case math_shift_group: {@+info(p)=math_shift_token+'$';print_char('$');
+@.Missing \$ inserted@>
+ } @+break;
+case math_left_group: {@+info(p)=cs_token_flag+frozen_right;link(p)=get_avail();
+ p=link(p);info(p)=other_token+'.';print_esc(@[@<|"right."|@>@]);
+@.Missing \\right\hbox{.} inserted@>
+@^null delimiter@>
+ } @+break;
+default:{@+info(p)=right_brace_token+'}';print_char('}');
+@.Missing \} inserted@>
+ }
+}
+
+@ @<Drop current token and complain that it was unmatched@>=
+{@+print_err("Extra ");print_cmd_chr(cur_cmd, cur_chr);
+@.Extra x@>
+help1("Things are pretty mixed up, but I think the worst is over.");@/
+error();
+}
+
+@ The routine for a |right_brace| character branches into many subcases,
+since a variety of things may happen, depending on |cur_group|. Some
+types of groups are not supposed to be ended by a right brace; error
+messages are given in hopes of pinpointing the problem. Most branches
+of this routine will be filled in later, when we are ready to understand
+them; meanwhile, we must prepare ourselves to deal with such errors.
+
+@<Cases of |main_control| that build...@>=
+any_mode(right_brace): handle_right_brace();@+break;
+
+@ @<Declare the procedure called |handle_right_brace|@>=
+void handle_right_brace(void)
+{@+pointer p, @!q; /*for short-term use*/
+scaled @!d; /*holds |split_max_depth| in |insert_group|*/
+int @!f; /*holds |floating_penalty| in |insert_group|*/
+switch (cur_group) {
+case simple_group: unsave();@+break;
+case bottom_level: {@+print_err("Too many }'s");
+@.Too many \}'s@>
+ help2("You've closed more groups than you opened.")@/
+ ("Such booboos are generally harmless, so keep going.");error();
+ } @+break;
+case semi_simple_group: case math_shift_group: case math_left_group: extra_right_brace();@+break;
+@t\4@>@<Cases of |handle_right_brace| where a |right_brace| triggers a delayed action@>@;
+default:confusion(@[@<|"rightbrace"|@>@]);
+@:this can't happen rightbrace}{\quad rightbrace@>
+}
+}
+
+@ @<Declare act...@>=
+void extra_right_brace(void)
+{@+print_err("Extra }, or forgotten ");
+@.Extra \}, or forgotten x@>
+switch (cur_group) {
+case semi_simple_group: print_esc(@[@<|"endgroup"|@>@]);@+break;
+case math_shift_group: print_char('$');@+break;
+case math_left_group: print_esc(@[@<|"right"|@>@]);
+} @/
+help5("I've deleted a group-closing symbol because it seems to be")@/
+("spurious, as in `$x}$'. But perhaps the } is legitimate and")@/
+("you forgot something else, as in `\\hbox{$x}'. In such cases")@/
+("the way to recover is to insert both the forgotten and the")@/
+("deleted material, e.g., by typing `I$}'.");error();
+incr(align_state);
+}
+
+@ Here is where we clear the parameters that are supposed to revert to their
+default values after every paragraph and when internal vertical mode is entered.
+
+@<Declare act...@>=
+void normal_paragraph(void)
+{@+if (looseness!=0) eq_word_define(int_base+looseness_code, 0);
+if (hang_indent!=0) eq_word_define(dimen_base+hang_indent_code, 0);
+if (hang_after!=1) eq_word_define(int_base+hang_after_code, 1);
+if (par_shape_ptr!=null) eq_define(par_shape_loc, shape_ref, null);
+}
+
+@ Now let's turn to the question of how \.{\\hbox} is treated. We actually
+need to consider also a slightly larger context, since constructions like
+`\.{\\setbox3=}\penalty0\.{\\hbox...}' and
+`\.{\\leaders}\penalty0\.{\\hbox...}' and
+`\.{\\lower3.8pt\\hbox...}'
+are supposed to invoke quite
+different actions after the box has been packaged. Conversely,
+constructions like `\.{\\setbox3=}' can be followed by a variety of
+different kinds of boxes, and we would like to encode such things in an
+efficient way.
+
+In other words, there are two problems: to represent the context of a box,
+and to represent its type.
+
+The first problem is solved by putting a ``context code'' on the |save_stack|,
+just below the two entries that give the dimensions produced by |scan_spec|.
+The context code is either a (signed) shift amount, or it is a large
+integer | >= box_flag|, where |box_flag==@t$2^{30}$@>|. Codes |box_flag| through
+|box_flag+255| represent `\.{\\setbox0}' through `\.{\\setbox255}';
+codes |box_flag+256| through |box_flag+511| represent `\.{\\global\\setbox0}'
+through `\.{\\global\\setbox255}';
+code |box_flag+512| represents `\.{\\shipout}'; and codes |box_flag+513|
+through |box_flag+515| represent `\.{\\leaders}', `\.{\\cleaders}',
+and `\.{\\xleaders}'.
+
+The second problem is solved by giving the command code |make_box| to all
+control sequences that produce a box, and by using the following |chr_code|
+values to distinguish between them: |box_code|, |copy_code|, |last_box_code|,
+|vsplit_code|, |vtop_code|, |vtop_code+vmode|, and |vtop_code+hmode|, where
+the latter two are used to denote \.{\\vbox} and \.{\\hbox}, respectively.
+
+@d box_flag 010000000000 /*context code for `\.{\\setbox0}'*/
+@d ship_out_flag box_flag+512 /*context code for `\.{\\shipout}'*/
+@d leader_flag box_flag+513 /*context code for `\.{\\leaders}'*/
+@d box_code 0 /*|chr_code| for `\.{\\box}'*/
+@d copy_code 1 /*|chr_code| for `\.{\\copy}'*/
+@d last_box_code 2 /*|chr_code| for `\.{\\lastbox}'*/
+@d vsplit_code 3 /*|chr_code| for `\.{\\vsplit}'*/
+@d vtop_code 4 /*|chr_code| for `\.{\\vtop}'*/
+
+@<Put each...@>=
+primitive(@[@<|"moveleft"|@>@], hmove, 1);
+@!@:move_left_}{\.{\\moveleft} primitive@>
+primitive(@[@<|"moveright"|@>@], hmove, 0);@/
+@!@:move_right_}{\.{\\moveright} primitive@>
+primitive(@[@<|"raise"|@>@], vmove, 1);
+@!@:raise_}{\.{\\raise} primitive@>
+primitive(@[@<|"lower"|@>@], vmove, 0);
+@!@:lower_}{\.{\\lower} primitive@>
+@#
+primitive(@[@<|"box"|@>@], make_box, box_code);
+@!@:box_}{\.{\\box} primitive@>
+primitive(@[@<|"copy"|@>@], make_box, copy_code);
+@!@:copy_}{\.{\\copy} primitive@>
+primitive(@[@<|"lastbox"|@>@], make_box, last_box_code);
+@!@:last_box_}{\.{\\lastbox} primitive@>
+primitive(@[@<|"vsplit"|@>@], make_box, vsplit_code);
+@!@:vsplit_}{\.{\\vsplit} primitive@>
+primitive(@[@<|"vtop"|@>@], make_box, vtop_code);@/
+@!@:vtop_}{\.{\\vtop} primitive@>
+primitive(@[@<|"vbox"|@>@], make_box, vtop_code+vmode);
+@!@:vbox_}{\.{\\vbox} primitive@>
+primitive(@[@<|"hbox"|@>@], make_box, vtop_code+hmode);@/
+@!@:hbox_}{\.{\\hbox} primitive@>
+primitive(@[@<|"shipout"|@>@], leader_ship, a_leaders-1); /*|ship_out_flag==leader_flag-1|*/
+@!@:ship_out_}{\.{\\shipout} primitive@>
+primitive(@[@<|"leaders"|@>@], leader_ship, a_leaders);
+@!@:leaders_}{\.{\\leaders} primitive@>
+primitive(@[@<|"cleaders"|@>@], leader_ship, c_leaders);
+@!@:c_leaders_}{\.{\\cleaders} primitive@>
+primitive(@[@<|"xleaders"|@>@], leader_ship, x_leaders);
+@!@:x_leaders_}{\.{\\xleaders} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case hmove: if (chr_code==1) print_esc(@[@<|"moveleft"|@>@]);@+else print_esc(@[@<|"moveright"|@>@]);@+break;
+case vmove: if (chr_code==1) print_esc(@[@<|"raise"|@>@]);@+else print_esc(@[@<|"lower"|@>@]);@+break;
+case make_box: switch (chr_code) {
+ case box_code: print_esc(@[@<|"box"|@>@]);@+break;
+ case copy_code: print_esc(@[@<|"copy"|@>@]);@+break;
+ case last_box_code: print_esc(@[@<|"lastbox"|@>@]);@+break;
+ case vsplit_code: print_esc(@[@<|"vsplit"|@>@]);@+break;
+ case vtop_code: print_esc(@[@<|"vtop"|@>@]);@+break;
+ case vtop_code+vmode: print_esc(@[@<|"vbox"|@>@]);@+break;
+ default:print_esc(@[@<|"hbox"|@>@]);
+ } @+break;
+case leader_ship: if (chr_code==a_leaders) print_esc(@[@<|"leaders"|@>@]);
+ else if (chr_code==c_leaders) print_esc(@[@<|"cleaders"|@>@]);
+ else if (chr_code==x_leaders) print_esc(@[@<|"xleaders"|@>@]);
+ else print_esc(@[@<|"shipout"|@>@]);@+break;
+
+@ Constructions that require a box are started by calling |scan_box| with
+a specified context code. The |scan_box| routine verifies
+that a |make_box| command comes next and then it calls |begin_box|.
+
+@<Cases of |main_control| that build...@>=
+case vmode+hmove: case hmode+vmove: case mmode+vmove: {@+t=cur_chr;
+ scan_normal_dimen;
+ if (t==0) scan_box(cur_val);@+else scan_box(-cur_val);
+ } @+break;
+any_mode(leader_ship): scan_box(leader_flag-a_leaders+cur_chr);@+break;
+any_mode(make_box): begin_box(0);@+break;
+
+@ The global variable |cur_box| will point to a newly made box. If the box
+is void, we will have |cur_box==null|. Otherwise we will have
+|type(cur_box)==hlist_node| or |vlist_node| or |rule_node|; the |rule_node|
+case can occur only with leaders.
+
+@<Glob...@>=
+pointer @!cur_box; /*box to be placed into its context*/
+
+@ The |box_end| procedure does the right thing with |cur_box|, if
+|box_context| represents the context as explained above.
+
+@<Declare act...@>=
+void box_end(int @!box_context)
+{@+pointer p; /*|ord_noad| for new box in math mode*/
+if (box_context < box_flag) @<Append box |cur_box| to the current list, shifted by
+|box_context|@>@;
+else if (box_context < ship_out_flag) @<Store \(c)|cur_box| in a box register@>;
+else if (cur_box!=null)
+ if (box_context > ship_out_flag) @<Append a new leader node that uses |cur_box|@>@;
+ else ship_out(cur_box);
+}
+
+@ The global variable |adjust_tail| will be non-null if and only if the
+current box might include adjustments that should be appended to the
+current vertical list.
+
+@<Append box |cur_box| to the current...@>=
+{@+if (cur_box!=null)
+ {@+shift_amount(cur_box)=box_context;
+ if (abs(mode)==vmode)
+ {@+append_to_vlist(cur_box);
+ if (adjust_tail!=null)
+ {@+if (adjust_head!=adjust_tail)
+ {@+link(tail)=link(adjust_head);tail=adjust_tail;
+ }
+ adjust_tail=null;
+ }
+ if (mode > 0) build_page();
+ }
+ else{@+if (abs(mode)==hmode) space_factor=1000;
+ else{@+p=new_noad();
+ math_type(nucleus(p))=sub_box;
+ info(nucleus(p))=cur_box;cur_box=p;
+ }
+ link(tail)=cur_box;tail=cur_box;
+ }
+ }
+}
+
+@ @<Store \(c)|cur_box| in a box register@>=
+if (box_context < box_flag+256)
+ eq_define(box_base-box_flag+box_context, box_ref, cur_box);
+else geq_define(box_base-box_flag-256+box_context, box_ref, cur_box)
+
+@ @<Append a new leader node...@>=
+{@+@<Get the next non-blank non-relax...@>;
+if (((cur_cmd==hskip)&&(abs(mode)!=vmode))||@|
+ ((cur_cmd==vskip)&&(abs(mode)==vmode)))
+ {@+append_glue();subtype(tail)=box_context-(leader_flag-a_leaders);
+ leader_ptr(tail)=cur_box;
+ }
+else{@+print_err("Leaders not followed by proper glue");
+@.Leaders not followed by...@>
+ help3("You should say `\\leaders <box or rule><hskip or vskip>'.")@/
+ ("I found the <box or rule>, but there's no suitable")@/
+ ("<hskip or vskip>, so I'm ignoring these leaders.");back_error();
+ flush_node_list(cur_box);
+ }
+}
+
+@ Now that we can see what eventually happens to boxes, we can consider
+the first steps in their creation. The |begin_box| routine is called when
+|box_context| is a context specification, |cur_chr| specifies the type of
+box desired, and |cur_cmd==make_box|.
+
+@<Declare act...@>=
+void begin_box(int @!box_context)
+{@+
+pointer @!p, @!q; /*run through the current list*/
+int @!m; /*the length of a replacement list*/
+halfword @!k; /*0 or |vmode| or |hmode|*/
+eight_bits @!n; /*a box number*/
+switch (cur_chr) {
+case box_code: {@+scan_eight_bit_int();cur_box=box(cur_val);
+ box(cur_val)=null; /*the box becomes void, at the same level*/
+ } @+break;
+case copy_code: {@+scan_eight_bit_int();cur_box=copy_node_list(box(cur_val));
+ } @+break;
+case last_box_code: @<If the current list ends with a box node, delete it from the
+list and make |cur_box| point to it; otherwise set |cur_box:=null|@>@;@+break;
+case vsplit_code: @<Split off part of a vertical box, make |cur_box| point to it@>@;@+break;
+default:@<Initiate the construction of an hbox or vbox, then |return|@>@;
+} @/
+box_end(box_context); /*in simple cases, we use the box immediately*/
+}
+
+@ Note that the condition |!is_char_node(tail)| implies that |head!=tail|,
+since |head| is a one-word node.
+
+@<If the current list ends with a box node, delete it...@>=
+{@+cur_box=null;
+if (abs(mode)==mmode)
+ {@+you_cant();help1("Sorry; this \\lastbox will be void.");error();
+ }
+else if ((mode==vmode)&&(head==tail))
+ {@+you_cant();
+ help2("Sorry...I usually can't take things from the current page.")@/
+ ("This \\lastbox will therefore be void.");error();
+ }
+else{@+if (!is_char_node(tail))
+ if ((type(tail)==hlist_node)||(type(tail)==vlist_node))
+ @<Remove the last box, unless it's part of a discretionary@>;
+ }
+}
+
+@ @<Remove the last box...@>=
+{@+q=head;
+@/do@+{p=q;
+if (!is_char_node(q)) if (type(q)==disc_node)
+ {@+for (m=1; m<=replace_count(q); m++) p=link(p);
+ if (p==tail) goto done;
+ }
+q=link(p);
+}@+ while (!(q==tail));
+cur_box=tail;shift_amount(cur_box)=0;
+tail=p;link(p)=null;
+done: ;}
+
+@ Here we deal with things like `\.{\\vsplit 13 to 100pt}'.
+
+@<Split off part of a vertical box, make |cur_box| point to it@>=
+{@+scan_eight_bit_int();n=cur_val;
+if (!scan_keyword(@[@<|"to"|@>@]))
+@.to@>
+ {@+print_err("Missing `to' inserted");
+@.Missing `to' inserted@>
+ help2("I'm working on `\\vsplit<box number> to <dimen>';")@/
+ ("will look for the <dimen> next.");error();
+ }
+scan_normal_dimen;
+cur_box=vsplit(n, cur_val);
+}
+
+@ Here is where we enter restricted horizontal mode or internal vertical
+mode, in order to make a box.
+
+@<Initiate the construction of an hbox or vbox, then |return|@>=
+{@+k=cur_chr-vtop_code;saved(0)=box_context;
+if (k==hmode)
+ if ((box_context < box_flag)&&(abs(mode)==vmode))
+ scan_spec(adjusted_hbox_group, true);
+ else scan_spec(hbox_group, true);
+else{@+if (k==vmode) scan_spec(vbox_group, true);
+ else{@+scan_spec(vtop_group, true);k=vmode;
+ }
+ normal_paragraph();
+ }
+push_nest();mode=-k;
+if (k==vmode)
+ {@+prev_depth=ignore_depth;
+ if (every_vbox!=null) begin_token_list(every_vbox, every_vbox_text);
+ }
+else{@+space_factor=1000;
+ if (every_hbox!=null) begin_token_list(every_hbox, every_hbox_text);
+ }
+return;
+}
+
+@ @<Declare act...@>=
+void scan_box(int @!box_context)
+ /*the next input should specify a box or perhaps a rule*/
+{@+@<Get the next non-blank non-relax...@>;
+if (cur_cmd==make_box) begin_box(box_context);
+else if ((box_context >= leader_flag)&&((cur_cmd==hrule)||(cur_cmd==vrule)))
+ {@+cur_box=scan_rule_spec();box_end(box_context);
+ }
+else{@+@t@>@;@/
+ print_err("A <box> was supposed to be here");@/
+@.A <box> was supposed to...@>
+ help3("I was expecting to see \\hbox or \\vbox or \\copy or \\box or")@/
+ ("something like that. So you might find something missing in")@/
+ ("your output. But keep trying; you can fix this later.");back_error();
+ }
+}
+
+@ When the right brace occurs at the end of an \.{\\hbox} or \.{\\vbox} or
+\.{\\vtop} construction, the |package| routine comes into action. We might
+also have to finish a paragraph that hasn't ended.
+
+@<Cases of |handle...@>=
+case hbox_group: package(0);@+break;
+case adjusted_hbox_group: {@+adjust_tail=adjust_head;package(0);
+ } @+break;
+case vbox_group: {@+end_graf();package(0);
+ } @+break;
+case vtop_group: {@+end_graf();package(vtop_code);
+ } @+break;
+
+@ @<Declare action...@>=
+void package(small_number @!c)
+{@+scaled h; /*height of box*/
+pointer @!p; /*first node in a box*/
+scaled @!d; /*max depth*/
+d=box_max_depth;unsave();save_ptr=save_ptr-3;
+if (mode==-hmode) cur_box=hpack(link(head), saved(2), saved(1));
+else{@+cur_box=vpackage(link(head), saved(2), saved(1), d);
+ if (c==vtop_code) @<Readjust the height and depth of |cur_box|, for \.{\\vtop}@>;
+ }
+pop_nest();box_end(saved(0));
+}
+
+@ The height of a `\.{\\vtop}' box is inherited from the first item on its list,
+if that item is an |hlist_node|, |vlist_node|, or |rule_node|; otherwise
+the \.{\\vtop} height is zero.
+
+
+@<Readjust the height...@>=
+{@+h=0;p=list_ptr(cur_box);
+if (p!=null) if (type(p) <= rule_node) h=height(p);
+depth(cur_box)=depth(cur_box)-h+height(cur_box);height(cur_box)=h;
+}
+
+@ A paragraph begins when horizontal-mode material occurs in vertical mode,
+or when the paragraph is explicitly started by `\.{\\indent}' or
+`\.{\\noindent}'.
+
+@<Put each...@>=
+primitive(@[@<|"indent"|@>@], start_par, 1);
+@!@:indent_}{\.{\\indent} primitive@>
+primitive(@[@<|"noindent"|@>@], start_par, 0);
+@!@:no_indent_}{\.{\\noindent} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case start_par: if (chr_code==0) print_esc(@[@<|"noindent"|@>@]);@+else print_esc(@[@<|"indent"|@>@]);@+break;
+
+@ @<Cases of |main_control| that build...@>=
+case vmode+start_par: new_graf(cur_chr > 0);@+break;
+case vmode+letter: case vmode+other_char: case vmode+char_num: case vmode+char_given:
+ case vmode+math_shift: case vmode+un_hbox: case vmode+vrule:
+ case vmode+accent: case vmode+discretionary: case vmode+hskip: case vmode+valign:
+ case vmode+ex_space: case vmode+no_boundary: @t@>@;@/
+ {@+back_input();new_graf(true);
+ } @+break;
+
+@ @<Declare act...@>=
+small_number norm_min(int @!h)
+{@+if (h <= 0) return 1;@+else if (h >= 63) return 63;@+
+else return h;
+}
+@#
+void new_graf(bool @!indented)
+{@+prev_graf=0;
+if ((mode==vmode)||(head!=tail))
+ tail_append(new_param_glue(par_skip_code));
+push_nest();mode=hmode;space_factor=1000;set_cur_lang;clang=cur_lang;
+prev_graf=(norm_min(left_hyphen_min)*0100+norm_min(right_hyphen_min))
+ *0200000+cur_lang;
+if (indented)
+ {@+tail=new_null_box();link(head)=tail;width(tail)=par_indent;@+
+ }
+if (every_par!=null) begin_token_list(every_par, every_par_text);
+if (nest_ptr==1) build_page(); /*put |par_skip| glue on current page*/
+}
+
+@ @<Cases of |main_control| that build...@>=
+case hmode+start_par: case mmode+start_par: indent_in_hmode();@+break;
+
+@ @<Declare act...@>=
+void indent_in_hmode(void)
+{@+pointer p, @!q;
+if (cur_chr > 0) /*\.{\\indent}*/
+ {@+p=new_null_box();width(p)=par_indent;
+ if (abs(mode)==hmode) space_factor=1000;
+ else{@+q=new_noad();math_type(nucleus(q))=sub_box;
+ info(nucleus(q))=p;p=q;
+ }
+ tail_append(p);
+ }
+}
+
+@ A paragraph ends when a |par_end| command is sensed, or when we are in
+horizontal mode when reaching the right brace of vertical-mode routines
+like \.{\\vbox}, \.{\\insert}, or \.{\\output}.
+
+@<Cases of |main_control| that build...@>=
+case vmode+par_end: {@+normal_paragraph();
+ if (mode > 0) build_page();
+ } @+break;
+case hmode+par_end: {@+if (align_state < 0) off_save(); /*this tries to
+ recover from an alignment that didn't end properly*/
+ end_graf(); /*this takes us to the enclosing mode, if |mode > 0|*/
+ if (mode==vmode) build_page();
+ } @+break;
+case hmode+stop: case hmode+vskip: case hmode+hrule: case hmode+un_vbox: case hmode+halign: head_for_vmode();@+break;
+
+@ @<Declare act...@>=
+void head_for_vmode(void)
+{@+if (mode < 0)
+ if (cur_cmd!=hrule) off_save();
+ else{@+print_err("You can't use `");
+ print_esc(@[@<|"hrule"|@>@]);print_str("' here except with leaders");
+@.You can't use \\hrule...@>
+ help2("To put a horizontal rule in an hbox or an alignment,")@/
+ ("you should use \\leaders or \\hrulefill (see The TeXbook).");
+ error();
+ }
+else{@+back_input();cur_tok=par_token;back_input();token_type=inserted;
+ }
+}
+
+@ @<Declare act...@>=
+void end_graf(void)
+{@+if (mode==hmode)
+ {@+if (head==tail) pop_nest(); /*null paragraphs are ignored*/
+ else line_break(widow_penalty);
+ normal_paragraph();
+ error_count=0;
+ }
+}
+
+@ Insertion and adjustment and mark nodes are constructed by the following
+pieces of the program.
+
+@<Cases of |main_control| that build...@>=
+any_mode(insert): case hmode+vadjust: case mmode+vadjust: begin_insert_or_adjust();@+break;
+any_mode(mark): make_mark();@+break;
+
+@ @<Forbidden...@>=
+case vmode+vadjust:
+
+@ @<Declare act...@>=
+void begin_insert_or_adjust(void)
+{@+if (cur_cmd==vadjust) cur_val=255;
+else{@+scan_eight_bit_int();
+ if (cur_val==255)
+ {@+print_err("You can't ");print_esc(@[@<|"insert"|@>@]);print_int(255);
+@.You can't \\insert255@>
+ help1("I'm changing to \\insert0; box 255 is special.");
+ error();cur_val=0;
+ }
+ }
+saved(0)=cur_val;incr(save_ptr);
+new_save_level(insert_group);scan_left_brace();normal_paragraph();
+push_nest();mode=-vmode;prev_depth=ignore_depth;
+}
+
+@ @<Cases of |handle...@>=
+case insert_group: {@+end_graf();q=split_top_skip;add_glue_ref(q);
+ d=split_max_depth;f=floating_penalty;unsave();decr(save_ptr);
+ /*now |saved(0)| is the insertion number, or 255 for |vadjust|*/
+ p=vpack(link(head), natural);pop_nest();
+ if (saved(0) < 255)
+ {@+tail_append(get_node(ins_node_size));
+ type(tail)=ins_node;subtype(tail)=qi(saved(0));
+ height(tail)=height(p)+depth(p);ins_ptr(tail)=list_ptr(p);
+ split_top_ptr(tail)=q;depth(tail)=d;float_cost(tail)=f;
+ }
+ else{@+tail_append(get_node(small_node_size));
+ type(tail)=adjust_node;@/
+ subtype(tail)=0; /*the |subtype| is not used*/
+ adjust_ptr(tail)=list_ptr(p);delete_glue_ref(q);
+ }
+ free_node(p, box_node_size);
+ if (nest_ptr==0) build_page();
+ } @+break;
+case output_group: @<Resume the page builder...@>@;@+break;
+
+@ @<Declare act...@>=
+void make_mark(void)
+{@+pointer p; /*new node*/
+p=scan_toks(false, true);p=get_node(small_node_size);
+type(p)=mark_node;subtype(p)=0; /*the |subtype| is not used*/
+mark_ptr(p)=def_ref;link(tail)=p;tail=p;
+}
+
+@ Penalty nodes get into a list via the |break_penalty| command.
+@^penalties@>
+
+@<Cases of |main_control| that build...@>=
+any_mode(break_penalty): append_penalty();@+break;
+
+@ @<Declare action...@>=
+void append_penalty(void)
+{@+scan_int();tail_append(new_penalty(cur_val));
+if (mode==vmode) build_page();
+}
+
+@ The |remove_item| command removes a penalty, kern, or glue node if it
+appears at the tail of the current list, using a brute-force linear scan.
+Like \.{\\lastbox}, this command is not allowed in vertical mode (except
+internal vertical mode), since the current list in vertical mode is sent
+to the page builder. But if we happen to be able to implement it in
+vertical mode, we do.
+
+@<Cases of |main_control| that build...@>=
+any_mode(remove_item): delete_last();@+break;
+
+@ When |delete_last| is called, |cur_chr| is the |type| of node that
+will be deleted, if present.
+
+@<Declare action...@>=
+void delete_last(void)
+{@+
+pointer @!p, @!q; /*run through the current list*/
+int @!m; /*the length of a replacement list*/
+if ((mode==vmode)&&(tail==head))
+ @<Apologize for inability to do the operation now, unless \.{\\unskip} follows non-glue@>@;
+else{@+if (!is_char_node(tail)) if (type(tail)==cur_chr)
+ {@+q=head;
+ @/do@+{p=q;
+ if (!is_char_node(q)) if (type(q)==disc_node)
+ {@+for (m=1; m<=replace_count(q); m++) p=link(p);
+ if (p==tail) return;
+ }
+ q=link(p);
+ }@+ while (!(q==tail));
+ link(p)=null;flush_node_list(tail);tail=p;
+ }
+ }
+}
+
+@ @<Apologize for inability to do the operation...@>=
+{@+if ((cur_chr!=glue_node)||(last_glue!=max_halfword))
+ {@+you_cant();
+ help2("Sorry...I usually can't take things from the current page.")@/
+ ("Try `I\\vskip-\\lastskip' instead.");
+ if (cur_chr==kern_node) help_line[0]=
+ ("Try `I\\kern-\\lastkern' instead.");
+ else if (cur_chr!=glue_node) help_line[0]=@|
+ ("Perhaps you can make the output routine do it.");
+ error();
+ }
+}
+
+@ @<Put each...@>=
+primitive(@[@<|"unpenalty"|@>@], remove_item, penalty_node);@/
+@!@:un_penalty_}{\.{\\unpenalty} primitive@>
+primitive(@[@<|"unkern"|@>@], remove_item, kern_node);@/
+@!@:un_kern_}{\.{\\unkern} primitive@>
+primitive(@[@<|"unskip"|@>@], remove_item, glue_node);@/
+@!@:un_skip_}{\.{\\unskip} primitive@>
+primitive(@[@<|"unhbox"|@>@], un_hbox, box_code);@/
+@!@:un_hbox_}{\.{\\unhbox} primitive@>
+primitive(@[@<|"unhcopy"|@>@], un_hbox, copy_code);@/
+@!@:un_hcopy_}{\.{\\unhcopy} primitive@>
+primitive(@[@<|"unvbox"|@>@], un_vbox, box_code);@/
+@!@:un_vbox_}{\.{\\unvbox} primitive@>
+primitive(@[@<|"unvcopy"|@>@], un_vbox, copy_code);@/
+@!@:un_vcopy_}{\.{\\unvcopy} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case remove_item: if (chr_code==glue_node) print_esc(@[@<|"unskip"|@>@]);
+ else if (chr_code==kern_node) print_esc(@[@<|"unkern"|@>@]);
+ else print_esc(@[@<|"unpenalty"|@>@]);@+break;
+case un_hbox: if (chr_code==copy_code) print_esc(@[@<|"unhcopy"|@>@]);
+ else print_esc(@[@<|"unhbox"|@>@]);@+break;
+case un_vbox: if (chr_code==copy_code) print_esc(@[@<|"unvcopy"|@>@]);
+ else print_esc(@[@<|"unvbox"|@>@]);@+break;
+
+@ The |un_hbox| and |un_vbox| commands unwrap one of the 256 current boxes.
+
+@<Cases of |main_control| that build...@>=
+case vmode+un_vbox: case hmode+un_hbox: case mmode+un_hbox: unpackage();@+break;
+
+@ @<Declare act...@>=
+void unpackage(void)
+{@+
+pointer p; /*the box*/
+uint8_t @!c; /*should we copy?*/
+c=cur_chr;scan_eight_bit_int();p=box(cur_val);
+if (p==null) return;
+if ((abs(mode)==mmode)||((abs(mode)==vmode)&&(type(p)!=vlist_node))||@|
+ ((abs(mode)==hmode)&&(type(p)!=hlist_node)))
+ {@+print_err("Incompatible list can't be unboxed");
+@.Incompatible list...@>
+ help3("Sorry, Pandora. (You sneaky devil.)")@/
+ ("I refuse to unbox an \\hbox in vertical mode or vice versa.")@/
+ ("And I can't open any boxes in math mode.");@/
+ error();return;
+ }
+if (c==copy_code) link(tail)=copy_node_list(list_ptr(p));
+else{@+link(tail)=list_ptr(p);box(cur_val)=null;
+ free_node(p, box_node_size);
+ }
+while (link(tail)!=null) tail=link(tail);
+}
+
+@ @<Forbidden...@>=case vmode+ital_corr:
+
+@ Italic corrections are converted to kern nodes when the |ital_corr| command
+follows a character. In math mode the same effect is achieved by appending
+a kern of zero here, since italic corrections are supplied later.
+
+@<Cases of |main_control| that build...@>=
+case hmode+ital_corr: append_italic_correction();@+break;
+case mmode+ital_corr: tail_append(new_kern(0))@;@+break;
+
+@ @<Declare act...@>=
+void append_italic_correction(void)
+{@+
+pointer p; /*|char_node| at the tail of the current list*/
+internal_font_number @!f; /*the font in the |char_node|*/
+if (tail!=head)
+ {@+if (is_char_node(tail)) p=tail;
+ else if (type(tail)==ligature_node) p=lig_char(tail);
+ else return;
+ f=font(p);
+ tail_append(new_kern(char_italic(f)(char_info(f)(character(p)))));
+ subtype(tail)=explicit;
+ }
+}
+
+@ Discretionary nodes are easy in the common case `\.{\\-}', but in the
+general case we must process three braces full of items.
+
+@<Put each...@>=
+primitive('-', discretionary, 1);
+@!@:Single-character primitives -}{\quad\.{\\-}@>
+primitive(@[@<|"discretionary"|@>@], discretionary, 0);
+@!@:discretionary_}{\.{\\discretionary} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case discretionary: if (chr_code==1)
+ print_esc('-');@+else print_esc(@[@<|"discretionary"|@>@]);@+break;
+
+@ @<Cases of |main_control| that build...@>=
+case hmode+discretionary: case mmode+discretionary: append_discretionary();@+break;
+
+@ The space factor does not change when we append a discretionary node,
+but it starts out as 1000 in the subsidiary lists.
+
+@<Declare act...@>=
+void append_discretionary(void)
+{@+int c; /*hyphen character*/
+tail_append(new_disc());
+if (cur_chr==1)
+ {@+c=hyphen_char[cur_font];
+ if (c >= 0) if (c < 256) pre_break(tail)=new_character(cur_font, c);
+ }
+else{@+incr(save_ptr);saved(-1)=0;new_save_level(disc_group);
+ scan_left_brace();push_nest();mode=-hmode;space_factor=1000;
+ }
+}
+
+@ The three discretionary lists are constructed somewhat as if they were
+hboxes. A~subroutine called |build_discretionary| handles the transitions.
+(This is sort of fun.)
+
+@<Cases of |handle...@>=
+case disc_group: build_discretionary();@+break;
+
+@ @<Declare act...@>=
+void build_discretionary(void)
+{@+
+pointer p, @!q; /*for link manipulation*/
+int @!n; /*length of discretionary list*/
+unsave();
+@<Prune the current list, if necessary, until it contains only |char_node|, |kern_node|,
+|hlist_node|, |vlist_node|, |rule_node|, and |ligature_node| items; set |n| to the
+length of the list, and set |q| to the list's tail@>;
+p=link(head);pop_nest();
+switch (saved(-1)) {
+case 0: pre_break(tail)=p;@+break;
+case 1: post_break(tail)=p;@+break;
+case 2: @<Attach list |p| to the current list, and record its length; then finish
+up and |return|@>;
+} /*there are no other cases*/
+incr(saved(-1));new_save_level(disc_group);scan_left_brace();
+push_nest();mode=-hmode;space_factor=1000;
+}
+
+@ @<Attach list |p| to the current...@>=
+{@+if ((n > 0)&&(abs(mode)==mmode))
+ {@+print_err("Illegal math ");print_esc(@[@<|"discretionary"|@>@]);
+@.Illegal math \\disc...@>
+ help2("Sorry: The third part of a discretionary break must be")@/
+ ("empty, in math formulas. I had to delete your third part.");
+ flush_node_list(p);n=0;error();
+ }
+else link(tail)=p;
+if (n <= max_quarterword) replace_count(tail)=n;
+else{@+print_err("Discretionary list is too long");
+@.Discretionary list is too long@>
+ help2("Wow---I never thought anybody would tweak me here.")@/
+ ("You can't seriously need such a huge discretionary list?");
+ error();
+ }
+if (n > 0) tail=q;
+decr(save_ptr);return;
+}
+
+@ During this loop, |p==link(q)| and there are |n| items preceding |p|.
+
+@<Prune the current list, if necessary...@>=
+q=head;p=link(q);n=0;
+while (p!=null)
+ {@+if (!is_char_node(p)) if (type(p) > rule_node)
+ if (type(p)!=kern_node) if (type(p)!=ligature_node)
+ {@+print_err("Improper discretionary list");
+@.Improper discretionary list@>
+ help1("Discretionary lists must contain only boxes and kerns.");@/
+ error();
+ begin_diagnostic();
+ print_nl("The following discretionary sublist has been deleted:");
+@.The following...deleted@>
+ show_box(p);
+ end_diagnostic(true);
+ flush_node_list(p);link(q)=null;goto done;
+ }
+ q=p;p=link(q);incr(n);
+ }
+done:
+
+@ We need only one more thing to complete the horizontal mode routines, namely
+the \.{\\accent} primitive.
+
+@<Cases of |main_control| that build...@>=
+case hmode+accent: make_accent();@+break;
+
+@ The positioning of accents is straightforward but tedious. Given an accent
+of width |a|, designed for characters of height |x| and slant |s|;
+and given a character of width |w|, height |h|, and slant |t|: We will shift
+the accent down by |x-h|, and we will insert kern nodes that have the effect of
+centering the accent over the character and shifting the accent to the
+right by $\delta={1\over2}(w-a)+h\cdot t-x\cdot s$. If either character is
+absent from the font, we will simply use the other, without shifting.
+
+@<Declare act...@>=
+void make_accent(void)
+{@+double s, @!t; /*amount of slant*/
+pointer @!p, @!q, @!r; /*character, box, and kern nodes*/
+internal_font_number @!f; /*relevant font*/
+scaled @!a, @!h, @!x, @!w, @!delta; /*heights and widths, as explained above*/
+four_quarters @!i; /*character information*/
+scan_char_num();f=cur_font;p=new_character(f, cur_val);
+if (p!=null)
+ {@+x=x_height(f);s=slant(f)/float_constant(65536);
+@^real division@>
+ a=char_width(f)(char_info(f)(character(p)));@/
+ do_assignments();@/
+ @<Create a character node |q| for the next character, but set |q:=null| if problems
+arise@>;
+ if (q!=null) @<Append the accent with appropriate kerns, then set |p:=q|@>;
+ link(tail)=p;tail=p;space_factor=1000;
+ }
+}
+
+@ @<Create a character node |q| for the next...@>=
+q=null;f=cur_font;
+if ((cur_cmd==letter)||(cur_cmd==other_char)||(cur_cmd==char_given))
+ q=new_character(f, cur_chr);
+else if (cur_cmd==char_num)
+ {@+scan_char_num();q=new_character(f, cur_val);
+ }
+else back_input()
+
+@ 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}.
+
+@<Append the accent with appropriate kerns...@>=
+{@+t=slant(f)/float_constant(65536);
+@^real division@>
+i=char_info(f)(character(q));
+w=char_width(f)(i);h=char_height(f)(height_depth(i));
+if (h!=x) /*the accent must be shifted up or down*/
+ {@+p=hpack(p, natural);shift_amount(p)=x-h;
+ }
+delta=round((w-a)/float_constant(2)+h*t-x*s);
+@^real multiplication@>
+@^real addition@>
+r=new_kern(delta);subtype(r)=acc_kern;link(tail)=r;link(r)=p;
+tail=new_kern(-a-delta);subtype(tail)=acc_kern;link(p)=tail;p=q;
+}
+
+@ When `\.{\\cr}' or `\.{\\span}' or a tab mark comes through the scanner
+into |main_control|, it might be that the user has foolishly inserted
+one of them into something that has nothing to do with alignment. But it is
+far more likely that a left brace or right brace has been omitted, since
+|get_next| takes actions appropriate to alignment only when `\.{\\cr}'
+or `\.{\\span}' or tab marks occur with |align_state==0|. The following
+program attempts to make an appropriate recovery.
+
+@<Cases of |main_control| that build...@>=
+any_mode(car_ret): any_mode(tab_mark): align_error();@+break;
+any_mode(no_align): no_align_error();@+break;
+any_mode(omit): omit_error();@+break;
+
+@ @<Declare act...@>=
+void align_error(void)
+{@+if (abs(align_state) > 2)
+ @<Express consternation over the fact that no alignment is in progress@>@;
+else{@+back_input();
+ if (align_state < 0)
+ {@+print_err("Missing { inserted");
+@.Missing \{ inserted@>
+ incr(align_state);cur_tok=left_brace_token+'{';
+ }
+ else{@+print_err("Missing } inserted");
+@.Missing \} inserted@>
+ decr(align_state);cur_tok=right_brace_token+'}';
+ }
+ help3("I've put in what seems to be necessary to fix")@/
+ ("the current column of the current alignment.")@/
+ ("Try to go on, since this might almost work.");ins_error();
+ }
+}
+
+@ @<Express consternation...@>=
+{@+print_err("Misplaced ");print_cmd_chr(cur_cmd, cur_chr);
+@.Misplaced \&@>
+@.Misplaced \\span@>
+@.Misplaced \\cr@>
+if (cur_tok==tab_token+'&')
+ {@+help6("I can't figure out why you would want to use a tab mark")@/
+ ("here. If you just want an ampersand, the remedy is")@/
+ ("simple: Just type `I\\&' now. But if some right brace")@/
+ ("up above has ended a previous alignment prematurely,")@/
+ ("you're probably due for more error messages, and you")@/
+ ("might try typing `S' now just to see what is salvageable.");
+ }
+else{@+help5("I can't figure out why you would want to use a tab mark")@/
+ ("or \\cr or \\span just now. If something like a right brace")@/
+ ("up above has ended a previous alignment prematurely,")@/
+ ("you're probably due for more error messages, and you")@/
+ ("might try typing `S' now just to see what is salvageable.");
+ }
+error();
+}
+
+@ The help messages here contain a little white lie, since \.{\\noalign}
+and \.{\\omit} are allowed also after `\.{\\noalign\{...\}}'.
+
+@<Declare act...@>=
+void no_align_error(void)
+{@+print_err("Misplaced ");print_esc(@[@<|"noalign"|@>@]);
+@.Misplaced \\noalign@>
+help2("I expect to see \\noalign only after the \\cr of")@/
+ ("an alignment. Proceed, and I'll ignore this case.");error();
+}
+void omit_error(void)
+{@+print_err("Misplaced ");print_esc(@[@<|"omit"|@>@]);
+@.Misplaced \\omit@>
+help2("I expect to see \\omit only after tab marks or the \\cr of")@/
+ ("an alignment. Proceed, and I'll ignore this case.");error();
+}
+
+@ We've now covered most of the abuses of \.{\\halign} and \.{\\valign}.
+Let's take a look at what happens when they are used correctly.
+
+@<Cases of |main_control| that build...@>=
+case vmode+halign: case hmode+valign: init_align();@+break;
+case mmode+halign: if (privileged())
+ if (cur_group==math_shift_group) init_align();
+ else off_save();@+break;
+case vmode+endv: case hmode+endv: do_endv();@+break;
+
+@ An |align_group| code is supposed to remain on the |save_stack|
+during an entire alignment, until |fin_align| removes it.
+
+A devious user might force an |endv| command to occur just about anywhere;
+we must defeat such hacks.
+
+@<Declare act...@>=
+void do_endv(void)
+{@+base_ptr=input_ptr;input_stack[base_ptr]=cur_input;
+while ((input_stack[base_ptr].index_field!=v_template)&&
+ (input_stack[base_ptr].loc_field==null)&&
+ (input_stack[base_ptr].state_field==token_list)) decr(base_ptr);
+if ((input_stack[base_ptr].index_field!=v_template)||
+ (input_stack[base_ptr].loc_field!=null)||
+ (input_stack[base_ptr].state_field!=token_list))
+ fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+ if (cur_group==align_group)
+ {@+end_graf();
+ if (fin_col()) fin_row();
+ }
+else off_save();
+}
+
+@ @<Cases of |handle_right_brace|...@>=
+case align_group: {@+back_input();cur_tok=cs_token_flag+frozen_cr;
+ print_err("Missing ");print_esc(@[@<|"cr"|@>@]);print_str(" inserted");
+@.Missing \\cr inserted@>
+ help1("I'm guessing that you meant to end an alignment here.");
+ ins_error();
+ } @+break;
+
+@ @<Cases of |handle_right_brace|...@>=
+case no_align_group: {@+end_graf();unsave();align_peek();
+ } @+break;
+
+@ Finally, \.{\\endcsname} is not supposed to get through to |main_control|.
+
+@<Cases of |main_control| that build...@>=
+any_mode(end_cs_name): cs_error();@+break;
+
+@ @<Declare act...@>=
+void cs_error(void)
+{@+print_err("Extra ");print_esc(@[@<|"endcsname"|@>@]);
+@.Extra \\endcsname@>
+help1("I'm ignoring this, since I wasn't doing a \\csname.");
+error();
+}
+
+@* Building math lists.
+The routines that \TeX\ uses to create mlists are similar to those we have
+just seen for the generation of hlists and vlists. But it is necessary to
+make ``noads'' as well as nodes, so the reader should review the
+discussion of math mode data structures before trying to make sense out of
+the following program.
+
+Here is a little routine that needs to be done whenever a subformula
+is about to be processed. The parameter is a code like |math_group|.
+
+@<Declare act...@>=
+void push_math(group_code @!c)
+{@+push_nest();mode=-mmode;incompleat_noad=null;new_save_level(c);
+}
+
+@ We get into math mode from horizontal mode when a `\.\$' (i.e., a
+|math_shift| character) is scanned. We must check to see whether this
+`\.\$' is immediately followed by another, in case display math mode is
+called for.
+
+@<Cases of |main_control| that build...@>=
+case hmode+math_shift: init_math();@+break;
+
+@ @<Declare act...@>=
+void init_math(void)
+{@+
+scaled w; /*new or partial |pre_display_size|*/
+scaled @!l; /*new |display_width|*/
+scaled @!s; /*new |display_indent|*/
+pointer @!p; /*current node when calculating |pre_display_size|*/
+pointer @!q; /*glue specification when calculating |pre_display_size|*/
+internal_font_number @!f; /*font in current |char_node|*/
+int @!n; /*scope of paragraph shape specification*/
+scaled @!v; /*|w| plus possible glue amount*/
+scaled @!d; /*increment to |v|*/
+get_token(); /*|get_x_token| would fail on \.{\\ifmmode}\thinspace!*/
+if ((cur_cmd==math_shift)&&(mode > 0)) @<Go into display math mode@>@;
+else{@+back_input();@<Go into ordinary math mode@>;
+ }
+}
+
+@ @<Go into ordinary math mode@>=
+{@+push_math(math_shift_group);eq_word_define(int_base+cur_fam_code,-1);
+if (every_math!=null) begin_token_list(every_math, every_math_text);
+}
+
+@ We get into ordinary math mode from display math mode when `\.{\\eqno}' or
+`\.{\\leqno}' appears. In such cases |cur_chr| will be 0 or~1, respectively;
+the value of |cur_chr| is placed onto |save_stack| for safe keeping.
+
+@<Cases of |main_control| that build...@>=
+case mmode+eq_no: if (privileged())
+ if (cur_group==math_shift_group) start_eq_no();
+ else off_save();@+break;
+
+@ @<Put each...@>=
+primitive(@[@<|"eqno"|@>@], eq_no, 0);
+@!@:eq_no_}{\.{\\eqno} primitive@>
+primitive(@[@<|"leqno"|@>@], eq_no, 1);
+@!@:leq_no_}{\.{\\leqno} primitive@>
+
+@ When \TeX\ is in display math mode, |cur_group==math_shift_group|,
+so it is not necessary for the |start_eq_no| procedure to test for
+this condition.
+
+@<Declare act...@>=
+void start_eq_no(void)
+{@+saved(0)=cur_chr;incr(save_ptr);
+@<Go into ordinary math mode@>;
+}
+
+@ @<Cases of |print_cmd_chr|...@>=
+case eq_no: if (chr_code==1) print_esc(@[@<|"leqno"|@>@]);@+else print_esc(@[@<|"eqno"|@>@]);@+break;
+
+@ @<Forbidden...@>=non_math(eq_no):
+
+@ When we enter display math mode, we need to call |line_break| to
+process the partial paragraph that has just been interrupted by the
+display. Then we can set the proper values of |display_width| and
+|display_indent| and |pre_display_size|.
+
+@<Go into display math mode@>=
+{@+if (head==tail) /*`\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}'*/
+ {@+pop_nest();w=-max_dimen;
+ }
+else{@+line_break(display_widow_penalty);@/
+ @<Calculate the natural width, |w|, by which the characters of the final line extend
+to the right of the reference point, plus two ems; or set |w:=max_dimen| if the non-blank
+information on that line is affected by stretching or shrinking@>;
+ }
+ /*now we are in vertical mode, working on the list that will contain the display*/
+@<Calculate the length, |l|, and the shift amount, |s|, of the display lines@>;
+push_math(math_shift_group);mode=mmode;
+eq_word_define(int_base+cur_fam_code,-1);@/
+eq_word_define(dimen_base+pre_display_size_code, w);
+eq_word_define(dimen_base+display_width_code, l);
+eq_word_define(dimen_base+display_indent_code, s);
+if (every_display!=null) begin_token_list(every_display, every_display_text);
+if (nest_ptr==1) build_page();
+}
+
+@ @<Calculate the natural width, |w|, by which...@>=
+v=shift_amount(just_box)+2*quad(cur_font);w=-max_dimen;
+p=list_ptr(just_box);
+while (p!=null)
+ {@+@<Let |d| be the natural width of node |p|; if the node is ``visible,'' |goto
+found|; if the node is glue that stretches or shrinks, set |v:=max_dimen|@>;
+ if (v < max_dimen) v=v+d;
+ goto not_found;
+ found: if (v < max_dimen)
+ {@+v=v+d;w=v;
+ }
+ else{@+w=max_dimen;goto done;
+ }
+ not_found: p=link(p);
+ }
+done:
+
+@ @<Let |d| be the natural width of node |p|...@>=
+reswitch: if (is_char_node(p))
+ {@+f=font(p);d=char_width(f)(char_info(f)(character(p)));
+ goto found;
+ }
+switch (type(p)) {
+case hlist_node: case vlist_node: case rule_node: {@+d=width(p);goto found;
+ }
+case ligature_node: @<Make node |p| look like a |char_node|...@>@;
+case kern_node: case math_node: d=width(p);@+break;
+case glue_node: @<Let |d| be the natural width of this glue; if stretching or shrinking,
+set |v:=max_dimen|; |goto found| in the case of leaders@>@;@+break;
+case whatsit_node: @<Let |d| be the width of the whatsit |p|@>;@+break;
+default:d=0;
+}
+
+@ We need to be careful that |w|, |v|, and |d| do not depend on any |glue_set|
+values, since such values are subject to system-dependent rounding.
+System-dependent numbers are not allowed to infiltrate parameters like
+|pre_display_size|, since \TeX82 is supposed to make the same decisions on all
+machines.
+
+@<Let |d| be the natural width of this glue...@>=
+{@+q=glue_ptr(p);d=width(q);
+if (glue_sign(just_box)==stretching)
+ {@+if ((glue_order(just_box)==stretch_order(q))&&@|
+ (stretch(q)!=0))
+ v=max_dimen;
+ }
+else if (glue_sign(just_box)==shrinking)
+ {@+if ((glue_order(just_box)==shrink_order(q))&&@|
+ (shrink(q)!=0))
+ v=max_dimen;
+ }
+if (subtype(p) >= a_leaders) goto found;
+}
+
+@ A displayed equation is considered to be three lines long, so we
+calculate the length and offset of line number |prev_graf+2|.
+
+@<Calculate the length, |l|,...@>=
+if (par_shape_ptr==null)
+ if ((hang_indent!=0)&&@|
+ (((hang_after >= 0)&&(prev_graf+2 > hang_after))||@|
+ (prev_graf+1 < -hang_after)))
+ {@+l=hsize-abs(hang_indent);
+ if (hang_indent > 0) s=hang_indent;@+else s=0;
+ }
+ else{@+l=hsize;s=0;
+ }
+else{@+n=info(par_shape_ptr);
+ if (prev_graf+2 >= n) p=par_shape_ptr+2*n;
+ else p=par_shape_ptr+2*(prev_graf+2);
+ s=mem[p-1].sc;l=mem[p].sc;
+ }
+
+@ Subformulas of math formulas cause a new level of math mode to be entered,
+on the semantic nest as well as the save stack. These subformulas arise in
+several ways: (1)~A left brace by itself indicates the beginning of a
+subformula that will be put into a box, thereby freezing its glue and
+preventing line breaks. (2)~A subscript or superscript is treated as a
+subformula if it is not a single character; the same applies to
+the nucleus of things like \.{\\underline}. (3)~The \.{\\left} primitive
+initiates a subformula that will be terminated by a matching \.{\\right}.
+The group codes placed on |save_stack| in these three cases are
+|math_group|, |math_group|, and |math_left_group|, respectively.
+
+Here is the code that handles case (1); the other cases are not quite as
+trivial, so we shall consider them later.
+
+@<Cases of |main_control| that build...@>=
+case mmode+left_brace: {@+tail_append(new_noad());
+ back_input();scan_math(nucleus(tail));
+ } @+break;
+
+@ Recall that the |nucleus|, |subscr|, and |supscr| fields in a noad are
+broken down into subfields called |math_type| and either |info| or
+|(fam, character)|. The job of |scan_math| is to figure out what to place
+in one of these principal fields; it looks at the subformula that
+comes next in the input, and places an encoding of that subformula
+into a given word of |mem|.
+
+@d fam_in_range ((cur_fam >= 0)&&(cur_fam < 16))
+
+@<Declare act...@>=
+void scan_math(pointer @!p)
+{@+
+int c; /*math character code*/
+restart: @<Get the next non-blank non-relax...@>;
+reswitch: switch (cur_cmd) {
+case letter: case other_char: case char_given: {@+c=ho(math_code(cur_chr));
+ if (c==0100000)
+ {@+@<Treat |cur_chr| as an active character@>;
+ goto restart;
+ }
+ } @+break;
+case char_num: {@+scan_char_num();cur_chr=cur_val;cur_cmd=char_given;
+ goto reswitch;
+ }
+case math_char_num: {@+scan_fifteen_bit_int();c=cur_val;
+ } @+break;
+case math_given: c=cur_chr;@+break;
+case delim_num: {@+scan_twenty_seven_bit_int();c=cur_val/010000;
+ } @+break;
+default:@<Scan a subformula enclosed in braces and |return|@>@;
+} @/
+math_type(p)=math_char;character(p)=qi(c%256);
+if ((c >= var_code)&&fam_in_range) fam(p)=cur_fam;
+else fam(p)=(c/256)%16;
+}
+
+@ An active character that is an |outer_call| is allowed here.
+
+@<Treat |cur_chr|...@>=
+{@+cur_cs=cur_chr+active_base;
+cur_cmd=eq_type(cur_cs);cur_chr=equiv(cur_cs);
+x_token();back_input();
+}
+
+@ The pointer |p| is placed on |save_stack| while a complex subformula
+is being scanned.
+
+@<Scan a subformula...@>=
+{@+back_input();scan_left_brace();@/
+saved(0)=p;incr(save_ptr);push_math(math_group);return;
+}
+
+@ The simplest math formula is, of course, `\.{\${ }\$}', when no noads are
+generated. The next simplest cases involve a single character, e.g.,
+`\.{\$x\$}'. Even though such cases may not seem to be very interesting,
+the reader can perhaps understand how happy the author was when `\.{\$x\$}'
+was first properly typeset by \TeX. The code in this section was used.
+@^Knuth, Donald Ervin@>
+
+@<Cases of |main_control| that build...@>=
+case mmode+letter: case mmode+other_char: case mmode+char_given:
+ set_math_char(ho(math_code(cur_chr)));@+break;
+case mmode+char_num: {@+scan_char_num();cur_chr=cur_val;
+ set_math_char(ho(math_code(cur_chr)));
+ } @+break;
+case mmode+math_char_num: {@+scan_fifteen_bit_int();set_math_char(cur_val);
+ } @+break;
+case mmode+math_given: set_math_char(cur_chr);@+break;
+case mmode+delim_num: {@+scan_twenty_seven_bit_int();
+ set_math_char(cur_val/010000);
+ } @+break;
+
+@ The |set_math_char| procedure creates a new noad appropriate to a given
+math code, and appends it to the current mlist. However, if the math code
+is sufficiently large, the |cur_chr| is treated as an active character and
+nothing is appended.
+
+@<Declare act...@>=
+void set_math_char(int @!c)
+{@+pointer p; /*the new noad*/
+if (c >= 0100000)
+ @<Treat |cur_chr|...@>@;
+else{@+p=new_noad();math_type(nucleus(p))=math_char;
+ character(nucleus(p))=qi(c%256);
+ fam(nucleus(p))=(c/256)%16;
+ if (c >= var_code)
+ {@+if (fam_in_range) fam(nucleus(p))=cur_fam;
+ type(p)=ord_noad;
+ }
+ else type(p)=ord_noad+(c/010000);
+ link(tail)=p;tail=p;
+ }
+}
+
+@ Primitive math operators like \.{\\mathop} and \.{\\underline} are given
+the command code |math_comp|, supplemented by the noad type that they
+generate.
+
+@<Put each...@>=
+primitive(@[@<|"mathord"|@>@], math_comp, ord_noad);
+@!@:math_ord_}{\.{\\mathord} primitive@>
+primitive(@[@<|"mathop"|@>@], math_comp, op_noad);
+@!@:math_op_}{\.{\\mathop} primitive@>
+primitive(@[@<|"mathbin"|@>@], math_comp, bin_noad);
+@!@:math_bin_}{\.{\\mathbin} primitive@>
+primitive(@[@<|"mathrel"|@>@], math_comp, rel_noad);
+@!@:math_rel_}{\.{\\mathrel} primitive@>
+primitive(@[@<|"mathopen"|@>@], math_comp, open_noad);
+@!@:math_open_}{\.{\\mathopen} primitive@>
+primitive(@[@<|"mathclose"|@>@], math_comp, close_noad);
+@!@:math_close_}{\.{\\mathclose} primitive@>
+primitive(@[@<|"mathpunct"|@>@], math_comp, punct_noad);
+@!@:math_punct_}{\.{\\mathpunct} primitive@>
+primitive(@[@<|"mathinner"|@>@], math_comp, inner_noad);
+@!@:math_inner_}{\.{\\mathinner} primitive@>
+primitive(@[@<|"underline"|@>@], math_comp, under_noad);
+@!@:underline_}{\.{\\underline} primitive@>
+primitive(@[@<|"overline"|@>@], math_comp, over_noad);@/
+@!@:overline_}{\.{\\overline} primitive@>
+primitive(@[@<|"displaylimits"|@>@], limit_switch, normal);
+@!@:display_limits_}{\.{\\displaylimits} primitive@>
+primitive(@[@<|"limits"|@>@], limit_switch, limits);
+@!@:limits_}{\.{\\limits} primitive@>
+primitive(@[@<|"nolimits"|@>@], limit_switch, no_limits);
+@!@:no_limits_}{\.{\\nolimits} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case math_comp: switch (chr_code) {
+ case ord_noad: print_esc(@[@<|"mathord"|@>@]);@+break;
+ case op_noad: print_esc(@[@<|"mathop"|@>@]);@+break;
+ case bin_noad: print_esc(@[@<|"mathbin"|@>@]);@+break;
+ case rel_noad: print_esc(@[@<|"mathrel"|@>@]);@+break;
+ case open_noad: print_esc(@[@<|"mathopen"|@>@]);@+break;
+ case close_noad: print_esc(@[@<|"mathclose"|@>@]);@+break;
+ case punct_noad: print_esc(@[@<|"mathpunct"|@>@]);@+break;
+ case inner_noad: print_esc(@[@<|"mathinner"|@>@]);@+break;
+ case under_noad: print_esc(@[@<|"underline"|@>@]);@+break;
+ default:print_esc(@[@<|"overline"|@>@]);
+ } @+break;
+case limit_switch: if (chr_code==limits) print_esc(@[@<|"limits"|@>@]);
+ else if (chr_code==no_limits) print_esc(@[@<|"nolimits"|@>@]);
+ else print_esc(@[@<|"displaylimits"|@>@]);@+break;
+
+@ @<Cases of |main_control| that build...@>=
+case mmode+math_comp: {@+tail_append(new_noad());
+ type(tail)=cur_chr;scan_math(nucleus(tail));
+ } @+break;
+case mmode+limit_switch: math_limit_switch();@+break;
+
+@ @<Declare act...@>=
+void math_limit_switch(void)
+{@+
+if (head!=tail) if (type(tail)==op_noad)
+ {@+subtype(tail)=cur_chr;return;
+ }
+print_err("Limit controls must follow a math operator");
+@.Limit controls must follow...@>
+help1("I'm ignoring this misplaced \\limits or \\nolimits command.");error();
+}
+
+@ Delimiter fields of noads are filled in by the |scan_delimiter| routine.
+The first parameter of this procedure is the |mem| address where the
+delimiter is to be placed; the second tells if this delimiter follows
+\.{\\radical} or not.
+
+@<Declare act...@>=
+void scan_delimiter(pointer @!p, bool @!r)
+{@+if (r) scan_twenty_seven_bit_int();
+else{@+@<Get the next non-blank non-relax...@>;
+ switch (cur_cmd) {
+ case letter: case other_char: cur_val=del_code(cur_chr);@+break;
+ case delim_num: scan_twenty_seven_bit_int();@+break;
+ default:cur_val=-1;
+ }
+ }
+if (cur_val < 0) @<Report that an invalid delimiter code is being changed to null;
+set~|cur_val:=0|@>;
+small_fam(p)=(cur_val/04000000)%16;
+small_char(p)=qi((cur_val/010000)%256);
+large_fam(p)=(cur_val/256)%16;
+large_char(p)=qi(cur_val%256);
+}
+
+@ @<Report that an invalid delimiter...@>=
+{@+print_err("Missing delimiter (. inserted)");
+@.Missing delimiter...@>
+help6("I was expecting to see something like `(' or `\\{' or")@/
+ ("`\\}' here. If you typed, e.g., `{' instead of `\\{', you")@/
+ ("should probably delete the `{' by typing `1' now, so that")@/
+ ("braces don't get unbalanced. Otherwise just proceed.")@/
+ ("Acceptable delimiters are characters whose \\delcode is")@/
+ ("nonnegative, or you can use `\\delimiter <delimiter code>'.");
+back_error();cur_val=0;
+}
+
+@ @<Cases of |main_control| that build...@>=
+case mmode+radical: math_radical();@+break;
+
+@ @<Declare act...@>=
+void math_radical(void)
+{@+tail_append(get_node(radical_noad_size));
+type(tail)=radical_noad;subtype(tail)=normal;
+mem[nucleus(tail)].hh=empty_field;
+mem[subscr(tail)].hh=empty_field;
+mem[supscr(tail)].hh=empty_field;
+scan_delimiter(left_delimiter(tail), true);scan_math(nucleus(tail));
+}
+
+@ @<Cases of |main_control| that build...@>=
+case mmode+accent: case mmode+math_accent: math_ac();@+break;
+
+@ @<Declare act...@>=
+void math_ac(void)
+{@+if (cur_cmd==accent)
+ @<Complain that the user should have said \.{\\mathaccent}@>;
+tail_append(get_node(accent_noad_size));
+type(tail)=accent_noad;subtype(tail)=normal;
+mem[nucleus(tail)].hh=empty_field;
+mem[subscr(tail)].hh=empty_field;
+mem[supscr(tail)].hh=empty_field;
+math_type(accent_chr(tail))=math_char;
+scan_fifteen_bit_int();
+character(accent_chr(tail))=qi(cur_val%256);
+if ((cur_val >= var_code)&&fam_in_range) fam(accent_chr(tail))=cur_fam;
+else fam(accent_chr(tail))=(cur_val/256)%16;
+scan_math(nucleus(tail));
+}
+
+@ @<Complain that the user should have said \.{\\mathaccent}@>=
+{@+print_err("Please use ");print_esc(@[@<|"mathaccent"|@>@]);
+print_str(" for accents in math mode");
+@.Please use \\mathaccent...@>
+help2("I'm changing \\accent to \\mathaccent here; wish me luck.")@/
+ ("(Accents are not the same in formulas as they are in text.)");
+error();
+}
+
+@ @<Cases of |main_control| that build...@>=
+case mmode+vcenter: {@+scan_spec(vcenter_group, false);normal_paragraph();
+ push_nest();mode=-vmode;prev_depth=ignore_depth;
+ if (every_vbox!=null) begin_token_list(every_vbox, every_vbox_text);
+ } @+break;
+
+@ @<Cases of |handle...@>=
+case vcenter_group: {@+end_graf();unsave();save_ptr=save_ptr-2;
+ p=vpack(link(head), saved(1), saved(0));pop_nest();
+ tail_append(new_noad());type(tail)=vcenter_noad;
+ math_type(nucleus(tail))=sub_box;info(nucleus(tail))=p;
+ } @+break;
+
+@ The routine that inserts a |style_node| holds no surprises.
+
+@<Put each...@>=
+primitive(@[@<|"displaystyle"|@>@], math_style, display_style);
+@!@:display_style_}{\.{\\displaystyle} primitive@>
+primitive(@[@<|"textstyle"|@>@], math_style, text_style);
+@!@:text_style_}{\.{\\textstyle} primitive@>
+primitive(@[@<|"scriptstyle"|@>@], math_style, script_style);
+@!@:script_style_}{\.{\\scriptstyle} primitive@>
+primitive(@[@<|"scriptscriptstyle"|@>@], math_style, script_script_style);
+@!@:script_script_style_}{\.{\\scriptscriptstyle} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case math_style: print_style(chr_code);@+break;
+
+@ @<Cases of |main_control| that build...@>=
+case mmode+math_style: tail_append(new_style(cur_chr))@;@+break;
+case mmode+non_script: {@+tail_append(new_glue(zero_glue));
+ subtype(tail)=cond_math_glue;
+ } @+break;
+case mmode+math_choice: append_choices();@+break;
+
+@ The routine that scans the four mlists of a \.{\\mathchoice} is very
+much like the routine that builds discretionary nodes.
+
+@<Declare act...@>=
+void append_choices(void)
+{@+tail_append(new_choice());incr(save_ptr);saved(-1)=0;
+push_math(math_choice_group);scan_left_brace();
+}
+
+@ @<Cases of |handle_right_brace|...@>=
+case math_choice_group: build_choices();@+break;
+
+@ @<Declare act...@>=
+@t\4@>@<Declare the function called |fin_mlist|@>@t@>@;@/
+void build_choices(void)
+{@+
+pointer p; /*the current mlist*/
+unsave();p=fin_mlist(null);
+switch (saved(-1)) {
+case 0: display_mlist(tail)=p;@+break;
+case 1: text_mlist(tail)=p;@+break;
+case 2: script_mlist(tail)=p;@+break;
+case 3: {@+script_script_mlist(tail)=p;decr(save_ptr);return;
+ }
+} /*there are no other cases*/
+incr(saved(-1));push_math(math_choice_group);scan_left_brace();
+}
+
+@ Subscripts and superscripts are attached to the previous nucleus by the
+@^superscripts@>@^subscripts@>
+action procedure called |sub_sup|. We use the facts that |sub_mark==sup_mark+1|
+and |subscr(p)==supscr(p)+1|.
+
+@<Cases of |main_control| that build...@>=
+case mmode+sub_mark: case mmode+sup_mark: sub_sup();@+break;
+
+@ @<Declare act...@>=
+void sub_sup(void)
+{@+small_number t; /*type of previous sub/superscript*/
+pointer @!p; /*field to be filled by |scan_math|*/
+t=empty;p=null;
+if (tail!=head) if (scripts_allowed(tail))
+ {@+p=supscr(tail)+cur_cmd-sup_mark; /*|supscr| or |subscr|*/
+ t=math_type(p);
+ }
+if ((p==null)||(t!=empty)) @<Insert a dummy noad to be sub/superscripted@>;
+scan_math(p);
+}
+
+@ @<Insert a dummy...@>=
+{@+tail_append(new_noad());
+p=supscr(tail)+cur_cmd-sup_mark; /*|supscr| or |subscr|*/
+if (t!=empty)
+ {@+if (cur_cmd==sup_mark)
+ {@+print_err("Double superscript");
+@.Double superscript@>
+ help1("I treat `x^1^2' essentially like `x^1{}^2'.");
+ }
+ else{@+print_err("Double subscript");
+@.Double subscript@>
+ help1("I treat `x_1_2' essentially like `x_1{}_2'.");
+ }
+ error();
+ }
+}
+
+@ An operation like `\.{\\over}' causes the current mlist to go into a
+state of suspended animation: |incompleat_noad| points to a |fraction_noad|
+that contains the mlist-so-far as its numerator, while the denominator
+is yet to come. Finally when the mlist is finished, the denominator will
+go into the incompleat fraction noad, and that noad will become the
+whole formula, unless it is surrounded by `\.{\\left}' and `\.{\\right}'
+delimiters.
+
+@d above_code 0 /* `\.{\\above}' */
+@d over_code 1 /* `\.{\\over}' */
+@d atop_code 2 /* `\.{\\atop}' */
+@d delimited_code 3 /* `\.{\\abovewithdelims}', etc.*/
+
+@<Put each...@>=
+primitive(@[@<|"above"|@>@], above, above_code);@/
+@!@:above_}{\.{\\above} primitive@>
+primitive(@[@<|"over"|@>@], above, over_code);@/
+@!@:over_}{\.{\\over} primitive@>
+primitive(@[@<|"atop"|@>@], above, atop_code);@/
+@!@:atop_}{\.{\\atop} primitive@>
+primitive(@[@<|"abovewithdelims"|@>@], above, delimited_code+above_code);@/
+@!@:above_with_delims_}{\.{\\abovewithdelims} primitive@>
+primitive(@[@<|"overwithdelims"|@>@], above, delimited_code+over_code);@/
+@!@:over_with_delims_}{\.{\\overwithdelims} primitive@>
+primitive(@[@<|"atopwithdelims"|@>@], above, delimited_code+atop_code);
+@!@:atop_with_delims_}{\.{\\atopwithdelims} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case above: switch (chr_code) {
+ case over_code: print_esc(@[@<|"over"|@>@]);@+break;
+ case atop_code: print_esc(@[@<|"atop"|@>@]);@+break;
+ case delimited_code+above_code: print_esc(@[@<|"abovewithdelims"|@>@]);@+break;
+ case delimited_code+over_code: print_esc(@[@<|"overwithdelims"|@>@]);@+break;
+ case delimited_code+atop_code: print_esc(@[@<|"atopwithdelims"|@>@]);@+break;
+ default:print_esc(@[@<|"above"|@>@]);
+ } @+break;
+
+@ @<Cases of |main_control| that build...@>=
+case mmode+above: math_fraction();@+break;
+
+@ @<Declare act...@>=
+void math_fraction(void)
+{@+small_number c; /*the type of generalized fraction we are scanning*/
+c=cur_chr;
+if (incompleat_noad!=null)
+ @<Ignore the fraction operation and complain about this ambiguous case@>@;
+else{@+incompleat_noad=get_node(fraction_noad_size);
+ type(incompleat_noad)=fraction_noad;
+ subtype(incompleat_noad)=normal;
+ math_type(numerator(incompleat_noad))=sub_mlist;
+ info(numerator(incompleat_noad))=link(head);
+ mem[denominator(incompleat_noad)].hh=empty_field;
+ mem[left_delimiter(incompleat_noad)].qqqq=null_delimiter;
+ mem[right_delimiter(incompleat_noad)].qqqq=null_delimiter;@/
+ link(head)=null;tail=head;
+ @<Use code |c| to distinguish between generalized fractions@>;
+ }
+}
+
+@ @<Use code |c|...@>=
+if (c >= delimited_code)
+ {@+scan_delimiter(left_delimiter(incompleat_noad), false);
+ scan_delimiter(right_delimiter(incompleat_noad), false);
+ }
+switch (c%delimited_code) {
+case above_code: {@+scan_normal_dimen;
+ thickness(incompleat_noad)=cur_val;
+ } @+break;
+case over_code: thickness(incompleat_noad)=default_code;@+break;
+case atop_code: thickness(incompleat_noad)=0;
+} /*there are no other cases*/
+
+@ @<Ignore the fraction...@>=
+{@+if (c >= delimited_code)
+ {@+scan_delimiter(garbage, false);scan_delimiter(garbage, false);
+ }
+if (c%delimited_code==above_code) scan_normal_dimen;
+print_err("Ambiguous; you need another { and }");
+@.Ambiguous...@>
+help3("I'm ignoring this fraction specification, since I don't")@/
+ ("know whether a construction like `x \\over y \\over z'")@/
+ ("means `{x \\over y} \\over z' or `x \\over {y \\over z}'.");
+error();
+}
+
+@ At the end of a math formula or subformula, the |fin_mlist| routine is
+called upon to return a pointer to the newly completed mlist, and to
+pop the nest back to the enclosing semantic level. The parameter to
+|fin_mlist|, if not null, points to a |right_noad| that ends the
+current mlist; this |right_noad| has not yet been appended.
+
+@<Declare the function called |fin_mlist|@>=
+pointer fin_mlist(pointer @!p)
+{@+pointer q; /*the mlist to return*/
+if (incompleat_noad!=null) @<Compleat the incompleat noad@>@;
+else{@+link(tail)=p;q=link(head);
+ }
+pop_nest();return q;
+}
+
+@ @<Compleat...@>=
+{@+math_type(denominator(incompleat_noad))=sub_mlist;
+info(denominator(incompleat_noad))=link(head);
+if (p==null) q=incompleat_noad;
+else{@+q=info(numerator(incompleat_noad));
+ if (type(q)!=left_noad) confusion(@[@<|"right"|@>@]);
+@:this can't happen right}{\quad right@>
+ info(numerator(incompleat_noad))=link(q);
+ link(q)=incompleat_noad;link(incompleat_noad)=p;
+ }
+}
+
+@ Now at last we're ready to see what happens when a right brace occurs
+in a math formula. Two special cases are simplified here: Braces are effectively
+removed when they surround a single Ord without sub/superscripts, or when they
+surround an accent that is the nucleus of an Ord atom.
+
+@<Cases of |handle...@>=
+case math_group: {@+unsave();decr(save_ptr);@/
+ math_type(saved(0))=sub_mlist;p=fin_mlist(null);info(saved(0))=p;
+ if (p!=null) if (link(p)==null)
+ if (type(p)==ord_noad)
+ {@+if (math_type(subscr(p))==empty)
+ if (math_type(supscr(p))==empty)
+ {@+mem[saved(0)].hh=mem[nucleus(p)].hh;
+ free_node(p, noad_size);
+ }
+ }
+ else if (type(p)==accent_noad) if (saved(0)==nucleus(tail))
+ if (type(tail)==ord_noad) @<Replace the tail of the list by |p|@>;
+ } @+break;
+
+@ @<Replace the tail...@>=
+{@+q=head;while (link(q)!=tail) q=link(q);
+link(q)=p;free_node(tail, noad_size);tail=p;
+}
+
+@ We have dealt with all constructions of math mode except `\.{\\left}' and
+`\.{\\right}', so the picture is completed by the following sections of
+the program.
+
+@<Put each...@>=
+primitive(@[@<|"left"|@>@], left_right, left_noad);
+@!@:left_}{\.{\\left} primitive@>
+primitive(@[@<|"right"|@>@], left_right, right_noad);
+@!@:right_}{\.{\\right} primitive@>
+text(frozen_right)=@[@<|"right"|@>@];eqtb[frozen_right]=eqtb[cur_val];
+
+@ @<Cases of |print_cmd_chr|...@>=
+case left_right: if (chr_code==left_noad) print_esc(@[@<|"left"|@>@]);
+else print_esc(@[@<|"right"|@>@]);@+break;
+
+@ @<Cases of |main_control| that build...@>=
+case mmode+left_right: math_left_right();@+break;
+
+@ @<Declare act...@>=
+void math_left_right(void)
+{@+small_number t; /*|left_noad| or |right_noad|*/
+pointer @!p; /*new noad*/
+t=cur_chr;
+if ((t==right_noad)&&(cur_group!=math_left_group))
+ @<Try to recover from mismatched \.{\\right}@>@;
+else{@+p=new_noad();type(p)=t;
+ scan_delimiter(delimiter(p), false);
+ if (t==left_noad)
+ {@+push_math(math_left_group);link(head)=p;tail=p;
+ }
+ else{@+p=fin_mlist(p);unsave(); /*end of |math_left_group|*/
+ tail_append(new_noad());type(tail)=inner_noad;
+ math_type(nucleus(tail))=sub_mlist;
+ info(nucleus(tail))=p;
+ }
+ }
+}
+
+@ @<Try to recover from mismatch...@>=
+{@+if (cur_group==math_shift_group)
+ {@+scan_delimiter(garbage, false);
+ print_err("Extra ");print_esc(@[@<|"right"|@>@]);
+@.Extra \\right.@>
+ help1("I'm ignoring a \\right that had no matching \\left.");
+ error();
+ }
+else off_save();
+}
+
+@ Here is the only way out of math mode.
+
+@<Cases of |main_control| that build...@>=
+case mmode+math_shift: if (cur_group==math_shift_group) after_math();
+ else off_save();@+break;
+
+@ @<Declare act...@>=
+void after_math(void)
+{@+bool l; /*`\.{\\leqno}' instead of `\.{\\eqno}'*/
+bool @!danger; /*not enough symbol fonts are present*/
+int @!m; /*|mmode| or |-mmode|*/
+pointer @!p; /*the formula*/
+pointer @!a; /*box containing equation number*/
+@<Local variables for finishing a displayed formula@>@;
+danger=false;
+@<Check that the necessary fonts for math symbols are present; if not, flush the current
+math lists and set |danger:=true|@>;
+m=mode;l=false;p=fin_mlist(null); /*this pops the nest*/
+if (mode==-m) /*end of equation number*/
+ {@+@<Check that another \.\$ follows@>;
+ cur_mlist=p;cur_style=text_style;mlist_penalties=false;
+ mlist_to_hlist();a=hpack(link(temp_head), natural);
+ unsave();decr(save_ptr); /*now |cur_group==math_shift_group|*/
+ if (saved(0)==1) l=true;
+ danger=false;
+ @<Check that the necessary fonts for math symbols are present; if not, flush the
+current math lists and set |danger:=true|@>;
+ m=mode;p=fin_mlist(null);
+ }
+else a=null;
+if (m < 0) @<Finish math in text@>@;
+else{@+if (a==null) @<Check that another \.\$ follows@>;
+ @<Finish displayed math@>;
+ }
+}
+
+@ @<Check that the necessary fonts...@>=
+if ((font_params[fam_fnt(2+text_size)] < total_mathsy_params)||@|
+ (font_params[fam_fnt(2+script_size)] < total_mathsy_params)||@|
+ (font_params[fam_fnt(2+script_script_size)] < total_mathsy_params))
+ {@+print_err("Math formula deleted: Insufficient symbol fonts");@/
+@.Math formula deleted...@>
+ help3("Sorry, but I can't typeset math unless \\textfont 2")@/
+ ("and \\scriptfont 2 and \\scriptscriptfont 2 have all")@/
+ ("the \\fontdimen values needed in math symbol fonts.");
+ error();flush_math();danger=true;
+ }
+else if ((font_params[fam_fnt(3+text_size)] < total_mathex_params)||@|
+ (font_params[fam_fnt(3+script_size)] < total_mathex_params)||@|
+ (font_params[fam_fnt(3+script_script_size)] < total_mathex_params))
+ {@+print_err("Math formula deleted: Insufficient extension fonts");@/
+ help3("Sorry, but I can't typeset math unless \\textfont 3")@/
+ ("and \\scriptfont 3 and \\scriptscriptfont 3 have all")@/
+ ("the \\fontdimen values needed in math extension fonts.");
+ error();flush_math();danger=true;
+ }
+
+@ The |unsave| is done after everything else here; hence an appearance of
+`\.{\\mathsurround}' inside of `\.{\$...\$}' affects the spacing at these
+particular \.\$'s. This is consistent with the conventions of
+`\.{\$\$...\$\$}', since `\.{\\abovedisplayskip}' inside a display affects the
+space above that display.
+
+@<Finish math in text@>=
+{@+tail_append(new_math(math_surround, before));
+cur_mlist=p;cur_style=text_style;mlist_penalties=(mode > 0);mlist_to_hlist();
+link(tail)=link(temp_head);
+while (link(tail)!=null) tail=link(tail);
+tail_append(new_math(math_surround, after));
+space_factor=1000;unsave();
+}
+
+@ \TeX\ gets to the following part of the program when the first `\.\$' ending
+a display has been scanned.
+
+@<Check that another \.\$ follows@>=
+{@+get_x_token();
+if (cur_cmd!=math_shift)
+ {@+print_err("Display math should end with $$");
+@.Display math...with \$\$@>
+ help2("The `$' that I just saw supposedly matches a previous `$$'.")@/
+ ("So I shall assume that you typed `$$' both times.");
+ back_error();
+ }
+}
+
+@ We have saved the worst for last: The fussiest part of math mode processing
+occurs when a displayed formula is being centered and placed with an optional
+equation number.
+
+@<Local variables for finishing...@>=
+pointer @!b; /*box containing the equation*/
+scaled @!w; /*width of the equation*/
+scaled @!z; /*width of the line*/
+scaled @!e; /*width of equation number*/
+scaled @!q; /*width of equation number plus space to separate from equation*/
+scaled @!d; /*displacement of equation in the line*/
+scaled @!s; /*move the line right this much*/
+small_number @!g1, @!g2; /*glue parameter codes for before and after*/
+pointer @!r; /*kern node used to position the display*/
+pointer @!t; /*tail of adjustment list*/
+
+@ At this time |p| points to the mlist for the formula; |a| is either
+|null| or it points to a box containing the equation number; and we are in
+vertical mode (or internal vertical mode).
+
+@<Finish displayed math@>=
+cur_mlist=p;cur_style=display_style;mlist_penalties=false;
+mlist_to_hlist();p=link(temp_head);@/
+adjust_tail=adjust_head;b=hpack(p, natural);p=list_ptr(b);
+t=adjust_tail;adjust_tail=null;@/
+w=width(b);z=display_width;s=display_indent;
+if ((a==null)||danger)
+ {@+e=0;q=0;
+ }
+else{@+e=width(a);q=e+math_quad(text_size);
+ }
+if (w+q > z)
+ @<Squeeze the equation as much as possible; if there is an equation number that
+should go on a separate line by itself, set~|e:=0|@>;
+@<Determine the displacement, |d|, of the left edge of the equation, with respect
+to the line size |z|, assuming that |l=false|@>;
+@<Append the glue or equation number preceding the display@>;
+@<Append the display and perhaps also the equation number@>;
+@<Append the glue or equation number following the display@>;
+resume_after_display()
+
+@ @<Declare act...@>=
+void resume_after_display(void)
+{@+if (cur_group!=math_shift_group) confusion(@[@<|"display"|@>@]);
+@:this can't happen display}{\quad display@>
+unsave();prev_graf=prev_graf+3;
+push_nest();mode=hmode;space_factor=1000;set_cur_lang;clang=cur_lang;
+prev_graf=(norm_min(left_hyphen_min)*0100+norm_min(right_hyphen_min))
+ *0200000+cur_lang;
+@<Scan an optional space@>;
+if (nest_ptr==1) build_page();
+}
+
+@ The user can force the equation number to go on a separate line
+by causing its width to be zero.
+
+@<Squeeze the equation as much as possible...@>=
+{@+if ((e!=0)&&((w-total_shrink[normal]+q <= z)||@|
+ (total_shrink[fil]!=0)||(total_shrink[fill]!=0)||
+ (total_shrink[filll]!=0)))
+ {@+free_node(b, box_node_size);
+ b=hpack(p, z-q, exactly);
+ }
+else{@+e=0;
+ if (w > z)
+ {@+free_node(b, box_node_size);
+ b=hpack(p, z, exactly);
+ }
+ }
+w=width(b);
+}
+
+@ We try first to center the display without regard to the existence of
+the equation number. If that would make it too close (where ``too close''
+means that the space between display and equation number is less than the
+width of the equation number), we either center it in the remaining space
+or move it as far from the equation number as possible. The latter alternative
+is taken only if the display begins with glue, since we assume that the
+user put glue there to control the spacing precisely.
+
+@<Determine the displacement, |d|, of the left edge of the equation...@>=
+d=half(z-w);
+if ((e > 0)&&(d < 2*e)) /*too close*/
+ {@+d=half(z-w-e);
+ if (p!=null) if (!is_char_node(p)) if (type(p)==glue_node) d=0;
+ }
+
+@ If the equation number is set on a line by itself, either before or
+after the formula, we append an infinite penalty so that no page break will
+separate the display from its number; and we use the same size and
+displacement for all three potential lines of the display, even though
+`\.{\\parshape}' may specify them differently.
+
+@<Append the glue or equation number preceding the display@>=
+tail_append(new_penalty(pre_display_penalty));@/
+if ((d+s <= pre_display_size)||l) /*not enough clearance*/
+ {@+g1=above_display_skip_code;g2=below_display_skip_code;
+ }
+else{@+g1=above_display_short_skip_code;
+ g2=below_display_short_skip_code;
+ }
+if (l&&(e==0)) /*it follows that |type(a)==hlist_node|*/
+ {@+shift_amount(a)=s;append_to_vlist(a);
+ tail_append(new_penalty(inf_penalty));
+ }
+else tail_append(new_param_glue(g1))
+
+@ @<Append the display and perhaps also the equation number@>=
+if (e!=0)
+ {@+r=new_kern(z-w-e-d);
+ if (l)
+ {@+link(a)=r;link(r)=b;b=a;d=0;
+ }
+ else{@+link(b)=r;link(r)=a;
+ }
+ b=hpack(b, natural);
+ }
+shift_amount(b)=s+d;append_to_vlist(b)
+
+@ @<Append the glue or equation number following the display@>=
+if ((a!=null)&&(e==0)&&!l)
+ {@+tail_append(new_penalty(inf_penalty));
+ shift_amount(a)=s+z-width(a);
+ append_to_vlist(a);
+ g2=0;
+ }
+if (t!=adjust_head) /*migrating material comes after equation number*/
+ {@+link(tail)=link(adjust_head);tail=t;
+ }
+tail_append(new_penalty(post_display_penalty));
+if (g2 > 0) tail_append(new_param_glue(g2))
+
+@ When \.{\\halign} appears in a display, the alignment routines operate
+essentially as they do in vertical mode. Then the following program is
+activated, with |p| and |q| pointing to the beginning and end of the
+resulting list, and with |aux_save| holding the |prev_depth| value.
+
+@<Finish an alignment in a display@>=
+{@+do_assignments();
+if (cur_cmd!=math_shift) @<Pontificate about improper alignment in display@>@;
+else@<Check that another \.\$ follows@>;
+pop_nest();
+tail_append(new_penalty(pre_display_penalty));
+tail_append(new_param_glue(above_display_skip_code));
+link(tail)=p;
+if (p!=null) tail=q;
+tail_append(new_penalty(post_display_penalty));
+tail_append(new_param_glue(below_display_skip_code));
+prev_depth=aux_save.sc;resume_after_display();
+}
+
+@ @<Pontificate...@>=
+{@+print_err("Missing $$ inserted");
+@.Missing {\$\$} inserted@>
+help2("Displays can use special alignments (like \\eqalignno)")@/
+ ("only if nothing but the alignment itself is between $$'s.");
+back_error();
+}
+
+@* Mode-independent processing.
+The long |main_control| procedure has now been fully specified, except for
+certain activities that are independent of the current mode. These activities
+do not change the current vlist or hlist or mlist; if they change anything,
+it is the value of a parameter or the meaning of a control sequence.
+
+Assignments to values in |eqtb| can be global or local. Furthermore, a
+control sequence can be defined to be `\.{\\long}' or `\.{\\outer}', and
+it might or might not be expanded. The prefixes `\.{\\global}', `\.{\\long}',
+and `\.{\\outer}' can occur in any order. Therefore we assign binary numeric
+codes, making it possible to accumulate the union of all specified prefixes
+by adding the corresponding codes. (\PASCAL's |set| operations could also
+have been used.)
+
+@<Put each...@>=
+primitive(@[@<|"long"|@>@], prefix, 1);
+@!@:long_}{\.{\\long} primitive@>
+primitive(@[@<|"outer"|@>@], prefix, 2);
+@!@:outer_}{\.{\\outer} primitive@>
+primitive(@[@<|"global"|@>@], prefix, 4);
+@!@:global_}{\.{\\global} primitive@>
+primitive(@[@<|"def"|@>@], def, 0);
+@!@:def_}{\.{\\def} primitive@>
+primitive(@[@<|"gdef"|@>@], def, 1);
+@!@:gdef_}{\.{\\gdef} primitive@>
+primitive(@[@<|"edef"|@>@], def, 2);
+@!@:edef_}{\.{\\edef} primitive@>
+primitive(@[@<|"xdef"|@>@], def, 3);
+@!@:xdef_}{\.{\\xdef} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case prefix: if (chr_code==1) print_esc(@[@<|"long"|@>@]);
+ else if (chr_code==2) print_esc(@[@<|"outer"|@>@]);
+ else print_esc(@[@<|"global"|@>@]);@+break;
+case def: if (chr_code==0) print_esc(@[@<|"def"|@>@]);
+ else if (chr_code==1) print_esc(@[@<|"gdef"|@>@]);
+ else if (chr_code==2) print_esc(@[@<|"edef"|@>@]);
+ else print_esc(@[@<|"xdef"|@>@]);@+break;
+
+@ Every prefix, and every command code that might or might not be prefixed,
+calls the action procedure |prefixed_command|. This routine accumulates
+a sequence of prefixes until coming to a non-prefix, then it carries out
+the command.
+
+@<Cases of |main_control| that don't...@>=
+any_mode(toks_register):
+any_mode(assign_toks):
+any_mode(assign_int):
+any_mode(assign_dimen):
+any_mode(assign_glue):
+any_mode(assign_mu_glue):
+any_mode(assign_font_dimen):
+any_mode(assign_font_int):
+any_mode(set_aux):
+any_mode(set_prev_graf):
+any_mode(set_page_dimen):
+any_mode(set_page_int):
+any_mode(set_box_dimen):
+any_mode(set_shape):
+any_mode(def_code):
+any_mode(def_family):
+any_mode(set_font):
+any_mode(def_font):
+any_mode(register):
+any_mode(advance):
+any_mode(multiply):
+any_mode(divide):
+any_mode(prefix):
+any_mode(let):
+any_mode(shorthand_def):
+any_mode(read_to_cs):
+any_mode(def):
+any_mode(set_box):
+any_mode(hyph_data):
+any_mode(set_interaction): prefixed_command();@+break;
+
+@ If the user says, e.g., `\.{\\global\\global}', the redundancy is
+silently accepted.
+
+@<Declare act...@>=
+@t\4@>@<Declare subprocedures for |prefixed_command|@>@t@>@;@/
+void prefixed_command(void)
+{@+
+small_number a; /*accumulated prefix codes so far*/
+internal_font_number @!f; /*identifies a font*/
+int @!j; /*index into a \.{\\parshape} specification*/
+font_index @!k; /*index into |font_info|*/
+pointer @!p, @!q; /*for temporary short-term use*/
+int @!n; /*ditto*/
+bool @!e; /*should a definition be expanded? or was \.{\\let} not done?*/
+a=0;
+while (cur_cmd==prefix)
+ {@+if (!odd(a/cur_chr)) a=a+cur_chr;
+ @<Get the next non-blank non-relax...@>;
+ if (cur_cmd <= max_non_prefixed_command)
+ @<Discard erroneous prefixes and |return|@>;
+ }
+@<Discard the prefixes \.{\\long} and \.{\\outer} if they are irrelevant@>;
+@<Adjust \(f)for the setting of \.{\\globaldefs}@>;
+switch (cur_cmd) {
+@t\4@>@<Assignments@>@;
+default:confusion(@[@<|"prefix"|@>@]);
+@:this can't happen prefix}{\quad prefix@>
+}
+done: @<Insert a token saved by \.{\\afterassignment}, if any@>;
+}
+
+@ @<Discard erroneous...@>=
+{@+print_err("You can't use a prefix with `");
+@.You can't use a prefix with x@>
+print_cmd_chr(cur_cmd, cur_chr);print_char('\'');
+help1("I'll pretend you didn't say \\long or \\outer or \\global.");
+back_error();return;
+}
+
+@ @<Discard the prefixes...@>=
+if ((cur_cmd!=def)&&(a%4!=0))
+ {@+print_err("You can't use `");print_esc(@[@<|"long"|@>@]);print_str("' or `");
+ print_esc(@[@<|"outer"|@>@]);print_str("' with `");
+@.You can't use \\long...@>
+ print_cmd_chr(cur_cmd, cur_chr);print_char('\'');
+ help1("I'll pretend you didn't say \\long or \\outer here.");
+ error();
+ }
+
+@ The previous routine does not have to adjust |a| so that |a%4==0|,
+since the following routines test for the \.{\\global} prefix as follows.
+
+@d global (a >= 4)
+@d define(X, Y, Z) if (global) geq_define(X, Y, Z);@+else eq_define(X, Y, Z)
+@d word_define(X, Y) if (global) geq_word_define(X, Y);@+else eq_word_define(X, Y)
+
+@<Adjust \(f)for the setting of \.{\\globaldefs}@>=
+if (global_defs!=0)
+ if (global_defs < 0)
+ {@+if (global) a=a-4;
+ }
+ else{@+if (!global) a=a+4;
+ }
+
+@ When a control sequence is to be defined, by \.{\\def} or \.{\\let} or
+something similar, the |get_r_token| routine will substitute a special
+control sequence for a token that is not redefinable.
+
+@<Declare subprocedures for |prefixed_command|@>=
+void get_r_token(void)
+{@+
+restart: @/do@+{get_token();
+}@+ while (!(cur_tok!=space_token));
+if ((cur_cs==0)||(cur_cs > frozen_control_sequence))
+ {@+print_err("Missing control sequence inserted");
+@.Missing control...@>
+ help5("Please don't say `\\def cs{...}', say `\\def\\cs{...}'.")@/
+ ("I've inserted an inaccessible control sequence so that your")@/
+ ("definition will be completed without mixing me up too badly.")@/
+ ("You can recover graciously from this error, if you're")@/
+ ("careful; see exercise 27.2 in The TeXbook.");
+@:TeXbook}{\sl The \TeX book@>
+ if (cur_cs==0) back_input();
+ cur_tok=cs_token_flag+frozen_protection;ins_error();goto restart;
+ }
+}
+
+@ @<Initialize table entries...@>=
+text(frozen_protection)=@[@<|"inaccessible"|@>@];
+
+@ Here's an example of the way many of the following routines operate.
+(Unfortunately, they aren't all as simple as this.)
+
+@<Assignments@>=
+case set_font: define(cur_font_loc, data, cur_chr);@+break;
+
+@ When a |def| command has been scanned,
+|cur_chr| is odd if the definition is supposed to be global, and
+|cur_chr >= 2| if the definition is supposed to be expanded.
+
+@<Assignments@>=
+case def: {@+if (odd(cur_chr)&&!global&&(global_defs >= 0)) a=a+4;
+ e=(cur_chr >= 2);get_r_token();p=cur_cs;
+ q=scan_toks(true, e);define(p, call+(a%4), def_ref);
+ } @+break;
+
+@ Both \.{\\let} and \.{\\futurelet} share the command code |let|.
+
+@<Put each...@>=
+primitive(@[@<|"let"|@>@], let, normal);@/
+@!@:let_}{\.{\\let} primitive@>
+primitive(@[@<|"futurelet"|@>@], let, normal+1);@/
+@!@:future_let_}{\.{\\futurelet} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case let: if (chr_code!=normal) print_esc(@[@<|"futurelet"|@>@]);@+else print_esc(@[@<|"let"|@>@]);@+break;
+
+@ @<Assignments@>=
+case let: {@+n=cur_chr;
+ get_r_token();p=cur_cs;
+ if (n==normal)
+ {@+@/do@+{get_token();
+ }@+ while (!(cur_cmd!=spacer));
+ if (cur_tok==other_token+'=')
+ {@+get_token();
+ if (cur_cmd==spacer) get_token();
+ }
+ }
+ else{@+get_token();q=cur_tok;get_token();back_input();
+ cur_tok=q;back_input(); /*look ahead, then back up*/
+ } /*note that |back_input| doesn't affect |cur_cmd|, |cur_chr|*/
+ if (cur_cmd >= call) add_token_ref(cur_chr);
+ define(p, cur_cmd, cur_chr);
+ } @+break;
+
+@ A \.{\\chardef} creates a control sequence whose |cmd| is |char_given|;
+a \.{\\mathchardef} creates a control sequence whose |cmd| is |math_given|;
+and the corresponding |chr| is the character code or math code. A \.{\\countdef}
+or \.{\\dimendef} or \.{\\skipdef} or \.{\\muskipdef} creates a control
+sequence whose |cmd| is |assign_int| or \dots\ or |assign_mu_glue|, and the
+corresponding |chr| is the |eqtb| location of the internal register in question.
+
+@d char_def_code 0 /*|shorthand_def| for \.{\\chardef}*/
+@d math_char_def_code 1 /*|shorthand_def| for \.{\\mathchardef}*/
+@d count_def_code 2 /*|shorthand_def| for \.{\\countdef}*/
+@d dimen_def_code 3 /*|shorthand_def| for \.{\\dimendef}*/
+@d skip_def_code 4 /*|shorthand_def| for \.{\\skipdef}*/
+@d mu_skip_def_code 5 /*|shorthand_def| for \.{\\muskipdef}*/
+@d toks_def_code 6 /*|shorthand_def| for \.{\\toksdef}*/
+
+@<Put each...@>=
+primitive(@[@<|"chardef"|@>@], shorthand_def, char_def_code);@/
+@!@:char_def_}{\.{\\chardef} primitive@>
+primitive(@[@<|"mathchardef"|@>@], shorthand_def, math_char_def_code);@/
+@!@:math_char_def_}{\.{\\mathchardef} primitive@>
+primitive(@[@<|"countdef"|@>@], shorthand_def, count_def_code);@/
+@!@:count_def_}{\.{\\countdef} primitive@>
+primitive(@[@<|"dimendef"|@>@], shorthand_def, dimen_def_code);@/
+@!@:dimen_def_}{\.{\\dimendef} primitive@>
+primitive(@[@<|"skipdef"|@>@], shorthand_def, skip_def_code);@/
+@!@:skip_def_}{\.{\\skipdef} primitive@>
+primitive(@[@<|"muskipdef"|@>@], shorthand_def, mu_skip_def_code);@/
+@!@:mu_skip_def_}{\.{\\muskipdef} primitive@>
+primitive(@[@<|"toksdef"|@>@], shorthand_def, toks_def_code);@/
+@!@:toks_def_}{\.{\\toksdef} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case shorthand_def: switch (chr_code) {
+ case char_def_code: print_esc(@[@<|"chardef"|@>@]);@+break;
+ case math_char_def_code: print_esc(@[@<|"mathchardef"|@>@]);@+break;
+ case count_def_code: print_esc(@[@<|"countdef"|@>@]);@+break;
+ case dimen_def_code: print_esc(@[@<|"dimendef"|@>@]);@+break;
+ case skip_def_code: print_esc(@[@<|"skipdef"|@>@]);@+break;
+ case mu_skip_def_code: print_esc(@[@<|"muskipdef"|@>@]);@+break;
+ default:print_esc(@[@<|"toksdef"|@>@]);
+ } @+break;
+case char_given: {@+print_esc(@[@<|"char"|@>@]);print_hex(chr_code);
+ } @+break;
+case math_given: {@+print_esc(@[@<|"mathchar"|@>@]);print_hex(chr_code);
+ } @+break;
+
+@ We temporarily define |p| to be |relax|, so that an occurrence of |p|
+while scanning the definition will simply stop the scanning instead of
+producing an ``undefined control sequence'' error or expanding the
+previous meaning. This allows, for instance, `\.{\\chardef\\foo=123\\foo}'.
+
+@<Assignments@>=
+case shorthand_def: {@+n=cur_chr;get_r_token();p=cur_cs;define(p, relax, 256);
+ scan_optional_equals();
+ switch (n) {
+ case char_def_code: {@+scan_char_num();define(p, char_given, cur_val);
+ } @+break;
+ case math_char_def_code: {@+scan_fifteen_bit_int();define(p, math_given, cur_val);
+ } @+break;
+ default:{@+scan_eight_bit_int();
+ switch (n) {
+ case count_def_code: define(p, assign_int, count_base+cur_val);@+break;
+ case dimen_def_code: define(p, assign_dimen, scaled_base+cur_val);@+break;
+ case skip_def_code: define(p, assign_glue, skip_base+cur_val);@+break;
+ case mu_skip_def_code: define(p, assign_mu_glue, mu_skip_base+cur_val);@+break;
+ case toks_def_code: define(p, assign_toks, toks_base+cur_val);
+ } /*there are no other cases*/
+ }
+ }
+ } @+break;
+
+@ @<Assignments@>=
+case read_to_cs: {@+scan_int();n=cur_val;
+ if (!scan_keyword(@[@<|"to"|@>@]))
+@.to@>
+ {@+print_err("Missing `to' inserted");
+@.Missing `to'...@>
+ help2("You should have said `\\read<number> to \\cs'.")@/
+ ("I'm going to look for the \\cs now.");error();
+ }
+ get_r_token();
+ p=cur_cs;read_toks(n, p);define(p, call, cur_val);
+ } @+break;
+
+@ The token-list parameters, \.{\\output} and \.{\\everypar}, etc., receive
+their values in the following way. (For safety's sake, we place an
+enclosing pair of braces around an \.{\\output} list.)
+
+@<Assignments@>=
+case toks_register: case assign_toks: {@+q=cur_cs;
+ if (cur_cmd==toks_register)
+ {@+scan_eight_bit_int();p=toks_base+cur_val;
+ }
+ else p=cur_chr; /*|p==every_par_loc| or |output_routine_loc| or \dots*/
+ scan_optional_equals();
+ @<Get the next non-blank non-relax non-call token@>;
+ if (cur_cmd!=left_brace) @<If the right-hand side is a token parameter or token
+register, finish the assignment and |goto done|@>;
+ back_input();cur_cs=q;q=scan_toks(false, false);
+ if (link(def_ref)==null) /*empty list: revert to the default*/
+ {@+define(p, undefined_cs, null);free_avail(def_ref);
+ }
+ else{@+if (p==output_routine_loc) /*enclose in curlies*/
+ {@+link(q)=get_avail();q=link(q);
+ info(q)=right_brace_token+'}';
+ q=get_avail();info(q)=left_brace_token+'{';
+ link(q)=link(def_ref);link(def_ref)=q;
+ }
+ define(p, call, def_ref);
+ }
+ } @+break;
+
+@ @<If the right-hand side is a token parameter...@>=
+{@+if (cur_cmd==toks_register)
+ {@+scan_eight_bit_int();cur_cmd=assign_toks;cur_chr=toks_base+cur_val;
+ }
+if (cur_cmd==assign_toks)
+ {@+q=equiv(cur_chr);
+ if (q==null) define(p, undefined_cs, null);
+ else{@+add_token_ref(q);define(p, call, q);
+ }
+ goto done;
+ }
+}
+
+@ Similar routines are used to assign values to the numeric parameters.
+
+@<Assignments@>=
+case assign_int: {@+p=cur_chr;scan_optional_equals();scan_int();
+ word_define(p, cur_val);
+ } @+break;
+case assign_dimen: {@+p=cur_chr;scan_optional_equals();
+ scan_normal_dimen;word_define(p, cur_val);
+ } @+break;
+case assign_glue: case assign_mu_glue: {@+p=cur_chr;n=cur_cmd;scan_optional_equals();
+ if (n==assign_mu_glue) scan_glue(mu_val);@+else scan_glue(glue_val);
+ trap_zero_glue();
+ define(p, glue_ref, cur_val);
+ } @+break;
+
+@ When a glue register or parameter becomes zero, it will always point to
+|zero_glue| because of the following procedure. (Exception: The tabskip
+glue isn't trapped while preambles are being scanned.)
+
+@<Declare subprocedures for |prefixed_command|@>=
+void trap_zero_glue(void)
+{@+if ((width(cur_val)==0)&&(stretch(cur_val)==0)&&(shrink(cur_val)==0))
+ {@+add_glue_ref(zero_glue);
+ delete_glue_ref(cur_val);cur_val=zero_glue;
+ }
+}
+
+@ The various character code tables are changed by the |def_code| commands,
+and the font families are declared by |def_family|.
+
+@<Put each...@>=
+primitive(@[@<|"catcode"|@>@], def_code, cat_code_base);
+@!@:cat_code_}{\.{\\catcode} primitive@>
+primitive(@[@<|"mathcode"|@>@], def_code, math_code_base);
+@!@:math_code_}{\.{\\mathcode} primitive@>
+primitive(@[@<|"lccode"|@>@], def_code, lc_code_base);
+@!@:lc_code_}{\.{\\lccode} primitive@>
+primitive(@[@<|"uccode"|@>@], def_code, uc_code_base);
+@!@:uc_code_}{\.{\\uccode} primitive@>
+primitive(@[@<|"sfcode"|@>@], def_code, sf_code_base);
+@!@:sf_code_}{\.{\\sfcode} primitive@>
+primitive(@[@<|"delcode"|@>@], def_code, del_code_base);
+@!@:del_code_}{\.{\\delcode} primitive@>
+primitive(@[@<|"textfont"|@>@], def_family, math_font_base);
+@!@:text_font_}{\.{\\textfont} primitive@>
+primitive(@[@<|"scriptfont"|@>@], def_family, math_font_base+script_size);
+@!@:script_font_}{\.{\\scriptfont} primitive@>
+primitive(@[@<|"scriptscriptfont"|@>@], def_family, math_font_base+script_script_size);
+@!@:script_script_font_}{\.{\\scriptscriptfont} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case def_code: if (chr_code==cat_code_base) print_esc(@[@<|"catcode"|@>@]);
+ else if (chr_code==math_code_base) print_esc(@[@<|"mathcode"|@>@]);
+ else if (chr_code==lc_code_base) print_esc(@[@<|"lccode"|@>@]);
+ else if (chr_code==uc_code_base) print_esc(@[@<|"uccode"|@>@]);
+ else if (chr_code==sf_code_base) print_esc(@[@<|"sfcode"|@>@]);
+ else print_esc(@[@<|"delcode"|@>@]);@+break;
+case def_family: print_size(chr_code-math_font_base);@+break;
+
+@ The different types of code values have different legal ranges; the
+following program is careful to check each case properly.
+
+@<Assignments@>=
+case def_code: {@+@<Let |n| be the largest legal code value, based on |cur_chr|@>;
+ p=cur_chr;scan_char_num();p=p+cur_val;scan_optional_equals();
+ scan_int();
+ if (((cur_val < 0)&&(p < del_code_base))||(cur_val > n))
+ {@+print_err("Invalid code (");print_int(cur_val);
+@.Invalid code@>
+ if (p < del_code_base) print_str("), should be in the range 0..");
+ else print_str("), should be at most ");
+ print_int(n);
+ help1("I'm going to use 0 instead of that illegal code value.");@/
+ error();cur_val=0;
+ }
+ if (p < math_code_base) define(p, data, cur_val);
+ else if (p < del_code_base) define(p, data, hi(cur_val));
+ else word_define(p, cur_val);
+ } @+break;
+
+@ @<Let |n| be the largest...@>=
+if (cur_chr==cat_code_base) n=max_char_code;
+else if (cur_chr==math_code_base) n=0100000;
+else if (cur_chr==sf_code_base) n=077777;
+else if (cur_chr==del_code_base) n=077777777;
+else n=255
+
+@ @<Assignments@>=
+case def_family: {@+p=cur_chr;scan_four_bit_int();p=p+cur_val;
+ scan_optional_equals();scan_font_ident();define(p, data, cur_val);
+ } @+break;
+
+@ Next we consider changes to \TeX's numeric registers.
+
+@<Assignments@>=
+case register: case advance: case multiply: case divide: do_register_command(a);@+break;
+
+@ We use the fact that |register < advance < multiply < divide|.
+
+@<Declare subprocedures for |prefixed_command|@>=
+void do_register_command(small_number @!a)
+{@+
+pointer l, @!q, @!r, @!s; /*for list manipulation*/
+uint8_t @!p; /*type of register involved*/
+q=cur_cmd;
+@<Compute the register location |l| and its type |p|; but |return| if invalid@>;
+if (q==register) scan_optional_equals();
+else if (scan_keyword(@[@<|"by"|@>@])) do_nothing; /*optional `\.{by}'*/
+@.by@>
+arith_error=false;
+if (q < multiply) @<Compute result of |register| or |advance|, put it in |cur_val|@>@;
+else@<Compute result of |multiply| or |divide|, put it in |cur_val|@>;
+if (arith_error)
+ {@+print_err("Arithmetic overflow");
+@.Arithmetic overflow@>
+ help2("I can't carry out that multiplication or division,")@/
+ ("since the result is out of range.");
+ if (p >= glue_val) delete_glue_ref(cur_val);
+ error();return;
+ }
+if (p < glue_val) word_define(l, cur_val);
+else{@+trap_zero_glue();define(l, glue_ref, cur_val);
+ }
+}
+
+@ 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.
+
+@<Compute the register location |l| and its type |p|...@>=
+{@+if (q!=register)
+ {@+get_x_token();
+ if ((cur_cmd >= assign_int)&&(cur_cmd <= assign_mu_glue))
+ {@+l=cur_chr;p=cur_cmd-assign_int;goto found;
+ }
+ if (cur_cmd!=register)
+ {@+print_err("You can't use `");print_cmd_chr(cur_cmd, cur_chr);
+@.You can't use x after ...@>
+ print_str("' after ");print_cmd_chr(q, 0);
+ help1("I'm forgetting what you said and not changing anything.");
+ error();return;
+ }
+ }
+p=cur_chr;scan_eight_bit_int();
+switch (p) {
+case int_val: l=cur_val+count_base;@+break;
+case dimen_val: l=cur_val+scaled_base;@+break;
+case glue_val: l=cur_val+skip_base;@+break;
+case mu_val: l=cur_val+mu_skip_base;
+} /*there are no other cases*/
+}
+found:
+
+@ @<Compute result of |register| or |advance|...@>=
+if (p < glue_val)
+ {@+if (p==int_val) scan_int();@+else scan_normal_dimen;
+ if (q==advance) cur_val=cur_val+eqtb[l].i;
+ }
+else{@+scan_glue(p);
+ if (q==advance) @<Compute the sum of two glue specs@>;
+ }
+
+@ @<Compute the sum of two glue specs@>=
+{@+q=new_spec(cur_val);r=equiv(l);
+delete_glue_ref(cur_val);
+width(q)=width(q)+width(r);
+if (stretch(q)==0) stretch_order(q)=normal;
+if (stretch_order(q)==stretch_order(r)) stretch(q)=stretch(q)+stretch(r);
+else if ((stretch_order(q) < stretch_order(r))&&(stretch(r)!=0))
+ {@+stretch(q)=stretch(r);stretch_order(q)=stretch_order(r);
+ }
+if (shrink(q)==0) shrink_order(q)=normal;
+if (shrink_order(q)==shrink_order(r)) shrink(q)=shrink(q)+shrink(r);
+else if ((shrink_order(q) < shrink_order(r))&&(shrink(r)!=0))
+ {@+shrink(q)=shrink(r);shrink_order(q)=shrink_order(r);
+ }
+cur_val=q;
+}
+
+@ @<Compute result of |multiply| or |divide|...@>=
+{@+scan_int();
+if (p < glue_val)
+ if (q==multiply)
+ if (p==int_val) cur_val=mult_integers(eqtb[l].i, cur_val);
+ else cur_val=nx_plus_y(eqtb[l].i, cur_val, 0);
+ else cur_val=x_over_n(eqtb[l].i, cur_val);
+else{@+s=equiv(l);r=new_spec(s);
+ if (q==multiply)
+ {@+width(r)=nx_plus_y(width(s), cur_val, 0);
+ stretch(r)=nx_plus_y(stretch(s), cur_val, 0);
+ shrink(r)=nx_plus_y(shrink(s), cur_val, 0);
+ }
+ else{@+width(r)=x_over_n(width(s), cur_val);
+ stretch(r)=x_over_n(stretch(s), cur_val);
+ shrink(r)=x_over_n(shrink(s), cur_val);
+ }
+ cur_val=r;
+ }
+}
+
+@ The processing of boxes is somewhat different, because we may need
+to scan and create an entire box before we actually change the value of the old
+one.
+
+@<Assignments@>=
+case set_box: {@+scan_eight_bit_int();
+ if (global) n=256+cur_val;@+else n=cur_val;
+ scan_optional_equals();
+ if (set_box_allowed) scan_box(box_flag+n);
+ else{@+print_err("Improper ");print_esc(@[@<|"setbox"|@>@]);
+@.Improper \\setbox@>
+ help2("Sorry, \\setbox is not allowed after \\halign in a display,")@/
+ ("or between \\accent and an accented character.");error();
+ }
+ } @+break;
+
+@ The |space_factor| or |prev_depth| settings are changed when a |set_aux|
+command is sensed. Similarly, |prev_graf| is changed in the presence of
+|set_prev_graf|, and |dead_cycles| or |insert_penalties| in the presence of
+|set_page_int|. These definitions are always global.
+
+When some dimension of a box register is changed, the change isn't exactly
+global; but \TeX\ does not look at the \.{\\global} switch.
+
+@<Assignments@>=
+case set_aux: alter_aux();@+break;
+case set_prev_graf: alter_prev_graf();@+break;
+case set_page_dimen: alter_page_so_far();@+break;
+case set_page_int: alter_integer();@+break;
+case set_box_dimen: alter_box_dimen();@+break;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+void alter_aux(void)
+{@+halfword c; /*|hmode| or |vmode|*/
+if (cur_chr!=abs(mode)) report_illegal_case();
+else{@+c=cur_chr;scan_optional_equals();
+ if (c==vmode)
+ {@+scan_normal_dimen;prev_depth=cur_val;
+ }
+ else{@+scan_int();
+ if ((cur_val <= 0)||(cur_val > 32767))
+ {@+print_err("Bad space factor");
+@.Bad space factor@>
+ help1("I allow only values in the range 1..32767 here.");
+ int_error(cur_val);
+ }
+ else space_factor=cur_val;
+ }
+ }
+}
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+void alter_prev_graf(void)
+{@+uint8_t p; /*index into |nest|*/
+nest[nest_ptr]=cur_list;p=nest_ptr;
+while (abs(nest[p].mode_field)!=vmode) decr(p);
+scan_optional_equals();scan_int();
+if (cur_val < 0)
+ {@+print_err("Bad ");print_esc(@[@<|"prevgraf"|@>@]);
+@.Bad \\prevgraf@>
+ help1("I allow only nonnegative values here.");
+ int_error(cur_val);
+ }
+else{@+nest[p].pg_field=cur_val;cur_list=nest[nest_ptr];
+ }
+}
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+void alter_page_so_far(void)
+{@+uint8_t c; /*index into |page_so_far|*/
+c=cur_chr;scan_optional_equals();scan_normal_dimen;
+page_so_far[c]=cur_val;
+}
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+void alter_integer(void)
+{@+uint8_t c; /*0 for \.{\\deadcycles}, 1 for \.{\\insertpenalties}*/
+c=cur_chr;scan_optional_equals();scan_int();
+if (c==0) dead_cycles=cur_val;
+else insert_penalties=cur_val;
+}
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+void alter_box_dimen(void)
+{@+small_number c; /*|width_offset| or |height_offset| or |depth_offset|*/
+eight_bits @!b; /*box number*/
+c=cur_chr;scan_eight_bit_int();b=cur_val;scan_optional_equals();
+scan_normal_dimen;
+if (box(b)!=null) mem[box(b)+c].sc=cur_val;
+}
+
+@ Paragraph shapes are set up in the obvious way.
+
+@<Assignments@>=
+case set_shape: {@+scan_optional_equals();scan_int();n=cur_val;
+ if (n <= 0) p=null;
+ else{@+p=get_node(2*n+1);info(p)=n;
+ for (j=1; j<=n; j++)
+ {@+scan_normal_dimen;
+ mem[p+2*j-1].sc=cur_val; /*indentation*/
+ scan_normal_dimen;
+ mem[p+2*j].sc=cur_val; /*width*/
+ }
+ }
+ define(par_shape_loc, shape_ref, p);
+ } @+break;
+
+@ Here's something that isn't quite so obvious. It guarantees that
+|info(par_shape_ptr)| can hold any positive~|n| for which |get_node(2*n+1)|
+doesn't overflow the memory capacity.
+
+@<Check the ``constant''...@>=
+if (2*max_halfword < mem_top-mem_min) bad=41;
+
+@ New hyphenation data is loaded by the |hyph_data| command.
+
+@<Put each...@>=
+primitive(@[@<|"hyphenation"|@>@], hyph_data, 0);
+@!@:hyphenation_}{\.{\\hyphenation} primitive@>
+primitive(@[@<|"patterns"|@>@], hyph_data, 1);
+@!@:patterns_}{\.{\\patterns} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case hyph_data: if (chr_code==1) print_esc(@[@<|"patterns"|@>@]);
+ else print_esc(@[@<|"hyphenation"|@>@]);@+break;
+
+@ @<Assignments@>=
+case hyph_data: if (cur_chr==1)
+ {
+#ifdef @!INIT
+new_patterns();goto done;@;
+#endif
+ print_err("Patterns can be loaded only by INITEX");
+@.Patterns can be...@>
+ help0;error();
+ @/do@+{get_token();}@+ while (!(cur_cmd==right_brace)); /*flush the patterns*/
+ return;
+ }
+ else{@+new_hyph_exceptions();goto done;
+ } @+break;
+
+@ All of \TeX's parameters are kept in |eqtb| except the font information,
+the interaction mode, and the hyphenation tables; these are strictly global.
+
+@<Assignments@>=
+case assign_font_dimen: {@+find_font_dimen(true);k=cur_val;
+ scan_optional_equals();scan_normal_dimen;font_info[k].sc=cur_val;
+ } @+break;
+case assign_font_int: {@+n=cur_chr;scan_font_ident();f=cur_val;
+ scan_optional_equals();scan_int();
+ if (n==0) hyphen_char[f]=cur_val;@+else skew_char[f]=cur_val;
+ } @+break;
+
+@ @<Put each...@>=
+primitive(@[@<|"hyphenchar"|@>@], assign_font_int, 0);
+@!@:hyphen_char_}{\.{\\hyphenchar} primitive@>
+primitive(@[@<|"skewchar"|@>@], assign_font_int, 1);
+@!@:skew_char_}{\.{\\skewchar} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case assign_font_int: if (chr_code==0) print_esc(@[@<|"hyphenchar"|@>@]);
+ else print_esc(@[@<|"skewchar"|@>@]);@+break;
+
+@ Here is where the information for a new font gets loaded.
+
+@<Assignments@>=
+case def_font: new_font(a);@+break;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+void new_font(small_number @!a)
+{@+
+pointer u; /*user's font identifier*/
+scaled @!s; /*stated ``at'' size, or negative of scaled magnification*/
+int @!f; /*runs through existing fonts*/
+str_number @!t; /*name for the frozen font identifier*/
+uint8_t @!old_setting; /*holds |selector| setting*/
+str_number @!flushable_string; /*string not yet referenced*/
+if (job_name==0) open_log_file();
+ /*avoid confusing \.{texput} with the font name*/
+@.texput@>
+get_r_token();u=cur_cs;
+if (u >= hash_base) t=text(u);
+else if (u >= single_base)
+ if (u==null_cs) t=@[@<|"FONT"|@>@];@+else t=u-single_base;
+else{@+old_setting=selector;selector=new_string;
+ print_str("FONT");print(u-active_base);selector=old_setting;
+@.FONTx@>
+ str_room(1);t=make_string();
+ }
+define(u, set_font, null_font);scan_optional_equals();scan_file_name();
+@<Scan the font size specification@>;
+@<If this font has already been loaded, set |f| to the internal font number and |goto
+common_ending|@>;
+f=read_font_info(u, cur_name, cur_area, s);
+common_ending: equiv(u)=f;eqtb[font_id_base+f]=eqtb[u];font_id_text(f)=t;
+}
+
+@ @<Scan the font size specification@>=
+name_in_progress=true; /*this keeps |cur_name| from being changed*/
+if (scan_keyword(@[@<|"at"|@>@])) @<Put the \(p)(positive) `at' size into |s|@>@;
+@.at@>
+else if (scan_keyword(@[@<|"scaled"|@>@]))
+@.scaled@>
+ {@+scan_int();s=-cur_val;
+ if ((cur_val <= 0)||(cur_val > 32768))
+ {@+print_err("Illegal magnification has been changed to 1000");@/
+@.Illegal magnification...@>
+ help1("The magnification ratio must be between 1 and 32768.");
+ int_error(cur_val);s=-1000;
+ }
+ }
+else s=-1000;
+name_in_progress=false
+
+@ @<Put the \(p)(positive) `at' size into |s|@>=
+{@+scan_normal_dimen;s=cur_val;
+if ((s <= 0)||(s >= 01000000000))
+ {@+print_err("Improper `at' size (");
+ print_scaled(s);print_str("pt), replaced by 10pt");
+@.Improper `at' size...@>
+ help2("I can only handle fonts at positive sizes that are")@/
+ ("less than 2048pt, so I've changed what you said to 10pt.");
+ error();s=10*unity;
+ }
+}
+
+@ When the user gives a new identifier to a font that was previously loaded,
+the new name becomes the font identifier of record. Font names `\.{xyz}' and
+`\.{XYZ}' are considered to be different.
+
+@<If this font has already been loaded...@>=
+flushable_string=str_ptr-1;
+for (f=font_base+1; f<=font_ptr; f++)
+ if (str_eq_str(font_name[f], cur_name)&&str_eq_str(font_area[f], cur_area))
+ {@+if (cur_name==flushable_string)
+ {@+flush_string;cur_name=font_name[f];
+ }
+ if (s > 0)
+ {@+if (s==font_size[f]) goto common_ending;
+ }
+ else if (font_size[f]==xn_over_d(font_dsize[f],-s, 1000))
+ goto common_ending;
+ }
+
+@ @<Cases of |print_cmd_chr|...@>=
+case set_font: {@+print_str("select font ");slow_print(font_name[chr_code]);
+ if (font_size[chr_code]!=font_dsize[chr_code])
+ {@+print_str(" at ");print_scaled(font_size[chr_code]);
+ print_str("pt");
+ }
+ } @+break;
+
+@ @<Put each...@>=
+primitive(@[@<|"batchmode"|@>@], set_interaction, batch_mode);
+@!@:batch_mode_}{\.{\\batchmode} primitive@>
+primitive(@[@<|"nonstopmode"|@>@], set_interaction, nonstop_mode);
+@!@:nonstop_mode_}{\.{\\nonstopmode} primitive@>
+primitive(@[@<|"scrollmode"|@>@], set_interaction, scroll_mode);
+@!@:scroll_mode_}{\.{\\scrollmode} primitive@>
+primitive(@[@<|"errorstopmode"|@>@], set_interaction, error_stop_mode);
+@!@:error_stop_mode_}{\.{\\errorstopmode} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case set_interaction: switch (chr_code) {
+ case batch_mode: print_esc(@[@<|"batchmode"|@>@]);@+break;
+ case nonstop_mode: print_esc(@[@<|"nonstopmode"|@>@]);@+break;
+ case scroll_mode: print_esc(@[@<|"scrollmode"|@>@]);@+break;
+ default:print_esc(@[@<|"errorstopmode"|@>@]);
+ } @+break;
+
+@ @<Assignments@>=
+case set_interaction: new_interaction();@+break;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+void new_interaction(void)
+{@+print_ln();
+interaction=cur_chr;
+@<Initialize the print |selector| based on |interaction|@>;
+if (log_opened) selector=selector+2;
+}
+
+@ The \.{\\afterassignment} command puts a token into the global
+variable |after_token|. This global variable is examined just after
+every assignment has been performed.
+
+@<Glob...@>=
+halfword @!after_token; /*zero, or a saved token*/
+
+@ @<Set init...@>=
+after_token=0;
+
+@ @<Cases of |main_control| that don't...@>=
+any_mode(after_assignment): {@+get_token();after_token=cur_tok;
+ } @+break;
+
+@ @<Insert a token saved by \.{\\afterassignment}, if any@>=
+if (after_token!=0)
+ {@+cur_tok=after_token;back_input();after_token=0;
+ }
+
+@ Here is a procedure that might be called `Get the next non-blank non-relax
+non-call non-assignment token'.
+
+@<Declare act...@>=
+void do_assignments(void)
+{@+
+loop{@+@<Get the next non-blank non-relax...@>;
+ if (cur_cmd <= max_non_prefixed_command) return;
+ set_box_allowed=false;prefixed_command();set_box_allowed=true;
+ }
+}
+
+@ @<Cases of |main_control| that don't...@>=
+any_mode(after_group): {@+get_token();save_for_after(cur_tok);
+ } @+break;
+
+@ Files for \.{\\read} are opened and closed by the |in_stream| command.
+
+@<Put each...@>=
+primitive(@[@<|"openin"|@>@], in_stream, 1);
+@!@:open_in_}{\.{\\openin} primitive@>
+primitive(@[@<|"closein"|@>@], in_stream, 0);
+@!@:close_in_}{\.{\\closein} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case in_stream: if (chr_code==0) print_esc(@[@<|"closein"|@>@]);
+ else print_esc(@[@<|"openin"|@>@]);@+break;
+
+@ @<Cases of |main_control| that don't...@>=
+any_mode(in_stream): open_or_close_in();@+break;
+
+@ @<Declare act...@>=
+void open_or_close_in(void)
+{@+uint8_t c; /*1 for \.{\\openin}, 0 for \.{\\closein}*/
+uint8_t @!n; /*stream number*/
+c=cur_chr;scan_four_bit_int();n=cur_val;
+if (read_open[n]!=closed)
+ {@+a_close(&read_file[n]);read_open[n]=closed;
+ }
+if (c!=0)
+ {@+scan_optional_equals();scan_file_name();
+ if (cur_ext==empty_string) cur_ext=@[@<|".tex"|@>@];
+ pack_cur_name;
+ if (a_open_in(&read_file[n])) read_open[n]=just_open;
+ }
+}
+
+@ The user can issue messages to the terminal, regardless of the
+current mode.
+
+@<Cases of |main_control| that don't...@>=
+any_mode(message): issue_message();@+break;
+
+@ @<Put each...@>=
+primitive(@[@<|"message"|@>@], message, 0);
+@!@:message_}{\.{\\message} primitive@>
+primitive(@[@<|"errmessage"|@>@], message, 1);
+@!@:err_message_}{\.{\\errmessage} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case message: if (chr_code==0) print_esc(@[@<|"message"|@>@]);
+ else print_esc(@[@<|"errmessage"|@>@]);@+break;
+
+@ @<Declare act...@>=
+void issue_message(void)
+{@+uint8_t old_setting; /*holds |selector| setting*/
+uint8_t @!c; /*identifies \.{\\message} and \.{\\errmessage}*/
+str_number @!s; /*the message*/
+c=cur_chr;link(garbage)=scan_toks(false, true);
+old_setting=selector;selector=new_string;
+token_show(def_ref);selector=old_setting;
+flush_list(def_ref);
+str_room(1);s=make_string();
+if (c==0) @<Print string |s| on the terminal@>@;
+else@<Print string |s| as an error message@>;
+flush_string;
+}
+
+@ @<Print string |s| on the terminal@>=
+{@+if (term_offset+length(s) > max_print_line-2) print_ln();
+else if ((term_offset > 0)||(file_offset > 0)) print_char(' ');
+slow_print(s);update_terminal;
+}
+
+@ If \.{\\errmessage} occurs often in |scroll_mode|, without user-defined
+\.{\\errhelp}, we don't want to give a long help message each time. So we
+give a verbose explanation only once.
+
+@<Glob...@>=
+bool @!long_help_seen; /*has the long \.{\\errmessage} help been used?*/
+
+@ @<Set init...@>=long_help_seen=false;
+
+@ @<Print string |s| as an error message@>=
+{@+print_err("");slow_print(s);
+if (err_help!=null) use_err_help=true;
+else if (long_help_seen) help1("(That was another \\errmessage.)")@;
+else{@+if (interaction < error_stop_mode) long_help_seen=true;
+ help4("This error message was generated by an \\errmessage")@/
+ ("command, so I can't give any explicit help.")@/
+ ("Pretend that you're Hercule Poirot: Examine all clues,")@/
+@^Poirot, Hercule@>
+ ("and deduce the truth by order and method.");
+ }
+error();use_err_help=false;
+}
+
+@ The |error| routine calls on |give_err_help| if help is requested from
+the |err_help| parameter.
+
+@p void give_err_help(void)
+{@+token_show(err_help);
+}
+
+@ The \.{\\uppercase} and \.{\\lowercase} commands are implemented by
+building a token list and then changing the cases of the letters in it.
+
+@<Cases of |main_control| that don't...@>=
+any_mode(case_shift): shift_case();@+break;
+
+@ @<Put each...@>=
+primitive(@[@<|"lowercase"|@>@], case_shift, lc_code_base);
+@!@:lowercase_}{\.{\\lowercase} primitive@>
+primitive(@[@<|"uppercase"|@>@], case_shift, uc_code_base);
+@!@:uppercase_}{\.{\\uppercase} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case case_shift: if (chr_code==lc_code_base) print_esc(@[@<|"lowercase"|@>@]);
+ else print_esc(@[@<|"uppercase"|@>@]);@+break;
+
+@ @<Declare act...@>=
+void shift_case(void)
+{@+pointer b; /*|lc_code_base| or |uc_code_base|*/
+pointer @!p; /*runs through the token list*/
+halfword @!t; /*token*/
+eight_bits @!c; /*character code*/
+b=cur_chr;p=scan_toks(false, false);p=link(def_ref);
+while (p!=null)
+ {@+@<Change the case of the token in |p|, if a change is appropriate@>;
+ p=link(p);
+ }
+back_list(link(def_ref));free_avail(def_ref); /*omit reference count*/
+}
+
+@ When the case of a |chr_code| changes, we don't change the |cmd|.
+We also change active characters, using the fact that
+|cs_token_flag+active_base| is a multiple of~256.
+@^data structure assumptions@>
+
+@<Change the case of the token in |p|, if a change is appropriate@>=
+t=info(p);
+if (t < cs_token_flag+single_base)
+ {@+c=t%256;
+ if (equiv(b+c)!=0) info(p)=t-c+equiv(b+c);
+ }
+
+@ We come finally to the last pieces missing from |main_control|, namely the
+`\.{\\show}' commands that are useful when debugging.
+
+@<Cases of |main_control| that don't...@>=
+any_mode(xray): show_whatever();@+break;
+
+@ @d show_code 0 /* \.{\\show} */
+@d show_box_code 1 /* \.{\\showbox} */
+@d show_the_code 2 /* \.{\\showthe} */
+@d show_lists 3 /* \.{\\showlists} */
+
+@<Put each...@>=
+primitive(@[@<|"show"|@>@], xray, show_code);
+@!@:show_}{\.{\\show} primitive@>
+primitive(@[@<|"showbox"|@>@], xray, show_box_code);
+@!@:show_box_}{\.{\\showbox} primitive@>
+primitive(@[@<|"showthe"|@>@], xray, show_the_code);
+@!@:show_the_}{\.{\\showthe} primitive@>
+primitive(@[@<|"showlists"|@>@], xray, show_lists);
+@!@:show_lists_}{\.{\\showlists} primitive@>
+
+@ @<Cases of |print_cmd_chr|...@>=
+case xray: switch (chr_code) {
+ case show_box_code: print_esc(@[@<|"showbox"|@>@]);@+break;
+ case show_the_code: print_esc(@[@<|"showthe"|@>@]);@+break;
+ case show_lists: print_esc(@[@<|"showlists"|@>@]);@+break;
+ default:print_esc(@[@<|"show"|@>@]);
+ } @+break;
+
+@ @<Declare act...@>=
+void show_whatever(void)
+{@+
+pointer p; /*tail of a token list to show*/
+switch (cur_chr) {
+case show_lists: {@+begin_diagnostic();show_activities();
+ } @+break;
+case show_box_code: @<Show the current contents of a box@>@;@+break;
+case show_code: @<Show the current meaning of a token, then |goto common_ending|@>@;
+default:@<Show the current value of some parameter or register, then |goto common_ending|@>@;
+} @/
+@<Complete a potentially long \.{\\show} command@>;
+common_ending: if (interaction < error_stop_mode)
+ {@+help0;decr(error_count);
+ }
+else if (tracing_online > 0)
+ {@+@t@>@;@/
+ help3("This isn't an error message; I'm just \\showing something.")@/
+ ("Type `I\\show...' to show more (e.g., \\show\\cs,")@/
+ ("\\showthe\\count10, \\showbox255, \\showlists).");
+ }
+else{@+@t@>@;@/
+ help5("This isn't an error message; I'm just \\showing something.")@/
+ ("Type `I\\show...' to show more (e.g., \\show\\cs,")@/
+ ("\\showthe\\count10, \\showbox255, \\showlists).")@/
+ ("And type `I\\tracingonline=1\\show...' to show boxes and")@/
+ ("lists on your terminal as well as in the transcript file.");
+ }
+error();
+}
+
+@ @<Show the current meaning of a token...@>=
+{@+get_token();
+if (interaction==error_stop_mode) wake_up_terminal;
+print_nl("> ");
+if (cur_cs!=0)
+ {@+sprint_cs(cur_cs);print_char('=');
+ }
+print_meaning();goto common_ending;
+}
+
+@ @<Cases of |print_cmd_chr|...@>=
+case undefined_cs: print_str("undefined");@+break;
+case call: print_str("macro");@+break;
+case long_call: print_esc(@[@<|"long macro"|@>@]);@+break;
+case outer_call: print_esc(@[@<|"outer macro"|@>@]);@+break;
+case long_outer_call: {@+print_esc(@[@<|"long"|@>@]);print_esc(@[@<|"outer macro"|@>@]);
+ } @+break;
+case end_template: print_esc(@[@<|"outer endtemplate"|@>@]);@+break;
+
+@ @<Show the current contents of a box@>=
+{@+scan_eight_bit_int();begin_diagnostic();
+print_nl("> \\box");print_int(cur_val);print_char('=');
+if (box(cur_val)==null) print_str("void");
+else show_box(box(cur_val));
+}
+
+@ @<Show the current value of some parameter...@>=
+{@+p=the_toks();
+if (interaction==error_stop_mode) wake_up_terminal;
+print_nl("> ");token_show(temp_head);
+flush_list(link(temp_head));goto common_ending;
+}
+
+@ @<Complete a potentially long \.{\\show} command@>=
+end_diagnostic(true);print_err("OK");
+@.OK@>
+if (selector==term_and_log) if (tracing_online <= 0)
+ {@+selector=term_only;print_str(" (see the transcript file)");
+ selector=term_and_log;
+ }
+
+@* Dumping and undumping the tables.
+After \.{INITEX} has seen a collection of fonts and macros, it
+can write all the necessary information on an auxiliary file so
+that production versions of \TeX\ are able to initialize their
+memory at high speed. The present section of the program takes
+care of such output and input. We shall consider simultaneously
+the processes of storing and restoring,
+so that the inverse relation between them is clear.
+@.INITEX@>
+
+The global variable |format_ident| is a string that is printed right
+after the |banner| line when \TeX\ is ready to start. For \.{INITEX} this
+string says simply `\.{(INITEX)}'; for other versions of \TeX\ it says,
+for example, `\.{(preloaded format=plain 1982.11.19)}', showing the year,
+month, and day that the format file was created. We have |format_ident==0|
+before \TeX's tables are loaded.
+
+@<Glob...@>=
+str_number @!format_ident;
+
+@ @<Set init...@>=
+format_ident=0;
+
+@ @<Initialize table entries...@>=
+format_ident=@[@<|" (INITEX)"|@>@];
+
+@ @<Declare act...@>=
+#ifdef @!INIT
+void store_fmt_file(void)
+{@+
+int j, @!k, @!l; /*all-purpose indices*/
+pointer @!p, @!q; /*all-purpose pointers*/
+int @!x; /*something to dump*/
+four_quarters @!w; /*four ASCII codes*/
+@<If dumping is not allowed, abort@>;
+@<Create the |format_ident|, open the format file, and inform the user that dumping
+has begun@>;
+@<Dump constants for consistency check@>;
+@<Dump the string pool@>;
+@<Dump the dynamic memory@>;
+@<Dump the table of equivalents@>;
+@<Dump the font information@>;
+@<Dump the hyphenation tables@>;
+@<Dump a couple more things and the closing check word@>;
+@<Close the format file@>;
+}
+#endif
+
+@ Corresponding to the procedure that dumps a format file, we have a function
+that reads one in. The function returns |false| if the dumped format is
+incompatible with the present \TeX\ table sizes, etc.
+
+@d too_small(X) {@+wake_up_terminal;
+ wterm_ln("---! Must increase the %s", X);
+@.Must increase the x@>
+ goto bad_fmt;
+ }
+
+@p@t\4@>@<Declare the function called |open_fmt_file|@>@;
+bool load_fmt_file(void)
+{@+
+int j, @!k; /*all-purpose indices*/
+pointer @!p, @!q; /*all-purpose pointers*/
+int @!x; /*something undumped*/
+four_quarters @!w; /*four ASCII codes*/
+@<Undump constants for consistency check@>;
+@<Undump the string pool@>;
+@<Undump the dynamic memory@>;
+@<Undump the table of equivalents@>;
+@<Undump the font information@>;
+@<Undump the hyphenation tables@>;
+@<Undump a couple more things and the closing check word@>;
+return true; /*it worked!*/
+bad_fmt: wake_up_terminal;
+ wterm_ln("(Fatal format file error; I'm stymied)");
+@.Fatal format file error@>
+return false;
+}
+
+@ The user is not allowed to dump a format file unless |save_ptr==0|.
+This condition implies that |cur_level==level_one|, hence
+the |xeq_level| array is constant and it need not be dumped.
+
+@<If dumping is not allowed, abort@>=
+if (save_ptr!=0)
+ {@+print_err("You can't dump inside a group");
+@.You can't dump...@>
+ help1("`{...\\dump}' is a no-no.");succumb;
+ }
+
+@ Format files consist of |memory_word| items, and we use the following
+macros to dump words of different types:
+
+@d dump_wd(X) {@+fmt_file.d=X;put(fmt_file);@+}
+@d dump_int(X) {@+fmt_file.d.i=X;put(fmt_file);@+}
+@d dump_hh(X) {@+fmt_file.d.hh=X;put(fmt_file);@+}
+@d dump_qqqq(X) {@+fmt_file.d.qqqq=X;put(fmt_file);@+}
+
+@<Glob...@>=
+word_file @!fmt_file; /*for input or output of format information*/
+
+@ The inverse macros are slightly more complicated, since we need to check
+the range of the values we are reading in. We say `|undump(a)(b)(x)|' to
+read an integer value |x| that is supposed to be in the range |a <= x <= b|.
+
+@d undump_wd(X) {@+get(fmt_file);X=fmt_file.d;@+}
+@d undump_int(X) {@+get(fmt_file);X=fmt_file.d.i;@+}
+@d undump_hh(X) {@+get(fmt_file);X=fmt_file.d.hh;@+}
+@d undump_qqqq(X) {@+get(fmt_file);X=fmt_file.d.qqqq;@+}
+@d undump_end_end(X) X=x;@+}
+@d undump_end(X) (x > X)) goto bad_fmt;@+else undump_end_end
+@d undump(X) {@+undump_int(x);if ((x < X)||undump_end
+@d undump_size_end_end(X) too_small(X)@;@+else undump_end_end
+@d undump_size_end(X) if (x > X) undump_size_end_end
+@d undump_size(X) {@+undump_int(x);
+ if (x < X) goto bad_fmt;undump_size_end
+
+@ The next few sections of the program should make it clear how we use the
+dump/undump macros.
+
+@<Dump constants for consistency check@>=
+dump_int(0);@/
+dump_int(mem_bot);@/
+dump_int(mem_top);@/
+dump_int(eqtb_size);@/
+dump_int(hash_prime);@/
+dump_int(hyph_size)
+
+@ Sections of a \.{WEB} program that are ``commented out'' still contribute
+strings to the string pool; therefore \.{INITEX} and \TeX\ will have
+the same strings. (And it is, of course, a good thing that they do.)
+@.WEB@>
+@^string pool@>
+
+@<Undump constants for consistency check@>=
+x=fmt_file.d.i;
+if (x!=0) goto bad_fmt; /*check that strings are the same*/
+undump_int(x);
+if (x!=mem_bot) goto bad_fmt;
+undump_int(x);
+if (x!=mem_top) goto bad_fmt;
+undump_int(x);
+if (x!=eqtb_size) goto bad_fmt;
+undump_int(x);
+if (x!=hash_prime) goto bad_fmt;
+undump_int(x);
+if (x!=hyph_size) goto bad_fmt
+
+@ @d dump_four_ASCII
+ w.b0=qi(so(str_pool[k]));w.b1=qi(so(str_pool[k+1]));
+ w.b2=qi(so(str_pool[k+2]));w.b3=qi(so(str_pool[k+3]));
+ dump_qqqq(w)
+
+@<Dump the string pool@>=
+dump_int(pool_ptr);
+dump_int(str_ptr);
+for (k=0; k<=str_ptr; k++) dump_int(str_start[k]);
+k=0;
+while (k+4 < pool_ptr)
+ {@+dump_four_ASCII;k=k+4;
+ }
+k=pool_ptr-4;dump_four_ASCII;
+print_ln();print_int(str_ptr);print_str(" strings of total length ");
+print_int(pool_ptr)
+
+@ @d undump_four_ASCII
+ undump_qqqq(w);
+ str_pool[k]=si(qo(w.b0));str_pool[k+1]=si(qo(w.b1));
+ str_pool[k+2]=si(qo(w.b2));str_pool[k+3]=si(qo(w.b3))
+
+@<Undump the string pool@>=
+undump_size(0)(pool_size)("string pool size")(pool_ptr);
+undump_size(0)(max_strings)("max strings")(str_ptr);
+for (k=0; k<=str_ptr; k++) undump(0)(pool_ptr)(str_start[k]);
+k=0;
+while (k+4 < pool_ptr)
+ {@+undump_four_ASCII;k=k+4;
+ }
+k=pool_ptr-4;undump_four_ASCII;
+init_str_ptr=str_ptr;init_pool_ptr=pool_ptr
+
+@ By sorting the list of available spaces in the variable-size portion of
+|mem|, we are usually able to get by without having to dump very much
+of the dynamic memory.
+
+We recompute |var_used| and |dyn_used|, so that \.{INITEX} dumps valid
+information even when it has not been gathering statistics.
+
+@<Dump the dynamic memory@>=
+sort_avail();var_used=0;
+dump_int(lo_mem_max);dump_int(rover);
+p=mem_bot;q=rover;x=0;
+@/do@+{for (k=p; k<=q+1; k++) dump_wd(mem[k]);
+x=x+q+2-p;var_used=var_used+q-p;
+p=q+node_size(q);q=rlink(q);
+}@+ while (!(q==rover));
+var_used=var_used+lo_mem_max-p;dyn_used=mem_end+1-hi_mem_min;@/
+for (k=p; k<=lo_mem_max; k++) dump_wd(mem[k]);
+x=x+lo_mem_max+1-p;
+dump_int(hi_mem_min);dump_int(avail);
+for (k=hi_mem_min; k<=mem_end; k++) dump_wd(mem[k]);
+x=x+mem_end+1-hi_mem_min;
+p=avail;
+while (p!=null)
+ {@+decr(dyn_used);p=link(p);
+ }
+dump_int(var_used);dump_int(dyn_used);
+print_ln();print_int(x);
+print_str(" memory locations dumped; current usage is ");
+print_int(var_used);print_char('&');print_int(dyn_used)
+
+@ @<Undump the dynamic memory@>=
+undump(lo_mem_stat_max+1000)(hi_mem_stat_min-1)(lo_mem_max);
+undump(lo_mem_stat_max+1)(lo_mem_max)(rover);
+p=mem_bot;q=rover;
+@/do@+{for (k=p; k<=q+1; k++) undump_wd(mem[k]);
+p=q+node_size(q);
+if ((p > lo_mem_max)||((q >= rlink(q))&&(rlink(q)!=rover))) goto bad_fmt;
+q=rlink(q);
+}@+ while (!(q==rover));
+for (k=p; k<=lo_mem_max; k++) undump_wd(mem[k]);
+if (mem_min < mem_bot-2) /*make more low memory available*/
+ {@+p=llink(rover);q=mem_min+1;
+ link(mem_min)=null;info(mem_min)=null; /*we don't use the bottom word*/
+ rlink(p)=q;llink(rover)=q;@/
+ rlink(q)=rover;llink(q)=p;link(q)=empty_flag;
+ node_size(q)=mem_bot-q;
+ }
+undump(lo_mem_max+1)(hi_mem_stat_min)(hi_mem_min);
+undump(null)(mem_top)(avail);mem_end=mem_top;
+for (k=hi_mem_min; k<=mem_end; k++) undump_wd(mem[k]);
+undump_int(var_used);undump_int(dyn_used)
+
+@ @<Dump the table of equivalents@>=
+@<Dump regions 1 to 4 of |eqtb|@>;
+@<Dump regions 5 and 6 of |eqtb|@>;
+dump_int(par_loc);dump_int(write_loc);@/
+@<Dump the hash table@>@;
+
+@ @<Undump the table of equivalents@>=
+@<Undump regions 1 to 6 of |eqtb|@>;
+undump(hash_base)(frozen_control_sequence)(par_loc);
+par_token=cs_token_flag+par_loc;@/
+undump(hash_base)(frozen_control_sequence)(write_loc);@/
+@<Undump the hash table@>@;
+
+@ The table of equivalents usually contains repeated information, so we dump it
+in compressed form: The sequence of $n+2$ values $(n,x_1,\ldots,x_n,m)$ in the
+format file represents $n+m$ consecutive entries of |eqtb|, with |m| extra
+copies of $x_n$, namely $(x_1,\ldots,x_n,x_n,\ldots,x_n)$.
+
+@<Dump regions 1 to 4 of |eqtb|@>=
+k=active_base;
+@/do@+{j=k;
+while (j < int_base-1)
+ {@+if ((equiv(j)==equiv(j+1))&&(eq_type(j)==eq_type(j+1))&&@|
+ (eq_level(j)==eq_level(j+1))) goto found1;
+ incr(j);
+ }
+l=int_base;goto done1; /*|j==int_base-1|*/
+found1: incr(j);l=j;
+while (j < int_base-1)
+ {@+if ((equiv(j)!=equiv(j+1))||(eq_type(j)!=eq_type(j+1))||@|
+ (eq_level(j)!=eq_level(j+1))) goto done1;
+ incr(j);
+ }
+done1: dump_int(l-k);
+while (k < l)
+ {@+dump_wd(eqtb[k]);incr(k);
+ }
+k=j+1;dump_int(k-l);
+}@+ while (!(k==int_base))
+
+@ @<Dump regions 5 and 6 of |eqtb|@>=
+@/do@+{j=k;
+while (j < eqtb_size)
+ {@+if (eqtb[j].i==eqtb[j+1].i) goto found2;
+ incr(j);
+ }
+l=eqtb_size+1;goto done2; /*|j==eqtb_size|*/
+found2: incr(j);l=j;
+while (j < eqtb_size)
+ {@+if (eqtb[j].i!=eqtb[j+1].i) goto done2;
+ incr(j);
+ }
+done2: dump_int(l-k);
+while (k < l)
+ {@+dump_wd(eqtb[k]);incr(k);
+ }
+k=j+1;dump_int(k-l);
+}@+ while (!(k > eqtb_size))
+
+@ @<Undump regions 1 to 6 of |eqtb|@>=
+k=active_base;
+@/do@+{undump_int(x);
+if ((x < 1)||(k+x > eqtb_size+1)) goto bad_fmt;
+for (j=k; j<=k+x-1; j++) undump_wd(eqtb[j]);
+k=k+x;
+undump_int(x);
+if ((x < 0)||(k+x > eqtb_size+1)) goto bad_fmt;
+for (j=k; j<=k+x-1; j++) eqtb[j]=eqtb[k-1];
+k=k+x;
+}@+ while (!(k > eqtb_size))
+
+@ A different scheme is used to compress the hash table, since its lower
+region is usually sparse. When |text(p)!=0| for |p <= hash_used|, we output
+two words, |p| and |hash[p]|. The hash table is, of course, densely packed
+for |p >= hash_used|, so the remaining entries are output in a~block.
+
+@<Dump the hash table@>=
+dump_int(hash_used);cs_count=frozen_control_sequence-1-hash_used;
+for (p=hash_base; p<=hash_used; p++) if (text(p)!=0)
+ {@+dump_int(p);dump_hh(hash[p]);incr(cs_count);
+ }
+for (p=hash_used+1; p<=undefined_control_sequence-1; p++) dump_hh(hash[p]);
+dump_int(cs_count);@/
+print_ln();print_int(cs_count);print_str(" multiletter control sequences")
+
+@ @<Undump the hash table@>=
+undump(hash_base)(frozen_control_sequence)(hash_used);p=hash_base-1;
+@/do@+{undump(p+1)(hash_used)(p);undump_hh(hash[p]);
+}@+ while (!(p==hash_used));
+for (p=hash_used+1; p<=undefined_control_sequence-1; p++) undump_hh(hash[p]);
+undump_int(cs_count)
+
+@ @<Dump the font information@>=
+dump_int(fmem_ptr);
+for (k=0; k<=fmem_ptr-1; k++) dump_wd(font_info[k]);
+dump_int(font_ptr);
+for (k=null_font; k<=font_ptr; k++)
+ @<Dump the array info for internal font number |k|@>;
+print_ln();print_int(fmem_ptr-7);print_str(" words of font info for ");
+print_int(font_ptr-font_base);print_str(" preloaded font");
+if (font_ptr!=font_base+1) print_char('s')
+
+@ @<Undump the font information@>=
+undump_size(7)(font_mem_size)("font mem size")(fmem_ptr);
+for (k=0; k<=fmem_ptr-1; k++) undump_wd(font_info[k]);
+undump_size(font_base)(font_max)("font max")(font_ptr);
+for (k=null_font; k<=font_ptr; k++)
+ @<Undump the array info for internal font number |k|@>@;
+
+@ @<Dump the array info for internal font number |k|@>=
+{@+dump_qqqq(font_check[k]);
+dump_int(font_size[k]);
+dump_int(font_dsize[k]);
+dump_int(font_params[k]);@/
+dump_int(hyphen_char[k]);
+dump_int(skew_char[k]);@/
+dump_int(font_name[k]);
+dump_int(font_area[k]);@/
+dump_int(font_bc[k]);
+dump_int(font_ec[k]);@/
+dump_int(char_base[k]);
+dump_int(width_base[k]);
+dump_int(height_base[k]);@/
+dump_int(depth_base[k]);
+dump_int(italic_base[k]);
+dump_int(lig_kern_base[k]);@/
+dump_int(kern_base[k]);
+dump_int(exten_base[k]);
+dump_int(param_base[k]);@/
+dump_int(font_glue[k]);@/
+dump_int(bchar_label[k]);
+dump_int(font_bchar[k]);
+dump_int(font_false_bchar[k]);@/
+print_nl("\\font");print_esc(font_id_text(k));print_char('=');
+print_file_name(font_name[k], font_area[k], empty_string);
+if (font_size[k]!=font_dsize[k])
+ {@+print_str(" at ");print_scaled(font_size[k]);print_str("pt");
+ }
+}
+
+@ @<Undump the array info for internal font number |k|@>=
+{@+undump_qqqq(font_check[k]);@/
+undump_int(font_size[k]);
+undump_int(font_dsize[k]);
+undump(min_halfword)(max_halfword)(font_params[k]);@/
+undump_int(hyphen_char[k]);
+undump_int(skew_char[k]);@/
+undump(0)(str_ptr)(font_name[k]);
+undump(0)(str_ptr)(font_area[k]);@/
+undump(0)(255)(font_bc[k]);
+undump(0)(255)(font_ec[k]);@/
+undump_int(char_base[k]);
+undump_int(width_base[k]);
+undump_int(height_base[k]);@/
+undump_int(depth_base[k]);
+undump_int(italic_base[k]);
+undump_int(lig_kern_base[k]);@/
+undump_int(kern_base[k]);
+undump_int(exten_base[k]);
+undump_int(param_base[k]);@/
+undump(min_halfword)(lo_mem_max)(font_glue[k]);@/
+undump(0)(fmem_ptr-1)(bchar_label[k]);
+undump(min_quarterword)(non_char)(font_bchar[k]);
+undump(min_quarterword)(non_char)(font_false_bchar[k]);
+}
+
+@ @<Dump the hyphenation tables@>=
+dump_int(hyph_count);
+for (k=0; k<=hyph_size; k++) if (hyph_word[k]!=0)
+ {@+dump_int(k);dump_int(hyph_word[k]);dump_int(hyph_list[k]);
+ }
+print_ln();print_int(hyph_count);print_str(" hyphenation exception");
+if (hyph_count!=1) print_char('s');
+if (trie_not_ready) init_trie();
+dump_int(trie_max);
+for (k=0; k<=trie_max; k++) dump_hh(trie[k]);
+dump_int(trie_op_ptr);
+for (k=1; k<=trie_op_ptr; k++)
+ {@+dump_int(hyf_distance[k]);
+ dump_int(hyf_num[k]);
+ dump_int(hyf_next[k]);
+ }
+print_nl("Hyphenation trie of length ");print_int(trie_max);
+@.Hyphenation trie...@>
+print_str(" has ");print_int(trie_op_ptr);print_str(" op");
+if (trie_op_ptr!=1) print_char('s');
+print_str(" out of ");print_int(trie_op_size);
+for (k=255; k>=0; k--) if (trie_used[k] > min_quarterword)
+ {@+print_nl(" ");print_int(qo(trie_used[k]));
+ print_str(" for language ");print_int(k);
+ dump_int(k);dump_int(qo(trie_used[k]));
+ }
+
+@ Only ``nonempty'' parts of |op_start| need to be restored.
+
+@<Undump the hyphenation tables@>=
+undump(0)(hyph_size)(hyph_count);
+for (k=1; k<=hyph_count; k++)
+ {@+undump(0)(hyph_size)(j);
+ undump(0)(str_ptr)(hyph_word[j]);
+ undump(min_halfword)(max_halfword)(hyph_list[j]);
+ }
+undump_size(0)(trie_size)("trie size")(j);
+#ifdef @!INIT
+trie_max=j;
+#endif
+for (k=0; k<=j; k++) undump_hh(trie[k]);
+undump_size(0)(trie_op_size)("trie op size")(j);
+#ifdef @!INIT
+trie_op_ptr=j;
+#endif
+for (k=1; k<=j; k++)
+ {@+undump(0)(63)(hyf_distance[k]); /*a |small_number|*/
+ undump(0)(63)(hyf_num[k]);
+ undump(min_quarterword)(max_quarterword)(hyf_next[k]);
+ }
+#ifdef @!INIT
+for (k=0; k<=255; k++) trie_used[k]=min_quarterword;
+#endif
+@;@/
+k=256;
+while (j > 0)
+ {@+undump(0)(k-1)(k);undump(1)(j)(x);
+#ifdef @!INIT
+trie_used[k]=qi(x);
+#endif
+@;@/
+ j=j-x;op_start[k]=qo(j);
+ }
+#ifdef @!INIT
+trie_not_ready=false
+#endif
+
+@ We have already printed a lot of statistics, so we set |tracing_stats=0|
+to prevent them from appearing again.
+
+@<Dump a couple more things and the closing check word@>=
+dump_int(interaction);dump_int(format_ident);dump_int(69069);
+tracing_stats=0
+
+@ @<Undump a couple more things and the closing check word@>=
+undump(batch_mode)(error_stop_mode)(interaction);
+undump(0)(str_ptr)(format_ident);
+undump_int(x);
+if ((x!=69069)||eof(fmt_file)) goto bad_fmt
+
+@ @<Create the |format_ident|...@>=
+selector=new_string;
+print_str(" (preloaded format=");print(job_name);print_char(' ');
+print_int(year);print_char('.');
+print_int(month);print_char('.');print_int(day);print_char(')');
+if (interaction==batch_mode) selector=log_only;
+else selector=term_and_log;
+str_room(1);
+format_ident=make_string();
+pack_job_name(format_extension);
+while (!w_open_out(&fmt_file))
+ prompt_file_name("format file name", format_extension);
+print_nl("Beginning to dump on file ");
+@.Beginning to dump...@>
+slow_print(w_make_name_string(&fmt_file));flush_string;
+print_nl("");slow_print(format_ident)
+
+@ @<Close the format file@>=
+w_close(&fmt_file)
+
+@* The main program.
+This is it: the part of \TeX\ that executes all those procedures we have
+written.
+
+Well---almost. Let's leave space for a few more routines that we may
+have forgotten.
+
+@p@<Last-minute procedures@>@;
+
+@ We have noted that there are two versions of \TeX82. One, called \.{INITEX},
+@.INITEX@>
+has to be run first; it initializes everything from scratch, without
+reading a format file, and it has the capability of dumping a format file.
+The other one is called `\.{VIRTEX}'; it is a ``virgin'' program that needs
+@.VIRTEX@>
+to input a format file in order to get started. \.{VIRTEX} typically has
+more memory capacity than \.{INITEX}, because it does not need the space
+consumed by the auxiliary hyphenation tables and the numerous calls on
+|primitive|, etc.
+
+The \.{VIRTEX} program cannot read a format file instantaneously, of course;
+the best implementations therefore allow for production versions of \TeX\ that
+not only avoid the loading routine for \PASCAL\ object code, they also have
+a format file pre-loaded. This is impossible to do if we stick to standard
+\PASCAL; but there is a simple way to fool many systems into avoiding the
+initialization, as follows:\quad(1)~We declare a global integer variable
+called |ready_already|. The probability is negligible that this
+variable holds any particular value like 314159 when \.{VIRTEX} is first
+loaded.\quad(2)~After we have read in a format file and initialized
+everything, we set |ready_already=314159|.\quad(3)~Soon \.{VIRTEX}
+will print `\.*', waiting for more input; and at this point we
+interrupt the program and save its core image in some form that the
+operating system can reload speedily.\quad(4)~When that core image is
+activated, the program starts again at the beginning; but now
+|ready_already==314159| and all the other global variables have
+their initial values too. The former chastity has vanished!
+
+In other words, if we allow ourselves to test the condition
+|ready_already==314159|, before |ready_already| has been
+assigned a value, we can avoid the lengthy initialization. Dirty tricks
+rarely pay off so handsomely.
+@^dirty \PASCAL@>
+@^system dependencies@>
+
+On systems that allow such preloading, the standard program called \.{TeX}
+should be the one that has \.{plain} format preloaded, since that agrees
+with {\sl The \TeX book}. Other versions, e.g., \.{AmSTeX}, should also
+@:TeXbook}{\sl The \TeX book@>
+@.AmSTeX@>
+@.plain@>
+be provided for commonly used formats.
+
+@<Glob...@>=
+int @!ready_already; /*a sacrifice of purity for economy*/
+
+@ Now this is really it: \TeX\ starts and ends here.
+
+The initial test involving |ready_already| should be deleted if the
+\PASCAL\ runtime system is smart enough to detect such a ``mistake.''
+@^system dependencies@>
+
+@p int main(void) {@! /*|start_here|*/
+history=fatal_error_stop; /*in case we quit during initialization*/
+t_open_out; /*open the terminal for output*/
+if (ready_already==314159) goto start_of_TEX;
+@<Check the ``constant'' values...@>@;
+if (bad > 0)
+ {@+wterm_ln("Ouch---my internal constants have been clobbered!"
+ "---case %d", bad);
+@.Ouch...clobbered@>
+ exit(0);
+ }
+initialize(); /*set global variables to their starting values*/
+#ifdef @!INIT
+init_prim(); /*call |primitive| for each primitive*/
+init_str_ptr=str_ptr;init_pool_ptr=pool_ptr;fix_date_and_time();
+#endif
+ready_already=314159;
+start_of_TEX: @<Initialize the output routines@>;
+@<Get the first line of input and prepare to start@>;
+history=spotless; /*ready to go!*/
+main_control(); /*come to life*/
+final_cleanup(); /*prepare for death*/
+close_files_and_terminate();
+ready_already=0;
+return 0; }
+
+@ Here we do whatever is needed to complete \TeX's job gracefully on the
+local operating system. The code here might come into play after a fatal
+error; it must therefore consist entirely of ``safe'' operations that
+cannot produce error messages. For example, it would be a mistake to call
+|str_room| or |make_string| at this time, because a call on |overflow|
+might lead to an infinite loop.
+@^system dependencies@>
+
+Actually there's one way to get error messages, via |prepare_mag|;
+but that can't cause infinite recursion.
+@^recursion@>
+
+This program doesn't bother to close the input files that may still be open.
+
+@<Last-minute...@>=
+void close_files_and_terminate(void)
+{@+int k; /*all-purpose index*/
+@<Finish the extensions@>;
+#ifdef @!STAT
+if (tracing_stats > 0) @<Output statistics about this job@>;@;
+#endif
+wake_up_terminal;@<Finish the \.{DVI} file@>;
+if (log_opened)
+ {@+wlog_cr;a_close(&log_file);selector=selector-2;
+ if (selector==term_only)
+ {@+print_nl("Transcript written on ");
+@.Transcript written...@>
+ slow_print(log_name);print_char('.');
+ }
+ }
+}
+
+@ The present section goes directly to the log file instead of using
+|print| commands, because there's no need for these strings to take
+up |str_pool| memory when a non-{\bf stat} version of \TeX\ is being used.
+
+@<Output statistics...@>=
+if (log_opened)
+ {@+wlog_ln(" ");
+ wlog_ln("Here is how much of TeX's memory you used:");
+@.Here is how much...@>
+ wlog(" %d string", str_ptr-init_str_ptr);
+ if (str_ptr!=init_str_ptr+1) wlog( "s" );
+ wlog_ln( " out of %d", max_strings-init_str_ptr);@/
+ wlog_ln( " %d string characters out of %d", pool_ptr-init_pool_ptr,
+ pool_size-init_pool_ptr);@/
+ wlog_ln(" %d words of memory out of %d", lo_mem_max-mem_min+mem_end-hi_mem_min+2,@|
+ mem_end+1-mem_min);@/
+ wlog_ln(" %d multiletter control sequences out of %d", cs_count, hash_size);@/
+ wlog(" %d words of font info for %d font", fmem_ptr, font_ptr-font_base);
+ if (font_ptr!=font_base+1) wlog("s");
+ wlog_ln( ", out of %d for %d", font_mem_size, font_max-font_base);@/
+ wlog(" %d hyphenation exception", hyph_count);
+ if (hyph_count!=1) wlog("s");
+ wlog_ln( " out of %d", hyph_size);@/
+ wlog_ln(" %di,%dn,%dp,%db,%ds stack positions out of %di,%dn,%dp,%db,%ds",
+ max_in_stack, max_nest_stack,@|
+ max_param_stack,@|
+ max_buf_stack+1,@|
+ max_save_stack+6,@|
+ stack_size,
+ nest_size,
+ param_size,
+ buf_size,
+ save_size );
+ }
+
+@ We get to the |final_cleanup| routine when \.{\\end} or \.{\\dump} has
+been scanned and |its_all_over|\kern-2pt.
+
+@<Last-minute...@>=
+void final_cleanup(void)
+{@+
+small_number c; /*0 for \.{\\end}, 1 for \.{\\dump}*/
+c=cur_chr;
+if (job_name==0) open_log_file();
+while (input_ptr > 0)
+ if (state==token_list) end_token_list();@+else end_file_reading();
+while (open_parens > 0)
+ {@+print_str(" )");decr(open_parens);
+ }
+if (cur_level > level_one)
+ {@+print_nl("(");print_esc(@[@<|"end occurred "|@>@]);
+ print_str("inside a group at level ");
+@:end_}{\.{(\\end occurred...)}@>
+ print_int(cur_level-level_one);print_char(')');
+ }
+while (cond_ptr!=null)
+ {@+print_nl("(");print_esc(@[@<|"end occurred "|@>@]);
+ print_str("when ");print_cmd_chr(if_test, cur_if);
+ if (if_line!=0)
+ {@+print_str(" on line ");print_int(if_line);
+ }
+ print_str(" was incomplete)");
+ if_line=if_line_field(cond_ptr);
+ cur_if=subtype(cond_ptr);temp_ptr=cond_ptr;
+ cond_ptr=link(cond_ptr);free_node(temp_ptr, if_node_size);
+ }
+if (history!=spotless)
+ if (((history==warning_issued)||(interaction < error_stop_mode)))
+ if (selector==term_and_log)
+ {@+selector=term_only;
+ print_nl("(see the transcript file for additional information)");
+@.see the transcript file...@>
+ selector=term_and_log;
+ }
+if (c==1)
+ {
+#ifdef @!INIT
+for (c=top_mark_code; c<=split_bot_mark_code; c++)
+ if (cur_mark[c]!=null) delete_token_ref(cur_mark[c]);
+ if (last_glue!=max_halfword) delete_glue_ref(last_glue);
+ store_fmt_file();return;
+#endif
+ print_nl("(\\dump is performed only by INITEX)");return;
+@:dump_}{\.{\\dump...only by INITEX}@>
+ }
+}
+
+@ @<Last-minute...@>=
+#ifdef @!INIT
+void init_prim(void) /*initialize all the primitives*/
+{@+no_new_control_sequence=false;
+@<Put each...@>;
+no_new_control_sequence=true;
+}
+#endif
+
+@ When we begin the following code, \TeX's tables may still contain garbage;
+the strings might not even be present. Thus we must proceed cautiously to get
+bootstrapped in.
+
+But when we finish this part of the program, \TeX\ is ready to call on the
+|main_control| routine to do its work.
+
+@<Get the first line...@>=
+{@+@<Initialize the input routines@>;
+if ((format_ident==0)||(buffer[loc]=='&'))
+ {@+if (format_ident!=0) initialize(); /*erase preloaded format*/
+ if (!open_fmt_file()) exit(0);
+ if (!load_fmt_file())
+ {@+w_close(&fmt_file);exit(0);
+ }
+ w_close(&fmt_file);
+ while ((loc < limit)&&(buffer[loc]==' ')) incr(loc);
+ }
+if (end_line_char_inactive) decr(limit);
+else buffer[limit]=end_line_char;
+fix_date_and_time();@/
+@<Compute the magic offset@>;
+@<Initialize the print |selector|...@>;
+if ((loc < limit)&&(cat_code(buffer[loc])!=escape)) start_input();
+ /*\.{\\input} assumed*/
+}
+
+@* Debugging.
+Once \TeX\ is working, you should be able to diagnose most errors with
+the \.{\\show} commands and other diagnostic features. But for the initial
+stages of debugging, and for the revelation of really deep mysteries, you
+can compile \TeX\ with a few more aids, including the \PASCAL\ runtime
+checks and its debugger. An additional routine called |debug_help|
+will also come into play when you type `\.D' after an error message;
+|debug_help| also occurs just before a fatal error causes \TeX\ to succumb.
+@^debugging@>
+@^system dependencies@>
+
+The interface to |debug_help| is primitive, but it is good enough when used
+with a \PASCAL\ debugger that allows you to set breakpoints and to read
+variables and change their values. After getting the prompt `\.{debug \#}', you
+type either a negative number (this exits |debug_help|), or zero (this
+goes to a location where you can set a breakpoint, thereby entering into
+dialog with the \PASCAL\ debugger), or a positive number |m| followed by
+an argument |n|. The meaning of |m| and |n| will be clear from the
+program below. (If |m==13|, there is an additional argument, |l|.)
+@.debug \#@>
+
+@<Last-minute...@>=
+#ifdef @!DEBUG
+void debug_help(void) /*routine to display various things*/
+{@+
+int k, @!l, @!m, @!n;
+loop{@+wake_up_terminal;
+ print_nl("debug # (-1 to exit):");update_terminal;
+@.debug \#@>
+ if (fscanf(term_in.f," %d",&m)<1 ||
+ m < 0) return;
+ else if (m==0)
+ {@+goto breakpoint; /*go to every label at least once*/
+ breakpoint: m=0;/*'BREAKPOINT'*/
+ }
+ else{@+fscanf(term_in.f," %d",&n);
+ switch (m) {
+ @t\4@>@<Numbered cases for |debug_help|@>@;
+ default:print_str("?");
+ }
+ }
+ }
+}
+#endif
+
+@ @<Numbered cases...@>=
+case 1: print_word(mem[n]);@+break; /*display |mem[n]| in all forms*/
+case 2: print_int(info(n));@+break;
+case 3: print_int(link(n));@+break;
+case 4: print_word(eqtb[n]);@+break;
+case 5: print_word(font_info[n]);@+break;
+case 6: print_word(save_stack[n]);@+break;
+case 7: show_box(n);@+break;
+ /*show a box, abbreviated by |show_box_depth| and |show_box_breadth|*/
+case 8: {@+breadth_max=10000;depth_threshold=pool_size-pool_ptr-10;
+ show_node_list(n); /*show a box in its entirety*/
+ } @+break;
+case 9: show_token_list(n, null, 1000);@+break;
+case 10: slow_print(n);@+break;
+case 11: check_mem(n > 0);@+break; /*check wellformedness; print new busy locations if |n > 0|*/
+case 12: search_mem(n);@+break; /*look for pointers to |n|*/
+case 13: {@+fscanf(term_in.f," %d",&l);print_cmd_chr(n, l);
+ } @+break;
+case 14: for (k=0; k<=n; k++) print(buffer[k]);@+break;
+case 15: {@+font_in_short_display=null_font;short_display(n);
+ } @+break;
+case 16: panicking=!panicking;@+break;
+
+@* Extensions.
+The program above includes a bunch of ``hooks'' that allow further
+capabilities to be added without upsetting \TeX's basic structure.
+Most of these hooks are concerned with ``whatsit'' nodes, which are
+intended to be used for special purposes; whenever a new extension to
+\TeX\ involves a new kind of whatsit node, a corresponding change needs
+to be made to the routines below that deal with such nodes,
+but it will usually be unnecessary to make many changes to the
+other parts of this program.
+
+In order to demonstrate how extensions can be made, we shall treat
+`\.{\\write}', `\.{\\openout}', `\.{\\closeout}', `\.{\\immediate}',
+`\.{\\special}', and `\.{\\setlanguage}' as if they were extensions.
+These commands are actually primitives of \TeX, and they should
+appear in all implementations of the system; but let's try to imagine
+that they aren't. Then the program below illustrates how a person
+could add them.
+
+Sometimes, of course, an extension will require changes to \TeX\ itself;
+no system of hooks could be complete enough for all conceivable extensions.
+The features associated with `\.{\\write}' are almost all confined to the
+following paragraphs, but there are small parts of the |print_ln| and
+|print_char| procedures that were introduced specifically to \.{\\write}
+characters. Furthermore one of the token lists recognized by the scanner
+is a |write_text|; and there are a few other miscellaneous places where we
+have already provided for some aspect of \.{\\write}. The goal of a \TeX\
+extender should be to minimize alterations to the standard parts of the
+program, and to avoid them completely if possible. He or she should also
+be quite sure that there's no easy way to accomplish the desired goals
+with the standard features that \TeX\ already has. ``Think thrice before
+extending,'' because that may save a lot of work, and it will also keep
+incompatible extensions of \TeX\ from proliferating.
+@^system dependencies@>
+@^extensions to \TeX@>
+
+@ First let's consider the format of whatsit nodes that are used to represent
+the data associated with \.{\\write} and its relatives. Recall that a whatsit
+has |type==whatsit_node|, and the |subtype| is supposed to distinguish
+different kinds of whatsits. Each node occupies two or more words; the
+exact number is immaterial, as long as it is readily determined from the
+|subtype| or other data.
+
+We shall introduce five |subtype| values here, corresponding to the
+control sequences \.{\\openout}, \.{\\write}, \.{\\closeout}, \.{\\special}, and
+\.{\\setlanguage}. The second word of I/O whatsits has a |write_stream| field
+that identifies the write-stream number (0 to 15, or 16 for out-of-range and
+positive, or 17 for out-of-range and negative).
+In the case of \.{\\write} and \.{\\special}, there is also a field that
+points to the reference count of a token list that should be sent. In the
+case of \.{\\openout}, we need three words and three auxiliary subfields
+to hold the string numbers for name, area, and extension.
+
+@d write_node_size 2 /*number of words in a write/whatsit node*/
+@d open_node_size 3 /*number of words in an open/whatsit node*/
+@d open_node 0 /*|subtype| in whatsits that represent files to \.{\\openout}*/
+@d write_node 1 /*|subtype| in whatsits that represent things to \.{\\write}*/
+@d close_node 2 /*|subtype| in whatsits that represent streams to \.{\\closeout}*/
+@d special_node 3 /*|subtype| in whatsits that represent \.{\\special} things*/
+@d language_node 4 /*|subtype| in whatsits that change the current language*/
+@d what_lang(X) link(X+1) /*language number, in the range |0 dotdot 255|*/
+@d what_lhm(X) type(X+1) /*minimum left fragment, in the range |1 dotdot 63|*/
+@d what_rhm(X) subtype(X+1) /*minimum right fragment, in the range |1 dotdot 63|*/
+@d write_tokens(X) link(X+1) /*reference count of token list to write*/
+@d write_stream(X) info(X+1) /*stream number (0 to 17)*/
+@d open_name(X) link(X+1) /*string number of file name to open*/
+@d open_area(X) info(X+2) /*string number of file area for |open_name|*/
+@d open_ext(X) link(X+2) /*string number of file extension for |open_name|*/
+
+@ The sixteen possible \.{\\write} streams are represented by the |write_file|
+array. The |j|th file is open if and only if |write_open[j]==true|. The last
+two streams are special; |write_open[16]| represents a stream number
+greater than 15, while |write_open[17]| represents a negative stream number,
+and both of these variables are always |false|.
+
+@<Glob...@>=
+alpha_file @!write_file[16];
+bool @!write_open[18];
+
+@ @<Set init...@>=
+for (k=0; k<=17; k++) write_open[k]=false;
+
+@ Extensions might introduce new command codes; but it's best to use
+|extension| with a modifier, whenever possible, so that |main_control|
+stays the same.
+
+@d immediate_code 4 /*command modifier for \.{\\immediate}*/
+@d set_language_code 5 /*command modifier for \.{\\setlanguage}*/
+
+@<Put each...@>=
+primitive(@[@<|"openout"|@>@], extension, open_node);@/
+@!@:open_out_}{\.{\\openout} primitive@>
+primitive(@[@<|"write"|@>@], extension, write_node);write_loc=cur_val;@/
+@!@:write_}{\.{\\write} primitive@>
+primitive(@[@<|"closeout"|@>@], extension, close_node);@/
+@!@:close_out_}{\.{\\closeout} primitive@>
+primitive(@[@<|"special"|@>@], extension, special_node);@/
+@!@:special_}{\.{\\special} primitive@>
+primitive(@[@<|"immediate"|@>@], extension, immediate_code);@/
+@!@:immediate_}{\.{\\immediate} primitive@>
+primitive(@[@<|"setlanguage"|@>@], extension, set_language_code);@/
+@!@:set_language_}{\.{\\setlanguage} primitive@>
+
+@ The variable |write_loc| just introduced is used to provide an
+appropriate error message in case of ``runaway'' write texts.
+
+@<Glob...@>=
+pointer @!write_loc; /*|eqtb| address of \.{\\write}*/
+
+@ @<Cases of |print_cmd_chr|...@>=
+case extension: switch (chr_code) {
+ case open_node: print_esc(@[@<|"openout"|@>@]);@+break;
+ case write_node: print_esc(@[@<|"write"|@>@]);@+break;
+ case close_node: print_esc(@[@<|"closeout"|@>@]);@+break;
+ case special_node: print_esc(@[@<|"special"|@>@]);@+break;
+ case immediate_code: print_esc(@[@<|"immediate"|@>@]);@+break;
+ case set_language_code: print_esc(@[@<|"setlanguage"|@>@]);@+break;
+ default:print_str("[unknown extension!]");
+ } @+break;
+
+@ When an |extension| command occurs in |main_control|, in any mode,
+the |do_extension| routine is called.
+
+@<Cases of |main_control| that are for extensions...@>=
+any_mode(extension): do_extension();
+
+@ @<Declare act...@>=
+@t\4@>@<Declare procedures needed in |do_extension|@>@;
+void do_extension(void)
+{@+int @!k; /*all-purpose integer*/
+pointer @!p; /*all-purpose pointer*/
+switch (cur_chr) {
+case open_node: @<Implement \.{\\openout}@>@;@+break;
+case write_node: @<Implement \.{\\write}@>@;@+break;
+case close_node: @<Implement \.{\\closeout}@>@;@+break;
+case special_node: @<Implement \.{\\special}@>@;@+break;
+case immediate_code: @<Implement \.{\\immediate}@>@;@+break;
+case set_language_code: @<Implement \.{\\setlanguage}@>@;@+break;
+default:confusion(@[@<|"ext1"|@>@]);
+@:this can't happen ext1}{\quad ext1@>
+}
+}
+
+@ Here is a subroutine that creates a whatsit node having a given |subtype|
+and a given number of words. It initializes only the first word of the whatsit,
+and appends it to the current list.
+
+@<Declare procedures needed in |do_extension|@>=
+void new_whatsit(small_number @!s, small_number @!w)
+{@+pointer p; /*the new node*/
+p=get_node(w);type(p)=whatsit_node;subtype(p)=s;
+link(tail)=p;tail=p;
+}
+
+@ The next subroutine uses |cur_chr| to decide what sort of whatsit is
+involved, and also inserts a |write_stream| number.
+
+@<Declare procedures needed in |do_ext...@>=
+void new_write_whatsit(small_number @!w)
+{@+new_whatsit(cur_chr, w);
+if (w!=write_node_size) scan_four_bit_int();
+else{@+scan_int();
+ if (cur_val < 0) cur_val=17;
+ else if (cur_val > 15) cur_val=16;
+ }
+write_stream(tail)=cur_val;
+}
+
+@ @<Implement \.{\\openout}@>=
+{@+new_write_whatsit(open_node_size);
+scan_optional_equals();scan_file_name();@/
+open_name(tail)=cur_name;open_area(tail)=cur_area;open_ext(tail)=cur_ext;
+}
+
+@ When `\.{\\write 12\{...\}}' appears, we scan the token list `\.{\{...\}}'
+without expanding its macros; the macros will be expanded later when this
+token list is rescanned.
+
+@<Implement \.{\\write}@>=
+{@+k=cur_cs;new_write_whatsit(write_node_size);@/
+cur_cs=k;p=scan_toks(false, false);write_tokens(tail)=def_ref;
+}
+
+@ @<Implement \.{\\closeout}@>=
+{@+new_write_whatsit(write_node_size);write_tokens(tail)=null;
+}
+
+@ When `\.{\\special\{...\}}' appears, we expand the macros in the token
+list as in \.{\\xdef} and \.{\\mark}.
+
+@<Implement \.{\\special}@>=
+{@+new_whatsit(special_node, write_node_size);write_stream(tail)=null;
+p=scan_toks(false, true);write_tokens(tail)=def_ref;
+}
+
+@ Each new type of node that appears in our data structure must be capable
+of being displayed, copied, destroyed, and so on. The routines that we
+need for write-oriented whatsits are somewhat like those for mark nodes;
+other extensions might, of course, involve more subtlety here.
+
+@<Basic printing...@>=
+void print_write_whatsit(str_number @!s, pointer @!p)
+{@+print_esc(s);
+if (write_stream(p) < 16) print_int(write_stream(p));
+else if (write_stream(p)==16) print_char('*');
+@.*\relax@>
+else print_char('-');
+}
+
+@ @<Display the whatsit...@>=
+switch (subtype(p)) {
+case open_node: {@+print_write_whatsit(@[@<|"openout"|@>@], p);
+ print_char('=');print_file_name(open_name(p), open_area(p), open_ext(p));
+ } @+break;
+case write_node: {@+print_write_whatsit(@[@<|"write"|@>@], p);
+ print_mark(write_tokens(p));
+ } @+break;
+case close_node: print_write_whatsit(@[@<|"closeout"|@>@], p);@+break;
+case special_node: {@+print_esc(@[@<|"special"|@>@]);
+ print_mark(write_tokens(p));
+ } @+break;
+case language_node: {@+print_esc(@[@<|"setlanguage"|@>@]);
+ print_int(what_lang(p));print_str(" (hyphenmin ");
+ print_int(what_lhm(p));print_char(',');
+ print_int(what_rhm(p));print_char(')');
+ } @+break;
+default:print_str("whatsit?");
+}
+
+@ @<Make a partial copy of the whatsit...@>=
+switch (subtype(p)) {
+case open_node: {@+r=get_node(open_node_size);words=open_node_size;
+ } @+break;
+case write_node: case special_node: {@+r=get_node(write_node_size);
+ add_token_ref(write_tokens(p));words=write_node_size;
+ } @+break;
+case close_node: case language_node: {@+r=get_node(small_node_size);
+ words=small_node_size;
+ } @+break;
+default:confusion(@[@<|"ext2"|@>@]);
+@:this can't happen ext2}{\quad ext2@>
+}
+
+@ @<Wipe out the whatsit...@>=
+{@+switch (subtype(p)) {
+case open_node: free_node(p, open_node_size);@+break;
+case write_node: case special_node: {@+delete_token_ref(write_tokens(p));
+ free_node(p, write_node_size);goto done;
+ }
+case close_node: case language_node: free_node(p, small_node_size);@+break;
+default:confusion(@[@<|"ext3"|@>@]);
+@:this can't happen ext3}{\quad ext3@>
+} @/
+goto done;
+}
+
+@ @<Incorporate a whatsit node into a vbox@>=do_nothing
+
+@ @<Incorporate a whatsit node into an hbox@>=do_nothing
+
+@ @<Let |d| be the width of the whatsit |p|@>=d=0
+
+@ @d adv_past(X) @+if (subtype(X)==language_node)
+ {@+cur_lang=what_lang(X);l_hyf=what_lhm(X);r_hyf=what_rhm(X);@+}
+
+@<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>=@+
+adv_past(cur_p)
+
+@ @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>=@+
+adv_past(s)
+
+@ @<Prepare to move whatsit |p| to the current page, then |goto contribute|@>=
+goto contribute
+
+@ @<Process whatsit |p| in |vert_break| loop, |goto not_found|@>=
+goto not_found
+
+@ @<Output the whatsit node |p| in a vlist@>=
+out_what(p)
+
+@ @<Output the whatsit node |p| in an hlist@>=
+out_what(p)
+
+@ After all this preliminary shuffling, we come finally to the routines
+that actually send out the requested data. Let's do \.{\\special} first
+(it's easier).
+
+@<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+void special_out(pointer @!p)
+{@+uint8_t old_setting; /*holds print |selector|*/
+int @!k; /*index into |str_pool|*/
+synch_h;synch_v;@/
+old_setting=selector;selector=new_string;
+show_token_list(link(write_tokens(p)), null, pool_size-pool_ptr);
+selector=old_setting;
+str_room(1);
+if (cur_length < 256)
+ {@+dvi_out(xxx1);dvi_out(cur_length);
+ }
+else{@+dvi_out(xxx4);dvi_four(cur_length);
+ }
+for (k=str_start[str_ptr]; k<=pool_ptr-1; k++) dvi_out(so(str_pool[k]));
+pool_ptr=str_start[str_ptr]; /*erase the string*/
+}
+
+@ To write a token list, we must run it through \TeX's scanner, expanding
+macros and \.{\\the} and \.{\\number}, etc. This might cause runaways,
+if a delimited macro parameter isn't matched, and runaways would be
+extremely confusing since we are calling on \TeX's scanner in the middle
+of a \.{\\shipout} command. Therefore we will put a dummy control sequence as
+a ``stopper,'' right after the token list. This control sequence is
+artificially defined to be \.{\\outer}.
+@:end_write_}{\.{\\endwrite}@>
+
+@<Initialize table...@>=
+text(end_write)=@[@<|"endwrite"|@>@];eq_level(end_write)=level_one;
+eq_type(end_write)=outer_call;equiv(end_write)=null;
+
+@ @<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+void write_out(pointer @!p)
+{@+uint8_t old_setting; /*holds print |selector|*/
+int @!old_mode; /*saved |mode|*/
+small_number @!j; /*write stream number*/
+pointer @!q, @!r; /*temporary variables for list manipulation*/
+@<Expand macros in the token list and make |link(def_ref)| point to the result@>;
+old_setting=selector;j=write_stream(p);
+if (write_open[j]) selector=j;
+else{@+ /*write to the terminal if file isn't open*/
+ if ((j==17)&&(selector==term_and_log)) selector=log_only;
+ print_nl("");
+ }
+token_show(def_ref);print_ln();
+flush_list(def_ref);selector=old_setting;
+}
+
+@ The final line of this routine is slightly subtle; at least, the author
+didn't think about it until getting burnt! There is a used-up token list
+@^Knuth, Donald Ervin@>
+on the stack, namely the one that contained |end_write_token|. (We
+insert this artificial `\.{\\endwrite}' to prevent runaways, as explained
+above.) If it were not removed, and if there were numerous writes on a
+single page, the stack would overflow.
+
+@d end_write_token cs_token_flag+end_write
+
+@<Expand macros in the token list and...@>=
+q=get_avail();info(q)=right_brace_token+'}';@/
+r=get_avail();link(q)=r;info(r)=end_write_token;ins_list(q);@/
+begin_token_list(write_tokens(p), write_text);@/
+q=get_avail();info(q)=left_brace_token+'{';ins_list(q);
+ /*now we're ready to scan
+ `\.\{$\langle\,$token list$\,\rangle$\.{\} \\endwrite}'*/
+old_mode=mode;mode=0;
+ /*disable \.{\\prevdepth}, \.{\\spacefactor}, \.{\\lastskip}, \.{\\prevgraf}*/
+cur_cs=write_loc;q=scan_toks(false, true); /*expand macros, etc.*/
+get_token();@+if (cur_tok!=end_write_token)
+ @<Recover from an unbalanced write command@>;
+mode=old_mode;
+end_token_list() /*conserve stack space*/
+
+@ @<Recover from an unbalanced write command@>=
+{@+print_err("Unbalanced write command");
+@.Unbalanced write...@>
+help2("On this page there's a \\write with fewer real {'s than }'s.")@/
+("I can't handle that very well; good luck.");error();
+@/do@+{get_token();
+}@+ while (!(cur_tok==end_write_token));
+}
+
+@ The |out_what| procedure takes care of outputting whatsit nodes for
+|vlist_out| and |hlist_out|\kern-.3pt.
+
+@<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+void out_what(pointer @!p)
+{@+small_number j; /*write stream number*/
+switch (subtype(p)) {
+case open_node: case write_node: case close_node: @<Do some work that has been queued
+up for \.{\\write}@>@;@+break;
+case special_node: special_out(p);@+break;
+case language_node: do_nothing;@+break;
+default:confusion(@[@<|"ext4"|@>@]);
+@:this can't happen ext4}{\quad ext4@>
+}
+}
+
+@ We don't implement \.{\\write} inside of leaders. (The reason is that
+the number of times a leader box appears might be different in different
+implementations, due to machine-dependent rounding in the glue calculations.)
+@^leaders@>
+
+@<Do some work that has been queued up...@>=
+if (!doing_leaders)
+ {@+j=write_stream(p);
+ if (subtype(p)==write_node) write_out(p);
+ else{@+if (write_open[j]) a_close(&write_file[j]);
+ if (subtype(p)==close_node) write_open[j]=false;
+ else if (j < 16)
+ {@+cur_name=open_name(p);cur_area=open_area(p);
+ cur_ext=open_ext(p);
+ if (cur_ext==empty_string) cur_ext=@[@<|".tex"|@>@];
+ pack_cur_name;
+ while (!a_open_out(&write_file[j]))
+ prompt_file_name("output file name",@[@<|".tex"|@>@]);
+ write_open[j]=true;
+ }
+ }
+ }
+
+@ The presence of `\.{\\immediate}' causes the |do_extension| procedure
+to descend to one level of recursion. Nothing happens unless \.{\\immediate}
+is followed by `\.{\\openout}', `\.{\\write}', or `\.{\\closeout}'.
+@^recursion@>
+
+@<Implement \.{\\immediate}@>=
+{@+get_x_token();
+if ((cur_cmd==extension)&&(cur_chr <= close_node))
+ {@+p=tail;do_extension(); /*append a whatsit node*/
+ out_what(tail); /*do the action immediately*/
+ flush_node_list(tail);tail=p;link(p)=null;
+ }
+else back_input();
+}
+
+@ The \.{\\language} extension is somewhat different.
+We need a subroutine that comes into play when a character of
+a non-|clang| language is being appended to the current paragraph.
+
+@<Declare action...@>=
+void fix_language(void)
+{@+ASCII_code @!l; /*the new current language*/
+if (language <= 0) l=0;
+else if (language > 255) l=0;
+else l=language;
+if (l!=clang)
+ {@+new_whatsit(language_node, small_node_size);
+ what_lang(tail)=l;clang=l;@/
+ what_lhm(tail)=norm_min(left_hyphen_min);
+ what_rhm(tail)=norm_min(right_hyphen_min);
+ }
+}
+
+@ @<Implement \.{\\setlanguage}@>=
+if (abs(mode)!=hmode) report_illegal_case();
+else{@+new_whatsit(language_node, small_node_size);
+ scan_int();
+ if (cur_val <= 0) clang=0;
+ else if (cur_val > 255) clang=0;
+ else clang=cur_val;
+ what_lang(tail)=clang;
+ what_lhm(tail)=norm_min(left_hyphen_min);
+ what_rhm(tail)=norm_min(right_hyphen_min);
+ }
+
+@ @<Finish the extensions@>=
+for (k=0; k<=15; k++) if (write_open[k]) a_close(&write_file[k])
+
+@* System-dependent changes.
+This section should be replaced, if necessary, by any special
+modifications of the program
+that are necessary to make \TeX\ work at a particular installation.
+It is usually best to design your change file so that all changes to
+previous sections preserve the section numbering; then everybody's version
+will be consistent with the published program. More extensive changes,
+which introduce new sections, can be inserted here; then only the index
+itself will get a new section number.
+@^system dependencies@>
+
+@ Appendix: Replacement of the string pool file.
+@d str_0_255 "^^@@^^A^^B^^C^^D^^E^^F^^G^^H^^I^^J^^K^^L^^M^^N^^O"@/
+ "^^P^^Q^^R^^S^^T^^U^^V^^W^^X^^Y^^Z^^[^^\\^^]^^^^^_"@/
+ " !\"#$%&'()*+,-./"@/
+ "0123456789:;<=>?"@/
+ "@@ABCDEFGHIJKLMNO"@/
+ "PQRSTUVWXYZ[\\]^_"@/
+ "`abcdefghijklmno"@/
+ "pqrstuvwxyz{|}~^^?"@/
+ "^^80^^81^^82^^83^^84^^85^^86^^87^^88^^89^^8a^^8b^^8c^^8d^^8e^^8f"@/
+ "^^90^^91^^92^^93^^94^^95^^96^^97^^98^^99^^9a^^9b^^9c^^9d^^9e^^9f"@/
+ "^^a0^^a1^^a2^^a3^^a4^^a5^^a6^^a7^^a8^^a9^^aa^^ab^^ac^^ad^^ae^^af"@/
+ "^^b0^^b1^^b2^^b3^^b4^^b5^^b6^^b7^^b8^^b9^^ba^^bb^^bc^^bd^^be^^bf"@/
+ "^^c0^^c1^^c2^^c3^^c4^^c5^^c6^^c7^^c8^^c9^^ca^^cb^^cc^^cd^^ce^^cf"@/
+ "^^d0^^d1^^d2^^d3^^d4^^d5^^d6^^d7^^d8^^d9^^da^^db^^dc^^dd^^de^^df"@/
+ "^^e0^^e1^^e2^^e3^^e4^^e5^^e6^^e7^^e8^^e9^^ea^^eb^^ec^^ed^^ee^^ef"@/
+ "^^f0^^f1^^f2^^f3^^f4^^f5^^f6^^f7^^f8^^f9^^fa^^fb^^fc^^fd^^fe^^ff"@/
+@d str_start_0_255 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45,@/
+ 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93,@/
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,@/
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,@/
+ 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,@/
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,@/
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,@/
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,@/
+ 194, 198, 202, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250, 254,@/
+ 258, 262, 266, 270, 274, 278, 282, 286, 290, 294, 298, 302, 306, 310, 314, 318,@/
+ 322, 326, 330, 334, 338, 342, 346, 350, 354, 358, 362, 366, 370, 374, 378, 382,@/
+ 386, 390, 394, 398, 402, 406, 410, 414, 418, 422, 426, 430, 434, 438, 442, 446,@/
+ 450, 454, 458, 462, 466, 470, 474, 478, 482, 486, 490, 494, 498, 502, 506, 510,@/
+ 514, 518, 522, 526, 530, 534, 538, 542, 546, 550, 554, 558, 562, 566, 570, 574,@/
+ 578, 582, 586, 590, 594, 598, 602, 606, 610, 614, 618, 622, 626, 630, 634, 638,@/
+ 642, 646, 650, 654, 658, 662, 666, 670, 674, 678, 682, 686, 690, 694, 698, 702,@/
+@
+@d str_256 "???"
+@<|"???"|@>=@+256
+@
+@d str_257 "m2d5c2l5x2v5i"
+@<|"m2d5c2l5x2v5i"|@>=@+257
+@
+@d str_258 "batchmode"
+@<|"batchmode"|@>=@+258
+@
+@d str_259 "nonstopmode"
+@<|"nonstopmode"|@>=@+259
+@
+@d str_260 "scrollmode"
+@<|"scrollmode"|@>=@+260
+@
+@d str_261 "CLOBBERED."
+@<|"CLOBBERED."|@>=@+261
+@
+@d str_262 "fil"
+@<|"fil"|@>=@+262
+@
+@d str_263 "unset"
+@<|"unset"|@>=@+263
+@
+@d str_264 "rule("
+@<|"rule("|@>=@+264
+@
+@d str_265 "insert"
+@<|"insert"|@>=@+265
+@
+@d str_266 "glue"
+@<|"glue"|@>=@+266
+@
+@d str_267 "nonscript"
+@<|"nonscript"|@>=@+267
+@
+@d str_268 "mskip"
+@<|"mskip"|@>=@+268
+@
+@d str_269 "mu"
+@<|"mu"|@>=@+269
+@
+@d str_270 ""
+@d empty_string 270
+@
+@d str_271 "kern"
+@<|"kern"|@>=@+271
+@
+@d str_272 "mkern"
+@<|"mkern"|@>=@+272
+@
+@d str_273 "math"
+@<|"math"|@>=@+273
+@
+@d str_274 "penalty "
+@<|"penalty "|@>=@+274
+@
+@d str_275 "discretionary"
+@<|"discretionary"|@>=@+275
+@
+@d str_276 "mark"
+@<|"mark"|@>=@+276
+@
+@d str_277 "vadjust"
+@<|"vadjust"|@>=@+277
+@
+@d str_278 "flushing"
+@<|"flushing"|@>=@+278
+@
+@d str_279 "copying"
+@<|"copying"|@>=@+279
+@
+@d str_280 "lineskip"
+@<|"lineskip"|@>=@+280
+@
+@d str_281 "baselineskip"
+@<|"baselineskip"|@>=@+281
+@
+@d str_282 "parskip"
+@<|"parskip"|@>=@+282
+@
+@d str_283 "abovedisplayskip"
+@<|"abovedisplayskip"|@>=@+283
+@
+@d str_284 "belowdisplayskip"
+@<|"belowdisplayskip"|@>=@+284
+@
+@d str_285 "abovedisplayshortskip"
+@<|"abovedisplayshortskip"|@>=@+285
+@
+@d str_286 "belowdisplayshortskip"
+@<|"belowdisplayshortskip"|@>=@+286
+@
+@d str_287 "leftskip"
+@<|"leftskip"|@>=@+287
+@
+@d str_288 "rightskip"
+@<|"rightskip"|@>=@+288
+@
+@d str_289 "topskip"
+@<|"topskip"|@>=@+289
+@
+@d str_290 "splittopskip"
+@<|"splittopskip"|@>=@+290
+@
+@d str_291 "tabskip"
+@<|"tabskip"|@>=@+291
+@
+@d str_292 "spaceskip"
+@<|"spaceskip"|@>=@+292
+@
+@d str_293 "xspaceskip"
+@<|"xspaceskip"|@>=@+293
+@
+@d str_294 "parfillskip"
+@<|"parfillskip"|@>=@+294
+@
+@d str_295 "thinmuskip"
+@<|"thinmuskip"|@>=@+295
+@
+@d str_296 "medmuskip"
+@<|"medmuskip"|@>=@+296
+@
+@d str_297 "thickmuskip"
+@<|"thickmuskip"|@>=@+297
+@
+@d str_298 "skip"
+@<|"skip"|@>=@+298
+@
+@d str_299 "muskip"
+@<|"muskip"|@>=@+299
+@
+@d str_300 "pt"
+@<|"pt"|@>=@+300
+@
+@d str_301 "output"
+@<|"output"|@>=@+301
+@
+@d str_302 "everypar"
+@<|"everypar"|@>=@+302
+@
+@d str_303 "everymath"
+@<|"everymath"|@>=@+303
+@
+@d str_304 "everydisplay"
+@<|"everydisplay"|@>=@+304
+@
+@d str_305 "everyhbox"
+@<|"everyhbox"|@>=@+305
+@
+@d str_306 "everyvbox"
+@<|"everyvbox"|@>=@+306
+@
+@d str_307 "everyjob"
+@<|"everyjob"|@>=@+307
+@
+@d str_308 "everycr"
+@<|"everycr"|@>=@+308
+@
+@d str_309 "errhelp"
+@<|"errhelp"|@>=@+309
+@
+@d str_310 "toks"
+@<|"toks"|@>=@+310
+@
+@d str_311 "parshape"
+@<|"parshape"|@>=@+311
+@
+@d str_312 "box"
+@<|"box"|@>=@+312
+@
+@d str_313 "textfont"
+@<|"textfont"|@>=@+313
+@
+@d str_314 "scriptfont"
+@<|"scriptfont"|@>=@+314
+@
+@d str_315 "scriptscriptfont"
+@<|"scriptscriptfont"|@>=@+315
+@
+@d str_316 "catcode"
+@<|"catcode"|@>=@+316
+@
+@d str_317 "lccode"
+@<|"lccode"|@>=@+317
+@
+@d str_318 "uccode"
+@<|"uccode"|@>=@+318
+@
+@d str_319 "sfcode"
+@<|"sfcode"|@>=@+319
+@
+@d str_320 "mathcode"
+@<|"mathcode"|@>=@+320
+@
+@d str_321 "pretolerance"
+@<|"pretolerance"|@>=@+321
+@
+@d str_322 "tolerance"
+@<|"tolerance"|@>=@+322
+@
+@d str_323 "linepenalty"
+@<|"linepenalty"|@>=@+323
+@
+@d str_324 "hyphenpenalty"
+@<|"hyphenpenalty"|@>=@+324
+@
+@d str_325 "exhyphenpenalty"
+@<|"exhyphenpenalty"|@>=@+325
+@
+@d str_326 "clubpenalty"
+@<|"clubpenalty"|@>=@+326
+@
+@d str_327 "widowpenalty"
+@<|"widowpenalty"|@>=@+327
+@
+@d str_328 "displaywidowpenalty"
+@<|"displaywidowpenalty"|@>=@+328
+@
+@d str_329 "brokenpenalty"
+@<|"brokenpenalty"|@>=@+329
+@
+@d str_330 "binoppenalty"
+@<|"binoppenalty"|@>=@+330
+@
+@d str_331 "relpenalty"
+@<|"relpenalty"|@>=@+331
+@
+@d str_332 "predisplaypenalty"
+@<|"predisplaypenalty"|@>=@+332
+@
+@d str_333 "postdisplaypenalty"
+@<|"postdisplaypenalty"|@>=@+333
+@
+@d str_334 "interlinepenalty"
+@<|"interlinepenalty"|@>=@+334
+@
+@d str_335 "doublehyphendemerits"
+@<|"doublehyphendemerits"|@>=@+335
+@
+@d str_336 "finalhyphendemerits"
+@<|"finalhyphendemerits"|@>=@+336
+@
+@d str_337 "adjdemerits"
+@<|"adjdemerits"|@>=@+337
+@
+@d str_338 "mag"
+@<|"mag"|@>=@+338
+@
+@d str_339 "delimiterfactor"
+@<|"delimiterfactor"|@>=@+339
+@
+@d str_340 "looseness"
+@<|"looseness"|@>=@+340
+@
+@d str_341 "time"
+@<|"time"|@>=@+341
+@
+@d str_342 "day"
+@<|"day"|@>=@+342
+@
+@d str_343 "month"
+@<|"month"|@>=@+343
+@
+@d str_344 "year"
+@<|"year"|@>=@+344
+@
+@d str_345 "showboxbreadth"
+@<|"showboxbreadth"|@>=@+345
+@
+@d str_346 "showboxdepth"
+@<|"showboxdepth"|@>=@+346
+@
+@d str_347 "hbadness"
+@<|"hbadness"|@>=@+347
+@
+@d str_348 "vbadness"
+@<|"vbadness"|@>=@+348
+@
+@d str_349 "pausing"
+@<|"pausing"|@>=@+349
+@
+@d str_350 "tracingonline"
+@<|"tracingonline"|@>=@+350
+@
+@d str_351 "tracingmacros"
+@<|"tracingmacros"|@>=@+351
+@
+@d str_352 "tracingstats"
+@<|"tracingstats"|@>=@+352
+@
+@d str_353 "tracingparagraphs"
+@<|"tracingparagraphs"|@>=@+353
+@
+@d str_354 "tracingpages"
+@<|"tracingpages"|@>=@+354
+@
+@d str_355 "tracingoutput"
+@<|"tracingoutput"|@>=@+355
+@
+@d str_356 "tracinglostchars"
+@<|"tracinglostchars"|@>=@+356
+@
+@d str_357 "tracingcommands"
+@<|"tracingcommands"|@>=@+357
+@
+@d str_358 "tracingrestores"
+@<|"tracingrestores"|@>=@+358
+@
+@d str_359 "uchyph"
+@<|"uchyph"|@>=@+359
+@
+@d str_360 "outputpenalty"
+@<|"outputpenalty"|@>=@+360
+@
+@d str_361 "maxdeadcycles"
+@<|"maxdeadcycles"|@>=@+361
+@
+@d str_362 "hangafter"
+@<|"hangafter"|@>=@+362
+@
+@d str_363 "floatingpenalty"
+@<|"floatingpenalty"|@>=@+363
+@
+@d str_364 "globaldefs"
+@<|"globaldefs"|@>=@+364
+@
+@d str_365 "fam"
+@<|"fam"|@>=@+365
+@
+@d str_366 "escapechar"
+@<|"escapechar"|@>=@+366
+@
+@d str_367 "defaulthyphenchar"
+@<|"defaulthyphenchar"|@>=@+367
+@
+@d str_368 "defaultskewchar"
+@<|"defaultskewchar"|@>=@+368
+@
+@d str_369 "endlinechar"
+@<|"endlinechar"|@>=@+369
+@
+@d str_370 "newlinechar"
+@<|"newlinechar"|@>=@+370
+@
+@d str_371 "language"
+@<|"language"|@>=@+371
+@
+@d str_372 "lefthyphenmin"
+@<|"lefthyphenmin"|@>=@+372
+@
+@d str_373 "righthyphenmin"
+@<|"righthyphenmin"|@>=@+373
+@
+@d str_374 "holdinginserts"
+@<|"holdinginserts"|@>=@+374
+@
+@d str_375 "errorcontextlines"
+@<|"errorcontextlines"|@>=@+375
+@
+@d str_376 "count"
+@<|"count"|@>=@+376
+@
+@d str_377 "delcode"
+@<|"delcode"|@>=@+377
+@
+@d str_378 "parindent"
+@<|"parindent"|@>=@+378
+@
+@d str_379 "mathsurround"
+@<|"mathsurround"|@>=@+379
+@
+@d str_380 "lineskiplimit"
+@<|"lineskiplimit"|@>=@+380
+@
+@d str_381 "hsize"
+@<|"hsize"|@>=@+381
+@
+@d str_382 "vsize"
+@<|"vsize"|@>=@+382
+@
+@d str_383 "maxdepth"
+@<|"maxdepth"|@>=@+383
+@
+@d str_384 "splitmaxdepth"
+@<|"splitmaxdepth"|@>=@+384
+@
+@d str_385 "boxmaxdepth"
+@<|"boxmaxdepth"|@>=@+385
+@
+@d str_386 "hfuzz"
+@<|"hfuzz"|@>=@+386
+@
+@d str_387 "vfuzz"
+@<|"vfuzz"|@>=@+387
+@
+@d str_388 "delimitershortfall"
+@<|"delimitershortfall"|@>=@+388
+@
+@d str_389 "nulldelimiterspace"
+@<|"nulldelimiterspace"|@>=@+389
+@
+@d str_390 "scriptspace"
+@<|"scriptspace"|@>=@+390
+@
+@d str_391 "predisplaysize"
+@<|"predisplaysize"|@>=@+391
+@
+@d str_392 "displaywidth"
+@<|"displaywidth"|@>=@+392
+@
+@d str_393 "displayindent"
+@<|"displayindent"|@>=@+393
+@
+@d str_394 "overfullrule"
+@<|"overfullrule"|@>=@+394
+@
+@d str_395 "hangindent"
+@<|"hangindent"|@>=@+395
+@
+@d str_396 "hoffset"
+@<|"hoffset"|@>=@+396
+@
+@d str_397 "voffset"
+@<|"voffset"|@>=@+397
+@
+@d str_398 "emergencystretch"
+@<|"emergencystretch"|@>=@+398
+@
+@d str_399 "dimen"
+@<|"dimen"|@>=@+399
+@
+@d str_400 "notexpanded:"
+@<|"notexpanded:"|@>=@+400
+@
+@d str_401 "csname"
+@<|"csname"|@>=@+401
+@
+@d str_402 "endcsname"
+@<|"endcsname"|@>=@+402
+@
+@d str_403 "IMPOSSIBLE."
+@<|"IMPOSSIBLE."|@>=@+403
+@
+@d str_404 "NONEXISTENT."
+@<|"NONEXISTENT."|@>=@+404
+@
+@d str_405 "accent"
+@<|"accent"|@>=@+405
+@
+@d str_406 "advance"
+@<|"advance"|@>=@+406
+@
+@d str_407 "afterassignment"
+@<|"afterassignment"|@>=@+407
+@
+@d str_408 "aftergroup"
+@<|"aftergroup"|@>=@+408
+@
+@d str_409 "begingroup"
+@<|"begingroup"|@>=@+409
+@
+@d str_410 "char"
+@<|"char"|@>=@+410
+@
+@d str_411 "delimiter"
+@<|"delimiter"|@>=@+411
+@
+@d str_412 "divide"
+@<|"divide"|@>=@+412
+@
+@d str_413 "endgroup"
+@<|"endgroup"|@>=@+413
+@
+@d str_414 "expandafter"
+@<|"expandafter"|@>=@+414
+@
+@d str_415 "font"
+@<|"font"|@>=@+415
+@
+@d str_416 "fontdimen"
+@<|"fontdimen"|@>=@+416
+@
+@d str_417 "halign"
+@<|"halign"|@>=@+417
+@
+@d str_418 "hrule"
+@<|"hrule"|@>=@+418
+@
+@d str_419 "ignorespaces"
+@<|"ignorespaces"|@>=@+419
+@
+@d str_420 "mathaccent"
+@<|"mathaccent"|@>=@+420
+@
+@d str_421 "mathchar"
+@<|"mathchar"|@>=@+421
+@
+@d str_422 "mathchoice"
+@<|"mathchoice"|@>=@+422
+@
+@d str_423 "multiply"
+@<|"multiply"|@>=@+423
+@
+@d str_424 "noalign"
+@<|"noalign"|@>=@+424
+@
+@d str_425 "noboundary"
+@<|"noboundary"|@>=@+425
+@
+@d str_426 "noexpand"
+@<|"noexpand"|@>=@+426
+@
+@d str_427 "omit"
+@<|"omit"|@>=@+427
+@
+@d str_428 "penalty"
+@<|"penalty"|@>=@+428
+@
+@d str_429 "prevgraf"
+@<|"prevgraf"|@>=@+429
+@
+@d str_430 "radical"
+@<|"radical"|@>=@+430
+@
+@d str_431 "read"
+@<|"read"|@>=@+431
+@
+@d str_432 "relax"
+@<|"relax"|@>=@+432
+@
+@d str_433 "setbox"
+@<|"setbox"|@>=@+433
+@
+@d str_434 "the"
+@<|"the"|@>=@+434
+@
+@d str_435 "valign"
+@<|"valign"|@>=@+435
+@
+@d str_436 "vcenter"
+@<|"vcenter"|@>=@+436
+@
+@d str_437 "vrule"
+@<|"vrule"|@>=@+437
+@
+@d str_438 "curlevel"
+@<|"curlevel"|@>=@+438
+@
+@d str_439 "retaining"
+@<|"retaining"|@>=@+439
+@
+@d str_440 "restoring"
+@<|"restoring"|@>=@+440
+@
+@d str_441 "ETC."
+@<|"ETC."|@>=@+441
+@
+@d str_442 "BAD."
+@<|"BAD."|@>=@+442
+@
+@d str_443 "write"
+@<|"write"|@>=@+443
+@
+@d str_444 "par"
+@<|"par"|@>=@+444
+@
+@d str_445 "input"
+@<|"input"|@>=@+445
+@
+@d str_446 "endinput"
+@<|"endinput"|@>=@+446
+@
+@d str_447 "topmark"
+@<|"topmark"|@>=@+447
+@
+@d str_448 "firstmark"
+@<|"firstmark"|@>=@+448
+@
+@d str_449 "botmark"
+@<|"botmark"|@>=@+449
+@
+@d str_450 "splitfirstmark"
+@<|"splitfirstmark"|@>=@+450
+@
+@d str_451 "splitbotmark"
+@<|"splitbotmark"|@>=@+451
+@
+@d str_452 "spacefactor"
+@<|"spacefactor"|@>=@+452
+@
+@d str_453 "prevdepth"
+@<|"prevdepth"|@>=@+453
+@
+@d str_454 "deadcycles"
+@<|"deadcycles"|@>=@+454
+@
+@d str_455 "insertpenalties"
+@<|"insertpenalties"|@>=@+455
+@
+@d str_456 "wd"
+@<|"wd"|@>=@+456
+@
+@d str_457 "ht"
+@<|"ht"|@>=@+457
+@
+@d str_458 "dp"
+@<|"dp"|@>=@+458
+@
+@d str_459 "lastpenalty"
+@<|"lastpenalty"|@>=@+459
+@
+@d str_460 "lastkern"
+@<|"lastkern"|@>=@+460
+@
+@d str_461 "lastskip"
+@<|"lastskip"|@>=@+461
+@
+@d str_462 "inputlineno"
+@<|"inputlineno"|@>=@+462
+@
+@d str_463 "badness"
+@<|"badness"|@>=@+463
+@
+@d str_464 "true"
+@<|"true"|@>=@+464
+@
+@d str_465 "em"
+@<|"em"|@>=@+465
+@
+@d str_466 "ex"
+@<|"ex"|@>=@+466
+@
+@d str_467 "in"
+@<|"in"|@>=@+467
+@
+@d str_468 "pc"
+@<|"pc"|@>=@+468
+@
+@d str_469 "cm"
+@<|"cm"|@>=@+469
+@
+@d str_470 "mm"
+@<|"mm"|@>=@+470
+@
+@d str_471 "bp"
+@<|"bp"|@>=@+471
+@
+@d str_472 "dd"
+@<|"dd"|@>=@+472
+@
+@d str_473 "cc"
+@<|"cc"|@>=@+473
+@
+@d str_474 "sp"
+@<|"sp"|@>=@+474
+@
+@d str_475 "plus"
+@<|"plus"|@>=@+475
+@
+@d str_476 "minus"
+@<|"minus"|@>=@+476
+@
+@d str_477 "width"
+@<|"width"|@>=@+477
+@
+@d str_478 "height"
+@<|"height"|@>=@+478
+@
+@d str_479 "depth"
+@<|"depth"|@>=@+479
+@
+@d str_480 "number"
+@<|"number"|@>=@+480
+@
+@d str_481 "romannumeral"
+@<|"romannumeral"|@>=@+481
+@
+@d str_482 "string"
+@<|"string"|@>=@+482
+@
+@d str_483 "meaning"
+@<|"meaning"|@>=@+483
+@
+@d str_484 "fontname"
+@<|"fontname"|@>=@+484
+@
+@d str_485 "jobname"
+@<|"jobname"|@>=@+485
+@
+@d str_486 "if"
+@<|"if"|@>=@+486
+@
+@d str_487 "ifcat"
+@<|"ifcat"|@>=@+487
+@
+@d str_488 "ifnum"
+@<|"ifnum"|@>=@+488
+@
+@d str_489 "ifdim"
+@<|"ifdim"|@>=@+489
+@
+@d str_490 "ifodd"
+@<|"ifodd"|@>=@+490
+@
+@d str_491 "ifvmode"
+@<|"ifvmode"|@>=@+491
+@
+@d str_492 "ifhmode"
+@<|"ifhmode"|@>=@+492
+@
+@d str_493 "ifmmode"
+@<|"ifmmode"|@>=@+493
+@
+@d str_494 "ifinner"
+@<|"ifinner"|@>=@+494
+@
+@d str_495 "ifvoid"
+@<|"ifvoid"|@>=@+495
+@
+@d str_496 "ifhbox"
+@<|"ifhbox"|@>=@+496
+@
+@d str_497 "ifvbox"
+@<|"ifvbox"|@>=@+497
+@
+@d str_498 "ifx"
+@<|"ifx"|@>=@+498
+@
+@d str_499 "ifeof"
+@<|"ifeof"|@>=@+499
+@
+@d str_500 "iftrue"
+@<|"iftrue"|@>=@+500
+@
+@d str_501 "iffalse"
+@<|"iffalse"|@>=@+501
+@
+@d str_502 "ifcase"
+@<|"ifcase"|@>=@+502
+@
+@d str_503 "fi"
+@<|"fi"|@>=@+503
+@
+@d str_504 "or"
+@<|"or"|@>=@+504
+@
+@d str_505 "else"
+@<|"else"|@>=@+505
+@
+@d str_506 "TeXinputs/"
+@d TEX_area 506
+@
+@d str_507 "TeXfonts/"
+@d TEX_font_area 507
+@
+@d str_508 ".fmt"
+@d format_extension 508
+@
+@d str_509 ".log"
+@<|".log"|@>=@+509
+@
+@d str_510 ".dvi"
+@<|".dvi"|@>=@+510
+@
+@d str_511 "input file name"
+@<|"input file name"|@>=@+511
+@
+@d str_512 ".tex"
+@<|".tex"|@>=@+512
+@
+@d str_513 "texput"
+@<|"texput"|@>=@+513
+@
+@d str_514 "nullfont"
+@<|"nullfont"|@>=@+514
+@
+@d str_515 ".tfm"
+@<|".tfm"|@>=@+515
+@
+@d str_516 "vlistout"
+@<|"vlistout"|@>=@+516
+@
+@d str_517 "to"
+@<|"to"|@>=@+517
+@
+@d str_518 "spread"
+@<|"spread"|@>=@+518
+@
+@d str_519 "vpack"
+@<|"vpack"|@>=@+519
+@
+@d str_520 "displaystyle"
+@<|"displaystyle"|@>=@+520
+@
+@d str_521 "textstyle"
+@<|"textstyle"|@>=@+521
+@
+@d str_522 "scriptstyle"
+@<|"scriptstyle"|@>=@+522
+@
+@d str_523 "scriptscriptstyle"
+@<|"scriptscriptstyle"|@>=@+523
+@
+@d str_524 "mathord"
+@<|"mathord"|@>=@+524
+@
+@d str_525 "mathop"
+@<|"mathop"|@>=@+525
+@
+@d str_526 "mathbin"
+@<|"mathbin"|@>=@+526
+@
+@d str_527 "mathrel"
+@<|"mathrel"|@>=@+527
+@
+@d str_528 "mathopen"
+@<|"mathopen"|@>=@+528
+@
+@d str_529 "mathclose"
+@<|"mathclose"|@>=@+529
+@
+@d str_530 "mathpunct"
+@<|"mathpunct"|@>=@+530
+@
+@d str_531 "mathinner"
+@<|"mathinner"|@>=@+531
+@
+@d str_532 "overline"
+@<|"overline"|@>=@+532
+@
+@d str_533 "underline"
+@<|"underline"|@>=@+533
+@
+@d str_534 "left"
+@<|"left"|@>=@+534
+@
+@d str_535 "right"
+@<|"right"|@>=@+535
+@
+@d str_536 "limits"
+@<|"limits"|@>=@+536
+@
+@d str_537 "nolimits"
+@<|"nolimits"|@>=@+537
+@
+@d str_538 "fraction, thickness "
+@<|"fraction, thickness "|@>=@+538
+@
+@d str_539 "mlist1"
+@<|"mlist1"|@>=@+539
+@
+@d str_540 "mlist2"
+@<|"mlist2"|@>=@+540
+@
+@d str_541 "mlist3"
+@<|"mlist3"|@>=@+541
+@
+@d str_542 "0234000122*4000133**3**344*0400400*000000234000111*1111112341011"
+@d math_spacing 542
+@
+@d str_543 "mlist4"
+@<|"mlist4"|@>=@+543
+@
+@d str_544 "span"
+@<|"span"|@>=@+544
+@
+@d str_545 "cr"
+@<|"cr"|@>=@+545
+@
+@d str_546 "crcr"
+@<|"crcr"|@>=@+546
+@
+@d str_547 "endtemplate"
+@<|"endtemplate"|@>=@+547
+@
+@d str_548 "endv"
+@<|"endv"|@>=@+548
+@
+@d str_549 "256 spans"
+@<|"256 spans"|@>=@+549
+@
+@d str_550 "align1"
+@<|"align1"|@>=@+550
+@
+@d str_551 "align0"
+@<|"align0"|@>=@+551
+@
+@d str_552 "disc1"
+@<|"disc1"|@>=@+552
+@
+@d str_553 "disc2"
+@<|"disc2"|@>=@+553
+@
+@d str_554 "paragraph"
+@<|"paragraph"|@>=@+554
+@
+@d str_555 "disc3"
+@<|"disc3"|@>=@+555
+@
+@d str_556 "disc4"
+@<|"disc4"|@>=@+556
+@
+@d str_557 "line breaking"
+@<|"line breaking"|@>=@+557
+@
+@d str_558 "hyphenation"
+@<|"hyphenation"|@>=@+558
+@
+@d str_559 "patterns"
+@<|"patterns"|@>=@+559
+@
+@d str_560 "pruning"
+@<|"pruning"|@>=@+560
+@
+@d str_561 "vertbreak"
+@<|"vertbreak"|@>=@+561
+@
+@d str_562 "vsplit"
+@<|"vsplit"|@>=@+562
+@
+@d str_563 "vbox"
+@<|"vbox"|@>=@+563
+@
+@d str_564 "pagegoal"
+@<|"pagegoal"|@>=@+564
+@
+@d str_565 "pagetotal"
+@<|"pagetotal"|@>=@+565
+@
+@d str_566 "pagestretch"
+@<|"pagestretch"|@>=@+566
+@
+@d str_567 "pagefilstretch"
+@<|"pagefilstretch"|@>=@+567
+@
+@d str_568 "pagefillstretch"
+@<|"pagefillstretch"|@>=@+568
+@
+@d str_569 "pagefilllstretch"
+@<|"pagefilllstretch"|@>=@+569
+@
+@d str_570 "pageshrink"
+@<|"pageshrink"|@>=@+570
+@
+@d str_571 "pagedepth"
+@<|"pagedepth"|@>=@+571
+@
+@d str_572 "page"
+@<|"page"|@>=@+572
+@
+@d str_573 "end"
+@<|"end"|@>=@+573
+@
+@d str_574 "dump"
+@<|"dump"|@>=@+574
+@
+@d str_575 "hskip"
+@<|"hskip"|@>=@+575
+@
+@d str_576 "hfil"
+@<|"hfil"|@>=@+576
+@
+@d str_577 "hfill"
+@<|"hfill"|@>=@+577
+@
+@d str_578 "hss"
+@<|"hss"|@>=@+578
+@
+@d str_579 "hfilneg"
+@<|"hfilneg"|@>=@+579
+@
+@d str_580 "vskip"
+@<|"vskip"|@>=@+580
+@
+@d str_581 "vfil"
+@<|"vfil"|@>=@+581
+@
+@d str_582 "vfill"
+@<|"vfill"|@>=@+582
+@
+@d str_583 "vss"
+@<|"vss"|@>=@+583
+@
+@d str_584 "vfilneg"
+@<|"vfilneg"|@>=@+584
+@
+@d str_585 "right."
+@<|"right."|@>=@+585
+@
+@d str_586 "rightbrace"
+@<|"rightbrace"|@>=@+586
+@
+@d str_587 "moveleft"
+@<|"moveleft"|@>=@+587
+@
+@d str_588 "moveright"
+@<|"moveright"|@>=@+588
+@
+@d str_589 "raise"
+@<|"raise"|@>=@+589
+@
+@d str_590 "lower"
+@<|"lower"|@>=@+590
+@
+@d str_591 "copy"
+@<|"copy"|@>=@+591
+@
+@d str_592 "lastbox"
+@<|"lastbox"|@>=@+592
+@
+@d str_593 "vtop"
+@<|"vtop"|@>=@+593
+@
+@d str_594 "hbox"
+@<|"hbox"|@>=@+594
+@
+@d str_595 "shipout"
+@<|"shipout"|@>=@+595
+@
+@d str_596 "leaders"
+@<|"leaders"|@>=@+596
+@
+@d str_597 "cleaders"
+@<|"cleaders"|@>=@+597
+@
+@d str_598 "xleaders"
+@<|"xleaders"|@>=@+598
+@
+@d str_599 "indent"
+@<|"indent"|@>=@+599
+@
+@d str_600 "noindent"
+@<|"noindent"|@>=@+600
+@
+@d str_601 "unpenalty"
+@<|"unpenalty"|@>=@+601
+@
+@d str_602 "unkern"
+@<|"unkern"|@>=@+602
+@
+@d str_603 "unskip"
+@<|"unskip"|@>=@+603
+@
+@d str_604 "unhbox"
+@<|"unhbox"|@>=@+604
+@
+@d str_605 "unhcopy"
+@<|"unhcopy"|@>=@+605
+@
+@d str_606 "unvbox"
+@<|"unvbox"|@>=@+606
+@
+@d str_607 "unvcopy"
+@<|"unvcopy"|@>=@+607
+@
+@d str_608 "eqno"
+@<|"eqno"|@>=@+608
+@
+@d str_609 "leqno"
+@<|"leqno"|@>=@+609
+@
+@d str_610 "displaylimits"
+@<|"displaylimits"|@>=@+610
+@
+@d str_611 "above"
+@<|"above"|@>=@+611
+@
+@d str_612 "over"
+@<|"over"|@>=@+612
+@
+@d str_613 "atop"
+@<|"atop"|@>=@+613
+@
+@d str_614 "abovewithdelims"
+@<|"abovewithdelims"|@>=@+614
+@
+@d str_615 "overwithdelims"
+@<|"overwithdelims"|@>=@+615
+@
+@d str_616 "atopwithdelims"
+@<|"atopwithdelims"|@>=@+616
+@
+@d str_617 "display"
+@<|"display"|@>=@+617
+@
+@d str_618 "long"
+@<|"long"|@>=@+618
+@
+@d str_619 "outer"
+@<|"outer"|@>=@+619
+@
+@d str_620 "global"
+@<|"global"|@>=@+620
+@
+@d str_621 "def"
+@<|"def"|@>=@+621
+@
+@d str_622 "gdef"
+@<|"gdef"|@>=@+622
+@
+@d str_623 "edef"
+@<|"edef"|@>=@+623
+@
+@d str_624 "xdef"
+@<|"xdef"|@>=@+624
+@
+@d str_625 "prefix"
+@<|"prefix"|@>=@+625
+@
+@d str_626 "inaccessible"
+@<|"inaccessible"|@>=@+626
+@
+@d str_627 "let"
+@<|"let"|@>=@+627
+@
+@d str_628 "futurelet"
+@<|"futurelet"|@>=@+628
+@
+@d str_629 "chardef"
+@<|"chardef"|@>=@+629
+@
+@d str_630 "mathchardef"
+@<|"mathchardef"|@>=@+630
+@
+@d str_631 "countdef"
+@<|"countdef"|@>=@+631
+@
+@d str_632 "dimendef"
+@<|"dimendef"|@>=@+632
+@
+@d str_633 "skipdef"
+@<|"skipdef"|@>=@+633
+@
+@d str_634 "muskipdef"
+@<|"muskipdef"|@>=@+634
+@
+@d str_635 "toksdef"
+@<|"toksdef"|@>=@+635
+@
+@d str_636 "by"
+@<|"by"|@>=@+636
+@
+@d str_637 "hyphenchar"
+@<|"hyphenchar"|@>=@+637
+@
+@d str_638 "skewchar"
+@<|"skewchar"|@>=@+638
+@
+@d str_639 "FONT"
+@<|"FONT"|@>=@+639
+@
+@d str_640 "at"
+@<|"at"|@>=@+640
+@
+@d str_641 "scaled"
+@<|"scaled"|@>=@+641
+@
+@d str_642 "errorstopmode"
+@<|"errorstopmode"|@>=@+642
+@
+@d str_643 "openin"
+@<|"openin"|@>=@+643
+@
+@d str_644 "closein"
+@<|"closein"|@>=@+644
+@
+@d str_645 "message"
+@<|"message"|@>=@+645
+@
+@d str_646 "errmessage"
+@<|"errmessage"|@>=@+646
+@
+@d str_647 "lowercase"
+@<|"lowercase"|@>=@+647
+@
+@d str_648 "uppercase"
+@<|"uppercase"|@>=@+648
+@
+@d str_649 "show"
+@<|"show"|@>=@+649
+@
+@d str_650 "showbox"
+@<|"showbox"|@>=@+650
+@
+@d str_651 "showthe"
+@<|"showthe"|@>=@+651
+@
+@d str_652 "showlists"
+@<|"showlists"|@>=@+652
+@
+@d str_653 "long macro"
+@<|"long macro"|@>=@+653
+@
+@d str_654 "outer macro"
+@<|"outer macro"|@>=@+654
+@
+@d str_655 "outer endtemplate"
+@<|"outer endtemplate"|@>=@+655
+@
+@d str_656 " (INITEX)"
+@<|" (INITEX)"|@>=@+656
+@
+@d str_657 "end occurred "
+@<|"end occurred "|@>=@+657
+@
+@d str_658 "openout"
+@<|"openout"|@>=@+658
+@
+@d str_659 "closeout"
+@<|"closeout"|@>=@+659
+@
+@d str_660 "special"
+@<|"special"|@>=@+660
+@
+@d str_661 "immediate"
+@<|"immediate"|@>=@+661
+@
+@d str_662 "setlanguage"
+@<|"setlanguage"|@>=@+662
+@
+@d str_663 "ext1"
+@<|"ext1"|@>=@+663
+@
+@d str_664 "ext2"
+@<|"ext2"|@>=@+664
+@
+@d str_665 "ext3"
+@<|"ext3"|@>=@+665
+@
+@d str_666 "endwrite"
+@<|"endwrite"|@>=@+666
+@
+@d str_667 "ext4"
+@<|"ext4"|@>=@+667
+
+@ All the above strings together make up the string pool.
+@<|str_pool| initialization@>=
+str_0_255
+str_256 str_257 str_258 str_259 str_260 str_261 str_262 str_263@/
+str_264 str_265 str_266 str_267 str_268 str_269 str_270 str_271@/
+str_272 str_273 str_274 str_275 str_276 str_277 str_278 str_279@/
+str_280 str_281 str_282 str_283 str_284 str_285 str_286 str_287@/
+str_288 str_289 str_290 str_291 str_292 str_293 str_294 str_295@/
+str_296 str_297 str_298 str_299 str_300 str_301 str_302 str_303@/
+str_304 str_305 str_306 str_307 str_308 str_309 str_310 str_311@/
+str_312 str_313 str_314 str_315 str_316 str_317 str_318 str_319@/
+str_320 str_321 str_322 str_323 str_324 str_325 str_326 str_327@/
+str_328 str_329 str_330 str_331 str_332 str_333 str_334 str_335@/
+str_336 str_337 str_338 str_339 str_340 str_341 str_342 str_343@/
+str_344 str_345 str_346 str_347 str_348 str_349 str_350 str_351@/
+str_352 str_353 str_354 str_355 str_356 str_357 str_358 str_359@/
+str_360 str_361 str_362 str_363 str_364 str_365 str_366 str_367@/
+str_368 str_369 str_370 str_371 str_372 str_373 str_374 str_375@/
+str_376 str_377 str_378 str_379 str_380 str_381 str_382 str_383@/
+str_384 str_385 str_386 str_387 str_388 str_389 str_390 str_391@/
+str_392 str_393 str_394 str_395 str_396 str_397 str_398 str_399@/
+str_400 str_401 str_402 str_403 str_404 str_405 str_406 str_407@/
+str_408 str_409 str_410 str_411 str_412 str_413 str_414 str_415@/
+str_416 str_417 str_418 str_419 str_420 str_421 str_422 str_423@/
+str_424 str_425 str_426 str_427 str_428 str_429 str_430 str_431@/
+str_432 str_433 str_434 str_435 str_436 str_437 str_438 str_439@/
+str_440 str_441 str_442 str_443 str_444 str_445 str_446 str_447@/
+str_448 str_449 str_450 str_451 str_452 str_453 str_454 str_455@/
+str_456 str_457 str_458 str_459 str_460 str_461 str_462 str_463@/
+str_464 str_465 str_466 str_467 str_468 str_469 str_470 str_471@/
+str_472 str_473 str_474 str_475 str_476 str_477 str_478 str_479@/
+str_480 str_481 str_482 str_483 str_484 str_485 str_486 str_487@/
+str_488 str_489 str_490 str_491 str_492 str_493 str_494 str_495@/
+str_496 str_497 str_498 str_499 str_500 str_501 str_502 str_503@/
+str_504 str_505 str_506 str_507 str_508 str_509 str_510 str_511@/
+str_512 str_513 str_514 str_515 str_516 str_517 str_518 str_519@/
+str_520 str_521 str_522 str_523 str_524 str_525 str_526 str_527@/
+str_528 str_529 str_530 str_531 str_532 str_533 str_534 str_535@/
+str_536 str_537 str_538 str_539 str_540 str_541 str_542 str_543@/
+str_544 str_545 str_546 str_547 str_548 str_549 str_550 str_551@/
+str_552 str_553 str_554 str_555 str_556 str_557 str_558 str_559@/
+str_560 str_561 str_562 str_563 str_564 str_565 str_566 str_567@/
+str_568 str_569 str_570 str_571 str_572 str_573 str_574 str_575@/
+str_576 str_577 str_578 str_579 str_580 str_581 str_582 str_583@/
+str_584 str_585 str_586 str_587 str_588 str_589 str_590 str_591@/
+str_592 str_593 str_594 str_595 str_596 str_597 str_598 str_599@/
+str_600 str_601 str_602 str_603 str_604 str_605 str_606 str_607@/
+str_608 str_609 str_610 str_611 str_612 str_613 str_614 str_615@/
+str_616 str_617 str_618 str_619 str_620 str_621 str_622 str_623@/
+str_624 str_625 str_626 str_627 str_628 str_629 str_630 str_631@/
+str_632 str_633 str_634 str_635 str_636 str_637 str_638 str_639@/
+str_640 str_641 str_642 str_643 str_644 str_645 str_646 str_647@/
+str_648 str_649 str_650 str_651 str_652 str_653 str_654 str_655@/
+str_656 str_657 str_658 str_659 str_660 str_661 str_662 str_663@/
+str_664 str_665 str_666 str_667
+
+@ @<|str_start| initialization@>=
+str_start_0_255
+str_start_256, str_start_257, str_start_258, str_start_259,
+str_start_260, str_start_261, str_start_262, str_start_263,
+str_start_264, str_start_265, str_start_266, str_start_267,
+str_start_268, str_start_269, str_start_270, str_start_271,
+str_start_272, str_start_273, str_start_274, str_start_275,
+str_start_276, str_start_277, str_start_278, str_start_279,
+str_start_280, str_start_281, str_start_282, str_start_283,
+str_start_284, str_start_285, str_start_286, str_start_287,
+str_start_288, str_start_289, str_start_290, str_start_291,
+str_start_292, str_start_293, str_start_294, str_start_295,
+str_start_296, str_start_297, str_start_298, str_start_299,
+str_start_300, str_start_301, str_start_302, str_start_303,
+str_start_304, str_start_305, str_start_306, str_start_307,
+str_start_308, str_start_309, str_start_310, str_start_311,
+str_start_312, str_start_313, str_start_314, str_start_315,
+str_start_316, str_start_317, str_start_318, str_start_319,
+str_start_320, str_start_321, str_start_322, str_start_323,
+str_start_324, str_start_325, str_start_326, str_start_327,
+str_start_328, str_start_329, str_start_330, str_start_331,
+str_start_332, str_start_333, str_start_334, str_start_335,
+str_start_336, str_start_337, str_start_338, str_start_339,
+str_start_340, str_start_341, str_start_342, str_start_343,
+str_start_344, str_start_345, str_start_346, str_start_347,
+str_start_348, str_start_349, str_start_350, str_start_351,
+str_start_352, str_start_353, str_start_354, str_start_355,
+str_start_356, str_start_357, str_start_358, str_start_359,
+str_start_360, str_start_361, str_start_362, str_start_363,
+str_start_364, str_start_365, str_start_366, str_start_367,
+str_start_368, str_start_369, str_start_370, str_start_371,
+str_start_372, str_start_373, str_start_374, str_start_375,
+str_start_376, str_start_377, str_start_378, str_start_379,
+str_start_380, str_start_381, str_start_382, str_start_383,
+str_start_384, str_start_385, str_start_386, str_start_387,
+str_start_388, str_start_389, str_start_390, str_start_391,
+str_start_392, str_start_393, str_start_394, str_start_395,
+str_start_396, str_start_397, str_start_398, str_start_399,
+str_start_400, str_start_401, str_start_402, str_start_403,
+str_start_404, str_start_405, str_start_406, str_start_407,
+str_start_408, str_start_409, str_start_410, str_start_411,
+str_start_412, str_start_413, str_start_414, str_start_415,
+str_start_416, str_start_417, str_start_418, str_start_419,
+str_start_420, str_start_421, str_start_422, str_start_423,
+str_start_424, str_start_425, str_start_426, str_start_427,
+str_start_428, str_start_429, str_start_430, str_start_431,
+str_start_432, str_start_433, str_start_434, str_start_435,
+str_start_436, str_start_437, str_start_438, str_start_439,
+str_start_440, str_start_441, str_start_442, str_start_443,
+str_start_444, str_start_445, str_start_446, str_start_447,
+str_start_448, str_start_449, str_start_450, str_start_451,
+str_start_452, str_start_453, str_start_454, str_start_455,
+str_start_456, str_start_457, str_start_458, str_start_459,
+str_start_460, str_start_461, str_start_462, str_start_463,
+str_start_464, str_start_465, str_start_466, str_start_467,
+str_start_468, str_start_469, str_start_470, str_start_471,
+str_start_472, str_start_473, str_start_474, str_start_475,
+str_start_476, str_start_477, str_start_478, str_start_479,
+str_start_480, str_start_481, str_start_482, str_start_483,
+str_start_484, str_start_485, str_start_486, str_start_487,
+str_start_488, str_start_489, str_start_490, str_start_491,
+str_start_492, str_start_493, str_start_494, str_start_495,
+str_start_496, str_start_497, str_start_498, str_start_499,
+str_start_500, str_start_501, str_start_502, str_start_503,
+str_start_504, str_start_505, str_start_506, str_start_507,
+str_start_508, str_start_509, str_start_510, str_start_511,
+str_start_512, str_start_513, str_start_514, str_start_515,
+str_start_516, str_start_517, str_start_518, str_start_519,
+str_start_520, str_start_521, str_start_522, str_start_523,
+str_start_524, str_start_525, str_start_526, str_start_527,
+str_start_528, str_start_529, str_start_530, str_start_531,
+str_start_532, str_start_533, str_start_534, str_start_535,
+str_start_536, str_start_537, str_start_538, str_start_539,
+str_start_540, str_start_541, str_start_542, str_start_543,
+str_start_544, str_start_545, str_start_546, str_start_547,
+str_start_548, str_start_549, str_start_550, str_start_551,
+str_start_552, str_start_553, str_start_554, str_start_555,
+str_start_556, str_start_557, str_start_558, str_start_559,
+str_start_560, str_start_561, str_start_562, str_start_563,
+str_start_564, str_start_565, str_start_566, str_start_567,
+str_start_568, str_start_569, str_start_570, str_start_571,
+str_start_572, str_start_573, str_start_574, str_start_575,
+str_start_576, str_start_577, str_start_578, str_start_579,
+str_start_580, str_start_581, str_start_582, str_start_583,
+str_start_584, str_start_585, str_start_586, str_start_587,
+str_start_588, str_start_589, str_start_590, str_start_591,
+str_start_592, str_start_593, str_start_594, str_start_595,
+str_start_596, str_start_597, str_start_598, str_start_599,
+str_start_600, str_start_601, str_start_602, str_start_603,
+str_start_604, str_start_605, str_start_606, str_start_607,
+str_start_608, str_start_609, str_start_610, str_start_611,
+str_start_612, str_start_613, str_start_614, str_start_615,
+str_start_616, str_start_617, str_start_618, str_start_619,
+str_start_620, str_start_621, str_start_622, str_start_623,
+str_start_624, str_start_625, str_start_626, str_start_627,
+str_start_628, str_start_629, str_start_630, str_start_631,
+str_start_632, str_start_633, str_start_634, str_start_635,
+str_start_636, str_start_637, str_start_638, str_start_639,
+str_start_640, str_start_641, str_start_642, str_start_643,
+str_start_644, str_start_645, str_start_646, str_start_647,
+str_start_648, str_start_649, str_start_650, str_start_651,
+str_start_652, str_start_653, str_start_654, str_start_655,
+str_start_656, str_start_657, str_start_658, str_start_659,
+str_start_660, str_start_661, str_start_662, str_start_663,
+str_start_664, str_start_665, str_start_666, str_start_667,
+str_start_668
+
+@ We still need to define the start locations of the strings.
+@<prepare for string pool initialization@>=
+typedef enum {
+str_start_256=sizeof(str_0_255)-1,
+str_start_257=str_start_256+sizeof(str_256)-1,@/
+str_start_258=str_start_257+sizeof(str_257)-1,@/
+str_start_259=str_start_258+sizeof(str_258)-1,@/
+str_start_260=str_start_259+sizeof(str_259)-1,@/
+str_start_261=str_start_260+sizeof(str_260)-1,@/
+str_start_262=str_start_261+sizeof(str_261)-1,@/
+str_start_263=str_start_262+sizeof(str_262)-1,@/
+str_start_264=str_start_263+sizeof(str_263)-1,@/
+str_start_265=str_start_264+sizeof(str_264)-1,@/
+str_start_266=str_start_265+sizeof(str_265)-1,@/
+str_start_267=str_start_266+sizeof(str_266)-1,@/
+str_start_268=str_start_267+sizeof(str_267)-1,@/
+str_start_269=str_start_268+sizeof(str_268)-1,@/
+str_start_270=str_start_269+sizeof(str_269)-1,@/
+str_start_271=str_start_270+sizeof(str_270)-1,@/
+str_start_272=str_start_271+sizeof(str_271)-1,@/
+str_start_273=str_start_272+sizeof(str_272)-1,@/
+str_start_274=str_start_273+sizeof(str_273)-1,@/
+str_start_275=str_start_274+sizeof(str_274)-1,@/
+str_start_276=str_start_275+sizeof(str_275)-1,@/
+str_start_277=str_start_276+sizeof(str_276)-1,@/
+str_start_278=str_start_277+sizeof(str_277)-1,@/
+str_start_279=str_start_278+sizeof(str_278)-1,@/
+str_start_280=str_start_279+sizeof(str_279)-1,@/
+str_start_281=str_start_280+sizeof(str_280)-1,@/
+str_start_282=str_start_281+sizeof(str_281)-1,@/
+str_start_283=str_start_282+sizeof(str_282)-1,@/
+str_start_284=str_start_283+sizeof(str_283)-1,@/
+str_start_285=str_start_284+sizeof(str_284)-1,@/
+str_start_286=str_start_285+sizeof(str_285)-1,@/
+str_start_287=str_start_286+sizeof(str_286)-1,@/
+str_start_288=str_start_287+sizeof(str_287)-1,@/
+str_start_289=str_start_288+sizeof(str_288)-1,@/
+str_start_290=str_start_289+sizeof(str_289)-1,@/
+str_start_291=str_start_290+sizeof(str_290)-1,@/
+str_start_292=str_start_291+sizeof(str_291)-1,@/
+str_start_293=str_start_292+sizeof(str_292)-1,@/
+str_start_294=str_start_293+sizeof(str_293)-1,@/
+str_start_295=str_start_294+sizeof(str_294)-1,@/
+str_start_296=str_start_295+sizeof(str_295)-1,@/
+str_start_297=str_start_296+sizeof(str_296)-1,@/
+str_start_298=str_start_297+sizeof(str_297)-1,@/
+str_start_299=str_start_298+sizeof(str_298)-1,@/
+str_start_300=str_start_299+sizeof(str_299)-1,@/
+str_start_301=str_start_300+sizeof(str_300)-1,@/
+str_start_302=str_start_301+sizeof(str_301)-1,@/
+str_start_303=str_start_302+sizeof(str_302)-1,@/
+str_start_304=str_start_303+sizeof(str_303)-1,@/
+str_start_305=str_start_304+sizeof(str_304)-1,@/
+str_start_306=str_start_305+sizeof(str_305)-1,@/
+str_start_307=str_start_306+sizeof(str_306)-1,@/
+str_start_308=str_start_307+sizeof(str_307)-1,@/
+str_start_309=str_start_308+sizeof(str_308)-1,@/
+str_start_310=str_start_309+sizeof(str_309)-1,@/
+str_start_311=str_start_310+sizeof(str_310)-1,@/
+str_start_312=str_start_311+sizeof(str_311)-1,@/
+str_start_313=str_start_312+sizeof(str_312)-1,@/
+str_start_314=str_start_313+sizeof(str_313)-1,@/
+str_start_315=str_start_314+sizeof(str_314)-1,@/
+str_start_316=str_start_315+sizeof(str_315)-1,@/
+str_start_317=str_start_316+sizeof(str_316)-1,@/
+str_start_318=str_start_317+sizeof(str_317)-1,@/
+str_start_319=str_start_318+sizeof(str_318)-1,@/
+str_start_320=str_start_319+sizeof(str_319)-1,@/
+str_start_321=str_start_320+sizeof(str_320)-1,@/
+str_start_322=str_start_321+sizeof(str_321)-1,@/
+str_start_323=str_start_322+sizeof(str_322)-1,@/
+str_start_324=str_start_323+sizeof(str_323)-1,@/
+str_start_325=str_start_324+sizeof(str_324)-1,@/
+str_start_326=str_start_325+sizeof(str_325)-1,@/
+str_start_327=str_start_326+sizeof(str_326)-1,@/
+str_start_328=str_start_327+sizeof(str_327)-1,@/
+str_start_329=str_start_328+sizeof(str_328)-1,@/
+str_start_330=str_start_329+sizeof(str_329)-1,@/
+str_start_331=str_start_330+sizeof(str_330)-1,@/
+str_start_332=str_start_331+sizeof(str_331)-1,@/
+str_start_333=str_start_332+sizeof(str_332)-1,@/
+str_start_334=str_start_333+sizeof(str_333)-1,@/
+str_start_335=str_start_334+sizeof(str_334)-1,@/
+str_start_336=str_start_335+sizeof(str_335)-1,@/
+str_start_337=str_start_336+sizeof(str_336)-1,@/
+str_start_338=str_start_337+sizeof(str_337)-1,@/
+str_start_339=str_start_338+sizeof(str_338)-1,@/
+str_start_340=str_start_339+sizeof(str_339)-1,@/
+str_start_341=str_start_340+sizeof(str_340)-1,@/
+str_start_342=str_start_341+sizeof(str_341)-1,@/
+str_start_343=str_start_342+sizeof(str_342)-1,@/
+str_start_344=str_start_343+sizeof(str_343)-1,@/
+str_start_345=str_start_344+sizeof(str_344)-1,@/
+str_start_346=str_start_345+sizeof(str_345)-1,@/
+str_start_347=str_start_346+sizeof(str_346)-1,@/
+str_start_348=str_start_347+sizeof(str_347)-1,@/
+str_start_349=str_start_348+sizeof(str_348)-1,@/
+str_start_350=str_start_349+sizeof(str_349)-1,@/
+str_start_351=str_start_350+sizeof(str_350)-1,@/
+str_start_352=str_start_351+sizeof(str_351)-1,@/
+str_start_353=str_start_352+sizeof(str_352)-1,@/
+str_start_354=str_start_353+sizeof(str_353)-1,@/
+str_start_355=str_start_354+sizeof(str_354)-1,@/
+str_start_356=str_start_355+sizeof(str_355)-1,@/
+str_start_357=str_start_356+sizeof(str_356)-1,@/
+str_start_358=str_start_357+sizeof(str_357)-1,@/
+str_start_359=str_start_358+sizeof(str_358)-1,@/
+str_start_360=str_start_359+sizeof(str_359)-1,@/
+str_start_361=str_start_360+sizeof(str_360)-1,@/
+str_start_362=str_start_361+sizeof(str_361)-1,@/
+str_start_363=str_start_362+sizeof(str_362)-1,@/
+str_start_364=str_start_363+sizeof(str_363)-1,@/
+str_start_365=str_start_364+sizeof(str_364)-1,@/
+str_start_366=str_start_365+sizeof(str_365)-1,@/
+str_start_367=str_start_366+sizeof(str_366)-1,@/
+str_start_368=str_start_367+sizeof(str_367)-1,@/
+str_start_369=str_start_368+sizeof(str_368)-1,@/
+str_start_370=str_start_369+sizeof(str_369)-1,@/
+str_start_371=str_start_370+sizeof(str_370)-1,@/
+str_start_372=str_start_371+sizeof(str_371)-1,@/
+str_start_373=str_start_372+sizeof(str_372)-1,@/
+str_start_374=str_start_373+sizeof(str_373)-1,@/
+str_start_375=str_start_374+sizeof(str_374)-1,@/
+str_start_376=str_start_375+sizeof(str_375)-1,@/
+str_start_377=str_start_376+sizeof(str_376)-1,@/
+str_start_378=str_start_377+sizeof(str_377)-1,@/
+str_start_379=str_start_378+sizeof(str_378)-1,@/
+str_start_380=str_start_379+sizeof(str_379)-1,@/
+str_start_381=str_start_380+sizeof(str_380)-1,@/
+str_start_382=str_start_381+sizeof(str_381)-1,@/
+str_start_383=str_start_382+sizeof(str_382)-1,@/
+str_start_384=str_start_383+sizeof(str_383)-1,@/
+str_start_385=str_start_384+sizeof(str_384)-1,@/
+str_start_386=str_start_385+sizeof(str_385)-1,@/
+str_start_387=str_start_386+sizeof(str_386)-1,@/
+str_start_388=str_start_387+sizeof(str_387)-1,@/
+str_start_389=str_start_388+sizeof(str_388)-1,@/
+str_start_390=str_start_389+sizeof(str_389)-1,@/
+str_start_391=str_start_390+sizeof(str_390)-1,@/
+str_start_392=str_start_391+sizeof(str_391)-1,@/
+str_start_393=str_start_392+sizeof(str_392)-1,@/
+str_start_394=str_start_393+sizeof(str_393)-1,@/
+str_start_395=str_start_394+sizeof(str_394)-1,@/
+str_start_396=str_start_395+sizeof(str_395)-1,@/
+str_start_397=str_start_396+sizeof(str_396)-1,@/
+str_start_398=str_start_397+sizeof(str_397)-1,@/
+str_start_399=str_start_398+sizeof(str_398)-1,@/
+str_start_400=str_start_399+sizeof(str_399)-1,@/
+str_start_401=str_start_400+sizeof(str_400)-1,@/
+str_start_402=str_start_401+sizeof(str_401)-1,@/
+str_start_403=str_start_402+sizeof(str_402)-1,@/
+str_start_404=str_start_403+sizeof(str_403)-1,@/
+str_start_405=str_start_404+sizeof(str_404)-1,@/
+str_start_406=str_start_405+sizeof(str_405)-1,@/
+str_start_407=str_start_406+sizeof(str_406)-1,@/
+str_start_408=str_start_407+sizeof(str_407)-1,@/
+str_start_409=str_start_408+sizeof(str_408)-1,@/
+str_start_410=str_start_409+sizeof(str_409)-1,@/
+str_start_411=str_start_410+sizeof(str_410)-1,@/
+str_start_412=str_start_411+sizeof(str_411)-1,@/
+str_start_413=str_start_412+sizeof(str_412)-1,@/
+str_start_414=str_start_413+sizeof(str_413)-1,@/
+str_start_415=str_start_414+sizeof(str_414)-1,@/
+str_start_416=str_start_415+sizeof(str_415)-1,@/
+str_start_417=str_start_416+sizeof(str_416)-1,@/
+str_start_418=str_start_417+sizeof(str_417)-1,@/
+str_start_419=str_start_418+sizeof(str_418)-1,@/
+str_start_420=str_start_419+sizeof(str_419)-1,@/
+str_start_421=str_start_420+sizeof(str_420)-1,@/
+str_start_422=str_start_421+sizeof(str_421)-1,@/
+str_start_423=str_start_422+sizeof(str_422)-1,@/
+str_start_424=str_start_423+sizeof(str_423)-1,@/
+str_start_425=str_start_424+sizeof(str_424)-1,@/
+str_start_426=str_start_425+sizeof(str_425)-1,@/
+str_start_427=str_start_426+sizeof(str_426)-1,@/
+str_start_428=str_start_427+sizeof(str_427)-1,@/
+str_start_429=str_start_428+sizeof(str_428)-1,@/
+str_start_430=str_start_429+sizeof(str_429)-1,@/
+str_start_431=str_start_430+sizeof(str_430)-1,@/
+str_start_432=str_start_431+sizeof(str_431)-1,@/
+str_start_433=str_start_432+sizeof(str_432)-1,@/
+str_start_434=str_start_433+sizeof(str_433)-1,@/
+str_start_435=str_start_434+sizeof(str_434)-1,@/
+str_start_436=str_start_435+sizeof(str_435)-1,@/
+str_start_437=str_start_436+sizeof(str_436)-1,@/
+str_start_438=str_start_437+sizeof(str_437)-1,@/
+str_start_439=str_start_438+sizeof(str_438)-1,@/
+str_start_440=str_start_439+sizeof(str_439)-1,@/
+str_start_441=str_start_440+sizeof(str_440)-1,@/
+str_start_442=str_start_441+sizeof(str_441)-1,@/
+str_start_443=str_start_442+sizeof(str_442)-1,@/
+str_start_444=str_start_443+sizeof(str_443)-1,@/
+str_start_445=str_start_444+sizeof(str_444)-1,@/
+str_start_446=str_start_445+sizeof(str_445)-1,@/
+str_start_447=str_start_446+sizeof(str_446)-1,@/
+str_start_448=str_start_447+sizeof(str_447)-1,@/
+str_start_449=str_start_448+sizeof(str_448)-1,@/
+str_start_450=str_start_449+sizeof(str_449)-1,@/
+str_start_451=str_start_450+sizeof(str_450)-1,@/
+str_start_452=str_start_451+sizeof(str_451)-1,@/
+str_start_453=str_start_452+sizeof(str_452)-1,@/
+str_start_454=str_start_453+sizeof(str_453)-1,@/
+str_start_455=str_start_454+sizeof(str_454)-1,@/
+str_start_456=str_start_455+sizeof(str_455)-1,@/
+str_start_457=str_start_456+sizeof(str_456)-1,@/
+str_start_458=str_start_457+sizeof(str_457)-1,@/
+str_start_459=str_start_458+sizeof(str_458)-1,@/
+str_start_460=str_start_459+sizeof(str_459)-1,@/
+str_start_461=str_start_460+sizeof(str_460)-1,@/
+str_start_462=str_start_461+sizeof(str_461)-1,@/
+str_start_463=str_start_462+sizeof(str_462)-1,@/
+str_start_464=str_start_463+sizeof(str_463)-1,@/
+str_start_465=str_start_464+sizeof(str_464)-1,@/
+str_start_466=str_start_465+sizeof(str_465)-1,@/
+str_start_467=str_start_466+sizeof(str_466)-1,@/
+str_start_468=str_start_467+sizeof(str_467)-1,@/
+str_start_469=str_start_468+sizeof(str_468)-1,@/
+str_start_470=str_start_469+sizeof(str_469)-1,@/
+str_start_471=str_start_470+sizeof(str_470)-1,@/
+str_start_472=str_start_471+sizeof(str_471)-1,@/
+str_start_473=str_start_472+sizeof(str_472)-1,@/
+str_start_474=str_start_473+sizeof(str_473)-1,@/
+str_start_475=str_start_474+sizeof(str_474)-1,@/
+str_start_476=str_start_475+sizeof(str_475)-1,@/
+str_start_477=str_start_476+sizeof(str_476)-1,@/
+str_start_478=str_start_477+sizeof(str_477)-1,@/
+str_start_479=str_start_478+sizeof(str_478)-1,@/
+str_start_480=str_start_479+sizeof(str_479)-1,@/
+str_start_481=str_start_480+sizeof(str_480)-1,@/
+str_start_482=str_start_481+sizeof(str_481)-1,@/
+str_start_483=str_start_482+sizeof(str_482)-1,@/
+str_start_484=str_start_483+sizeof(str_483)-1,@/
+str_start_485=str_start_484+sizeof(str_484)-1,@/
+str_start_486=str_start_485+sizeof(str_485)-1,@/
+str_start_487=str_start_486+sizeof(str_486)-1,@/
+str_start_488=str_start_487+sizeof(str_487)-1,@/
+str_start_489=str_start_488+sizeof(str_488)-1,@/
+str_start_490=str_start_489+sizeof(str_489)-1,@/
+str_start_491=str_start_490+sizeof(str_490)-1,@/
+str_start_492=str_start_491+sizeof(str_491)-1,@/
+str_start_493=str_start_492+sizeof(str_492)-1,@/
+str_start_494=str_start_493+sizeof(str_493)-1,@/
+str_start_495=str_start_494+sizeof(str_494)-1,@/
+str_start_496=str_start_495+sizeof(str_495)-1,@/
+str_start_497=str_start_496+sizeof(str_496)-1,@/
+str_start_498=str_start_497+sizeof(str_497)-1,@/
+str_start_499=str_start_498+sizeof(str_498)-1,@/
+str_start_500=str_start_499+sizeof(str_499)-1,@/
+str_start_501=str_start_500+sizeof(str_500)-1,@/
+str_start_502=str_start_501+sizeof(str_501)-1,@/
+str_start_503=str_start_502+sizeof(str_502)-1,@/
+str_start_504=str_start_503+sizeof(str_503)-1,@/
+str_start_505=str_start_504+sizeof(str_504)-1,@/
+str_start_506=str_start_505+sizeof(str_505)-1,@/
+str_start_507=str_start_506+sizeof(str_506)-1,@/
+str_start_508=str_start_507+sizeof(str_507)-1,@/
+str_start_509=str_start_508+sizeof(str_508)-1,@/
+str_start_510=str_start_509+sizeof(str_509)-1,@/
+str_start_511=str_start_510+sizeof(str_510)-1,@/
+str_start_512=str_start_511+sizeof(str_511)-1,@/
+str_start_513=str_start_512+sizeof(str_512)-1,@/
+str_start_514=str_start_513+sizeof(str_513)-1,@/
+str_start_515=str_start_514+sizeof(str_514)-1,@/
+str_start_516=str_start_515+sizeof(str_515)-1,@/
+str_start_517=str_start_516+sizeof(str_516)-1,@/
+str_start_518=str_start_517+sizeof(str_517)-1,@/
+str_start_519=str_start_518+sizeof(str_518)-1,@/
+str_start_520=str_start_519+sizeof(str_519)-1,@/
+str_start_521=str_start_520+sizeof(str_520)-1,@/
+str_start_522=str_start_521+sizeof(str_521)-1,@/
+str_start_523=str_start_522+sizeof(str_522)-1,@/
+str_start_524=str_start_523+sizeof(str_523)-1,@/
+str_start_525=str_start_524+sizeof(str_524)-1,@/
+str_start_526=str_start_525+sizeof(str_525)-1,@/
+str_start_527=str_start_526+sizeof(str_526)-1,@/
+str_start_528=str_start_527+sizeof(str_527)-1,@/
+str_start_529=str_start_528+sizeof(str_528)-1,@/
+str_start_530=str_start_529+sizeof(str_529)-1,@/
+str_start_531=str_start_530+sizeof(str_530)-1,@/
+str_start_532=str_start_531+sizeof(str_531)-1,@/
+str_start_533=str_start_532+sizeof(str_532)-1,@/
+str_start_534=str_start_533+sizeof(str_533)-1,@/
+str_start_535=str_start_534+sizeof(str_534)-1,@/
+str_start_536=str_start_535+sizeof(str_535)-1,@/
+str_start_537=str_start_536+sizeof(str_536)-1,@/
+str_start_538=str_start_537+sizeof(str_537)-1,@/
+str_start_539=str_start_538+sizeof(str_538)-1,@/
+str_start_540=str_start_539+sizeof(str_539)-1,@/
+str_start_541=str_start_540+sizeof(str_540)-1,@/
+str_start_542=str_start_541+sizeof(str_541)-1,@/
+str_start_543=str_start_542+sizeof(str_542)-1,@/
+str_start_544=str_start_543+sizeof(str_543)-1,@/
+str_start_545=str_start_544+sizeof(str_544)-1,@/
+str_start_546=str_start_545+sizeof(str_545)-1,@/
+str_start_547=str_start_546+sizeof(str_546)-1,@/
+str_start_548=str_start_547+sizeof(str_547)-1,@/
+str_start_549=str_start_548+sizeof(str_548)-1,@/
+str_start_550=str_start_549+sizeof(str_549)-1,@/
+str_start_551=str_start_550+sizeof(str_550)-1,@/
+str_start_552=str_start_551+sizeof(str_551)-1,@/
+str_start_553=str_start_552+sizeof(str_552)-1,@/
+str_start_554=str_start_553+sizeof(str_553)-1,@/
+str_start_555=str_start_554+sizeof(str_554)-1,@/
+str_start_556=str_start_555+sizeof(str_555)-1,@/
+str_start_557=str_start_556+sizeof(str_556)-1,@/
+str_start_558=str_start_557+sizeof(str_557)-1,@/
+str_start_559=str_start_558+sizeof(str_558)-1,@/
+str_start_560=str_start_559+sizeof(str_559)-1,@/
+str_start_561=str_start_560+sizeof(str_560)-1,@/
+str_start_562=str_start_561+sizeof(str_561)-1,@/
+str_start_563=str_start_562+sizeof(str_562)-1,@/
+str_start_564=str_start_563+sizeof(str_563)-1,@/
+str_start_565=str_start_564+sizeof(str_564)-1,@/
+str_start_566=str_start_565+sizeof(str_565)-1,@/
+str_start_567=str_start_566+sizeof(str_566)-1,@/
+str_start_568=str_start_567+sizeof(str_567)-1,@/
+str_start_569=str_start_568+sizeof(str_568)-1,@/
+str_start_570=str_start_569+sizeof(str_569)-1,@/
+str_start_571=str_start_570+sizeof(str_570)-1,@/
+str_start_572=str_start_571+sizeof(str_571)-1,@/
+str_start_573=str_start_572+sizeof(str_572)-1,@/
+str_start_574=str_start_573+sizeof(str_573)-1,@/
+str_start_575=str_start_574+sizeof(str_574)-1,@/
+str_start_576=str_start_575+sizeof(str_575)-1,@/
+str_start_577=str_start_576+sizeof(str_576)-1,@/
+str_start_578=str_start_577+sizeof(str_577)-1,@/
+str_start_579=str_start_578+sizeof(str_578)-1,@/
+str_start_580=str_start_579+sizeof(str_579)-1,@/
+str_start_581=str_start_580+sizeof(str_580)-1,@/
+str_start_582=str_start_581+sizeof(str_581)-1,@/
+str_start_583=str_start_582+sizeof(str_582)-1,@/
+str_start_584=str_start_583+sizeof(str_583)-1,@/
+str_start_585=str_start_584+sizeof(str_584)-1,@/
+str_start_586=str_start_585+sizeof(str_585)-1,@/
+str_start_587=str_start_586+sizeof(str_586)-1,@/
+str_start_588=str_start_587+sizeof(str_587)-1,@/
+str_start_589=str_start_588+sizeof(str_588)-1,@/
+str_start_590=str_start_589+sizeof(str_589)-1,@/
+str_start_591=str_start_590+sizeof(str_590)-1,@/
+str_start_592=str_start_591+sizeof(str_591)-1,@/
+str_start_593=str_start_592+sizeof(str_592)-1,@/
+str_start_594=str_start_593+sizeof(str_593)-1,@/
+str_start_595=str_start_594+sizeof(str_594)-1,@/
+str_start_596=str_start_595+sizeof(str_595)-1,@/
+str_start_597=str_start_596+sizeof(str_596)-1,@/
+str_start_598=str_start_597+sizeof(str_597)-1,@/
+str_start_599=str_start_598+sizeof(str_598)-1,@/
+str_start_600=str_start_599+sizeof(str_599)-1,@/
+str_start_601=str_start_600+sizeof(str_600)-1,@/
+str_start_602=str_start_601+sizeof(str_601)-1,@/
+str_start_603=str_start_602+sizeof(str_602)-1,@/
+str_start_604=str_start_603+sizeof(str_603)-1,@/
+str_start_605=str_start_604+sizeof(str_604)-1,@/
+str_start_606=str_start_605+sizeof(str_605)-1,@/
+str_start_607=str_start_606+sizeof(str_606)-1,@/
+str_start_608=str_start_607+sizeof(str_607)-1,@/
+str_start_609=str_start_608+sizeof(str_608)-1,@/
+str_start_610=str_start_609+sizeof(str_609)-1,@/
+str_start_611=str_start_610+sizeof(str_610)-1,@/
+str_start_612=str_start_611+sizeof(str_611)-1,@/
+str_start_613=str_start_612+sizeof(str_612)-1,@/
+str_start_614=str_start_613+sizeof(str_613)-1,@/
+str_start_615=str_start_614+sizeof(str_614)-1,@/
+str_start_616=str_start_615+sizeof(str_615)-1,@/
+str_start_617=str_start_616+sizeof(str_616)-1,@/
+str_start_618=str_start_617+sizeof(str_617)-1,@/
+str_start_619=str_start_618+sizeof(str_618)-1,@/
+str_start_620=str_start_619+sizeof(str_619)-1,@/
+str_start_621=str_start_620+sizeof(str_620)-1,@/
+str_start_622=str_start_621+sizeof(str_621)-1,@/
+str_start_623=str_start_622+sizeof(str_622)-1,@/
+str_start_624=str_start_623+sizeof(str_623)-1,@/
+str_start_625=str_start_624+sizeof(str_624)-1,@/
+str_start_626=str_start_625+sizeof(str_625)-1,@/
+str_start_627=str_start_626+sizeof(str_626)-1,@/
+str_start_628=str_start_627+sizeof(str_627)-1,@/
+str_start_629=str_start_628+sizeof(str_628)-1,@/
+str_start_630=str_start_629+sizeof(str_629)-1,@/
+str_start_631=str_start_630+sizeof(str_630)-1,@/
+str_start_632=str_start_631+sizeof(str_631)-1,@/
+str_start_633=str_start_632+sizeof(str_632)-1,@/
+str_start_634=str_start_633+sizeof(str_633)-1,@/
+str_start_635=str_start_634+sizeof(str_634)-1,@/
+str_start_636=str_start_635+sizeof(str_635)-1,@/
+str_start_637=str_start_636+sizeof(str_636)-1,@/
+str_start_638=str_start_637+sizeof(str_637)-1,@/
+str_start_639=str_start_638+sizeof(str_638)-1,@/
+str_start_640=str_start_639+sizeof(str_639)-1,@/
+str_start_641=str_start_640+sizeof(str_640)-1,@/
+str_start_642=str_start_641+sizeof(str_641)-1,@/
+str_start_643=str_start_642+sizeof(str_642)-1,@/
+str_start_644=str_start_643+sizeof(str_643)-1,@/
+str_start_645=str_start_644+sizeof(str_644)-1,@/
+str_start_646=str_start_645+sizeof(str_645)-1,@/
+str_start_647=str_start_646+sizeof(str_646)-1,@/
+str_start_648=str_start_647+sizeof(str_647)-1,@/
+str_start_649=str_start_648+sizeof(str_648)-1,@/
+str_start_650=str_start_649+sizeof(str_649)-1,@/
+str_start_651=str_start_650+sizeof(str_650)-1,@/
+str_start_652=str_start_651+sizeof(str_651)-1,@/
+str_start_653=str_start_652+sizeof(str_652)-1,@/
+str_start_654=str_start_653+sizeof(str_653)-1,@/
+str_start_655=str_start_654+sizeof(str_654)-1,@/
+str_start_656=str_start_655+sizeof(str_655)-1,@/
+str_start_657=str_start_656+sizeof(str_656)-1,@/
+str_start_658=str_start_657+sizeof(str_657)-1,@/
+str_start_659=str_start_658+sizeof(str_658)-1,@/
+str_start_660=str_start_659+sizeof(str_659)-1,@/
+str_start_661=str_start_660+sizeof(str_660)-1,@/
+str_start_662=str_start_661+sizeof(str_661)-1,@/
+str_start_663=str_start_662+sizeof(str_662)-1,@/
+str_start_664=str_start_663+sizeof(str_663)-1,@/
+str_start_665=str_start_664+sizeof(str_664)-1,@/
+str_start_666=str_start_665+sizeof(str_665)-1,@/
+str_start_667=str_start_666+sizeof(str_666)-1,@/
+str_start_668=str_start_667+sizeof(str_667)-1,@/
+str_start_end } str_starts;
+
+@ @<|pool_ptr| initialization@>= str_start_668
+
+@ @<|str_ptr| initialization@>= 668
+
+@* 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.
diff --git a/web/web2w/cweave.patch b/web/web2w/cweave.patch
new file mode 100644
index 0000000000..7a5af82159
--- /dev/null
+++ b/web/web2w/cweave.patch
@@ -0,0 +1,54 @@
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+--- /home/ruckert/hint/web2w/cweb/cweb/cweave.w 2002-02-01 00:00:00.000000000 +0100
++++ /home/ruckert/hint/web2w/cweb/cweave.w 2017-07-29 12:02:35.060013910 +0200
+@@ -117,24 +117,24 @@
+ If you change |max_bytes|, |max_names|, |hash_size|, or |buf_size|
+ you have to change them also in the file |"common.w"|.
+
+-@d max_bytes 90000 /* the number of bytes in identifiers,
++@d max_bytes 150000 /* the number of bytes in identifiers,
+ index entries, and section names */
+-@d max_names 4000 /* number of identifiers, strings, section names;
++@d max_names 6000 /* number of identifiers, strings, section names;
+ must be less than 10240; used in |"common.w"| */
+-@d max_sections 2000 /* greater than the total number of sections */
++@d max_sections 4000 /* greater than the total number of sections */
+ @d hash_size 353 /* should be prime */
+-@d buf_size 100 /* maximum length of input line, plus one */
++@d buf_size 5000 /* maximum length of input line, plus one */
+ @d longest_name 10000 /* section names and strings shouldn't be longer than this */
+ @d long_buf_size (buf_size+longest_name)
+-@d line_length 80 /* lines of \TEX/ output have at most this many characters;
++@d line_length 255 /* lines of \TEX/ output have at most this many characters;
+ should be less than 256 */
+-@d max_refs 20000 /* number of cross-references; must be less than 65536 */
+-@d max_toks 20000 /* number of symbols in \CEE/ texts being parsed;
++@d max_refs 40000 /* number of cross-references; must be less than 65536 */
++@d max_toks 65000 /* number of symbols in \CEE/ texts being parsed;
+ must be less than 65536 */
+-@d max_texts 4000 /* number of phrases in \CEE/ texts being parsed;
++@d max_texts 10200 /* number of phrases in \CEE/ texts being parsed;
+ must be less than 10240 */
+-@d max_scraps 2000 /* number of tokens in \CEE/ texts being parsed */
+-@d stack_size 400 /* number of simultaneous output levels */
++@d max_scraps 65000 /* number of tokens in \CEE/ texts being parsed */
++@d stack_size 4000 /* number of simultaneous output levels */
+
+ @ The next few sections contain stuff from the file |"common.w"| that must
+ be included in both |"ctangle.w"| and |"cweave.w"|. It appears in
diff --git a/web/web2w/pascal.tab.c b/web/web2w/pascal.tab.c
new file mode 100644
index 0000000000..bf6982ed2b
--- /dev/null
+++ b/web/web2w/pascal.tab.c
@@ -0,0 +1,3352 @@
+/*
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+*/
+/* A Bison parser, made by GNU Bison 2.7. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.7"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Substitute the type names. */
+#define YYSTYPE PPSTYPE
+/* Substitute the variable and function names. */
+#define yyparse ppparse
+#define yylex pplex
+#define yyerror pperror
+#define yylval pplval
+#define yychar ppchar
+#define yydebug ppdebug
+#define yynerrs ppnerrs
+
+/* Copy the first part of user declarations. */
+/* Line 371 of yacc.c */
+#line 1 "pascal.y"
+
+/*
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+*/
+
+#include <stdio.h>
+#include "web2w.h"
+
+/* the tag=token number of the left hand side symbol of a rule */
+#define LHSS (yyr1[yyn]+FIRST_PASCAL_TOKEN-3)
+
+ static int function=0;
+
+
+/* Line 371 of yacc.c */
+#line 107 "pascal.tab.c"
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "pascal.tab.h". */
+#ifndef YY_PP_PASCAL_TAB_H_INCLUDED
+# define YY_PP_PASCAL_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef PPDEBUG
+# if defined YYDEBUG
+# if YYDEBUG
+# define PPDEBUG 1
+# else
+# define PPDEBUG 0
+# endif
+# else /* ! defined YYDEBUG */
+# define PPDEBUG 1
+# endif /* ! defined YYDEBUG */
+#endif /* ! defined PPDEBUG */
+#if PPDEBUG
+extern int ppdebug;
+#endif
+/* "%code requires" blocks. */
+/* Line 387 of yacc.c */
+#line 32 "pascal.y"
+
+#define PPSTYPE token *
+#define YYSTYPE PPSTYPE
+
+ extern int ppparse(void);
+ extern int ppdebug;
+
+
+/* Line 387 of yacc.c */
+#line 156 "pascal.tab.c"
+
+/* Tokens. */
+#ifndef PPTOKENTYPE
+# define PPTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum pptokentype {
+ PEOF = 0,
+ WEBEOF = 258,
+ HEAD = 259,
+ BAR = 260,
+ PLEFT = 261,
+ MLEFT = 262,
+ RIGHT = 263,
+ OPEN = 264,
+ CLOSE = 265,
+ TEXT = 266,
+ NL = 267,
+ HASH = 268,
+ NMACRO = 269,
+ OMACRO = 270,
+ PMACRO = 271,
+ PARAM = 272,
+ EQ = 273,
+ EQEQ = 274,
+ ATSTAR = 275,
+ ATSPACE = 276,
+ ATD = 277,
+ ATF = 278,
+ ATLESS = 279,
+ ATGREATER = 280,
+ ELIPSIS = 281,
+ ATP = 282,
+ OCTAL = 283,
+ HEX = 284,
+ ATAT = 285,
+ ATDOLLAR = 286,
+ ATLEFT = 287,
+ ATRIGHT = 288,
+ ATINDEX = 289,
+ ATINDEXTT = 290,
+ ATINDEX9 = 291,
+ ATT = 292,
+ ATEQ = 293,
+ ATAND = 294,
+ ATBACKSLASH = 295,
+ ATEX = 296,
+ ATQM = 297,
+ ATCOMMA = 298,
+ ATSLASH = 299,
+ ATBAR = 300,
+ ATHASH = 301,
+ ATPLUS = 302,
+ ATSEMICOLON = 303,
+ STRING = 304,
+ CHAR = 305,
+ INDENT = 306,
+ METACOMMENT = 307,
+ CSEMICOLON = 308,
+ ID = 309,
+ WDEBUG = 310,
+ WSTAT = 311,
+ WINIT = 312,
+ WTINI = 313,
+ WTATS = 314,
+ WGUBED = 315,
+ PRETURN = 316,
+ FIRST_PASCAL_TOKEN = 317,
+ PPLUS = 318,
+ PMINUS = 319,
+ PSTAR = 320,
+ PSLASH = 321,
+ PEQ = 322,
+ PNOTEQ = 323,
+ PLESS = 324,
+ PGREATER = 325,
+ PLESSEQ = 326,
+ PGREATEREQ = 327,
+ POPEN = 328,
+ PCLOSE = 329,
+ PSQOPEN = 330,
+ PSQCLOSE = 331,
+ PASSIGN = 332,
+ PDOT = 333,
+ PCOMMA = 334,
+ PSEMICOLON = 335,
+ PMOD = 336,
+ PDIV = 337,
+ PNIL = 338,
+ POR = 339,
+ PAND = 340,
+ PNOT = 341,
+ PIF = 342,
+ PTHEN = 343,
+ PELSE = 344,
+ PREPEAT = 345,
+ PUNTIL = 346,
+ PWHILE = 347,
+ PDO = 348,
+ PFOR = 349,
+ PTO = 350,
+ PDOWNTO = 351,
+ PBEGIN = 352,
+ PEND = 353,
+ PGOTO = 354,
+ PINTEGER = 355,
+ PREAL = 356,
+ POTHERS = 357,
+ PSTRING = 358,
+ PCHAR = 359,
+ PTYPECHAR = 360,
+ PTYPEBOOL = 361,
+ PTYPEINT = 362,
+ PTYPEREAL = 363,
+ PTYPEINDEX = 364,
+ PID = 365,
+ PDEFVARID = 366,
+ PDEFPARAMID = 367,
+ PDEFREFID = 368,
+ PCONSTID = 369,
+ PDEFCONSTID = 370,
+ PDEFTYPEID = 371,
+ PDEFTYPESUBID = 372,
+ PARRAYFILETYPEID = 373,
+ PARRAYFILEID = 374,
+ PFUNCID = 375,
+ PDEFFUNCID = 376,
+ PPROCID = 377,
+ PCALLID = 378,
+ PRETURNID = 379,
+ PEXIT = 380,
+ PFBEGIN = 381,
+ PFEND = 382,
+ PDOTDOT = 383,
+ PCOLON = 384,
+ PUP = 385,
+ PIN = 386,
+ PCASE = 387,
+ POF = 388,
+ PWITH = 389,
+ PCONST = 390,
+ PVAR = 391,
+ PTYPE = 392,
+ PARRAY = 393,
+ PRECORD = 394,
+ PSET = 395,
+ PFILE = 396,
+ PFUNCTION = 397,
+ PPROCEDURE = 398,
+ PLABEL = 399,
+ PPACKED = 400,
+ PPROGRAM = 401,
+ PFORWARD = 402,
+ CIGNORE = 403,
+ CLABEL = 404,
+ CLABELN = 405,
+ CINTDEF = 406,
+ CSTRDEF = 407,
+ CMAIN = 408,
+ CMAINEND = 409,
+ CUNION = 410,
+ CTSUBRANGE = 411,
+ CINT = 412,
+ CREFID = 413,
+ CRETURN = 414,
+ CPROCRETURN = 415,
+ CCASE = 416,
+ CCOLON = 417,
+ CBREAK = 418,
+ CEMPTY = 419
+ };
+#endif
+
+
+#if ! defined PPSTYPE && ! defined PPSTYPE_IS_DECLARED
+typedef int PPSTYPE;
+# define PPSTYPE_IS_TRIVIAL 1
+# define ppstype PPSTYPE /* obsolescent; will be withdrawn */
+# define PPSTYPE_IS_DECLARED 1
+#endif
+
+extern PPSTYPE pplval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int ppparse (void *YYPARSE_PARAM);
+#else
+int ppparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int ppparse (void);
+#else
+int ppparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_PP_PASCAL_TAB_H_INCLUDED */
+
+/* Copy the second part of user declarations. */
+
+/* Line 390 of yacc.c */
+#line 359 "pascal.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(N) (N)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined PPSTYPE_IS_TRIVIAL && PPSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 5
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 581
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 165
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 97
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 251
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 457
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 419
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 155, 156, 157, 158, 159, 160, 161, 162, 163, 164
+};
+
+#if PPDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 10, 14, 20, 21, 25, 27, 31,
+ 33, 35, 37, 41, 42, 45, 49, 51, 54, 59,
+ 64, 65, 68, 70, 73, 78, 83, 87, 89, 91,
+ 95, 99, 101, 104, 107, 109, 111, 113, 118, 123,
+ 125, 126, 128, 130, 132, 134, 139, 144, 151, 153,
+ 157, 158, 162, 166, 168, 172, 177, 179, 182, 189,
+ 198, 200, 202, 204, 214, 224, 232, 240, 248, 249,
+ 252, 254, 257, 262, 267, 272, 274, 278, 279, 282,
+ 285, 288, 293, 295, 299, 301, 303, 307, 308, 311,
+ 313, 316, 321, 326, 331, 333, 337, 339, 341, 348,
+ 354, 358, 359, 366, 367, 375, 377, 379, 381, 385,
+ 392, 398, 407, 409, 413, 417, 419, 423, 425, 428,
+ 433, 438, 440, 442, 447, 452, 454, 456, 458, 462,
+ 464, 466, 468, 470, 474, 476, 480, 482, 486, 490,
+ 493, 496, 499, 501, 503, 505, 507, 511, 513, 515,
+ 517, 519, 521, 523, 525, 526, 530, 534, 540, 544,
+ 548, 554, 556, 558, 560, 562, 564, 568, 570, 572,
+ 577, 584, 590, 597, 599, 603, 607, 611, 614, 616,
+ 620, 624, 626, 628, 632, 636, 640, 643, 646, 651,
+ 657, 659, 661, 663, 668, 673, 682, 691, 700, 702,
+ 706, 710, 714, 716, 718, 720, 722, 724, 726, 728,
+ 733, 738, 743, 747, 750, 752, 756, 760, 762, 764,
+ 766, 768, 770, 772, 774, 777, 781, 786, 788, 790,
+ 792, 794, 796, 798, 802, 804, 806, 808, 810, 812,
+ 814, 816, 820, 822, 825, 827, 829, 831, 833, 835,
+ 837, 839
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 166, 0, -1, 167, 168, 97, 224, 98, 78, -1,
+ 146, 110, 80, -1, 169, 172, 176, 195, 199, -1,
+ -1, 144, 170, 80, -1, 171, -1, 170, 79, 171,
+ -1, 14, -1, 100, -1, 125, -1, 171, 63, 100,
+ -1, -1, 135, 173, -1, 135, 173, 175, -1, 174,
+ -1, 173, 174, -1, 110, 67, 100, 80, -1, 110,
+ 67, 103, 80, -1, -1, 137, 177, -1, 178, -1,
+ 177, 178, -1, 110, 67, 179, 80, -1, 110, 67,
+ 193, 80, -1, 180, 128, 180, -1, 105, -1, 181,
+ -1, 180, 63, 182, -1, 180, 64, 182, -1, 182,
+ -1, 63, 182, -1, 64, 182, -1, 100, -1, 14,
+ -1, 114, -1, 184, 141, 133, 185, -1, 184, 141,
+ 133, 179, -1, 145, -1, -1, 107, -1, 108, -1,
+ 106, -1, 110, -1, 184, 139, 187, 98, -1, 184,
+ 139, 190, 98, -1, 184, 139, 187, 80, 190, 98,
+ -1, 188, -1, 187, 80, 188, -1, -1, 189, 129,
+ 193, -1, 189, 129, 179, -1, 110, -1, 189, 79,
+ 110, -1, 132, 110, 133, 191, -1, 192, -1, 191,
+ 192, -1, 100, 129, 73, 188, 74, 80, -1, 100,
+ 129, 73, 188, 80, 188, 74, 80, -1, 185, -1,
+ 183, -1, 186, -1, 184, 138, 75, 180, 128, 180,
+ 76, 133, 193, -1, 184, 138, 75, 180, 128, 180,
+ 76, 133, 179, -1, 184, 138, 75, 110, 76, 133,
+ 193, -1, 184, 138, 75, 110, 76, 133, 179, -1,
+ 184, 138, 75, 105, 76, 133, 193, -1, -1, 136,
+ 196, -1, 197, -1, 196, 197, -1, 198, 129, 193,
+ 80, -1, 198, 129, 194, 80, -1, 198, 129, 179,
+ 80, -1, 248, -1, 198, 79, 248, -1, -1, 199,
+ 208, -1, 199, 209, -1, 136, 204, -1, 144, 201,
+ 80, 203, -1, 202, -1, 201, 79, 202, -1, 14,
+ -1, 100, -1, 171, 63, 100, -1, -1, 136, 204,
+ -1, 205, -1, 204, 205, -1, 206, 129, 193, 80,
+ -1, 206, 129, 194, 80, -1, 206, 129, 179, 80,
+ -1, 207, -1, 206, 79, 207, -1, 110, -1, 158,
+ -1, 213, 200, 97, 224, 98, 80, -1, 213, 97,
+ 224, 98, 80, -1, 213, 147, 80, -1, -1, 214,
+ 97, 210, 224, 98, 80, -1, -1, 214, 200, 97,
+ 211, 224, 98, 80, -1, 110, -1, 122, -1, 120,
+ -1, 143, 212, 80, -1, 143, 212, 73, 215, 74,
+ 80, -1, 142, 212, 129, 185, 80, -1, 142, 212,
+ 73, 215, 74, 129, 185, 80, -1, 216, -1, 215,
+ 80, 216, -1, 217, 129, 185, -1, 218, -1, 217,
+ 79, 218, -1, 248, -1, 136, 248, -1, 122, 73,
+ 221, 74, -1, 123, 73, 221, 74, -1, 122, -1,
+ 123, -1, 120, 73, 221, 74, -1, 123, 73, 221,
+ 74, -1, 120, -1, 123, -1, 222, -1, 221, 79,
+ 222, -1, 252, -1, 223, -1, 49, -1, 50, -1,
+ 252, 129, 252, -1, 225, -1, 224, 80, 225, -1,
+ 228, -1, 227, 129, 228, -1, 125, 129, 228, -1,
+ 99, 227, -1, 99, 125, -1, 148, 125, -1, 61,
+ -1, 100, -1, 14, -1, 149, -1, 14, 63, 100,
+ -1, 229, -1, 233, -1, 230, -1, 231, -1, 232,
+ -1, 226, -1, 219, -1, -1, 247, 77, 252, -1,
+ 247, 77, 49, -1, 247, 77, 73, 49, 74, -1,
+ 120, 77, 252, -1, 159, 148, 252, -1, 159, 148,
+ 252, 148, 148, -1, 159, -1, 160, -1, 234, -1,
+ 235, -1, 242, -1, 97, 224, 98, -1, 236, -1,
+ 237, -1, 87, 252, 88, 225, -1, 87, 252, 88,
+ 225, 89, 225, -1, 132, 252, 133, 238, 98, -1,
+ 132, 252, 133, 238, 80, 98, -1, 239, -1, 238,
+ 80, 239, -1, 238, 163, 239, -1, 240, 129, 225,
+ -1, 102, 225, -1, 241, -1, 240, 79, 241, -1,
+ 240, 162, 241, -1, 100, -1, 14, -1, 100, 63,
+ 14, -1, 14, 63, 14, -1, 14, 63, 100, -1,
+ 161, 14, -1, 161, 100, -1, 161, 14, 63, 14,
+ -1, 14, 64, 14, 63, 14, -1, 243, -1, 244,
+ -1, 245, -1, 92, 252, 93, 225, -1, 90, 224,
+ 91, 252, -1, 94, 110, 77, 252, 95, 246, 93,
+ 225, -1, 94, 110, 77, 252, 95, 180, 93, 225,
+ -1, 94, 110, 77, 252, 96, 180, 93, 225, -1,
+ 247, -1, 247, 64, 252, -1, 247, 63, 252, -1,
+ 180, 65, 252, -1, 110, -1, 158, -1, 249, -1,
+ 250, -1, 251, -1, 110, -1, 158, -1, 247, 75,
+ 252, 76, -1, 247, 75, 49, 76, -1, 119, 75,
+ 252, 76, -1, 247, 78, 110, -1, 247, 130, -1,
+ 254, -1, 254, 253, 254, -1, 254, 67, 49, -1,
+ 67, -1, 68, -1, 69, -1, 71, -1, 70, -1,
+ 72, -1, 257, -1, 255, 257, -1, 254, 256, 257,
+ -1, 254, 256, 255, 257, -1, 63, -1, 64, -1,
+ 63, -1, 64, -1, 84, -1, 259, -1, 257, 258,
+ 259, -1, 65, -1, 66, -1, 82, -1, 81, -1,
+ 85, -1, 247, -1, 260, -1, 73, 252, 74, -1,
+ 220, -1, 86, 259, -1, 261, -1, 100, -1, 14,
+ -1, 103, -1, 104, -1, 114, -1, 101, -1, 100,
+ 78, 100, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 220, 220, 227, 230, 233, 234, 237, 238, 241,
+ 242, 243, 244, 247, 248, 249, 252, 253, 256, 261,
+ 267, 268, 271, 272, 275, 283, 293, 295, 300, 301,
+ 303, 307, 308, 309, 314, 315, 316, 319, 320, 323,
+ 323, 325, 326, 327, 328, 332, 334, 336, 341, 342,
+ 348, 349, 350, 355, 356, 359, 363, 364, 368, 372,
+ 379, 380, 381, 387, 391, 396, 398, 401, 409, 410,
+ 413, 414, 417, 419, 421, 426, 427, 431, 432, 433,
+ 436, 437, 441, 442, 445, 446, 447, 451, 452, 455,
+ 456, 459, 461, 463, 467, 468, 471, 472, 479, 482,
+ 484, 487, 487, 490, 490, 510, 511, 512, 515, 517,
+ 522, 525, 531, 532, 536, 540, 541, 544, 545, 550,
+ 552, 554, 555, 558, 560, 561, 562, 566, 567, 572,
+ 573, 574, 575, 579, 582, 583, 588, 589, 590, 594,
+ 595, 596, 597, 603, 604, 605, 606, 611, 611, 613,
+ 613, 613, 613, 613, 615, 617, 618, 619, 623, 624,
+ 625, 627, 628, 632, 632, 632, 634, 637, 637, 639,
+ 640, 644, 646, 650, 651, 653, 657, 658, 661, 662,
+ 664, 667, 668, 669, 671, 673, 675, 676, 677, 678,
+ 682, 682, 682, 684, 687, 690, 695, 700, 707, 707,
+ 707, 707, 709, 710, 711, 712, 713, 716, 717, 720,
+ 721, 722, 726, 729, 732, 733, 734, 737, 737, 737,
+ 737, 737, 737, 739, 740, 741, 742, 745, 745, 747,
+ 747, 747, 749, 750, 753, 754, 755, 756, 757, 759,
+ 760, 761, 762, 763, 767, 768, 769, 770, 771, 772,
+ 775, 776
+};
+#endif
+
+#if PPDEBUG || YYERROR_VERBOSE || 1
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "\"end of file\"", "error", "$undefined", "\"end of web\"", "HEAD",
+ "BAR", "PLEFT", "MLEFT", "RIGHT", "OPEN", "CLOSE", "TEXT", "NL", "HASH",
+ "NMACRO", "OMACRO", "PMACRO", "PARAM", "EQ", "EQEQ", "ATSTAR", "ATSPACE",
+ "ATD", "ATF", "ATLESS", "ATGREATER", "ELIPSIS", "ATP", "OCTAL", "HEX",
+ "ATAT", "ATDOLLAR", "ATLEFT", "ATRIGHT", "ATINDEX", "ATINDEXTT",
+ "ATINDEX9", "ATT", "ATEQ", "ATAND", "ATBACKSLASH", "ATEX", "ATQM",
+ "ATCOMMA", "ATSLASH", "ATBAR", "ATHASH", "ATPLUS", "ATSEMICOLON",
+ "STRING", "CHAR", "INDENT", "METACOMMENT", "CSEMICOLON", "ID", "WDEBUG",
+ "WSTAT", "WINIT", "WTINI", "WTATS", "WGUBED", "\"return\"",
+ "FIRST_PASCAL_TOKEN", "\"+\"", "\"-\"", "\"*\"", "\"/\"", "\"=\"",
+ "\"<>\"", "\"<\"", "\">\"", "\"<=\"", "\">=\"", "\"(\"", "\")\"",
+ "\"[\"", "\"]\"", "\":=\"", "\".\"", "\",\"", "\";\"", "\"mod\"",
+ "\"div\"", "\"nil\"", "\"or\"", "\"and\"", "\"not\"", "\"if\"",
+ "\"then\"", "\"else\"", "\"repeat\"", "\"until\"", "\"while\"", "\"do\"",
+ "\"for\"", "\"to\"", "\"downto\"", "\"begin\"", "\"end\"", "\"goto\"",
+ "\"0-9\"", "\"real\"", "\"others\"", "\"'...'\"", "\"'.'\"",
+ "\"char type\"", "\"bool type\"", "\"integer type\"", "\"real type\"",
+ "\"index type\"", "\"identifier\"", "\"variable definition\"",
+ "\"parameter definition\"", "\"reference parameter definition\"",
+ "\"constant\"", "\"constant definition\"", "\"typename definition\"",
+ "\"subrange typename definition\"", "\"array of file type\"",
+ "\"array of file name\"", "\"functionname\"",
+ "\"functionname definition\"", "\"procedurename\"", "\"call\"",
+ "\"return value\"", "\"final_end\"", "\"function begin\"",
+ "\"function end\"", "\"..\"", "\":\"", "\"^\"", "\"in\"", "\"case\"",
+ "\"of\"", "\"with\"", "\"const\"", "\"var\"", "\"type\"", "\"array\"",
+ "\"record\"", "\"set\"", "\"file\"", "\"function\"", "\"procedure\"",
+ "\"label\"", "\"packed\"", "\"program\"", "\"forward\"", "CIGNORE",
+ "CLABEL", "CLABELN", "CINTDEF", "CSTRDEF", "CMAIN", "CMAINEND", "CUNION",
+ "CTSUBRANGE", "CINT", "\"reference variable\"", "\"C function return\"",
+ "\"C procedure return\"", "\"C case\"", "\"C :\"", "\"break\"",
+ "\"empty statement\"", "$accept", "program", "programheading", "globals",
+ "labels", "labellist", "labeldecl", "constants", "constdefinitions",
+ "constdefinition", "conststringdefinition", "types", "typedefinitions",
+ "typedefinition", "subrange", "iconst", "signed_iconst", "simple_iconst",
+ "file_type", "packed", "typename", "record_type", "fields",
+ "recordsection", "recids", "variant_part", "variants", "variant", "type",
+ "array_type", "variables", "vardeclarations", "vardeclaration", "varids",
+ "procedures", "locals", "locallabellist", "locallabeldecl",
+ "localvariables", "localvardeclarations", "localvardeclaration",
+ "localvarids", "localentire_var", "procedure", "function", "$@1", "$@2",
+ "pid", "pheading", "fheading", "formals", "formalparameters", "params",
+ "param", "proc_stmt", "function_call", "args", "arg", "write_arg",
+ "statements", "statement", "goto_stmt", "label", "stmt", "simple_stmt",
+ "empty_stmt", "assign_stmt", "return_stmt", "structured_stmt",
+ "compound_stmt", "conditional_stmt", "if_stmt", "case_stmt", "case_list",
+ "case_element", "case_labels", "case_label", "repetitive_stmt",
+ "while_stmt", "repeat_stmt", "for_stmt", "varlimit", "variable",
+ "entire_var", "indexed_var", "field_var", "file_var", "expression",
+ "relop", "simple_expr", "sign", "addop", "term", "mulop", "factor",
+ "unsigned_const", "real", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
+ 365, 366, 367, 368, 369, 370, 371, 372, 373, 374,
+ 375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+ 385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
+ 395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
+ 405, 406, 407, 408, 409, 410, 411, 412, 413, 414,
+ 415, 416, 417, 418, 419
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint16 yyr1[] =
+{
+ 0, 165, 166, 167, 168, 169, 169, 170, 170, 171,
+ 171, 171, 171, 172, 172, 172, 173, 173, 174, 175,
+ 176, 176, 177, 177, 178, 178, 179, 179, 180, 180,
+ 180, 181, 181, 181, 182, 182, 182, 183, 183, 184,
+ 184, 185, 185, 185, 185, 186, 186, 186, 187, 187,
+ 188, 188, 188, 189, 189, 190, 191, 191, 192, 192,
+ 193, 193, 193, 194, 194, 194, 194, 194, 195, 195,
+ 196, 196, 197, 197, 197, 198, 198, 199, 199, 199,
+ 200, 200, 201, 201, 202, 202, 202, 203, 203, 204,
+ 204, 205, 205, 205, 206, 206, 207, 207, 208, 208,
+ 208, 210, 209, 211, 209, 212, 212, 212, 213, 213,
+ 214, 214, 215, 215, 216, 217, 217, 218, 218, 219,
+ 219, 219, 219, 220, 220, 220, 220, 221, 221, 222,
+ 222, 222, 222, 223, 224, 224, 225, 225, 225, 226,
+ 226, 226, 226, 227, 227, 227, 227, 228, 228, 229,
+ 229, 229, 229, 229, 230, 231, 231, 231, 232, 232,
+ 232, 232, 232, 233, 233, 233, 234, 235, 235, 236,
+ 236, 237, 237, 238, 238, 238, 239, 239, 240, 240,
+ 240, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 242, 242, 242, 243, 244, 245, 245, 245, 246, 246,
+ 246, 246, 247, 247, 247, 247, 247, 248, 248, 249,
+ 249, 249, 250, 251, 252, 252, 252, 253, 253, 253,
+ 253, 253, 253, 254, 254, 254, 254, 255, 255, 256,
+ 256, 256, 257, 257, 258, 258, 258, 258, 258, 259,
+ 259, 259, 259, 259, 260, 260, 260, 260, 260, 260,
+ 261, 261
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 6, 3, 5, 0, 3, 1, 3, 1,
+ 1, 1, 3, 0, 2, 3, 1, 2, 4, 4,
+ 0, 2, 1, 2, 4, 4, 3, 1, 1, 3,
+ 3, 1, 2, 2, 1, 1, 1, 4, 4, 1,
+ 0, 1, 1, 1, 1, 4, 4, 6, 1, 3,
+ 0, 3, 3, 1, 3, 4, 1, 2, 6, 8,
+ 1, 1, 1, 9, 9, 7, 7, 7, 0, 2,
+ 1, 2, 4, 4, 4, 1, 3, 0, 2, 2,
+ 2, 4, 1, 3, 1, 1, 3, 0, 2, 1,
+ 2, 4, 4, 4, 1, 3, 1, 1, 6, 5,
+ 3, 0, 6, 0, 7, 1, 1, 1, 3, 6,
+ 5, 8, 1, 3, 3, 1, 3, 1, 2, 4,
+ 4, 1, 1, 4, 4, 1, 1, 1, 3, 1,
+ 1, 1, 1, 3, 1, 3, 1, 3, 3, 2,
+ 2, 2, 1, 1, 1, 1, 3, 1, 1, 1,
+ 1, 1, 1, 1, 0, 3, 3, 5, 3, 3,
+ 5, 1, 1, 1, 1, 1, 3, 1, 1, 4,
+ 6, 5, 6, 1, 3, 3, 3, 2, 1, 3,
+ 3, 1, 1, 3, 3, 3, 2, 2, 4, 5,
+ 1, 1, 1, 4, 4, 8, 8, 8, 1, 3,
+ 3, 3, 1, 1, 1, 1, 1, 1, 1, 4,
+ 4, 4, 3, 2, 1, 3, 3, 1, 1, 1,
+ 1, 1, 1, 1, 2, 3, 4, 1, 1, 1,
+ 1, 1, 1, 3, 1, 1, 1, 1, 1, 1,
+ 1, 3, 1, 2, 1, 1, 1, 1, 1, 1,
+ 1, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 0, 0, 5, 0, 1, 0, 0, 13, 3,
+ 9, 10, 11, 0, 7, 154, 0, 20, 0, 6,
+ 0, 144, 142, 0, 154, 0, 0, 154, 0, 143,
+ 202, 0, 0, 121, 122, 0, 0, 0, 145, 203,
+ 161, 162, 153, 0, 134, 152, 0, 136, 147, 149,
+ 150, 151, 148, 163, 164, 167, 168, 165, 190, 191,
+ 192, 0, 204, 205, 206, 0, 14, 16, 0, 68,
+ 8, 12, 0, 246, 227, 228, 0, 0, 245, 250,
+ 247, 248, 249, 125, 126, 242, 239, 0, 214, 0,
+ 223, 232, 240, 244, 0, 0, 0, 0, 140, 139,
+ 0, 0, 0, 0, 154, 0, 141, 0, 154, 0,
+ 154, 0, 0, 0, 213, 0, 0, 17, 15, 0,
+ 21, 22, 0, 77, 146, 0, 243, 0, 0, 0,
+ 154, 229, 230, 217, 218, 219, 221, 220, 222, 231,
+ 0, 0, 224, 234, 235, 237, 236, 238, 0, 0,
+ 154, 0, 166, 0, 158, 131, 132, 0, 127, 130,
+ 129, 0, 138, 0, 159, 135, 2, 137, 0, 0,
+ 156, 0, 155, 212, 0, 0, 40, 23, 207, 208,
+ 69, 70, 0, 75, 4, 241, 251, 0, 0, 169,
+ 216, 215, 0, 225, 233, 194, 193, 0, 211, 119,
+ 0, 0, 120, 182, 181, 154, 0, 0, 173, 0,
+ 178, 0, 210, 209, 0, 18, 0, 35, 0, 0,
+ 34, 27, 43, 41, 42, 44, 36, 39, 0, 0,
+ 28, 31, 61, 0, 60, 62, 0, 71, 0, 40,
+ 0, 0, 78, 79, 0, 0, 123, 124, 154, 226,
+ 0, 0, 128, 133, 0, 0, 0, 177, 186, 187,
+ 0, 171, 0, 0, 154, 0, 160, 157, 19, 32,
+ 33, 24, 0, 0, 0, 50, 0, 25, 76, 0,
+ 0, 0, 0, 105, 107, 106, 0, 0, 154, 0,
+ 0, 0, 0, 101, 0, 170, 0, 0, 198, 0,
+ 184, 185, 0, 183, 0, 172, 174, 175, 179, 176,
+ 180, 29, 30, 26, 53, 0, 0, 48, 0, 0,
+ 0, 74, 0, 72, 73, 0, 0, 0, 108, 0,
+ 96, 97, 80, 89, 0, 94, 84, 85, 0, 0,
+ 82, 100, 154, 154, 103, 0, 154, 154, 0, 0,
+ 154, 0, 188, 0, 50, 45, 0, 40, 46, 38,
+ 37, 0, 0, 0, 112, 0, 115, 117, 0, 0,
+ 0, 90, 0, 40, 0, 0, 87, 0, 0, 154,
+ 201, 196, 195, 200, 199, 197, 189, 0, 49, 0,
+ 54, 52, 51, 0, 0, 0, 118, 0, 0, 0,
+ 0, 110, 0, 99, 95, 0, 0, 0, 86, 83,
+ 0, 81, 0, 0, 0, 0, 55, 56, 47, 0,
+ 0, 0, 0, 113, 116, 114, 109, 93, 91, 92,
+ 88, 98, 102, 0, 0, 57, 40, 40, 0, 0,
+ 104, 50, 67, 66, 65, 0, 111, 0, 40, 0,
+ 50, 64, 63, 58, 0, 0, 59
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 2, 3, 7, 8, 13, 338, 17, 66, 67,
+ 118, 69, 120, 121, 228, 229, 230, 231, 232, 233,
+ 234, 235, 316, 317, 318, 319, 416, 417, 236, 282,
+ 123, 180, 181, 182, 184, 292, 339, 340, 411, 332,
+ 333, 334, 335, 242, 243, 343, 379, 286, 244, 245,
+ 363, 364, 365, 366, 42, 85, 157, 158, 159, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 207, 208, 209, 210, 57, 58, 59,
+ 60, 297, 86, 367, 62, 63, 64, 160, 140, 88,
+ 89, 141, 90, 148, 91, 92, 93
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -318
+static const yytype_int16 yypact[] =
+{
+ -97, -29, 65, -50, 53, -318, 5, 85, 59, -318,
+ -318, -318, -318, 87, 141, 64, 119, 107, 5, -318,
+ 151, 200, -318, 341, 64, 341, 164, 64, 19, -318,
+ -318, 207, 209, 220, 236, 193, 341, 188, -318, -318,
+ 178, -318, -318, -37, -318, -318, 215, -318, -318, -318,
+ -318, -318, -318, -318, -318, -318, -318, -318, -318, -318,
+ -318, 71, -318, -318, -318, 266, 240, -318, 247, 223,
+ 141, -318, 263, -318, -318, -318, 341, 367, 283, -318,
+ -318, -318, -318, 299, 303, -318, 75, 278, 465, 367,
+ 288, -318, -318, -318, 108, 290, 313, -32, -318, -318,
+ 341, 341, 157, 157, 421, 258, -318, 341, 64, 317,
+ 421, 248, 274, 297, -318, 298, 343, -318, -318, 344,
+ 247, -318, 27, -318, -318, 334, -318, 312, 157, 157,
+ 64, -318, -318, 364, -318, -318, -318, -318, -318, -318,
+ 341, 341, 288, -318, -318, -318, -318, -318, 367, 341,
+ 64, 341, -318, 339, -318, -318, -318, -16, -318, -318,
+ 289, 185, -318, 4, 273, -318, -318, -318, 346, 347,
+ -318, 316, -318, -318, 345, 52, 184, -318, -318, -318,
+ 27, -318, -44, -318, 66, -318, -318, 204, 221, 335,
+ -318, 113, 367, 288, -318, -318, -318, 222, -318, -318,
+ 157, 341, -318, 261, 365, 64, 8, -54, -318, -45,
+ -318, 281, -318, -318, 357, -318, 353, -318, 14, 14,
+ -318, -318, -318, -318, -318, -318, -318, -318, 354, -17,
+ -318, -318, -318, -100, -318, -318, 358, -318, 27, 184,
+ 146, 146, -318, -318, -57, 96, -318, -318, 64, 288,
+ 117, 10, -318, -318, 16, 423, 429, -318, 383, -318,
+ -1, -318, 4, -4, 64, -4, -318, -318, -318, -318,
+ -318, -318, 14, 14, 10, -73, 314, -318, -318, 368,
+ 169, 369, 370, -318, -318, -318, -53, 99, 64, 60,
+ 7, 372, 359, -318, 360, -318, -13, 361, 175, 162,
+ -318, -318, 399, -318, 449, -318, -318, -318, -318, -318,
+ -318, -318, -318, 279, -318, 355, -27, -318, -43, 371,
+ 395, -318, 391, -318, -318, 37, 293, 37, -318, 130,
+ -318, -318, 60, -318, -2, -318, 409, 410, 412, 306,
+ -318, -318, 64, 64, -318, 341, 64, 64, 341, 341,
+ 64, 462, -318, 350, -73, -318, 374, 184, -318, -318,
+ -318, 282, 27, -12, -318, 62, -318, -318, 398, 95,
+ 400, -318, 60, 184, 379, 7, 349, 139, 154, 64,
+ -318, -318, -318, -318, -318, -318, -318, 388, -318, 393,
+ -318, -318, -318, 413, 416, -7, -318, 375, 37, 37,
+ 293, -318, 414, -318, -318, 417, 418, 426, 430, -318,
+ 60, -318, 427, 432, 174, 381, 388, -318, -318, 363,
+ 384, 10, 293, -318, -318, -318, -318, -318, -318, -318,
+ 60, -318, -318, 434, 443, -318, 196, 184, 6, 439,
+ -318, 411, -318, -318, -318, 389, -318, 205, 184, 444,
+ 411, -318, -318, -318, 452, 447, -318
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -318, -318, -318, -318, -318, -318, 54, -318, -318, 457,
+ -318, -318, -318, 419, -237, -243, -318, -3, -318, -228,
+ -288, -318, -318, -312, -318, 176, -318, 122, -234, 172,
+ -318, -318, 362, -318, -318, 301, -318, 173, -318, 137,
+ -317, -318, 179, -318, -318, -318, -318, 309, -318, -318,
+ 225, 156, -318, 158, -318, -318, -74, 356, -318, -23,
+ -105, -318, 527, 177, -318, -318, -318, -318, -318, -318,
+ -318, -318, -318, -318, 39, -318, 51, -318, -318, -318,
+ -318, -318, -15, -116, -318, -318, -318, -9, -318, 420,
+ 422, -318, -66, -318, -60, -318, -318
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -13
+static const yytype_int16 yytable[] =
+{
+ 61, 94, 279, 165, 97, 281, 183, 296, 299, 61,
+ 203, 280, 61, 203, 87, 371, 95, 126, 203, 10,
+ 325, 336, 258, 142, 217, 189, 260, 105, 217, 161,
+ 300, 313, 360, 21, 263, 238, 356, 314, 368, 275,
+ 288, 276, 388, 108, 261, 196, 272, 273, 108, 1,
+ 272, 273, 345, 354, 187, 188, 272, 273, 199, 315,
+ 14, 109, 397, 200, 183, 5, 152, 125, 398, 272,
+ 273, 355, 70, 218, 219, 193, 326, 372, 21, 289,
+ 346, 4, 445, 359, 264, 239, 357, 290, 194, 61,
+ 291, 153, 154, 61, 6, 61, 204, 305, 164, 204,
+ 257, 205, 169, 172, 204, 11, 205, 337, 259, 262,
+ 220, 274, 425, 371, 220, 61, 301, 265, 395, 29,
+ 391, 421, 278, 392, 226, 22, 249, 373, 226, 447,
+ 12, 217, 12, 9, 439, 61, 405, 178, 454, 406,
+ 195, 399, 197, 295, 98, 280, 111, 178, 112, 113,
+ 111, 23, 174, 113, 24, 216, 25, 206, 26, 309,
+ 206, 27, 125, 28, 29, 206, 18, 19, 38, 402,
+ 330, 73, 327, 362, 30, 398, 131, 132, 438, 328,
+ 218, 219, 15, 31, 32, 179, 33, 34, 108, 35,
+ 61, 400, 253, 293, 16, 179, 36, 139, 217, 149,
+ 443, 114, 442, 444, 20, 114, 155, 156, 240, 241,
+ 108, 451, 37, 38, 452, 269, 270, 220, 331, 108,
+ 74, 75, 39, 40, 41, 272, 273, 30, 370, 65,
+ 76, 226, 289, 61, 108, 298, 31, 412, 348, 349,
+ 290, 381, 382, 77, 68, 385, 396, 218, 219, 61,
+ 111, 71, 413, 113, 108, 350, 283, 78, 79, 202,
+ 80, 81, 73, 72, 200, 329, 284, 30, 285, 311,
+ 312, 82, 433, 61, 96, 39, 31, 83, 246, 449,
+ 84, 162, 100, 200, 220, 450, 101, 167, 73, 221,
+ 222, 223, 224, 102, 225, 247, 217, 168, 226, 306,
+ 200, 307, 222, 223, 224, 114, 225, 322, 275, 103,
+ 276, 74, 75, 106, 308, 39, 310, 250, 251, 377,
+ 378, 76, 104, 170, 254, 255, 107, 61, 61, 227,
+ 73, 61, 61, 115, 77, 61, 380, 74, 75, 383,
+ 384, 227, 272, 273, 110, 218, 219, 171, 78, 79,
+ 116, 80, 81, 143, 144, 73, 414, 119, 30, 122,
+ 77, 127, 82, 124, 61, 214, 130, 31, 83, 145,
+ 146, 84, 128, 147, 78, 79, 129, 80, 81, 74,
+ 75, 73, 220, 150, 30, 375, 376, 393, 82, 76,
+ 151, 163, 394, 31, 83, 166, 226, 84, 174, 222,
+ 223, 224, 77, 225, 74, 75, 39, 173, 185, 217,
+ 175, 176, 186, 190, 76, 198, 78, 79, 201, 80,
+ 81, 211, 212, 213, 248, 215, 30, 77, 256, 266,
+ 82, 267, 39, 268, 271, 31, 83, 302, 277, 84,
+ 76, 78, 79, 303, 80, 81, 304, 320, 321, 323,
+ 324, 30, 341, 77, 347, 82, 342, 344, 218, 219,
+ 31, 83, 351, 352, 84, 353, 361, 78, 79, 358,
+ 80, 81, -9, -10, 39, 374, 386, 30, 401, 408,
+ 403, 82, 22, 387, 390, 410, 31, 83, 415, 419,
+ 84, 418, 420, -12, 426, 220, 436, 427, 428, 39,
+ 221, 222, 223, 224, 422, 225, 429, 431, 23, 226,
+ 434, 24, 432, 25, 440, 26, 441, 437, 27, 446,
+ 28, 314, 448, 117, 453, 39, 455, 456, 131, 132,
+ 389, 30, 133, 134, 135, 136, 137, 138, 435, 177,
+ 31, 32, 237, 33, 34, 407, 294, 430, 409, 139,
+ 287, 404, 369, 36, 423, 99, 252, 424, 0, 0,
+ 191, 0, 0, 192, 0, 0, 0, 0, 0, 37,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 39,
+ 40, 41
+};
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-318)))
+
+#define yytable_value_is_error(Yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 15, 24, 239, 108, 27, 239, 122, 250, 251, 24,
+ 14, 239, 27, 14, 23, 332, 25, 77, 14, 14,
+ 73, 14, 14, 89, 14, 130, 80, 36, 14, 103,
+ 14, 274, 320, 14, 79, 79, 79, 110, 326, 139,
+ 97, 141, 354, 80, 98, 150, 63, 64, 80, 146,
+ 63, 64, 65, 80, 128, 129, 63, 64, 74, 132,
+ 6, 98, 74, 79, 180, 0, 98, 76, 80, 63,
+ 64, 98, 18, 63, 64, 141, 129, 79, 14, 136,
+ 93, 110, 76, 320, 129, 129, 129, 144, 148, 104,
+ 147, 100, 101, 108, 144, 110, 100, 98, 107, 100,
+ 205, 102, 111, 112, 100, 100, 102, 100, 100, 163,
+ 100, 128, 400, 430, 100, 130, 100, 162, 361, 100,
+ 357, 128, 238, 357, 114, 61, 192, 129, 114, 441,
+ 125, 14, 125, 80, 422, 150, 373, 110, 450, 373,
+ 149, 79, 151, 248, 125, 373, 75, 110, 77, 78,
+ 75, 87, 100, 78, 90, 103, 92, 161, 94, 264,
+ 161, 97, 171, 99, 100, 161, 79, 80, 149, 74,
+ 110, 14, 73, 136, 110, 80, 63, 64, 421, 80,
+ 63, 64, 97, 119, 120, 158, 122, 123, 80, 125,
+ 205, 129, 201, 97, 135, 158, 132, 84, 14, 91,
+ 437, 130, 436, 437, 63, 130, 49, 50, 142, 143,
+ 80, 448, 148, 149, 448, 218, 219, 100, 158, 80,
+ 63, 64, 158, 159, 160, 63, 64, 110, 98, 110,
+ 73, 114, 136, 248, 80, 250, 119, 98, 63, 64,
+ 144, 346, 347, 86, 137, 350, 362, 63, 64, 264,
+ 75, 100, 98, 78, 80, 93, 110, 100, 101, 74,
+ 103, 104, 14, 63, 79, 288, 120, 110, 122, 272,
+ 273, 114, 98, 288, 110, 158, 119, 120, 74, 74,
+ 123, 104, 75, 79, 100, 80, 77, 110, 14, 105,
+ 106, 107, 108, 73, 110, 74, 14, 49, 114, 260,
+ 79, 262, 106, 107, 108, 130, 110, 138, 139, 73,
+ 141, 63, 64, 125, 263, 158, 265, 95, 96, 342,
+ 343, 73, 129, 49, 63, 64, 148, 342, 343, 145,
+ 14, 346, 347, 67, 86, 350, 345, 63, 64, 348,
+ 349, 145, 63, 64, 129, 63, 64, 73, 100, 101,
+ 110, 103, 104, 65, 66, 14, 379, 110, 110, 136,
+ 86, 78, 114, 100, 379, 49, 88, 119, 120, 81,
+ 82, 123, 73, 85, 100, 101, 73, 103, 104, 63,
+ 64, 14, 100, 93, 110, 79, 80, 105, 114, 73,
+ 77, 133, 110, 119, 120, 78, 114, 123, 100, 106,
+ 107, 108, 86, 110, 63, 64, 158, 110, 74, 14,
+ 67, 67, 100, 49, 73, 76, 100, 101, 129, 103,
+ 104, 148, 76, 76, 89, 80, 110, 86, 63, 148,
+ 114, 74, 158, 80, 80, 119, 120, 14, 80, 123,
+ 73, 100, 101, 14, 103, 104, 63, 133, 80, 80,
+ 80, 110, 80, 86, 93, 114, 97, 97, 63, 64,
+ 119, 120, 63, 14, 123, 110, 75, 100, 101, 98,
+ 103, 104, 63, 63, 158, 63, 14, 110, 80, 100,
+ 80, 114, 61, 133, 110, 136, 119, 120, 100, 76,
+ 123, 98, 76, 63, 80, 100, 133, 80, 80, 158,
+ 105, 106, 107, 108, 129, 110, 80, 80, 87, 114,
+ 129, 90, 80, 92, 80, 94, 73, 133, 97, 80,
+ 99, 110, 133, 66, 80, 158, 74, 80, 63, 64,
+ 354, 110, 67, 68, 69, 70, 71, 72, 416, 120,
+ 119, 120, 180, 122, 123, 373, 245, 410, 375, 84,
+ 241, 372, 327, 132, 398, 28, 200, 399, -1, -1,
+ 140, -1, -1, 141, -1, -1, -1, -1, -1, 148,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 158,
+ 159, 160
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint16 yystos[] =
+{
+ 0, 146, 166, 167, 110, 0, 144, 168, 169, 80,
+ 14, 100, 125, 170, 171, 97, 135, 172, 79, 80,
+ 63, 14, 61, 87, 90, 92, 94, 97, 99, 100,
+ 110, 119, 120, 122, 123, 125, 132, 148, 149, 158,
+ 159, 160, 219, 224, 225, 226, 227, 228, 229, 230,
+ 231, 232, 233, 234, 235, 236, 237, 242, 243, 244,
+ 245, 247, 249, 250, 251, 110, 173, 174, 137, 176,
+ 171, 100, 63, 14, 63, 64, 73, 86, 100, 101,
+ 103, 104, 114, 120, 123, 220, 247, 252, 254, 255,
+ 257, 259, 260, 261, 224, 252, 110, 224, 125, 227,
+ 75, 77, 73, 73, 129, 252, 125, 148, 80, 98,
+ 129, 75, 77, 78, 130, 67, 110, 174, 175, 110,
+ 177, 178, 136, 195, 100, 252, 259, 78, 73, 73,
+ 88, 63, 64, 67, 68, 69, 70, 71, 72, 84,
+ 253, 256, 257, 65, 66, 81, 82, 85, 258, 91,
+ 93, 77, 98, 252, 252, 49, 50, 221, 222, 223,
+ 252, 221, 228, 133, 252, 225, 78, 228, 49, 252,
+ 49, 73, 252, 110, 100, 67, 67, 178, 110, 158,
+ 196, 197, 198, 248, 199, 74, 100, 221, 221, 225,
+ 49, 254, 255, 257, 259, 252, 225, 252, 76, 74,
+ 79, 129, 74, 14, 100, 102, 161, 238, 239, 240,
+ 241, 148, 76, 76, 49, 80, 103, 14, 63, 64,
+ 100, 105, 106, 107, 108, 110, 114, 145, 179, 180,
+ 181, 182, 183, 184, 185, 186, 193, 197, 79, 129,
+ 142, 143, 208, 209, 213, 214, 74, 74, 89, 257,
+ 95, 96, 222, 252, 63, 64, 63, 225, 14, 100,
+ 80, 98, 163, 79, 129, 162, 148, 74, 80, 182,
+ 182, 80, 63, 64, 128, 139, 141, 80, 248, 179,
+ 184, 193, 194, 110, 120, 122, 212, 212, 97, 136,
+ 144, 147, 200, 97, 200, 225, 180, 246, 247, 180,
+ 14, 100, 14, 14, 63, 98, 239, 239, 241, 225,
+ 241, 182, 182, 180, 110, 132, 187, 188, 189, 190,
+ 133, 80, 138, 80, 80, 73, 129, 73, 80, 224,
+ 110, 158, 204, 205, 206, 207, 14, 100, 171, 201,
+ 202, 80, 97, 210, 97, 65, 93, 93, 63, 64,
+ 93, 63, 14, 110, 80, 98, 79, 129, 98, 179,
+ 185, 75, 136, 215, 216, 217, 218, 248, 185, 215,
+ 98, 205, 79, 129, 63, 79, 80, 224, 224, 211,
+ 252, 225, 225, 252, 252, 225, 14, 133, 188, 190,
+ 110, 179, 193, 105, 110, 180, 248, 74, 80, 79,
+ 129, 80, 74, 80, 207, 179, 193, 194, 100, 202,
+ 136, 203, 98, 98, 224, 100, 191, 192, 98, 76,
+ 76, 128, 129, 216, 218, 185, 80, 80, 80, 80,
+ 204, 80, 80, 98, 129, 192, 133, 133, 180, 185,
+ 80, 73, 193, 179, 193, 76, 80, 188, 133, 74,
+ 80, 179, 193, 80, 188, 74, 80
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if PPDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !PPDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !PPDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+/* Line 1792 of yacc.c */
+#line 222 "pascal.y"
+ { CHGTAG((yyvsp[(3) - (6)]),CMAIN); CHGTAG((yyvsp[(5) - (6)]),CMAINEND); IGN((yyvsp[(6) - (6)]));
+ wsemicolon((yyvsp[(4) - (6)]),(yyvsp[(5) - (6)]));
+ }
+ break;
+
+ case 3:
+/* Line 1792 of yacc.c */
+#line 227 "pascal.y"
+ {IGN((yyvsp[(2) - (3)])); IGN((yyvsp[(3) - (3)])); }
+ break;
+
+ case 6:
+/* Line 1792 of yacc.c */
+#line 234 "pascal.y"
+ { IGN((yyvsp[(3) - (3)])); }
+ break;
+
+ case 8:
+/* Line 1792 of yacc.c */
+#line 238 "pascal.y"
+ { IGN((yyvsp[(2) - (3)])); }
+ break;
+
+ case 9:
+/* Line 1792 of yacc.c */
+#line 241 "pascal.y"
+ {IGN((yyvsp[(1) - (1)])); SYM((yyvsp[(1) - (1)]))->obsolete=1; }
+ break;
+
+ case 10:
+/* Line 1792 of yacc.c */
+#line 242 "pascal.y"
+ {IGN((yyvsp[(1) - (1)])); }
+ break;
+
+ case 11:
+/* Line 1792 of yacc.c */
+#line 243 "pascal.y"
+ {IGN((yyvsp[(1) - (1)])); }
+ break;
+
+ case 12:
+/* Line 1792 of yacc.c */
+#line 244 "pascal.y"
+ {IGN((yyvsp[(2) - (3)])); IGN((yyvsp[(3) - (3)])); }
+ break;
+
+ case 18:
+/* Line 1792 of yacc.c */
+#line 256 "pascal.y"
+ { LNK((yyvsp[(1) - (4)]),(yyvsp[(2) - (4)])); LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)]));
+ SETVAL((yyvsp[(1) - (4)]),getval((yyvsp[(3) - (4)]))); CHGID((yyvsp[(1) - (4)]),PCONSTID);
+ CHGTAG((yyvsp[(1) - (4)]),CINTDEF); }
+ break;
+
+ case 19:
+/* Line 1792 of yacc.c */
+#line 262 "pascal.y"
+ { seq((yyvsp[(1) - (4)]),(yyvsp[(4) - (4)])); CHGID((yyvsp[(1) - (4)]),PCONSTID);
+ CHGTAG((yyvsp[(1) - (4)]),CSTRDEF);CHGTAG((yyvsp[(2) - (4)]),PASSIGN); }
+ break;
+
+ case 21:
+/* Line 1792 of yacc.c */
+#line 268 "pascal.y"
+ { IGN((yyvsp[(1) - (2)])); }
+ break;
+
+ case 24:
+/* Line 1792 of yacc.c */
+#line 276 "pascal.y"
+ { DBG(dbgparse,"New Subrange Type: %s\n",
+ SYM((yyvsp[(1) - (4)]))->name);
+ LNK((yyvsp[(1) - (4)]),(yyvsp[(2) - (4)])); IGN((yyvsp[(2) - (4)]));LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)]));
+ CHGTYPE((yyvsp[(1) - (4)]),(yyvsp[(3) - (4)]));
+ CHGTAG((yyvsp[(1) - (4)]),PDEFTYPEID);
+ CHGTAG((yyvsp[(2) - (4)]),CTSUBRANGE); UP((yyvsp[(2) - (4)]),(yyvsp[(3) - (4)]));
+ }
+ break;
+
+ case 25:
+/* Line 1792 of yacc.c */
+#line 284 "pascal.y"
+ { DBG(dbgparse,"New Type: %s\n",
+ SYM((yyvsp[(1) - (4)]))->name);
+ LNK((yyvsp[(1) - (4)]),(yyvsp[(2) - (4)])); IGN((yyvsp[(2) - (4)])); LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)]));
+ CHGTYPE((yyvsp[(1) - (4)]),(yyvsp[(3) - (4)])); LNK((yyvsp[(3) - (4)]),(yyvsp[(4) - (4)]));
+ CHGTAG((yyvsp[(1) - (4)]),PDEFTYPEID);
+ }
+ break;
+
+ case 26:
+/* Line 1792 of yacc.c */
+#line 294 "pascal.y"
+ {(yyval)=join(PDOTDOT,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),(yyvsp[(3) - (3)])->value-(yyvsp[(1) - (3)])->value+1); }
+ break;
+
+ case 27:
+/* Line 1792 of yacc.c */
+#line 296 "pascal.y"
+ {(yyval)=join(PDOTDOT,join(PTYPECHAR,(yyvsp[(1) - (1)]),(yyvsp[(1) - (1)]),0),
+ join(PTYPECHAR,(yyvsp[(1) - (1)]),(yyvsp[(1) - (1)]),255),256); }
+ break;
+
+ case 28:
+/* Line 1792 of yacc.c */
+#line 300 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 29:
+/* Line 1792 of yacc.c */
+#line 302 "pascal.y"
+ {(yyval)=join(PPLUS,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),(yyvsp[(1) - (3)])->value+(yyvsp[(3) - (3)])->value); }
+ break;
+
+ case 30:
+/* Line 1792 of yacc.c */
+#line 304 "pascal.y"
+ {(yyval)=join(PMINUS,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),(yyvsp[(1) - (3)])->value-(yyvsp[(3) - (3)])->value); }
+ break;
+
+ case 31:
+/* Line 1792 of yacc.c */
+#line 307 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 32:
+/* Line 1792 of yacc.c */
+#line 308 "pascal.y"
+ {(yyval)=join(PPLUS,NULL,(yyvsp[(2) - (2)]),(yyvsp[(2) - (2)])->value); }
+ break;
+
+ case 33:
+/* Line 1792 of yacc.c */
+#line 310 "pascal.y"
+ {(yyval)=join(PMINUS,NULL,(yyvsp[(2) - (2)]),-((yyvsp[(2) - (2)])->value)); }
+ break;
+
+ case 34:
+/* Line 1792 of yacc.c */
+#line 314 "pascal.y"
+ {(yyval)=join(PINTEGER,(yyvsp[(1) - (1)]),NULL,getval((yyvsp[(1) - (1)]))); }
+ break;
+
+ case 35:
+/* Line 1792 of yacc.c */
+#line 315 "pascal.y"
+ {(yyval)=join(NMACRO,(yyvsp[(1) - (1)]),NULL,getval((yyvsp[(1) - (1)]))); }
+ break;
+
+ case 36:
+/* Line 1792 of yacc.c */
+#line 316 "pascal.y"
+ {(yyval)=join(PCONSTID,(yyvsp[(1) - (1)]),NULL,getval((yyvsp[(1) - (1)]))); }
+ break;
+
+ case 37:
+/* Line 1792 of yacc.c */
+#line 319 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (4)]); }
+ break;
+
+ case 38:
+/* Line 1792 of yacc.c */
+#line 320 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (4)]); }
+ break;
+
+ case 41:
+/* Line 1792 of yacc.c */
+#line 325 "pascal.y"
+ {(yyval)=NULL; }
+ break;
+
+ case 42:
+/* Line 1792 of yacc.c */
+#line 326 "pascal.y"
+ {(yyval)=NULL; }
+ break;
+
+ case 43:
+/* Line 1792 of yacc.c */
+#line 327 "pascal.y"
+ {(yyval)=NULL; }
+ break;
+
+ case 44:
+/* Line 1792 of yacc.c */
+#line 328 "pascal.y"
+ {(yyval)=NULL; }
+ break;
+
+ case 45:
+/* Line 1792 of yacc.c */
+#line 332 "pascal.y"
+ { LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)])); LNK((yyvsp[(3) - (4)]),(yyvsp[(4) - (4)]));
+ if ((yyvsp[(3) - (4)])) CHGTAG((yyvsp[(4) - (4)]),PSEMICOLON); else IGN((yyvsp[(4) - (4)])); (yyval)=NULL; }
+ break;
+
+ case 46:
+/* Line 1792 of yacc.c */
+#line 335 "pascal.y"
+ { LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)])); LNK((yyvsp[(3) - (4)]),(yyvsp[(4) - (4)])); IGN((yyvsp[(4) - (4)])); (yyval)=NULL; }
+ break;
+
+ case 47:
+/* Line 1792 of yacc.c */
+#line 337 "pascal.y"
+ { LNK((yyvsp[(2) - (6)]),(yyvsp[(6) - (6)])); LNK((yyvsp[(3) - (6)]),(yyvsp[(4) - (6)])); LNK((yyvsp[(5) - (6)]),(yyvsp[(6) - (6)])); IGN((yyvsp[(6) - (6)])); (yyval)=NULL; }
+ break;
+
+ case 48:
+/* Line 1792 of yacc.c */
+#line 341 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 49:
+/* Line 1792 of yacc.c */
+#line 342 "pascal.y"
+ { LNK((yyvsp[(1) - (3)]),(yyvsp[(2) - (3)])); (yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 50:
+/* Line 1792 of yacc.c */
+#line 348 "pascal.y"
+ {(yyval)=NULL; }
+ break;
+
+ case 51:
+/* Line 1792 of yacc.c */
+#line 349 "pascal.y"
+ {LNK((yyvsp[(1) - (3)]),(yyvsp[(2) - (3)])); IGN((yyvsp[(2) - (3)])); (yyval)=(yyvsp[(2) - (3)]); }
+ break;
+
+ case 52:
+/* Line 1792 of yacc.c */
+#line 351 "pascal.y"
+ {LNK((yyvsp[(1) - (3)]),(yyvsp[(2) - (3)])); CHGTAG((yyvsp[(2) - (3)]),CTSUBRANGE); UP((yyvsp[(2) - (3)]),(yyvsp[(3) - (3)])); (yyval)=(yyvsp[(2) - (3)]); }
+ break;
+
+ case 53:
+/* Line 1792 of yacc.c */
+#line 355 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); CHGTAG((yyvsp[(1) - (1)]),PDEFVARID); }
+ break;
+
+ case 54:
+/* Line 1792 of yacc.c */
+#line 356 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (3)]); }
+ break;
+
+ case 55:
+/* Line 1792 of yacc.c */
+#line 359 "pascal.y"
+ {IGN((yyvsp[(1) - (4)]));IGN((yyvsp[(2) - (4)]));
+ CHGTAG((yyvsp[(3) - (4)]),CUNION); (yyval)=(yyvsp[(3) - (4)]); }
+ break;
+
+ case 58:
+/* Line 1792 of yacc.c */
+#line 369 "pascal.y"
+ { IGN((yyvsp[(1) - (6)])); IGN((yyvsp[(2) - (6)])); IGN((yyvsp[(3) - (6)]));
+ LNK((yyvsp[(4) - (6)]),(yyvsp[(5) - (6)]));
+ IGN((yyvsp[(5) - (6)])); }
+ break;
+
+ case 59:
+/* Line 1792 of yacc.c */
+#line 374 "pascal.y"
+ { IGN((yyvsp[(1) - (8)])); IGN((yyvsp[(2) - (8)])); CHGTAG((yyvsp[(3) - (8)]),PRECORD);
+ LNK((yyvsp[(3) - (8)]),(yyvsp[(8) - (8)])); LNK((yyvsp[(4) - (8)]),(yyvsp[(5) - (8)])); LNK((yyvsp[(6) - (8)]),(yyvsp[(7) - (8)])); CHGTAG((yyvsp[(7) - (8)]),PSEMICOLON); }
+ break;
+
+ case 63:
+/* Line 1792 of yacc.c */
+#line 388 "pascal.y"
+ {LNK((yyvsp[(2) - (9)]),(yyvsp[(3) - (9)]));
+ UP((yyvsp[(2) - (9)]),join(PDOTDOT,(yyvsp[(4) - (9)]),(yyvsp[(6) - (9)]),(yyvsp[(6) - (9)])->value-(yyvsp[(4) - (9)])->value+1));
+ LNK((yyvsp[(3) - (9)]),(yyvsp[(5) - (9)])); LNK((yyvsp[(5) - (9)]),(yyvsp[(7) - (9)])); LNK((yyvsp[(7) - (9)]),(yyvsp[(8) - (9)]));(yyval)=(yyvsp[(8) - (9)]); }
+ break;
+
+ case 64:
+/* Line 1792 of yacc.c */
+#line 392 "pascal.y"
+ {LNK((yyvsp[(2) - (9)]),(yyvsp[(3) - (9)]));
+ UP((yyvsp[(2) - (9)]),join(PDOTDOT,(yyvsp[(4) - (9)]),(yyvsp[(6) - (9)]),(yyvsp[(6) - (9)])->value-(yyvsp[(4) - (9)])->value+1));
+ LNK((yyvsp[(3) - (9)]),(yyvsp[(5) - (9)])); LNK((yyvsp[(5) - (9)]),(yyvsp[(7) - (9)])); LNK((yyvsp[(7) - (9)]),(yyvsp[(8) - (9)]));
+ CHGTAG((yyvsp[(8) - (9)]),CTSUBRANGE); UP((yyvsp[(8) - (9)]),(yyvsp[(9) - (9)]));(yyval)=(yyvsp[(8) - (9)]); }
+ break;
+
+ case 65:
+/* Line 1792 of yacc.c */
+#line 396 "pascal.y"
+ {LNK((yyvsp[(2) - (7)]),(yyvsp[(3) - (7)]));
+ UP((yyvsp[(2) - (7)]),(yyvsp[(4) - (7)]));LNK((yyvsp[(3) - (7)]),(yyvsp[(4) - (7)])); LNK((yyvsp[(4) - (7)]),(yyvsp[(5) - (7)])); LNK((yyvsp[(5) - (7)]),(yyvsp[(6) - (7)]));(yyval)=(yyvsp[(6) - (7)]); }
+ break;
+
+ case 66:
+/* Line 1792 of yacc.c */
+#line 399 "pascal.y"
+ {LNK((yyvsp[(2) - (7)]),(yyvsp[(3) - (7)])); UP((yyvsp[(2) - (7)]),(yyvsp[(4) - (7)])); LNK((yyvsp[(3) - (7)]),(yyvsp[(4) - (7)])); LNK((yyvsp[(4) - (7)]),(yyvsp[(5) - (7)]));
+ LNK((yyvsp[(5) - (7)]),(yyvsp[(6) - (7)])); CHGTAG((yyvsp[(6) - (7)]),CTSUBRANGE); UP((yyvsp[(6) - (7)]),(yyvsp[(7) - (7)]));(yyval)=(yyvsp[(6) - (7)]); }
+ break;
+
+ case 67:
+/* Line 1792 of yacc.c */
+#line 402 "pascal.y"
+ {LNK((yyvsp[(2) - (7)]),(yyvsp[(3) - (7)])); UP((yyvsp[(2) - (7)]),join(PDOTDOT,
+ join(PTYPECHAR,(yyvsp[(1) - (7)]),(yyvsp[(1) - (7)]),0),join(PTYPECHAR,(yyvsp[(1) - (7)]),(yyvsp[(1) - (7)]),255),256));
+ (yyvsp[(3) - (7)])->link=join(PTYPECHAR,(yyvsp[(3) - (7)]),(yyvsp[(5) - (7)]),256); (yyvsp[(3) - (7)])->link->link=(yyvsp[(5) - (7)]);
+ /* the PTYPECHAR comes from a macroexpansion, so we can not
+ link it directly */ LNK((yyvsp[(5) - (7)]),(yyvsp[(6) - (7)])); (yyval)=(yyvsp[(6) - (7)]); }
+ break;
+
+ case 69:
+/* Line 1792 of yacc.c */
+#line 410 "pascal.y"
+ { IGN((yyvsp[(1) - (2)])); }
+ break;
+
+ case 72:
+/* Line 1792 of yacc.c */
+#line 417 "pascal.y"
+ { LNK((yyvsp[(1) - (4)]),(yyvsp[(2) - (4)]));
+ IGN((yyvsp[(2) - (4)])); LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)])); }
+ break;
+
+ case 73:
+/* Line 1792 of yacc.c */
+#line 419 "pascal.y"
+ { LNK((yyvsp[(1) - (4)]),(yyvsp[(2) - (4)]));
+ IGN((yyvsp[(2) - (4)])); LNK((yyvsp[(3) - (4)]),(yyvsp[(4) - (4)])); LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)])); }
+ break;
+
+ case 74:
+/* Line 1792 of yacc.c */
+#line 421 "pascal.y"
+ { LNK((yyvsp[(1) - (4)]),(yyvsp[(2) - (4)]));
+ CHGTAG((yyvsp[(2) - (4)]),CTSUBRANGE); UP((yyvsp[(2) - (4)]),(yyvsp[(3) - (4)])); LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)])); }
+ break;
+
+ case 75:
+/* Line 1792 of yacc.c */
+#line 426 "pascal.y"
+ {CHGTAG((yyvsp[(1) - (1)]),PDEFVARID); (yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 76:
+/* Line 1792 of yacc.c */
+#line 427 "pascal.y"
+ {LNK((yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]));(yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 80:
+/* Line 1792 of yacc.c */
+#line 436 "pascal.y"
+ { CHGTAG((yyvsp[(1) - (2)]),PBEGIN); }
+ break;
+
+ case 81:
+/* Line 1792 of yacc.c */
+#line 438 "pascal.y"
+ { CHGTAG((yyvsp[(1) - (4)]),PBEGIN); IGN((yyvsp[(3) - (4)])); }
+ break;
+
+ case 83:
+/* Line 1792 of yacc.c */
+#line 442 "pascal.y"
+ {IGN((yyvsp[(2) - (3)])); }
+ break;
+
+ case 84:
+/* Line 1792 of yacc.c */
+#line 445 "pascal.y"
+ {IGN((yyvsp[(1) - (1)])); SYM((yyvsp[(1) - (1)]))->obsolete=1; localize((yyvsp[(1) - (1)])); }
+ break;
+
+ case 85:
+/* Line 1792 of yacc.c */
+#line 446 "pascal.y"
+ {IGN((yyvsp[(1) - (1)])); }
+ break;
+
+ case 86:
+/* Line 1792 of yacc.c */
+#line 447 "pascal.y"
+ {IGN((yyvsp[(2) - (3)])); IGN((yyvsp[(3) - (3)])); }
+ break;
+
+ case 88:
+/* Line 1792 of yacc.c */
+#line 452 "pascal.y"
+ { IGN((yyvsp[(1) - (2)])); }
+ break;
+
+ case 91:
+/* Line 1792 of yacc.c */
+#line 460 "pascal.y"
+ { LNK((yyvsp[(1) - (4)]),(yyvsp[(2) - (4)])); IGN((yyvsp[(2) - (4)])); LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)])); }
+ break;
+
+ case 92:
+/* Line 1792 of yacc.c */
+#line 462 "pascal.y"
+ { LNK((yyvsp[(1) - (4)]),(yyvsp[(2) - (4)])); IGN((yyvsp[(2) - (4)])); LNK((yyvsp[(3) - (4)]),(yyvsp[(4) - (4)])); LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)])); }
+ break;
+
+ case 93:
+/* Line 1792 of yacc.c */
+#line 464 "pascal.y"
+ { LNK((yyvsp[(1) - (4)]),(yyvsp[(2) - (4)])); CHGTAG((yyvsp[(2) - (4)]),CTSUBRANGE);
+ UP((yyvsp[(2) - (4)]),(yyvsp[(3) - (4)])); LNK((yyvsp[(2) - (4)]),(yyvsp[(4) - (4)])); }
+ break;
+
+ case 94:
+/* Line 1792 of yacc.c */
+#line 467 "pascal.y"
+ {CHGTAG((yyvsp[(1) - (1)]),PDEFVARID); (yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 95:
+/* Line 1792 of yacc.c */
+#line 468 "pascal.y"
+ {LNK((yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]));(yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 96:
+/* Line 1792 of yacc.c */
+#line 471 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); localize((yyvsp[(1) - (1)])); }
+ break;
+
+ case 97:
+/* Line 1792 of yacc.c */
+#line 472 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); CHGTAG((yyvsp[(1) - (1)]),PID);
+ CHGID((yyvsp[(1) - (1)]),PID); localize((yyvsp[(1) - (1)])); }
+ break;
+
+ case 98:
+/* Line 1792 of yacc.c */
+#line 480 "pascal.y"
+ {IGN((yyvsp[(3) - (6)])); IGN((yyvsp[(6) - (6)])); wend((yyvsp[(4) - (6)]),(yyvsp[(5) - (6)])); wsemicolon((yyvsp[(4) - (6)]),(yyvsp[(5) - (6)]));
+ scope_close(); }
+ break;
+
+ case 99:
+/* Line 1792 of yacc.c */
+#line 483 "pascal.y"
+ { IGN((yyvsp[(5) - (5)])); wend((yyvsp[(3) - (5)]),(yyvsp[(4) - (5)])); wsemicolon((yyvsp[(3) - (5)]),(yyvsp[(4) - (5)])); scope_close(); }
+ break;
+
+ case 100:
+/* Line 1792 of yacc.c */
+#line 484 "pascal.y"
+ { scope_close(); }
+ break;
+
+ case 101:
+/* Line 1792 of yacc.c */
+#line 487 "pascal.y"
+ {function=1; }
+ break;
+
+ case 102:
+/* Line 1792 of yacc.c */
+#line 488 "pascal.y"
+ {function=0; wreturn((yyvsp[(4) - (6)]), 1,NULL); IGN((yyvsp[(6) - (6)]));
+ wsemicolon((yyvsp[(4) - (6)]),(yyvsp[(5) - (6)])); scope_close(); }
+ break;
+
+ case 103:
+/* Line 1792 of yacc.c */
+#line 490 "pascal.y"
+ {function=1; }
+ break;
+
+ case 104:
+/* Line 1792 of yacc.c */
+#line 492 "pascal.y"
+ { int f_no=(yyvsp[(1) - (7)])->sym_no;
+ function=0;
+ if (f_no==x_over_n || f_no==xn_over_d)
+ { DBG(dbgcweb,"Discovered function %s; in line %d\n",
+ SYM((yyvsp[(1) - (7)]))->name,(yyvsp[(1) - (7)])->lineno);
+ CHGTAG((yyvsp[(3) - (7)]),PFBEGIN); (yyvsp[(3) - (7)])->sym_no=f_no;
+ CHGTAG((yyvsp[(6) - (7)]),PFEND); (yyvsp[(6) - (7)])->sym_no=f_no;
+ }
+ else
+ { IGN((yyvsp[(3) - (7)]));
+ wreturn((yyvsp[(5) - (7)]),1,NULL);
+ }
+ wsemicolon((yyvsp[(5) - (7)]),(yyvsp[(6) - (7)]));
+ IGN((yyvsp[(7) - (7)]));
+ scope_close();
+ }
+ break;
+
+ case 105:
+/* Line 1792 of yacc.c */
+#line 510 "pascal.y"
+ {scope_open(); (yyval)=(yyvsp[(1) - (1)]); START_PARAM; }
+ break;
+
+ case 106:
+/* Line 1792 of yacc.c */
+#line 511 "pascal.y"
+ {scope_open(); (yyval)=(yyvsp[(1) - (1)]); START_PARAM; }
+ break;
+
+ case 107:
+/* Line 1792 of yacc.c */
+#line 512 "pascal.y"
+ {scope_open(); (yyval)=(yyvsp[(1) - (1)]); START_PARAM; }
+ break;
+
+ case 108:
+/* Line 1792 of yacc.c */
+#line 516 "pascal.y"
+ { LNK((yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); CHGID((yyvsp[(2) - (3)]),PPROCID); CHGVALUE((yyvsp[(2) - (3)]),1); IGN((yyvsp[(3) - (3)])); }
+ break;
+
+ case 109:
+/* Line 1792 of yacc.c */
+#line 518 "pascal.y"
+ { LNK((yyvsp[(1) - (6)]),(yyvsp[(3) - (6)])); CHGID((yyvsp[(2) - (6)]),PPROCID); CHGVALUE((yyvsp[(2) - (6)]),param_mask);
+ LNK((yyvsp[(4) - (6)]),(yyvsp[(5) - (6)])); IGN((yyvsp[(6) - (6)])); }
+ break;
+
+ case 110:
+/* Line 1792 of yacc.c */
+#line 523 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (5)]); LNK((yyvsp[(1) - (5)]),(yyvsp[(3) - (5)])); CHGID((yyvsp[(2) - (5)]),PFUNCID);
+ CHGVALUE((yyvsp[(2) - (5)]),1);IGN((yyvsp[(3) - (5)])); LNK((yyvsp[(3) - (5)]),(yyvsp[(5) - (5)])); IGN((yyvsp[(5) - (5)])); }
+ break;
+
+ case 111:
+/* Line 1792 of yacc.c */
+#line 526 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (8)]); LNK((yyvsp[(1) - (8)]),(yyvsp[(3) - (8)]));
+ CHGID((yyvsp[(2) - (8)]),PFUNCID); CHGVALUE((yyvsp[(2) - (8)]),param_mask);
+ LNK((yyvsp[(4) - (8)]),(yyvsp[(5) - (8)])); LNK((yyvsp[(5) - (8)]),(yyvsp[(6) - (8)])); IGN((yyvsp[(6) - (8)])); LNK((yyvsp[(6) - (8)]),(yyvsp[(8) - (8)])); IGN((yyvsp[(8) - (8)])); }
+ break;
+
+ case 112:
+/* Line 1792 of yacc.c */
+#line 531 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 113:
+/* Line 1792 of yacc.c */
+#line 533 "pascal.y"
+ { LNK((yyvsp[(1) - (3)]),(yyvsp[(2) - (3)])); CHGTAG((yyvsp[(2) - (3)]),PCOMMA); (yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 114:
+/* Line 1792 of yacc.c */
+#line 537 "pascal.y"
+ { LNK((yyvsp[(1) - (3)]),(yyvsp[(2) - (3)])); IGN((yyvsp[(2) - (3)])); (yyval)=(yyvsp[(2) - (3)]); }
+ break;
+
+ case 115:
+/* Line 1792 of yacc.c */
+#line 540 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 116:
+/* Line 1792 of yacc.c */
+#line 541 "pascal.y"
+ {LNK((yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]));(yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 117:
+/* Line 1792 of yacc.c */
+#line 544 "pascal.y"
+ {NEXT_PARAM; CHGTAG((yyvsp[(1) - (1)]),PDEFPARAMID); (yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 118:
+/* Line 1792 of yacc.c */
+#line 545 "pascal.y"
+ {REF_PARAM; NEXT_PARAM; IGN((yyvsp[(1) - (2)]));
+ CHGTAG((yyvsp[(2) - (2)]),PDEFREFID);CHGID((yyvsp[(2) - (2)]),CREFID); (yyval)=(yyvsp[(2) - (2)]); }
+ break;
+
+ case 119:
+/* Line 1792 of yacc.c */
+#line 550 "pascal.y"
+ {CHGTAG((yyvsp[(1) - (4)]),PCALLID); (yyval)=(yyvsp[(1) - (4)]);
+ UP((yyvsp[(2) - (4)]),(yyvsp[(1) - (4)])); pstring_args((yyvsp[(1) - (4)]),(yyvsp[(3) - (4)])); }
+ break;
+
+ case 120:
+/* Line 1792 of yacc.c */
+#line 553 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (4)]); UP((yyvsp[(2) - (4)]),(yyvsp[(1) - (4)])); pstring_args((yyvsp[(1) - (4)]),(yyvsp[(3) - (4)])); }
+ break;
+
+ case 121:
+/* Line 1792 of yacc.c */
+#line 554 "pascal.y"
+ {CHGTAG((yyvsp[(1) - (1)]),PCALLID); (yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 122:
+/* Line 1792 of yacc.c */
+#line 555 "pascal.y"
+ { (yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 123:
+/* Line 1792 of yacc.c */
+#line 559 "pascal.y"
+ {CHGTAG((yyvsp[(1) - (4)]),PCALLID); (yyval)=(yyvsp[(4) - (4)]); UP((yyvsp[(2) - (4)]),(yyvsp[(1) - (4)])); }
+ break;
+
+ case 124:
+/* Line 1792 of yacc.c */
+#line 560 "pascal.y"
+ { (yyval)=(yyvsp[(4) - (4)]); UP((yyvsp[(2) - (4)]),(yyvsp[(1) - (4)])); }
+ break;
+
+ case 125:
+/* Line 1792 of yacc.c */
+#line 561 "pascal.y"
+ {CHGTAG((yyvsp[(1) - (1)]),PCALLID);(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 126:
+/* Line 1792 of yacc.c */
+#line 562 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 127:
+/* Line 1792 of yacc.c */
+#line 566 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 128:
+/* Line 1792 of yacc.c */
+#line 568 "pascal.y"
+ {if ((yyvsp[(3) - (3)])==NULL) (yyval)=(yyvsp[(1) - (3)]); else if ((yyvsp[(1) - (3)])==NULL) (yyval)=(yyvsp[(3) - (3)]);
+ else (yyval)=join(PCOMMA,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),0); }
+ break;
+
+ case 129:
+/* Line 1792 of yacc.c */
+#line 572 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 130:
+/* Line 1792 of yacc.c */
+#line 573 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 131:
+/* Line 1792 of yacc.c */
+#line 574 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 132:
+/* Line 1792 of yacc.c */
+#line 575 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 133:
+/* Line 1792 of yacc.c */
+#line 579 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (3)]); }
+ break;
+
+ case 134:
+/* Line 1792 of yacc.c */
+#line 582 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 135:
+/* Line 1792 of yacc.c */
+#line 584 "pascal.y"
+ {(yyval)=join(PSEMICOLON,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),0); }
+ break;
+
+ case 136:
+/* Line 1792 of yacc.c */
+#line 588 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 137:
+/* Line 1792 of yacc.c */
+#line 589 "pascal.y"
+ { clabel((yyvsp[(1) - (3)]),0);(yyval)=join(PCOLON,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),0); }
+ break;
+
+ case 138:
+/* Line 1792 of yacc.c */
+#line 591 "pascal.y"
+ { IGN((yyvsp[(1) - (3)])); IGN((yyvsp[(2) - (3)])); (yyval)=join(PCOLON,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),0); }
+ break;
+
+ case 139:
+/* Line 1792 of yacc.c */
+#line 594 "pascal.y"
+ { clabel((yyvsp[(2) - (2)]),1); (yyval)=join(PGOTO,(yyvsp[(2) - (2)]),NULL,0); }
+ break;
+
+ case 140:
+/* Line 1792 of yacc.c */
+#line 595 "pascal.y"
+ { IGN((yyvsp[(1) - (2)])); (yyval)=(yyvsp[(2) - (2)]); }
+ break;
+
+ case 141:
+/* Line 1792 of yacc.c */
+#line 596 "pascal.y"
+ { (yyval)=(yyvsp[(2) - (2)]); }
+ break;
+
+ case 142:
+/* Line 1792 of yacc.c */
+#line 597 "pascal.y"
+ { if (function) clabel((yyvsp[(1) - (1)]),1);
+ else { CHGTAG((yyvsp[(1) - (1)]),CPROCRETURN);(yyvsp[(1) - (1)])->sym_ptr->value++; }
+ (yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 146:
+/* Line 1792 of yacc.c */
+#line 606 "pascal.y"
+ {seq((yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); (yyval)=(yyvsp[(1) - (3)]); }
+ break;
+
+ case 154:
+/* Line 1792 of yacc.c */
+#line 615 "pascal.y"
+ {(yyval)=join(CEMPTY,NULL,NULL,0); }
+ break;
+
+ case 155:
+/* Line 1792 of yacc.c */
+#line 617 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (3)]); }
+ break;
+
+ case 156:
+/* Line 1792 of yacc.c */
+#line 618 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (3)]); pstring_assign((yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); }
+ break;
+
+ case 157:
+/* Line 1792 of yacc.c */
+#line 620 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (5)]); pstring_assign((yyvsp[(1) - (5)]),(yyvsp[(4) - (5)])); }
+ break;
+
+ case 158:
+/* Line 1792 of yacc.c */
+#line 623 "pascal.y"
+ { (yyval)=(yyvsp[(1) - (3)]); }
+ break;
+
+ case 159:
+/* Line 1792 of yacc.c */
+#line 624 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (3)]); }
+ break;
+
+ case 160:
+/* Line 1792 of yacc.c */
+#line 626 "pascal.y"
+ {(yyval)=join(CRETURN,NULL,NULL,0); }
+ break;
+
+ case 161:
+/* Line 1792 of yacc.c */
+#line 627 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 162:
+/* Line 1792 of yacc.c */
+#line 628 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 166:
+/* Line 1792 of yacc.c */
+#line 635 "pascal.y"
+ {(yyval)=join(PBEGIN,(yyvsp[(2) - (3)]),NULL,0); wsemicolon((yyvsp[(2) - (3)]),(yyvsp[(3) - (3)])); }
+ break;
+
+ case 169:
+/* Line 1792 of yacc.c */
+#line 639 "pascal.y"
+ {(yyval)=join(PIF,(yyvsp[(4) - (4)]),NULL,0); }
+ break;
+
+ case 170:
+/* Line 1792 of yacc.c */
+#line 641 "pascal.y"
+ {wsemicolon((yyvsp[(4) - (6)]),(yyvsp[(5) - (6)])); (yyval)=join(PELSE,(yyvsp[(4) - (6)]),(yyvsp[(6) - (6)]),0); }
+ break;
+
+ case 171:
+/* Line 1792 of yacc.c */
+#line 644 "pascal.y"
+ {LNK((yyvsp[(1) - (5)]),(yyvsp[(3) - (5)]));
+ wsemicolon((yyvsp[(4) - (5)]),(yyvsp[(5) - (5)]));(yyval)=join(PCASE,(yyvsp[(4) - (5)]),NULL,0); }
+ break;
+
+ case 172:
+/* Line 1792 of yacc.c */
+#line 647 "pascal.y"
+ {LNK((yyvsp[(1) - (6)]),(yyvsp[(3) - (6)]));(yyval)=join(PCASE,(yyvsp[(4) - (6)]),NULL,0); }
+ break;
+
+ case 174:
+/* Line 1792 of yacc.c */
+#line 651 "pascal.y"
+ {(yyval)=join(CCASE,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),0);
+ wsemicolon((yyvsp[(1) - (3)]),(yyvsp[(2) - (3)])); CHGTAG((yyvsp[(2) - (3)]),CBREAK); UP((yyvsp[(2) - (3)]),(yyvsp[(1) - (3)])); }
+ break;
+
+ case 175:
+/* Line 1792 of yacc.c */
+#line 654 "pascal.y"
+ {(yyval)=join(CCASE,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),0); /* etex parses same module twice */ }
+ break;
+
+ case 176:
+/* Line 1792 of yacc.c */
+#line 657 "pascal.y"
+ { (yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 177:
+/* Line 1792 of yacc.c */
+#line 658 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (2)]); }
+ break;
+
+ case 179:
+/* Line 1792 of yacc.c */
+#line 663 "pascal.y"
+ {CHGTAG((yyvsp[(2) - (3)]),CCOLON); CHGTEXT((yyvsp[(2) - (3)]),": "); }
+ break;
+
+ case 181:
+/* Line 1792 of yacc.c */
+#line 667 "pascal.y"
+ { winsert_after((yyvsp[(1) - (1)])->previous,CCASE,"case "); }
+ break;
+
+ case 182:
+/* Line 1792 of yacc.c */
+#line 668 "pascal.y"
+ { winsert_after((yyvsp[(1) - (1)])->previous,CCASE,"case "); }
+ break;
+
+ case 183:
+/* Line 1792 of yacc.c */
+#line 670 "pascal.y"
+ {winsert_after((yyvsp[(1) - (3)])->previous,CCASE,"case "); }
+ break;
+
+ case 184:
+/* Line 1792 of yacc.c */
+#line 672 "pascal.y"
+ {winsert_after((yyvsp[(1) - (3)])->previous,CCASE,"case "); }
+ break;
+
+ case 185:
+/* Line 1792 of yacc.c */
+#line 674 "pascal.y"
+ {winsert_after((yyvsp[(1) - (3)])->previous,CCASE,"case "); }
+ break;
+
+ case 189:
+/* Line 1792 of yacc.c */
+#line 679 "pascal.y"
+ {winsert_after((yyvsp[(1) - (5)])->previous,CCASE,"case "); /* etex */ }
+ break;
+
+ case 193:
+/* Line 1792 of yacc.c */
+#line 685 "pascal.y"
+ {LNK((yyvsp[(1) - (4)]),(yyvsp[(3) - (4)])); (yyval)=join(PWHILE,(yyvsp[(4) - (4)]),NULL,0); }
+ break;
+
+ case 194:
+/* Line 1792 of yacc.c */
+#line 688 "pascal.y"
+ { wsemicolon((yyvsp[(2) - (4)]),(yyvsp[(3) - (4)])); (yyval)=join(PREPEAT,(yyvsp[(2) - (4)]),NULL,0); }
+ break;
+
+ case 195:
+/* Line 1792 of yacc.c */
+#line 691 "pascal.y"
+ { mark_for_variable((yyvsp[(2) - (8)]),(yyvsp[(1) - (8)])->lineno,0,VAR_LOOP);
+ DBG(dbgfor,"for variable %s, limit variable in line %d\n",
+ SYM((yyvsp[(2) - (8)]))->name,(yyvsp[(2) - (8)])->lineno);
+ (yyval)=join(PFOR,(yyvsp[(8) - (8)]),NULL,0);LNK((yyvsp[(1) - (8)]),(yyvsp[(5) - (8)]));LNK((yyvsp[(5) - (8)]),(yyvsp[(7) - (8)])); }
+ break;
+
+ case 196:
+/* Line 1792 of yacc.c */
+#line 696 "pascal.y"
+ { mark_for_variable((yyvsp[(2) - (8)]),(yyvsp[(1) - (8)])->lineno,(yyvsp[(6) - (8)])->value,TO_LOOP);
+ DBG(dbgfor,"for variable %s, limit up in line %d\n",
+ SYM((yyvsp[(2) - (8)]))->name,(yyvsp[(2) - (8)])->lineno);
+ (yyval)=join(PFOR,(yyvsp[(8) - (8)]),NULL,0);LNK((yyvsp[(1) - (8)]),(yyvsp[(5) - (8)]));LNK((yyvsp[(5) - (8)]),(yyvsp[(7) - (8)])); }
+ break;
+
+ case 197:
+/* Line 1792 of yacc.c */
+#line 701 "pascal.y"
+ { mark_for_variable((yyvsp[(2) - (8)]),(yyvsp[(1) - (8)])->lineno,(yyvsp[(6) - (8)])->value,DOWNTO_LOOP);
+ DBG(dbgfor,"for variable %s, limit down in line %d\n",
+ SYM((yyvsp[(2) - (8)]))->name,(yyvsp[(2) - (8)])->lineno);
+ (yyval)=join(PFOR,(yyvsp[(8) - (8)]),NULL,0);LNK((yyvsp[(1) - (8)]),(yyvsp[(5) - (8)]));LNK((yyvsp[(5) - (8)]),(yyvsp[(7) - (8)])); }
+ break;
+
+ case 207:
+/* Line 1792 of yacc.c */
+#line 716 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 208:
+/* Line 1792 of yacc.c */
+#line 717 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); CHGTAG((yyvsp[(1) - (1)]),PID); CHGID((yyvsp[(1) - (1)]),PID); }
+ break;
+
+ case 214:
+/* Line 1792 of yacc.c */
+#line 732 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 215:
+/* Line 1792 of yacc.c */
+#line 733 "pascal.y"
+ {(yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 216:
+/* Line 1792 of yacc.c */
+#line 734 "pascal.y"
+ {(yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 223:
+/* Line 1792 of yacc.c */
+#line 739 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 224:
+/* Line 1792 of yacc.c */
+#line 740 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (2)]); }
+ break;
+
+ case 225:
+/* Line 1792 of yacc.c */
+#line 741 "pascal.y"
+ {(yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 226:
+/* Line 1792 of yacc.c */
+#line 742 "pascal.y"
+ {(yyval)=(yyvsp[(4) - (4)]); }
+ break;
+
+ case 232:
+/* Line 1792 of yacc.c */
+#line 749 "pascal.y"
+ {(yyval)=(yyvsp[(1) - (1)]); }
+ break;
+
+ case 233:
+/* Line 1792 of yacc.c */
+#line 750 "pascal.y"
+ {(yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 235:
+/* Line 1792 of yacc.c */
+#line 754 "pascal.y"
+ { DBG(dbgslash,"Pascal / in line %d\n",(yyvsp[(1) - (1)])->lineno); }
+ break;
+
+ case 241:
+/* Line 1792 of yacc.c */
+#line 761 "pascal.y"
+ {(yyval)=(yyvsp[(3) - (3)]); }
+ break;
+
+ case 243:
+/* Line 1792 of yacc.c */
+#line 763 "pascal.y"
+ {(yyval)=(yyvsp[(2) - (2)]); }
+ break;
+
+ case 251:
+/* Line 1792 of yacc.c */
+#line 776 "pascal.y"
+ {(yyval)=(yyvsp[(3) - (3)]); /* used in line 2361 */}
+ break;
+
+
+/* Line 1792 of yacc.c */
+#line 3097 "pascal.tab.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+/* Line 2055 of yacc.c */
+#line 779 "pascal.y"
+
+
+const char *tagname(int tag)
+{ return yytname[YYTRANSLATE(tag)];
+}
diff --git a/web/web2w/pascal.tab.h b/web/web2w/pascal.tab.h
new file mode 100644
index 0000000000..547a1dd13d
--- /dev/null
+++ b/web/web2w/pascal.tab.h
@@ -0,0 +1,279 @@
+/*
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+*/
+/* A Bison parser, made by GNU Bison 2.7. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_PP_PASCAL_TAB_H_INCLUDED
+# define YY_PP_PASCAL_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef PPDEBUG
+# if defined YYDEBUG
+# if YYDEBUG
+# define PPDEBUG 1
+# else
+# define PPDEBUG 0
+# endif
+# else /* ! defined YYDEBUG */
+# define PPDEBUG 1
+# endif /* ! defined YYDEBUG */
+#endif /* ! defined PPDEBUG */
+#if PPDEBUG
+extern int ppdebug;
+#endif
+/* "%code requires" blocks. */
+/* Line 2058 of yacc.c */
+#line 32 "pascal.y"
+
+#define PPSTYPE token *
+#define YYSTYPE PPSTYPE
+
+ extern int ppparse(void);
+ extern int ppdebug;
+
+
+/* Line 2058 of yacc.c */
+#line 63 "pascal.tab.h"
+
+/* Tokens. */
+#ifndef PPTOKENTYPE
+# define PPTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum pptokentype {
+ PEOF = 0,
+ WEBEOF = 258,
+ HEAD = 259,
+ BAR = 260,
+ PLEFT = 261,
+ MLEFT = 262,
+ RIGHT = 263,
+ OPEN = 264,
+ CLOSE = 265,
+ TEXT = 266,
+ NL = 267,
+ HASH = 268,
+ NMACRO = 269,
+ OMACRO = 270,
+ PMACRO = 271,
+ PARAM = 272,
+ EQ = 273,
+ EQEQ = 274,
+ ATSTAR = 275,
+ ATSPACE = 276,
+ ATD = 277,
+ ATF = 278,
+ ATLESS = 279,
+ ATGREATER = 280,
+ ELIPSIS = 281,
+ ATP = 282,
+ OCTAL = 283,
+ HEX = 284,
+ ATAT = 285,
+ ATDOLLAR = 286,
+ ATLEFT = 287,
+ ATRIGHT = 288,
+ ATINDEX = 289,
+ ATINDEXTT = 290,
+ ATINDEX9 = 291,
+ ATT = 292,
+ ATEQ = 293,
+ ATAND = 294,
+ ATBACKSLASH = 295,
+ ATEX = 296,
+ ATQM = 297,
+ ATCOMMA = 298,
+ ATSLASH = 299,
+ ATBAR = 300,
+ ATHASH = 301,
+ ATPLUS = 302,
+ ATSEMICOLON = 303,
+ STRING = 304,
+ CHAR = 305,
+ INDENT = 306,
+ METACOMMENT = 307,
+ CSEMICOLON = 308,
+ ID = 309,
+ WDEBUG = 310,
+ WSTAT = 311,
+ WINIT = 312,
+ WTINI = 313,
+ WTATS = 314,
+ WGUBED = 315,
+ PRETURN = 316,
+ FIRST_PASCAL_TOKEN = 317,
+ PPLUS = 318,
+ PMINUS = 319,
+ PSTAR = 320,
+ PSLASH = 321,
+ PEQ = 322,
+ PNOTEQ = 323,
+ PLESS = 324,
+ PGREATER = 325,
+ PLESSEQ = 326,
+ PGREATEREQ = 327,
+ POPEN = 328,
+ PCLOSE = 329,
+ PSQOPEN = 330,
+ PSQCLOSE = 331,
+ PASSIGN = 332,
+ PDOT = 333,
+ PCOMMA = 334,
+ PSEMICOLON = 335,
+ PMOD = 336,
+ PDIV = 337,
+ PNIL = 338,
+ POR = 339,
+ PAND = 340,
+ PNOT = 341,
+ PIF = 342,
+ PTHEN = 343,
+ PELSE = 344,
+ PREPEAT = 345,
+ PUNTIL = 346,
+ PWHILE = 347,
+ PDO = 348,
+ PFOR = 349,
+ PTO = 350,
+ PDOWNTO = 351,
+ PBEGIN = 352,
+ PEND = 353,
+ PGOTO = 354,
+ PINTEGER = 355,
+ PREAL = 356,
+ POTHERS = 357,
+ PSTRING = 358,
+ PCHAR = 359,
+ PTYPECHAR = 360,
+ PTYPEBOOL = 361,
+ PTYPEINT = 362,
+ PTYPEREAL = 363,
+ PTYPEINDEX = 364,
+ PID = 365,
+ PDEFVARID = 366,
+ PDEFPARAMID = 367,
+ PDEFREFID = 368,
+ PCONSTID = 369,
+ PDEFCONSTID = 370,
+ PDEFTYPEID = 371,
+ PDEFTYPESUBID = 372,
+ PARRAYFILETYPEID = 373,
+ PARRAYFILEID = 374,
+ PFUNCID = 375,
+ PDEFFUNCID = 376,
+ PPROCID = 377,
+ PCALLID = 378,
+ PRETURNID = 379,
+ PEXIT = 380,
+ PFBEGIN = 381,
+ PFEND = 382,
+ PDOTDOT = 383,
+ PCOLON = 384,
+ PUP = 385,
+ PIN = 386,
+ PCASE = 387,
+ POF = 388,
+ PWITH = 389,
+ PCONST = 390,
+ PVAR = 391,
+ PTYPE = 392,
+ PARRAY = 393,
+ PRECORD = 394,
+ PSET = 395,
+ PFILE = 396,
+ PFUNCTION = 397,
+ PPROCEDURE = 398,
+ PLABEL = 399,
+ PPACKED = 400,
+ PPROGRAM = 401,
+ PFORWARD = 402,
+ CIGNORE = 403,
+ CLABEL = 404,
+ CLABELN = 405,
+ CINTDEF = 406,
+ CSTRDEF = 407,
+ CMAIN = 408,
+ CMAINEND = 409,
+ CUNION = 410,
+ CTSUBRANGE = 411,
+ CINT = 412,
+ CREFID = 413,
+ CRETURN = 414,
+ CPROCRETURN = 415,
+ CCASE = 416,
+ CCOLON = 417,
+ CBREAK = 418,
+ CEMPTY = 419
+ };
+#endif
+
+
+#if ! defined PPSTYPE && ! defined PPSTYPE_IS_DECLARED
+typedef int PPSTYPE;
+# define PPSTYPE_IS_TRIVIAL 1
+# define ppstype PPSTYPE /* obsolescent; will be withdrawn */
+# define PPSTYPE_IS_DECLARED 1
+#endif
+
+extern PPSTYPE pplval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int ppparse (void *YYPARSE_PARAM);
+#else
+int ppparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int ppparse (void);
+#else
+int ppparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_PP_PASCAL_TAB_H_INCLUDED */
diff --git a/web/web2w/pascal.y b/web/web2w/pascal.y
new file mode 100644
index 0000000000..4d6f367140
--- /dev/null
+++ b/web/web2w/pascal.y
@@ -0,0 +1,783 @@
+%{
+/*
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+*/
+
+#include <stdio.h>
+#include "web2w.h"
+
+/* the tag=token number of the left hand side symbol of a rule */
+#define LHSS (yyr1[yyn]+FIRST_PASCAL_TOKEN-3)
+
+ static int function=0;
+
+%}
+
+%code requires {
+#define PPSTYPE token *
+#define YYSTYPE PPSTYPE
+
+ extern int ppparse(void);
+ extern int ppdebug;
+ }
+
+%token-table
+%defines
+%error_verbose
+%debug
+%define api.prefix "pp"
+%expect 1
+
+%token PEOF 0 "end of file"
+%token WEBEOF "end of web"
+%token HEAD
+%token BAR
+%token PLEFT
+%token MLEFT
+%token RIGHT
+%token OPEN
+%token CLOSE
+%token TEXT
+%token NL
+%token HASH
+%token NMACRO
+%token OMACRO
+%token PMACRO
+%token PARAM
+%token EQ
+%token EQEQ
+%token ATSTAR
+%token ATSPACE
+%token ATD
+%token ATF
+%token ATLESS
+%token ATGREATER
+%token ELIPSIS
+%token ATP
+%token OCTAL
+%token HEX
+%token ATAT
+%token ATDOLLAR
+%token ATLEFT
+%token ATRIGHT
+%token ATINDEX
+%token ATINDEXTT
+%token ATINDEX9
+%token ATT
+%token ATEQ
+%token ATAND
+%token ATBACKSLASH
+%token ATEX
+%token ATQM
+%token ATCOMMA
+%token ATSLASH
+%token ATBAR
+%token ATHASH
+%token ATPLUS
+%token ATSEMICOLON
+%token STRING
+%token CHAR
+%token INDENT
+%token METACOMMENT
+%token CSEMICOLON
+%token ID
+
+%token WDEBUG
+%token WSTAT
+%token WINIT
+%token WTINI
+%token WTATS
+%token WGUBED
+
+%token PRETURN "return"
+
+%token FIRST_PASCAL_TOKEN
+
+%token PPLUS "+"
+%token PMINUS "-"
+%token PSTAR "*"
+%token PSLASH "/"
+%token PEQ "="
+%token PNOTEQ "<>"
+%token PLESS "<"
+%token PGREATER ">"
+%token PLESSEQ "<="
+%token PGREATEREQ ">="
+%token POPEN "("
+%token PCLOSE ")"
+%token PSQOPEN "["
+%token PSQCLOSE "]"
+%token PASSIGN ":="
+%token PDOT "."
+%token PCOMMA ","
+%token PSEMICOLON ";"
+%token PMOD "mod"
+%token PDIV "div"
+%token PNIL "nil"
+%token POR "or"
+%token PAND "and"
+%token PNOT "not"
+%token PIF "if"
+%token PTHEN "then"
+%token PELSE "else"
+%token PREPEAT "repeat"
+%token PUNTIL "until"
+%token PWHILE "while"
+%token PDO "do"
+%token PFOR "for"
+%token PTO "to"
+%token PDOWNTO "downto"
+%token PBEGIN "begin"
+%token PEND "end"
+%token PGOTO "goto"
+%token PINTEGER "0-9"
+%token PREAL "real"
+%token POTHERS "others"
+%token PSTRING "'...'"
+%token PCHAR "'.'"
+%token PTYPECHAR "char type"
+%token PTYPEBOOL "bool type"
+%token PTYPEINT "integer type"
+%token PTYPEREAL "real type"
+%token PTYPEINDEX "index type"
+
+%token PID "identifier"
+%token PDEFVARID "variable definition"
+%token PDEFPARAMID "parameter definition"
+%token PDEFREFID "reference parameter definition"
+%token PCONSTID "constant"
+%token PDEFCONSTID "constant definition"
+%token PDEFTYPEID "typename definition"
+%token PDEFTYPESUBID "subrange typename definition"
+%token PARRAYFILETYPEID "array of file type"
+%token PARRAYFILEID "array of file name"
+%token PFUNCID "functionname"
+%token PDEFFUNCID "functionname definition"
+%token PPROCID "procedurename"
+%token PCALLID "call"
+%token PRETURNID "return value"
+
+
+%token PEXIT "final_end"
+%token PFBEGIN "function begin"
+%token PFEND "function end"
+%token PDOTDOT ".."
+%token PCOLON ":"
+%token PUP "^"
+%token PIN "in"
+%token PCASE "case"
+%token POF "of"
+%token PWITH "with"
+%token PCONST "const"
+%token PVAR "var"
+%token PTYPE "type"
+%token PARRAY "array"
+%token PRECORD "record"
+%token PSET "set"
+%token PFILE "file"
+%token PFUNCTION "function"
+%token PPROCEDURE "procedure"
+%token PLABEL "label"
+%token PPACKED "packed"
+%token PPROGRAM "program"
+%token PFORWARD "forward"
+
+%token CIGNORE
+%token CLABEL
+%token CLABELN
+%token CINTDEF
+%token CSTRDEF
+%token CMAIN
+%token CMAINEND
+%token CUNION
+%token CTSUBRANGE
+%token CINT
+%token CREFID "reference variable"
+%token CRETURN "C function return"
+%token CPROCRETURN "C procedure return"
+%token CCASE "C case"
+%token CCOLON "C :"
+%token CBREAK "break"
+%token CEMPTY "empty statement"
+%%
+
+program: programheading globals
+ PBEGIN statements PEND PDOT
+ { CHGTAG($3,CMAIN); CHGTAG($5,CMAINEND); IGN($6);
+ wsemicolon($4,$5);
+ }
+ ;
+
+programheading: PPROGRAM PID PSEMICOLON {IGN($2); IGN($3); }
+ ;
+
+globals: labels constants types variables procedures ;
+
+
+labels:
+ | PLABEL labellist PSEMICOLON { IGN($3); }
+ ;
+
+labellist: labeldecl
+ | labellist PCOMMA labeldecl { IGN($2); }
+ ;
+
+labeldecl: NMACRO {IGN($1); SYM($1)->obsolete=1; }
+ | PINTEGER {IGN($1); }
+ | PEXIT {IGN($1); }
+ | labeldecl PPLUS PINTEGER {IGN($2); IGN($3); }
+ ;
+
+constants:
+ | PCONST constdefinitions
+ | PCONST constdefinitions conststringdefinition
+ ;
+
+constdefinitions: constdefinition
+ | constdefinitions constdefinition
+ ;
+
+constdefinition: PID PEQ PINTEGER PSEMICOLON { LNK($1,$2); LNK($2,$4);
+ SETVAL($1,getval($3)); CHGID($1,PCONSTID);
+ CHGTAG($1,CINTDEF); }
+ ;
+
+conststringdefinition: PID PEQ PSTRING PSEMICOLON
+ { seq($1,$4); CHGID($1,PCONSTID);
+ CHGTAG($1,CSTRDEF);CHGTAG($2,PASSIGN); }
+ ;
+
+
+types:
+ | PTYPE typedefinitions { IGN($1); }
+ ;
+
+typedefinitions: typedefinition
+ | typedefinitions typedefinition
+ ;
+
+typedefinition: PID PEQ subrange PSEMICOLON
+ { DBG(dbgparse,"New Subrange Type: %s\n",
+ SYM($1)->name);
+ LNK($1,$2); IGN($2);LNK($2,$4);
+ CHGTYPE($1,$3);
+ CHGTAG($1,PDEFTYPEID);
+ CHGTAG($2,CTSUBRANGE); UP($2,$3);
+ }
+ | PID PEQ type PSEMICOLON
+ { DBG(dbgparse,"New Type: %s\n",
+ SYM($1)->name);
+ LNK($1,$2); IGN($2); LNK($2,$4);
+ CHGTYPE($1,$3); LNK($3,$4);
+ CHGTAG($1,PDEFTYPEID);
+ }
+ ;
+
+
+subrange: iconst PDOTDOT iconst
+ {$$=join(PDOTDOT,$1,$3,$3->value-$1->value+1); }
+ | PTYPECHAR
+ {$$=join(PDOTDOT,join(PTYPECHAR,$1,$1,0),
+ join(PTYPECHAR,$1,$1,255),256); }
+ ;
+
+iconst: signed_iconst {$$=$1; }
+ | iconst PPLUS simple_iconst
+ {$$=join(PPLUS,$1,$3,$1->value+$3->value); }
+ | iconst PMINUS simple_iconst
+ {$$=join(PMINUS,$1,$3,$1->value-$3->value); }
+ ;
+
+signed_iconst: simple_iconst {$$=$1; }
+ | PPLUS simple_iconst {$$=join(PPLUS,NULL,$2,$2->value); }
+ | PMINUS simple_iconst
+ {$$=join(PMINUS,NULL,$2,-($2->value)); }
+ ;
+
+
+simple_iconst: PINTEGER {$$=join(PINTEGER,$1,NULL,getval($1)); }
+ | NMACRO {$$=join(NMACRO,$1,NULL,getval($1)); }
+ | PCONSTID {$$=join(PCONSTID,$1,NULL,getval($1)); }
+ ;
+
+file_type: packed PFILE POF typename {$$=$2; }
+ |packed PFILE POF subrange {$$=$2; }
+ ;
+
+packed: PPACKED | ;
+
+typename: PTYPEINT {$$=NULL; }
+ | PTYPEREAL {$$=NULL; }
+ | PTYPEBOOL {$$=NULL; }
+ | PID {$$=NULL; }
+ ;
+
+
+record_type: packed PRECORD fields PEND { LNK($2,$4); LNK($3,$4);
+ if ($3) CHGTAG($4,PSEMICOLON); else IGN($4); $$=NULL; }
+ | packed PRECORD variant_part PEND
+ { LNK($2,$4); LNK($3,$4); IGN($4); $$=NULL; }
+ | packed PRECORD fields PSEMICOLON variant_part PEND
+ { LNK($2,$6); LNK($3,$4); LNK($5,$6); IGN($6); $$=NULL; }
+ ;
+
+
+fields: recordsection {$$=$1; }
+ | fields PSEMICOLON recordsection { LNK($1,$2); $$=$3; }
+ ;
+
+/* in a recordsection the first PID links to the PCOLON,
+ the recordsection points to the PCOLON
+*/
+recordsection: {$$=NULL; }
+ | recids PCOLON type {LNK($1,$2); IGN($2); $$=$2; }
+ | recids PCOLON subrange
+ {LNK($1,$2); CHGTAG($2,CTSUBRANGE); UP($2,$3); $$=$2; }
+ ;
+
+/* recids point to the first PID which is changed to PDEFVARID */
+recids: PID {$$=$1; CHGTAG($1,PDEFVARID); }
+ | recids PCOMMA PID {$$=$1; }
+ ;
+
+variant_part: PCASE PID POF variants {IGN($1);IGN($2);
+ CHGTAG($3,CUNION); $$=$3; }
+ ;
+
+variants: variant
+ | variants variant
+ ;
+
+
+variant: PINTEGER PCOLON POPEN recordsection PCLOSE PSEMICOLON
+ { IGN($1); IGN($2); IGN($3);
+ LNK($4,$5);
+ IGN($5); }
+ | PINTEGER PCOLON POPEN recordsection PSEMICOLON
+ recordsection PCLOSE PSEMICOLON
+ { IGN($1); IGN($2); CHGTAG($3,PRECORD);
+ LNK($3,$8); LNK($4,$5); LNK($6,$7); CHGTAG($7,PSEMICOLON); }
+ ;
+
+
+type: typename
+ | file_type
+ | record_type
+ ;
+
+
+
+
+array_type: packed PARRAY PSQOPEN iconst PDOTDOT iconst PSQCLOSE
+ POF type {LNK($2,$3);
+ UP($2,join(PDOTDOT,$4,$6,$6->value-$4->value+1));
+ LNK($3,$5); LNK($5,$7); LNK($7,$8);$$=$8; }
+ | packed PARRAY PSQOPEN iconst PDOTDOT iconst PSQCLOSE
+ POF subrange {LNK($2,$3);
+ UP($2,join(PDOTDOT,$4,$6,$6->value-$4->value+1));
+ LNK($3,$5); LNK($5,$7); LNK($7,$8);
+ CHGTAG($8,CTSUBRANGE); UP($8,$9);$$=$8; }
+ | packed PARRAY PSQOPEN PID PSQCLOSE POF type {LNK($2,$3);
+ UP($2,$4);LNK($3,$4); LNK($4,$5); LNK($5,$6);$$=$6; }
+ | packed PARRAY PSQOPEN PID PSQCLOSE POF subrange
+ {LNK($2,$3); UP($2,$4); LNK($3,$4); LNK($4,$5);
+ LNK($5,$6); CHGTAG($6,CTSUBRANGE); UP($6,$7);$$=$6; }
+ | packed PARRAY PSQOPEN PTYPECHAR PSQCLOSE
+ POF type {LNK($2,$3); UP($2,join(PDOTDOT,
+ join(PTYPECHAR,$1,$1,0),join(PTYPECHAR,$1,$1,255),256));
+ $3->link=join(PTYPECHAR,$3,$5,256); $3->link->link=$5;
+ /* the PTYPECHAR comes from a macroexpansion, so we can not
+ link it directly */ LNK($5,$6); $$=$6; }
+ ;
+
+variables:
+ | PVAR vardeclarations { IGN($1); }
+ ;
+
+vardeclarations: vardeclaration
+ | vardeclarations vardeclaration
+ ;
+
+vardeclaration: varids PCOLON type PSEMICOLON { LNK($1,$2);
+ IGN($2); LNK($2,$4); }
+ | varids PCOLON array_type PSEMICOLON { LNK($1,$2);
+ IGN($2); LNK($3,$4); LNK($2,$4); }
+ | varids PCOLON subrange PSEMICOLON { LNK($1,$2);
+ CHGTAG($2,CTSUBRANGE); UP($2,$3); LNK($2,$4); }
+ ;
+
+
+varids: entire_var {CHGTAG($1,PDEFVARID); $$=$1; }
+ | varids PCOMMA entire_var {LNK($1,$3);$$=$3; }
+ ;
+
+
+procedures:
+ | procedures procedure
+ | procedures function
+ ;
+
+locals: PVAR localvardeclarations { CHGTAG($1,PBEGIN); }
+ | PLABEL locallabellist PSEMICOLON localvariables
+ { CHGTAG($1,PBEGIN); IGN($3); }
+ ;
+
+locallabellist: locallabeldecl
+ | locallabellist PCOMMA locallabeldecl {IGN($2); }
+ ;
+
+locallabeldecl: NMACRO {IGN($1); SYM($1)->obsolete=1; localize($1); }
+ | PINTEGER {IGN($1); }
+ | labeldecl PPLUS PINTEGER {IGN($2); IGN($3); }
+ ;
+
+
+localvariables:
+ | PVAR localvardeclarations { IGN($1); }
+ ;
+
+localvardeclarations: localvardeclaration
+ | localvardeclarations localvardeclaration
+ ;
+
+localvardeclaration: localvarids PCOLON type PSEMICOLON
+ { LNK($1,$2); IGN($2); LNK($2,$4); }
+ | localvarids PCOLON array_type PSEMICOLON
+ { LNK($1,$2); IGN($2); LNK($3,$4); LNK($2,$4); }
+ | localvarids PCOLON subrange PSEMICOLON
+ { LNK($1,$2); CHGTAG($2,CTSUBRANGE);
+ UP($2,$3); LNK($2,$4); }
+ ;
+localvarids: localentire_var {CHGTAG($1,PDEFVARID); $$=$1; }
+ | localvarids PCOMMA localentire_var {LNK($1,$3);$$=$3; }
+ ;
+
+localentire_var: PID {$$=$1; localize($1); }
+ | CREFID {$$=$1; CHGTAG($1,PID);
+ CHGID($1,PID); localize($1); }
+ ;
+
+
+
+
+procedure: pheading locals PBEGIN statements PEND PSEMICOLON
+ {IGN($3); IGN($6); wend($4,$5); wsemicolon($4,$5);
+ scope_close(); }
+ | pheading PBEGIN statements PEND PSEMICOLON
+ { IGN($5); wend($3,$4); wsemicolon($3,$4); scope_close(); }
+ | pheading PFORWARD PSEMICOLON { scope_close(); }
+ ;
+
+function: fheading PBEGIN {function=1; } statements PEND PSEMICOLON
+ {function=0; wreturn($4, 1,NULL); IGN($6);
+ wsemicolon($4,$5); scope_close(); }
+ | fheading locals PBEGIN {function=1; }
+ statements PEND PSEMICOLON
+ { int f_no=$1->sym_no;
+ function=0;
+ if (f_no==x_over_n || f_no==xn_over_d)
+ { DBG(dbgcweb,"Discovered function %s; in line %d\n",
+ SYM($1)->name,$1->lineno);
+ CHGTAG($3,PFBEGIN); $3->sym_no=f_no;
+ CHGTAG($6,PFEND); $6->sym_no=f_no;
+ }
+ else
+ { IGN($3);
+ wreturn($5,1,NULL);
+ }
+ wsemicolon($5,$6);
+ IGN($7);
+ scope_close();
+ }
+ ;
+
+pid: PID {scope_open(); $$=$1; START_PARAM; }
+ |PPROCID {scope_open(); $$=$1; START_PARAM; }
+ |PFUNCID {scope_open(); $$=$1; START_PARAM; }
+ ;
+
+pheading: PPROCEDURE pid PSEMICOLON
+ { LNK($1,$3); CHGID($2,PPROCID); CHGVALUE($2,1); IGN($3); }
+ | PPROCEDURE pid POPEN formals PCLOSE PSEMICOLON
+ { LNK($1,$3); CHGID($2,PPROCID); CHGVALUE($2,param_mask);
+ LNK($4,$5); IGN($6); }
+ ;
+
+fheading: PFUNCTION pid PCOLON typename PSEMICOLON
+ {$$=$2; LNK($1,$3); CHGID($2,PFUNCID);
+ CHGVALUE($2,1);IGN($3); LNK($3,$5); IGN($5); }
+ | PFUNCTION pid POPEN formals PCLOSE
+ PCOLON typename PSEMICOLON {$$=$2; LNK($1,$3);
+ CHGID($2,PFUNCID); CHGVALUE($2,param_mask);
+ LNK($4,$5); LNK($5,$6); IGN($6); LNK($6,$8); IGN($8); }
+ ;
+
+formals: formalparameters {$$=$1; }
+ | formals PSEMICOLON formalparameters
+ { LNK($1,$2); CHGTAG($2,PCOMMA); $$=$3; }
+ ;
+
+formalparameters: params PCOLON typename
+ { LNK($1,$2); IGN($2); $$=$2; }
+ ;
+
+params: param {$$=$1; }
+ | params PCOMMA param {LNK($1,$3);$$=$3; }
+ ;
+
+param: entire_var {NEXT_PARAM; CHGTAG($1,PDEFPARAMID); $$=$1; }
+ | PVAR entire_var {REF_PARAM; NEXT_PARAM; IGN($1);
+ CHGTAG($2,PDEFREFID);CHGID($2,CREFID); $$=$2; }
+ ;
+
+
+proc_stmt: PPROCID POPEN args PCLOSE {CHGTAG($1,PCALLID); $$=$1;
+ UP($2,$1); pstring_args($1,$3); }
+ | PCALLID POPEN args PCLOSE
+ {$$=$1; UP($2,$1); pstring_args($1,$3); }
+ | PPROCID {CHGTAG($1,PCALLID); $$=$1; }
+ | PCALLID { $$=$1; }
+ ;
+
+function_call: PFUNCID POPEN args PCLOSE
+ {CHGTAG($1,PCALLID); $$=$4; UP($2,$1); }
+ | PCALLID POPEN args PCLOSE { $$=$4; UP($2,$1); }
+ | PFUNCID {CHGTAG($1,PCALLID);$$=$1; }
+ | PCALLID {$$=$1; }
+ ;
+
+
+args: arg {$$=$1; }
+ | args PCOMMA arg
+ {if ($3==NULL) $$=$1; else if ($1==NULL) $$=$3;
+ else $$=join(PCOMMA,$1,$3,0); }
+ ;
+
+arg: expression {$$=$1; }
+ | write_arg {$$=$1; }
+ | STRING {$$=$1; }
+ | CHAR {$$=$1; }
+ ;
+
+
+write_arg: expression PCOLON expression {$$=$2; }
+ ;
+
+statements: statement {$$=$1; }
+ | statements PSEMICOLON statement
+ {$$=join(PSEMICOLON,$1,$3,0); }
+
+ ;
+
+statement: stmt {$$=$1; }
+ | label PCOLON stmt { clabel($1,0);$$=join(PCOLON,$1,$3,0); }
+ | PEXIT PCOLON stmt
+ { IGN($1); IGN($2); $$=join(PCOLON,$1,$3,0); }
+ ;
+
+goto_stmt: PGOTO label { clabel($2,1); $$=join(PGOTO,$2,NULL,0); }
+ | PGOTO PEXIT { IGN($1); $$=$2; }
+ | CIGNORE PEXIT { $$=$2; }
+ | PRETURN { if (function) clabel($1,1);
+ else { CHGTAG($1,CPROCRETURN);$1->sym_ptr->value++; }
+ $$=$1; }
+ ;
+
+
+label: PINTEGER
+ | NMACRO
+ | CLABEL
+ | NMACRO PPLUS PINTEGER {seq($1,$3); $$=$1; }
+ ;
+
+
+
+stmt: simple_stmt | structured_stmt ;
+
+simple_stmt: empty_stmt | assign_stmt | return_stmt | goto_stmt | proc_stmt ;
+
+empty_stmt: {$$=join(CEMPTY,NULL,NULL,0); } ;
+
+assign_stmt: variable PASSIGN expression {$$=$2; }
+ | variable PASSIGN STRING {$$=$2; pstring_assign($1,$3); }
+ | variable PASSIGN POPEN STRING PCLOSE
+ {$$=$2; pstring_assign($1,$4); }
+ ;
+
+return_stmt: PFUNCID PASSIGN expression { $$=$1; }
+ | CRETURN CIGNORE expression {$$=$1; }
+ | CRETURN CIGNORE expression CIGNORE CIGNORE
+ {$$=join(CRETURN,NULL,NULL,0); }
+ | CRETURN {$$=$1; }
+ | CPROCRETURN {$$=$1; }
+ ;
+
+
+structured_stmt: compound_stmt | conditional_stmt | repetitive_stmt ;
+
+compound_stmt: PBEGIN statements PEND
+ {$$=join(PBEGIN,$2,NULL,0); wsemicolon($2,$3); } ;
+
+conditional_stmt: if_stmt | case_stmt;
+
+if_stmt: PIF expression PTHEN statement {$$=join(PIF,$4,NULL,0); }
+ | PIF expression PTHEN statement PELSE statement
+ {wsemicolon($4,$5); $$=join(PELSE,$4,$6,0); }
+ ;
+
+case_stmt: PCASE expression POF case_list PEND {LNK($1,$3);
+ wsemicolon($4,$5);$$=join(PCASE,$4,NULL,0); }
+ | PCASE expression POF case_list PSEMICOLON PEND
+ {LNK($1,$3);$$=join(PCASE,$4,NULL,0); }
+ ;
+
+case_list: case_element
+ | case_list PSEMICOLON case_element {$$=join(CCASE,$1,$3,0);
+ wsemicolon($1,$2); CHGTAG($2,CBREAK); UP($2,$1); }
+ | case_list CBREAK case_element
+ {$$=join(CCASE,$1,$3,0); /* etex parses same module twice */ }
+ ;
+
+case_element: case_labels PCOLON statement { $$=$3; }
+ | POTHERS statement {$$=$2; }
+ ;
+
+case_labels: case_label
+ | case_labels PCOMMA case_label
+ {CHGTAG($2,CCOLON); CHGTEXT($2,": "); }
+ | case_labels CCOLON case_label
+ ;
+
+case_label: PINTEGER { winsert_after($1->previous,CCASE,"case "); }
+ | NMACRO { winsert_after($1->previous,CCASE,"case "); }
+ | PINTEGER PPLUS NMACRO
+ {winsert_after($1->previous,CCASE,"case "); }
+ | NMACRO PPLUS NMACRO
+ {winsert_after($1->previous,CCASE,"case "); }
+ | NMACRO PPLUS PINTEGER
+ {winsert_after($1->previous,CCASE,"case "); }
+ | CCASE NMACRO
+ | CCASE PINTEGER
+ | CCASE NMACRO PPLUS NMACRO
+ | NMACRO PMINUS NMACRO PPLUS NMACRO
+ {winsert_after($1->previous,CCASE,"case "); /* etex */ }
+ ;
+
+repetitive_stmt: while_stmt | repeat_stmt | for_stmt ;
+
+while_stmt: PWHILE expression PDO statement
+ {LNK($1,$3); $$=join(PWHILE,$4,NULL,0); } ;
+
+repeat_stmt: PREPEAT statements PUNTIL expression
+ { wsemicolon($2,$3); $$=join(PREPEAT,$2,NULL,0); } ;
+
+for_stmt: PFOR PID PASSIGN expression PTO varlimit PDO statement
+ { mark_for_variable($2,$1->lineno,0,VAR_LOOP);
+ DBG(dbgfor,"for variable %s, limit variable in line %d\n",
+ SYM($2)->name,$2->lineno);
+ $$=join(PFOR,$8,NULL,0);LNK($1,$5);LNK($5,$7); }
+ | PFOR PID PASSIGN expression PTO iconst PDO statement
+ { mark_for_variable($2,$1->lineno,$6->value,TO_LOOP);
+ DBG(dbgfor,"for variable %s, limit up in line %d\n",
+ SYM($2)->name,$2->lineno);
+ $$=join(PFOR,$8,NULL,0);LNK($1,$5);LNK($5,$7); }
+ | PFOR PID PASSIGN expression PDOWNTO iconst PDO statement
+ { mark_for_variable($2,$1->lineno,$6->value,DOWNTO_LOOP);
+ DBG(dbgfor,"for variable %s, limit down in line %d\n",
+ SYM($2)->name,$2->lineno);
+ $$=join(PFOR,$8,NULL,0);LNK($1,$5);LNK($5,$7); }
+ ;
+
+varlimit: variable | variable PMINUS expression | variable PPLUS expression| iconst PSTAR expression;
+
+variable: PID
+ | CREFID
+ | indexed_var
+ | field_var
+ | file_var;
+
+
+entire_var: PID {$$=$1; }
+ | CREFID {$$=$1; CHGTAG($1,PID); CHGID($1,PID); }
+ ;
+
+indexed_var: variable PSQOPEN expression PSQCLOSE
+ | variable PSQOPEN STRING PSQCLOSE
+ | PARRAYFILEID PSQOPEN expression PSQCLOSE
+ ;
+
+
+field_var: variable PDOT PID
+ ;
+
+file_var: variable PUP
+ ;
+
+expression: simple_expr {$$=$1; }
+ | simple_expr relop simple_expr {$$=$3; }
+ | simple_expr PEQ STRING {$$=$3; }
+ ;
+
+relop: PEQ | PNOTEQ | PLESS | PLESSEQ | PGREATER | PGREATEREQ;
+
+simple_expr: term {$$=$1; }
+ | sign term {$$=$2; }
+ | simple_expr addop term {$$=$3; }
+ | simple_expr addop sign term {$$=$4; }
+ ;
+
+sign: PPLUS | PMINUS ;
+
+addop: PPLUS | PMINUS | POR ;
+
+term: factor {$$=$1; }
+ | term mulop factor {$$=$3; }
+ ;
+
+mulop: PSTAR
+ | PSLASH { DBG(dbgslash,"Pascal / in line %d\n",$1->lineno); }
+ | PDIV
+ | PMOD
+ | PAND ;
+
+factor: variable
+ | unsigned_const
+ | POPEN expression PCLOSE {$$=$3; }
+ | function_call
+ | PNOT factor {$$=$2; }
+ ;
+
+
+unsigned_const: real
+ | PINTEGER
+ | NMACRO
+ | PSTRING
+ | PCHAR
+ | PCONSTID
+ ;
+
+real: PREAL
+ | PINTEGER PDOT PINTEGER {$$=$3; /* used in line 2361 */};
+
+
+%%
+
+const char *tagname(int tag)
+{ return yytname[YYTRANSLATE(tag)];
+}
diff --git a/web/web2w/triptest.patch b/web/web2w/triptest.patch
new file mode 100644
index 0000000000..3bd63a7c96
--- /dev/null
+++ b/web/web2w/triptest.patch
@@ -0,0 +1,56 @@
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+--- tex.w 2017-05-10 15:25:36.263009459 +0200
++++ triptex.w 2017-05-10 15:33:30.859016580 +0200
+@@ -399,19 +399,19 @@
+ @^system dependencies@>
+
+ @<Constants...@>=
+-enum {@+@!mem_max=30000@+}; /*greatest index in \TeX's internal |mem| array;
++enum {@+@!mem_max=3000@+}; /*greatest index in \TeX's internal |mem| array;
+ must be strictly less than |max_halfword|;
+ must be equal to |mem_top| in \.{INITEX}, otherwise | >= mem_top|*/
+-enum {@+@!mem_min=0@+}; /*smallest index in \TeX's internal |mem| array;
++enum {@+@!mem_min=1@+}; /*smallest index in \TeX's internal |mem| array;
+ must be |min_halfword| or more;
+ must be equal to |mem_bot| in \.{INITEX}, otherwise | <= mem_bot|*/
+ enum {@+@!buf_size=500@+}; /*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|*/
+-enum {@+@!error_line=72@+}; /*width of context lines on terminal error messages*/
+-enum {@+@!half_error_line=42@+}; /*width of first lines of contexts in terminal
++enum {@+@!error_line=64@+}; /*width of context lines on terminal error messages*/
++enum {@+@!half_error_line=32@+}; /*width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|*/
+-enum {@+@!max_print_line=79@+}; /*width of longest text lines output; should be at least 60*/
++enum {@+@!max_print_line=72@+}; /*width of longest text lines output; should be at least 60*/
+ enum {@+@!stack_size=200@+}; /*maximum number of simultaneous input sources*/
+ enum {@+@!max_in_open=6@+}; /*maximum number of input files and error insertions that
+ can be going on simultaneously*/
+@@ -447,9 +447,9 @@
+ \.{WEB} macros, instead of being put into \PASCAL's || list, in order to
+ emphasize this distinction.
+
+-@d mem_bot 0 /*smallest index in the |mem| array dumped by \.{INITEX};
++@d mem_bot 1 /*smallest index in the |mem| array dumped by \.{INITEX};
+ must not be less than |mem_min|*/
+-@d mem_top 30000 /*largest index in the |mem| array dumped by \.{INITEX};
++@d mem_top 3000 /*largest index in the |mem| array dumped by \.{INITEX};
+ must be substantially larger than |mem_bot|
+ and not greater than |mem_max|*/
+ @d font_base 0 /*smallest internal font number; must not be less
diff --git a/web/web2w/web.l b/web/web2w/web.l
new file mode 100644
index 0000000000..884eb1b5fe
--- /dev/null
+++ b/web/web2w/web.l
@@ -0,0 +1,261 @@
+%{
+/*
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+*/
+#include "web2w.h"
+#include "pascal.tab.h"
+%}
+
+%option prefix="ww"
+%option noyywrap yylineno nounput noinput batch
+%option debug
+
+%x PASCAL MIDDLE DEFINITION FORMAT NAME
+
+CONTROL [^@\n]*
+ID [a-zA-Z][a-zA-Z0-9_]*
+SP [[:blank:]]*
+STARSECTION @\*{SP}(\\\[[0-9a-z]+\])?
+SPACESECTION @[[:space:]]{SP}
+REAL [0-9]+(\.[0-9]+(E[+-]?[0-9]+)?|E[+-]?[0-9]+)
+DDD {SP}\.\.\.{SP}
+%%
+ /* WEB codes, see WEB User Manual page 7 ff*/
+<INITIAL>{
+{SPACESECTION} EOS;TOK("@ ",ATSPACE);BOS;
+{STARSECTION} EOS;TOK("@*",ATSTAR); BOS;
+@[dD] EOS;TOK("@d ",ATD);BEGIN(DEFINITION);
+@[fF] EOS;TOK("@f ",ATF);BEGIN(FORMAT);
+@[pP] EOS;TOK("@p",ATP);PROGRAM;PUSH;SEQ;BEGIN(PASCAL);
+@\<{SP} EOS;TOK("@<",ATLESS);PUSH;BOS;BEGIN(NAME);
+
+\{ ADD;PUSH_NULL;
+\} POP_LEFT;
+
+\| EOS;TOK("|",BAR);PUSH;BEGIN(PASCAL);
+
+
+@'[0-7]+ EOS;TOK(COPY,OCTAL);BOS;
+@\"[0-9a-fA-F]+ EOS;TOK(COPY,HEX);BOS;
+@\^{CONTROL}@\> EOS;TOK(COPY,ATINDEX); BOS;
+@\.{CONTROL}@\> EOS;TOK(COPY,ATINDEXTT); BOS;
+@\:{CONTROL}@\> EOS;TOK(COPY,ATINDEX9); BOS;
+@! EOS;TOK("@!",ATEX); BOS;
+@\? EOS;TOK("@?",ATQM); BOS;
+@@ EOS;TOK("@@",ATAT);BOS;
+
+
+\n ADD;
+([^\\%@|{}.\n])* ADD; /* we do not analyze TEX parts any further */
+\\[\\%@|{}] ADD;
+\\ ADD;
+\%.* ADD;
+. ADD;
+
+<<EOF>> EOS;TOK("",WEBEOF);return 0;
+}
+
+<MIDDLE>{
+{SPACESECTION} TOK("@ ",ATSPACE);POP;BOS;BEGIN(TEX);
+{STARSECTION} TOK("@*",ATSTAR); POP;BOS;BEGIN(TEX);
+@[dD] TOK("@d ",ATD);POP;BEGIN(DEFINITION);
+@[fF] TOK("@f ",ATF);POP;BEGIN(FORMAT);
+@[pP] TOK("@p",ATP);POP;PROGRAM;PUSH;SEQ;BEGIN(PASCAL);
+@\<{SP} TOK("@<",ATLESS);POP;PUSH;BOS;BEGIN(NAME);
+\{ TOK(" {",MLEFT);PUSH;BEGIN(TEX);BOS;
+}
+
+<DEFINITION>{
+{ID} SYMBOL;
+\(#\) TOK("(#)",PARAM);
+= TOK("=",EQEQ);PUSH;DEF_MACRO(NMACRO);BEGIN(MIDDLE);
+== TOK("==",EQEQ);PUSH;DEF_MACRO(OMACRO);BEGIN(MIDDLE);
+[[:space:]] ;
+}
+
+<FORMAT>{
+begin TOK("if",PIF);
+end TOK("if",PIF);
+{ID} SYMBOL;
+== TOK("==",EQEQ);PUSH;
+\{ TOK(" {",MLEFT);PUSH;BEGIN(TEX);BOS;
+\n TOK("\n",NL);BEGIN(MIDDLE);
+[[:space:]] ;
+}
+
+<NAME>{
+{SP}@\> EOS;AT_GREATER;BEGIN(PASCAL);
+{DDD}@\> EOS;TOK("...",ELIPSIS);AT_GREATER;BEGIN(PASCAL);
+{SP}@\>{SP}= EOS;AT_GREATER_EQ;BEGIN(PASCAL);
+{DDD}@\>{SP}= EOS;TOK("...",ELIPSIS);AT_GREATER_EQ;BEGIN(PASCAL);
+[[:space:]]+ add_string(" ");
+. ADD;
+}
+
+
+<PASCAL>{
+{SPACESECTION} TOK("@ ",ATSPACE);POP;BOS;BEGIN(TEX);
+{STARSECTION} TOK("@*",ATSTAR);POP;BOS;BEGIN(TEX);
+@\<{SP} TOK("@<",ATLESS);PUSH;BOS;BEGIN(NAME);
+\{ TOK(" {",PLEFT);PUSH;BEGIN(TEX);BOS;
+}
+
+<MIDDLE,PASCAL>{
+<<EOF>> TOK("",WEBEOF);POP;return 0;
+
+@'[0-7]+ TOK(COPY,OCTAL);
+@\"[0-9a-fA-F]+ TOK(COPY,HEX);
+@! TOK("@!",ATEX);
+@\? TOK("@?",ATQM);
+\| TOK("|",BAR);POP;BEGIN(TEX);BOS;
+@t{CONTROL}@\> TOK(COPY,ATT);
+@={CONTROL}@\> TOK(COPY,ATEQ);
+
+
+\} ERROR("Unexpected }");
+\( TOK("(",POPEN);PUSH;
+\) TOK(")",PCLOSE);POP;
+# TOK("#",HASH);/* used in macros */
+
+
+
+ /* non Pascal tokens */
+\n TOK("\n",NL);
+@\^{CONTROL}@\> TOK(COPY,ATINDEX);
+@\.{CONTROL}@\> TOK(COPY,ATINDEXTT);
+@\:{CONTROL}@\> TOK(COPY,ATINDEX9);
+@\$ TOK("@$",ATDOLLAR);
+@\{ TOK("@{",ATLEFT);
+@\} TOK("@}",ATRIGHT);
+@\{[^\n]*@\} TOK(COPY,METACOMMENT);
+@\& TOK("@&",ATAND);
+@\\ TOK("@\\",ATBACKSLASH);
+@, TOK("@,",ATCOMMA);
+@\/ TOK("@/",ATSLASH);
+@\| TOK("@|",ATBAR);
+@\# TOK("@#",ATHASH);
+@\+ TOK("@+",ATPLUS);
+@\; TOK("@;",ATSEMICOLON);
+
+ /* Pascal tokens */
+= TOK("=",PEQ);
+\+ TOK("+",PPLUS);
+\- TOK("-",PMINUS);
+\* TOK("*",PSTAR);
+\/ TOK("/",PSLASH);
+\<\> TOK(" <> ",PNOTEQ);
+\< TOK(" < ",PLESS);
+\> TOK(" > ",PGREATER);
+\<= TOK(" <= ",PLESSEQ);
+\>= TOK(" >= ",PGREATEREQ);
+\[ TOK("[",PSQOPEN);
+\] TOK("]",PSQCLOSE);
+:= TOK(":=",PASSIGN);
+\. TOK(".",PDOT);
+\.\. TOK("..",PDOTDOT);
+, TOK(",",PCOMMA);
+; TOK(";",PSEMICOLON);
+: TOK(": ",PCOLON);
+\^ TOK("^",PUP);
+
+ /* special coding trick in line 676 of tex.web */
+t@&y@&p@&e TOK("type",PTYPE);
+
+ /* pascal keywords */
+"mod" TOK("mod",PMOD);
+"div" TOK("div",PDIV);
+"nil" TOK("nil",PNIL);
+"in" TOK("in",PIN);
+"or" TOK("or",POR);
+"and" TOK("and",PAND);
+"not" TOK("not",PNOT);
+"if" TOK("if",PIF);
+"then" TOK("then",PTHEN);
+"else" TOK("else",PELSE);
+"case" TOK("case",PCASE);
+"of" TOK("of",POF);
+"others" TOK("others",POTHERS);
+"forward" TOK("forward",PFORWARD);
+"repeat" TOK("repeat",PREPEAT);
+"until" TOK("until",PUNTIL);
+"while" TOK("while",PWHILE);
+"do" TOK("do",PDO);
+"for" TOK("for",PFOR);
+"to" TOK("to",PTO);
+"downto" TOK("downto",PDOWNTO);
+"begin" TOK("begin",PBEGIN);
+"end" TOK("end",PEND);
+"with" TOK("with",PWITH);
+"goto" TOK("goto",PGOTO);
+"const" TOK("const",PCONST);
+"var" TOK("var",PVAR);
+"array" TOK("array",PARRAY);
+"record" TOK("record",PRECORD);
+"set" TOK("set",PSET);
+"file" TOK("file",PFILE);
+"function" TOK("function",PFUNCTION);
+"procedure" TOK("procedure",PPROCEDURE);
+"label" TOK("label",PLABEL);
+"packed" TOK("packed",PPACKED);
+"program" TOK("program",PPROGRAM);
+"char" TOK("char",PTYPECHAR);
+"integer" TOK("integer",PTYPEINT);
+"real" TOK("real",PTYPEREAL);
+"boolean" TOK("boolean",PTYPEBOOL);
+
+"endcases" TOK("endcases",PEND);
+"othercases" TOK("othercases",POTHERS);
+"mtype" TOK("type",PTYPE);
+"final_end" TOK("final_end",PEXIT);
+
+"return" TOK_RETURN;
+
+"debug" TOK("debug",WDEBUG);
+"gubed" TOK("debug",WGUBED);
+"stat" TOK("stat",WSTAT);
+"tats" TOK("tats",WTATS);
+"init" TOK("init",WINIT);
+"tini" TOK("tini",WTINI);
+
+{ID} SYMBOL;
+\"([^"\n]|\"\")\" TOK(COPY,CHAR); /* single character string */
+\"([^"\n]|\"\")*\" WWSTRING; /* multiple character string */
+\'([^'\n]|\'\'|@@)\' TOK(COPY,PCHAR);
+\'([^'\n]|\'\')*\' TOK(COPY,PSTRING);
+[0-9]+ TOK(COPY,PINTEGER);
+{REAL} TOK(COPY,PREAL);
+
+^[[:space:]]+ TOK(COPY,INDENT);
+[[:space:]] ; /* in Pascal mode we ignore spaces */
+
+
+}
+
+
+
+
+
+ /* anything that gets to this line
+ is an illegal character */
+<*>. { ERROR("Illegal %c (0x%02x) in line %d mode %d",
+ yytext[0],yytext[0],yylineno, YY_START);}
+
+
+%%
+
diff --git a/web/web2w/web.lex.c b/web/web2w/web.lex.c
new file mode 100644
index 0000000000..0c13b519b9
--- /dev/null
+++ b/web/web2w/web.lex.c
@@ -0,0 +1,3290 @@
+/*
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+*/
+#line 2 "web.lex.c"
+
+#line 4 "web.lex.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+/* %not-for-header */
+
+/* %if-c-only */
+/* %if-not-reentrant */
+#define yy_create_buffer ww_create_buffer
+#define yy_delete_buffer ww_delete_buffer
+#define yy_flex_debug ww_flex_debug
+#define yy_init_buffer ww_init_buffer
+#define yy_flush_buffer ww_flush_buffer
+#define yy_load_buffer_state ww_load_buffer_state
+#define yy_switch_to_buffer ww_switch_to_buffer
+#define yyin wwin
+#define yyleng wwleng
+#define yylex wwlex
+#define yylineno wwlineno
+#define yyout wwout
+#define yyrestart wwrestart
+#define yytext wwtext
+#define yywrap wwwrap
+#define yyalloc wwalloc
+#define yyrealloc wwrealloc
+#define yyfree wwfree
+
+/* %endif */
+/* %endif */
+/* %ok-for-header */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 37
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* %if-c++-only */
+/* %endif */
+
+/* %if-c-only */
+
+/* %endif */
+
+/* %if-c-only */
+
+/* %endif */
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+/* %if-c-only */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+/* %endif */
+
+/* %if-tables-serialization */
+/* %endif */
+/* end standard C headers. */
+
+/* %if-c-or-c++ */
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* %endif */
+
+/* %if-c++-only */
+/* %endif */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* %not-for-header */
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+/* %ok-for-header */
+
+/* %not-for-header */
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+/* %ok-for-header */
+
+/* %if-reentrant */
+/* %endif */
+
+/* %if-not-reentrant */
+
+/* %endif */
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE wwrestart(wwin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+/* %if-not-reentrant */
+extern yy_size_t wwleng;
+/* %endif */
+
+/* %if-c-only */
+/* %if-not-reentrant */
+extern FILE *wwin, *wwout;
+/* %endif */
+/* %endif */
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE wwlex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-wwlineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ int yyl;\
+ for ( yyl = n; yyl < wwleng; ++yyl )\
+ if ( wwtext[yyl] == '\n' )\
+ --wwlineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up wwtext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up wwtext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+/* %if-c-only */
+ FILE *yy_input_file;
+/* %endif */
+
+/* %if-c++-only */
+/* %endif */
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via wwrestart()), so that the user can continue scanning by
+ * just pointing wwin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* %if-c-only Standard (non-C++) definition */
+/* %not-for-header */
+
+/* %if-not-reentrant */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+/* %endif */
+/* %ok-for-header */
+
+/* %endif */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* %if-c-only Standard (non-C++) definition */
+
+/* %if-not-reentrant */
+/* %not-for-header */
+
+/* yy_hold_char holds the character lost when wwtext is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t wwleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow wwwrap()'s to do buffer switches
+ * instead of setting up a fresh wwin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+/* %ok-for-header */
+
+/* %endif */
+
+void wwrestart (FILE *input_file );
+void ww_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE ww_create_buffer (FILE *file,int size );
+void ww_delete_buffer (YY_BUFFER_STATE b );
+void ww_flush_buffer (YY_BUFFER_STATE b );
+void wwpush_buffer_state (YY_BUFFER_STATE new_buffer );
+void wwpop_buffer_state (void );
+
+static void wwensure_buffer_stack (void );
+static void ww_load_buffer_state (void );
+static void ww_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER ww_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE ww_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE ww_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE ww_scan_bytes (yyconst char *bytes,yy_size_t len );
+
+/* %endif */
+
+void *wwalloc (yy_size_t );
+void *wwrealloc (void *,yy_size_t );
+void wwfree (void * );
+
+#define yy_new_buffer ww_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ wwensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ ww_create_buffer(wwin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ wwensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ ww_create_buffer(wwin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* %% [1.0] wwtext/wwin/wwout/yy_state_type/wwlineno etc. def's & init go here */
+/* Begin user sect3 */
+
+#define wwwrap() 1
+#define YY_SKIP_YYWRAP
+
+#define FLEX_DEBUG
+
+typedef unsigned char YY_CHAR;
+
+FILE *wwin = (FILE *) 0, *wwout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int wwlineno;
+
+int wwlineno = 1;
+
+extern char *wwtext;
+#define yytext_ptr wwtext
+
+/* %if-c-only Standard (non-C++) definition */
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* %endif */
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up wwtext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+/* %% [2.0] code to fiddle wwtext and wwleng for yymore() goes here \ */\
+ wwleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+/* %% [3.0] code to copy yytext_ptr to wwtext[] goes here, if %array \ */\
+ (yy_c_buf_p) = yy_cp;
+
+/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
+#define YY_NUM_RULES 161
+#define YY_END_OF_BUFFER 162
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[425] =
+ { 0,
+ 19, 19, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 162, 19, 18, 22, 23, 23, 21, 7,
+ 9, 8, 160, 159, 64, 160, 63, 160, 61, 62,
+ 83, 81, 95, 82, 93, 84, 156, 97, 96, 86,
+ 80, 87, 160, 151, 90, 91, 98, 151, 151, 151,
+ 151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
+ 151, 151, 151, 151, 151, 151, 52, 57, 60, 158,
+ 64, 160, 30, 35, 35, 160, 33, 31, 42, 41,
+ 160, 38, 38, 38, 40, 48, 47, 47, 47, 48,
+ 48, 19, 22, 1, 15, 0, 0, 2, 0, 0,
+
+ 6, 16, 17, 3, 4, 5, 0, 20, 0, 153,
+ 0, 155, 0, 94, 0, 156, 0, 92, 88, 85,
+ 89, 49, 55, 0, 77, 68, 72, 0, 50, 78,
+ 74, 0, 75, 0, 79, 51, 0, 56, 73, 0,
+ 0, 69, 76, 70, 151, 151, 151, 151, 151, 151,
+ 151, 151, 151, 151, 117, 151, 151, 151, 151, 151,
+ 151, 151, 107, 103, 151, 151, 151, 151, 151, 111,
+ 104, 151, 151, 151, 151, 151, 151, 0, 151, 151,
+ 151, 119, 151, 151, 151, 151, 158, 24, 25, 29,
+ 26, 27, 28, 0, 34, 31, 39, 38, 38, 38,
+
+ 47, 47, 0, 0, 0, 43, 1, 11, 10, 2,
+ 0, 0, 0, 0, 0, 6, 0, 0, 0, 152,
+ 0, 154, 157, 0, 157, 49, 54, 53, 50, 0,
+ 0, 0, 0, 0, 51, 0, 0, 0, 0, 0,
+ 0, 0, 0, 105, 151, 151, 151, 151, 151, 151,
+ 151, 101, 151, 151, 122, 151, 151, 118, 151, 151,
+ 151, 151, 151, 151, 100, 151, 102, 106, 151, 151,
+ 151, 151, 151, 151, 151, 129, 151, 0, 151, 151,
+ 151, 151, 126, 151, 151, 24, 25, 0, 29, 32,
+ 38, 37, 0, 0, 45, 0, 13, 14, 12, 153,
+
+ 155, 0, 0, 66, 67, 59, 65, 58, 71, 151,
+ 151, 151, 110, 136, 151, 151, 151, 109, 151, 130,
+ 151, 151, 151, 124, 151, 149, 151, 151, 151, 151,
+ 151, 151, 151, 138, 151, 151, 151, 147, 0, 148,
+ 108, 150, 151, 151, 123, 0, 38, 0, 0, 0,
+ 0, 157, 0, 127, 121, 151, 125, 145, 151, 151,
+ 151, 151, 151, 146, 151, 133, 142, 151, 151, 151,
+ 151, 151, 151, 151, 0, 115, 116, 0, 36, 44,
+ 2, 50, 151, 120, 151, 151, 151, 151, 151, 151,
+ 112, 134, 151, 151, 128, 114, 144, 0, 25, 0,
+
+ 46, 139, 151, 151, 113, 151, 137, 151, 151, 135,
+ 0, 140, 151, 131, 151, 151, 0, 143, 151, 132,
+ 0, 141, 99, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 4, 4, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 20, 20,
+ 20, 20, 20, 20, 20, 21, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 29, 29, 30, 31, 32,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 34,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 35, 36, 37, 38, 39, 1, 40, 41, 42, 43,
+
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 49, 56, 57, 58, 59, 60, 61, 49,
+ 62, 49, 63, 64, 65, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[66] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 1, 1, 3, 1,
+ 1, 1, 1, 1, 1, 1, 1, 3, 1, 4,
+ 4, 1, 1, 1, 1, 1, 1, 3, 5, 5,
+ 5, 5, 6, 6, 1, 3, 1, 1, 6, 4,
+ 4, 4, 4, 4, 4, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 3, 3, 3
+ } ;
+
+static yyconst flex_int16_t yy_base[450] =
+ { 0,
+ 0, 3, 68, 11, 106, 133, 196, 0, 261, 0,
+ 20, 23, 776, 0, 777, 0, 777, 325, 129, 777,
+ 777, 777, 777, 777, 777, 769, 777, 5, 777, 777,
+ 777, 777, 777, 777, 756, 777, 14, 748, 777, 4,
+ 777, 747, 379, 0, 777, 777, 777, 0, 0, 3,
+ 95, 7, 92, 88, 2, 731, 87, 96, 108, 6,
+ 726, 104, 127, 716, 728, 111, 777, 777, 777, 168,
+ 174, 443, 777, 777, 777, 760, 741, 0, 777, 777,
+ 740, 0, 720, 710, 777, 777, 330, 180, 183, 744,
+ 735, 0, 0, 758, 777, 0, 739, 6, 730, 729,
+
+ 754, 777, 777, 777, 777, 777, 727, 777, 748, 747,
+ 741, 740, 9, 777, 159, 320, 345, 777, 777, 777,
+ 777, 748, 777, 0, 777, 777, 777, 729, 152, 777,
+ 777, 720, 777, 719, 777, 744, 717, 777, 777, 716,
+ 715, 714, 777, 777, 0, 698, 684, 693, 684, 680,
+ 696, 682, 693, 673, 671, 674, 687, 8, 673, 675,
+ 669, 685, 0, 115, 684, 681, 661, 671, 663, 0,
+ 0, 673, 677, 664, 314, 659, 676, 705, 656, 669,
+ 659, 0, 653, 654, 661, 650, 187, 705, 335, 704,
+ 777, 777, 777, 692, 777, 0, 777, 0, 658, 660,
+
+ 405, 342, 684, 675, 682, 15, 697, 0, 678, 340,
+ 662, 668, 669, 666, 667, 690, 663, 664, 683, 682,
+ 676, 675, 357, 353, 371, 683, 0, 664, 377, 648,
+ 654, 655, 652, 653, 676, 649, 650, 647, 648, 645,
+ 646, 643, 347, 0, 630, 621, 617, 623, 610, 608,
+ 605, 0, 610, 618, 619, 616, 619, 597, 615, 602,
+ 611, 596, 609, 608, 0, 596, 0, 0, 606, 599,
+ 110, 597, 593, 602, 585, 0, 585, 578, 582, 583,
+ 587, 580, 0, 570, 567, 605, 394, 565, 591, 777,
+ 536, 0, 333, 397, 777, 0, 777, 777, 777, 571,
+
+ 559, 399, 0, 777, 777, 777, 777, 777, 535, 494,
+ 482, 484, 0, 0, 463, 469, 456, 0, 457, 0,
+ 445, 455, 436, 0, 450, 0, 446, 440, 446, 433,
+ 443, 441, 428, 0, 427, 442, 425, 0, 452, 0,
+ 0, 0, 428, 434, 0, 0, 423, 398, 448, 435,
+ 390, 404, 434, 0, 0, 430, 0, 0, 415, 411,
+ 427, 409, 416, 0, 419, 0, 0, 379, 419, 418,
+ 420, 416, 400, 403, 445, 0, 0, 417, 0, 403,
+ 777, 777, 400, 0, 408, 407, 407, 395, 392, 400,
+ 0, 0, 380, 386, 0, 0, 0, 380, 777, 416,
+
+ 777, 0, 377, 379, 0, 378, 0, 372, 371, 0,
+ 339, 0, 321, 0, 306, 151, 158, 0, 103, 0,
+ 5, 0, 777, 777, 498, 505, 512, 519, 526, 533,
+ 537, 541, 545, 549, 554, 561, 568, 575, 582, 586,
+ 591, 598, 605, 612, 619, 626, 630, 634, 638
+ } ;
+
+static yyconst flex_int16_t yy_def[450] =
+ { 0,
+ 425, 425, 424, 3, 3, 3, 424, 7, 424, 9,
+ 426, 426, 424, 427, 424, 428, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 429, 424, 430, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 431, 424, 424, 424, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 424, 424, 424, 424,
+ 424, 43, 424, 424, 424, 424, 424, 432, 424, 424,
+ 424, 433, 433, 433, 424, 424, 424, 424, 424, 424,
+ 424, 427, 428, 424, 424, 434, 424, 424, 435, 436,
+
+ 424, 424, 424, 424, 424, 424, 437, 424, 438, 424,
+ 439, 424, 439, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 440, 424, 424, 424, 424, 424, 424,
+ 424, 441, 424, 442, 424, 424, 443, 424, 424, 444,
+ 445, 446, 424, 424, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 424, 431, 431,
+ 431, 431, 431, 431, 431, 431, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 432, 424, 433, 433, 433,
+
+ 424, 424, 424, 424, 424, 424, 424, 434, 424, 424,
+ 424, 435, 424, 436, 424, 424, 437, 424, 438, 424,
+ 439, 424, 424, 424, 424, 424, 440, 424, 424, 424,
+ 441, 424, 442, 424, 424, 443, 424, 444, 424, 445,
+ 424, 446, 446, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 424, 431, 431,
+ 431, 431, 431, 431, 431, 424, 424, 424, 424, 424,
+ 433, 433, 424, 424, 424, 447, 424, 424, 424, 424,
+
+ 424, 424, 448, 424, 424, 424, 424, 424, 446, 431,
+ 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 431, 424, 431,
+ 431, 431, 431, 431, 431, 449, 433, 424, 424, 447,
+ 424, 424, 448, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 424, 431, 431, 449, 433, 424,
+ 424, 424, 431, 431, 431, 431, 431, 431, 431, 431,
+ 431, 431, 431, 431, 431, 431, 431, 424, 424, 424,
+
+ 424, 431, 431, 431, 431, 431, 431, 431, 431, 431,
+ 424, 431, 431, 431, 431, 431, 424, 431, 431, 431,
+ 424, 431, 424, 0, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424
+ } ;
+
+static yyconst flex_int16_t yy_nxt[843] =
+ { 0,
+ 424, 424, 15, 424, 424, 15, 424, 210, 16, 424,
+ 424, 16, 70, 71, 70, 112, 294, 17, 424, 222,
+ 17, 87, 88, 89, 87, 88, 89, 18, 119, 120,
+ 18, 115, 113, 116, 116, 19, 111, 90, 19, 295,
+ 90, 211, 150, 148, 117, 173, 163, 91, 423, 151,
+ 91, 424, 146, 149, 164, 147, 152, 156, 256, 157,
+ 257, 174, 20, 21, 22, 20, 21, 22, 23, 24,
+ 25, 24, 23, 26, 27, 23, 23, 23, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 37, 38,
+ 39, 40, 41, 42, 23, 43, 44, 44, 44, 44,
+
+ 44, 44, 45, 23, 46, 47, 23, 48, 49, 50,
+ 51, 52, 53, 54, 44, 55, 44, 44, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 44,
+ 67, 68, 69, 72, 70, 71, 70, 108, 153, 158,
+ 166, 161, 154, 168, 167, 159, 162, 176, 155, 169,
+ 160, 332, 170, 229, 178, 333, 108, 185, 186, 422,
+ 72, 177, 262, 171, 108, 172, 179, 421, 73, 187,
+ 187, 187, 263, 180, 181, 187, 187, 187, 223, 223,
+ 182, 202, 202, 202, 202, 202, 202, 230, 187, 187,
+ 187, 108, 108, 108, 420, 73, 23, 74, 75, 74,
+
+ 23, 23, 23, 23, 23, 23, 23, 76, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 77, 23, 23, 23, 78, 78, 78, 78, 78, 78,
+ 23, 23, 23, 23, 23, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 23, 23,
+ 23, 23, 79, 80, 79, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 81, 23, 23, 23, 82,
+ 82, 82, 82, 82, 82, 23, 23, 23, 23, 23,
+
+ 82, 83, 82, 82, 84, 82, 82, 82, 82, 82,
+ 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 82, 82, 85, 23, 23, 94, 94, 94, 95,
+ 96, 201, 202, 202, 348, 97, 287, 115, 98, 116,
+ 116, 210, 99, 202, 202, 202, 100, 203, 101, 419,
+ 117, 102, 103, 272, 104, 273, 105, 204, 106, 224,
+ 349, 224, 107, 418, 225, 225, 417, 104, 274, 105,
+ 288, 275, 225, 225, 243, 211, 223, 223, 229, 106,
+ 122, 122, 122, 123, 124, 125, 126, 302, 127, 128,
+ 225, 225, 129, 130, 131, 287, 132, 133, 294, 348,
+
+ 134, 135, 136, 137, 400, 138, 201, 202, 202, 352,
+ 352, 309, 230, 351, 139, 351, 140, 400, 352, 352,
+ 390, 295, 203, 352, 352, 349, 416, 401, 415, 288,
+ 414, 413, 204, 412, 411, 391, 141, 410, 409, 408,
+ 401, 142, 143, 144, 188, 188, 188, 407, 406, 405,
+ 404, 403, 402, 399, 398, 397, 189, 396, 395, 394,
+ 393, 392, 389, 388, 387, 386, 190, 385, 384, 383,
+ 382, 381, 191, 380, 192, 379, 193, 377, 376, 375,
+ 374, 373, 372, 371, 370, 191, 369, 192, 368, 367,
+ 366, 365, 364, 363, 362, 361, 360, 193, 14, 14,
+
+ 14, 14, 14, 14, 14, 86, 86, 86, 86, 86,
+ 86, 86, 92, 359, 358, 92, 92, 92, 92, 93,
+ 357, 93, 93, 93, 93, 93, 109, 356, 109, 109,
+ 109, 109, 109, 111, 355, 111, 111, 111, 111, 111,
+ 145, 145, 145, 145, 196, 196, 196, 196, 198, 198,
+ 198, 198, 208, 208, 212, 354, 212, 212, 212, 212,
+ 212, 214, 243, 214, 214, 214, 214, 214, 217, 221,
+ 217, 217, 217, 217, 217, 219, 219, 219, 219, 219,
+ 219, 219, 221, 347, 221, 221, 221, 221, 221, 227,
+ 227, 231, 289, 231, 231, 231, 231, 231, 233, 346,
+
+ 233, 233, 233, 233, 233, 236, 286, 236, 236, 236,
+ 236, 236, 238, 345, 238, 238, 238, 238, 238, 240,
+ 344, 240, 240, 240, 240, 240, 242, 343, 242, 242,
+ 242, 242, 242, 350, 342, 341, 350, 353, 340, 339,
+ 353, 378, 338, 337, 378, 336, 335, 334, 331, 330,
+ 329, 328, 327, 326, 325, 324, 323, 322, 321, 320,
+ 319, 318, 317, 316, 315, 314, 313, 312, 311, 310,
+ 243, 308, 241, 307, 239, 306, 237, 235, 305, 234,
+ 304, 232, 303, 228, 226, 221, 301, 219, 300, 299,
+ 218, 216, 298, 215, 297, 213, 296, 209, 207, 293,
+
+ 206, 205, 292, 291, 290, 289, 286, 285, 284, 283,
+ 282, 281, 280, 279, 278, 277, 276, 271, 270, 269,
+ 268, 267, 266, 265, 264, 261, 260, 259, 258, 255,
+ 254, 253, 252, 251, 250, 249, 248, 247, 246, 245,
+ 244, 243, 241, 239, 237, 235, 234, 232, 228, 226,
+ 111, 222, 109, 220, 218, 216, 215, 213, 209, 207,
+ 206, 205, 200, 199, 197, 195, 194, 184, 183, 175,
+ 165, 121, 118, 114, 110, 424, 13, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424
+ } ;
+
+static yyconst flex_int16_t yy_chk[843] =
+ { 0,
+ 0, 0, 1, 0, 0, 2, 0, 98, 1, 0,
+ 0, 2, 4, 4, 4, 28, 206, 1, 0, 113,
+ 2, 11, 11, 11, 12, 12, 12, 1, 40, 40,
+ 2, 37, 28, 37, 37, 1, 113, 11, 2, 206,
+ 12, 98, 50, 49, 37, 60, 55, 11, 421, 50,
+ 12, 0, 48, 49, 55, 48, 50, 52, 158, 52,
+ 158, 60, 1, 1, 1, 2, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 5, 6, 6, 6, 19, 51, 53,
+ 57, 54, 51, 58, 57, 53, 54, 62, 51, 58,
+ 53, 271, 59, 129, 63, 271, 19, 66, 66, 419,
+ 6, 62, 164, 59, 19, 59, 63, 417, 5, 70,
+ 70, 70, 164, 63, 63, 71, 71, 71, 115, 115,
+ 63, 88, 88, 88, 89, 89, 89, 129, 187, 187,
+ 187, 19, 19, 19, 416, 6, 7, 7, 7, 7,
+
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 18, 18, 18, 18,
+ 18, 87, 87, 87, 293, 18, 189, 116, 18, 116,
+ 116, 210, 18, 202, 202, 202, 18, 87, 18, 415,
+ 116, 18, 18, 175, 18, 175, 18, 87, 18, 117,
+ 293, 117, 18, 413, 117, 117, 411, 18, 175, 18,
+ 189, 175, 224, 224, 243, 210, 223, 223, 229, 18,
+ 43, 43, 43, 43, 43, 43, 43, 223, 43, 43,
+ 225, 225, 43, 43, 43, 287, 43, 43, 294, 348,
+
+ 43, 43, 43, 43, 380, 43, 201, 201, 201, 351,
+ 351, 243, 229, 302, 43, 302, 43, 400, 302, 302,
+ 368, 294, 201, 352, 352, 348, 409, 380, 408, 287,
+ 406, 404, 201, 403, 398, 368, 43, 394, 393, 390,
+ 400, 43, 43, 43, 72, 72, 72, 389, 388, 387,
+ 386, 385, 383, 378, 375, 374, 72, 373, 372, 371,
+ 370, 369, 365, 363, 362, 361, 72, 360, 359, 356,
+ 353, 350, 72, 349, 72, 347, 72, 344, 343, 339,
+ 337, 336, 335, 333, 332, 72, 331, 72, 330, 329,
+ 328, 327, 325, 323, 322, 321, 319, 72, 425, 425,
+
+ 425, 425, 425, 425, 425, 426, 426, 426, 426, 426,
+ 426, 426, 427, 317, 316, 427, 427, 427, 427, 428,
+ 315, 428, 428, 428, 428, 428, 429, 312, 429, 429,
+ 429, 429, 429, 430, 311, 430, 430, 430, 430, 430,
+ 431, 431, 431, 431, 432, 432, 432, 432, 433, 433,
+ 433, 433, 434, 434, 435, 310, 435, 435, 435, 435,
+ 435, 436, 309, 436, 436, 436, 436, 436, 437, 301,
+ 437, 437, 437, 437, 437, 438, 300, 438, 438, 438,
+ 438, 438, 439, 291, 439, 439, 439, 439, 439, 440,
+ 440, 441, 289, 441, 441, 441, 441, 441, 442, 288,
+
+ 442, 442, 442, 442, 442, 443, 286, 443, 443, 443,
+ 443, 443, 444, 285, 444, 444, 444, 444, 444, 445,
+ 284, 445, 445, 445, 445, 445, 446, 282, 446, 446,
+ 446, 446, 446, 447, 281, 280, 447, 448, 279, 278,
+ 448, 449, 277, 275, 449, 274, 273, 272, 270, 269,
+ 266, 264, 263, 262, 261, 260, 259, 258, 257, 256,
+ 255, 254, 253, 251, 250, 249, 248, 247, 246, 245,
+ 242, 241, 240, 239, 238, 237, 236, 235, 234, 233,
+ 232, 231, 230, 228, 226, 222, 221, 220, 219, 218,
+ 217, 216, 215, 214, 213, 212, 211, 209, 207, 205,
+
+ 204, 203, 200, 199, 194, 190, 188, 186, 185, 184,
+ 183, 181, 180, 179, 178, 177, 176, 174, 173, 172,
+ 169, 168, 167, 166, 165, 162, 161, 160, 159, 157,
+ 156, 155, 154, 153, 152, 151, 150, 149, 148, 147,
+ 146, 142, 141, 140, 137, 136, 134, 132, 128, 122,
+ 112, 111, 110, 109, 107, 101, 100, 99, 97, 94,
+ 91, 90, 84, 83, 81, 77, 76, 65, 64, 61,
+ 56, 42, 38, 35, 26, 13, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424,
+ 424, 424
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[162] =
+ { 0,
+1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+ 0, 0, };
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int ww_flex_debug;
+int ww_flex_debug = 1;
+
+static yyconst flex_int16_t yy_rule_linenum[161] =
+ { 0,
+ 41, 42, 43, 44, 45, 46, 48, 49, 51, 54,
+ 55, 56, 57, 58, 59, 60, 61, 64, 65, 66,
+ 67, 68, 69, 75, 76, 77, 78, 79, 80, 81,
+ 85, 86, 87, 88, 89, 93, 94, 95, 96, 97,
+ 98, 99, 103, 104, 105, 106, 107, 108, 113, 114,
+ 115, 116, 122, 123, 124, 125, 126, 127, 128, 131,
+ 132, 133, 134, 139, 140, 141, 142, 143, 144, 145,
+ 146, 147, 148, 149, 150, 151, 152, 153, 154, 157,
+ 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175, 178, 181,
+
+ 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
+ 202, 203, 204, 205, 206, 207, 208, 209, 210, 211,
+ 212, 213, 214, 215, 216, 217, 218, 219, 220, 222,
+ 223, 224, 225, 227, 229, 230, 231, 232, 233, 234,
+ 236, 237, 238, 239, 240, 241, 242, 244, 245, 256
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *wwtext;
+#line 1 "web.l"
+#line 2 "web.l"
+/*
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+*/
+#include "web2w.h"
+#include "pascal.tab.h"
+#define YY_NO_INPUT 1
+
+#line 958 "web.lex.c"
+
+#define INITIAL 0
+#define PASCAL 1
+#define MIDDLE 2
+#define DEFINITION 3
+#define FORMAT 4
+#define NAME 5
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+/* %if-c-only */
+#include <unistd.h>
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* %if-c-only Reentrant structure and macros (non-C++). */
+/* %if-reentrant */
+/* %if-c-only */
+
+static int yy_init_globals (void );
+
+/* %endif */
+/* %if-reentrant */
+/* %endif */
+/* %endif End reentrant structures and macros. */
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int wwlex_destroy (void );
+
+int wwget_debug (void );
+
+void wwset_debug (int debug_flag );
+
+YY_EXTRA_TYPE wwget_extra (void );
+
+void wwset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *wwget_in (void );
+
+void wwset_in (FILE * in_str );
+
+FILE *wwget_out (void );
+
+void wwset_out (FILE * out_str );
+
+yy_size_t wwget_leng (void );
+
+char *wwget_text (void );
+
+int wwget_lineno (void );
+
+void wwset_lineno (int line_number );
+
+/* %if-bison-bridge */
+/* %endif */
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int wwwrap (void );
+#else
+extern int wwwrap (void );
+#endif
+#endif
+
+/* %not-for-header */
+
+/* %ok-for-header */
+
+/* %endif */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+/* %if-c-only Standard (non-C++) definition */
+/* %not-for-header */
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+/* %ok-for-header */
+
+/* %endif */
+#endif
+
+/* %if-c-only */
+
+/* %endif */
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* %if-c-only Standard (non-C++) definition */
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( wwtext, wwleng, 1, wwout )) {} } while (0)
+/* %endif */
+/* %if-c++-only C++ definition */
+/* %endif */
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+/* %% [5.0] fread()/read() definition of YY_INPUT goes here unless we're doing C++ \ */\
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( wwin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( wwin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, wwin))==0 && ferror(wwin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(wwin); \
+ } \
+ }\
+\
+/* %if-c++-only C++ definition \ */\
+/* %endif */
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+/* %if-c-only */
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+#endif
+
+/* %if-tables-serialization structures and prototypes */
+/* %not-for-header */
+
+/* %ok-for-header */
+
+/* %not-for-header */
+
+/* %tables-yydmap generated elements */
+/* %endif */
+/* end tables serialization structures and prototypes */
+
+/* %ok-for-header */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+/* %if-c-only Standard (non-C++) definition */
+
+extern int wwlex (void);
+
+#define YY_DECL int wwlex (void)
+/* %endif */
+/* %if-c++-only C++ definition */
+/* %endif */
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after wwtext and wwleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+/* %% [6.0] YY_RULE_SETUP definition goes here */
+#define YY_RULE_SETUP \
+ if ( wwleng > 0 ) \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ (wwtext[wwleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+/* %not-for-header */
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+/* %% [7.0] user's declarations go here */
+#line 38 "web.l"
+
+ /* WEB codes, see WEB User Manual page 7 ff*/
+#line 1209 "web.lex.c"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! wwin )
+/* %if-c-only */
+ wwin = stdin;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+ if ( ! wwout )
+/* %if-c-only */
+ wwout = stdout;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ wwensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ ww_create_buffer(wwin,YY_BUF_SIZE );
+ }
+
+ ww_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+/* %% [8.0] yymore()-related code goes here */
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of wwtext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+/* %% [9.0] code to set up and find next match goes here */
+ yy_current_state = (yy_start);
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 425 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 424 );
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+
+yy_find_action:
+/* %% [10.0] code to find the action number goes here */
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+/* %% [11.0] code for wwlineno update goes here */
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ int yyl;
+ for ( yyl = 0; yyl < wwleng; ++yyl )
+ if ( wwtext[yyl] == '\n' )
+
+ wwlineno++;
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+/* %% [12.0] debug code goes here */
+ if ( ww_flex_debug )
+ {
+ if ( yy_act == 0 )
+ fprintf( stderr, "--scanner backing up\n" );
+ else if ( yy_act < 161 )
+ fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
+ (long)yy_rule_linenum[yy_act], wwtext );
+ else if ( yy_act == 161 )
+ fprintf( stderr, "--accepting default rule (\"%s\")\n",
+ wwtext );
+ else if ( yy_act == 162 )
+ fprintf( stderr, "--(end of buffer or a NUL)\n" );
+ else
+ fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
+ }
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+/* %% [13.0] actions go here */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+#line 41 "web.l"
+EOS;TOK("@ ",ATSPACE);BOS;
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 42 "web.l"
+EOS;TOK("@*",ATSTAR); BOS;
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 43 "web.l"
+EOS;TOK("@d ",ATD);BEGIN(DEFINITION);
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 44 "web.l"
+EOS;TOK("@f ",ATF);BEGIN(FORMAT);
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 45 "web.l"
+EOS;TOK("@p",ATP);PROGRAM;PUSH;SEQ;BEGIN(PASCAL);
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 46 "web.l"
+EOS;TOK("@<",ATLESS);PUSH;BOS;BEGIN(NAME);
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 48 "web.l"
+ADD;PUSH_NULL;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 49 "web.l"
+POP_LEFT;
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 51 "web.l"
+EOS;TOK("|",BAR);PUSH;BEGIN(PASCAL);
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 54 "web.l"
+EOS;TOK(COPY,OCTAL);BOS;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 55 "web.l"
+EOS;TOK(COPY,HEX);BOS;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 56 "web.l"
+EOS;TOK(COPY,ATINDEX); BOS;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 57 "web.l"
+EOS;TOK(COPY,ATINDEXTT); BOS;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 58 "web.l"
+EOS;TOK(COPY,ATINDEX9); BOS;
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 59 "web.l"
+EOS;TOK("@!",ATEX); BOS;
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 60 "web.l"
+EOS;TOK("@?",ATQM); BOS;
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 61 "web.l"
+EOS;TOK("@@",ATAT);BOS;
+ YY_BREAK
+case 18:
+/* rule 18 can match eol */
+YY_RULE_SETUP
+#line 64 "web.l"
+ADD;
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 65 "web.l"
+ADD; /* we do not analyze TEX parts any further */
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 66 "web.l"
+ADD;
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 67 "web.l"
+ADD;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 68 "web.l"
+ADD;
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 69 "web.l"
+ADD;
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 71 "web.l"
+EOS;TOK("",WEBEOF);return 0;
+ YY_BREAK
+
+
+case 24:
+/* rule 24 can match eol */
+YY_RULE_SETUP
+#line 75 "web.l"
+TOK("@ ",ATSPACE);POP;BOS;BEGIN(TEX);
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 76 "web.l"
+TOK("@*",ATSTAR); POP;BOS;BEGIN(TEX);
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 77 "web.l"
+TOK("@d ",ATD);POP;BEGIN(DEFINITION);
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 78 "web.l"
+TOK("@f ",ATF);POP;BEGIN(FORMAT);
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 79 "web.l"
+TOK("@p",ATP);POP;PROGRAM;PUSH;SEQ;BEGIN(PASCAL);
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 80 "web.l"
+TOK("@<",ATLESS);POP;PUSH;BOS;BEGIN(NAME);
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 81 "web.l"
+TOK(" {",MLEFT);PUSH;BEGIN(TEX);BOS;
+ YY_BREAK
+
+
+case 31:
+YY_RULE_SETUP
+#line 85 "web.l"
+SYMBOL;
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 86 "web.l"
+TOK("(#)",PARAM);
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 87 "web.l"
+TOK("=",EQEQ);PUSH;DEF_MACRO(NMACRO);BEGIN(MIDDLE);
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 88 "web.l"
+TOK("==",EQEQ);PUSH;DEF_MACRO(OMACRO);BEGIN(MIDDLE);
+ YY_BREAK
+case 35:
+/* rule 35 can match eol */
+YY_RULE_SETUP
+#line 89 "web.l"
+;
+ YY_BREAK
+
+
+case 36:
+YY_RULE_SETUP
+#line 93 "web.l"
+TOK("if",PIF);
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 94 "web.l"
+TOK("if",PIF);
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 95 "web.l"
+SYMBOL;
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 96 "web.l"
+TOK("==",EQEQ);PUSH;
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 97 "web.l"
+TOK(" {",MLEFT);PUSH;BEGIN(TEX);BOS;
+ YY_BREAK
+case 41:
+/* rule 41 can match eol */
+YY_RULE_SETUP
+#line 98 "web.l"
+TOK("\n",NL);BEGIN(MIDDLE);
+ YY_BREAK
+case 42:
+/* rule 42 can match eol */
+YY_RULE_SETUP
+#line 99 "web.l"
+;
+ YY_BREAK
+
+
+case 43:
+YY_RULE_SETUP
+#line 103 "web.l"
+EOS;AT_GREATER;BEGIN(PASCAL);
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 104 "web.l"
+EOS;TOK("...",ELIPSIS);AT_GREATER;BEGIN(PASCAL);
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 105 "web.l"
+EOS;AT_GREATER_EQ;BEGIN(PASCAL);
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 106 "web.l"
+EOS;TOK("...",ELIPSIS);AT_GREATER_EQ;BEGIN(PASCAL);
+ YY_BREAK
+case 47:
+/* rule 47 can match eol */
+YY_RULE_SETUP
+#line 107 "web.l"
+add_string(" ");
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 108 "web.l"
+ADD;
+ YY_BREAK
+
+
+case 49:
+/* rule 49 can match eol */
+YY_RULE_SETUP
+#line 113 "web.l"
+TOK("@ ",ATSPACE);POP;BOS;BEGIN(TEX);
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 114 "web.l"
+TOK("@*",ATSTAR);POP;BOS;BEGIN(TEX);
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 115 "web.l"
+TOK("@<",ATLESS);PUSH;BOS;BEGIN(NAME);
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 116 "web.l"
+TOK(" {",PLEFT);PUSH;BEGIN(TEX);BOS;
+ YY_BREAK
+
+
+case YY_STATE_EOF(MIDDLE):
+case YY_STATE_EOF(PASCAL):
+#line 120 "web.l"
+TOK("",WEBEOF);POP;return 0;
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 122 "web.l"
+TOK(COPY,OCTAL);
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 123 "web.l"
+TOK(COPY,HEX);
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 124 "web.l"
+TOK("@!",ATEX);
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 125 "web.l"
+TOK("@?",ATQM);
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 126 "web.l"
+TOK("|",BAR);POP;BEGIN(TEX);BOS;
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 127 "web.l"
+TOK(COPY,ATT);
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 128 "web.l"
+TOK(COPY,ATEQ);
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 131 "web.l"
+ERROR("Unexpected }");
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 132 "web.l"
+TOK("(",POPEN);PUSH;
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 133 "web.l"
+TOK(")",PCLOSE);POP;
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 134 "web.l"
+TOK("#",HASH);/* used in macros */
+ YY_BREAK
+/* non Pascal tokens */
+case 64:
+/* rule 64 can match eol */
+YY_RULE_SETUP
+#line 139 "web.l"
+TOK("\n",NL);
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 140 "web.l"
+TOK(COPY,ATINDEX);
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 141 "web.l"
+TOK(COPY,ATINDEXTT);
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 142 "web.l"
+TOK(COPY,ATINDEX9);
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 143 "web.l"
+TOK("@$",ATDOLLAR);
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 144 "web.l"
+TOK("@{",ATLEFT);
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 145 "web.l"
+TOK("@}",ATRIGHT);
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 146 "web.l"
+TOK(COPY,METACOMMENT);
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 147 "web.l"
+TOK("@&",ATAND);
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 148 "web.l"
+TOK("@\\",ATBACKSLASH);
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 149 "web.l"
+TOK("@,",ATCOMMA);
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 150 "web.l"
+TOK("@/",ATSLASH);
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 151 "web.l"
+TOK("@|",ATBAR);
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 152 "web.l"
+TOK("@#",ATHASH);
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 153 "web.l"
+TOK("@+",ATPLUS);
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 154 "web.l"
+TOK("@;",ATSEMICOLON);
+ YY_BREAK
+/* Pascal tokens */
+case 80:
+YY_RULE_SETUP
+#line 157 "web.l"
+TOK("=",PEQ);
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 158 "web.l"
+TOK("+",PPLUS);
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 159 "web.l"
+TOK("-",PMINUS);
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 160 "web.l"
+TOK("*",PSTAR);
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 161 "web.l"
+TOK("/",PSLASH);
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 162 "web.l"
+TOK(" <> ",PNOTEQ);
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 163 "web.l"
+TOK(" < ",PLESS);
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 164 "web.l"
+TOK(" > ",PGREATER);
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 165 "web.l"
+TOK(" <= ",PLESSEQ);
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 166 "web.l"
+TOK(" >= ",PGREATEREQ);
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 167 "web.l"
+TOK("[",PSQOPEN);
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 168 "web.l"
+TOK("]",PSQCLOSE);
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 169 "web.l"
+TOK(":=",PASSIGN);
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 170 "web.l"
+TOK(".",PDOT);
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 171 "web.l"
+TOK("..",PDOTDOT);
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 172 "web.l"
+TOK(",",PCOMMA);
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 173 "web.l"
+TOK(";",PSEMICOLON);
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 174 "web.l"
+TOK(": ",PCOLON);
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 175 "web.l"
+TOK("^",PUP);
+ YY_BREAK
+/* special coding trick in line 676 of tex.web */
+case 99:
+YY_RULE_SETUP
+#line 178 "web.l"
+TOK("type",PTYPE);
+ YY_BREAK
+/* pascal keywords */
+case 100:
+YY_RULE_SETUP
+#line 181 "web.l"
+TOK("mod",PMOD);
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 182 "web.l"
+TOK("div",PDIV);
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+#line 183 "web.l"
+TOK("nil",PNIL);
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+#line 184 "web.l"
+TOK("in",PIN);
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 185 "web.l"
+TOK("or",POR);
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 186 "web.l"
+TOK("and",PAND);
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 187 "web.l"
+TOK("not",PNOT);
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 188 "web.l"
+TOK("if",PIF);
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+#line 189 "web.l"
+TOK("then",PTHEN);
+ YY_BREAK
+case 109:
+YY_RULE_SETUP
+#line 190 "web.l"
+TOK("else",PELSE);
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 191 "web.l"
+TOK("case",PCASE);
+ YY_BREAK
+case 111:
+YY_RULE_SETUP
+#line 192 "web.l"
+TOK("of",POF);
+ YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 193 "web.l"
+TOK("others",POTHERS);
+ YY_BREAK
+case 113:
+YY_RULE_SETUP
+#line 194 "web.l"
+TOK("forward",PFORWARD);
+ YY_BREAK
+case 114:
+YY_RULE_SETUP
+#line 195 "web.l"
+TOK("repeat",PREPEAT);
+ YY_BREAK
+case 115:
+YY_RULE_SETUP
+#line 196 "web.l"
+TOK("until",PUNTIL);
+ YY_BREAK
+case 116:
+YY_RULE_SETUP
+#line 197 "web.l"
+TOK("while",PWHILE);
+ YY_BREAK
+case 117:
+YY_RULE_SETUP
+#line 198 "web.l"
+TOK("do",PDO);
+ YY_BREAK
+case 118:
+YY_RULE_SETUP
+#line 199 "web.l"
+TOK("for",PFOR);
+ YY_BREAK
+case 119:
+YY_RULE_SETUP
+#line 200 "web.l"
+TOK("to",PTO);
+ YY_BREAK
+case 120:
+YY_RULE_SETUP
+#line 201 "web.l"
+TOK("downto",PDOWNTO);
+ YY_BREAK
+case 121:
+YY_RULE_SETUP
+#line 202 "web.l"
+TOK("begin",PBEGIN);
+ YY_BREAK
+case 122:
+YY_RULE_SETUP
+#line 203 "web.l"
+TOK("end",PEND);
+ YY_BREAK
+case 123:
+YY_RULE_SETUP
+#line 204 "web.l"
+TOK("with",PWITH);
+ YY_BREAK
+case 124:
+YY_RULE_SETUP
+#line 205 "web.l"
+TOK("goto",PGOTO);
+ YY_BREAK
+case 125:
+YY_RULE_SETUP
+#line 206 "web.l"
+TOK("const",PCONST);
+ YY_BREAK
+case 126:
+YY_RULE_SETUP
+#line 207 "web.l"
+TOK("var",PVAR);
+ YY_BREAK
+case 127:
+YY_RULE_SETUP
+#line 208 "web.l"
+TOK("array",PARRAY);
+ YY_BREAK
+case 128:
+YY_RULE_SETUP
+#line 209 "web.l"
+TOK("record",PRECORD);
+ YY_BREAK
+case 129:
+YY_RULE_SETUP
+#line 210 "web.l"
+TOK("set",PSET);
+ YY_BREAK
+case 130:
+YY_RULE_SETUP
+#line 211 "web.l"
+TOK("file",PFILE);
+ YY_BREAK
+case 131:
+YY_RULE_SETUP
+#line 212 "web.l"
+TOK("function",PFUNCTION);
+ YY_BREAK
+case 132:
+YY_RULE_SETUP
+#line 213 "web.l"
+TOK("procedure",PPROCEDURE);
+ YY_BREAK
+case 133:
+YY_RULE_SETUP
+#line 214 "web.l"
+TOK("label",PLABEL);
+ YY_BREAK
+case 134:
+YY_RULE_SETUP
+#line 215 "web.l"
+TOK("packed",PPACKED);
+ YY_BREAK
+case 135:
+YY_RULE_SETUP
+#line 216 "web.l"
+TOK("program",PPROGRAM);
+ YY_BREAK
+case 136:
+YY_RULE_SETUP
+#line 217 "web.l"
+TOK("char",PTYPECHAR);
+ YY_BREAK
+case 137:
+YY_RULE_SETUP
+#line 218 "web.l"
+TOK("integer",PTYPEINT);
+ YY_BREAK
+case 138:
+YY_RULE_SETUP
+#line 219 "web.l"
+TOK("real",PTYPEREAL);
+ YY_BREAK
+case 139:
+YY_RULE_SETUP
+#line 220 "web.l"
+TOK("boolean",PTYPEBOOL);
+ YY_BREAK
+case 140:
+YY_RULE_SETUP
+#line 222 "web.l"
+TOK("endcases",PEND);
+ YY_BREAK
+case 141:
+YY_RULE_SETUP
+#line 223 "web.l"
+TOK("othercases",POTHERS);
+ YY_BREAK
+case 142:
+YY_RULE_SETUP
+#line 224 "web.l"
+TOK("type",PTYPE);
+ YY_BREAK
+case 143:
+YY_RULE_SETUP
+#line 225 "web.l"
+TOK("final_end",PEXIT);
+ YY_BREAK
+case 144:
+YY_RULE_SETUP
+#line 227 "web.l"
+TOK_RETURN;
+ YY_BREAK
+case 145:
+YY_RULE_SETUP
+#line 229 "web.l"
+TOK("debug",WDEBUG);
+ YY_BREAK
+case 146:
+YY_RULE_SETUP
+#line 230 "web.l"
+TOK("debug",WGUBED);
+ YY_BREAK
+case 147:
+YY_RULE_SETUP
+#line 231 "web.l"
+TOK("stat",WSTAT);
+ YY_BREAK
+case 148:
+YY_RULE_SETUP
+#line 232 "web.l"
+TOK("tats",WTATS);
+ YY_BREAK
+case 149:
+YY_RULE_SETUP
+#line 233 "web.l"
+TOK("init",WINIT);
+ YY_BREAK
+case 150:
+YY_RULE_SETUP
+#line 234 "web.l"
+TOK("tini",WTINI);
+ YY_BREAK
+case 151:
+YY_RULE_SETUP
+#line 236 "web.l"
+SYMBOL;
+ YY_BREAK
+case 152:
+YY_RULE_SETUP
+#line 237 "web.l"
+TOK(COPY,CHAR); /* single character string */
+ YY_BREAK
+case 153:
+YY_RULE_SETUP
+#line 238 "web.l"
+WWSTRING; /* multiple character string */
+ YY_BREAK
+case 154:
+YY_RULE_SETUP
+#line 239 "web.l"
+TOK(COPY,PCHAR);
+ YY_BREAK
+case 155:
+YY_RULE_SETUP
+#line 240 "web.l"
+TOK(COPY,PSTRING);
+ YY_BREAK
+case 156:
+YY_RULE_SETUP
+#line 241 "web.l"
+TOK(COPY,PINTEGER);
+ YY_BREAK
+case 157:
+YY_RULE_SETUP
+#line 242 "web.l"
+TOK(COPY,PREAL);
+ YY_BREAK
+case 158:
+/* rule 158 can match eol */
+YY_RULE_SETUP
+#line 244 "web.l"
+TOK(COPY,INDENT);
+ YY_BREAK
+case 159:
+/* rule 159 can match eol */
+YY_RULE_SETUP
+#line 245 "web.l"
+; /* in Pascal mode we ignore spaces */
+ YY_BREAK
+
+/* anything that gets to this line
+ is an illegal character */
+case 160:
+YY_RULE_SETUP
+#line 256 "web.l"
+{ ERROR("Illegal %c (0x%02x) in line %d mode %d",
+ wwtext[0],wwtext[0],wwlineno, YY_START);}
+ YY_BREAK
+case 161:
+YY_RULE_SETUP
+#line 260 "web.l"
+ECHO;
+ YY_BREAK
+#line 2175 "web.lex.c"
+case YY_STATE_EOF(DEFINITION):
+case YY_STATE_EOF(FORMAT):
+case YY_STATE_EOF(NAME):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed wwin at a new source and called
+ * wwlex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = wwin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+/* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( wwwrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * wwtext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of wwlex */
+/* %ok-for-header */
+
+/* %if-c++-only */
+/* %not-for-header */
+
+/* %ok-for-header */
+
+/* %endif */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+/* %if-c-only */
+static int yy_get_next_buffer (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ wwrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ wwrestart(wwin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) wwrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+/* %if-c-only */
+/* %not-for-header */
+
+ static yy_state_type yy_get_previous_state (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+/* %% [15.0] code to get the start state into yy_current_state goes here */
+ yy_current_state = (yy_start);
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+/* %% [16.0] code to find the next state goes here */
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 425 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+/* %if-c-only */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ register int yy_is_jam;
+ /* %% [17.0] code to find the next state, and perhaps do backing up, goes here */
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 425 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 424);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+/* %if-c-only */
+
+/* %endif */
+
+/* %if-c-only */
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ wwrestart(wwin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( wwwrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve wwtext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+/* %% [19.0] update BOL and wwlineno */
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )
+
+ wwlineno++;
+;
+
+ return c;
+}
+/* %if-c-only */
+#endif /* ifndef YY_NO_INPUT */
+/* %endif */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+/* %if-c-only */
+ void wwrestart (FILE * input_file )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ wwensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ ww_create_buffer(wwin,YY_BUF_SIZE );
+ }
+
+ ww_init_buffer(YY_CURRENT_BUFFER,input_file );
+ ww_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+/* %if-c-only */
+ void ww_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * wwpop_buffer_state();
+ * wwpush_buffer_state(new_buffer);
+ */
+ wwensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ ww_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (wwwrap()) processing, but the only time this flag
+ * is looked at is after wwwrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/* %if-c-only */
+static void ww_load_buffer_state (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ wwin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+/* %if-c-only */
+ YY_BUFFER_STATE ww_create_buffer (FILE * file, int size )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) wwalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in ww_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) wwalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in ww_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ ww_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with ww_create_buffer()
+ *
+ */
+/* %if-c-only */
+ void ww_delete_buffer (YY_BUFFER_STATE b )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ wwfree((void *) b->yy_ch_buf );
+
+ wwfree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a wwrestart() or at EOF.
+ */
+/* %if-c-only */
+ static void ww_init_buffer (YY_BUFFER_STATE b, FILE * file )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+{
+ int oerrno = errno;
+
+ ww_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then ww_init_buffer was _probably_
+ * called from wwrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+/* %if-c-only */
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+/* %if-c-only */
+ void ww_flush_buffer (YY_BUFFER_STATE b )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ ww_load_buffer_state( );
+}
+
+/* %if-c-or-c++ */
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+/* %if-c-only */
+void wwpush_buffer_state (YY_BUFFER_STATE new_buffer )
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ if (new_buffer == NULL)
+ return;
+
+ wwensure_buffer_stack();
+
+ /* This block is copied from ww_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from ww_switch_to_buffer. */
+ ww_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+/* %endif */
+
+/* %if-c-or-c++ */
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+/* %if-c-only */
+void wwpop_buffer_state (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ ww_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ ww_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+/* %endif */
+
+/* %if-c-or-c++ */
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+/* %if-c-only */
+static void wwensure_buffer_stack (void)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)wwalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in wwensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)wwrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in wwensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+/* %endif */
+
+/* %if-c-only */
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE ww_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) wwalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in ww_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ ww_switch_to_buffer(b );
+
+ return b;
+}
+/* %endif */
+
+/* %if-c-only */
+/** Setup the input buffer state to scan a string. The next call to wwlex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * ww_scan_bytes() instead.
+ */
+YY_BUFFER_STATE ww_scan_string (yyconst char * yystr )
+{
+
+ return ww_scan_bytes(yystr,strlen(yystr) );
+}
+/* %endif */
+
+/* %if-c-only */
+/** Setup the input buffer state to scan the given bytes. The next call to wwlex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE ww_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) wwalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in ww_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = ww_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in ww_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+/* %endif */
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+/* %if-c-only */
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up wwtext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ wwtext[wwleng] = (yy_hold_char); \
+ (yy_c_buf_p) = wwtext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ wwleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/* %if-c-only */
+/* %if-reentrant */
+/* %endif */
+
+/** Get the current line number.
+ *
+ */
+int wwget_lineno (void)
+{
+
+ return wwlineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *wwget_in (void)
+{
+ return wwin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *wwget_out (void)
+{
+ return wwout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+yy_size_t wwget_leng (void)
+{
+ return wwleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *wwget_text (void)
+{
+ return wwtext;
+}
+
+/* %if-reentrant */
+/* %endif */
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void wwset_lineno (int line_number )
+{
+
+ wwlineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see ww_switch_to_buffer
+ */
+void wwset_in (FILE * in_str )
+{
+ wwin = in_str ;
+}
+
+void wwset_out (FILE * out_str )
+{
+ wwout = out_str ;
+}
+
+int wwget_debug (void)
+{
+ return ww_flex_debug;
+}
+
+void wwset_debug (int bdebug )
+{
+ ww_flex_debug = bdebug ;
+}
+
+/* %endif */
+
+/* %if-reentrant */
+/* %if-bison-bridge */
+/* %endif */
+/* %endif if-c-only */
+
+/* %if-c-only */
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from wwlex_destroy(), so don't allocate here.
+ */
+
+ /* We do not touch wwlineno unless the option is enabled. */
+ wwlineno = 1;
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ wwin = stdin;
+ wwout = stdout;
+#else
+ wwin = (FILE *) 0;
+ wwout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * wwlex_init()
+ */
+ return 0;
+}
+/* %endif */
+
+/* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */
+/* wwlex_destroy is for both reentrant and non-reentrant scanners. */
+int wwlex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ ww_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ wwpop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ wwfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * wwlex() is called, initialization will occur. */
+ yy_init_globals( );
+
+/* %if-reentrant */
+/* %endif */
+ return 0;
+}
+/* %endif */
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *wwalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *wwrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void wwfree (void * ptr )
+{
+ free( (char *) ptr ); /* see wwrealloc() for (char *) cast */
+}
+
+/* %if-tables-serialization definitions */
+/* %define-yytables The name for this specific scanner's tables. */
+#define YYTABLES_NAME "yytables"
+/* %endif */
+
+/* %ok-for-header */
+
+#line 260 "web.l"
+
+
+
+
diff --git a/web/web2w/web2w.c b/web/web2w/web2w.c
new file mode 100644
index 0000000000..20d6c7a8db
--- /dev/null
+++ b/web/web2w/web2w.c
@@ -0,0 +1,2297 @@
+/*
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+*/
+/*1:*/
+#line 501 "web2w.w"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <math.h>
+#include "web2w.h"
+#include "pascal.tab.h"
+
+/*3:*/
+#line 544 "web2w.w"
+
+extern int wwlex(void);
+extern FILE*wwin;
+extern FILE*wwout;
+/*:3*//*11:*/
+#line 692 "web2w.w"
+
+#define MAX_TOKEN_MEM 250000
+/*:11*//*29:*/
+#line 857 "web2w.w"
+
+#define MAX_STRING_MEM 800000
+/*:29*//*34:*/
+#line 934 "web2w.w"
+
+#define MAX_SYMBOL_TABLE 6007
+#define MAX_SYMBOLS 5200
+/*:34*//*54:*/
+#line 1258 "web2w.w"
+
+#define MAX_MODULE_TABLE 1009
+/*:54*//*99:*/
+#line 2088 "web2w.w"
+
+static char*token2string(token*t);
+/*:99*//*103:*/
+#line 2148 "web2w.w"
+
+static token*wprint_to(token*t,token*end);
+static token*wskip_to(token*t,token*end);
+/*:103*//*111:*/
+#line 2257 "web2w.w"
+
+static bool following_directive(token*t);
+/*:111*//*118:*/
+#line 2395 "web2w.w"
+
+static void wid(token*t);
+/*:118*//*158:*/
+#line 3131 "web2w.w"
+
+static token*varlist;
+/*:158*//*169:*/
+#line 3363 "web2w.w"
+
+int generate_constant(token*t,char sign,int value);
+/*:169*/
+#line 512 "web2w.w"
+
+/*12:*/
+#line 696 "web2w.w"
+
+static token token_mem[MAX_TOKEN_MEM]= {{0}};
+static int free_tokens= MAX_TOKEN_MEM;
+/*:12*//*16:*/
+#line 724 "web2w.w"
+
+int sequenceno= 0;
+/*:16*//*21:*/
+#line 757 "web2w.w"
+
+static token*first_token;
+token*last_token;
+/*:21*//*30:*/
+#line 861 "web2w.w"
+
+static char string_mem[MAX_STRING_MEM];
+static int free_strings= MAX_STRING_MEM;
+static int current_string= 0;
+/*:30*//*35:*/
+#line 939 "web2w.w"
+
+symbol*symbol_table[MAX_SYMBOL_TABLE]= {NULL};
+static symbol symbols[MAX_SYMBOLS]= {{0}};
+static int free_symbols= MAX_SYMBOLS;
+/*:35*//*43:*/
+#line 1045 "web2w.w"
+
+#define MAX_LOCALS 50
+static int locals[MAX_LOCALS];
+static symbol*globals[MAX_LOCALS];
+static int free_locals= MAX_LOCALS;
+/*:43*//*46:*/
+#line 1125 "web2w.w"
+
+#define MAX_WWSTACK 200
+static token*wwstack[MAX_WWSTACK]= {0};
+static int wwsp= 0;
+/*:46*//*52:*/
+#line 1221 "web2w.w"
+
+static token*first_string= NULL,**last_string= &first_string;
+/*:52*//*55:*/
+#line 1262 "web2w.w"
+
+static module module_table[MAX_MODULE_TABLE]= {{0}};
+static int free_modules= MAX_MODULE_TABLE;
+static module*module_root= NULL;
+/*:55*//*62:*/
+#line 1355 "web2w.w"
+
+token*program;
+/*:62*//*71:*/
+#line 1491 "web2w.w"
+
+#define MAX_PPSTACK 40
+static struct{
+token*next,*end,*link;
+int environment;
+token*parameter;
+}pp_stack[MAX_PPSTACK];
+static int pp_sp= MAX_PPSTACK;
+/*:71*//*97:*/
+#line 2053 "web2w.w"
+
+static int alfanum= 0;
+static int comma= 0;
+static int column= 0;
+/*:97*//*114:*/
+#line 2346 "web2w.w"
+
+static int float_constant_no;
+/*:114*//*134:*/
+#line 2725 "web2w.w"
+
+int print_no,print_str_no,overflow_no,print_err_no,
+print_nl_no,fatal_error_no,prompt_file_name_no,
+help_line_no,empty_string_no,max_reg_help_line_no;
+/*:134*//*139:*/
+#line 2798 "web2w.w"
+
+int TeXinputs_no,TeXfonts_no,fmt_no,math_spacing_no;
+/*:139*//*147:*/
+#line 2958 "web2w.w"
+
+static char*hash_str;
+/*:147*//*152:*/
+#line 3023 "web2w.w"
+
+int exit_no;
+/*:152*//*159:*/
+#line 3134 "web2w.w"
+
+static token*varlist= NULL;
+/*:159*//*196:*/
+#line 4035 "web2w.w"
+
+unsigned int param_mask,param_bit;
+/*:196*//*204:*/
+#line 4236 "web2w.w"
+
+int x_over_n,xn_over_d;
+/*:204*//*213:*/
+#line 4446 "web2w.w"
+
+#define MAX_NAME 256
+static char basename[MAX_NAME];
+static FILE*w= NULL;
+static FILE*pascal= NULL;
+FILE*logfile= NULL;
+debugmode debugflags= dbgnone;
+/*:213*/
+#line 513 "web2w.w"
+
+/*14:*/
+#line 705 "web2w.w"
+
+static token*new_token(int tag)
+{token*n;
+if(free_tokens> 0)n= &token_mem[--free_tokens];
+else ERROR("token mem overflow");
+n->lineno= wwlineno;
+n->sequenceno= sequenceno;
+n->tag= tag;
+return n;
+}
+/*:14*//*19:*/
+#line 740 "web2w.w"
+
+void seq(token*t,token*s)
+{CHECK(t->sequenceno==s->sequenceno,
+"tokens in line %d and %d belong to different code sequences",t->lineno,s->lineno);
+}
+/*:19*//*24:*/
+#line 773 "web2w.w"
+
+token*add_token(int tag)
+{token*n= new_token(tag);
+last_token->next= n;
+n->previous= last_token;
+last_token= n;
+return n;
+}
+/*:24*//*32:*/
+#line 876 "web2w.w"
+
+char*new_string(void)
+{current_string= MAX_STRING_MEM-free_strings;
+return string_mem+current_string;
+}
+
+void add_string(char*str)
+{while(free_strings> 0)
+{if(*str!=0)
+string_mem[MAX_STRING_MEM-free_strings--]= *str++;
+else
+return;
+}
+ERROR("String mem overflow");
+}
+
+char*end_string(void)
+{char*str= string_mem+current_string;
+if(free_strings> 0)
+string_mem[MAX_STRING_MEM-free_strings--]= 0;
+else
+ERROR("String mem overflow");
+current_string= MAX_STRING_MEM-free_strings;
+return str;
+}
+
+char*copy_string(char*str)
+{new_string();
+add_string(str);
+return end_string();
+}
+
+int string_length(void)
+{return(MAX_STRING_MEM-free_strings)-current_string;}
+
+/*:32*//*37:*/
+#line 951 "web2w.w"
+
+static int symbol_hash(char*name)
+{int hash= 0;
+while(*name!=0)
+hash= hash+(*(name++)^0x9E);
+return hash;
+}
+
+static symbol*new_symbol(void)
+{CHECK(free_symbols> 0,"Symbol table overflow");
+free_symbols--;
+return symbols+free_symbols;
+}
+
+int get_sym_no(char*name)
+{int i,c;
+i= symbol_hash(name)%MAX_SYMBOL_TABLE;
+if(symbol_table[i]!=NULL)
+{if(strcmp(symbol_table[i]->name,name)==0)
+return i;
+if(i==0)c= 1;else c= MAX_SYMBOL_TABLE-i;
+while(true)
+{i= i-c;
+if(i<0)i= i+MAX_SYMBOL_TABLE;
+if(symbol_table[i]==NULL)break;
+if(strcmp(symbol_table[i]->name,name)==0)
+return i;
+}
+}
+symbol_table[i]= new_symbol();
+symbol_table[i]->name= new_string();add_string(name);end_string();
+symbol_table[i]->tag= ID;
+return i;
+}
+/*:37*//*44:*/
+#line 1053 "web2w.w"
+
+void scope_open(void)
+{
+CHECK(free_locals==MAX_LOCALS,"Opening a new scope without closing the previous one");
+}
+
+void scope_close(void)
+{int i;
+for(i= free_locals;i<MAX_LOCALS;i++)
+symbol_table[locals[i]]= globals[i];
+free_locals= MAX_LOCALS;
+}
+/*:44*//*45:*/
+#line 1069 "web2w.w"
+
+void localize(token*t)
+{int sym_no= t->sym_no;
+symbol*l,*g;
+l= new_symbol();
+g= symbol_table[sym_no];
+l->name= g->name;
+l->tag= g->tag;
+l->eq= g->eq;
+symbol_table[sym_no]= l;
+CHECK(free_locals> 0,"Overflow of local symbols in line %d",t->lineno);
+free_locals--;
+locals[free_locals]= sym_no;
+globals[free_locals]= g;
+t->sym_ptr= l;
+}
+/*:45*//*48:*/
+#line 1143 "web2w.w"
+
+void ww_push(token*left)
+{CHECK(wwsp<MAX_WWSTACK,"WW stack overflow");
+DBG(dbglink,"Pushing[%d]:",wwsp);if(left!=NULL)DBG(dbglink,THE_TOKEN(left));
+wwstack[wwsp++]= left;
+}
+
+token*ww_pop(token*right)
+{token*left;
+CHECK(wwsp> 0,"Mode stack underflow");
+left= wwstack[--wwsp];
+if(left!=NULL)left->link= right;
+DBG(dbglink,"Popping[%d]:",wwsp);if(left!=NULL)DBG(dbglink,THE_TOKEN(left));
+return left;
+}
+
+int ww_is(int tag)
+{return wwsp> 0&&wwstack[wwsp-1]!=NULL&&wwstack[wwsp-1]->tag==tag;
+}
+
+/*:48*//*51:*/
+#line 1209 "web2w.w"
+
+void wwstring(char*wwtext)
+{token*t= add_token(STRING);
+t->sym_no= get_sym_no(wwtext);
+t->text= SYM(t)->name;
+*last_string= t;
+last_string= &(t->link);
+}
+/*:51*//*53:*/
+#line 1246 "web2w.w"
+
+static int module_name_cmp(token*n,token*m)
+{n= n->next;m= m->next;
+if(n->next->tag==ELIPSIS)
+return strncmp(n->text,m->text,strlen(n->text));
+else
+return strcmp(n->text,m->text);
+}
+/*:53*//*58:*/
+#line 1288 "web2w.w"
+
+module*find_module(token*atless)
+{module**m= &module_root;
+while(*m!=NULL)
+{int d= module_name_cmp(atless,(*m)->atless);
+if(d==0)
+return*m;
+else if(d<0)m= &((*m)->left);
+else m= &((*m)->right);
+}
+CHECK(free_modules> 0,"Module table overflow");
+*m= module_table+MAX_MODULE_TABLE-free_modules--;
+(*m)->atless= atless;
+return*m;
+}
+/*:58*//*59:*/
+#line 1310 "web2w.w"
+
+void add_module(token*atless)
+{module*m= find_module(atless);
+token*atgreater= m->atgreater;
+if(atgreater==NULL)
+m->atgreater= atless->link;
+else
+{while(atgreater->link!=NULL)atgreater= atgreater->link;
+atgreater->link= atless->link;
+}
+}
+/*:59*//*65:*/
+#line 1391 "web2w.w"
+
+void def_macro(token*eq,int tag)
+{token*id;
+if(eq->previous->tag==PARAM)
+{id= eq->previous->previous;
+tag= PMACRO;
+}
+else
+{id= eq->previous;
+}
+CHGTAG(id,tag);
+CHGID(id,tag);
+SYM(id)->eq= eq;
+DBG(dbgexpand,"Defining %s: %s\n",tagname(tag),SYM(id)->name);
+}
+/*:65*//*70:*/
+#line 1475 "web2w.w"
+
+void pperror(const char*message)
+{ERROR("Parse error line %d: %s",pplval->lineno,message);}
+/*:70*//*72:*/
+#line 1530 "web2w.w"
+
+token*pp_push(token*link,token*eq,int environment,token*parameter)
+{CHECK(pp_sp> 0,"Pascal lexer stack overflow");
+pp_sp--;
+pp_stack[pp_sp].link= link;
+pp_stack[pp_sp].next= eq->next;
+pp_stack[pp_sp].end= eq->link;
+pp_stack[pp_sp].environment= environment;
+pp_stack[pp_sp].parameter= parameter;
+DBG(dbgexpand,"Push pplex[%d]: ",MAX_PPSTACK-pp_sp);DBGTOKS(dbgexpand,eq->next,eq->link);
+return pp_stack[pp_sp].next;
+}
+
+token*pp_pop(void)
+{CHECK(pp_sp<MAX_PPSTACK,"Pascal Lexer stack underflow");
+pp_sp++;
+DBG(dbgexpand,"Pop pplex[%d]: ",MAX_PPSTACK-pp_sp);
+DBGTOKS(dbgexpand,pp_stack[pp_sp].next,pp_stack[pp_sp].end);
+return pp_stack[pp_sp].next;
+}
+/*:72*//*73:*/
+#line 1561 "web2w.w"
+
+int pplex(void)
+{token*t;
+int tag;
+t= pp_stack[pp_sp].next;
+while(true)
+{
+if(t==pp_stack[pp_sp].end)
+{/*88:*/
+#line 1886 "web2w.w"
+
+token*link= pp_stack[pp_sp].link;
+if(link!=NULL)
+{token*eq;
+eq= link->next;
+link= link->link;
+pp_pop();
+t= pp_push(link,eq,0,NULL);
+}
+else
+t= pp_pop();
+/*:88*/
+#line 1569 "web2w.w"
+
+continue;
+}
+tag= t->tag;
+tag_known:
+if(tag> FIRST_PASCAL_TOKEN)
+{
+pp_stack[pp_sp].next= t->next;
+goto found;
+}
+else
+{switch(tag)
+{/*74:*/
+#line 1600 "web2w.w"
+
+case NL:
+case INDENT:
+if(pascal!=NULL)fprintf(pascal,"%s",token2string(t));
+case METACOMMENT:
+case ATT:
+case ATEX:
+case ATQM:
+case ATPLUS:
+case ATSLASH:
+case ATBACKSLASH:
+case ATBAR:
+case ATHASH:
+case ATCOMMA:
+case ATINDEX:
+case ATINDEXTT:
+case ATINDEX9:
+case ATAND:
+case ATSEMICOLON:
+case ATLEFT:
+case ATRIGHT:
+t= t->next;
+continue;
+/*:74*//*75:*/
+#line 1625 "web2w.w"
+
+case MLEFT:
+case PLEFT:
+t= t->link->next;
+continue;
+/*:75*//*76:*/
+#line 1634 "web2w.w"
+
+case PEOF:
+pp_stack[pp_sp].next= t->next;
+goto found;
+/*:76*//*77:*/
+#line 1646 "web2w.w"
+
+case ATDOLLAR:
+case OCTAL:
+case HEX:
+case CHAR:
+pp_stack[pp_sp].next= t->next;
+tag= PINTEGER;
+goto found;
+/*:77*//*78:*/
+#line 1662 "web2w.w"
+
+case ID:
+{symbol*s= SYM(t);
+tag= s->tag;
+if(tag==ID)
+tag= s->tag= PID;
+t->sym_ptr= s;
+t->tag= tag;
+goto tag_known;
+}
+/*:78*//*79:*/
+#line 1707 "web2w.w"
+
+case WDEBUG:
+case WGUBED:
+case WINIT:
+case WTINI:
+case WSTAT:
+case WTATS:
+t= t->next;
+continue;
+/*:79*//*83:*/
+#line 1794 "web2w.w"
+
+case NMACRO:
+t->sym_ptr= SYM(t);
+if(t->sym_ptr->eq->next->tag==STRING)
+{token*s= t->sym_ptr->eq->next;
+s->sym_ptr= SYM(s);
+s->sym_ptr->value++;
+DBG(dbgstring,"Using numeric macro %s (%d) in line %d\n",
+s->sym_ptr->name,s->sym_ptr->value,t->lineno);
+}
+pp_stack[pp_sp].next= t->next;
+goto found;
+case STRING:
+t->sym_ptr= SYM(t);
+t->sym_ptr->value++;
+DBG(dbgstring,"Using string %s (%d) in line %d\n",
+t->sym_ptr->name,t->sym_ptr->value,t->lineno);
+pp_stack[pp_sp].next= t->next;
+goto found;
+/*:83*//*87:*/
+#line 1868 "web2w.w"
+
+case ATLESS:
+{token*eq,*atgreater;
+atgreater= find_module(t)->atgreater;
+CHECK(atgreater!=NULL,"Undefined module @<%s ...@> in line %d",
+token2string(t->next),t->lineno);
+DBG(dbgexpand,"Expanding module @<%s@> in line %d\n",
+token2string(t->next),t->lineno);
+eq= atgreater->next;
+pp_stack[pp_sp].next= t->link->next;
+t= pp_push(atgreater->link,eq,0,NULL);
+continue;
+}
+/*:87*//*89:*/
+#line 1900 "web2w.w"
+
+case OMACRO:
+{token*eq;
+eq= SYM(t)->eq;
+pp_stack[pp_sp].next= t->next;
+DBG(dbgexpand,"Expanding ordinary macro %s in line %d\n",token2string(t),t->lineno);
+t= pp_push(NULL,eq,0,NULL);
+continue;
+}
+/*:89*//*91:*/
+#line 1954 "web2w.w"
+
+case PMACRO:
+{token*open,*eq;
+int popen;
+DBG(dbgexpand,"Expanding parameter macro %s in line %d\n",
+token2string(t),t->lineno);
+eq= SYM(t)->eq;
+pp_stack[pp_sp].next= t->next;
+popen= pplex();
+CHECK(popen==POPEN,"expected ( after macro with parameter");
+open= pplval;
+pp_stack[pp_sp].next= open->link->next;
+/*145:*/
+#line 2928 "web2w.w"
+
+{token*p;int count= 1;
+if(open->next->tag==HASH)
+{DBG(dbgmacro,"Counting %s parameters (#) in line %d\n",SYM(t)->name,t->lineno);}
+else
+{for(p= open->next;p!=open->link;p= p->next)
+if(p->tag==PCOMMA)count++;
+else if(p->tag==POPEN)p= p->link;
+if(SYM(t)->value==0)SYM(t)->value= count;
+else if(SYM(t)->value!=count)SYM(t)->value= 4;
+DBG(dbgmacro,"Counting %s parameters %d line %d\n",SYM(t)->name,SYM(t)->value,t->lineno);
+}
+}
+/*:145*/
+#line 1966 "web2w.w"
+
+t= pp_push(NULL,eq,pp_sp,open);
+continue;
+}
+/*:91*//*92:*/
+#line 1977 "web2w.w"
+
+case HASH:
+{token*parameter= pp_stack[pp_sp].parameter;
+int environment= pp_stack[pp_sp].environment;
+pp_stack[pp_sp].next= t->next;
+t= pp_push(NULL,parameter,pp_stack[environment].environment,
+pp_stack[environment].parameter);
+continue;
+}
+/*:92*//*154:*/
+#line 3036 "web2w.w"
+
+case PRETURN:
+t->sym_ptr= SYM(t);
+pp_stack[pp_sp].next= t->next;
+goto found;
+/*:154*//*191:*/
+#line 3953 "web2w.w"
+
+case CSEMICOLON:
+t= t->next;
+continue;
+/*:191*/
+#line 1581 "web2w.w"
+
+default:
+ERROR("Unexpected token in pplex:"THE_TOKEN(t));
+}
+}
+}
+found:
+DBG(dbgpascal,"pplex: %s->\t",tagname(tag));
+DBG(dbgpascal,THE_TOKEN(t));
+if(pascal!=NULL)fprintf(pascal,"%s ",token2string(t));
+pplval= t;
+return tag;
+}
+/*:73*//*85:*/
+#line 1822 "web2w.w"
+
+int getval(token*t)
+{int n= 0;
+switch(t->tag)
+{case ATDOLLAR:n= 0;break;
+case PINTEGER:n= strtol(t->text,NULL,10);break;
+case NMACRO:
+t= SYM(t)->eq;
+CHECK(t->tag==EQEQ,"= expected in numeric macro in line %d",t->lineno);
+t= t->next;
+if(t->tag==PMINUS){t= t->next;n= -getval(t);}
+else n= getval(t);
+while(true)
+{if(t->next->tag==PPLUS)
+{t= t->next->next;n= n+getval(t);}
+else if(t->next->tag==PMINUS)
+{t= t->next->next;n= n-getval(t);}
+else break;
+}
+break;
+case OCTAL:n= strtol(t->text+2,NULL,8);break;
+case HEX:n= strtol(t->text+2,NULL,16);break;
+case CHAR:n= (int)(unsigned char)t->text[1];break;
+case PCONSTID:n= SYM(t)->value;break;
+default:ERROR("Unable to get value for tag %s in line %d",TAG(t),t->lineno);
+}
+return n;
+}
+/*:85*//*96:*/
+#line 2024 "web2w.w"
+
+token*join(int tag,token*left,token*right,int value)
+{token*n= new_token(tag);
+n->previous= left;
+n->next= right;
+n->value= value;
+DBG(dbgjoin,"tree: ");DBGTREE(dbgjoin,n);
+return n;
+}
+/*:96*//*98:*/
+#line 2059 "web2w.w"
+
+static void wput(char c)
+{fputc(c,w);
+alfanum= isalnum(c);
+comma= c==',';
+if(c=='\n')column= 0;else column++;
+}
+
+static void wputs(char*str)
+{while(*str!=0)wput(*str++);
+}
+
+static void wputi(int i)
+{if(alfanum||comma)fputc(' ',w),column++;
+column+= fprintf(w,"%d",i);
+alfanum= true;
+comma= false;
+}
+
+static void wprint(char*str)
+{if((alfanum||comma)&&isalnum(str[0]))fputc(' ',w);
+wputs(str);
+}
+/*:98*//*100:*/
+#line 2092 "web2w.w"
+
+static char*token2string(token*t)
+{CHECK(t!=NULL,"Unable to convert NULL token to a string");
+switch(t->tag)
+{default:
+if(t->text!=NULL)
+return t->text;
+else
+return"";
+/*40:*/
+#line 1008 "web2w.w"
+
+case ID:case PID:case PCONSTID:
+case PARRAYFILETYPEID:case PARRAYFILEID:
+case PFUNCID:case PPROCID:
+case PDEFVARID:case PDEFPARAMID:case PDEFREFID:case PDEFCONSTID:
+case PDEFTYPEID:case PDEFTYPESUBID:case PDEFFUNCID:case CREFID:
+case NMACRO:case OMACRO:case PMACRO:
+return SYM(t)->name;
+/*:40*//*190:*/
+#line 3948 "web2w.w"
+
+case CSEMICOLON:
+return";";
+/*:190*/
+#line 2101 "web2w.w"
+
+}
+}
+/*:100*//*102:*/
+#line 2131 "web2w.w"
+
+static token*wtoken(token*t)
+{static int level= 0;
+level++;
+DBG(dbgcweb,"wtoken[%d] %s (%s) line %d\n",level,TAG(t),token2string(t),t->lineno);
+switch(t->tag)
+{/*80:*/
+#line 1721 "web2w.w"
+
+case WDEBUG:
+if(t->previous->tag==BAR)
+wputs(t->text);
+else
+{if(column!=0)wput('\n');
+wputs("#ifdef @!DEBUG\n");
+}
+t= t->next;break;
+case WINIT:
+if(t->previous->tag==BAR)
+wputs(t->text);
+else
+{if(column!=0)wput('\n');
+wputs("#ifdef @!INIT\n");
+}
+t= t->next;break;
+case WSTAT:
+if(t->previous->tag==BAR)
+wputs(t->text);
+else
+{
+if(column!=0)wput('\n');
+wputs("#ifdef @!STAT\n");
+}
+t= t->next;break;
+case WGUBED:
+case WTINI:
+case WTATS:
+if(t->previous->tag==BAR)
+wputs(t->text);
+else
+{if(column!=0)wput('\n');
+wputs("#endif\n");
+}
+t= t->next;
+if(t->tag==ATPLUS||t->tag==ATSLASH)t= t->next;
+if(t->tag==NL)t= t->next;
+break;
+/*:80*//*81:*/
+#line 1763 "web2w.w"
+
+case ATPLUS:
+t= t->next;
+if(!following_directive(t))
+wputs("@+");
+else
+DBG(dbgcweb,"Eliminating @+ in line %d\n",t->lineno);
+break;
+/*:81*//*105:*/
+#line 2172 "web2w.w"
+
+case CIGNORE:case PPROGRAM:case PLABEL:case PCONST:case PVAR:
+case PPACKED:case POF:case ATQM:case ATBACKSLASH:
+t= t->next;break;
+/*:105*//*107:*/
+#line 2186 "web2w.w"
+
+case PFORWARD:
+if(t->next->tag==PSEMICOLON)wput(';'),t= t->next->next;
+else wprint("forward"),t= t->next;
+if(t->tag==ATT)t= t->next;
+break;
+/*:107*//*108:*/
+#line 2200 "web2w.w"
+
+case METACOMMENT:
+{char*c;
+wputs("/*");
+for(c= t->text+2;c[0]!='@'||c[1]!='}';c++)wput(*c);
+wputs("*/");
+t= t->next;
+}
+break;
+case ATLEFT:
+if(column!=0)wput('\n');
+wputs("#if 0\n");
+t= t->next;break;
+case ATRIGHT:
+if(column!=0)wput('\n');
+wputs("#endif\n");
+t= t->next;break;
+/*:108*//*109:*/
+#line 2224 "web2w.w"
+
+case PLEFT:case MLEFT:wputs(" /*");t= t->next;break;
+case RIGHT:wputs("*/ ");t= t->next;break;
+case PSEMICOLON:wputs(";");t= t->next;break;
+case PCOMMA:wputs(",");t= t->next;break;
+case PMOD:wput('%');t= t->next;break;
+case PDIV:wput('/');t= t->next;break;
+case PNIL:wprint("NULL");t= t->next;break;
+case POR:wputs("||");t= t->next;break;
+case PAND:wputs("&&");t= t->next;break;
+case PNOT:wputs("!");t= t->next;break;
+case PIF:wprint("if (");t= t->next;break;
+case PTHEN:wputs(") ");t= t->next;break;
+case PASSIGN:wput('=');t= t->next;break;
+case PNOTEQ:wputs("!=");t= t->next;break;
+case PEQ:wputs("==");t= t->next;break;
+case EQEQ:wput('\t');t= t->next;break;
+case OCTAL:wprint("0");wputs(t->text+2);t= t->next;break;
+case HEX:wprint("0x");wputs(t->text+2);t= t->next;break;
+case PTYPEINT:wprint("int");t= t->next;break;
+case PTYPEREAL:wprint("double");t= t->next;break;
+case PTYPEBOOL:wprint("bool");t= t->next;break;
+case PTYPECHAR:wprint("unsigned char");t= t->next;break;
+/*:109*//*110:*/
+#line 2252 "web2w.w"
+
+case PBEGIN:wput('{'),t= t->next;
+if(!following_directive(t))wputs("@+");
+break;
+/*:110*//*113:*/
+#line 2275 "web2w.w"
+
+case PDOTDOT:wprint("dotdot");t= t->next;break;
+/*:113*//*116:*/
+#line 2354 "web2w.w"
+
+case PSLASH:
+wput('/');
+if(t->next->tag!=PMACRO||t->next->sym_no!=float_constant_no)
+{wprint("(double)");
+DBG(dbgslash,"Inserting (double) after / in line %d\n",t->lineno);
+}
+t= t->next;break;
+/*:116*//*117:*/
+#line 2377 "web2w.w"
+
+case ATEX:
+t= t->next;
+if(t->tag!=ID&&t->tag!=PID&&t->tag!=PFUNCID&&
+t->tag!=PDEFVARID&&t->tag!=PDEFPARAMID&&t->tag!=PDEFTYPEID&&
+t->tag!=OMACRO&&t->tag!=PMACRO&&t->tag!=NMACRO&&
+t->tag!=CINTDEF&&t->tag!=CSTRDEF&&t->tag!=PDIV&&
+t->tag!=WDEBUG&&t->tag!=WINIT&&t->tag!=WSTAT)
+{wputs("@!");
+DBG(dbgbasic,"Tag after @! is %s in line %d\n",tagname(t->tag),t->lineno);
+}
+break;
+/*:117*//*120:*/
+#line 2406 "web2w.w"
+
+case ID:
+case PID:
+case OMACRO:
+case PMACRO:
+case NMACRO:
+wid(t);t= t->next;break;
+/*:120*//*122:*/
+#line 2450 "web2w.w"
+
+case PCHAR:
+{char*str= t->text;
+wput(' ');
+wput('\''),str++;
+if(str[0]=='\'')wputs("\\'");
+else if(str[0]=='\\')wputs("\\\\");
+else if(str[0]=='@')wputs("@@");
+else wput(str[0]);
+wput('\'');
+wput(' ');
+}
+t= t->next;
+break;
+case PSTRING:
+{char*str= t->text;
+wput('"'),str++;
+while(*str!=0)
+{if(str[0]=='\''&&str[1]=='\'')wput('\''),str++;
+else if(str[0]=='"'&&str[1]=='"')wputs("\\\""),str++;
+else if(str[0]=='\\')wputs("\\\\");
+else if(str[0]=='\''&&str[1]==0)wput('"');
+else if(str[0]=='"'&&str[1]==0)wput('"');
+else if(str[0]=='"')wput('\\'),wput('"');
+else wput(str[0]);
+str++;
+}
+}
+t= t->next;
+break;
+/*:122*//*123:*/
+#line 2487 "web2w.w"
+
+case ATLESS:
+wputs("@<");
+t= t->next;
+CHECK(t->tag==TEXT,"Module name expected instead of %s in line %d",
+token2string(t),t->lineno);
+{char*str= t->text;
+do
+if(str[0]=='@'&&str[1]==',')
+str= str+2;
+else if(column> 80&&isspace(*str))wput('\n'),str++;
+else wput(*str++);
+while(*str!=0);
+}
+t= t->next;
+if(t->tag==ELIPSIS)wputs("..."),t= t->next;
+CHECK(t->tag==ATGREATER,"@> expected instead of %s in line %d",
+token2string(t),t->lineno);
+wputs("@>");
+t= t->next;
+if(t->tag==ATSLASH)wputs("@;"),t= t->next;
+else if(t->tag==PELSE||
+(t->tag==NL))wputs("@;");
+break;
+/*:123*//*124:*/
+#line 2526 "web2w.w"
+
+case CHAR:
+{char c= t->text[1];
+wput('\'');
+if(c=='\''||c=='\\')wput('\\');
+wput(c);
+wput('\'');
+t= t->next;break;
+}
+case ATDOLLAR:wputs("0");t= t->next;break;
+/*:124*//*125:*/
+#line 2549 "web2w.w"
+
+case STRING:
+{/*126:*/
+#line 2564 "web2w.w"
+
+if(t->sym_no==empty_string_no)
+wprint("empty_string");
+/*:126*//*137:*/
+#line 2783 "web2w.w"
+
+else if(t->sym_no==TeXinputs_no)wprint("TEX_area");
+else if(t->sym_no==TeXfonts_no)wprint("TEX_font_area");
+else if(t->sym_no==fmt_no)wprint("format_extension");
+else if(t->sym_no==math_spacing_no)wprint("math_spacing");
+/*:137*/
+#line 2551 "web2w.w"
+
+else
+{wputs("@[@<|");wputs(SYM(t)->name);wputs("|@>@]");}
+t= t->next;break;
+}
+/*:125*//*142:*/
+#line 2854 "web2w.w"
+
+case ATD:
+{token*eq= t->next->next;
+DBG(dbgcweb,"Macro definition in line %d\n",t->lineno);
+if(SYM(t->next)->obsolete)
+t= wskip_to(t,eq->link);
+else
+{wputs("@d "),t= t->next;
+wprint(SYM(t)->name);
+if(t->tag==NMACRO)
+/*144:*/
+#line 2907 "web2w.w"
+
+{int has_operators;
+wput('\t');
+has_operators= 0;
+for(t= eq->next;t!=eq->link&&t->tag!=MLEFT&&t->tag!=NL;t= t->next)
+if(t->tag==PPLUS||t->tag==PMINUS){has_operators= 1;break;}
+if(has_operators)wput('(');
+for(t= eq->next;t!=eq->link&&t->tag!=MLEFT&&t->tag!=NL;t= wtoken(t))
+continue;
+if(has_operators)wput(')');
+}
+/*:144*/
+#line 2864 "web2w.w"
+
+else if(t->tag==OMACRO)
+/*143:*/
+#line 2890 "web2w.w"
+
+{wput('\t');
+t= eq->next;
+}
+/*:143*/
+#line 2866 "web2w.w"
+
+else if(t->tag==PMACRO)
+/*146:*/
+#line 2946 "web2w.w"
+
+{static char*params[4]= {"X","X","X, Y","X, Y, Z"};
+char*param;
+eq= eq->next;
+if(SYM(t)->value> 3)
+{param= "...";hash_str= "__VA_ARGS__";}
+else
+hash_str= param= params[SYM(t)->value];
+wput('('),wputs(param),wputs(")\t"),t= eq->next;
+}
+/*:146*/
+#line 2868 "web2w.w"
+
+else
+ERROR("Macro name expected in line %d",t->lineno);
+}
+DBG(dbgcweb,"End Macro definition in line %d\n",t->lineno);
+break;
+}
+case ATF:
+{token*eq= t->next->next;
+DBG(dbgcweb,"Format definition in line %d\n",t->lineno);
+if(SYM(t->next)->obsolete)
+t= wskip_to(t,eq->link);
+else
+{wputs("@f "),t= t->next;
+wprint(SYM(t)->name);
+t= wprint_to(eq->next,eq->link);
+}
+break;
+}
+/*:142*//*148:*/
+#line 2962 "web2w.w"
+
+case HASH:
+wprint(hash_str),t= t->next;break;
+/*:148*//*155:*/
+#line 3051 "web2w.w"
+
+case CLABEL:
+if(t->sym_ptr->value<=0)
+{t= t->next;
+if(t->tag==PPLUS)
+t= t->next->next;
+if(t->tag==PCOLON)
+{t= t->next;
+if(t->tag==CSEMICOLON)
+t= t->next;
+}
+}
+else
+{wprint(SYM(t)->name);t= t->next;
+if(t->tag==PPLUS)
+{t= t->next;wputs(t->text);t= t->next;}
+}
+break;
+case CLABELN:
+wprint("label");wputs(t->text);t= t->next;
+break;
+case PEXIT:
+wprint("exit(0)");t= t->next;
+break;
+case PRETURN:
+wprint("goto end");t= t->next;
+break;
+/*:155*//*156:*/
+#line 3091 "web2w.w"
+
+case CINTDEF:
+wputs("enum {@+"),wid(t),wput('=');
+t= wprint_to(t->link->next,t->link->link);
+wputs("@+};");
+t= t->next;
+break;
+case CSTRDEF:
+wprint("const char *"),wid(t);t= t->next;break;
+/*:156*//*160:*/
+#line 3138 "web2w.w"
+
+case PDEFVARID:
+{token*type= t->link;
+varlist= t;
+DBG(dbgcweb,"Converting variable list in line %d\n",t->lineno);
+while(type->tag==PID)type= type->link;
+{int replace= 0;
+/*185:*/
+#line 3763 "web2w.w"
+
+
+{token*subrange= NULL;
+if(type->tag==CTSUBRANGE)
+subrange= type->up;
+else if(type->tag==CIGNORE&&type->next->tag==PID&&
+type->next->sym_ptr->type!=NULL&&type->next->sym_ptr->type->tag==PDOTDOT)
+subrange= type->next->sym_ptr->type;
+if(subrange!=NULL)
+{token*id= t;
+while(id!=type&&!replace)
+{if(id->sym_ptr->for_ctrl!=0)
+{int lo= subrange->previous->value;
+int hi= subrange->next->value;
+int bits= FOR_CTRL_BITS(id->sym_ptr->for_ctrl);
+int direction= FOR_CTRL_DIRECTION(id->sym_ptr->for_ctrl);
+int lineno= FOR_CTRL_LINE(id->sym_ptr->for_ctrl);
+replace= FOR_CTRL_REPLACE(id->sym_ptr->for_ctrl);
+DBG(dbgfor,"Subrange for marked variable %s in line %d\n",
+token2string(id),id->lineno);
+DBG(dbgfor,"\tRange %d to %d, limit %d bits, direction %d in line %d\n",
+lo,hi,bits,direction,lineno);
+if(direction==DOWNTO_LOOP)
+{if(lo>=0&&bits==0)replace= true;
+else if(lo<0&&INT8_MIN<=lo&&hi<=INT8_MAX&&bits>=7)replace= true;
+else if(lo<0&&INT16_MIN<=lo&&hi<=INT16_MAX&&bits>=15)replace= true;
+}
+else if(direction==TO_LOOP)
+{if(lo<0&&INT8_MIN<=lo&&hi<=INT8_MAX&&bits>=7)replace= true;
+else if(0<=lo&&hi<=UINT8_MAX&&bits>=8)replace= true;
+else if(lo<0&&INT16_MIN<=lo&&hi<=INT16_MAX&&bits>=15)replace= true;
+else if(0<=lo&&hi<=UINT16_MAX&&bits>=16)replace= true;
+}
+}
+id= id->link;
+}
+}
+}
+/*:185*/
+#line 3145 "web2w.w"
+
+if(replace)
+{wprint("int");
+DBG(dbgfor,"\tReplacing subrange type by int\n");
+}
+else
+wprint_to(type,type->link);
+}
+DBG(dbgcweb,"Finished variable type in line %d\n",t->lineno);
+if(varlist->tag==PDEFVARID)
+{wid(varlist);varlist= varlist->next;}
+wprint_to(varlist,type);
+t= type->link;
+DBG(dbgcweb,"Finishing variable list in line %d\n",t->lineno);
+break;
+}
+/*:160*//*161:*/
+#line 3175 "web2w.w"
+
+case PDEFTYPEID:
+{token*type_name= t;
+token*type= type_name->link;
+DBG(dbgcweb,"Defining type %s in line %d\n",token2string(t),t->lineno);
+wprint("typedef ");
+t= wprint_to(type,type->link);
+wprint(token2string(type_name));
+break;
+}
+/*:161*//*162:*/
+#line 3196 "web2w.w"
+
+case CTSUBRANGE:
+{int lo= t->up->previous->value;
+int hi= t->up->next->value;
+DBG(dbgcweb,"Defining subrange type %d..%d\n",lo,hi);
+if(lo<0&&INT8_MIN<=lo&&hi<=INT8_MAX)wprint("int8_t");
+else if(0<=lo&&hi<=UINT8_MAX)wprint("uint8_t");
+else if(lo<0&&INT16_MIN<=lo&&hi<=INT16_MAX)wprint("int16_t");
+else if(0<=lo&&hi<=UINT16_MAX)wprint("uint16_t");
+else if(lo<0&&INT32_MIN<=lo&&hi<=INT32_MAX)wprint("int32_t");
+else if(0<=lo&&hi<=UINT32_MAX)wprint("uint32_t");
+else ERROR("unable to convert subrange type %d..%d in line %d\n",lo,hi,t->lineno);
+t= t->link;
+break;
+}
+/*:162*//*164:*/
+#line 3223 "web2w.w"
+
+case PRECORD:
+{DBG(dbgcweb,"Converting record type in line %d\n",t->lineno);
+wprint("struct { ");
+t= wprint_to(t->next,t->link);
+DBG(dbgcweb,"Finished record type in line %d\n",t->lineno);
+wprint("} ");
+break;
+}
+case CUNION:
+{DBG(dbgcweb,"Converting union type in line %d\n",t->lineno);
+wprint("union { ");
+t= wprint_to(t->next,t->link);
+wprint("};");
+DBG(dbgcweb,"Finished union type in line %d\n",t->lineno);
+break;
+}
+/*:164*//*165:*/
+#line 3267 "web2w.w"
+
+case PARRAY:
+if(t->up==NULL)
+wputs(t->text),t= t->next;
+else
+{token*from= t->link;
+token*index= from->link;
+token*to= index->link;
+token*element_type= to->link;
+token*subrange= t->up;
+int lo,hi,zero_based;
+
+if(subrange->tag==PID)subrange= subrange->sym_ptr->type;
+lo= subrange->previous->value;
+hi= subrange->next->value;
+
+zero_based= (subrange->previous->tag==PINTEGER&&lo==0)||
+subrange->previous->tag==PTYPECHAR;
+DBG(dbgarray,"Converting array[%d..%d] type in line %d\n",lo,hi,t->lineno);
+t= wprint_to(element_type,element_type->link);
+while(true)
+{CHECK(varlist!=NULL,"Nonempty variable list expected in line %d",
+varlist->lineno);
+DBG(dbgarray,"Generating array variable %s in line %d\n",
+varlist->sym_ptr->name,varlist->lineno);
+wid(varlist);
+if(!zero_based)wput('0');
+wput('[');/*166:*/
+#line 3312 "web2w.w"
+
+{int hi,size;
+hi= generate_constant(subrange->next,0,0);
+size= generate_constant(subrange->previous,'-',hi);
+size= size+1;
+if(size<0)wput('-'),wputi(-size);
+else if(size> 0)
+{if(subrange->previous->tag!=PTYPECHAR&&
+(subrange->previous->tag!=PINTEGER||subrange->next->tag!=PINTEGER))wput('+');
+wputi(size);
+}
+}
+/*:166*/
+#line 3294 "web2w.w"
+wput(']');
+if(!zero_based)
+{DBG(dbgarray,"Generating array pointer %s[%s=%d.. ] in line %d\n",
+varlist->sym_ptr->name,token2string(from->next),lo,varlist->lineno);
+wputs(", *const ");
+wid(varlist);
+wputs(" = ");
+wid(varlist),wput('0');
+/*167:*/
+#line 3326 "web2w.w"
+
+{int lo= generate_constant(subrange->previous,'-',0);
+if(lo<0)wput('-'),wputi(-lo);
+else if(lo> 0)wput('+'),wputi(lo);
+}
+/*:167*/
+#line 3302 "web2w.w"
+;
+}
+varlist= varlist->link;
+if(varlist->tag==PDEFVARID||varlist->tag==PID)wput(',');else break;
+}
+DBG(dbgarray,"Finished array type in line %d\n",t->lineno);
+}
+break;
+/*:165*//*170:*/
+#line 3377 "web2w.w"
+
+case PFILE:
+{DBG(dbgcweb,"Converting file type in line %d\n",t->lineno);
+wprint("struct {@+FILE *f;@+");
+t= wprint_to(t->next,t->link);
+wprint("@,d;@+} ");
+DBG(dbgcweb,"Finished file type in line %d\n",t->lineno);
+break;
+}
+/*:170*//*171:*/
+#line 3403 "web2w.w"
+
+case PUP:wputs(".d");t= t->next;break;
+/*:171*//*172:*/
+#line 3420 "web2w.w"
+
+case PWHILE:
+wprint("while ");
+if(t->link!=NULL){
+wput('(');t= wprint_to(t->next,t->link);wputs(") ");
+}
+t= t->next;break;
+/*:172*//*173:*/
+#line 3438 "web2w.w"
+
+case PCASE:
+if(t->link==NULL)
+{wprint(t->text);t= t->next;}
+else
+{wprint("switch (");
+t= wprint_to(t->next,t->link);
+wputs(") {");
+}
+break;
+/*:173*//*176:*/
+#line 3484 "web2w.w"
+
+case CBREAK:
+if(t->previous->tag!=PSEMICOLON&&t->previous->tag!=CSEMICOLON
+&&t->previous->tag!=PEND)wputs("@;");
+if(!dead_end(t->up,t->lineno))wprint("@+break;");
+t= t->next;
+break;
+/*:176*//*179:*/
+#line 3522 "web2w.w"
+
+case POTHERS:
+wprint("default:");
+t= t->next;
+break;
+/*:179*//*180:*/
+#line 3545 "web2w.w"
+
+case PREPEAT:wprint("@/do@+{");t= t->next;break;
+case PUNTIL:
+{int sequenceno,lineno;
+token*end;
+wputs("}@+ while (!(");
+sequenceno= t->sequenceno;
+lineno= t->lineno;
+end= t->next;
+while(true)
+{if(end->tag==PSEMICOLON||end->tag==CSEMICOLON||end->tag==PELSE)
+break;
+else if(end->tag==ATSPACE)
+{while(true)
+{int tag= end->previous->tag;
+if(tag> FIRST_PASCAL_TOKEN||tag==OMACRO||tag==NMACRO||tag==CHAR)break;
+end= end->previous;
+}
+break;
+}
+end= end->next;
+}
+CHECK(sequenceno==end->sequenceno,"until: end of expression not found in line %d",lineno);
+t= wprint_to(t->next,end);
+wputs("))");
+break;
+}
+/*:180*//*181:*/
+#line 3582 "web2w.w"
+
+case PFOR:
+{token*id= t->next;
+token*to= t->link;
+if(to==NULL){wprint("for");t= t->next;break;}
+wprint("for (");
+wprint_to(id,to);
+wputs("; ");
+wid(id);
+if(to->tag==PTO)wputs("<=");
+else if(to->tag==PDOWNTO)wputs(">=");
+else ERROR("to or downto expected in line %d",to->lineno);
+wprint_to(to->next,to->link);
+wputs("; ");
+wid(id);
+if(to->tag==PTO)wputs("++");
+else wputs("--");
+wputs(") ");
+t= to->link->next;
+break;
+}
+/*:181*//*186:*/
+#line 3818 "web2w.w"
+
+case PEND:wputs("} "),t= t->next;
+if(t->tag==PSEMICOLON)t= t->next;
+break;
+/*:186*//*192:*/
+#line 3964 "web2w.w"
+
+case PPROCEDURE:
+DBG(dbgcweb,"Converting procedure heading in line %d\n",t->lineno);
+wprint("void");
+t= wprint_to(t->next,t->link);
+if(t->tag!=POPEN)wputs("(void)");
+break;
+/*:192*//*193:*/
+#line 3983 "web2w.w"
+
+case PDEFPARAMID:
+case PDEFREFID:
+{token*varlist= t,*type= t->link;
+DBG(dbgcweb,"Converting parameter list in line %d\n",t->lineno);
+while(type->tag==PDEFPARAMID||type->tag==PDEFREFID)type= type->link;
+while(true)
+{wprint_to(type,type->link);
+if(varlist->tag==PDEFREFID)wputs(" *");
+wid(varlist);
+varlist= varlist->link;
+if(varlist!=type)wput(',');
+else break;
+}
+t= type->link;
+DBG(dbgcweb,"Finishing parameter list in line %d\n",t->lineno);
+break;
+}
+/*:193*//*194:*/
+#line 4006 "web2w.w"
+
+case CREFID:
+wputs("(*"),wid(t),wput(')');
+t= t->next;
+break;
+/*:194*//*197:*/
+#line 4054 "web2w.w"
+
+case PCALLID:
+DBG(dbgcweb,"Converting call in line %d\n",t->lineno);
+wid(t);
+if(SYM(t)->value==1)wputs("()");
+t= t->next;break;
+/*:197*//*198:*/
+#line 4068 "web2w.w"
+
+case POPEN:
+wput('(');
+if(t->up==NULL||SYM(t->up)->value==0)
+t= wprint_to(t->next,t->link);
+else
+{int param_mask= SYM(t->up)->value;
+token*close= t->link;
+t= t->next;
+if(param_mask<0)wput('&');
+param_mask= param_mask<<1;
+while(t!=close)
+{if(t->tag==PCOMMA)
+{wputs(", ");t= t->next;
+if(param_mask<0)wput('&');
+param_mask= param_mask<<1;
+}
+else
+t= wtoken(t);
+}
+}
+break;
+/*:198*//*199:*/
+#line 4102 "web2w.w"
+
+case PFUNCTION:
+{token*param= t->link;
+token*type;
+DBG(dbgcweb,"Converting function heading in line %d\n",t->lineno);
+if(param->tag==POPEN)type= param->link->link;
+else type= param;
+wprint_to(type,type->link);
+wprint_to(t->next,t->link);
+if(param->tag!=POPEN)wputs("(void)");
+else wprint_to(param,param->link->next);
+t= type->link;
+break;
+}
+/*:199*//*206:*/
+#line 4251 "web2w.w"
+
+case PFBEGIN:
+DBG(dbgcweb,"Adding scaled %s; in line %d\n",SYM(t)->name,t->lineno);
+wprint("scaled");wid(t);wputs("; ");
+t= t->next;
+break;
+case PFEND:
+DBG(dbgcweb,"Adding return %s; in line %d\n",SYM(t)->name,t->lineno);
+wprint("return");wid(t);wputs(";}");
+t= t->next;
+break;
+/*:206*//*207:*/
+#line 4265 "web2w.w"
+
+case PFUNCID:
+DBG(dbgcweb,"function %s in line %d assigns result variable\n",SYM(t)->name,t->lineno);
+wid(t);
+t= t->next;
+break;
+case CRETURN:
+DBG(dbgcweb,"Converted function return %s in line %d\n",SYM(t)->name,t->lineno);
+wprint("return");
+t= t->next;
+break;
+case CPROCRETURN:
+if(t->sym_ptr->value<=0)wprint("return");
+else wprint("goto end");
+t= t->next;
+break;
+/*:207*//*208:*/
+#line 4291 "web2w.w"
+
+case CMAIN:wprint("int main(void) {");t= t->next;break;
+case CMAINEND:wprint("return 0; }");t= t->next;break;
+/*:208*/
+#line 2137 "web2w.w"
+
+default:wprint(token2string(t));t= t->next;break;
+}
+level--;
+return t;
+}
+/*:102*//*104:*/
+#line 2153 "web2w.w"
+
+static token*wprint_to(token*t,token*end)
+{while(t!=end)
+t= wtoken(t);
+return t;
+}
+
+static token*wskip_to(token*t,token*end)
+{while(t!=end)
+t= t->next;
+return t;
+}
+/*:104*//*112:*/
+#line 2260 "web2w.w"
+
+static bool following_directive(token*t)
+{while(true)
+if(WDEBUG<=t->tag&&t->tag<=WGUBED)return true;
+else if(t->tag==ATPLUS||t->tag==ATEX||t->tag==ATSEMICOLON||
+t->tag==NL||t->tag==INDENT)t= t->next;
+else return false;
+}
+/*:112*//*119:*/
+#line 2398 "web2w.w"
+
+void wid(token*t)
+{if(alfanum||comma)wput(' ');
+if(t->previous->tag==ATEX)wputs("@!");
+wputs(SYM(t)->name);
+}
+/*:119*//*132:*/
+#line 2673 "web2w.w"
+
+static int convert_arg(token*arg)
+{if(arg->tag==STRING)
+{symbol*s= symbol_table[arg->sym_no];
+s->value--;
+DBG(dbgstring,"Eliminating string argument %s (%d) in line %d\n",s->name,s->value,arg->lineno);
+arg->tag= PSTRING;
+return 1;
+}
+else if(arg->tag==CHAR)
+{arg->tag= PSTRING;
+return 1;
+}
+return 0;
+}
+void pstring_args(token*id,token*arg)
+{if(arg->tag==PCOLON||arg->tag==CREFID)return;
+if(id->sym_no==overflow_no||id->sym_no==prompt_file_name_no)
+{CHECK(arg->tag==PCOMMA,"function should have two arguments in line %d",id->lineno);
+convert_arg(arg->previous);
+}
+else if(id->sym_no==print_no)
+{if(convert_arg(arg))id->sym_no= print_str_no;
+}
+else if(id->sym_no==print_str_no
+||id->sym_no==print_nl_no
+||id->sym_no==fatal_error_no
+)
+convert_arg(arg);
+}
+/*:132*//*133:*/
+#line 2709 "web2w.w"
+
+void pstring_assign(token*id,token*val)
+{if(id->tag==PID&&(id->sym_no==help_line_no||id->sym_no==max_reg_help_line_no))
+{SYM(val)->value--;
+DBG(dbgstring,"Eliminating string assignment %s (%d) in line %d\n",
+SYM(val)->name,SYM(val)->value,val->lineno);
+val->tag= PSTRING;
+}
+else
+DBG(dbgstring,"No string assignment %s (%d) in line %d\n",
+SYM(val)->name,SYM(val)->value,val->lineno);
+}
+/*:133*//*135:*/
+#line 2732 "web2w.w"
+
+int predefine(char*name,int tag,int value)
+{int sym_no= get_sym_no(name);
+symbol*s= symbol_table[sym_no];
+s->tag= tag;
+s->value= value;
+return sym_no;
+}
+/*:135*//*150:*/
+#line 2990 "web2w.w"
+
+void clabel(token*t,int use)
+{
+if(t->tag==NMACRO)
+{SYM(t)->obsolete= true;
+SYM(t)->value+= use;
+t->tag= CLABEL;
+}
+else if(t->tag==CLABEL)
+SYM(t)->value+= use;
+else if(t->tag==PRETURN)
+SYM(t)->value+= use;
+else
+{if(t->tag==PINTEGER)
+t->tag= CLABELN;
+return;
+}
+DBG(dbgstring,"Using label %s (%d) in line %d\n",SYM(t)->name,SYM(t)->value,t->lineno);
+}
+/*:150*//*168:*/
+#line 3340 "web2w.w"
+
+int generate_constant(token*t,char sign,int value)
+{if(t->tag==PTYPECHAR||t->tag==PINTEGER)
+{if(sign=='-')return value-t->value;else return value+t->value;}
+else if(t->tag==NMACRO||t->tag==PCONSTID)
+{if(sign!=0)wput(sign);wprint(token2string(t->previous));
+return value;
+}
+if(t->tag==PPLUS)
+{if(t->previous!=NULL)value= generate_constant(t->previous,sign,value);
+if(sign==0)sign= '+';
+return generate_constant(t->next,sign,value);
+}
+if(t->tag==PMINUS)
+{if(t->previous!=NULL)value= generate_constant(t->previous,sign,value);
+if(sign==0||sign=='+')sign= '-';else sign= '+';
+return generate_constant(t->next,sign,value);
+}
+else
+ERROR("Unexpected tag %s while generating a constant expression in line %d",TAG(t),t->lineno);
+}
+/*:168*//*175:*/
+#line 3464 "web2w.w"
+
+token*winsert_after(token*t,int tag,char*text)
+{token*n;
+DBG(dbgcweb,"Inserting token %s after %s in line %d\n",
+tagname(tag),TAG(t),t->lineno);
+n= new_token(tag);
+n->next= t->next;
+n->next->previous= n;
+n->previous= t;
+t->next= n;
+n->sequenceno= t->sequenceno;
+n->lineno= t->lineno;
+n->text= text;
+return n;
+}
+/*:175*//*178:*/
+#line 3504 "web2w.w"
+
+int dead_end(token*t,int lineno)
+{DBG(dbgbreak,"Searching for dead end in line %d:\n",lineno);
+while(true)
+{DBG(dbgbreak,"\t%s\n",TAG(t));
+if(t->tag==PGOTO||t->tag==PEXIT||t->tag==CPROCRETURN)return true;
+else if(t->tag==PCOLON)t= t->next;
+else if(t->tag==PBEGIN)t= t->previous;
+else if(t->tag==PSEMICOLON||t->tag==CCASE)
+{if(t->next->tag==CEMPTY)t= t->previous;else t= t->next;}
+else return false;
+}
+}
+/*:178*//*183:*/
+#line 3658 "web2w.w"
+
+void mark_for_variable(token*id,int lineno,int value,int direction)
+{int replace= 0;
+int bits= 0;
+if(direction==VAR_LOOP)replace= 1;
+else if(direction==DOWNTO_LOOP)
+{if(value>=0)bits= 0;
+else if(value> INT8_MIN)bits= 6;
+else if(value> INT16_MIN)bits= 14;
+else bits= 15;
+}
+else
+{if(value<0)bits= 0;
+else if(value<INT8_MAX)bits= 6;
+else if(value<UINT8_MAX)bits= 7;
+else if(value<INT16_MAX)bits= 14;
+else if(value<UINT16_MAX)bits= 15;
+else if(value<INT32_MAX)bits= 31;
+else bits= 32;
+}
+SYM(id)->for_ctrl= FOR_CTRL_PACK(lineno,replace,direction,bits);
+}
+/*:183*//*187:*/
+#line 3854 "web2w.w"
+
+bool wneeds_semicolon(token*p)
+{while(p!=NULL)
+{switch(p->tag)
+{case PCASE:case PBEGIN:case CIGNORE:return false;
+case PSEMICOLON:
+case CCASE:case PELSE:p= p->next;continue;
+case PIF:case PWHILE:case PFOR:case PCOLON:p= p->previous;continue;
+case PASSIGN:case PFUNCID:case PCALLID:case PREPEAT:
+case PRETURN:case CRETURN:case CPROCRETURN:case PGOTO:case PEXIT:case CEMPTY:
+default:return true;
+}
+}
+return false;
+}
+
+static token*wback(token*t)
+{while(true)
+{CHECK(t->previous!=NULL,"Error searching backward");
+t= t->previous;
+switch(t->tag)
+{case PSEMICOLON:case CSEMICOLON:case PEND:return t;
+case RIGHT:while(t->tag!=PLEFT&&t->tag!=MLEFT)t= t->previous;
+break;
+case ATGREATER:case EQ:case HASH:case ATDOLLAR:case NMACRO:case OMACRO:
+case OCTAL:case HEX:case CHAR:case STRING:case PRETURN:case CEMPTY:
+return t;
+case CIGNORE:continue;
+default:break;
+}
+if(t->tag> FIRST_PASCAL_TOKEN)
+return t;
+}
+}
+
+void wsemicolon(token*p,token*t)
+{t= wback(t);
+if(t->tag!=PSEMICOLON&&t->tag!=CSEMICOLON&&t->tag!=PEND)
+{if(wneeds_semicolon(p))
+{DBG(dbgsemicolon,"inserting ; in line %d\n",t->lineno);
+if(t->next->tag==ATSEMICOLON)
+{t->next->tag= CSEMICOLON;t->next->text= ";";}
+else
+winsert_after(t,CSEMICOLON,";");
+}
+else if(t->next->tag!=ATSEMICOLON&&t->next->tag!=PSEMICOLON)
+{
+DBG(dbgsemicolon,"inserting @; in line %d\n",t->lineno);
+winsert_after(t,ATSEMICOLON,"@;");
+}
+
+}
+}
+/*:187*//*188:*/
+#line 3917 "web2w.w"
+
+void wend(token*p,token*t)
+{if(p->tag==PSEMICOLON&&p->next->tag==PCOLON&&
+p->next->next->tag==CEMPTY&&p->next->previous->tag==CLABEL&&
+p->next->previous->sym_no==exit_no)
+{token*label= p->next->previous;
+DBG(dbgreturn,"Trailing exit: found preceding line %d\n",t->lineno);
+label->tag= CIGNORE;
+SYM(label)->value= -1000;
+CHECK(label->next->tag==PCOLON,"Expected colon after label in line %d\n",label->lineno);
+label->next->tag= CIGNORE;
+p->next->tag= CIGNORE;
+}
+else
+DBG(dbgreturn,"No trailing exit: found preceding line %d\n",t->lineno);
+}
+
+/*:188*//*200:*/
+#line 4135 "web2w.w"
+
+static bool wtail(token*t)
+{CHECK(t!=NULL,"Unexpected NULL token while searching for tail statements");
+switch(t->tag)
+{case PSEMICOLON:case PELSE:case CCASE:
+return wtail(t->next)&&wtail(t->previous);
+case PCOLON:
+return wtail(t->next);
+case PRETURN:case CIGNORE:case CEMPTY:
+return true;
+case PASSIGN:case PCALLID:
+case PFUNCID:case CRETURN:case CPROCRETURN:
+case PWHILE:case PREPEAT:case PFOR:
+case PEXIT:case PGOTO:
+return false;
+case PBEGIN:case PIF:case PCASE:
+return wtail(t->previous);
+default:ERROR("Unexpected tag %s while searching for tail statements",TAG(t));
+}
+}
+/*:200*//*202:*/
+#line 4175 "web2w.w"
+
+void wreturn(token*t,int tail,token*link)
+{CHECK(t!=NULL,"Unexpected NULL token while searching for return statements");
+switch(t->tag)
+{case PSEMICOLON:
+if(t->next->tag==PRETURN)
+wreturn(t->previous,true,t->next);
+else
+{wreturn(t->next,tail,link);
+if(wtail(t->next))wreturn(t->previous,tail,link);
+else wreturn(t->previous,false,NULL);
+}
+return;
+case PCOLON:
+wreturn(t->next,tail,link);
+return;
+case PASSIGN:case PCALLID:
+case PRETURN:case PEXIT:case PGOTO:case CIGNORE:case CEMPTY:
+return;
+case PWHILE:case PREPEAT:case PFOR:
+wreturn(t->previous,false,NULL);return;
+case PELSE:case CCASE:
+wreturn(t->next,tail,link);wreturn(t->previous,tail,link);return;
+case PCASE:case PIF:case PBEGIN:
+wreturn(t->previous,tail,link);return;
+case PFUNCID:
+if(tail)
+{DBG(dbgreturn,"Converting assignment to function in line %d\n",t->lineno);
+t->tag= CRETURN;IGN(t->next);
+if(link!=NULL)
+{link->sym_ptr->value--;
+t->sym_ptr= link->sym_ptr;
+IGN(link),IGN(link->next);
+DBG(dbgreturn,"Eliminating label %s (%d) in line %d\n",
+link->sym_ptr->name,link->sym_ptr->value,t->lineno);
+}
+}
+return;
+case CRETURN:
+if(t->sym_ptr!=NULL){
+t->sym_ptr->value--;
+DBG(dbgreturn,"Eliminating label %s (%d) in line %d\n",
+t->sym_ptr->name,t->sym_ptr->value,t->lineno);
+}
+return;
+default:ERROR("Unexpected tag %s in line %d"
+" while searching for return statements",TAG(t),t->lineno);
+}
+}
+/*:202*//*210:*/
+#line 4380 "web2w.w"
+
+void usage(void)
+{fprintf(stderr,
+"Usage: web2w [parameters] filename.web\n"
+"Parameters:\n"
+"\t -p \t generate a pascal output file\n"
+"\t -o file \t specify an output file name\n"
+"\t -l \t redirect stderr to a log file\n"
+"\t -y \t generate a trace while parsing pascal\n"
+"\t -d XX\t hexadecimal debug value. OR together these values:\n"
+"\t \t \t XX=1 basic debugging\n"
+"\t \t \t XX=2 flex debugging\n"
+"\t \t \t XX=4 link debugging\n"
+"\t \t \t XX=8 token debugging\n"
+"\t \t \t XX=10 identifier debugging\n"
+"\t \t \t XX=20 pascal tokens debugging\n"
+"\t \t \t XX=40 expansion debugging\n"
+"\t \t \t XX=80 bison debugging\n"
+"\t \t \t XX=100 pascal parser debugging\n"
+"\t \t \t XX=200 cweb debugging\n"
+"\t \t \t XX=400 join debugging\n"
+"\t \t \t XX=800 string pool debugging\n"
+"\t \t \t XX=1000 for variables debugging\n"
+"\t \t \t XX=2000 for real division debugging\n"
+"\t \t \t XX=4000 for macro debugging\n"
+"\t \t \t XX=8000 for array debugging\n"
+"\t \t \t XX=10000 for return debugging\n"
+"\t \t \t XX=20000 for semicolon debugging\n"
+"\t \t \t XX=40000 for break debugging\n"
+);
+exit(1);
+}
+/*:210*/
+#line 514 "web2w.w"
+
+
+int main(int argc,char*argv[])
+{/*214:*/
+#line 4455 "web2w.w"
+
+{int mk_logfile= 0,mk_pascal= 0,baselength= 0;
+char*w_file_name= NULL;
+ww_flex_debug= 0;
+ppdebug= 0;
+if(argc<2)usage();
+argv++;
+while(*argv!=NULL)
+{if((*argv)[0]=='-')
+{char option= (*argv)[1];
+switch(option)
+{default:usage();
+case'p':mk_pascal= 1;break;
+case'o':argv++;w_file_name= *argv;break;
+case'l':mk_logfile= 1;break;
+case'y':ppdebug= 1;break;
+case'd':
+argv++;if(*argv==NULL)usage();
+debugflags= strtol(*argv,NULL,16);
+if(debugflags&dbgflex)ww_flex_debug= 1;
+if(debugflags&dbgbison)ppdebug= 1;
+break;
+}
+}
+else
+{strncpy(basename,*argv,MAX_NAME-1);
+baselength= strlen(basename)-4;
+if(baselength<1||strncmp(basename+baselength,".web",4)!=0)usage();
+basename[baselength]= 0;
+if(*(argv+1)!=NULL)usage();
+}
+argv++;
+}
+/*215:*/
+#line 4501 "web2w.w"
+
+if(mk_logfile)
+{basename[baselength]= 0;
+strcat(basename,".log");
+logfile= freopen(basename,"w",stderr);
+if(logfile==NULL)
+{fprintf(stderr,"Unable to open logfile %s",basename);
+logfile= stderr;
+}
+wwout= logfile;
+}
+else
+{logfile= stderr;
+wwout= stderr;
+}
+basename[baselength]= 0;
+strcat(basename,".web");
+wwin= fopen(basename,"r");
+if(wwin==NULL)ERROR("Unable to open input file %s",basename);
+if(w_file_name==NULL)
+{w_file_name= basename;
+basename[baselength]= 0;
+strcat(basename,".w");
+}
+w= fopen(w_file_name,"w");
+if(w==NULL)ERROR("Unable to open output file %s",w_file_name);
+if(mk_pascal)
+{basename[baselength]= 0;
+strcat(basename,".pas");
+pascal= fopen(basename,"w");
+if(pascal==NULL)ERROR("Unable to open pascal file %s",basename);
+}
+/*:215*/
+#line 4488 "web2w.w"
+
+}
+/*:214*/
+#line 517 "web2w.w"
+
+/*5:*/
+#line 552 "web2w.w"
+
+/*23:*/
+#line 768 "web2w.w"
+
+first_token= last_token= new_token(HEAD);
+first_token->text= "";
+/*:23*//*63:*/
+#line 1358 "web2w.w"
+
+program= first_token;
+/*:63*//*115:*/
+#line 2350 "web2w.w"
+
+float_constant_no= predefine("float_constant",ID,0);
+/*:115*//*136:*/
+#line 2742 "web2w.w"
+
+print_str_no= predefine("print_str",PPROCID,0);
+empty_string_no= predefine("\"\"",PID,1);
+help_line_no= predefine("help_line",ID,0);
+print_no= predefine("print",PPROCID,0);
+overflow_no= predefine("overflow",PPROCID,0);
+print_err_no= predefine("print_err",PPROCID,0);
+print_nl_no= predefine("print_nl",PPROCID,0);
+fatal_error_no= predefine("fatal_error",PPROCID,0);
+prompt_file_name_no= predefine("prompt_file_name",PPROCID,0);
+max_reg_help_line_no= predefine("max_reg_help_line",ID,0);
+/*:136*//*140:*/
+#line 2801 "web2w.w"
+
+TeXinputs_no= predefine("\"TeXinputs:\"",PID,0);
+TeXfonts_no= predefine("\"TeXfonts:\"",PID,0);
+fmt_no= predefine("\".fmt\"",PID,0);
+math_spacing_no= predefine(
+"\"0234000122*4000133**3**344*0400400*000000234000111*1111112341011\"",PID,1);
+/*:140*//*153:*/
+#line 3027 "web2w.w"
+
+exit_no= get_sym_no("exit");
+/*:153*//*205:*/
+#line 4239 "web2w.w"
+
+x_over_n= get_sym_no("x_over_n");
+xn_over_d= get_sym_no("xn_over_d");
+/*:205*//*209:*/
+#line 4324 "web2w.w"
+
+predefine("put",PPROCID,0);
+predefine("get",PPROCID,0);
+predefine("reset",PPROCID,0);
+predefine("rewrite",PPROCID,0);
+predefine("abs",PFUNCID,0);
+predefine("odd",PFUNCID,0);
+predefine("eof",PFUNCID,0);
+predefine("eoln",PFUNCID,0);
+predefine("round",PFUNCID,0);
+predefine("ord",PFUNCID,0);
+predefine("chr",PFUNCID,0);
+predefine("close",PPROCID,0);
+predefine("read",PPROCID,0);
+predefine("read_ln",PPROCID,0);
+predefine("write",PPROCID,0);
+predefine("write_ln",PPROCID,0);
+predefine("break",PPROCID,0);
+predefine("break_in",PPROCID,0);
+predefine("erstat",PFUNCID,0);
+predefine("false",PCONSTID,0);
+predefine("true",PCONSTID,1);
+/*:209*/
+#line 553 "web2w.w"
+
+wwlex();
+/*67:*/
+#line 1423 "web2w.w"
+
+TOK("",ATP);PROGRAM;PUSH;TOK("",PEOF);TOK("",WEBEOF);POP;
+/*:67*//*68:*/
+#line 1430 "web2w.w"
+
+if(debugflags&dbgtoken)
+{token*t= first_token;
+while(t!=NULL){MESSAGE(THE_TOKEN(t));t= t->next;}
+}
+if(debugflags&dbgid)
+{int i;
+for(i= free_symbols;i<MAX_SYMBOLS;i++)
+MESSAGE("symbol[%d]=%s\n",i,symbols[i].name);
+}
+/*:68*//*82:*/
+#line 1775 "web2w.w"
+
+SYM_PTR("debug")->obsolete= 1;
+SYM_PTR("gubed")->obsolete= 1;
+SYM_PTR("stat")->obsolete= 1;
+SYM_PTR("tats")->obsolete= 1;
+SYM_PTR("init")->obsolete= 1;
+SYM_PTR("tini")->obsolete= 1;
+/*:82*//*90:*/
+#line 1917 "web2w.w"
+
+SYM_PTR("return")->obsolete= 1;
+SYM_PTR("endcases")->obsolete= 1;
+SYM_PTR("othercases")->obsolete= 1;
+SYM_PTR("mtype")->obsolete= 1;
+SYM_PTR("final_end")->obsolete= 1;
+/*:90*//*121:*/
+#line 2427 "web2w.w"
+
+SYM_PTR("xclause")->name= "else";
+SYM_PTR("switch")->name= "get_cur_chr";
+SYM_PTR("continue")->name= "resume";
+SYM_PTR("exit")->name= "end";
+SYM_PTR("free")->name= "is_free";
+SYM_PTR("int")->name= "i";
+SYM_PTR("remainder")->name= "rem";
+/*:121*/
+#line 555 "web2w.w"
+
+/*:5*/
+#line 518 "web2w.w"
+
+/*93:*/
+#line 2000 "web2w.w"
+
+program= first_token->link;
+pp_push(program->link,program->next,0,NULL);
+ppparse();
+/*:93*/
+#line 519 "web2w.w"
+
+/*101:*/
+#line 2119 "web2w.w"
+
+wprint_to(first_token,last_token);
+/*:101*//*127:*/
+#line 2573 "web2w.w"
+
+wputs("\n@ Appendix: Replacement of the string pool file.\n");
+{token*str_k;
+int i,k;
+/*128:*/
+#line 2588 "web2w.w"
+
+wputs("@d str_0_255 ");
+for(k= 0;k<256;k++)
+{if((k&0xF)==0)wputs("\t\"");
+if((/*129:*/
+#line 2625 "web2w.w"
+
+(k<' ')||(k> '~')
+/*:129*/
+#line 2592 "web2w.w"
+))
+{wputs("^^");
+if(k<0100&&k+0100=='@')wputs("@@");
+else if(k<0100&&k+0100=='\\')wputs("\\\\");
+else if(k<0100)wput(k+0100);
+else if(k<0200&&k-0100=='@')wputs("@@");
+else if(k<0200)wput(k-0100);
+#define HEXDIGIT(x) ((x)<10?((x)+'0'):((x)-10+'a'))
+else wput(HEXDIGIT(k/16)),wput(HEXDIGIT(k%16));
+}
+else if(k=='"')wputs("\\\"");
+else if(k=='\\')wputs("\\\\");
+else if(k=='@')wputs("@@");
+else wput(k);
+if((k&0xF)==0xF)wputs("\"@/\n");
+}
+wputs("@d str_start_0_255");
+i= 0;
+for(k= 0;k<256;k++)
+{if((k&0xF)==0)wput('\t');
+wputi(i);
+if((/*129:*/
+#line 2625 "web2w.w"
+
+(k<' ')||(k> '~')
+/*:129*/
+#line 2613 "web2w.w"
+))
+{if(k<0100)i= i+3;
+else if(k<0200)i= i+3;
+else i= i+4;
+}
+else i= i+1;
+wput(',');
+if((k&0xF)==0xF)wputs("@/\n");
+}
+/*:128*/
+#line 2577 "web2w.w"
+
+for(str_k= first_string;str_k!=NULL;str_k= str_k->link)
+/*130:*/
+#line 2630 "web2w.w"
+
+{symbol*s= SYM(str_k);
+if(s->value> 0)
+{s->value= 0;
+wputs("@ \n");
+wputs("@d str_"),wputi(k),wput(' '),wputs(s->name),wput('\n');
+/*138:*/
+#line 2790 "web2w.w"
+
+if(str_k->sym_no==empty_string_no)wputs("@d empty_string "),wputi(k);
+else if(str_k->sym_no==TeXinputs_no)wputs("@d TEX_area "),wputi(k);
+else if(str_k->sym_no==TeXfonts_no)wputs("@d TEX_font_area "),wputi(k);
+else if(str_k->sym_no==fmt_no)wputs("@d format_extension "),wputi(k);
+else if(str_k->sym_no==math_spacing_no)wputs("@d math_spacing "),wputi(k);
+/*:138*/
+#line 2636 "web2w.w"
+
+else
+wputs("@<|"),wputs(s->name),wputs("|@>=@+"),wputi(k);
+wput('\n');
+k++;
+}
+}
+/*:130*/
+#line 2579 "web2w.w"
+
+/*141:*/
+#line 2817 "web2w.w"
+
+wputs("\n@ All the above strings together make up the string pool.\n"
+"@<|str_pool| initialization@>=\n"
+"str_0_255\n");
+for(i= 256;i<k;i++)
+{wputs("str_"),wputi(i);
+if((i&7)==7)wputs("@/\n");else wput(' ');
+}
+wputs("\n\n@ @<|str_start| initialization@>=\n"
+"str_start_0_255\n");
+for(i= 256;i<k;i++)
+{wputs("str_start_"),wputi(i),wput(',');
+if((i&3)==3)wput('\n');else wput(' ');
+}
+wputs("str_start_"),wputi(k);
+wputs("\n\n"
+"@ We still need to define the start locations of the strings.\n"
+"@<prepare for string pool initialization@>=\n"
+"typedef enum {\n"
+"str_start_256=sizeof(str_0_255)-1,\n");
+for(i= 257;i<=k;i++)
+wputs("str_start_"),wputi(i),wputs("=str_start_"),wputi(i-1),
+wputs("+sizeof(str_"),wputi(i-1),wputs(")-1,@/\n");
+
+wputs("str_start_end } str_starts;\n"
+"\n@ @<|pool_ptr| initialization@>= str_start_"),wputi(k),wputs("\n"
+"\n@ @<|str_ptr| initialization@>= "),wputi(k),wput('\n');
+/*:141*/
+#line 2580 "web2w.w"
+
+}
+/*:127*/
+#line 520 "web2w.w"
+
+/*13:*/
+#line 701 "web2w.w"
+
+DBG(dbgbasic,"free tokens = %d\n",free_tokens);
+/*:13*//*31:*/
+#line 867 "web2w.w"
+
+DBG(dbgbasic,"free strings = %d\n",free_strings);
+/*:31*//*36:*/
+#line 944 "web2w.w"
+
+DBG(dbgbasic,"free symbols = %d\n",free_symbols);
+/*:36*//*57:*/
+#line 1279 "web2w.w"
+
+DBG(dbgbasic,"free modules = %d\n",free_modules);
+/*:57*/
+#line 521 "web2w.w"
+
+return 0;
+}
+/*:1*/
diff --git a/web/web2w/web2w.h b/web/web2w/web2w.h
new file mode 100644
index 0000000000..0a3ed85d15
--- /dev/null
+++ b/web/web2w/web2w.h
@@ -0,0 +1,347 @@
+/*
+This file is part of web2w.
+Copyright 2017 Martin Ruckert
+
+web2w is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web2w is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with web2w. If not, see <http://www.gnu.org/licenses/>.
+
+Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+*/
+/*2:*/
+#line 532 "web2w.w"
+
+/*6:*/
+#line 585 "web2w.w"
+
+#define TEX INITIAL
+/*:6*//*7:*/
+#line 644 "web2w.w"
+
+typedef struct token{
+int tag;
+struct token*next,*previous,*link,*up;
+union{
+/*8:*/
+#line 661 "web2w.w"
+
+struct{
+int sequenceno;
+int lineno;
+/*9:*/
+#line 675 "web2w.w"
+
+char*text;
+/*:9*//*38:*/
+#line 995 "web2w.w"
+
+int sym_no;
+struct symbol*sym_ptr;
+/*:38*/
+#line 665 "web2w.w"
+
+}
+/*:8*/
+#line 649 "web2w.w"
+;
+/*94:*/
+#line 2012 "web2w.w"
+
+struct{
+int value;
+}
+/*:94*/
+#line 650 "web2w.w"
+;
+};
+}token;
+/*:7*//*10:*/
+#line 685 "web2w.w"
+
+extern const char*tagname(int tag);
+/*:10*//*15:*/
+#line 719 "web2w.w"
+
+extern int wwlineno;
+/*:15*//*17:*/
+#line 728 "web2w.w"
+
+extern int sequenceno;
+#define SEQ (sequenceno++)
+/*:17*//*18:*/
+#line 736 "web2w.w"
+
+void seq(token*t,token*s);
+/*:18*//*20:*/
+#line 749 "web2w.w"
+
+extern token*add_token(int tag);
+/*:20*//*22:*/
+#line 761 "web2w.w"
+
+extern token*last_token;
+/*:22*//*25:*/
+#line 794 "web2w.w"
+
+#define TOK(string,tag) (add_token(tag)->text= string)
+/*:25*//*26:*/
+#line 807 "web2w.w"
+
+#define COPY copy_string(wwtext)
+/*:26*//*27:*/
+#line 819 "web2w.w"
+
+#define BOS new_string()
+#define ADD add_string(wwtext)
+#define EOS (string_length()> 0?TOK(end_string(),TEXT):0)
+/*:27*//*28:*/
+#line 831 "web2w.w"
+
+extern char*new_string(void);
+extern void add_string(char*str);
+extern char*end_string(void);
+extern char*copy_string(char*str);
+extern int string_length(void);
+/*:28*//*33:*/
+#line 920 "web2w.w"
+
+typedef struct symbol{
+char*name;
+int tag;
+int obsolete;
+int for_ctrl;
+int value;
+struct symbol*link;
+token*type;
+token*eq;
+}symbol;
+extern int get_sym_no(char*name);
+extern symbol*symbol_table[];
+/*:33*//*39:*/
+#line 1001 "web2w.w"
+
+#define SYM_PTR(name) symbol_table[get_sym_no(name)]
+#define SYMBOL {int s= get_sym_no(yytext);add_token(symbol_table[s]->tag)->sym_no= s;}
+#define SYM(t) (symbol_table[(t)->sym_no])
+/*:39*//*41:*/
+#line 1030 "web2w.w"
+
+extern void localize(token*t);
+/*:41*//*42:*/
+#line 1037 "web2w.w"
+
+extern void scope_open(void);
+extern void scope_close(void);
+/*:42*//*47:*/
+#line 1137 "web2w.w"
+
+extern void ww_push(token*t);
+extern token*ww_pop(token*t);
+extern int ww_is(int tag);
+/*:47*//*49:*/
+#line 1180 "web2w.w"
+
+#define PUSH ww_push(last_token)
+#define PUSH_NULL ww_push(NULL)
+#define POP ww_pop(last_token)
+#define POP_NULL (ADD, POP)
+#define POP_MLEFT (EOS, TOK("}",RIGHT), BEGIN(MIDDLE), POP)
+#define POP_PLEFT (EOS, TOK("}",RIGHT), BEGIN(PASCAL), POP)
+#define POP_LEFT (ww_is(MLEFT)? POP_MLEFT : (ww_is(PLEFT)? POP_PLEFT: POP_NULL))
+/*:49*//*50:*/
+#line 1204 "web2w.w"
+
+extern void wwstring(char*wwtext);
+#define WWSTRING wwstring(wwtext)
+/*:50*//*56:*/
+#line 1268 "web2w.w"
+
+typedef struct module{
+token*atless;
+token*atgreater;
+struct module*left,*right;
+}module;
+extern void add_module(token*atless);
+extern module*find_module(token*atless);
+/*:56*//*60:*/
+#line 1336 "web2w.w"
+
+#define AT_GREATER_EQ TOK("@>",ATGREATER), add_module(POP), TOK("=",EQ), PUSH, SEQ
+#define AT_GREATER TOK("@>",ATGREATER), find_module(POP)
+/*:60*//*61:*/
+#line 1349 "web2w.w"
+
+extern token*program;
+#define PROGRAM (program->link= last_token,program= last_token),TOK("",EQ)
+/*:61*//*64:*/
+#line 1378 "web2w.w"
+
+#define CHGTAG(t,x) ((t)->tag= (x))
+#define CHGID(t,x) (SYM(t)->tag= (x))
+#define CHGTYPE(t,x) (SYM(t)->type= (x))
+#define CHGVALUE(t,x) (SYM(t)->value= (x))
+#define CHGTEXT(t,x) ((t)->text= (x))
+/*:64*//*66:*/
+#line 1408 "web2w.w"
+
+extern void def_macro(token*eq,int tag);
+#define DEF_MACRO(tag) def_macro(last_token,tag),SEQ
+/*:66*//*69:*/
+#line 1470 "web2w.w"
+
+extern int pplex(void);
+extern void pperror(const char*message);
+/*:69*//*84:*/
+#line 1819 "web2w.w"
+
+extern int getval(token*t);
+/*:84*//*86:*/
+#line 1856 "web2w.w"
+
+#define SETVAL(t,val) SYM(t)->value= val
+/*:86*//*95:*/
+#line 2020 "web2w.w"
+
+token*join(int tag,token*left,token*right,int value);
+/*:95*//*106:*/
+#line 2178 "web2w.w"
+
+#define IGN(t) ((t)->tag= CIGNORE)
+/*:106*//*131:*/
+#line 2655 "web2w.w"
+
+extern void pstring_args(token*id,token*arg);
+extern void pstring_assign(token*id,token*val);
+/*:131*//*149:*/
+#line 2987 "web2w.w"
+
+extern void clabel(token*t,int use);
+/*:149*//*151:*/
+#line 3018 "web2w.w"
+
+extern int exit_no;
+#define TOK_RETURN {token *t= add_token(PRETURN); t->sym_no= exit_no; }
+/*:151*//*157:*/
+#line 3110 "web2w.w"
+
+#define LNK(from,to) ((from)?(seq((from),(to)),(from)->link= (to)):0)
+/*:157*//*163:*/
+#line 3214 "web2w.w"
+
+#define UP(from,to) ((from)->up= (to))
+/*:163*//*174:*/
+#line 3460 "web2w.w"
+
+extern token*winsert_after(token*t,int tag,char*text);
+/*:174*//*177:*/
+#line 3500 "web2w.w"
+
+int dead_end(token*t,int lineno);
+/*:177*//*182:*/
+#line 3631 "web2w.w"
+
+#define VAR_LOOP 0
+#define TO_LOOP 1
+#define DOWNTO_LOOP 2
+/*:182*//*184:*/
+#line 3685 "web2w.w"
+
+extern void mark_for_variable(token*id,int lineno,int value,int direction);
+#define FOR_CTRL_PACK(lineno,replace,direction,bits) \
+ ((lineno<<16)|((replace&0x1)<<15)|((direction&0x3)<<13)|(bits&0x1FFF))
+#define FOR_CTRL_LINE(X) (((X)>>16)&0xFFFF)
+#define FOR_CTRL_REPLACE(X) (((X)>>15)&1)
+#define FOR_CTRL_DIRECTION(X) (((X)>>13)&0x3)
+#define FOR_CTRL_BITS(X) ((X)&0x1FFF)
+/*:184*//*189:*/
+#line 3938 "web2w.w"
+
+extern void wsemicolon(token*p,token*t);
+extern void wend(token*p,token*t);
+/*:189*//*195:*/
+#line 4028 "web2w.w"
+
+extern unsigned int param_mask,param_bit;
+#define SIGN_BIT (~(((unsigned int)~0)>>1))
+#define START_PARAM (param_mask= 0,param_bit= SIGN_BIT)
+#define NEXT_PARAM (param_bit= param_bit>>1,CHECK(param_bit!=0,"Too many parameters"))
+#define REF_PARAM (param_mask= param_mask|param_bit)
+/*:195*//*201:*/
+#line 4164 "web2w.w"
+
+extern void wreturn(token*t,int tail,token*link);
+/*:201*//*203:*/
+#line 4233 "web2w.w"
+
+extern int x_over_n,xn_over_d;
+/*:203*//*211:*/
+#line 4414 "web2w.w"
+
+typedef enum{dbgnone= 0x0,
+dbgbasic= 0x1,
+dbgflex= 0x2,
+dbglink= 0x4,
+dbgtoken= 0x8,
+dbgid= 0x10,
+dbgpascal= 0x20,
+dbgexpand= 0x40,
+dbgbison= 0x80,
+dbgparse= 0x100,
+dbgcweb= 0x200,
+dbgjoin= 0x400,
+dbgstring= 0x800,
+dbgfor= 0x1000,
+dbgslash= 0x2000,
+dbgmacro= 0x4000,
+dbgarray= 0x8000,
+dbgreturn= 0x10000,
+dbgsemicolon= 0x20000,
+dbgbreak= 0x40000
+}debugmode;
+/*:211*//*212:*/
+#line 4441 "web2w.w"
+
+extern FILE*logfile;
+extern int ww_flex_debug;
+extern debugmode debugflags;
+/*:212*//*216:*/
+#line 4540 "web2w.w"
+
+#include <stdlib.h>
+#include <stdio.h>
+#define MESSAGE(...) (fprintf(logfile,__VA_ARGS__),fflush(logfile))
+#define ERROR(...) (fprintf(logfile,"ERROR: "),\
+ MESSAGE(__VA_ARGS__),fprintf(logfile,"\n"),exit(1))
+#define CHECK(condition,...) (!(condition)? ERROR(__VA_ARGS__):0)
+/*:216*//*217:*/
+#line 4550 "web2w.w"
+
+#define THE_TOKEN(t) "%d\t%d: %s\t[%s]\n",\
+ t->lineno,t->sequenceno,token2string(t),tagname(t->tag)
+/*:217*//*218:*/
+#line 4556 "web2w.w"
+
+#define DBG(flags,...) {if(debugflags & flags) MESSAGE(__VA_ARGS__);}
+#define DBGTOKS(flags, from,to) { if (debugflags & flags) \
+{ token *t= from; MESSAGE("<<");\
+ while (t!=to) { MESSAGE("%s",token2string(t)); t= t->next;}\
+MESSAGE(">>\n"); }}
+
+#define TAG(t) (t?tagname(t->tag):"NULL")
+
+#define DBGTREE(flags,t) DBG(flags,"%s -> %s | %s | %d\n",TAG(t),\
+ TAG(t->previous),TAG(t->next),t->value)
+
+/*:218*/
+#line 533 "web2w.w"
+
+/*:2*/
diff --git a/web/web2w/web2w.pdf b/web/web2w/web2w.pdf
new file mode 100644
index 0000000000..f2c7f1729a
--- /dev/null
+++ b/web/web2w/web2w.pdf
Binary files differ
diff --git a/web/web2w/web2w.w b/web/web2w/web2w.w
new file mode 100644
index 0000000000..caf059c1c4
--- /dev/null
+++ b/web/web2w/web2w.w
@@ -0,0 +1,4989 @@
+% This file is part of web2w.
+% Copyright 2017 Martin Ruckert
+%
+% web2w is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% web2w is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with web2w. If not, see <http://www.gnu.org/licenses/>.
+%
+% Martin Ruckert, Hochschule Muenchen, Lothstrasse 64, 80336 Muenchen
+%
+
+\input web2w.sty
+
+
+%% defining how to display certain C identifiers
+@s token int
+@s symbol int
+@s debug if
+@s gubed if
+@s stat if
+@s tats if
+@s init if
+@s tini if
+@s int8_t int
+@s uint8_t int
+@s int16_t int
+@s uint16_t int
+@s integer int
+@s real float
+@s repeat while
+@s until while
+@s bool int
+
+\makeindex
+\maketoc
+
+\titletrue
+
+\def\lastrevision{${}$Revision: 943 ${}$}
+\def\lastdate{${}$Date: 2017-07-28 14:37:50 +0200 (Fri, 28 Jul 2017) ${}$}
+
+\input titlepage.tex
+
+
+\frontmatter
+
+@
+
+\plainsection{Preface}
+
+This book describes a project to convert the \TeX\ source code\cite{Knuth:tex}
+written by \index{Knuth, Donald E.}Donald E. Knuth
+as a ``\WEB/''\cite{Knuth:lp} into a ``\cweb/''\cite{Knuth:cweb}.
+
+\itemize
+\item On December 9, 2016, I started to implement \web2w/ as a compiler for \WEB/ files
+which is described below. The compiler, as compilers usually do, reads an input file
+and continues to produce a parse tree.
+The resulting parse tree
+has two structures: a linear structure representing the
+linear order of the input file and a tree structure
+representing the embedded \Pascal/ program.
+Then the embedded \Pascal/ program needs to be translated into an
+equivalent \CEE/ program. And finally, the linear structure
+of the parse tree will be used to output a \cweb/ file.
+Small corrections on the resulting \cweb/ file are implemented by
+a patch file\index{patch file}.
+
+The overall goal is the generation of a
+\.{ctex.w} file that is as close as possible to the \.{tex.web} input file,
+and can be used to produce \.{ctex.tex} and \.{ctex.c} using the
+standard tools \.{ctangle} and \.{cweave}.
+
+The \TeX\ program can then be compiled from \.{ctex.c} and the \TeX\ documentation
+can be generated from \.{ctex.tex} by \TeX\ itself.
+
+This will simplify the tool chain necessary to generate \TeX\ from
+its ``sources''.
+
+\item On April 20, 2017, I was able to create the first ``hello world'' \.{dvi} file
+with my newly generated \TeX\ program and with that, I had reached
+version 0.1\index{version 0.1} of \web2w/.% revision 794
+
+\item On April 26, 2017, I succeeded for the first time
+to generate a program that would pass the trip test\index{trip test} and
+therefore can be called \TeX.
+This was then version 0.2\index{version 0.2} of \web2w/. % revision 808
+
+While the program at this point was a ``correct implementation of \TeX'',
+its form still needed further improvement.
+For example, the sizes of arrays were computed
+and occurred in the source as literal numbers. It would be appropriate
+for source code that instead the expression defining the
+array size were used to specify the array size\index{array size}.
+The use of \&{return} statements
+and the elimination of unused |end|
+labels also asked for improvement.
+
+\item On May 11, 2017, I completed version 0.3 of \web2w/. % revision 834
+Numerous improvements were added by then: some concerning the presentation
+of \web2w/ itself, others with the goal of generating better \cweb/ code for \TeX.
+I decided then to freeze the improvement of the code for a while and
+prepare this document for publication as a book.
+
+\item On July 27, 2017, I completed version 0.4 of \web2w/, % revision 935
+the first version that will be published as a book.
+More improvements (and more versions) are still to come.
+
+Of course, changes in the code part of \TeX\ will necessarily require
+changes in the documentation part. These can, however, not result from
+an automatic compilation. So the plan is to develop patch files\index{patch file}
+that generate from the latest 0.$x$~versions\index{0.1 version+0.$x$~version}
+improved 1.$y$~versions\index{1.y version+1.$y$~version}.
+These versions will share
+the same goal as version 0.$x$: producing a \cweb/ \TeX\ source file
+that is as close as possible to the original web source
+but with a documentation part of each section that reflects the changes
+made in the code.
+
+
+\item There is a long term goal that brought me to construct \.{web2w}
+in the first place: I plan to derive from the \TeX\ sources
+a new kind of \TeX\ that is influenced
+by the means and necessities of current software and hardware.
+The name for this new implementation will be \HINT/\index{HINT+\HINT/} which is,
+in the usual Open Software naming schema, the acronym for
+``\HINT/ is not \TeX''.
+
+For example, \HINT/ will accept UTF-8 input files because this
+is the defacto standard due to its use on the world wide web.
+Further, the machine model will be a processor that can
+efficiently handle 64-Bit values and has
+access to large amounts of main memory (several GByte).
+Last not least, I assume the availability of a good modern \CEE/
+compiler and will leave optimizations to the compiler if possible.
+
+The major change however will be the separation of the \TeX\ frontend\index{frontend}:
+the processing of \.{.tex} files, from the \TeX\ backend\index{backend}:
+the rendering of paragraphs and pages.
+
+Let's look, for example, at ebooks\index{ebook}:
+Current ebooks are of minor typographic quality. Just compiling
+\TeX\ sources to a standard ebook format, for example epub, does
+not work because a lot of information that is used by \TeX\ to
+produce good looking pages is not available in these formats.
+So I need to cut \TeX\ (or \HINT/) in two pieces: a frontend, that
+reads \TeX\ input and a backend that renders pixel on a page.
+The frontend will not know about the final page size because
+the size of the output medium may change while we read---for
+example by turning a mobile device from landscape to portrait
+mode. On the other hand, the computational resources of the backend
+are usually limited because a mobile device has a limited
+supply of electrical energy. So we should do as much as we
+can in the frontend and postpone what needs to be postponed
+to the backend. In between front and back, we need a nice
+new file format, that is compact and efficient, and transports
+whatever information is necessary between both parts.
+
+These are the possible next steps:
+\itemize
+\item As a first step, I will make a version of \TeX\ that produces a file listing all
+the contributions and insertions that \TeX\ sends to the page builder\index{page builder}.
+Let's call this a \.{.hint} file. This version of \TeX\ will become
+the final frontend.
+
+\item Next, I will use a second version of \TeX\ where I replace the
+reading of \.{.tex} files by the reading of a \.{.hint} file and feeding
+its content directly to the page builder. This version of \TeX\ will become
+the final backend. Once done, I can test the equation
+$\hbox{\TeX} =\hbox{\HINT/ frontend}+\hbox{\HINT/ backend}$.
+
+\item
+Next, I will replace the generation of dvi files in the backend
+by directly displaying the results in a ``viewer''.
+The ``viewer'' reads in a \.{.hint} file
+and uses it to display one single page
+at an arbitrary position. Using page up and page down buttons,
+the viewer can be used to navigate in the \.{.hint} file.
+At that point, it should be possible to change \.{vsize}\index{vsize+\.{vsize}} dynamically
+in the viewer.
+
+\item The hardest part will be the removal of \.{hsize}\index{hsize+\.{hsize}} dependencies
+from the frontend and moving them to the backend. I am still not sure
+how this will work out.
+
+\item Once the author of a \TeX\ document can no longer
+specify the final \.{hsize} and \.{vsize}, he or she would probably wish
+to be able to write conditional text for different ranges of \.{hsize}
+and \.{vsize}. So if the frontend encounters such tests it needs to include
+all variants in its output file.
+
+\item Last not least, most people use \LaTeX\index{LaTeX+\LaTeX}\ not plain \TeX.
+Hence, if I want many people to use \HINT/, it should be able to
+work with \LaTeX. As a first step,
+I looked at $\epsilon$-\TeX\index{e-TeX+$\epsilon$-\TeX}, and my
+cweb version of $\epsilon$-\TeX\ already passes the extended trip test\index{trip test} for
+$\epsilon$-\TeX. But I am not sure what \LaTeX\ needs
+beside the extensions of $\epsilon$-\TeX.
+So if someone knows, please let me know.
+
+\enditemize
+
+Enough now of these fussy ideas about the future. Let's turn to the present
+and the conversion of \TeX\ from \WEB/ to \cweb/.
+\enditemize
+
+\index{literate programming}
+\index{Knuth, Donald E.}
+
+\vskip 1cm
+\noindent {\it San Luis Obispo, CA\hfil\break
+June 27, 2017 \hfill Martin Ruckert}
+
+
+\tableofcontent
+
+\thefigindex
+\makefigindex
+
+\mainmatter
+
+\section{Introduction}
+\web2w/, the program that follows, was not written following an established
+software engineering workflow as we teach it in our software
+engineering classes. Instead the development of this program was driven by an ongoing
+exploration of the problem at hand where the daily dose of success
+or failure would determine the direction I would go on the next day.
+
+This description of my program development approach sounds a bit like
+``rapid prototyping''. But ``prototype'' implies the future existence of
+a ``final'' version and I do not intend to produce such a ``final'' version.
+Actually I have no intention to finish the prototype either,
+and I might change it in the future in unpredictable ways.
+I expect, however, that the speed of its further development will certainly
+decrease as I move on to other problems.
+Instead I have documented the development process
+as a literate program\index{literate programming}: the pages
+you are just reading. So in terms of literature, this is not an epic novel with
+a carefully designed plot, but it's more like the diary of an explorer who sets out
+to travel trough yet uncharted territories.
+
+The territory ahead of me was the program \TeX\ written
+by Donald E. Knuth\index{Knuth, Donald E.}
+ using the \WEB/\index{WEB+\WEB/}
+language as a literate program. As such, it contains snippets of code in the programming
+language \Pascal/---\Pascal/-H\index{Pascal H+\Pascal/-H} to be precise.
+\Pascal/-H is Charles Hedrick's\index{Hedrick, Charles} modification of a compiler
+for the DECsystem-10\index{DECsystem-10} that was originally developed at the
+University of Hamburg\index{University of Hamburg}
+(cf. \cite{GLN:pascal} see~\cite{Knuth:tex}).
+So I could not expect to find a pure ``Standard Pascal''.
+But then, the implementation of \TeX\ deliberately does not use the full set of
+features that the language \Pascal/ has to offer in order to make
+it easier to run \TeX\ on a
+large variety of machines. At the beginning, it was unclear to me what problems
+I would encounter with the subset of \Pascal/ that is actually used in \TeX.
+
+Further, the problem was not the translation of \Pascal/ to \CEE/.
+A program that does
+this is available in the \TeX\ Live\index{TeX Live+\TeX\ Live}
+project: \.{web2c}\cite{web2c} translates the \Pascal/
+code that is produced using \.{tangle}\index{tangle+\.{tangle}}
+from \.{tex.web} into \CEE/ code.
+The \CEE/ code that is generated this way can, however, not be regarded
+as human readable source code.
+The following example might illustrate this: Figure~\figref{tex_code}
+shows the \WEB/ code for the function |new_null_box|.
+The result of translating it to \CEE/
+by \.{web2c} can be seen in figure~\figref{tl_code}.
+In contrast, figure~\figref{ctex_code} shows what \web2w/ will achieve.
+
+\float{\line{\noindent
+\fig{\includefig{tex_new_null_box}%
+\caption{\WEB/ code for |new_null_box|}\label{tex_code}}%
+\hfill
+\fig{\includefig{ctex_new_null_box}%
+\caption{\cweb/ code for |new_null_box|}\label{ctex_code}}\hfil}%
+\par\bigskip
+\fig{\includefig{tl_new_null_box}%
+\caption{The \CEE/ code for |new_null_box| as generated by {\tt web2c}}\label{tl_code}}
+}
+
+It can be seen, that \.{web2c} has desugared the sweet code written by
+Knuth to make it unpalatable to human beings, the only use you can
+make of it is feeding it to a \CEE/ compiler. In contrast, \web2w/
+tries to create source code that is as close to the original as
+possible but still translates \Pascal/ to \CEE/. For example, note
+the last statement in the |new_null_box| function: where \CEE/ has a
+\&{return} statement, \Pascal/ assigns
+the return value to the function
+name. A simple translation, sufficient for a \CEE/ compiler, can just
+replace the function name by ``\.{Result}'' (an identifier that is not
+used in the implementation of \TeX) and add ``\.{return Result;}'' at
+the end of the function (see figure~\figref{tl_code}). A translation
+that strives to produce nice code should, however, avoid such ugly
+code.
+
+Let's look at another example\index{new character+|new_character|}:
+
+\float{\line{\noindent
+\fig{\includefig{tex_new_character}%
+\caption{The \WEB/ code for |new_character|}\label{tex_new_character}}\hfil}%
+\par\bigskip
+\line{\noindent
+\fig{\includefig{ctex_new_character}%
+\caption{The \cweb/ code for |new_character|}\label{ctex_new_character}}\hfil}%
+}%
+
+In figure~\figref{tex_new_character} there is a ``\&{return}'' in the
+innermost \&{if}. This ``\&{return}'' is actually a macro defined as ``|goto
+exit|'', and ``|exit|'' is a numeric macro defined as ``|10|''. ``\&{return}''
+is a reserved word in \CEE/ and ``|exit|'' is a function of the \CEE/
+standard library, so something has to be done. The example also
+illustrates the point that I can not always replace an assignment to
+the function name by a \CEE/ return statement. Only if the assignment
+is in a tail position\index{tail position}, that is a position
+where the control-flow leads
+directly to the end of the function body, it can be turned into a
+return statement as happened in
+figure~\figref{ctex_new_character}. Further, if all the goto
+statements that lead to a given label have been eliminated, as it is the
+case here, the label can be eliminated as well.
+In figure~\figref{ctex_new_character} there is no ``|exit:|''
+preceding the final ``\.{\RB}''.
+
+Another seemingly small problem is the different use of semicolons\index{semicolon} in
+\CEE/ and \Pascal/. While in \CEE/ a semicolon follows an expression
+to make it into a statement, in \Pascal/ the semicolon connects two
+statements into a statement sequence. For example, if an assignment
+precedes an ``\&{else}'', in \Pascal/ you have ``\.{x:=0 else}'' where as in
+\CEE/ you have ``\.{x=0; else}''; no additional semicolon is needed if
+a compound statement precedes the ``\&{else}''. When converting
+\.{tex.web}, a total of 1119~semicolons need to be inserted at the right
+places. Speaking of the right place: Consider the following \WEB/
+code:
+\medskip
+\nointerlineskip
+\vbox{\includefig{tex_cant_happen}}
+\nointerlineskip
+\medskip
+\noindent
+Where should the semicolon\index{semicolon} go? Directly preceding the ``\&{else}''?
+Probably not! Alternatively, I can start the search for the right
+place to insert the semicolon with the assignment. But this does not
+work either: the assignment\index{assignment} can be spread over several macros or
+modules which can be used multiple times; so the right place to insert
+a semicolon in one instance can be the wrong place in another
+instance. \web2w/ places the semicolon correctly behind the
+assignment like this:
+\medskip
+\nointerlineskip
+\vbox{\includefig{ctex_cant_happen}}
+\nointerlineskip
+\medskip\noindent
+But look what happened to the string\index{string} |"???"|.
+Strings enclosed in \CEE/-like double quotes\index{double quote} receive a special
+treatment by \.{tangle}\index{tangle+\.{tangle}}:
+the strings are collected in a string pool\index{string pool}
+file and replaced by string numbers in the \Pascal/ source. No such
+mechanism is available in \.{ctangle}. My first attempt was to replace
+the string handling of \TeX\ and keep the \CEE/-like strings in the
+source code. \TeX s string pool\index{string pool} is, however, hardwired into the
+program and is used not only for static strings but also for strings
+created at runtime, for example the names of control sequences\index{control sequence}.
+So I tried a hybrid approach: keeping strings that are used only for output
+(error messages for example) and translating other strings to string
+numbers. There are different places where the translation of a string like
+|"Maybe you should try asking a human?"| to a number like |283| can take place.
+\enumerate
+\item One could add a function |s| to do the translation at runtime and then write
+|s("Maybe you should try asking a human?")|. The advantage is simplicity and readability;
+the disadvantage is the overhead in time and space (the string will exist twice:
+as a static string
+and as a copy in the string pool).
+\item One could use the \CEE/ preprocessor to do the job. For
+example, I could generate a macro {\it Maybe\_you\_should\_try\_asking\_a\_human0x63\/}
+that is defined as 283 and a second macro
+{\it str\_283\/} for the string itself. Then, I can replace the occurrence of
+the string in the source by the macro name that mimics the string
+content and initialize the |str_pool| and |str_start| array using
+the other macro.
+\item As a third variation used below, one can use the module
+expansion mechanism of \.{ctangle}. I generate for each string a
+module, in the above example named \PB{$\X1234:\PB{\.{"Maybe\ you\
+should\ try\ asking\ a\ human?"}}\X$}, that will expand to the correct
+number, here |283|. And as in the previous method use a macro
+|str_283| to initialize |str_pool| and |str_start|. The advantage
+is the greater flexibility and the nicer looking replacements for
+strings, because module names can use the full character set.
+(Imagine replacing |"???"| by {\it \_0x630x630x63\/}.)
+\endenumerate
+In retrospect, after seeing how nice method 3 works, I ponder if I
+should have decided to avoid the hybrid approach and use approach 3
+for all strings. It would have reduced the amount of changes to the
+source file considerably. I further think that approach 1 has its
+merits too. The overhead in space is just a few thousand byte and the
+overhead in time is incurred only when the strings are actually needed
+which is mostly during a run of \.{initex} and while generating output
+(which is slow anyway).
+
+A mayor difference between \Pascal/ and \CEE/ is the use of
+subrange types\index{subrange type}.
+Subrange types are used to specify the range of valid
+indices when defining arrays. While most arrays\index{array}
+used in \TeX\ start with index zero,
+not all do. In the first case, they can be implemented as \CEE/ arrays
+which always start at index zero; in the latter case, I define a zero
+based array having the right size, adding a ``0'' to the name. Then, I
+define a constant pointer initialized by the address of the zero based
+array plus/minus a suitable offset so that I can use this pointer as
+a replacement for the \Pascal/ array.
+
+When subrange types are used to define variables, I replace subrange
+types by the next largest \CEE/ standard integer type as defined in
+\.{stdint.h} which works most of the time. Consider the code
+\medskip
+\nointerlineskip
+\vbox{\includefig{tex_print_totals}}
+\nointerlineskip
+\medskip\noindent
+where ${}\\{nest\_size}\K{}$\T{40}.
+Translating this to
+\medskip
+\nointerlineskip
+\vbox{\includefig{ctex_print_totals}}
+\nointerlineskip
+\medskip\noindent
+would result in an infinite loop because |p| would never become less
+than zero; instead it would wrap around. So in this (and 21 similar
+cases), I declare the variables used in
+for-loops\index{for+\&{for}} to be of type \&{int}.
+
+I will not go into further details of the translation process as you
+will find all the information in what follows below. Instead, I will
+take a step back now and give you the big picture, looking back at the
+journey that took me to this point.
+
+The program \web2w/ works in three phases: First I run the input file
+\.{tex.web} through a scanner\index{scanner} producing
+ tokens (see section~\secref{scanner}). The pattern matching
+is done using \.{flex}\index{flex+\.{flex}}, the action code consists of
+macros described here. The tokens form a doubly linked list, so that later I can
+traverse the source file forward and backward. During scanning,
+information is gathered and stored about macros, identifiers, and
+modules. In addition, every token has a |link| field which is used to
+connect related tokens. For example, I link an opening parenthesis
+to the matching closing parenthesis, and the start of a comment to the
+end of the comment.
+
+After scanning comes parsing\index{parsing}. The parser is generated
+using \.{bison}\index{bison+\.{bison}}
+from a modified \Pascal/ grammar (see section~\secref{parser}).
+To run the parser, I need to feed
+it with tokens, rearranged in the order that \.{tangle}\index{tangle+\.{tangle}}
+would produce, expanding macros and modules as I go. While parsing, I gather
+information about the \Pascal/ code. At the beginning, I tended to use
+this information immediately to rearrange the token sequence just
+parsed. Later, I learned the hard way (modules that were modified on
+the first encounter would later be feed to the parser in the modified
+form) that it is better to leave the token sequence untouched and just
+annotate it with information needed to transform it during the next stage.
+A technique that proved to be very useful is connecting the key tokens
+of a \Pascal/ structure using the |link| field. For example, connecting
+a ``\&{case}'' token with its ``\&{do}'' token makes it easy to place
+the expression that is between these tokens, without knowing anything about
+its actual structure, between `` \&{switch} ('' and
+``)''. The final stage is the generation of \cweb/
+output. Here the token sequence is traversed a third time, this time
+again in input file order. This time, the traversal will stop at the warning signs put
+up during the first two passes, use the information gathered so far,
+and rewrite the token sequence as gentle and respectful as possible
+from \Pascal/ to \CEE/.
+
+Et voil\`a! \.{tex.w} is ready---almost at least. I apply a last patch
+file\index{patch file}, for instance to adapt documentation reliant
+on \.{webmac.tex}\index{webmac tex+\.{webmac.tex}}
+so that it works with \.{cwebmac.tex}\index{cwebmac tex+\.{cwebmac.tex}},
+ or I make small changes that do not deserve a more general treatment.
+The final file is then called \.{ctex.w} from
+which I obtain \.{ctex.c} and \.{ctex.tex} simply by applying
+\.{ctangle} and \.{cweave}. Using ``\.{gcc ctex.c -o ctex}'' I get a
+running \.{ctex}. Running ``\.{ctex ctex.tex}'' to get \.{ctex.dvi} is
+then just a tiny step away: it is necessary to set up format and font metric
+files. The details on how to do that and run (and pass) the infamous
+trip test\index{trip test} are described in section~\secref{triptest}.
+
+
+\section{Converting \WEB/ to \cweb/}
+
+\web2w/ is implemented by a \CEE/ code file\index{web2w.c+\.{web2w.c}}:
+
+
+@c
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <math.h>
+#include "web2w.h"
+#include "pascal.tab.h"
+
+@<internal declarations@>@;
+@<global variables@>@;
+@<functions@>@;
+
+int @!main(int argc, char *argv[])
+{ @<process the command line@>@;
+ @<read the \WEB/@>@;
+ @<parse \Pascal/@>@;
+ @<generate \cweb/ output@>@;
+ @<show summary@>@;
+ return 0;
+}
+@
+
+
+I also create the header file \.{web2w.h}\index{web2w.h+\.{web2w.h}}
+included in the above \CEE/ file.
+ It contains the external declarations and is used to share constants, macros,
+types, variables, and functions with other \CEE/ files.
+
+@(web2w.h@>=
+@<external declarations@>
+@
+
+\section{Reading the \WEB/}
+
+When I read the \WEB/, I split it into a list of tokens\index{token};
+this process is called ``scanning''.\index{scanner}
+I use \.{flex}\index{flex+\.{flex}} (the free counterpart
+of \.{lex}\index{lex+\.{lex}}) to generate the function
+|wwlex| from the file \.{web.l}\index{web.l+\.{web.l}}.
+
+@<internal declarations@>=
+extern int wwlex(void); /* the scanner */
+extern FILE *wwin; /* the scanners input file */
+extern FILE *wwout; /* the scanners needs an output file */@/@,
+@
+
+@
+Using this function, I can read the \WEB/ and produce a token list.
+@<read the \WEB/@>=
+ @<initialize token list@>@;
+ wwlex();
+ @<finalize token list@>@;
+@
+
+Reading the \WEB/ results in a list of tokens as used by
+\.{tangle}\index{tangle+\.{tangle}} or \.{weave}.
+At this point, I do not need to extract the structure of the \Pascal/
+program contained in the \WEB/. This is left for a later stage.
+I need to extract the \WEB/ specific structure: text in limbo\index{limbo} followed
+by modules\index{module}; modules starting with \TeX\ text followed optionally by
+definitions and \Pascal/ code. Aside from this general structure,
+I will later need to translate the \WEB/ specific control sequences
+(starting with @@) by \cweb/ specific control sequences.
+
+The scanner identifies tokens by
+matching the input against regular expressions\index{regular expression} and
+executing \CEE/ code if a match is found.
+The lex file \.{web.l}\index{web.l+\.{web.l}} is not a literate program
+since it's not a \CEE/ file;
+it is given verbatim in section~\secref{scanner}.
+The functions and macros used in the action parts
+inside the file, however, are described below.
+
+\subsection{Scanning the \WEB/}
+
+The scanner\index{scanner} is written following the \WEB/\index{WEB+\WEB/}
+User Manual\cite{Knuth:WEB}.
+
+It has three main modes: the |INITIAL| mode (or |TEX| mode),
+the |MIDDLE| mode, and the |PASCAL| mode;
+and three special modes |DEFINITION|, |FORMAT|, and |NAME|.
+@<external declarations@>=
+#define @!TEX INITIAL
+@
+
+The scanner starts out in |TEX| mode scanning the part of the file
+that is ``in limbo''\index{limbo} and then switches back and forth between |TEX|
+mode, |MIDDLE| mode, and |PASCAL| mode, occasionally taking a detour
+through |DEFINITION|, |FORMAT|, or |NAME| mode.
+
+
+While scanning in |TEX| mode, I need to deal with a few
+special characters: the character ``\.{@@}'', because
+it introduces special web commands and might introduce a change into
+\Pascal/ mode; the ``\.{\VB}'' character, because it starts \Pascal/ mode;
+and the ``\.{\LB}'' and ``\.{\RB}'' characters , which are
+used for grouping while in \TeX\ mode. Unfortunately, these same characters
+also start and end comments while in \Pascal/ mode. So finding a ``\.{\}}''
+in |TEX| mode might be the end of a group or the end of a comment.
+Everything else is just considered plain text. Text may also contain the
+``\.{@@}'', ``\.{\VB}'', ``\.{\LB}'', and ``\.{\RB}'' characters if these
+are preceded by a backslash\index{backslash}.
+
+In |PASCAL| mode, I match the tokens needed to
+build the \Pascal/ parse tree. These are different---and
+far more numerous---than what I need for the \TeX\ part which
+my translator will not touch at all. The |MIDDLE| mode is a
+restricted |PASCAL| mode that does not allow module names. Instead,
+a module name terminates |MIDDLE| mode and starts a new module.
+
+The |DEFINITION| mode is used to scan the initial part of a macro
+definition; the |FORMAT| mode is a simplified version of the
+|DEFINITION| mode used for format definitions; and the |NAME| mode is
+used to scan module names.
+
+In |PASCAL| mode, I ignore most spaces and match the usual \Pascal/ tokens.
+The main work is left to the \Pascal/ parser.
+
+The switching between the scanning modes is supported by a
+stack\index{stack} (see section~\secref{linking})
+because it may involve nested structures. For example inside
+\Pascal/, a comment contains \TeX\ code and inside \TeX\ code whatever
+comes between two ``\.{\VB}'' characters is considered \Pascal/ code.
+A scanner produced by \.{flex}\index{flex+\.{flex}} is very fast,
+but by itself not capable of tracking
+nested structures.
+
+\subsection{Tokens}
+The parser creates a representation of the \WEB/ file as a list
+of tokens\index{token}. Later the parser will build a parse tree with tokens
+as leaf nodes. Because \CEE/ lacks object orientation,
+I define |token| as a |union| of leaf nodes\index{leaf node}
+and internal nodes\index{internal node}
+of the tree. All instances of the type defined this way share
+a common |tag| field as a replacement for the class information.
+Every token has a pointer to the |next| token,
+a pointer the |previous| token,
+a |link| field to connect related tokens, and an |up| pointer
+pointing from the leafs upwards and from internal
+nodes upwards until reaching the root node.
+@<external declarations@>=
+typedef struct token {
+ int tag;
+ struct token *next, *previous, *link, *up;
+ union {
+ @<leaf node@>;
+ @<internal node@>;
+ };
+} @!token;
+@
+
+Leaf nodes also contain a sequence number\index{sequence number}, enumerating stretches
+of contiguous \Pascal/ code, and for debugging\index{debugging} purposes,
+a line number\index{line number} field.
+There is some more token specific information, that will be explained
+as needed.
+
+@<leaf node@>=
+ struct {
+ int @!sequenceno;
+ int @!lineno;
+ @<token specific info@>
+ }
+@
+
+
+
+
+As a first example for token specific information,
+I note that most tokens have a |text| field that contains the textual
+representation of the token.
+@<token specific info@>=
+char *text;
+@
+
+The assignment of the |tag| numbers is mostly arbitrary.
+The file \.{pascal.y} lists all possible tags and gives them
+symbolic names which are shown using small caps in the following.
+The function |tagname|, defined in \.{pascal.y}\index{pascal.y+\.{pascal.y}},
+is responsible for converting the tag numbers back into readable strings.
+
+@<external declarations@>=
+extern const char *tagname(int tag);
+@
+
+Because I do not deallocate tokens, I can simply allocate them from
+a token array using the function |new_token|.
+
+@<internal declarations@>=
+#define MAX_TOKEN_MEM 250000
+@
+
+@<global variables@>=
+static token token_mem[MAX_TOKEN_MEM]= {{0}};
+static int free_tokens=MAX_TOKEN_MEM;
+@
+
+@<show summary@>=
+ DBG(dbgbasic,"free tokens = %d\n",free_tokens);
+@
+
+@<functions@>=
+static token *new_token(int tag)
+{ token *n;
+ if (free_tokens>0) n=&token_mem[--free_tokens];
+ else ERROR("token mem overflow");
+ n->lineno=wwlineno;
+ n->sequenceno=sequenceno;
+ n->tag=tag;
+ return n;
+}
+@
+
+The value of |wwlineno|, the current line number, is maintained automatically
+by the code generated from \.{web.l}\index{web.l+\.{web.l}}.
+@<external declarations@>=
+extern int wwlineno;
+@
+
+The value of |sequenceno| is taken from a global variable.
+@<global variables@>=
+int sequenceno=0;
+@
+I increment this variable as part of the scanner actions using the macro |SEQ|.
+@<external declarations@>=
+extern int sequenceno;
+#define SEQ @[(sequenceno++)@]
+@
+
+The following function is used in the parser to verify that two tokens |t| and |s|
+belong to the same token sequence.
+
+@<external declarations@>=
+void seq(token *t, token*s);
+@
+
+@<functions@>=
+void seq(token *t, token*s)
+{ CHECK(t->sequenceno==s->sequenceno,
+ "tokens in line %d and %d belong to different code sequences",t->lineno,s->lineno);
+}
+@
+
+
+The list of tokens is created by the function |add_token|.
+@<external declarations@>=
+extern token *add_token(int tag);
+@
+
+The function creates a new token and adds it to the
+global list of all tokens maintaining two pointers,
+one to the first and one to the last token of the list.
+
+@<global variables@>=
+static token *first_token;
+token *last_token;
+@
+@<external declarations@>=
+extern token *last_token;
+@
+
+I initialize the list of tokens by creating a |HEAD| token, and make it the
+first and last token of the list.
+
+@<initialize token list@>=
+first_token=last_token=new_token(HEAD);
+first_token->text="";
+@
+
+@<functions@>=
+token *add_token(int tag)
+{ token *n=new_token(tag);
+ last_token->next=n;
+ n->previous=last_token;
+ last_token=n;
+ return n;
+}
+@
+
+\subsection{Scanner actions}
+
+Now I am ready to explain scanner actions\index{scanner action}.
+Let's start with the most
+simple cases. There are quite a few tokens, that are just added to
+the token list and have a fixed literal string as textual
+representation. I use the macro |TOK| to do this. Making |TOK| an
+external declaration will write its definition into the file
+\.{web2w.h}\index{web2w.h+\.{web2w.h}} which will be
+included by \.{web.l}\index{web.l+\.{web.l}}.
+
+@<external declarations@>=
+#define TOK(string,tag) (add_token(tag)->text=string)
+@
+
+Another class of simple tokens are those that have a varying textual
+representation which is defined by the string found in the input file.
+The variable |wwtext| points to this input string after it was matched
+against the regular expression\index{regular expression}.
+ Since these strings are not persistent,
+I need to use the string handling function |copy_string| before I can
+store them in the tokens |text| field.
+The macro |COPY| can be used together with |TOK| to achieve the desired effect.
+
+@<external declarations@>=
+#define COPY @[copy_string(wwtext)@]
+@
+
+The last class of tokens that I discuss before I turn my attention
+to the functions that actually do the string-handling are the tokens
+where the textual representation is build up in small increments.
+Three macros are used to perform the desired operations: |BOS| (Begin of String)
+is used to start a new string, |ADD| adds characters to the current string,
+and |EOS| (End of String) is used to complete
+the definition of the string.
+
+@<external declarations@>=
+#define BOS @[new_string()@]
+#define ADD @[add_string(wwtext)@]
+#define EOS @[(string_length()>0?TOK(end_string(),TEXT):0)@]
+@
+
+More string handling functions are used to define these macros and
+it is time to explain the string handling in more detail.
+
+\subsection{Strings}
+In this section, I define the following functions:\index{string}
+
+@<external declarations@>=
+extern char *new_string(void); /* start a new string */
+extern void add_string(char *str); /* add characters to the string */
+extern char *end_string(void); /* finish the string */
+extern char *copy_string(char *str); /* all of the above */
+extern int string_length(void); /* the length of the string */@\@,
+@
+
+I use a character array called |string_mem|
+to store these strings. Strings in the |string_mem| are never
+deallocated, so memory management is simple.
+When the scanner has identified a string, it will add it to the
+current string using |add_string|. The scanner can then decide
+when to start a new string by calling |new_string| and when the string is
+ready for permanent storage by calling |end_string|.
+|string_length| returns the length of the current string.
+
+
+
+Some statistics: \.{tex.web} contains
+11195 Strings with an average of 46.6 characters
+per string and a maximum of 5234 characters (the text in limbo);
+the second largest string has 1891 characters.
+The total number of characters in all strings is 516646.
+(Scanning \.{etex.web} will require even more string memory.)
+
+@<internal declarations@>=
+#define MAX_STRING_MEM 800000
+@
+
+@<global variables@>=
+static char string_mem[MAX_STRING_MEM];
+static int free_strings = MAX_STRING_MEM;
+static int current_string= 0;
+@
+
+@<show summary@>=
+ DBG(dbgbasic,"free strings = %d\n",free_strings);
+@
+
+The string currently under construction is identified by
+the position of its first character, the |current_string|,
+and its last character |MAX_STRING_MEM-free_strings|.
+
+
+@<functions@>=
+char *new_string(void)
+{ current_string= MAX_STRING_MEM-free_strings;
+ return string_mem+current_string;
+}
+
+void add_string(char *str)
+{ while (free_strings>0)
+ { if (*str!=0)
+ string_mem[MAX_STRING_MEM-free_strings--]=*str++;
+ else
+ return;
+ }
+ ERROR("String mem overflow");
+}
+
+char *end_string(void)
+{ char *str=string_mem+current_string;
+ if (free_strings>0)
+ string_mem[MAX_STRING_MEM-free_strings--]=0;
+ else
+ ERROR("String mem overflow");
+ current_string= MAX_STRING_MEM-free_strings;
+ return str;
+}
+
+char *copy_string(char *str)
+{@+ new_string();
+ add_string(str);
+ return end_string();@+
+}
+
+int string_length(void)
+{@+return (MAX_STRING_MEM-free_strings)- current_string;@+}
+
+@
+
+
+\subsection{Identifiers}
+To be able to parse the embedded \Pascal/ code,
+I need to take special care of identifiers\index{identifier}. I keep
+information related to identifiers in a table, called the |symbol_table|.
+The table is accessed by the string representing the identifier
+as a key and it returns a pointer to the table entry, called a |symbol|.
+@<external declarations@>=
+typedef struct symbol {
+char *name;
+int tag;
+int obsolete;
+int for_ctrl;
+int value;
+struct symbol *link;
+token *type;
+token *eq;
+} symbol;
+extern int get_sym_no(char *name);
+extern symbol *symbol_table[];
+@
+@<internal declarations@>=
+#define MAX_SYMBOL_TABLE 6007 /* or 4001 4999, a prime */
+#define MAX_SYMBOLS 5200 /* must be less than |MAX_SYMBOL_TABLE| */
+@
+
+@<global variables@>=
+symbol *symbol_table[MAX_SYMBOL_TABLE]= {NULL};
+static symbol symbols[MAX_SYMBOLS]= {{0}};
+static int free_symbols=MAX_SYMBOLS;
+@
+@<show summary@>=
+ DBG(dbgbasic,"free symbols = %d\n",free_symbols);
+@
+
+I organize the symbol table as a hash table\index{hash table}
+ using double hashing\index{double hashing}
+as described in~\cite{Knuth:TAOCP}, Chapter 6.4.
+@<functions@>=
+static int symbol_hash(char *name)
+{ int hash=0;
+ while (*name!=0)
+ hash=hash + (*(name++)^0x9E);
+ return hash;
+}
+
+static symbol *new_symbol(void)
+{ CHECK(free_symbols>0,"Symbol table overflow");
+ free_symbols--;
+ return symbols+free_symbols;
+}
+
+int get_sym_no(char *name)
+{ int i,c;
+ i = symbol_hash(name)%MAX_SYMBOL_TABLE;
+ if (symbol_table[i]!=NULL)
+ { if (strcmp(symbol_table[i]->name,name)==0)
+ return i;
+ if (i==0) c=1; else c = MAX_SYMBOL_TABLE-i;
+ while (true)
+ { i=i-c;
+ if (i<0) i=i+MAX_SYMBOL_TABLE;
+ if (symbol_table[i]==NULL) break;
+ if (strcmp(symbol_table[i]->name,name)==0)
+ return i;
+ }
+ }
+ symbol_table[i]=new_symbol();
+ symbol_table[i]->name=new_string(); add_string(name); end_string();
+ symbol_table[i]->tag=ID;
+ return i;
+}
+@
+
+The pointer into the symbol table can be stored inside the token
+in two ways: as an index into the |symbol_table| or as a direct pointer
+to the |symbol| structure. While scanning the \WEB/, I will assign
+the symbol number(|sym_no|), and while parsing \Pascal/, I will replace the
+symbol number by the symbol pointer (|sym_ptr|). This is necessary, because I
+will need to distinguish between various local symbols\index{local symbol}
+with the same name; these have only a single entry in the symbol table but
+the pointers will point to different |symbol| structures.
+@<token specific info@>=
+int sym_no;
+struct symbol *sym_ptr;
+@
+\noindent
+This leads to the following macros:
+@<external declarations@>=
+#define SYM_PTR(name) @[symbol_table[get_sym_no(name)]@]
+#define SYMBOL {@+int s=get_sym_no(yytext);@+add_token(symbol_table[s]->tag)->sym_no=s;@+}
+#define SYM(t) @[(symbol_table[(t)->sym_no])@]
+@
+\noindent
+It's easy to convert such a token back to a string.
+@<convert token |t| to a string@>=
+case ID: case PID: case PCONSTID:
+case PARRAYFILETYPEID: case PARRAYFILEID:
+case PFUNCID: case PPROCID:
+case PDEFVARID: case PDEFPARAMID: case PDEFREFID: case PDEFCONSTID:
+case PDEFTYPEID: case PDEFTYPESUBID: case PDEFFUNCID: case CREFID:
+case NMACRO: case OMACRO: case PMACRO:@/
+ return SYM(t)->name;
+@
+
+
+In \TeX, like in most programs, I encounter two kinds of symbols:
+global\index{global symbol} and local symbols\index{local symbol}.
+While scanning, every symbol that I
+encounter gets entered into the global symbol table. While parsing, I
+will discover, that the variable |f| is a file variable in one
+function and an integer variable in another function. The two
+occurrences of |f| have different scope\index{scope}. So I want to link different
+occurrences of |f| to different entries in the symbol table.
+
+I use the function |localize| to create a local version of a symbol.
+
+@<external declarations@>=
+extern void localize(token *t);
+@
+
+To open a new scope, I use the function |scope_open|; to close it again, I
+use the function |scope_close|.
+
+@<external declarations@>=
+extern void scope_open(void);
+extern void scope_close(void);
+@
+These functions use a small array holding all the symbol numbers of
+currently local symbols and another array to hold pointers to the global
+symbols of the same name.
+
+@<global variables@>=
+#define MAX_LOCALS 50
+static int locals[MAX_LOCALS];
+static symbol *globals[MAX_LOCALS];
+static int free_locals=MAX_LOCALS;
+@
+
+
+@<functions@>=
+void scope_open(void)
+{
+ CHECK(free_locals==MAX_LOCALS,"Opening a new scope without closing the previous one");
+}
+
+void scope_close(void)
+{ int i;
+ for (i=free_locals; i<MAX_LOCALS; i++)
+ symbol_table[locals[i]]=globals[i];
+ free_locals=MAX_LOCALS;
+}
+@
+To localize a symbol, I create a new one and enter it, after
+saving the global symbol, into the symbol table.
+
+@<functions@>=
+void localize(token *t)
+{ int sym_no=t->sym_no;
+ symbol *l, *g;
+ l=new_symbol();
+ g=symbol_table[sym_no];
+ l->name=g->name;
+ l->tag=g->tag;
+ l->eq=g->eq;
+ symbol_table[sym_no]=l;
+ CHECK(free_locals>0,"Overflow of local symbols in line %d",t->lineno);
+ free_locals--;
+ locals[free_locals]=sym_no;
+ globals[free_locals]=g;
+ t->sym_ptr=l;
+}
+@
+
+
+\subsection{Linking related tokens}
+\label{linking}%
+So far I have considered the \WEB/ file as one long flat list of
+tokens.\index{related token}
+As already mentioned above, the file has, however, also a nested structure:
+For example, each ``\.{\LB}'' token is related to a ``\.{\RB}'' token
+that ends either a \TeX\ group or a \Pascal/ comment.
+While scanning, I will need to know about this structure because it
+is necessary to do a correct switching of modes. Hence, I use the |link| field
+to connect the first token to the later token. This information
+is also useful at later stages, for example when I expand macros.
+The following table gives a list of related tokens.
+
+\center{\table{List of linked tokens}{%
+&Left &Right &Mode & Comment\hfill\cr
+\noalign{\hrule}
+&\.{(} & \.{)} & |PASCAL|/|PASCAL|& needed for macro expansion\index{macro expansion}\hfill\cr
+&\.{\{} & \.{\}} & |PASCAL|/|TEX|/|PASCAL| & comments\index{comment} \hfill\cr
+&\.{\{} & \.{\}} & |MIDDLE|/|TEX|/|MIDDLE| & comments \hfill\cr
+&\.{\{} & \.{\}} & |TEX|/|TEX| & grouping\hfill\cr
+& \.{\VB}& \.{\VB} & |TEX|/|PASCAL|/|TEX| & typesetting code\hfill\cr
+&\.{@@<} & \.{@@>} & & module names\hfill\cr
+& \.{=} & & & begin of \Pascal/\hfill\cr
+& \.{==} & & & begin of \Pascal/\hfill\cr
+& & \.{@@ } & |PASCAL| & \hfill end of \Pascal/\cr
+& & \.{@@*} & |PASCAL| & \hfill end of \Pascal/\cr
+& & \.{@@d} & |PASCAL| & \hfill end of \Pascal/\cr
+& & \.{@@f} & |PASCAL| & \hfill end of \Pascal/\cr
+& & \.{@@p} & |PASCAL| & \hfill end of \Pascal/\cr
+& \.{"} & \.{"} & & list of \WEB/ strings\index{string}\hfill\cr
+&\.{@@>=} &\.{@@>=} & & continuation of module\index{module}\hfill\cr
+& \.{@@p}& \.{@@p} & & continuation of program\index{program}\hfill\cr
+}\label{Linked}}
+
+
+To track the nesting of structures, I need a stack\index{stack}:
+
+@<global variables@>=
+#define MAX_WWSTACK 200
+static token *wwstack[MAX_WWSTACK]={0};
+static int wwsp = 0;
+@
+
+I define the functions |ww_push| and |ww_pop| to
+operate on the stack. When popping a token, I keep the nesting information
+by linking it to its matching token.
+The function |ww_is| can be used to test the |tag| of the token
+on top of the stack.
+
+@<external declarations@>=
+extern void ww_push(token *t);
+extern token *ww_pop(token *t);
+extern int ww_is(int tag);
+@
+
+@<functions@>=
+void ww_push(token *left)
+{ CHECK(wwsp<MAX_WWSTACK,"WW stack overflow");
+ DBG(dbglink,"Pushing[%d]:",wwsp); if (left!=NULL) DBG(dbglink,THE_TOKEN(left));
+ wwstack[wwsp++]=left;
+}
+
+token *ww_pop(token *right)
+{ token *left;
+ CHECK(wwsp>0,"Mode stack underflow");
+ left=wwstack[--wwsp];
+ if (left!=NULL) left->link=right;
+ DBG(dbglink,"Popping[%d]:",wwsp); if (left!=NULL) DBG(dbglink,THE_TOKEN(left));
+ return left;
+}
+
+int ww_is(int tag)
+{ return wwsp>0 && wwstack[wwsp-1]!=NULL && wwstack[wwsp-1]->tag==tag;
+}
+
+@
+
+Using the stack\index{stack},
+I can now also distinguish the use of ``\.{\LB}'' and ``\.{\RB}''
+as a grouping\index{grouping}
+construct in \TeX\ from the use of starting and ending comments\index{comment}
+in \Pascal/. When I encounter ``\.{\LB}'' in |TEX| mode, it introduces a new level of
+grouping and I do not create a new token.
+Instead I push |NULL| on the stack.
+When I encounter ``\.{\LB}'' in |PASCAL| mode, however, it is the start of a comment;
+I create a token and push it.
+When I encounter the matching ``\.{\RB}'', I am always in |TEX| mode.
+I pop the stack and test the value:
+If it was |NULL|, I can continue in |TEX| mode because it was a grouping character;
+if it was not |NULL|, it is the end of a comment. I create a token for it and
+continue in |PASCAL| mode.
+
+@<external declarations@>=
+#define PUSH @[ww_push(last_token)@]
+#define PUSH_NULL @[ww_push(NULL)@]
+#define POP @[ww_pop(last_token)@]
+#define POP_NULL @[(ADD, POP)@]
+#define POP_MLEFT @[(EOS, TOK("}",RIGHT), BEGIN(MIDDLE), POP)@]
+#define POP_PLEFT @[(EOS, TOK("}",RIGHT), BEGIN(PASCAL), POP)@]
+#define POP_LEFT @[(ww_is(MLEFT)? POP_MLEFT : (ww_is(PLEFT)? POP_PLEFT: POP_NULL))@]
+@
+
+
+Besides linking matching tokens, the |link| field can also be used
+to build linear list of related token. One example for such a list
+is the list of \WEB/ strings\index{string}.
+The program \.{tangle}\index{tangle+\.{tangle}}, converting a
+\WEB/ to \Pascal/, creates a string pool\index{string pool} file. This mechanism is
+no longer available in \.{ctangle} so I have to implement an alternative
+(see section~\secref{stringpool} on replacing the \TeX\ string pool).
+Here I take the first step and collect all the strings that occur
+in the \WEB/ in one linked list. For this purpose, I use
+a pointer to the |first_string|, and a pointer to the link field
+of the |last_string|. The macro |WWSTRING| is used in the scanner and
+adds the new string token to this list.
+
+@<external declarations@>=
+extern void wwstring(char *wwtext);
+#define WWSTRING @[wwstring(wwtext)@]
+@
+
+@<functions@>=
+void wwstring(char *wwtext)
+{ token *t=add_token(STRING);
+ t->sym_no=get_sym_no(wwtext);
+ t->text=SYM(t)->name;
+ *last_string=t;
+ last_string=&(t->link);
+}
+@
+
+To make this work, it is sufficient to initialize the two pointers
+appropriately.
+@<global variables@>=
+static token *first_string=NULL, **last_string=&first_string;
+@
+
+
+
+
+
+\subsection{Module names}
+I need to maintain information for each module\index{module}. I keep
+this information in a table, called the module table\index{module table}.
+The table is accessed by the string representing the module name\index{module name}
+as a key. This sounds very similar to what I did for identifiers,
+there is, however, one main difference:
+Modules are sometimes referenced by incomplete module names\index{incomplete module name}
+that end with an ellipsis\index{ellipsis} ($\ldots$).
+These incomplete module names may not even be valid \TeX\ code.
+For this reason, I use a binary search tree\index{binary search tree}
+to map module names to modules.
+The first thing I need, therefore, is a function to compare two module names.
+The function |module_cmp(n,m)| will compare the name of |n| to the name of |m|;
+it returns a negative value if $|n| < |m|$; zero if $|n|=|m|$; and a positive
+value if $|n|>|m|$. |m| is always a full module name, |n| might end abruptly
+with an ellipsis.
+
+@<functions@>=
+static int module_name_cmp(token *n, token *m)
+{ n=n->next;@+ m=m->next; /* advance from ``\.{@@<}'' to the name */
+ if (n->next->tag==ELIPSIS)
+ return strncmp(n->text,m->text,strlen(n->text));
+ else
+ return strcmp(n->text,m->text);
+}
+@
+
+I organize the module table as a binary tree and allocate new modules from
+a large array.
+@<internal declarations@>=
+#define MAX_MODULE_TABLE 1009 /* or 1009, 1231, 2017, 3001, a prime */
+@
+
+@<global variables@>=
+static module module_table[MAX_MODULE_TABLE]= {{0}};
+static int free_modules=MAX_MODULE_TABLE;
+static module *module_root=NULL;
+@
+
+@<external declarations@>=
+typedef struct module {
+ token *atless;
+ token *atgreater;
+ struct module *left,*right;
+} module;
+extern void add_module(token *atless);
+extern module *find_module(token *atless);
+@
+
+
+@<show summary@>=
+ DBG(dbgbasic,"free modules = %d\n",free_modules);
+@
+
+To look up a module in the module table
+I use the function |find_module|. It returns a pointer to the module
+given the pointer to the ``\.{@@<}'' token that starts the module
+name. The function will allocate a new module if needed.
+
+@<functions@>=
+module *find_module(token *atless)
+{ module **m=&module_root;
+ while (*m!=NULL)
+ {int d = module_name_cmp(atless, (*m)->atless);
+ if (d==0)
+ return *m;
+ else if (d<0) m=&((*m)->left);
+ else m=&((*m)->right);
+ }
+ CHECK(free_modules>0,"Module table overflow");
+ *m= module_table+MAX_MODULE_TABLE-free_modules--;
+ (*m)->atless=atless;
+ return *m;
+}
+@
+
+Because modules can be defined in multiple installments,
+I link together the closing ``\.{@@>}'' tokens.
+This is done by calling the function |add_module| whenever
+I find the two tokens ``\.{@@>=}''.
+
+@<functions@>=
+void add_module(token *atless)
+{ module *m=find_module(atless);
+ token *atgreater = m->atgreater;
+ if (atgreater==NULL)
+ m->atgreater=atless->link;
+ else
+ { while (atgreater->link!=NULL) atgreater=atgreater->link;
+ atgreater->link=atless->link;
+ }
+}
+@
+
+Next I consider the problem of scanning module names. The name of a
+module starts after a ``\.{@@<}'' token. If this token shows up, I have
+to do some preparations depending on the current mode: If I am in
+|TEX| mode, I need to terminate the current |TEXT| token; if I am
+in |MIDDLE| mode, I pop the stack and terminate the macro or format
+definition I were just scanning;
+no special preparation is needed if I am in |PASCAL| mode. Then I
+push the ``\.{@@<}'' token on the stack, start a new |TEXT| token, and
+switch to |NAME| mode. When I encounter the matching ``\.{@@>}'' or
+``\.{@@>=}'' token, I add the module to the module table---calling
+|find_module| to cover the case that this is the first and only
+complete occurrence of the module name.
+
+@<external declarations@>=
+#define AT_GREATER_EQ @[TOK("@@>",ATGREATER), add_module(POP), TOK("=",EQ), PUSH, SEQ@]
+#define AT_GREATER @[TOK("@@>",ATGREATER), find_module(POP)@]
+@
+
+You may have noticed that the above |AT_GREATER_EQ| macro pushes the
+|EQ| token on the stack. I match this token up with the token that
+ends the \Pascal/ code following the equal sign. As you will see
+below, I do the same for macro definitions.
+Further, I link all the unnamed modules together using the ``\.{@@p}''
+tokens. I add an extra |EQ| token to match the convention that I
+have established for named modules.
+
+@<external declarations@>=
+extern token *program;
+#define PROGRAM @[(program->link=last_token,program=last_token),TOK("",EQ)@]
+@
+\noindent
+I use the first token as list head.
+@<global variables@>=
+token *program;
+@
+@<initialize token list@>=
+program=first_token;
+@
+
+\subsection{Definitions}
+In a \WEB/ file, the token ``\.{@@d}'' introduces the definition\index{definition}
+of a numeric constants or a macro with or without parameter.
+When the scanner encounters such a token, it enters the |DEFINITION| mode.
+
+The first token in |DEFINITION| mode is an identifier which will be
+stored in the symbol table\index{symbol table}.
+Then follows an optional macro parameter\index{macro parameter}
+``\.{(\#)}''; after the single or double equal sign, the scanner\index{scanner} switches
+to |MIDDLE| mode, not without pushing the equal sign on the stack\index{stack} to
+be matched against the first token after the following \Pascal/ code.
+
+After scanning an ``\.{=}'' token, I know that a numeric macro\index{numeric macro}
+is following, and I record this fact
+by changing the |tag| of the identifier\index{identifier} in the token\index{token}
+and in the symbol table\index{symbol table}.
+@<external declarations@>=
+#define CHGTAG(t,x) @[((t)->tag=(x))@]
+#define CHGID(t,x) @[(SYM(t)->tag=(x))
+#define CHGTYPE(t,x) @[(SYM(t)->type=(x))
+#define CHGVALUE(t,x) @[(SYM(t)->value=(x))
+#define CHGTEXT(t,x) @[((t)->text=(x))@]
+@
+
+After scanning an ``\.{==}'' token, I know that I have either an
+ordinary macro\index{ordinary macro} or a parametrized macro\index{parametrized macro}.
+A |PARAM| token tells the difference.
+
+
+@<functions@>=
+void def_macro(token *eq, int tag)
+{ token *id;
+ if (eq->previous->tag==PARAM)
+ { id = eq->previous->previous;
+ tag=PMACRO;
+ }
+ else
+ { id = eq->previous;
+ }
+ CHGTAG(id,tag);
+ CHGID(id,tag);
+ SYM(id)->eq=eq;
+ DBG(dbgexpand,"Defining %s: %s\n", tagname(tag),SYM(id)->name);
+}
+@
+
+@<external declarations@>=
+extern void def_macro(token *eq, int tag);
+#define DEF_MACRO(tag) @[def_macro(last_token,tag),SEQ@]
+@
+
+Similar, the token ``\.{@@f}'' introduces a format
+specification\index{format specification} switching the
+scanner\index{scanner} to |FORMAT| mode. It then scans tokens until the first newline
+character brings the scanner back to |MIDDLE| mode.
+
+\subsection{Finishing the token list}
+
+When the scanner is done, I terminate the token list with two
+end of file\index{end of file} tokens: one for \Pascal/ and one for the \WEB/.
+
+@<finalize token list@>=
+TOK("",ATP);@+ PROGRAM;@+ PUSH;@+ TOK("",PEOF);@+ TOK("",WEBEOF);@+ POP;
+@
+
+At this point I might want to have a complete list of all tokens and
+identifiers for debugging\index{debugging} purposes.
+
+@<finalize token list@>=
+if (debugflags&dbgtoken)
+{ token *t=first_token;
+ while (t!=NULL)@+ {@+MESSAGE(THE_TOKEN(t));@+t=t->next;@+}
+}
+if (debugflags&dbgid)
+{ int i;
+ for (i=free_symbols; i < MAX_SYMBOLS; i++)
+ MESSAGE("symbol[%d]=%s\n",i,symbols[i].name);
+}
+@
+
+
+
+
+\section{Parsing Pascal}
+
+%bug reported: subrange types have the form constant..constant;
+%\TeX\ uses constant..constant-1
+%in line 5499
+\index{parsing}
+I use \.{bison}\index{bison+\.{bison}} (the free replacement
+ of \.{yacc}\index{yacc+\.{yacc}}) to implement the
+parser\index{parser}.
+Fortunately \TeX\ does not use the full \Pascal/\index{Pascal+\Pascal/}
+language, so the parser can be simpler. Further, I do not need to generate code,
+but just analyze the \Pascal/ programs for the purpose of finding
+those constructions where \Pascal/ differs from \CEE/ and need a
+conversion. If I discover such an instance, I change the tags of
+the affected tokens, set the |link| field to connect related tokens,
+or even construct a parse tree and link to it using the |up| field.
+In a next sweep over the token list in
+section~\secref{writing}, these changed tokens will help us make the
+appropriate transformations. But before I can do this, I need to
+feed the parser with the proper tokens, but not in the order I find
+them in the \WEB/ file. I have to ``tangle''\index{tangle+\.{tangle}} them
+to get them into \Pascal/ program order. The function that is supposed
+to deliver the tangled tokens is called |pplex|. In addition, the parser
+expects a function |pperror| to produce error messages\index{error message}.
+
+@<external declarations@>=
+extern int pplex(void);
+extern void pperror(const char *message);
+@
+The function |pperror| is very simple:
+@<functions@>=
+void pperror(const char *message)
+{ ERROR("Parse error line %d: %s",pplval->lineno,message);@+}
+@
+
+
+
+\subsection{Generating the sequence of \Pascal/ tokens}
+Primarily, the \Pascal/\index{Pascal+\Pascal/} tokens\index{token} come from the
+ unnamed modules\index{unnamed module} and then
+from expanding module names\index{module name} and macros\index{macro}.
+ Because modules and macros
+may reference other modules and macros, I will need a stack\index{stack} to keep
+track of where to continue expansion when I have reached the end of
+the current expansion.
+
+@<global variables@>=
+#define MAX_PPSTACK 40
+static struct {
+ token *next,*end,*link;
+ int environment;
+ token *parameter;
+} pp_stack[MAX_PPSTACK];
+static int pp_sp=MAX_PPSTACK;
+@
+
+In each stack\index{stack} entry, the pointers |next| and |end| point to
+the next and past the last
+token of the current replacement text\index{replacement text}.
+In the case of modules, where
+the replacement text for the module name might be defined in multiple
+installments, the |link| pointer is used to point to the continuation
+of the current replacement text.
+
+In the |parameter| field, I store the pointer to the ``\.{(}'' token
+preceding the parameter\index{parameter} of a
+parametrized macro\index{parametrized macro}; it provides us
+conveniently with a pointer to the parameter text with its |next|
+pointer and with its |link| pointer to the ``\.{)}'' token a pointer
+directly to the |end| of the parameter text. When I expand the
+parameter text of a parametrized macro, I need the |environment|
+variable. It points down the stack to the stack entry that contains
+the macro call. This is the place where I will find the replacement
+for a ``\.{\#}'' token that might occur in the parameter text of
+nested parametrized macros.
+
+The function |pp_push| will store the required information on the
+stack. Instead of passing the |next| and |end| pointer separately, I
+pass a pointer to the ``\.{=}'' token from the macro or module
+definition. This token conveniently contains both pointers. The
+function then advances the stack pointer, initializes the new stack\index{stack}
+entry, and returns the pointer to the first token of the replacement.
+|pp_pop| will pop the stack and again return the pointer to the next
+token.
+
+@<functions@>=
+token *pp_push(token *link, token *eq, int environment, token*parameter)
+{ CHECK(pp_sp>0,"Pascal lexer stack overflow");
+ pp_sp--;
+ pp_stack[pp_sp].link=link;
+ pp_stack[pp_sp].next=eq->next;
+ pp_stack[pp_sp].end=eq->link;
+ pp_stack[pp_sp].environment=environment;
+ pp_stack[pp_sp].parameter=parameter;
+ DBG(dbgexpand,"Push pplex[%d]: ", MAX_PPSTACK-pp_sp); DBGTOKS(dbgexpand,eq->next,eq->link);
+ return pp_stack[pp_sp].next;
+}
+
+token *pp_pop(void)
+{ CHECK(pp_sp<MAX_PPSTACK,"Pascal Lexer stack underflow");
+ pp_sp++;
+ DBG(dbgexpand,"Pop pplex[%d]: ", MAX_PPSTACK-pp_sp);
+ DBGTOKS(dbgexpand,pp_stack[pp_sp].next,pp_stack[pp_sp].end);
+ return pp_stack[pp_sp].next;
+}
+@
+
+
+The function |pplex| is what I write next. In an "endless" loop, I
+read the next token from the stack\index{stack} just described, popping and pushing the
+stack as necessary. If I find a \Pascal/ token---it has
+a |tag| value greater than |FIRST_PASCAL_TOKEN|---I can
+return its |tag| immediately to the parser. \WEB/ tokens receive
+special treatment. When I deliver a token to the parser, |pplval|,
+the semantic value\index{semantic value} of the token, is the token pointer itself.
+
+@<functions@>=
+int pplex(void)
+{ token *t;
+ int tag;
+ t=pp_stack[pp_sp].next;
+ while (true)
+ {
+ if (t==pp_stack[pp_sp].end)
+ { @<process the end of a code segment@>@;
+ continue;
+ }
+ tag = t->tag;
+tag_known:
+ if (tag>FIRST_PASCAL_TOKEN)
+ {
+ pp_stack[pp_sp].next=t->next;
+ goto found;
+ }
+ else
+ { switch (tag)
+ { @<special treatment for \WEB/ tokens@>@;
+ default:
+ ERROR("Unexpected token in pplex:" THE_TOKEN(t));
+ }
+ }
+ }
+found:@/
+ DBG(dbgpascal,"pplex: %s->\t",tagname(tag));
+ DBG(dbgpascal,THE_TOKEN(t));
+ if (pascal!=NULL) fprintf(pascal,"%s ",token2string(t));
+ pplval=t;
+ return tag;
+}
+@
+
+\subsection{Simple cases for the parser}
+Now let's look at all the \WEB/ tokens and
+what |pplex| should to do with them.
+Quite a lot of them can be simply skipped:
+@<special treatment for \WEB/ tokens@>=
+ case NL:
+ case INDENT:
+ if (pascal!=NULL) fprintf(pascal,"%s",token2string(t));
+ case METACOMMENT:
+ case ATT:
+ case ATEX:
+ case ATQM:
+ case ATPLUS:
+ case ATSLASH:
+ case ATBACKSLASH:
+ case ATBAR:
+ case ATHASH:
+ case ATCOMMA:
+ case ATINDEX:
+ case ATINDEXTT:
+ case ATINDEX9:
+ case ATAND:
+ case ATSEMICOLON:
+ case ATLEFT:
+ case ATRIGHT:@/
+ t=t->next;
+ continue;
+@
+Comments\index{comment} can be skipped in a single step:
+@<special treatment for \WEB/ tokens@>=
+ case MLEFT:
+ case PLEFT:
+ t=t->link->next;
+ continue;
+@
+
+The \Pascal/ end-of-file\index{end of file} token is passed to the
+parser which then should terminate.
+@<special treatment for \WEB/ tokens@>=
+ case PEOF:
+ pp_stack[pp_sp].next=t->next;
+ goto found;
+@
+
+
+Simple is also the translation of octal\index{octal constant}
+or hexadecimal\index{hexadecimal constant} constants
+and single character strings: I translate them as \Pascal/ integers.
+The token ``\.{@@\$}'', it's the string pool\index{string pool}
+checksum\index{string pool checksum}, is an integer as well.
+@<special treatment for \WEB/ tokens@>=
+ case ATDOLLAR:
+ case OCTAL:
+ case HEX:
+ case CHAR:
+ pp_stack[pp_sp].next=t->next;
+ tag=PINTEGER;
+ goto found;
+@
+
+The last simple case are identifiers\index{identifier}. For identifiers, I find the
+correct tag in the symbol table which is maintained by the parser. At
+this point, I give tokens that still have the |tag==ID| the default
+tag |PID| and link tokens to the actual symbol structure, which might
+be local\index{local symbol} or global\index{global symbol}.
+
+@<special treatment for \WEB/ tokens@>=
+ case ID:
+ { symbol *s=SYM(t);
+ tag=s->tag;
+ if (tag==ID)
+ tag=s->tag=PID;
+ t->sym_ptr=s;
+ t->tag=tag;
+ goto tag_known;
+ }
+@
+
+\subsection{The macros {\bf debug}, {\bf gubed}, and friends}
+\TeX\ does some special trickery with the pseudo keywords \&{debug},
+\&{gubed}, \&{init}, \&{tini}, \&{stat}, and \&{tats}. These identifiers are
+used to generate different versions of \TeX\ for debugging\index{debugging},
+initialization\index{initialization}, and gathering of statistics\index{statistics}.
+The natural way to do
+this in \CEE/ is the use of |#ifdef|\dots|#endif|. It is however not
+possible in \CEE/ to define a macro like ``|#define debug|\quad|#ifdef
+DEBUG|'' because the \CEE/ preprocessor\index{preprocessor} performs a simple one-pass
+replacement on the source code. So macros are expanded and the
+expansion is not expanded a second time.
+
+It would be possible to define a module \X123:\.{debug}\X\ that
+\.{ctangle} expands to ``\hbox{|#ifdef DEBUG|}'' before the \CEE/
+preprocessor sees it; the other possibility is to do the expansion
+right now in \web2w/. The latter possibility is simple, so I do it
+here, but it affects the visual appearance of the converted code to
+its disadvantage.
+
+There are further possibilities too: I could redefine the macro as
+``|#define debug|\quad|if (Debug) {|'' making it plain \CEE/
+code. Then the compiler would insert or optimize away the code in
+question depending on whether I say ``|#define Debug @, 1|'' or
+``|#define Debug @, 0|''. The \&{stat}\dots\&{tats} brackets are however
+often used to enclose variable- or function-definitions where an ``|if
+(Debug) {|'' would not work.
+
+There are, however, also instances where the ``|#ifdef DEBUG|''
+approach does not work. For instance, |debug|\dots|gubed| is used
+inside the macro |succumb|. Fortunately there are only a few of these
+instances and I deal with them in the patch file\index{patch file}.
+
+As far as the parser is concerned, I just skip these tokens.
+@<special treatment for \WEB/ tokens@>=
+ case WDEBUG:
+ case WGUBED:
+ case WINIT:
+ case WTINI:
+ case WSTAT:
+ case WTATS:
+ t=t->next;
+ continue;
+@
+
+Later, I get them back into the \cweb/ file using the following code.
+It takes care not to replace the special keywords when they are
+enclosed between vertical bars and are only part of the descriptive text.
+@<convert |t| from \WEB/ to \cweb/@>=
+ case WDEBUG:
+ if (t->previous->tag==BAR)
+ wputs(t->text);
+ else
+ { if (column!=0) wput('\n');
+ wputs("#ifdef @@!DEBUG\n");
+ }
+ t=t->next;@+break;
+ case WINIT:
+ if (t->previous->tag==BAR)
+ wputs(t->text);
+ else
+ { if (column!=0) wput('\n');
+ wputs("#ifdef @@!INIT\n");
+ }
+ t=t->next;@+break;
+ case WSTAT:
+ if (t->previous->tag==BAR)
+ wputs(t->text);
+ else
+ {
+ if (column!=0) wput('\n');
+ wputs("#ifdef @@!STAT\n");
+ }
+ t=t->next;@+break;
+ case WGUBED:
+ case WTINI:
+ case WTATS:
+ if (t->previous->tag==BAR)
+ wputs(t->text);
+ else
+ { if (column!=0) wput('\n');
+ wputs("#endif\n");
+ }
+ t=t->next;
+ if (t->tag==ATPLUS||t->tag==ATSLASH) t=t->next;
+ if (t->tag==NL) t=t->next;
+ break;
+@
+I ignore ``\.{@@+}'' tokens that precede \&{debug} and friends, because
+their replacement should always start on the beginning of a line.
+@<convert |t| from \WEB/ to \cweb/@>=
+case ATPLUS:
+ t=t->next;
+ if (!following_directive(t))
+ wputs("@@+");
+ else
+ DBG(dbgcweb,"Eliminating @@+ in line %d\n",t->lineno);
+ @+break;
+@
+
+Because they also occur in format definitions, I mark the identifiers as
+obsolete\index{obsolete}.
+@<finalize token list@>=
+SYM_PTR("debug")->obsolete=1;
+SYM_PTR("gubed")->obsolete=1;
+SYM_PTR("stat")->obsolete=1;
+SYM_PTR("tats")->obsolete=1;
+SYM_PTR("init")->obsolete=1;
+SYM_PTR("tini")->obsolete=1;
+@
+
+\subsection{Parsing numerical constants}
+
+I do not expand numerical macros\index{numerical macro},
+ instead I expand the \Pascal/
+grammar to handle |NMACRO| tokens. This is also the right place to
+switch numeric macros from symbol numbers to symbol pointers. For each
+use of the token, I increment its |value| field in the symbol
+table. This will allow us later to eliminate definitions that are no
+longer used. The handling of \WEB/ strings is similar.
+
+@<special treatment for \WEB/ tokens@>=
+ case NMACRO:
+ t->sym_ptr=SYM(t);
+ if (t->sym_ptr->eq->next->tag==STRING)
+ {token *s= t->sym_ptr->eq->next;
+ s->sym_ptr=SYM(s);
+ s->sym_ptr->value++;
+ DBG(dbgstring,"Using numeric macro %s (%d) in line %d\n",
+ s->sym_ptr->name,s->sym_ptr->value,t->lineno);
+ }
+ pp_stack[pp_sp].next=t->next;
+ goto found;
+ case STRING:
+ t->sym_ptr=SYM(t);
+ t->sym_ptr->value++;
+ DBG(dbgstring,"Using string %s (%d) in line %d\n",
+ t->sym_ptr->name,t->sym_ptr->value,t->lineno);
+ pp_stack[pp_sp].next=t->next;
+ goto found;
+@
+
+
+Occasionally, I will need the ability to determine the value of a token
+that the \Pascal/ parser considers an integer.
+The function |getval| will return this value.
+@<external declarations@>=
+extern int getval(token *t);
+@
+@<functions@>=
+int getval(token *t)
+{ int n=0;
+ switch (t->tag)
+ { case ATDOLLAR: n=0;@+ break;
+ case PINTEGER: n =strtol(t->text,NULL,10);@+ break;
+ case NMACRO:
+ t = SYM(t)->eq;
+ CHECK(t->tag==EQEQ, "= expected in numeric macro in line %d",t->lineno);
+ t = t->next;
+ if (t->tag==PMINUS) {t=t->next; n=-getval(t);}
+ else n=getval(t);
+ while (true)
+ { if (t->next->tag==PPLUS)
+ { t=t->next->next; n=n+getval(t); }
+ else if (t->next->tag==PMINUS)
+ { t=t->next->next; n=n-getval(t); }
+ else break;
+ }
+ break;
+ case OCTAL: n=strtol(t->text+2,NULL,8);@+ break;
+ case HEX: n=strtol(t->text+2,NULL,16);@+ break;
+ case CHAR: n=(int)(unsigned char)t->text[1];@+ break;
+ case PCONSTID: n=SYM(t)->value;@+ break;
+ default: ERROR("Unable to get value for tag %s in line %d",TAG(t),t->lineno);
+ }
+ return n;
+}
+@
+
+Notice that I assume that tokens which are tagged as constant
+identifiers are expected to have a value stored in the symbol table. We
+write this value using the macro |SETVAL|.
+
+@<external declarations@>=
+#define SETVAL(t,val) @[SYM(t)->value=val@]
+@
+
+\subsection{Expanding module names and macros}
+\index{macro expansion}\index{module name expansion}
+Now let's turn to the more complicated operations, for example the
+expansion of module names. I know that I hit a module name\index{module name}
+when I encounter an ``\.{@@<}'' token. At this point, I advance
+the current token pointer past the end of the module name, look up
+the module in the module table, and push its first code segment.
+
+@<special treatment for \WEB/ tokens@>=
+ case ATLESS:
+ { token *eq, *atgreater;
+ atgreater = find_module(t)->atgreater;
+ CHECK(atgreater!=NULL,"Undefined module @@<%s ...@@> in line %d",
+ token2string(t->next),t->lineno);
+ DBG(dbgexpand,"Expanding module @@<%s@@> in line %d\n",
+ token2string(t->next),t->lineno);
+ eq=atgreater->next;
+ pp_stack[pp_sp].next=t->link->next;
+ t=pp_push(atgreater->link,eq,0,NULL);
+ continue;
+ }
+@
+
+When I reach the end of the code segment, I can check the link field
+to find its continuation.
+
+@<process the end of a code segment@>=
+ token *link=pp_stack[pp_sp].link;
+ if (link!=NULL)
+ { token *eq;
+ eq=link->next;
+ link=link->link;
+ pp_pop();
+ t=pp_push(link,eq,0,NULL);
+ }
+ else
+ t=pp_pop();
+@
+
+Slightly simpler are ordinary macros\index{ordinary macro}.
+@<special treatment for \WEB/ tokens@>=
+ case OMACRO:
+ { token *eq;
+ eq=SYM(t)->eq;
+ pp_stack[pp_sp].next=t->next;
+ DBG(dbgexpand,"Expanding ordinary macro %s in line %d\n",token2string(t),t->lineno);
+ t=pp_push(NULL,eq,0,NULL);
+ continue;
+ }
+@
+
+There are a few macros, that are special\index{special macro}; I do not want to expand
+them but instead generate special tokens in \.{web.l}\index{web.l+\.{web.l}} and expand the
+\Pascal/ grammar to cope with them directly. It remains, however, to
+mark them as obsolete\index{obsolete} to remove the macro definitions form the \cweb/
+output.
+
+@<finalize token list@>=
+SYM_PTR("return")->obsolete=1;
+SYM_PTR("endcases")->obsolete=1;
+SYM_PTR("othercases")->obsolete=1;
+SYM_PTR("mtype")->obsolete=1;
+SYM_PTR("final_end")->obsolete=1;
+@
+
+\subsection{Expanding macros with parameters}
+
+Now I come to the most complex case: parametrized macros\index{parametrized macro}.
+When the \WEB/ invokes a parametrized macro as part of the \Pascal/ code, the macro
+identifier is followed by a ``\.{(}'' token, the parameter tokens, and
+a matching ``\.{)}'' token. The \WEB/ scanner has also set the |link|
+field of the ``\.{(}'' token to point to the ``\.{)}'' token. The
+replacement text for the macro is found in the same way as for
+ordinary macros above. The replacement text, however, may now contain
+a ``\.{\#}'' token, asking for another replacement by the parameter
+tokens. The whole process can be nested because the parameter tokens
+may again contain a ``\.{\#}'' token. Hence, I need to store the
+parameter tokens on the stack as well as a reference to the enclosing
+environment\index{environment}. I store a reference to the ``\.{(}''
+token on the stack\index{stack},
+because from it, I can get the first token and the last token of the
+replacement text\index{replacement text}.
+
+I can write now the code to expand a parametrized macro. To cope
+with cases like \.{font(x)}, \.{font == type} and
+\.{type(\#)=mem[\#]}, I call |pplex| to find the opening parenthesis
+before pushing the macro expansion and its parameter.
+(Note: I expand \.{font} as an ordinary macro; then find \.{type}
+which is a parametrized macro and end up in the ``|case PMACRO:|''
+below. The ``\.{(}'' token is not the next token after \.{type}
+because I am still expanding \.{font}. Calling |pplex| will reach
+the end of the expansion, pop the stack, and then find the ``\.{(}''
+token.)
+
+@<special treatment for \WEB/ tokens@>=
+ case PMACRO:
+ { token *open,*eq;
+ int popen;
+ DBG(dbgexpand,"Expanding parameter macro %s in line %d\n",
+ token2string(t),t->lineno);
+ eq=SYM(t)->eq;
+ pp_stack[pp_sp].next=t->next;
+ popen=pplex();
+ CHECK(popen==POPEN,"expected ( after macro with parameter");
+ open=pplval;
+ pp_stack[pp_sp].next=open->link->next;
+ @<count macro parameters@>@;
+ t=pp_push(NULL,eq,pp_sp,open);
+ continue;
+ }
+@
+
+
+While traversing the replacement text, I may find a ``\.{\#}'' token.
+In this case, I find on the |pp_stack| the pointer to the |parameter| and,
+in case the |parameter| contains again a ``\.{\#}'' token, its |environment|.
+
+@<special treatment for \WEB/ tokens@>=
+ case HASH:
+ { token *parameter=pp_stack[pp_sp].parameter;
+ int environment=pp_stack[pp_sp].environment;
+ pp_stack[pp_sp].next=t->next;
+ t=pp_push(NULL,parameter,pp_stack[environment].environment,
+ pp_stack[environment].parameter);
+ continue;
+ }
+@
+
+
+\subsection{The function |ppparse|}
+The function |ppparse| is implemented in the
+file \.{pascal.y}\index{pascal.y+\.{pascal.y}}
+which must be processed by \.{bison}\index{bison+\.{bison}}
+(the free version of \.{yacc}\index{yacc+\.{yacc}})
+to produce \.{pascal.tab.c}\index{pascal tab c+\.{pascal.tab.c}}
+and \.{pascal.tab.h}\index{pascal tab h+\.{pascal.tab.h}}.
+The former contains the definition of the parser function |ppparse|
+which I call after initializing the |pp_stack| in preparation
+for the first call to |pplex|.
+
+@<parse \Pascal/@>=
+ program=first_token->link;
+ pp_push(program->link, program->next, 0, NULL);
+ ppparse();
+@
+
+
+The function |ppparse| occasionally builds a parse tree\index{parse tree}
+ out of internal nodes\index{internal node} for the \Pascal/ program;
+this parse tree is then used to accomplish the transformations
+needed to turn the \Pascal/ code into \CEE/ code.
+
+@<internal node@>=
+struct {
+ int value;
+}
+@
+
+
+Internal nodes are constructed using the function |join|.
+@<external declarations@>=
+token *join(int tag, token *left, token *right, int value);
+@
+
+@<functions@>=
+token *join(int tag, token *left, token *right, int value)
+{ token *n=new_token(tag);
+ n->previous=left;
+ n->next=right;
+ n->value = value;
+ DBG(dbgjoin,"tree: "); DBGTREE(dbgjoin,n);
+ return n;
+}
+@
+
+
+\section{Writing the \cweb/}
+\label{writing}%
+
+\subsection{\cweb/ output routines}
+
+\index{output routine}The basic function to write the \cweb/ file is the function |wprint|,
+along with its simpler cousins |wput| and |wputs|, and the more
+specialized member of the family |wputi|. While most of the work of
+converting the visual representation of tokens to \cweb/ is left to
+the function |token2string|, the basic functions take care of
+inserting spaces\index{space} after a comma\index{comma} and to prevent adjacent tokens from
+running together.
+
+The variables |alfanum| and |comma| indicate that the last character
+written was alphanumeric or a comma; the variable |column| counts the
+characters on the current line.
+
+@<global variables@>=
+static int alfanum=0;
+static int comma=0;
+static int column=0;
+@
+
+@<functions@>=
+static void wput(char c)
+{ fputc(c,w);
+ alfanum = isalnum(c);
+ comma = c==',';
+ if (c=='\n') column=0;@+ else column++;
+}
+
+static void wputs(char *str)
+{ while (*str!=0) wput(*str++);
+}
+
+static void wputi(int i)
+{ if (alfanum || comma) fputc(' ',w),column++;
+ column+=fprintf(w,"%d",i);
+ alfanum=true;
+ comma=false;
+}
+
+static void wprint(char *str)
+{ if ((alfanum || comma) && isalnum(str[0])) fputc(' ',w);
+ wputs(str);
+}
+@
+
+
+Most tokens have their string representation stored in the |info.text| field,
+so I sketch the function |token2string| here and
+describe the details of conversion later.
+@<internal declarations@>=
+static char *token2string(token *t);
+@
+
+@<functions@>=
+static char *token2string(token *t)
+{ CHECK(t!=NULL,"Unable to convert NULL token to a string");
+ switch (t->tag)
+ { default:
+ if (t->text!=NULL)
+ return t->text;
+ else
+ return "";
+ @<convert token |t| to a string@>@;
+ }
+}
+@
+
+
+\subsection{Traversing the \WEB/}
+
+After these preparations, I am ready to traverse the list of tokens
+ again; this time not in \Pascal/ order but in the order given
+ in the \WEB/ file because I want the \cweb/ file to be as close as
+ possible to the original \WEB/ file.
+
+The main loop can be performed by the function |wprint_to|. It
+traverses the token list until a given |last_token| is found. Using
+this function I can generate the whole \cweb/ file simply by starting
+with the |first_token| and terminating with the |last_token|.
+
+@<generate \cweb/ output@>=
+ wprint_to(first_token,last_token);
+@
+
+The function |wprint_to| delegates all the work to |wtoken| which in
+turn uses |wprint| and |token2string| after converting the tokens from
+\WEB/ to \cweb/ as necessary. Besides writing out the token, |wtoken|
+also advances past the written token and returns a pointer to the
+token immediately following it. The function |wtoken| will be called
+recursively. For debugging\index{debugging} purposes, it maintains a counter of its
+nesting |level|.
+
+@<functions@>=
+static token *wtoken(token *t)
+{ static int level=0;
+ level++;
+ DBG(dbgcweb,"wtoken[%d] %s (%s) line %d\n",level,TAG(t),token2string(t),t->lineno);
+ switch(t->tag)
+ { @<convert |t| from \WEB/ to \cweb/@>@;
+ default: wprint(token2string(t));@+ t=t->next;@+ break;
+ }
+ level--;
+ return t;
+}
+@
+
+|wprint_to| is complemented by the function |wskip_to| which
+ suppresses the printing of tokens.
+
+@<internal declarations@>=
+static token *wprint_to(token *t, token *end);
+static token *wskip_to(token *t, token *end);
+@
+
+@<functions@>=
+static token *wprint_to(token *t, token *end)
+{ while(t!=end)
+ t=wtoken(t);
+ return t;
+}
+
+static token *wskip_to(token *t, token *end)
+{ while(t!=end)
+ t=t->next;
+ return t;
+}
+@
+
+\subsection{Simple cases of conversion}
+
+Quite a few tokens serve a syntactical purpose in \Pascal/ but are
+simply ignored when generating \CEE/ code.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+ case CIGNORE: case PPROGRAM: case PLABEL: case PCONST: case PVAR:
+case PPACKED: case POF: case ATQM: case ATBACKSLASH:@/
+t=t->next;@+ break;
+@
+The parser will change a |tag| to |CIGNORE| by using the |IGN| macro.
+@<external declarations@>=
+#define IGN(t) @[((t)->tag=CIGNORE)@]
+@
+
+\TeX\ uses the control sequence ``\.{@@t\\2@@>}'' after ``{\bf
+forward};''. It needs to be removed together with the forward
+declaration, because it does confuse \cweb/.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PFORWARD:
+ if (t->next->tag==PSEMICOLON) wput(';'),t=t->next->next;
+ else wprint("forward"),t=t->next;
+ if (t->tag==ATT) t=t->next;
+ break;
+@
+
+
+The meta-comments\index{meta-comment} of \WEB/ are translated to
+plain \CEE/ comments\index{comment} if
+they are just a single line and to \.{\#if 0}\dots\.{\#endif}
+otherwise.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case METACOMMENT:
+ { char *c;
+ wputs("/*");
+ for (c=t->text+2; c[0]!='@@' || c[1]!='}'; c++) wput(*c);
+ wputs("*/");
+ t=t->next;
+ }
+ break;
+case ATLEFT:
+ if (column!=0) wput('\n');
+ wputs("#if 0\n");
+ t=t->next;@+break;
+case ATRIGHT:
+ if (column!=0) wput('\n');
+ wputs("#endif\n");
+ t=t->next;@+break;
+@
+
+Some tokens just need a slight adjustment of their textual
+representation. In other cases, the parser changes the tag of a
+token, for example to |PSEMICOLON|, without changing the textual
+representation of that token. All these tokens are listed below.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PLEFT: case MLEFT: wputs(" /*");@+t=t->next;@+ break;
+case RIGHT: wputs("*/ ");@+t=t->next;@+ break;
+case PSEMICOLON: wputs(";");@+t=t->next;@+ break;
+case PCOMMA: wputs(",");@+t=t->next;@+ break;
+case PMOD: wput('%');@+t=t->next;@+ break;
+case PDIV: wput('/');@+t=t->next;@+ break;
+case PNIL: wprint("NULL");@+t=t->next;@+ break;
+case POR: wputs("||");@+t=t->next;@+ break;
+case PAND: wputs("&&");@+t=t->next;@+ break;
+case PNOT: wputs("!");@+t=t->next;@+ break;
+case PIF: wprint("if (");@+t=t->next;@+ break;
+case PTHEN: wputs(") ");@+t=t->next;@+ break;
+case PASSIGN: wput('=');@+t=t->next;@+ break;
+case PNOTEQ: wputs("!=");@+t=t->next;@+ break;
+case PEQ: wputs("==");@+t=t->next;@+ break;
+case EQEQ: wput('\t');@+t=t->next;@+ break;
+case OCTAL: wprint("0");@+ wputs(t->text+2);@+t=t->next;@+ break;
+case HEX: wprint("0x");@+ wputs(t->text+2);@+t=t->next;@+ break;
+case PTYPEINT: wprint("int");@+t=t->next;@+ break;
+case PTYPEREAL: wprint("double");@+t=t->next;@+ break;
+case PTYPEBOOL: wprint("bool");@+t=t->next;@+ break;
+case PTYPECHAR: wprint("unsigned char");@+t=t->next;@+ break;
+@
+
+I convert ``\&{begin}'' to ``\.{\LB}''. In most cases, I want an ``\.{@@+}'' to
+follow; except of course if a preprocessor directive is following.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PBEGIN: wput('{'),t=t->next;
+ if (!following_directive(t)) wputs("@@+");
+ break;
+@
+@<internal declarations@>=
+static bool following_directive(token *t);
+@
+@<functions@>=
+static bool following_directive(token *t)
+{ while (true)
+ if (WDEBUG<=t->tag && t->tag<=WGUBED) return true;
+ else if (t->tag==ATPLUS || t->tag==ATEX || t->tag==ATSEMICOLON ||
+ t->tag==NL || t->tag==INDENT) t=t->next;
+ else return false;
+}
+@
+
+After the conversion, the \Pascal/ token ``\.{..}'' will
+still occur in the file as part of code between vertical bars.
+To make it print nicely in the \TeX\ output,
+it is converted to an identifier, ``\.{dotdot}''\index{dotdot+\.{dotdot}}, that is
+used nowhere else.
+@<convert |t| from \WEB/ to \cweb/@>=
+case PDOTDOT: wprint("dotdot");@+t=t->next;@+ break;
+@
+Using the patch file, I instruct \.{cweave} to treat this identifier in a special way
+and print it like ``${}\mathrel{.\,.}{}$''.
+
+\subsection{\Pascal/ division}
+
+In some cases build-in functions\index{build-in function}
+of \Pascal/ can be replaced by a
+suitably defined macro in \CEE/. The most simple solution was to add
+these definitions to the
+module ``$\langle\,${\eightrm Compiler directives}$\,\rangle$'' using
+the patch file\index{patch file}.
+Using Macros instead of inline replacement has the advantage
+that the visual appearance of the original code remains undisturbed.
+A not so simple case is the \Pascal/ division\index{division}.
+
+The \Pascal/ language has two different division\index{division} operators: ``{\bf
+div}'' divides two integers and gives an integer result; it can be
+replaced by ``|/|'' in the \CEE/ language. The \Pascal/ operator
+``|/|'' divides |integer| and \&{real} values and converts both operands
+to type \&{real} before doing so; replacing it simply by the \CEE/
+operator ``|/|'' will give different results if both operands are
+\&{integer} values because in this case \CEE/ will do an integer
+division truncating the result. So expressions of the form ``|X / Y|''
+should be replaced by ``|X / (double)(Y)|'' to force a
+floating point division\index{floating point division} in \CEE/
+
+% these are the instances of real division in \.{tex.web}:
+%Pascal real division / in line 13032
+%if total_stretch[o]<>0 then glue_set(r):=unfloat(x/total_stretch[o])
+%
+%Pascal real division / in line 13091
+%if total_shrink[o]<>0 then glue_set(r):=unfloat((-x)/total_shrink[o])
+%
+%Pascal real division / in line 13223
+%if total_stretch[o]<>0 then glue_set(r):=unfloat(x/total_stretch[o])
+%
+%Pascal real division / in line 13262
+%if total_shrink[o]<>0 then glue_set(r):=unfloat((-x)/total_shrink[o])
+%
+%Pascal real division / in line 15929
+% else glue_set(r):=unfloat((t-width(r))/glue_stretch(r));
+%
+%Pascal real division / in line 15936
+% else glue_set(r):=unfloat((width(r)-t)/glue_shrink(r));
+%
+%Pascal real division / in line 15950
+% else glue_set(r):=unfloat((t-height(r))/glue_stretch(r));
+%
+%Pascal real division / in line 15957
+% else glue_set(r):=unfloat((height(r)-t)/glue_shrink(r));
+%
+%Pascal real division / in line 21484
+% begin x:=x_height(f); s:=slant(f)/float_constant(65536);
+%
+%Pascal real division / in line 21513
+%begin t:=slant(f)/float_constant(65536);
+%
+%Pascal real division / in line 21520
+%delta:=round((w-a)/float_constant(2)+h*t-x*s);
+
+Fortunately, all expressions in the denominator have the form
+|total_stretch[o]|, |total_shrink[o]|, |glue_stretch(r)|,
+|glue_shrink(r)|, or |float_constant(n)|. So no parentheses around
+the denominator are required and inserting a simple |(double)| after
+the |/| is sufficient. Further, the macro |float_constant| is already
+a cast to \&{double}, so I can check for the corresponding identifier
+and omit the extra cast.
+
+@<global variables@>=
+static int float_constant_no;
+@
+
+@<initialize token list@>=
+float_constant_no=predefine("float_constant",ID,0);
+@
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PSLASH:
+ wput('/');
+ if (t->next->tag!=PMACRO || t->next->sym_no!=float_constant_no)
+ { wprint("(double)");
+ DBG(dbgslash,"Inserting (double) after / in line %d\n",t->lineno);
+ }
+ t=t->next;@+break;
+@
+
+
+\subsection{Identifiers}
+
+Before I can look at the identifiers\index{identifier}, I have to consider the
+``\.{@@!}'' token which can precede an identifier and will cause the
+identifiers to appear underlined in the index\index{index}. The ``\.{@@!}'' token
+needs a special treatment. When I convert \Pascal/ to \CEE/, I have
+to rearrange the order of tokens and while I am doing so, a
+``\.{@@!}'' token that precedes an identifier should stick to the
+identifier and move with it. I accomplish this by suppressing the
+output of the ``\.{@@!}'' token if it is followed by an identifier,
+and insert it again when I output the identifier itself.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case ATEX:
+t=t->next;
+if (t->tag!=ID && t->tag!=PID && t->tag!=PFUNCID &&@/
+ t->tag!=PDEFVARID && t->tag!=PDEFPARAMID && t->tag!=PDEFTYPEID &&@/
+ t->tag!=OMACRO&& t->tag!=PMACRO && t->tag!=NMACRO &&@/
+ t->tag!=CINTDEF && t->tag!=CSTRDEF && t->tag!=PDIV &&@/
+ t->tag!=WDEBUG && t->tag!=WINIT && t->tag!=WSTAT)
+{ wputs("@@!");
+ DBG(dbgbasic,"Tag after @@! is %s in line %d\n",tagname(t->tag), t->lineno);
+}
+break;
+@
+
+Identifier tokens are converted by using their name. I use a simple
+function to do the name lookup and take care of adding the ``\.{@@!}''
+token if necessary.
+
+@<internal declarations@>=
+static void wid(token *t);
+@
+@<functions@>=
+void wid(token *t)
+{ if (alfanum || comma) wput(' ');
+ if (t->previous->tag==ATEX) wputs("@@!");
+ wputs(SYM(t)->name);
+}
+@
+I use this function like this:
+@<convert |t| from \WEB/ to \cweb/@>=
+case ID:
+case PID:
+case OMACRO:
+case PMACRO:
+case NMACRO:
+ wid(t);@+t=t->next;@+ break;
+@
+
+Some identifiers that \TeX\ uses are reserved words\index{reserved words}
+in \CEE/ or loose their special meaning. So after I finish scanning the \WEB/, I
+change the names of these identifiers.%
+\index{xclause+\\{xclause}}%
+\index{switch+\&{switch}}%
+\index{continue+\&{continue}}%
+\index{exit+\\{exit}}%
+\index{free+\\{free}}%
+\index{int+\&{int}}%
+\index{remainder+\\{remainder}}%
+
+
+@<finalize token list@>=
+SYM_PTR("xclause")->name="else";
+SYM_PTR("switch")->name="get_cur_chr";
+SYM_PTR("continue")->name="resume";
+SYM_PTR("exit")->name="end";
+SYM_PTR("free")->name="is_free";
+SYM_PTR("int")->name="i";
+SYM_PTR("remainder")->name="rem";
+@
+
+A special case is the the field identifier |int|. It can not be used
+in \CEE/ because it is a very common (if not the most common) reserved
+word. I replace it with |i| which does not conflict with the
+variable |i| because field names have their own name-space in \CEE/.
+
+
+
+\subsection{Strings}
+
+Pascal strings\index{string} need some more work. I translate them to characters or
+\CEE/ strings. Note that the parser occasionally converts |STRING| or
+|CHAR| tokens to |PSTRING| tokens.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PCHAR:
+ { char *str=t->text;
+ wput(' ');
+ wput('\''),str++;
+ if (str[0]=='\'') wputs("\\'");
+ else if (str[0]=='\\') wputs("\\\\");
+ else if (str[0]=='@@') wputs("@@@@");
+ else wput(str[0]);
+ wput('\'');
+ wput(' ');
+ }
+ t=t->next;@+
+ break;
+case PSTRING:
+ { char *str=t->text;
+ wput('"'),str++;
+ while (*str!=0)
+ { if (str[0]=='\'' && str[1]=='\'') wput('\''),str++;
+ else if (str[0]=='"' && str[1]=='"') wputs("\\\""),str++;
+ else if (str[0]=='\\') wputs("\\\\");
+ else if (str[0]=='\'' && str[1]==0) wput('"');
+ else if (str[0]=='"' && str[1]==0) wput('"');
+ else if (str[0]=='"') wput('\\'), wput('"');
+ else wput(str[0]);
+ str++;
+ }
+ }
+ t=t->next;@+
+ break;
+@
+
+\subsection{Module names}
+
+I have removed newlines and extra spaces from module names\index{module name};
+now I have to insert newlines\index{newline} if the module names are too long.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case ATLESS:
+ wputs("@@<");
+ t=t->next;
+ CHECK(t->tag==TEXT,"Module name expected instead of %s in line %d",
+ token2string(t), t->lineno);
+ { char *str=t->text;
+ do
+ if (str[0]=='@@' && str[1]==',')
+ str=str+2; /*control codes are forbidden in section names*/
+ else if (column>80 && isspace(*str)) wput('\n'),str++;
+ else wput(*str++);
+ while (*str!=0);
+ }
+ t=t->next;
+ if (t->tag==ELIPSIS) wputs("..."), t=t->next;
+ CHECK(t->tag==ATGREATER,"@@> expected instead of %s in line %d",
+ token2string(t), t->lineno);
+ wputs("@@>");
+ t=t->next;
+ if (t->tag==ATSLASH) wputs("@@;"),t=t->next;
+ else if (t->tag==PELSE ||
+ (t->tag==NL)) wputs("@@;");
+ break;
+@
+
+Note that I replace an ``\.{@@/}'' after the module name by an
+``\.{@@;}'' Because in most places this is enough to cause the
+requested new line and causes the correct indentation.
+
+
+\subsection{Replacing the \WEB/ string pool file}
+\label{stringpool}%
+\WEB/ strings need more work because I have to replace the \WEB/
+string pool\index{string pool} file. Before I start, I finish two easy cases. Single
+character strings are replaced by \CEE/ character constants\index{character constant}. The
+string pool checksum\index{string pool checksum} is simply replaced by zero,
+because I will not use it.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case CHAR:
+ { char c=t->text[1];
+ wput('\'');
+ if (c=='\'' || c=='\\') wput('\\');
+ wput(c);
+ wput('\'');
+ t=t->next;@+ break;
+ }
+case ATDOLLAR: wputs("0");@+t=t->next;@+ break;
+@
+
+
+Of course it would be possible to generate suitable initializations
+for the variables |str_pool| and |str_start| and replace each string
+with its corresponding index in the |str_start| array. The goal of my
+project is, however, to generate readable source code and
+replacing for example |"Maybe you should try asking a human?"| by
+|283| is not very readable. Instead, I will create for each string a
+module, in the above example named \PB{$\X1234:\PB{\.{"Maybe you
+should try asking} \.{a} \.{human?"}}\X$}, that will expand to the
+correct number, here |283|.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case STRING:
+ { @<convert some strings to macro names@>@;
+ else
+ { wputs("@@[@@<|");@+wputs(SYM(t)->name);@+wputs("|@@>@@]");@+ }
+ t=t->next;@+ break;
+ }
+@
+
+There are some exceptions to the general rule, for example for the
+empty string\index{empty string}.
+I define an appropriate constant |empty_string| and
+use it instead of a module (which would have a rather unsightly
+name). More instances of this scheme follow below.
+
+@<convert some strings to macro names@>=
+ if (t->sym_no==empty_string_no)
+ wprint("empty_string");
+@
+
+
+To define all the other new modules, I add some code at the very end
+of the output file.
+
+@<generate \cweb/ output@>=
+wputs("\n@@ Appendix: Replacement of the string pool file.\n");
+{ token *str_k;
+ int i, k;
+ @<generate definitions for the first 256 strings@>@;
+ for (str_k=first_string;str_k != NULL;str_k=str_k->link)
+ @<generate definition for string |k|@>@;
+ @<generate string pool initializations@>@;
+}
+@
+
+The first 256 strings in the string pool\index{string pool}
+are the printable replacements
+for the single character strings for all character codes from 0 to 255.
+
+@<generate definitions for the first 256 strings@>=
+wputs("@@d str_0_255 ");
+for (k=0;k<256;k++)
+{ if ((k&0xF)==0) wputs("\t\"");
+ if ((@<Character |k| cannot be printed@>))
+ { wputs("^^");
+ if (k<0100 && k+0100=='@@') wputs("@@@@");
+ else if (k<0100 && k+0100=='\\') wputs("\\\\");
+ else if (k < 0100) wput(k+0100);
+ else if (k<0200 && k-0100=='@@') wputs("@@@@");
+ else if (k < 0200) wput(k-0100);
+#define HEXDIGIT(x) ((x)<10?((x)+'0'):((x)-10+'a'))
+ else wput(HEXDIGIT(k/16)),wput(HEXDIGIT(k%16));
+ }
+ else if (k=='"') wputs("\\\"");
+ else if (k=='\\') wputs("\\\\");
+ else if (k=='@@') wputs("@@@@");
+ else wput(k);
+ if ((k&0xF)==0xF) wputs("\"@@/\n");
+}
+wputs("@@d str_start_0_255");
+i=0;
+for (k=0;k<256;k++)
+{ if ((k&0xF)==0) wput('\t');
+ wputi(i);
+ if ((@<Character |k| cannot be printed@>))
+ { if (k < 0100) i=i+3;
+ else if (k < 0200) i=i+3;
+ else i=i+4;
+ }
+ else i=i+1;
+ wput(',');
+ if ((k&0xF)==0xF) wputs("@@/\n");
+}
+@
+
+This condition is taken from \.{tex.web}:
+@<Character |k| cannot be printed@>=
+ (k < ' ')||(k > '~')
+@
+
+
+@<generate definition for string |k|@>=
+{ symbol *s=SYM(str_k);
+ if (s->value>0)
+ { s->value=0;
+ wputs("@@ \n");
+ wputs("@@d str_"),wputi(k),wput(' '),wputs(s->name),wput('\n');
+ @<generate macros for some strings@>@;
+ else
+ wputs("@@<|"),wputs(s->name),wputs("|@@>=@@+"),wputi(k);
+ wput('\n');
+ k++;
+ }
+}
+@
+
+There are, however, a few more exceptions to the general procedure.
+Many of the \WEB/ strings are used simply for printing with
+the procedure |print|. There is actually no need to enter all these
+strings into the string pool\index{string pool}.
+Instead I add a procedure |print_str|
+that prints plain zero terminated \CEE/ strings.
+
+Now I can convert the |STRING| argument of the procedure |print| to
+a |PSTRING| by calling the following procedures in the parser.
+
+@<external declarations@>=
+extern void pstring_args(token *id, token *arg);
+extern void pstring_assign(token *id, token *val);
+@
+
+The function |pstring_args| is called with the |id| of the
+function. The |arg| token points to the argument list. A few other
+functions just pass their arguments to |print|. By replacing their
+call to |print| by a call to |print_str|, I can convert those
+arguments as well. For example the function |overflow| expects two
+arguments of which the first one is the |STRING| token. The other
+functions are: |prompt_file_name|, |print_nl|, and |fatal_error|.
+
+If a |STRING| token is found, its |value| in the symbol table is
+decremented. This |value| counts the number of occurrences; if it
+goes down to zero, the |STRING| token is no longer used and no module
+needs to be generated for it.
+
+@<functions@>=
+static int convert_arg( token *arg)
+{ if (arg->tag==STRING)
+ { symbol *s=symbol_table[arg->sym_no];
+ s->value--;
+ DBG(dbgstring,"Eliminating string argument %s (%d) in line %d\n",s->name,s->value,arg->lineno);
+ arg->tag=PSTRING;
+ return 1;
+ }
+ else if (arg->tag==CHAR)
+ { arg->tag=PSTRING;
+ return 1;
+ }
+ return 0;
+}
+void pstring_args(token *id, token *arg)
+{ if (arg->tag==PCOLON || arg->tag==CREFID) return;
+ if (id->sym_no==overflow_no || id->sym_no==prompt_file_name_no )
+ { CHECK(arg->tag==PCOMMA,"function should have two arguments in line %d",id->lineno);
+ convert_arg(arg->previous);
+ }
+ else if (id->sym_no==print_no)
+ { if (convert_arg(arg)) id->sym_no=print_str_no;
+ }
+ else if ( id->sym_no==print_str_no
+ || id->sym_no==print_nl_no
+ || id->sym_no==fatal_error_no
+ )
+ convert_arg(arg);
+}
+@
+
+The function |pstring_assign| is used when |STRING| tokens are
+assigned to the variable |help_line|, which I redefine as a
+variable containing character pointers instead of string numbers.
+
+@<functions@>=
+void pstring_assign(token *id, token *val)
+{ if (id->tag==PID && ( id->sym_no==help_line_no || id->sym_no==max_reg_help_line_no))
+ { SYM(val)->value--;
+ DBG(dbgstring,"Eliminating string assignment %s (%d) in line %d\n",
+ SYM(val)->name,SYM(val)->value,val->lineno);
+ val->tag=PSTRING;
+ }
+ else
+ DBG(dbgstring,"No string assignment %s (%d) in line %d\n",
+ SYM(val)->name,SYM(val)->value,val->lineno);
+}
+@
+Note: |max_reg_help_line| is used in $\epsilon$-\TeX\index{e-TeX+$\epsilon$-\TeX}.
+
+I have used these variables:
+@<global variables@>=
+int print_no, print_str_no, overflow_no, print_err_no,
+print_nl_no, fatal_error_no, prompt_file_name_no,
+help_line_no, empty_string_no, max_reg_help_line_no;
+@
+The variables are initialized like this:
+
+@<functions@>=
+int predefine(char *name, int tag, int value)
+{ int sym_no= get_sym_no(name);
+ symbol *s= symbol_table[sym_no];
+ s->tag=tag;
+ s->value=value;
+ return sym_no;
+}
+@
+
+@<initialize token list@>=
+print_str_no=predefine("print_str",PPROCID,0);
+empty_string_no=predefine("\"\"",PID,1);
+help_line_no=predefine("help_line",ID,0);
+print_no=predefine("print",PPROCID,0);
+overflow_no=predefine("overflow",PPROCID,0);
+print_err_no=predefine("print_err",PPROCID,0);
+print_nl_no=predefine("print_nl",PPROCID,0);
+fatal_error_no=predefine("fatal_error",PPROCID,0);
+prompt_file_name_no=predefine("prompt_file_name",PPROCID,0);
+max_reg_help_line_no=predefine("max_reg_help_line",ID,0);
+@
+
+There are still a few remaining problems.
+First, |STRING| tokens occur occasionally as part of a
+macro replacement text\index{replacement text}.
+There I can not substitute a module name\index{module name} for them.
+By having introduced the function |print_str|, some
+of them are now plain \CEE/ strings:
+|"pool size"| in line 1184 (|overflow|),
+|"! "| in line 1750 (|print_nl|)
+|"save size"| in line 5910 (|overflow|),
+|"input stack size"| in line 6940 (|overflow|),
+|"Font "| in line 10927 (|print_err|),
+|" at "| in line 10930 (|print|),
+|"pt"| in line 10930 (|print|),
+|" scaled "| in line 10933 (|print|), and
+|" plus "| in line 19250 (|print|).
+
+Most other macros are numeric macros\index{numeric macro},
+ and I just generate these instead of module names:
+|"TeXinputs:"| in line 9992 (|TEX_area|),
+|"TeXfonts:"| in line 9994 (|TEX_font_area|),
+|".fmt"| in line 10082 (|format_extension|),
+the |empty_string| in line 10928, and
+\.{"0234000122*}\)\.{4000133**3**344*}\)\.{0400400*0000}\)\.{00234000111*}\)\.{111111}\)\.{2341011"}
+in line 15049 (|math_spacing|).
+
+I have shown already some of the handling of the empty string\index{empty string};
+the rest follows now:
+
+@<convert some strings to macro names@>=
+ else@+ if (t->sym_no==TeXinputs_no) wprint("TEX_area");
+ else if (t->sym_no==TeXfonts_no) wprint("TEX_font_area");
+ else if (t->sym_no==fmt_no) wprint("format_extension");
+ else if (t->sym_no==math_spacing_no) wprint("math_spacing");
+@
+
+@<generate macros for some strings@>=
+ if (str_k->sym_no==empty_string_no) wputs("@@d empty_string "),wputi(k);
+ else if (str_k->sym_no==TeXinputs_no) wputs("@@d TEX_area "),wputi(k);
+ else if (str_k->sym_no==TeXfonts_no) wputs("@@d TEX_font_area "),wputi(k);
+ else if (str_k->sym_no==fmt_no) wputs("@@d format_extension "),wputi(k);
+ else if (str_k->sym_no==math_spacing_no) wputs("@@d math_spacing "),wputi(k);
+@
+
+@<global variables@>=
+int TeXinputs_no, TeXfonts_no, fmt_no, math_spacing_no;
+@
+@<initialize token list@>=
+TeXinputs_no=predefine("\"TeXinputs:\"",PID,0);
+TeXfonts_no=predefine("\"TeXfonts:\"",PID,0);
+fmt_no=predefine("\".fmt\"",PID,0);
+math_spacing_no=predefine(
+ "\"0234000122*4000133**3**344*0400400*000000234000111*1111112341011\"",PID,1);
+@
+
+I am left with the macro |ensure_dvi_open|, containing
+|".dvi"| in line 10284,\index{.dvi+\.{.dvi}}
+|"file name for output"| in line 10286, and
+|".dvi"| in line 10286,
+which I simply turn into a module of the same name using the patch file\index{patch file}.
+
+I conclude the generation of \cweb/ output by generating
+initializations for the |str_pool| and |str_start| array.
+@<generate string pool initializations@>=
+ wputs("\n@@ All the above strings together make up the string pool.\n"
+ "@@<|str_pool| initialization@@>=\n"
+ "str_0_255\n");
+ for (i=256; i<k;i++)
+ { wputs("str_"),wputi(i);
+ if ((i&7)==7) wputs("@@/\n");@+ else wput(' ');
+ }
+ wputs("\n\n@@ @@<|str_start| initialization@@>=\n"
+ "str_start_0_255\n");
+ for (i=256; i<k;i++)
+ { wputs("str_start_"),wputi(i),wput(',');
+ if ((i&3)==3) wput('\n');@+ else wput(' ');
+ }
+ wputs("str_start_"),wputi(k);
+ wputs("\n\n"@/
+ "@@ We still need to define the start locations of the strings.\n"@/
+ "@@<prepare for string pool initialization@@>=\n"@/
+ "typedef enum {\n"@/
+ "str_start_256=sizeof(str_0_255)-1,\n");
+ for (i=257; i<=k;i++)@/
+ wputs("str_start_"),wputi(i),wputs("=str_start_"),wputi(i-1),
+ wputs("+sizeof(str_"),wputi(i-1),wputs(")-1,@@/\n");
+
+ wputs("str_start_end } str_starts;\n"@/
+ "\n@@ @@<|pool_ptr| initialization@@>= str_start_"),wputi(k),wputs("\n"@/
+ "\n@@ @@<|str_ptr| initialization@@>= "), wputi(k), wput('\n');@/
+@
+
+
+\subsection{Macro and format declarations}
+When I convert a macro\index{macro declaration}\index{format declaration},
+I first check if the translation has made it
+obsolete\index{obsolete} in which case I skip it. Otherwise, I output the initial
+part of the macro declaration up to the equal sign. From here on, I
+go different routes for the different types of declarations.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case ATD:
+ { token *eq=t->next->next;
+ DBG(dbgcweb,"Macro definition in line %d\n",t->lineno);
+ if (SYM(t->next)->obsolete)
+ t= wskip_to(t, eq->link);
+ else
+ { wputs("@@d "), t=t->next;@+
+ wprint(SYM(t)->name);
+ if (t->tag==NMACRO)
+ @<convert |NMACRO| from \WEB/ to \cweb/@>@;
+ else if (t->tag==OMACRO)
+ @<convert |OMACRO| from \WEB/ to \cweb/@>@;
+ else if (t->tag==PMACRO)
+ @<convert |PMACRO| from \WEB/ to \cweb/@>@;
+ else
+ ERROR("Macro name expected in line %d",t->lineno);
+ }
+ DBG(dbgcweb,"End Macro definition in line %d\n",t->lineno);
+ break;
+ }
+case ATF:
+ { token *eq=t->next->next;
+ DBG(dbgcweb,"Format definition in line %d\n",t->lineno);
+ if (SYM(t->next)->obsolete)
+ t= wskip_to(t, eq->link);
+ else
+ { wputs("@@f "), t=t->next;@+
+ wprint(SYM(t)->name);
+ t=wprint_to(eq->next,eq->link);
+ }
+ break;
+ }
+@
+
+Ordinary parameterless macros\index{parameterless macro} map directly to \CEE/ style macros.
+@<convert |OMACRO| from \WEB/ to \cweb/@>=
+{ wput('\t');
+ t=eq->next;
+}
+@
+
+\WEB/ features numeric macros\index{numeric macro} that are evaluated to a numeric value by
+\WEB/ before they are inserted into the final \Pascal/ program. When
+converting such macros to \CEE/ style macros, I have to make sure
+that a replacement text containing operators is evaluated as one
+expression. For example when \TeX\ defines
+$|single_base|\equiv|active_base|+256$, where $|active_base|\equiv 1$,
+then |print_esc(p-single_base)| should be evaluated as
+|print_esc(p-(1+256))| not|print_esc(p-1+256)|. So I add an extra
+pair of parentheses around the replacement text in case it contains a
+plus sign or a minus sign.
+
+@<convert |NMACRO| from \WEB/ to \cweb/@>=
+ { int has_operators;
+ wput('\t');
+ has_operators=0;
+ for (t=eq->next;t!=eq->link && t->tag!=MLEFT && t->tag!=NL;t=t->next)
+ if (t->tag==PPLUS || t->tag==PMINUS) { has_operators=1;@+ break;@+}
+ if (has_operators) wput('(');
+ for (t=eq->next;t!=eq->link && t->tag!=MLEFT && t->tag!=NL;t=wtoken(t))
+ continue;
+ if (has_operators) wput(')');
+ }
+@
+
+Parametrized macros\index{parametrized macro} in \WEB/ can use any number of arguments.
+In \CEE/, typical parametrized macros have a fixed number
+of arguments, variadic macros\index{variadic macro} being the exception rather
+than the rule. Therefore, I count the number of macro arguments
+each time I expand a macro. Since \TeX\ uses macros with a
+fixed number of arguments only for 1, 2, or 3 arguments,
+I use the value 4, for variadic macros.
+
+@<count macro parameters@>=
+{ token *p; int count=1;
+ if (open->next->tag==HASH)
+ { DBG(dbgmacro,"Counting %s parameters (#) in line %d\n", SYM(t)->name, t->lineno); }
+ else
+ { for (p=open->next; p!=open->link; p=p->next)
+ if (p->tag==PCOMMA) count++;
+ else if (p->tag==POPEN) p=p->link;
+ if (SYM(t)->value==0) SYM(t)->value=count;
+ else if (SYM(t)->value!=count) SYM(t)->value=4;
+ DBG(dbgmacro,"Counting %s parameters %d line %d\n", SYM(t)->name,SYM(t)->value, t->lineno);
+ }
+}
+@
+
+Now that I know the number of arguments,
+I can construct the macro definition\index{macro definition}.
+
+@<convert |PMACRO| from \WEB/ to \cweb/@>=
+{ static char *params[4]={"X","X","X, Y","X, Y, Z"}; /* if I have no information, I assume 1 */
+ char *param;
+ eq=eq->next; /* account for the \.{(\#)} token */
+ if (SYM(t)->value>3)
+ { param="...";@+ hash_str="__VA_ARGS__";@+}
+ else
+ hash_str=param=params[SYM(t)->value];
+ wput('('),wputs(param),wputs(")\t"), t=eq->next;
+}
+@
+
+@<global variables@>=
+static char *hash_str;
+@
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case HASH:
+ wprint(hash_str),t=t->next;@+break;
+@
+
+\subsection{Labels}
+
+In \CEE/, labels\index{label} are identifiers and labels do not need a declaration.
+So in the parser, I mark the tokens belonging to a
+label declaration\index{label declaration}
+with the tag |CIGNORE| and they will be ignored when the \cweb/ file
+is written.
+
+The tag |CLABEL| is used now to mark the labels when they are used.
+In most cases the labels in \TeX\ are numeric macros. So I use the
+name of the macro as the name of the |CLABEL| token and mark the
+definition of the numeric macro\index{numeric macro} as obsolete\index{obsolete}
+(Occasionally these label names are modified by adding an integer). In the rare cases where
+the label is indeed an integer, I use the tag |CLABELN|. In this
+case I add the prefix ``label'' to the numeric value to make it a
+\CEE/ identifier. Further, I count the number of times a label is
+used. Later transformation might render a label as unused and I can
+remove also the target label. The whole bookkeeping is achieved by
+calling the function |clabel| at appropriate places in the parser.
+
+@<external declarations@>=
+extern void clabel(token *t, int use);
+@
+@<functions@>=
+void clabel(token *t, int use)
+{
+ if (t->tag==NMACRO)
+ { SYM(t)->obsolete=true;
+ SYM(t)->value+=use;
+ t->tag=CLABEL;
+ }
+ else if (t->tag==CLABEL)
+ SYM(t)->value+=use;
+ else if (t->tag==PRETURN)
+ SYM(t)->value+=use;
+ else
+ { if (t->tag==PINTEGER)
+ t->tag=CLABELN;
+ return;
+ }
+ DBG(dbgstring,"Using label %s (%d) in line %d\n",SYM(t)->name,SYM(t)->value,t->lineno);
+}
+@
+
+A very special case is the \&{return} macro of \TeX;
+it is defined as |goto exit|\index{exit+\\{exit}}. I need to deal with it in a special
+way, because it usually follows the assignment of a function return
+value and therefore can be converted to a \CEE/ \&{return} statement.
+In the scanner, I create the PRETURN token and set its symbol number to
+the |exit| symbol.
+
+@<external declarations@>=
+extern int exit_no;
+#define TOK_RETURN {token *t=add_token(PRETURN); t->sym_no=exit_no; }
+@
+
+@<global variables@>=
+int exit_no;
+@
+
+@<initialize token list@>=
+exit_no=get_sym_no("exit");
+@
+
+
+While parsing, I replace the symbol number\index{symbol number}
+by the symbol pointer\index{symbol pointer}
+to reflect local\index{local label} |exit| labels.
+
+@<special treatment for \WEB/ tokens@>=
+ case PRETURN:
+ t->sym_ptr=SYM(t);
+ pp_stack[pp_sp].next=t->next;
+ goto found;
+@
+
+
+
+The output of the \CEE/-style labels is done with the following code.
+In the case of a |CLABEL|, I check the use-count in |value| and
+eliminate unused labels; I also check for a plus sign and a second
+number (remember labels in \Pascal/ are numeric values) and if found
+append the number to the label name.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case CLABEL:
+ if (t->sym_ptr->value<=0)
+ { t=t->next;
+ if (t->tag==PPLUS)
+ t=t->next->next;
+ if (t->tag==PCOLON)
+ { t=t->next;
+ if (t->tag==CSEMICOLON)
+ t=t->next;
+ }
+ }
+ else
+ { wprint(SYM(t)->name); t=t->next;
+ if (t->tag==PPLUS)
+ { t=t->next; wputs(t->text); t=t->next; }
+ }
+ break;
+case CLABELN:
+ wprint("label"); wputs(t->text); t=t->next;
+ break;
+case PEXIT:
+ wprint("exit(0)"); t=t->next;
+ break;
+case PRETURN:
+ wprint("goto end"); t=t->next;
+ break;
+@
+
+\subsection{Constant declarations}
+
+In \TeX\ there are only two types of
+constant declarations\index{constant declaration}: integers
+and strings. I also observe, that the integer declarations are
+followed by at most one string declaration. While parsing, I change
+the tag of the identifier getting defined to |CINTDEF| or |CSTRDEF|.
+I convert the constant declarations into an
+enumeration type\index{enumeration type} or a |const char *|.
+
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case CINTDEF:
+ wputs("enum {@@+"), wid(t), wput('=');
+ t=wprint_to(t->link->next,t->link->link);
+ wputs("@@+};");
+ t=t->next;@+
+ break;
+case CSTRDEF:
+ wprint("const char *"), wid(t);@+t=t->next;@+ break;
+@
+
+I have used above a technique that I will use often in the following
+code. While parsing, I use the link filed of the tokens to connect
+key tokens of a certain \Pascal/ constructions. Using these links, I
+can find the different parts (including the intervening \WEB/ tokens)
+and rearrange them as needed. Linking tokens is achieved with the
+following macro which also checks that the link stays within the same
+code sequence.
+
+@<external declarations@>=
+#define LNK(from,to) @[((from)?(seq((from),(to)),(from)->link=(to)):0)@]
+@
+
+\subsection{Variable declarations }
+
+When I parse variable declarations\index{variable declaration}, I replace the |tag| of the first
+variable identifier by |PDEFVARID| and link all the variables
+following it together. The last variable is linked to the token
+separating the identifier from the type\index{type}, a |PCOLON| token which the
+parser has changed to a |CIGNORE| token. The former |PCOLON| token
+itself is then linked to the |PSEMICOLON| that terminates the variable
+declaration. In the special case of array variables, I have to
+insert the variable identifiers inside the type definition. To
+accomplish this, I set the global variable |varlist| to point to the
+|PDEFVARID| token, and continue after printing the type with whatever
+is left from this list. Note the special precautions taken to get the
+type of variables right that are used to control
+\&{for}-loops\index{for+\&{for}}; I deal
+with this problem in section~\secref{forloop}.
+
+@<internal declarations@>=
+static token *varlist;
+@
+@<global variables@>=
+static token *varlist=NULL;
+@
+Using this information I can convert the variable declaration.
+@<convert |t| from \WEB/ to \cweb/@>=
+case PDEFVARID:
+ { token *type=t->link;
+ varlist=t;
+ DBG(dbgcweb,"Converting variable list in line %d\n",t->lineno);
+ while (type->tag==PID) type=type->link;
+ { int replace=0;
+ @<decide whether to replace a subrange type for loop control variables@>@;
+ if (replace)
+ { wprint("int");
+ DBG(dbgfor,"\tReplacing subrange type by int\n");
+ }
+ else
+ wprint_to(type,type->link);
+ }
+ DBG(dbgcweb,"Finished variable type in line %d\n",t->lineno);
+ if (varlist->tag== PDEFVARID)
+ { wid(varlist); @+varlist=varlist->next;@+}
+ wprint_to(varlist,type);
+ t=type->link;
+ DBG(dbgcweb,"Finishing variable list in line %d\n",t->lineno);
+ break;
+ }
+@
+
+\subsection{Types}
+
+\Pascal/ type declarations\index{type declaration} start with the
+keyword \&{type}, then
+follows a list of declarations each one starting with a
+type identifier\index{type identifier}. While parsing \Pascal/,
+I change the |tag| of the
+identifier being defined to |PDEFTYPEID|. I link this token to the
+first token of the type, and link the first token of the type to the
+semicolon terminating the type. When I encounter these |tags| now a
+second time, I can convert them into \CEE/ \&{typedef}'s.\index{typedef+\&{typedef}}
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PDEFTYPEID:
+{ token @[*type_name=t@];
+ token @[*type=type_name->link@];
+ DBG(dbgcweb,"Defining type %s in line %d\n",token2string(t),t->lineno);
+ wprint("typedef ");
+ t=wprint_to(type,type->link);
+ wprint(token2string(type_name));
+ break;
+}
+@
+
+The above code just uses |wprint_to| to print the type itself. Some
+types need a little help to print correctly.
+For instance, subrange types\index{subrange type} are converted
+by changing the |PEQ| token after the new type
+identifier to a |CTSUBRANGE| token, with an |up|-link to the parse tree
+for the subrange. Since \CEE/ does not have this kind of subrange
+types, I approximate them by the standard integer types found in
+\.{stdint.h}\index{stdint.h+\.{stdint.h}}.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case CTSUBRANGE:
+{ int lo = t->up->previous->value;
+ int hi = t->up->next->value;
+ DBG(dbgcweb,"Defining subrange type %d..%d\n",lo,hi);
+ if (lo<0 && INT8_MIN<=lo && hi <= INT8_MAX) wprint("int8_t");
+ else if (0<=lo && hi <= UINT8_MAX) wprint("uint8_t");
+ else if (lo<0 && INT16_MIN<=lo && hi <= INT16_MAX) wprint("int16_t");
+ else if (0<=lo && hi <= UINT16_MAX) wprint("uint16_t");
+ else if (lo<0 && INT32_MIN<=lo && hi <= INT32_MAX) wprint("int32_t");
+ else if (0<=lo && hi <= UINT32_MAX) wprint("uint32_t");
+ else ERROR("unable to convert subrange type %d..%d in line %d\n",lo,hi,t->lineno);
+ t= t->link;
+ break;
+}
+@
+
+To set |up|-links in the parser, I use the following macro:
+@<external declarations@>=
+#define UP(from,to) @[((from)->up=(to))@]
+@
+
+
+Record types\index{record type} get converted into \CEE/
+structures\index{structure type}; the variant parts\index{variant part}
+of records become \CEE/ unions\index{union type}.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PRECORD:
+ { DBG(dbgcweb,"Converting record type in line %d\n",t->lineno);
+ wprint("struct { ");
+ t=wprint_to(t->next,t->link);
+ DBG(dbgcweb,"Finished record type in line %d\n",t->lineno);
+ wprint("} ");
+ break;
+ }
+case CUNION:
+ { DBG(dbgcweb,"Converting union type in line %d\n",t->lineno);
+ wprint("union { ");
+ t=wprint_to(t->next,t->link);
+ wprint("};");
+ DBG(dbgcweb,"Finished union type in line %d\n",t->lineno);
+ break;
+ }
+@
+
+The conversion of the field declarations\index{field declaration}
+of a record type assumes that
+the \Pascal/ parser has changed the first |PID| token to a |PDEFVARID|
+token and linked it to the following |PCOLON| token; then linked the
+|PCOLON| token to the |PSEMICOLON| or |PEND| token that follows the
+type.
+
+Arrays\index{array} also need special conversion. \Pascal/ arrays specify a
+subrange type\index{subrange type} while \CEE/ arrays are always zero based and specify a
+size. Common to both is the specification of an element type\index{element type}.
+\TeX\ does not use named array types. Array types only occur in the
+definition of variables.
+
+I link the |PARRAY| token to the |PSQOPEN| token, which I link to
+either the |PDOTDOT| token or the type identifier, which I link to
+the |PSQCLOSE| token, which I link to the |POF| token, which is
+finally linked to the |PSEMICOLON| following the element type.
+
+%I link the |PARRAY| token to the |POF| token preceding the
+%element type, and link the |POF| token to the |PSEMICOLON|
+%following the element type.
+
+The |up| pointer of the |PARRAY| token points to the parse tree for
+the subrange of the index type\index{index type}.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PARRAY:
+ if (t->up==NULL) /* happens for example code which is not part of the program */
+ wputs(t->text),t=t->next;
+ else
+ { token *from=t->link;
+ token *index=from->link;
+ token *to=index->link;
+ token *element_type=to->link;
+ token *subrange=t->up;
+ int lo, hi, zero_based;
+
+ if (subrange->tag==PID) subrange=subrange->sym_ptr->type;
+ lo = subrange->previous->value;
+ hi = subrange->next->value;
+
+ zero_based=(subrange->previous->tag==PINTEGER && lo==0) ||
+ subrange->previous->tag==PTYPECHAR;
+ DBG(dbgarray,"Converting array[%d..%d] type in line %d\n",lo,hi,t->lineno);
+ t=wprint_to(element_type,element_type->link);
+ while (true)
+ { CHECK(varlist!=NULL,"Nonempty variable list expected in line %d",
+ varlist->lineno);
+ DBG(dbgarray,"Generating array variable %s in line %d\n",
+ varlist->sym_ptr->name,varlist->lineno);
+ wid(varlist);
+ if (!zero_based) wput('0'); /* add a zero to the array name */
+ wput('[');@+@<generate array size@>@+wput(']');
+ if (!zero_based) /* now I need the array with the appropriate offset */
+ { DBG(dbgarray,"Generating array pointer %s[%s=%d.. ] in line %d\n",
+ varlist->sym_ptr->name,token2string(from->next),lo,varlist->lineno);
+ wputs(", *const ");
+ wid(varlist);
+ wputs(" = ");
+ wid(varlist),wput('0');
+ @<generate array offset@>;
+ }
+ varlist=varlist->link;
+ if (varlist->tag==PDEFVARID || varlist->tag==PID) wput(','); else break;
+ }
+ DBG(dbgarray,"Finished array type in line %d\n",t->lineno);
+ }
+ break;
+@
+
+@<generate array size@>=
+ { int hi,size;
+ hi=generate_constant(subrange->next,0,0);
+ size=generate_constant(subrange->previous,'-',hi);
+ size=size+1;
+ if (size<0) wput('-'), wputi(-size);
+ else if (size>0)
+ { if (subrange->previous->tag!=PTYPECHAR &&
+ (subrange->previous->tag!=PINTEGER || subrange->next->tag!=PINTEGER)) wput('+');
+ wputi(size);
+ }
+}
+@
+
+@<generate array offset@>=
+{ int lo=generate_constant(subrange->previous,'-',0);
+ if (lo<0) wput('-'), wputi(-lo);
+ else if (lo>0) wput('+'), wputi(lo);
+}
+@
+
+I use the following function to generate a symbolic expression for
+the given parse tree representing a constant integer value. The
+expression contains only plus or minus operators. Parentheses are
+eliminated using the |sign| parameter. The function returns the
+numeric value that needs to be printed after all the symbolic
+constants, accumulating literal constants on its way.
+
+@<functions@>=
+int generate_constant(token *t, char sign, int value)
+{ if (t->tag==PTYPECHAR || t->tag==PINTEGER)
+ { if (sign=='-') return value-t->value; else return value+t->value; }
+ else if (t->tag==NMACRO || t->tag==PCONSTID)
+ { if (sign != 0) wput(sign); wprint(token2string(t->previous));
+ return value;
+ }
+ if (t->tag==PPLUS)
+ { if (t->previous!=NULL) value=generate_constant(t->previous,sign,value);
+ if (sign==0 ) sign='+';
+ return generate_constant(t->next,sign,value);
+ }
+ if (t->tag==PMINUS)
+ { if (t->previous!=NULL) value=generate_constant(t->previous,sign,value);
+ if (sign==0|| sign=='+') sign='-'; else sign='+';
+ return generate_constant(t->next,sign,value);
+ }
+ else
+ ERROR("Unexpected tag %s while generating a constant expression in line %d",TAG(t),t->lineno);
+}
+@
+
+@<internal declarations@>=
+int generate_constant(token *t, char sign, int value);
+@
+
+
+\subsection{Files}
+
+The \Pascal/ idea of a file\index{file}, let's say ``|fmt_file|: {\bf file of}
+|memory_word|'', is a combination of two things: the file itself and
+the file's buffer\index{file buffer} variable capable of holding one data item, in this
+case one |memory_word|. In \CEE/, I can simulate such a \Pascal/ file
+by a structure containing both: |FILE *f|, the file in the \CEE/
+sense; and |memory_word@,d|, the data item.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PFILE:
+ { DBG(dbgcweb,"Converting file type in line %d\n",t->lineno);
+ wprint("struct {@@+FILE *f;@@+");
+ t=wprint_to(t->next,t->link);
+ wprint("@@,d;@@+} ");
+ DBG(dbgcweb,"Finished file type in line %d\n",t->lineno);
+ break;
+ }
+@
+
+As I will show in section~\secref{procedures}, it is also convenient
+that \TeX\ always passes files, and only files, by reference\index{pass by reference} to
+functions\index{function} or procedures\index{procedure}.
+Now I can transcribe |get(fmt_file)| into
+|fread(&fmt_file.d, sizeof(memory_word), 1, fmt_file.f)|.
+%In the simpler case, where the data type is a single byte,
+%I have for example |dvi_file.f=fgetc(dvi_file.f)|.
+I put these ``rewrite rules'' as macros in the patch file\index{patch file};
+it has the advantage that the rewriting does not disturb the visual
+appearance of the program code.
+
+
+Access to the file's buffer\index{file buffer} variable, in \Pascal/ written as {\it f\^}
+becomes simply |f.d|.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PUP: wputs(".d");@+t=t->next;@+ break;
+@
+
+
+\subsection{Structured statements}
+
+Some of the structured statements\index{structured statement} are easy to convert.
+For example the
+\&{if} statement just needs an extra pair of parentheses around the
+controlling expression. These small adjustment are made when dealing
+with the |PIF| and |PTHEN| token. The \&{while} statement is similarly
+simple, but the |PDO| token may also be part of a
+\&{for}-loop\index{for+\&{for}}. So the
+parser links the |PWHILE| token to the |PDO| token to insert the
+parentheses.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PWHILE:
+ wprint("while ");
+ if (t->link!=NULL){
+ wput('(');@+t=wprint_to(t->next,t->link);@+ wputs(") ");
+ }
+ t=t->next;@+ break;
+@
+
+Other structured statements need more work.
+
+Let's start with the \Pascal/ \&{case} statement. Adding parentheses
+around the controlling expression is not as simple, because I lack a
+unique second keyword; instead I have a |POF| token which occurs at
+various places and is usually ignored. So I link the |PCASE| token
+to the corresponding |POF| token while parsing and generate
+a \&{switch} statement.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+ case PCASE:
+ if (t->link==NULL)
+ { wprint(t->text);@+t=t->next; }
+ else
+ { wprint("switch (");@+
+ t=wprint_to(t->next, t->link);@+
+ wputs(") {");
+ }
+ break;
+@
+The case labels\index{case label} are converted while parsing.
+While \Pascal/ requires a list of labels followed by a semicolon and a
+statement, \CEE/ needs the keyword ``\&{case}'' preceding a single
+label, a colon, and a statement list usually ending with ``|break;|''.
+When faced with this problem, I tried a new strategy: inserting new tokens.
+I insert a |CCASE| token before each \Pascal/ case label and replace
+the |PCOMMA| between labels by a |CCOLON|. (While it worked quite well,
+I still wished, I would have solved the problem without modifying
+the token list).
+
+To insert the |CCASE| tokens, the parser uses the function |winsert_after|.
+@<external declarations@>=
+extern token *winsert_after(token *t, int tag, char *text);
+@
+
+@<functions@>=
+token *winsert_after(token *t, int tag, char *text)
+{ token *n;
+ DBG(dbgcweb,"Inserting token %s after %s in line %d\n",
+ tagname(tag),TAG(t), t->lineno);
+ n = new_token(tag);
+ n->next=t->next;
+ n->next->previous=n;
+ n->previous=t;
+ t->next=n;
+ n->sequenceno=t->sequenceno;
+ n->lineno=t->lineno;
+ n->text=text;
+ return n;
+}
+@
+
+Further, the parser replaces the semicolons separating the \Pascal/
+case elements by a |CBREAK| token.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case CBREAK:
+ if (t->previous->tag!=PSEMICOLON && t->previous->tag!=CSEMICOLON
+ &&t->previous->tag!=PEND) wputs("@@;");
+ if (!dead_end(t->up,t->lineno)) wprint("@@+break;");
+ t=t->next;
+ break;
+@
+
+The semicolon\index{semicolon} that might be necessary before the ``\&{break}'' is inserted
+using a general procedure described in section~\secref{semicolon}.
+
+\TeX\ often terminates the statement following the case label with a
+\&{goto} statement. In this case of course it looks silly to add a
+\&{break} statement. I can test this by calling the |dead_end| function
+
+@<external declarations@>=
+int dead_end(token *t, int lineno);
+@
+
+@<functions@>=
+int dead_end(token *t, int lineno)
+{ DBG(dbgbreak,"Searching for dead end in line %d:\n",lineno);
+ while (true)
+ { DBG(dbgbreak,"\t%s\n",TAG(t));
+ if (t->tag==PGOTO||t->tag==PEXIT||t->tag==CPROCRETURN) return true;
+ else if (t->tag==PCOLON) t=t->next;
+ else if (t->tag==PBEGIN) t=t->previous;
+ else if (t->tag==PSEMICOLON || t->tag==CCASE)
+ { if (t->next->tag==CEMPTY) t=t->previous; else t=t->next; }
+ else return false;
+ }
+}
+@
+
+The ``\&{others}'' label can be
+replaced by ``\&{default}''.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case POTHERS:
+ wprint("default:");
+ t=t->next;
+ break;
+@
+
+I suspect that a {\sl case\_list\/}\index{case_list+{\sl case\_list\/}}
+always ends with either a semicolon or
+|POTHERS| without a semicolon. It could be better to generate also a
+\&{break} statement at the end of the last
+case element---especially if the
+order of cases gets rearranged by rearranging or adding modules.
+
+Finally I convert the \&{repeat}-\&{until} statement. The ``\&{repeat}''
+becomes ``|do {|''\index{do+\&{do}}
+and the ``\&{until}'' becomes ``|} while|''\index{while+\&{while}}.
+All that is left is to enclose the expression following the ``\&{until}'' in a pair of
+parentheses and add a |!|\index{"!+$\neg$} operator. The opening parenthesis follows
+the ``\&{while}''; but where should the closing parenthesis's go? Here I
+use the fact that in \TeX\ the condition after the ``\&{until}'' is either
+followed directly by a semicolon\index{semicolon}, or by the start of a new section.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PREPEAT: wprint("@@/do@@+{");@+ t=t->next;@+ break;
+case PUNTIL:
+{ int sequenceno, lineno;
+ token *end;
+ wputs("}@@+ while (!(");
+ sequenceno=t->sequenceno;
+ lineno=t->lineno;
+ end=t->next;
+ while(true)
+ { if (end->tag==PSEMICOLON || end->tag==CSEMICOLON || end->tag==PELSE )
+ break;
+ else if (end->tag==ATSPACE)
+ { while (true)
+ { int tag=end->previous->tag;
+ if (tag>FIRST_PASCAL_TOKEN || tag==OMACRO || tag==NMACRO || tag==CHAR) break;
+ end=end->previous;
+ }
+ break;
+ }
+ end=end->next;
+ }
+ CHECK(sequenceno==end->sequenceno,"until: end of expression not found in line %d",lineno);
+ t=wprint_to(t->next, end);
+ wputs("))");
+ break;
+}
+@
+
+
+
+\subsection{{\bf for}-loops}
+\label{forloop}%
+To convert the \&{for} statement, I link the |PFOR| token to the |PTO|
+or |PDOWNTO| token respectively, which is then linked to the |PDO|
+token. The rest seems simple but it hides a surprising difficulty.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PFOR:
+{ token *id=t->next;
+ token *to=t->link;
+ if (to==NULL) { wprint("for"); t=t->next; break; }
+ wprint("for (");
+ wprint_to(id,to);
+ wputs("; ");
+ wid(id);
+ if (to->tag==PTO) wputs("<=");
+ else if (to->tag==PDOWNTO) wputs(">=");
+ else ERROR("to or downto expected in line %d",to->lineno);
+ wprint_to(to->next,to->link);
+ wputs("; ");
+ wid(id);
+ if (to->tag==PTO) wputs("++");
+ else wputs("--");
+ wputs(") ");
+ t=to->link->next;
+ break;
+}
+@
+
+The above code checks that there is actually a link to the |PTO|
+token. This link will exist only if the \&{for}-loop\index{for+\&{for}}
+was parsed as part of
+the \Pascal/ program; it will not exists if the code segment was just
+part of an explanation (see for example section 823). In this case, I
+need to deal with the |PTO| and |PDO| separately.
+
+Given a \Pascal/ variable ``{\bf var} |i:0..255;|''
+the \&{for}-loop\index{for+\&{for}}
+``|for i:=255| \&{downto} |0| \&{do}\dots'' will work as expected.
+If I translate the variable definition to ``|uint8_t@, i;|''
+the translated \&{for}-loop ``|for (i=255;i>=0;i--)|\dots''
+will not terminate because the loop control variable will never
+be smaller than 0, instead it will wrap around.
+If the variable |i| is used in such a \&{for}-loop, I should
+define it simply as ``|int i;|''.
+
+The first step is the analysis of \&{for}-loops\index{for+\&{for}}
+in the \Pascal/ parser.
+To do so, I call the function |mark_for_variable| with three
+parameters: |id|, the loop control variable; |lineno|, the line number
+for debugging\index{debugging} purposes; |value|, the value of the limit terminating
+the loop; and |direction|, indicating the type of loop. For the
+|direction|, I distinguish three cases: |TO_LOOP|, |DOWNTO_LOOP|, and
+loops where the loops limit is a variable (|VAR_LOOP|).
+
+@<external declarations@>=
+#define VAR_LOOP 0
+#define TO_LOOP 1
+#define DOWNTO_LOOP 2
+@
+
+The function then tries to decide whether the type of the for loop
+control variable should be changed from a subrange type\index{subrange type}
+ to a plain integer.
+
+If the limit controlling the loop is a variable, I can not ensure
+(without reasoning about program semantics) that the limit will not
+coincide with the limit of the subrange type of the control
+variable. In this case I stay on the safe side and replace the
+subrange type.
+
+%It would probably also suffice, if I did
+%this only for |uint8_t| or |int8_t| types.
+
+If the limit controlling the loop is a constant, I check its value
+and replace the type of the control variable only if the value
+coincides with the upper (or lower) limit of the subrange type\index{subrange type} used
+for the control variable. The comparison of the given loop limit with
+the variables possible range limit is postponed until I generate the
+variable declaration. For now, I just determine the minimum number of
+|bits| needed for a suitable variable type.
+
+@<functions@>=
+void mark_for_variable(token *id, int lineno, int value, int direction)
+{ int replace=0;
+ int bits=0;
+ if (direction==VAR_LOOP) replace=1;
+ else if (direction==DOWNTO_LOOP)
+ { if (value>=0) bits=0; /* lower limit of all unsigned types */
+ else if (value > INT8_MIN) bits=6;
+ else if (value > INT16_MIN) bits=14;
+ else bits=15;
+ }
+ else /* |TO_LOOP| */
+ { if (value < 0) bits=0;
+ else if (value < INT8_MAX) bits=6;
+ else if (value < UINT8_MAX) bits=7;
+ else if (value < INT16_MAX) bits=14;
+ else if (value < UINT16_MAX) bits=15;
+ else if (value < INT32_MAX) bits=31;
+ else bits=32;
+ }
+ SYM(id)->for_ctrl= FOR_CTRL_PACK(lineno,replace,direction,bits);
+}
+@
+
+I pack the result of my analysis into the |for_ctrl| field of the
+variables symbol table entry using the following macros.
+
+@<external declarations@>=
+extern void mark_for_variable(token *id, int lineno, int value, int direction);
+#define FOR_CTRL_PACK(lineno,replace,direction,bits) \
+ ((lineno<<16)|((replace&0x1)<<15)|((direction&0x3)<<13)|(bits&0x1FFF))
+#define FOR_CTRL_LINE(X) (((X)>>16)&0xFFFF)
+#define FOR_CTRL_REPLACE(X) (((X)>>15)&1)
+#define FOR_CTRL_DIRECTION(X) (((X)>>13)&0x3)
+#define FOR_CTRL_BITS(X) ((X)&0x1FFF)
+@
+
+
+%These are the lines:
+%Subrange for marked variable k in line 1256
+% Range 0 to 255, limit 32767 in line 1354
+% limit is variable but always below 100, so OK
+% This is OK, multiple replacement is OK
+%
+%Subrange for marked variable k in line 1709
+% Range 0 to 500, limit 32767 in line 1715
+% range is 0 to buf_size=500 but might be defined smaller or larger
+% the limit is last-1 where I have always last<buf_size
+% This is OK, replacement is OK
+%
+%Subrange for marked variable p in line 4390
+% Range 0 to 40, limit 0 in line 4397
+% the Range is 0 to nest_size which gives an uint8_t
+% with a for loop down to 0
+% var p:0..nest_size; {index into |nest|}
+% This is NOT OK, lower limit = range, replacement OK
+%
+%Subrange for marked variable i in line 6867
+% Range 0 to 500, limit 32767 in line 6916
+% limit is j-1 where j is inside the buffer
+% This is OK, replacement is OK
+%
+%Subrange for marked variable k in line 7579
+% Range 0 to 500, limit 32767 in line 7587
+% the limit is last-1 where I have always last<buf_size,
+% This is OK, Limit > range(500)> 255, replacement is OK
+%
+%Subrange for marked variable k in line 10170
+% Range 1 to 40, limit 32767 in line 10174
+% range is 1..file_name_size
+% var k:1..file_name_size; {index into |name_of_file|}
+% the limit is name_length which might be equal to file_name_size
+% limit > 255 > range
+% this is NOT OK if file_name_size is 255, replacement is OK
+%
+%Subrange for marked variable k in line 10302
+% Range 0 to 500, limit 32767 in line 10318
+% Limit is l which can be as large as last-1
+% This is OK, limit > range(500) > 2^16 > 2^8, replacement is OK
+%
+%Subrange for marked variable k in line 12668
+% Range 0 to 9, limit 9 in line 12719
+% This is OK, limit < 255, no replacement needed
+%
+%Subrange for marked variable fit_class in line 16380
+% Range 0 to 3, limit 3 in line 16467
+% This is OK, limit <255, no replacement needed
+%
+%Subrange for marked variable j in line 17645
+% Range 0 to 65, limit 32767 in line 17657
+% Here the limit is inside the array so less then 64
+% This is OK, limit>255>64, replacement for multiple is OK
+%
+%Subrange for marked variable j in line 18248
+% Range 0 to 64, limit 32767 in line 18308
+% The limit n is less than 64
+% This is OK, limit>255>64, replacement is OK
+
+When I finally come to the place where I generate a variable
+declaration, I can decide whether to replace a subrange type for loop
+control variables. To do this I iterate over the list of variables
+and if I find in the list one variable that requires replacement, I
+change the type of the whole list (this is a bit more than necessary,
+but it does no harm either).
+
+@<decide whether to replace a subrange type for loop control variables@>=
+
+{ token *subrange=NULL;
+ if (type->tag==CTSUBRANGE)
+ subrange=type->up;
+ else if (type->tag==CIGNORE && type->next->tag==PID &&
+ type->next->sym_ptr->type!=NULL && type->next->sym_ptr->type->tag==PDOTDOT)
+ subrange=type->next->sym_ptr->type; /* subrange type identifier */
+ if (subrange!=NULL)
+ { token *id=t;
+ while (id!=type && !replace)
+ { if (id->sym_ptr->for_ctrl!=0)
+ { int lo = subrange->previous->value;
+ int hi = subrange->next->value;
+ int bits = FOR_CTRL_BITS(id->sym_ptr->for_ctrl);
+ int direction = FOR_CTRL_DIRECTION(id->sym_ptr->for_ctrl);
+ int lineno = FOR_CTRL_LINE(id->sym_ptr->for_ctrl);
+ replace = FOR_CTRL_REPLACE(id->sym_ptr->for_ctrl);
+ DBG(dbgfor,"Subrange for marked variable %s in line %d\n",
+ token2string(id),id->lineno);
+ DBG(dbgfor,"\tRange %d to %d, limit %d bits, direction %d in line %d\n",
+ lo,hi, bits, direction, lineno );
+ if (direction==DOWNTO_LOOP)
+ { if (lo>=0 && bits==0) replace=true;
+ else if (lo<0 && INT8_MIN<=lo && hi <= INT8_MAX && bits>=7) replace=true;
+ else if (lo<0 && INT16_MIN<=lo && hi <= INT16_MAX && bits>=15) replace=true;
+ }
+ else if (direction==TO_LOOP)
+ { if (lo<0 && INT8_MIN<=lo && hi <= INT8_MAX && bits>=7) replace=true;
+ else if (0<=lo && hi <= UINT8_MAX && bits>=8) replace=true;
+ else if (lo<0 && INT16_MIN<=lo && hi <= INT16_MAX && bits>=15) replace=true;
+ else if (0<=lo && hi <= UINT16_MAX && bits>=16) replace=true;
+ }
+ }
+ id=id->link;
+ }
+ }
+}
+@
+
+
+
+\subsection{Semicolons}
+\label{semicolon}%
+In \CEE/, the semicolon\index{semicolon} is used to turn an expression, for example an
+assignment\index{assignment}, into a statement; while in \Pascal/ semicolons are used to
+separate statements in a statement sequence\index{statement sequence}.
+ This difference is important, because \CEE/ will need in certain cases, for example,
+preceding an ``\&{else}'' or a ``\.{\RB}'' a semicolon, where \Pascal/ must not have one.
+
+The simpler case is the semicolon that in \Pascal/ quite frequently
+follows an \&{end}. In \CEE/ this semicolon often does no harm (it
+indicates an empty statement\index{empty statement}), but looks kind of strange, in other
+cases, for example following a procedure body, it must be eliminated.
+So I test for it and eliminate it wherever I find it.
+@<convert |t| from \WEB/ to \cweb/@>=
+case PEND: wputs("} "),t=t->next;
+ if (t->tag==PSEMICOLON) t=t->next;
+ break;
+@
+
+Now let's turn to the more difficult case where \CEE/ needs a
+semicolon and \Pascal/ does not have one: preceding an ``\&{else}'', at the
+end of a {\sl case\_element}\index{case_element+{\sl case\_element}},
+and at the end of a statement sequence
+(preceding an ``\&{end}'' or ``\&{until}''). Adding a semicolon\index{semicolon}
+directly before such an ``\&{else}'' would in many cases not look very nice.
+For instance when the code preceding it is in a different module.
+The semicolon should instead follow immediately after the last
+preceding \Pascal/ token. I insert a |CSEMICOLON| token just there
+using the function |wsemicolon|. The function has two parameters:
+|t|, the token that might require a preceding semicolon; and |p|, the
+pointer to the parse tree preceding the token pointed to by |t|.
+
+
+I first check the parse tree whether a semicolon\index{semicolon} is indeed needed, and
+if so, I search for the proper place to insert the semicolon. The
+function |wneeds_semicolon| descends into the parse tree, finds its
+rightmost statement, and determines whether it needs a semicolon. The
+function |wback| searches backward to the earliest token that is
+relevant for the \CEE/ parser.
+
+The situation is slightly different for \.{ctangle}\index{ctangle+\.{ctangle}}.
+Its pattern matching algorithm does not work good, if the material, for example
+preceding an else, does not look like a statement, for example
+because the closing semicolon is hidden in a module or a macro. In
+these cases it is appropriate to insert a ``\.{@@;}'' token. I do
+this by looking at the token preceding the ``\&{else}'', skipping over index
+entries, newlines, indents and such stuff, until finding the end of a
+module, or macro and insert the ``\.{@@;}'' there.
+
+@<functions@>=
+bool wneeds_semicolon(token *p)
+{ while (p!=NULL)
+ { switch (p->tag)
+ { case PCASE: case PBEGIN: case CIGNORE: return false;
+ case PSEMICOLON:
+ case CCASE: case PELSE: p=p->next;@+ continue;
+ case PIF: case PWHILE: case PFOR: case PCOLON:@/ p=p->previous;@+ continue;
+ case PASSIGN: case PFUNCID: case PCALLID: case PREPEAT:
+ case PRETURN: case CRETURN: case CPROCRETURN:case PGOTO: case PEXIT: case CEMPTY:
+ default: return true;
+ }
+ }
+ return false;
+}
+
+static token * wback(token *t)
+{ while (true)
+ { CHECK(t->previous!=NULL,"Error searching backward");
+ t=t->previous;
+ switch (t->tag)
+ { case PSEMICOLON: case CSEMICOLON: case PEND: return t;
+ case RIGHT: while (t->tag!=PLEFT && t->tag!=MLEFT) t=t->previous;
+ break;
+ case ATGREATER: case EQ: case HASH: case ATDOLLAR: case NMACRO: case OMACRO:
+ case OCTAL: case HEX: case CHAR: case STRING: case PRETURN: case CEMPTY:
+ return t;
+ case CIGNORE: continue;
+ default: break;
+ }
+ if (t->tag>FIRST_PASCAL_TOKEN)
+ return t;
+ }
+}
+
+void wsemicolon(token *p, token *t)
+{ t=wback(t);
+ if (t->tag!= PSEMICOLON && t->tag!=CSEMICOLON && t->tag!=PEND)
+ { if (wneeds_semicolon(p))
+ { DBG(dbgsemicolon,"inserting ; in line %d\n",t->lineno);
+ if (t->next->tag==ATSEMICOLON)
+ { t->next->tag=CSEMICOLON; t->next->text=";"; }
+ else
+ winsert_after(t,CSEMICOLON,";");
+ }
+ else if (t->next->tag!=ATSEMICOLON && t->next->tag!=PSEMICOLON)
+ {
+ DBG(dbgsemicolon,"inserting @@; in line %d\n",t->lineno);
+ winsert_after(t,ATSEMICOLON,"@@;");
+ }
+
+ }
+}
+@
+
+In procedures, I eliminate a final ``|exit:|''
+because I have replaced ``|goto exit|'' by ``\&{return}''.\index{goto+\&{goto}}
+
+%It might be a good idea to classify the modules
+%as statements or expressions and enclose the
+% module names in \.{@@[...@@]} or add a trailing ``\.{@@;}''
+
+
+@<functions@>=
+void wend(token *p, token *t)
+{ if (p->tag==PSEMICOLON && p->next->tag==PCOLON &&
+ p->next->next->tag==CEMPTY && p->next->previous->tag==CLABEL &&
+ p->next->previous->sym_no==exit_no)
+ { token *label=p->next->previous;
+ DBG(dbgreturn,"Trailing exit: found preceding line %d\n",t->lineno);
+ label->tag=CIGNORE;
+ SYM(label)->value=-1000;
+ CHECK(label->next->tag==PCOLON,"Expected colon after label in line %d\n",label->lineno);
+ label->next->tag=CIGNORE;
+ p->next->tag=CIGNORE;
+ }
+ else
+ DBG(dbgreturn,"No trailing exit: found preceding line %d\n",t->lineno);
+}
+
+@
+
+
+
+@<external declarations@>=
+extern void wsemicolon(token *p, token *t);
+extern void wend(token *p, token *t);
+@
+
+The inserted semicolons\index{semicolon} have the tag |CSEMICOLON|.
+These tokens are printed
+but---and this is new---hidden from the \Pascal/ parser. This idea might
+be useful also for other inserted tokens.
+
+@<convert token |t| to a string@>=
+case CSEMICOLON:
+ return ";";
+@
+
+@<special treatment for \WEB/ tokens@>=
+ case CSEMICOLON:
+ t=t->next;@+
+ continue;
+@
+
+\subsection{Procedures}
+\label{procedures}%
+While parsing, I link the |PPROCEDURE| token to the |PSEMICOLON| or |POPEN| following
+the procedure\index{procedure} name. The |PSEMICOLON|
+following the heading is always changed to a |CIGNORE|.
+@<convert |t| from \WEB/ to \cweb/@>=
+case PPROCEDURE:
+ DBG(dbgcweb,"Converting procedure heading in line %d\n",t->lineno);
+ wprint("void");
+ t=wprint_to(t->next,t->link);
+ if (t->tag!=POPEN) wputs("(void)");
+ break;
+@
+
+The list of parameter\index{parameter} identifiers spans from the beginning parenthesis
+that is pointed to by |t| to the closing parenthesis pointed to by
+|t->link|. It is handled similar to a variable declaration\index{variable declaration}.
+The type identifier\index{type identifier}, however, needs to be repeated
+for each parameter in a list. The parser has converted the parameter identifiers to either
+|PDEFPARAMID| or |PDEFREFID|, linked the identifiers together with the
+final link pointing to the |PCOLON| preceding the type, and it linked
+the |PCOLON| to the |PSEMICOLON| or |PCLOSE| following the type. This
+information is sufficient to convert the parameter list\index{parameter list}.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PDEFPARAMID:
+case PDEFREFID:
+{ token *varlist=t, *type=t->link;
+ DBG(dbgcweb,"Converting parameter list in line %d\n",t->lineno);
+ while (type->tag==PDEFPARAMID || type->tag==PDEFREFID) type=type->link;
+ while (true)
+ { wprint_to(type,type->link);
+ if (varlist->tag==PDEFREFID) wputs(" *");
+ wid(varlist);
+ varlist=varlist->link;
+ if (varlist!=type) wput(',');
+ else break;
+ }
+ t=type->link;
+ DBG(dbgcweb,"Finishing parameter list in line %d\n",t->lineno);
+ break;
+}
+@
+
+The parser changes the use of a reference\index{pass by reference} variable to a |CREFID|
+token, and when I find one now, I dereference it.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case CREFID:
+ wputs("(*"), wid(t), wput(')');
+ t=t->next;@+
+ break;
+@
+
+
+Now consider a procedure call\index{procedure call}.
+The most complex part about it is the
+argument list\index{argument list}. If a procedure has no parameters, there is no
+argument list in \Pascal/ but there is an empty argument list in
+\CEE/. Further, the use of reference parameters\index{pass by reference} complicates the
+processing. I need to add a ``|&|'' in front of a variable that is
+passed by reference in \CEE/. To accomplish this, the parser
+constructs for every procedure a |param_mask| and stores it in the
+|value| field of the procedure identifiers entry in the symbol table\index{symbol table}.
+A value of 1 means ``no parameter list''; all the other bits
+correspond from left to right to up to 31 parameters; a bit is set if
+the corresponding parameter is a reference parameter. I use these
+definitions:
+
+@<external declarations@>=
+extern unsigned int param_mask, param_bit;
+#define SIGN_BIT (~(((unsigned int)~0)>>1))
+#define START_PARAM (param_mask=0,param_bit=SIGN_BIT)
+#define NEXT_PARAM (param_bit=param_bit>>1,CHECK(param_bit!=0,"Too many parameters"))
+#define REF_PARAM (param_mask=param_mask|param_bit)
+@
+@<global variables@>=
+unsigned int param_mask, param_bit;
+@
+
+Due to forward declarations\index{forward declaration},
+procedure calls\index{procedure call} can occur before the
+procedure definition\index{procedure definition}.
+Therefore I can not apply my knowledge about
+reference parameters when I parse the procedure call, I have to wait
+for the second pass, when I convert the \WEB/ to \cweb/. In \TeX\
+the procedure identifier (for example |print|) can be a macro, so the
+procedure identifier is not necessarily preceding the argument list\index{argument list}.
+Hence I have to process the procedure identifier and the argument
+list separately.
+
+Let's start with the procedure identifier. When I find it, I check
+for its |value|, and if the value indicates that there is an empty
+argument list, I add it.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PCALLID:
+ DBG(dbgcweb,"Converting call in line %d\n",t->lineno);
+ wid(t);
+ if (SYM(t)->value==1) wputs("()");
+ t=t->next;@+break;
+@
+
+At a possibly different place in the \WEB/ file, I will encounter the
+|POPEN| token that starts the argument list. It is linked to the
+corresponding |PCLOSE| token, and the parser takes care of setting its
+|up| pointer to the corresponding |PCALLID| token if there are
+reference parameters in the argument list.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case POPEN:
+ wput('(');
+ if (t->up==NULL || SYM(t->up)->value==0)
+ t=wprint_to(t->next,t->link);
+ else
+ { int param_mask=SYM(t->up)->value;
+ token *close=t->link;
+ t=t->next;
+ if (param_mask<0) wput('&');
+ param_mask=param_mask<<1;
+ while(t!=close)
+ { if (t->tag==PCOMMA)
+ { wputs(", ");@+t=t->next;
+ if (param_mask<0) wput('&');
+ param_mask=param_mask<<1;
+ }
+ else
+ t=wtoken(t);
+ }
+ }
+ break;
+@
+
+
+
+\subsection{Functions}
+
+Functions\index{function} are slightly more complicated than procedures because they
+feature a return type\index{return type} and a return value\index{return value}.
+ Let's start with the
+function header\index{function header}. To find the return type, the parser links the end of
+the parameter list to the colon and the colon to the end of the return type.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PFUNCTION:
+{ token *param=t->link;
+ token *type;
+ DBG(dbgcweb,"Converting function heading in line %d\n",t->lineno);
+ if (param->tag==POPEN) type=param->link->link;
+ else type=param;
+ wprint_to(type, type->link);
+ wprint_to(t->next,t->link);
+ if (param->tag!=POPEN) wputs("(void)");
+ else wprint_to(param,param->link->next);
+ t=type->link;
+ break;
+}
+@
+
+
+Functions in \Pascal/ return values by assigning them to the function
+identifier somewhere within the body of the function. In contrast,
+\CEE/ uses a return statement, which also terminates the execution of
+the function immediately. The \&{return}\index{return+ \&{return}}
+statement is equivalent to the
+\Pascal/ assignment only if the assignment\index{assignment} is in
+the tail position\index{tail position} of
+the function. While parsing, I build a tree of the statements. This
+tree is then searched for assignments to the function identifier\index{function identifier}
+in tail positions and these assignments can be converted
+to \&{return}
+statements.
+
+I start with a function that determines whether a part of the parse tree
+is a ``tail'', that is it leads directly to the function return.
+
+@<functions@>=
+static bool wtail(token *t)
+{ CHECK(t!=NULL,"Unexpected NULL token while searching for tail statements");
+ switch(t->tag)
+ { case PSEMICOLON: case PELSE: case CCASE:
+ return wtail(t->next) && wtail(t->previous);
+ case PCOLON:
+ return wtail(t->next);
+ case PRETURN: case CIGNORE: case CEMPTY:
+ return true;
+ case PASSIGN: case PCALLID:
+ case PFUNCID: case CRETURN: case CPROCRETURN:
+ case PWHILE: case PREPEAT: case PFOR:
+ case PEXIT: case PGOTO:
+ return false;
+ case PBEGIN: case PIF: case PCASE:
+ return wtail(t->previous);
+ default: ERROR("Unexpected tag %s while searching for tail statements",TAG(t));
+ }
+}
+@
+
+The function |wreturn| accomplishes the main task. It is called by the
+parser, when it has completed the parsing of the function body with
+parameter |t| pointing to the parse tree of the entire body. The
+parameter |tail|, which tells us if the parse tree |t| is in a tail
+position, is then set to true. The link parameter, pointing to a
+possible |PRETURN| token, is |NULL|.
+
+@<external declarations@>=
+extern void wreturn(token *t, int tail, token *link);
+@
+
+The function |wreturn| calls itself recursively to find and convert
+all instances where a \CEE/ return statement is appropriate. If I
+convert the \TeX\ macro ``\&{return}'' to
+a \CEE/ \&{return} statement, I decrement its
+use-count. If at the end it is zero, I can omit the label {\it end}
+marking the end of the function body.
+
+@<functions@>=
+void wreturn(token *t, int tail, token *link)
+{ CHECK(t!=NULL,"Unexpected NULL token while searching for return statements");
+ switch(t->tag)
+ { case PSEMICOLON:
+ if (t->next->tag==PRETURN)
+ wreturn(t->previous,true,t->next);
+ else
+ { wreturn(t->next,tail, link);
+ if (wtail(t->next)) wreturn(t->previous, tail, link);
+ else wreturn(t->previous,false,NULL);
+ }
+ return;
+ case PCOLON:
+ wreturn(t->next, tail,link);
+ return;
+ case PASSIGN: case PCALLID:
+ case PRETURN: case PEXIT: case PGOTO: case CIGNORE: case CEMPTY:
+ return;
+ case PWHILE: case PREPEAT: case PFOR:
+ wreturn(t->previous, false,NULL); return;
+ case PELSE: case CCASE:
+ wreturn(t->next, tail,link); wreturn(t->previous, tail,link); return;
+ case PCASE: case PIF: case PBEGIN:
+ wreturn(t->previous, tail,link); return;
+ case PFUNCID:
+ if (tail)
+ { DBG(dbgreturn,"Converting assignment to function in line %d\n",t->lineno);
+ t->tag=CRETURN; IGN(t->next);
+ if (link!=NULL)
+ { link->sym_ptr->value--;
+ t->sym_ptr=link->sym_ptr;
+ IGN(link), IGN(link->next);
+ DBG(dbgreturn,"Eliminating label %s (%d) in line %d\n",
+ link->sym_ptr->name,link->sym_ptr->value,t->lineno);
+ }
+ }
+ return;
+ case CRETURN: /* this happened when the return; is inside a macro */
+ if (t->sym_ptr!=NULL) {
+ t->sym_ptr->value--;
+ DBG(dbgreturn,"Eliminating label %s (%d) in line %d\n",
+ t->sym_ptr->name,t->sym_ptr->value,t->lineno);
+ }
+ return;
+ default: ERROR("Unexpected tag %s in line %d"
+ " while searching for return statements",TAG(t), t->lineno);
+ }
+}
+@
+
+After these precautions, there are only two functions left: |x_over_n|
+in line 2273 and |xn_over_d| in line 2306.
+These need a special local
+variable matching the function name in the assignment and a trailing
+\&{return} statement.
+
+I have two global variables to hold the symbol numbers of the two function names.
+@<external declarations@>=
+extern int x_over_n, xn_over_d;
+@
+@<global variables@>=
+int x_over_n, xn_over_d;
+@
+@<initialize token list@>=
+x_over_n=get_sym_no("x_over_n");
+xn_over_d=get_sym_no("xn_over_d");
+@
+
+While parsing, I check for these two function names and change the
+initial |PBEGIN| to an |PFBEGIN| and the trailing |PEND| to |PFEND|,
+setting the |sym_no| of these tokens to the symbol number of the
+function name. Now I can generate the definition of a local variable
+with the same name as the function (shadowing the function name) at
+the beginning and a matching return statement at the end.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case PFBEGIN:
+ DBG(dbgcweb,"Adding scaled %s; in line %d\n",SYM(t)->name,t->lineno);
+ wprint("scaled");wid(t); wputs("; ");
+ t=t->next;
+ break;
+case PFEND:
+ DBG(dbgcweb,"Adding return %s; in line %d\n",SYM(t)->name,t->lineno);
+ wprint("return");wid(t); wputs(";}");
+ t=t->next;
+ break;
+@
+
+While converting the token list, I check for |PFUNCID| and |CRETURN| tokens
+@<convert |t| from \WEB/ to \cweb/@>=
+case PFUNCID:
+ DBG(dbgcweb,"function %s in line %d assigns result variable\n",SYM(t)->name,t->lineno);
+ wid(t);
+ t=t->next;
+ break;
+case CRETURN:
+ DBG(dbgcweb,"Converted function return %s in line %d\n",SYM(t)->name,t->lineno);
+ wprint("return");
+ t=t->next;
+ break;
+case CPROCRETURN:
+ if (t->sym_ptr->value <=0) wprint("return");
+ else wprint("goto end");
+ t=t->next;
+ break;
+@
+
+\subsection{The |main| program}
+
+While parsing the \Pascal/ program, I change the |PBEGIN| token
+starting the main program\index{main program+\\{main} program}
+to a |CMAIN| token. Now I replace it by the
+heading of the main program. Similarly I deal with the |PEND| ending
+the main program.
+
+@<convert |t| from \WEB/ to \cweb/@>=
+case CMAIN:@+ wprint("int main(void) {");@+t=t->next;@+ break;
+case CMAINEND:@+ wprint("return 0; }");@+t=t->next;@+ break;
+@
+
+\section{Predefined symbols in Pascal}
+
+I put predefine function- and
+constant-names of \Pascal/ into the symbol table.
+I~omit predefined symbols\index{predefined symbol}
+that are not used in \TeX.
+\index{put+\\{put}}%
+\index{get+\\{get}}%
+\index{reset+\\{reset}}%
+\index{rewrite+\\{rewrite}}%
+\index{abs+\\{abs}}%
+\index{odd+\\{odd}}%
+\index{eof+\\{eof}}%
+\index{eoln+\\{eoln}}%
+\index{round+\\{round}}%
+\index{ord+\\{ord}}%
+\index{chr+\\{chr}}%
+\index{close+\\{close}}%
+\index{read+\\{read}}%
+\index{read_ln+\\{read_ln}}%
+\index{write+\\{write}}%
+\index{write_ln+\\{write_ln}}%
+\index{break+\\{break}}%
+\index{break_in+\\{break_in}}%
+\index{erstat+\\{erstat}}%
+\index{false+\\{false}}%
+\index{true+\\{true}}%
+
+@<initialize token list@>=
+predefine("put",PPROCID,0);
+predefine("get",PPROCID,0);
+predefine("reset",PPROCID,0);
+predefine("rewrite",PPROCID,0);
+predefine("abs",PFUNCID,0);
+predefine("odd",PFUNCID,0);
+predefine("eof",PFUNCID,0);
+predefine("eoln",PFUNCID,0);
+predefine("round",PFUNCID,0);
+predefine("ord",PFUNCID,0);
+predefine("chr",PFUNCID,0);
+predefine("close",PPROCID,0);
+predefine("read",PPROCID,0);
+predefine("read_ln",PPROCID,0);
+predefine("write",PPROCID,0);
+predefine("write_ln",PPROCID,0);
+predefine("break",PPROCID,0);
+predefine("break_in",PPROCID,0);
+predefine("erstat",PFUNCID,0);
+predefine("false",PCONSTID,0);
+predefine("true",PCONSTID,1);
+@
+
+% also predefined but not needed for TeX
+%predefine("type",PTYPE,0); /* type is redefined */
+%predefine("text",PTYPEID,0); /* text is used as a macro */
+%predefine("succ",PFUNCID,1);
+%predefine("pred",PFUNCID,1);
+%predefine("new",PPROCID,1);
+%predefine("dispose",PPROCID,1);
+%predefine("sqr",PFUNCID,1);
+%predefine("sin",PFUNCID,1);
+%predefine("cos",PFUNCID,1);
+%predefine("exp",PFUNCID,1);
+%predefine("ln",PFUNCID,1);
+%predefine("sqrt",PFUNCID,1);
+%predefine("arctan",PFUNCID,1);
+%predefine("trunc",PFUNCID,1);
+%predefine("readln",PPROCID,0);
+%predefine("writeln",PPROCID,0);
+%predefine("page",PPROCID,0);
+
+
+
+
+%Some need to be translated to C directly
+% OCTAL HEX ATDOLLAR ATLEFT ATRIGHT ATT ATEQ ATBACKSLASH
+
+
+%More complicated are (possibly) the following
+% ELIPSIS ATQM
+
+\section{Processing the command line}
+The |usage| function explains command line\index{command line}
+parameters and options\index{option}\index{debugging}.
+@<functions@>=
+void usage(void)
+{ fprintf(stderr,
+ "Usage: web2w [parameters] filename.web\n"@/
+ "Parameters:\n"@/
+ "\t -p \t generate a pascal output file\n"@/
+ "\t -o file \t specify an output file name\n"@/
+ "\t -l \t redirect stderr to a log file\n"@/
+ "\t -y \t generate a trace while parsing pascal\n"@/
+ "\t -d XX\t hexadecimal debug value. OR together these values:\n"@/
+ "\t \t \t XX=1 basic debugging\n"@/
+ "\t \t \t XX=2 flex debugging\n"@/
+ "\t \t \t XX=4 link debugging\n"@/
+ "\t \t \t XX=8 token debugging\n"@/
+ "\t \t \t XX=10 identifier debugging\n"@/
+ "\t \t \t XX=20 pascal tokens debugging\n"@/
+ "\t \t \t XX=40 expansion debugging\n"@/
+ "\t \t \t XX=80 bison debugging\n"@/
+ "\t \t \t XX=100 pascal parser debugging\n"@/
+ "\t \t \t XX=200 cweb debugging\n"@/
+ "\t \t \t XX=400 join debugging\n"@/
+ "\t \t \t XX=800 string pool debugging\n"@/
+ "\t \t \t XX=1000 for variables debugging\n"@/
+ "\t \t \t XX=2000 for real division debugging\n"@/
+ "\t \t \t XX=4000 for macro debugging\n"@/
+ "\t \t \t XX=8000 for array debugging\n"@/
+ "\t \t \t XX=10000 for return debugging\n"@/
+ "\t \t \t XX=20000 for semicolon debugging\n"@/
+ "\t \t \t XX=40000 for break debugging\n"@/
+ );
+ exit(1);
+}
+@
+The different debug values are taken from an enumeration type.
+@<external declarations@>=
+typedef enum {dbgnone=0x0,
+ dbgbasic=0x1,
+ dbgflex=0x2,
+ dbglink=0x4,
+ dbgtoken=0x8,
+ dbgid=0x10,
+ dbgpascal=0x20,
+ dbgexpand=0x40,
+ dbgbison=0x80,
+ dbgparse=0x100,
+ dbgcweb=0x200,
+ dbgjoin=0x400,
+ dbgstring=0x800,
+ dbgfor=0x1000,
+ dbgslash=0x2000,
+ dbgmacro=0x4000,
+ dbgarray=0x8000,
+ dbgreturn=0x10000,
+ dbgsemicolon=0x20000,
+ dbgbreak=0x40000
+ } debugmode;
+@
+
+Processing the command line looks for options and then sets the
+basename\index{basename}.
+
+@<external declarations@>=
+extern FILE *logfile;
+extern int ww_flex_debug;
+extern debugmode debugflags;
+@
+@<global variables@>=
+#define MAX_NAME 256
+static char basename[MAX_NAME];
+static FILE *w=NULL;
+static FILE *pascal=NULL;
+FILE *logfile=NULL;
+debugmode debugflags=dbgnone;
+@
+
+@<process the command line@>=
+{ int mk_logfile=0, mk_pascal=0, baselength=0;
+ char *w_file_name=NULL;
+ ww_flex_debug=0;
+ ppdebug=0;
+ if (argc < 2) usage();
+ argv++; /* skip the program name */
+ while (*argv!=NULL)
+ { if ((*argv)[0]=='-')
+ { char option=(*argv)[1];
+ switch(option)
+ { default: usage();
+ case 'p': mk_pascal=1; @+break;
+ case 'o': argv++;@+ w_file_name=*argv;@+ break;
+ case 'l': mk_logfile=1; @+break;
+ case 'y': ppdebug=1; @+break;
+ case 'd': @/
+ argv++; if (*argv==NULL) usage();
+ debugflags=strtol(*argv,NULL,16);
+ if (debugflags&dbgflex) ww_flex_debug=1;
+ if (debugflags&dbgbison) ppdebug=1;
+ break;
+ }
+ }
+ else
+ { strncpy(basename,*argv,MAX_NAME-1);
+ baselength=strlen(basename)-4;
+ if (baselength<1 || strncmp(basename+baselength,".web",4)!=0) usage();
+ basename[baselength]=0;
+ if (*(argv+1)!=NULL) usage();
+ }
+ argv++;
+ }
+ @<open the files@>@;
+}
+@
+After the command line has been processed, four file streams need to be opened:
+|win|, the input file\index{input file};
+|w|, the output file\index{output file};
+|logfile|, if a log file\index{log file} is asked for;
+and |pascal|, if the output of the pascal code is requested.
+For technical reasons, the scanner generated by \.{flex} needs
+an output file |wwout|. The log file is opened first because
+this is the place where error messages\index{error message}
+should go while the other files are opened.
+
+@<open the files@>=
+ if (mk_logfile)
+ { basename[baselength]=0;
+ strcat(basename,".log");
+ logfile=freopen(basename,"w",stderr);
+ if (logfile==NULL)
+ { fprintf(stderr,"Unable to open logfile %s",basename);
+ logfile=stderr;
+ }
+ wwout=logfile;
+ }
+ else
+ { logfile=stderr;
+ wwout=stderr;
+ }
+ basename[baselength]=0;
+ strcat(basename,".web");
+ wwin=fopen(basename,"r");
+ if (wwin==NULL) ERROR("Unable to open input file %s",basename);
+ if (w_file_name==NULL)
+ { w_file_name=basename;
+ basename[baselength]=0;
+ strcat(basename,".w");
+ }
+ w=fopen(w_file_name,"w");
+ if (w==NULL) ERROR("Unable to open output file %s",w_file_name);
+ if (mk_pascal)
+ { basename[baselength]=0;
+ strcat(basename,".pas");
+ pascal=fopen(basename,"w");
+ if (pascal==NULL) ERROR("Unable to open pascal file %s",basename);
+ }
+@
+
+
+
+\section{Error handling and debugging}
+There is no good program without good error handling\index{error handling}\index{debugging}.
+To print messages\index{message} or indicate errors I define the following macros:
+@<external declarations@>=
+#include <stdlib.h>
+#include <stdio.h>
+#define MESSAGE(...) @[(fprintf(logfile,__VA_ARGS__),fflush(logfile))@]
+#define ERROR(...) (fprintf(logfile,"ERROR: "),\
+ MESSAGE(__VA_ARGS__),fprintf(logfile,"\n"),exit(1))
+#define CHECK(condition,...) (!(condition)? ERROR(__VA_ARGS__):0)
+@
+
+To display the content of a token I can use |THE_TOKEN|.
+@<external declarations@>=
+#define THE_TOKEN(t) @["%d\t%d: %s\t[%s]\n",\
+ t->lineno,t->sequenceno,token2string(t),tagname(t->tag)@]
+@
+
+The amount of debugging\index{debugging} depends on the debugging flags.
+@<external declarations@>=
+#define DBG(flags,...) {@+if(debugflags & flags) MESSAGE(__VA_ARGS__);@+}
+#define DBGTOKS(flags, from,to) { if (debugflags & flags) \
+{ token *t=from; MESSAGE("<<");\
+ while (t!=to) { MESSAGE("%s",token2string(t)); t=t->next;}\
+MESSAGE(">>\n"); }}
+
+#define TAG(t) (t?tagname(t->tag):"NULL")
+
+#define DBGTREE(flags,t) DBG(flags,"%s -> %s | %s | %d\n",TAG(t),\
+ TAG(t->previous),TAG(t->next),t->value)
+
+@
+
+
+
+\section{The scanner}
+\label{scanner}%
+{\index{scanner}\index{web.l+\.{web.l}}\small
+\input web.l.tex
+}
+
+\section{The parser}
+\label{parser}%
+The following code is contained in the
+file \.{pascal.y}\index{parser}\index{pascal.y+\.{pascal.y}}.
+It represents a modified grammar\index{grammar} for the \Pascal/ language.
+Here and throughout of this document,
+terminal symbols\index{terminal symbols}, or tokens\index{token}, are shown using a small caps font;
+for nonterminal symbols\index{nonterminal symbol}
+I use a slanted font.
+
+\medskip
+{\small
+\input pascal.y.tex
+}
+
+\section{Generating \TeX, Running \TeX, and Passing the Trip Test}
+\label{triptest}%
+Here I give a step by step instruction on how to get \TeX\ up and
+running\index{running TeX+running \TeX}
+and finally, how to pass Donald Knuth's trip test\index{trip test}.
+
+I assume that you have a Unix/Linux system with a terminal window but other
+operating systems might work as well as long as you have access to the internet (I need
+files from \.{www.ctan.org}\index{CTAN}), an \.{unzip} program ( because packages on \.{www.ctan.org}
+come in \.{.zip} files), and a \CEE/ compiler.
+
+The recommended, short, and easy way is to start with the file \.{ctex.w}
+the \cweb/ version of \.{tex.web}.
+After all, this is the reason for the whole \web2w/ project:
+to provide you with a \cweb/ version of \TeX\ that is much easier to use
+than the original \WEB/ version of \TeX. But if you insist, there is also
+a subsection below that explains how to get \web2w/ up and
+running and use it to generate the \.{ctex.w} file.
+
+\subsection{Generating \TeX}
+\enumerate
+\index{generating TeX+generating \TeX}
+\item
+\label{start}%
+Download the \web2w/ package from \.{www.ctan.org} and
+expand the files. Open a terminal window and navigate to
+the root directory of the package. This directory will
+be called the \.{web2w} directory in the following.
+It contains a \.{Makefile} that contains most of the commands
+that are explained in the following.
+
+
+\item
+In the \.{web2w} directory are the files
+\.{ctex.c}\index{ctex.c+\.{ctex.c}} and \.{ctex.tex}\index{ctex.tex+\.{ctex.tex}}. If you
+want to use them, go to step \enumref{compile}; if you want to build
+them yourself, continue with the next step.
+
+\item
+\label{cweb1}%
+\TeX\ and \web2w/ are written as literate programs. To use them,
+you need the \.{cweb}\index{cweb+\.{cweb}} tools \.{ctangle}\index{ctangle+\.{ctangle}}
+and \.{cweave}\index{cweave+\.{cweave}} that I build now.
+
+Since the \TeX\ program is
+a pretty big file, you can not use the standard configuration
+even if you have \.{ctangle} and \.{cweave} already installed.
+
+Now download the \.{cweb} package from \.{www.ctan.org} and expand
+the files in the \.{web2w} directory creating the subdirectory \.{cweb}.
+
+Change to this subdirectory and try \.{make}. If it builds \.{ctangle}
+and \.{cweave} (using the preinstalled programs) skip the next step.
+
+\item
+\label{cweb2}%
+If it complains that it can not find \.{ctangle} then it's trying
+to bootstrap \.{ctangle} from \.{ctangle.w} without having \.{ctangle}
+to begin with. Try \.{touch *.c} and try \.{make} again. This time it
+should try to make \.{ctangle} from \.{ctangle.c} and \.{common.c},
+running:
+
+\.{cc -g -c -o ctangle.o ctangle.c}
+
+\.{cc -g -DCWEBINPUTS="/usr/local/lib/cweb" -c common.c}
+
+\.{cc -g -o ctangle ctangle.o common.o}
+
+\noindent
+Now you should have \.{ctangle}. Then building \.{cweave} should be no problem
+by running \.{make}.
+
+
+\item
+\label{cweb3}%
+Next I need to patch \.{ctangle.w}, \.{cweave.w}, and \.{common.w}
+to enlarge the settings for various parameters. Change to the \.{cweb} subdirectory
+and run the commands
+
+\.{patch --verbose cweave.w ../cweave.patch}
+
+\.{patch --verbose ctangle.w ../ctangle.patch}
+
+\.{patch --verbose common.w ../common.patch}
+
+\.{make}
+
+\noindent
+If you do not have the \.{patch} program, look at the patch files
+and read them as instructions how to change the settings in
+ \.{ctangle.w}, \.{cweave.w}, and \.{common.w}; you can do these small changes easily
+with any text editor yourself.
+
+The final \.{make} should produce a new \.{ctangle} and \.{cweave} by running the
+old \.{ctangle} on the new \.{ctangle.w}, \.{cweave.w}, and
+\.{common.w}.
+The \.{cweb} directory contains change files to adapt the programs to particular
+operating systems and it might be a good idea to use them. On an Win32 machine, for
+example, you might want to write
+
+\.{./ctangle ctangle.w ctang-w32.ch}
+
+\.{./ctangle cweave.w cweav-w32.ch}
+
+\.{./ctangle common.w comm-w32.ch}
+
+Then run the \CEE/ compiler again as in the previous step.
+
+\item
+\label{creating}%
+Now you use your extra powerful \.{ctangle} and \.{cweave} from step~\enumref{cweb3},
+return to the \.{web2w} directory,
+and generate \.{ctex.c} and \.{ctex.tex} simply by running the
+commands
+
+\.{cweb/ctangle ctex.w}
+
+\.{cweb/cweave ctex.w}
+
+
+\item
+\label{compile}%
+Compiling\index{compiling} \.{ctex.c} is pretty easy: use the command
+
+\.{cc ctex.c -lm -o ctex}
+
+\noindent
+The \.{-lm} tells it to link in the \CEE/ math library.
+You may add other options like \.{-g} or \.{-O3} as you like.
+What you have now is the virgin \TeX\ program (also called \.{VIRTEX}).
+
+\item
+If you have \TeX\ on your system, you can generate the documentation with the command
+
+\.{tex ctex.tex} \quad or\quad \.{pdftex ctex.tex}.
+
+\noindent
+Otherwise, you will have to wait until step~\enumref{documentation}.
+
+Note that the above commands will need the files \.{ctex.idx} and \.{ctex.scn}.
+These are part of the \.{web2w} package and are produced as a side effect of
+running \.{cweave} on \.{ctex.w}.
+
+
+\advance\leftskip by-\parindent
+\subsection{Running \TeX}
+\advance\leftskip by\parindent
+\item Producing ``Hello world!'' with \.{ctex}.\index{running TeX+running \TeX}
+
+There are some differences between the plain \TeX\ that you have
+generated now and the \TeX\ that you get if you install one of the
+large and convenient \TeX\ distributions. First, there is no
+sophisticated searching for font files, formats, and tex input files
+(as usually provided by the \.{kpathsea} library), instead files are
+looked up in the current directory or in the subdirectories
+\.{TeXfonts}\index{TeXfonts+\.{TeXfonts}}, \.{TeXformats}\index{TeXformats+\.{TeXformats}},
+and \.{TeXinputs}\index{TeXinputs+\.{TeXinputs}}. Second, the plain
+\TeX\ that you have now does not come with preloadable format files,
+you have to generate them first. So let's get started with populating
+the subdirectories just mentioned with the necessary files from
+the \.{www.ctan.org} archives.
+
+The first file is the \.{plain.tex}\index{plain.tex+\.{plain.tex}} file.
+You find it on \.{www.ctan.org}
+in the \.{lib} subdirectory
+of \.{systems/knuth/dist/}. This file defines the plain \TeX\ format; save it to
+the \.{TeXinputs} subdirectory.
+
+Now, do the same for the file \.{hyphen.tex}\index{hyphen.tex+\.{hyphen.tex}}
+(same source same destination directory) containing basic hyphenation patterns.
+
+
+\item Next, you need the \TeX\ font metric files\index{font metric file}.
+Download the package ``\.{cm-tfm}---Metric files for the Computer Modern fonts''
+from \.{www.ctan.org} and unpack the files in \.{tfm.zip} into the
+\.{TeXfonts} subdirectory.
+
+\item Now you need to create \.{cinitex}\index{cinitex+\.{cinitex}}, a special version of \TeX\ that is
+able to initialize all its internal data structures and therefore does not depend
+on format files; instead it can be used to create format files.
+Special versions of \.{ctex} can be created by defining the \CEE/ macros \.{DEBUG},
+\.{INIT}, or \.{STAT} on the command line. So (compare step~\enumref{compile}) run the command
+
+\.{cc -DINIT ctex.c -lm -o cinitex}
+
+\item Ready? Start \.{cinitex} and see what happens.
+The dialog with \.{cinitex} should follow the
+outline below. \TeX's output is shown in typewriter style, your input is shown in italics.
+
+\.{This is TeX, Version 3.14159265 (HINT) (INITEX)}\par
+\.{**}{\it plain}\par
+\.{(TeXinputs/plain.tex Preloading the plain format: codes,}\par
+\.{registers, parameters, fonts, more fonts, macros,}\par
+\.{math definitions, output routines,}\par
+\.{hyphenation (TeXinputs/hyphen.tex))}\par
+\.{*}{\it Hello world!}\par
+\.{}\par
+\.{*}{\it $\backslash$end}\par
+\.{[1]}\par
+\.{Output written on plain.dvi (1 page, 224 bytes).}\par
+\.{Transcript written on plain.log.}\par
+
+\noindent
+Well that's it. You should now have a file \.{plain.dvi} which you can open with any
+run-of-the-mill dvi-viewer.
+
+\item
+\label{format}%
+To do the same with the virgin \.{ctex} program, you need a \.{plain.fmt} file
+which I produce next. Start \.{cinitex} again. This time your dialog should be as follows:
+
+\.{This is TeX, Version 3.14159265 (HINT) (INITEX)}\par
+\.{**}{\it plain $\backslash$dump}\par
+\.{(TeXinputs/plain.tex Preloading the plain format: codes,}\par
+\.{registers, parameters, fonts, more fonts, macros,}\par
+\.{math definitions, output routines,}\par
+\.{hyphenation (TeXinputs/hyphen.tex))}\par
+\.{Beginning to dump on file plain.fmt}\par
+\.{ (preloaded format=plain 1776.7.4)}\par
+\.{1338 strings of total length 8447}\par
+\.{4990 memory locations dumped; current usage is 110\AM4877}\par
+\.{926 multiletter control sequences}\par
+\.{\BS font\BS nullfont=nullfont}\par
+{\medskip$\qquad\vcenter{\vdots}$\smallskip}
+\.{\font\preloaded=manfnt}\par
+\.{14707 words of font info for 50 preloaded fonts}\par
+\.{14 hyphenation exceptions}\par
+\.{Hyphenation trie of length 6075 has 181 ops out of 500}\par
+\.{ 181 for language 0}\par
+\.{No pages of output.}\par
+\.{Transcript written on plain.log}\par
+
+\noindent
+Now you should have a file \.{plain.fmt}. Move it to the \.{TeXformats/} subdirectory,
+where plain \.{ctex} will find it, and you are ready for the final ``Hello world!'' step.
+
+\item Start the virgin \.{ctex} program and answer as follows:
+
+\.{This is TeX, Version 3.14159265 (HINT) (no format preloaded)}\par
+\.{**}{\it $\AM$plain}\par
+\.{*}{\it Hello world!}\par
+\.{*}{\it $\backslash$end}\par
+\.{[1]}\par
+\.{Output written on texput.dvi (1 page, 224 bytes).}\par
+\.{Transcript written on texput.log}\par
+
+\noindent
+The ``$\AM$'' preceding ``{\it plain}'' tells \TeX\ that this is a format file.
+Your dvi output is now in the \.{texput.dvi} file.
+
+\item If you have \.{ctex.tex} from step~\enumref{creating},
+\.{ctex} from step~\enumref{compile}, and \.{plain.fmt} from step~\enumref{format},
+producing \.{ctex.dvi} using \.{ctex} itself seems like a snap.
+Running \.{ctex} on \.{ctex.tex} will, however, need the include file \.{cwebmac.tex} which
+you should have downloaded already with the \.{cweb} sources in step~\enumref{cweb1};
+copy it to the \.{TeXinputs/} subdirectory. Then \.{ctex.tex} will further need the
+\.{logo10.tfm} file from the mflogo fonts package. Download the file from the
+\.{fonts/mflogo/tfm} directory (part of the mflogo package) on \.{www.ctan.org}
+and place it in the \.{TeXfonts} subdirectory.
+
+Unfortunately \TeX\ is a real big program and you need not only a super \.{ctangle}
+and \.{cweave}, you need also a super \TeX\ to process it. The out-of-the box \.{ctex}
+will end with a ``{\tt ! TeX capacity exceeded, sorry [main memory size=30001].}''
+
+So the next step describes how to get this super \TeX.
+
+\item
+\label{documentation}%
+Take your favorite text editor and open the file \.{ctex.w}.
+Locate the line (this should be line 397) where it says \.{enum \{@@+@@!mem\_max=30000@@+\};}
+and change the size to 50000. (You see how easy it is to change the code of \TeX\ now?)
+It remains to run \.{ctangle} and \.{cc} to get the super \.{ctex}:
+
+\.{cweb/ctangle ctex.w}\par
+\.{cc ctex.c -lm -o ctex}\par
+
+Now start super \.{ctex} and answer
+{\it $\AM$plain ctex}. You should get \.{ctex.dvi}
+
+\advance\leftskip by-\parindent
+\subsection{Passing the Trip Test}
+\advance\leftskip by+\parindent
+\item
+\label{proof}
+Passing the trip test\index{trip test} is the last proof of concept!
+
+Download the package \.{tex.zip} from \.{www.ctan.org}
+which contains the files of \.{systems/knuth/dist/tex} (this is the
+original \TeX\ distribution by Donald E. Knuth\index{Knuth, Donald E.}) and extract the files
+into the \.{tex} subdirectory of \.{web2w} (see also step~\enumref{gettex} below).
+
+Perform all the steps described in \.{tripman.tex} in the
+\.{tex} subdirectory (you might want to create a dvi file with \.{ctex} before reading it)
+replacing ``\.{tex.web}'' by ``\.{ctex.w}'' and ``\.{tangle}'' by ``\.{ctangle}''.
+You should encounter
+no difficulties (if yes, let me know) if you observe the following hints:
+\itemize
+
+\item Make a copy of \.{ctex.w} and modify the setting of constants as
+required by step 2 of Knuths instructions. If you have the \.{patch} program,
+you might want to use the file \.{triptest.patch} to get these changes.
+
+\item After generating \.{ctex.c} from the modified \.{ctex.w} by running \.{ctangle},
+compile \.{ctex.c}
+with the options \.{-DINIT} and \.{-DSTAT} like this:
+
+\.{cc -DINIT -DSTAT ctex.c -lm -o cinitex}\par
+
+\noindent
+Instead of setting \&{init} and \&{stats} in \.{ctex.w}, use the \.{-D} command line options.
+\enditemize
+
+
+\advance\leftskip by-\parindent
+\subsection{Generating {\tt ctex.w} from {\tt tex.web}}
+\advance\leftskip by+\parindent
+
+
+\item To create \.{ctex.w} from \.{tex.web}, you need to build \.{web2w}, which
+is written as a literate program. So you can start building it from the file
+\.{web2w.w} or use the file \.{web2w.c} which comes with the \.{web2w} package.
+In the latter case, you can skip the next step.
+
+\item
+\label{web2w}%
+You create \.{web2w.c}\index{web2w.c+\.{web2w.c}} and \.{web2w.h}\index{web2w.h+\.{web2w.h}} from \.{web2w.w} by running
+
+\.{ctangle web2w.w}\quad or \quad \.{cweb/ctangle web2w.w}
+
+\noindent
+Any \.{ctangle} program should work here, but it doesn't harm if you use
+your own \.{ctangle} created in step~\enumref{cweb3}.
+
+I do not describe how to produce \.{web2w.pdf} from \.{web2w.w}: First, because
+you seem to have that file already if you are reading this, and second, because
+it is a much more complicated process. In addition, if you like reading on paper
+and prefer a nicely bound book over a mess of photocopies, you can buy this document
+also as a book titled ``WEB to cweb''\cite{Ruckert:web2w}.
+
+\item From \.{web2w.c}, \.{web2w.h}, \.{web.l}, and \.{pascal.y}, you get \.{web2w} by running
+
+\.{flex -o web.lex.c web.l}
+
+\.{bison -d -v pascal.y}
+
+\.{cc -o web2w web2w.c web.lex.c pascal.tab.c}
+
+The first command produces the scanner \.{web.lex.c};
+the second command produces the parser in two files
+\.{pascal.tab.c} and \.{pascal.tab.h}.
+If your version of \.{bison} does not support an api prefix, you can use the option \.{-p pp}
+instead.
+The last command invokes the \CEE/ compiler to create \.{web2w}.
+
+\item
+\label{gettex}%
+Next I want to run \.{tex.web} through \.{web2w}. To obtain \.{tex.web}
+download the package \.{tex.zip} from \.{www.ctan.org}
+which contains the files of the
+original \TeX\ distribution by Donald E. Knuth
+in directory \.{systems/knuth/dist/tex} and extract the files
+into the \.{tex} subdirectory of \.{web2w} (see also step~\enumref{proof}).
+
+\item Now I am ready to apply \.{web2w}. Run
+
+\.{./web2w -o tex.w tex/tex.web}
+
+\noindent
+This command will produce \.{tex.w}, but I am not yet finished. I have to apply
+the patch file\index{patch file} \.{ctex.patch} to get the finished \.{ctex.w} like this:
+
+\.{patch --verbose -o ctex.w tex.w ctex.patch}
+
+\noindent
+And \.{ctex.w} has been created.
+
+
+\endenumerate
+
+
+
+
+
+\plainsection{References}
+
+{\baselineskip=11pt
+\def\bfblrm{\small\rm}%
+\def\bblem{\small\it}%
+\bibliography{web2w}
+\bibliographystyle{plain}
+}
+\plainsection{Index}
+{
+\def\_{{\tt \UL}} % underline in a string
+\catcode`\_=\active \let_=\_ % underline is a letter
+\input web2w.ind
+}